Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: components/metrics/leak_detector/gnu_build_id_reader.cc

Issue 2159013002: Read Chrome build ID and store it in leak reports (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove DCHECK for build ID having been read Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/metrics/leak_detector/gnu_build_id_reader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 <elf.h>
8
9 #include <algorithm>
10
11 #if defined(OS_CHROMEOS)
12 #include <link.h> // for dl_iterate_phdr
13 #else
14 #error "Getting binary mapping info is not supported on this platform."
15 #endif // defined(OS_CHROMEOS)
16
17 namespace metrics {
18 namespace leak_detector {
19 namespace gnu_build_id_reader {
20
21 namespace {
22
23 // Contains data passed to dl_iterate_phdr() for reading build ID.
24 struct ReadBuildIDData {
25 // Points to a vector for storing the build ID.
26 std::vector<uint8_t>* build_id;
27 // Indicates whether build ID was read successfully.
28 bool success;
29 };
30
31 // Given a pointer and an offset, add the offset to the pointer and round it up
32 // to the next uint32_t.
33 const void* AlignPtrAndOffsetToUint32(const void* ptr, intptr_t offset) {
34 uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + offset;
35 uintptr_t aligned_addr =
36 (addr + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
37 return reinterpret_cast<const void*>(aligned_addr);
38 }
39
40 // Searches for the ELF note containing the build ID within the data range
41 // specified by [start, end). Returns the build ID in |*result|. If the build ID
42 // is not found, |*result| will be unchanged. Returns true if the build ID was
43 // successfully read or false otherwise.
44 bool GetBuildIdFromNotes(const void* start,
45 const void* end,
46 std::vector<uint8_t>* result) {
47 using NoteHeaderPtr = const ElfW(Nhdr)*;
48 NoteHeaderPtr note = reinterpret_cast<NoteHeaderPtr>(start);
49
50 while (note < end) {
51 const char* name_ptr = reinterpret_cast<const char*>(note + 1);
52 if (name_ptr >= end) {
53 break;
54 }
55 // |desc_ptr| points the to the actual build ID data.
56 const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>(
57 AlignPtrAndOffsetToUint32(name_ptr, note->n_namesz));
58 if (note->n_type == NT_GNU_BUILD_ID &&
59 note->n_namesz == sizeof(ELF_NOTE_GNU) &&
60 std::equal(name_ptr, name_ptr + sizeof(ELF_NOTE_GNU), ELF_NOTE_GNU)) {
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 //
77 // This function always returns 1 to signal the end of dl_iterate_phdr()'s
78 // iteration, because it is only interested in the first binary iterated by
79 // dl_iterate_phdr(), which is the current binary.
80 int FindNotesAndGetBuildID(struct dl_phdr_info* info,
81 size_t /* size */,
82 void* data) {
83 uintptr_t mapping_addr = reinterpret_cast<uintptr_t>(info->dlpi_addr);
84 const ElfW(Ehdr)* file_header =
85 reinterpret_cast<const ElfW(Ehdr)*>(mapping_addr);
86
87 // Make sure that a valid |mapping_addr| was read.
88 if (!file_header || file_header->e_phentsize != sizeof(ElfW(Phdr))) {
89 return 1;
90 }
91
92 // Find the ELF segment header for the NOTES section.
93 for (int i = 0; i < info->dlpi_phnum; ++i) {
94 const ElfW(Phdr)& segment_header = info->dlpi_phdr[i];
95 if (segment_header.p_type == PT_NOTE) {
96 const void* note = reinterpret_cast<const void*>(
97 mapping_addr + segment_header.p_vaddr);
98 const void* note_end = reinterpret_cast<const void*>(
99 mapping_addr + segment_header.p_vaddr + segment_header.p_memsz);
100 ReadBuildIDData* read_data = reinterpret_cast<ReadBuildIDData*>(data);
101 read_data->success =
102 GetBuildIdFromNotes(note, note_end, read_data->build_id);
103 }
104 }
105 return 1;
106 }
107
108 } // namespace
109
110 bool ReadBuildID(std::vector<uint8_t>* build_id) {
111 ReadBuildIDData data;
112 data.build_id = build_id;
113 data.success = false;
114
115 #if defined(OS_CHROMEOS)
116 dl_iterate_phdr(FindNotesAndGetBuildID, &data);
117 #endif // defined(OS_CHROMEOS)
118
119 return data.success;
120 }
121
122 } // namespace gnu_build_id_reader
123 } // namespace leak_detector
124 } // namespace metrics
OLDNEW
« no previous file with comments | « components/metrics/leak_detector/gnu_build_id_reader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698