Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "components/metrics/leak_detector/gnu_build_id_reader.h" | |
| 6 | |
| 7 #include <libelf.h> | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
Is just <elf.h> sufficient here?
Simon Que
2016/07/22 01:40:06
Done.
| |
| 8 #include <string.h> | |
|
Will Harris
2016/07/22 01:58:02
why is string needed?
Simon Que
2016/07/22 02:49:22
For memcmp(). But I wonder if that could be replac
| |
| 9 | |
| 10 #if defined(OS_CHROMEOS) | |
| 11 #include <link.h> // for dl_iterate_phdr | |
| 12 #else | |
| 13 #error "Getting binary mapping info is not supported on this platform." | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
Any reason to limit this to Chrome OS instead of L
Simon Que
2016/07/22 01:40:06
Using OS_POSIX or OS_LINUX cause the #else conditi
rickyz (no longer on Chrome)
2016/07/22 02:47:31
Yeah, what I meant was - if this works on OS_POSIX
| |
| 14 #endif // defined(OS_CHROMEOS) | |
| 15 | |
| 16 namespace metrics { | |
| 17 namespace leak_detector { | |
| 18 namespace gnu_build_id_reader { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Contains data passed to dl_iterate_phdr() for reading build ID. | |
| 23 struct ReadBuildIDData { | |
| 24 // Points to a vector for storing the build ID. | |
| 25 std::vector<uint8_t>* build_id; | |
| 26 // Indicates whether build ID was read successfully. | |
| 27 bool success; | |
| 28 }; | |
| 29 | |
| 30 // Given a pointer and an offset, add the offset to the pointer and round it up | |
| 31 // to the next uint32_t. | |
| 32 const void* AlignPtrAndOffsetToUint32(const void* ptr, intptr_t offset) { | |
| 33 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + offset; | |
| 34 uintptr_t aligned_addr = | |
| 35 (addr + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1); | |
| 36 return reinterpret_cast<const void*>(aligned_addr); | |
| 37 } | |
| 38 | |
| 39 // Searches for the ELF note containing the build ID within the data range | |
| 40 // specified by [start, end). Returns the build ID in |*result|. If the build ID | |
| 41 // is not found, |*result| will be unchanged. Returns true if the build ID was | |
| 42 // successfully read or false otherwise. | |
| 43 bool GetBuildIdFromNotes(const void* start, | |
| 44 const void* end, | |
| 45 std::vector<uint8_t>* result) { | |
| 46 using NoteHeaderPtr = const Elf32_Nhdr*; | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
This is the same for 64 vs. 32, but might as well
Simon Que
2016/07/22 01:40:06
Done.
| |
| 47 NoteHeaderPtr note = reinterpret_cast<NoteHeaderPtr>(start); | |
| 48 | |
| 49 while (note < end) { | |
| 50 NoteHeaderPtr name_ptr = ¬e[1]; | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
Wouldn't use NoteHeaderPtr as the type here, since
Simon Que
2016/07/22 01:40:06
Done.
| |
| 51 if (name_ptr > end) { | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
>=
| |
| 52 break; | |
| 53 } | |
| 54 // |desc_ptr| points the to the actual build ID data. | |
| 55 const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>( | |
| 56 AlignPtrAndOffsetToUint32(name_ptr, note->n_namesz)); | |
| 57 if (note->n_type == NT_GNU_BUILD_ID && | |
| 58 note->n_namesz == sizeof(ELF_NOTE_GNU) && | |
| 59 memcmp((const char*)name_ptr, ELF_NOTE_GNU, sizeof(ELF_NOTE_GNU)) == | |
| 60 0) { | |
| 61 result->assign(desc_ptr, desc_ptr + note->n_descsz); | |
| 62 return true; | |
| 63 } | |
| 64 NoteHeaderPtr next_ptr = reinterpret_cast<NoteHeaderPtr>( | |
| 65 AlignPtrAndOffsetToUint32(desc_ptr, note->n_descsz)); | |
| 66 note = next_ptr; | |
| 67 } | |
| 68 return false; | |
| 69 } | |
| 70 | |
| 71 // Callback for dl_iterate_phdr(). Finds the notes section and looks for the | |
| 72 // build ID in there. |data| points to a ReadBuildIDData struct whose |build_id| | |
| 73 // field should point to a valid std::vector<uint8_t>. Returns the build ID in | |
| 74 // that field, and sets |ReadBuildIDData::success| based on whether the build ID | |
| 75 // was successfully read. | |
| 76 int FindNotesAndGetBuildID(struct dl_phdr_info* info, | |
| 77 size_t /* size */, | |
| 78 void* data) { | |
| 79 uintptr_t mapping_addr = reinterpret_cast<uintptr_t>(info->dlpi_addr); | |
| 80 const ElfW(Ehdr)* file_header = | |
| 81 reinterpret_cast<const ElfW(Ehdr)*>(mapping_addr); | |
| 82 | |
| 83 // Make sure that a valid |mapping_addr| was read. | |
| 84 if (!file_header || file_header->e_phentsize != sizeof(ElfW(Phdr))) { | |
| 85 return 1; | |
| 86 } | |
| 87 | |
| 88 for (int i = 0; i < info->dlpi_phnum; i++) { | |
| 89 // Find the ELF segment header for the NOTES section. | |
| 90 for (int i = 0; i < info->dlpi_phnum; ++i) { | |
|
Will Harris
2016/07/19 02:51:38
i masks variable i, is this what you meant?
Simon Que
2016/07/22 01:40:06
No, accidentally had a duplicate nested loop.
| |
| 91 const ElfW(Phdr)& segment_header = info->dlpi_phdr[i]; | |
| 92 if (segment_header.p_type == PT_NOTE) { | |
| 93 // Elf64_Nhdr is the same as Elf32_Nhdr so we can use either here. | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
Was this a leftover comment from a previous iterat
Simon Que
2016/07/22 01:40:06
Done.
| |
| 94 const void* note = reinterpret_cast<const void*>( | |
| 95 mapping_addr + segment_header.p_offset); | |
|
rickyz (no longer on Chrome)
2016/07/19 04:58:22
segment_header.p_vaddr is probably more accurate h
Simon Que
2016/07/22 01:40:06
Done.
| |
| 96 const void* note_end = reinterpret_cast<const void*>( | |
| 97 mapping_addr + segment_header.p_offset + segment_header.p_memsz); | |
| 98 ReadBuildIDData* read_data = reinterpret_cast<ReadBuildIDData*>(data); | |
| 99 read_data->success = | |
| 100 GetBuildIdFromNotes(note, note_end, read_data->build_id); | |
| 101 } | |
| 102 } | |
| 103 } | |
| 104 return 1; | |
|
Will Harris
2016/07/19 02:51:38
"The dl_iterate_phdr() function walks through the
Simon Que
2016/07/22 01:40:06
Yes. We are only interested in the currently runni
| |
| 105 } | |
| 106 | |
| 107 } // namespace | |
| 108 | |
| 109 bool ReadBuildID(std::vector<uint8_t>* build_id) { | |
| 110 ReadBuildIDData data; | |
| 111 data.build_id = build_id; | |
| 112 data.success = false; | |
| 113 | |
| 114 #if defined(OS_CHROMEOS) | |
| 115 dl_iterate_phdr(FindNotesAndGetBuildID, &data); | |
| 116 #endif // defined(OS_CHROMEOS) | |
| 117 | |
| 118 return data.success; | |
| 119 } | |
| 120 | |
| 121 } // namespace gnu_build_id_reader | |
| 122 } // namespace leak_detector | |
| 123 } // namespace metrics | |
| OLD | NEW |