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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/metrics/leak_detector/gnu_build_id_reader.cc
diff --git a/components/metrics/leak_detector/gnu_build_id_reader.cc b/components/metrics/leak_detector/gnu_build_id_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ac0f07daeccb697cc83f3379f84b6783037beb43
--- /dev/null
+++ b/components/metrics/leak_detector/gnu_build_id_reader.cc
@@ -0,0 +1,124 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/leak_detector/gnu_build_id_reader.h"
+
+#include <elf.h>
+
+#include <algorithm>
+
+#if defined(OS_CHROMEOS)
+#include <link.h> // for dl_iterate_phdr
+#else
+#error "Getting binary mapping info is not supported on this platform."
+#endif // defined(OS_CHROMEOS)
+
+namespace metrics {
+namespace leak_detector {
+namespace gnu_build_id_reader {
+
+namespace {
+
+// Contains data passed to dl_iterate_phdr() for reading build ID.
+struct ReadBuildIDData {
+ // Points to a vector for storing the build ID.
+ std::vector<uint8_t>* build_id;
+ // Indicates whether build ID was read successfully.
+ bool success;
+};
+
+// Given a pointer and an offset, add the offset to the pointer and round it up
+// to the next uint32_t.
+const void* AlignPtrAndOffsetToUint32(const void* ptr, intptr_t offset) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + offset;
+ uintptr_t aligned_addr =
+ (addr + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
+ return reinterpret_cast<const void*>(aligned_addr);
+}
+
+// Searches for the ELF note containing the build ID within the data range
+// specified by [start, end). Returns the build ID in |*result|. If the build ID
+// is not found, |*result| will be unchanged. Returns true if the build ID was
+// successfully read or false otherwise.
+bool GetBuildIdFromNotes(const void* start,
+ const void* end,
+ std::vector<uint8_t>* result) {
+ using NoteHeaderPtr = const ElfW(Nhdr)*;
+ NoteHeaderPtr note = reinterpret_cast<NoteHeaderPtr>(start);
+
+ while (note < end) {
+ const char* name_ptr = reinterpret_cast<const char*>(note + 1);
+ if (name_ptr >= end) {
+ break;
+ }
+ // |desc_ptr| points the to the actual build ID data.
+ const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>(
+ AlignPtrAndOffsetToUint32(name_ptr, note->n_namesz));
+ if (note->n_type == NT_GNU_BUILD_ID &&
+ note->n_namesz == sizeof(ELF_NOTE_GNU) &&
+ std::equal(name_ptr, name_ptr + sizeof(ELF_NOTE_GNU), ELF_NOTE_GNU)) {
+ result->assign(desc_ptr, desc_ptr + note->n_descsz);
+ return true;
+ }
+ NoteHeaderPtr next_ptr = reinterpret_cast<NoteHeaderPtr>(
+ AlignPtrAndOffsetToUint32(desc_ptr, note->n_descsz));
+ note = next_ptr;
+ }
+ return false;
+}
+
+// Callback for dl_iterate_phdr(). Finds the notes section and looks for the
+// build ID in there. |data| points to a ReadBuildIDData struct whose |build_id|
+// field should point to a valid std::vector<uint8_t>. Returns the build ID in
+// that field, and sets |ReadBuildIDData::success| based on whether the build ID
+// was successfully read.
+//
+// This function always returns 1 to signal the end of dl_iterate_phdr()'s
+// iteration, because it is only interested in the first binary iterated by
+// dl_iterate_phdr(), which is the current binary.
+int FindNotesAndGetBuildID(struct dl_phdr_info* info,
+ size_t /* size */,
+ void* data) {
+ uintptr_t mapping_addr = reinterpret_cast<uintptr_t>(info->dlpi_addr);
+ const ElfW(Ehdr)* file_header =
+ reinterpret_cast<const ElfW(Ehdr)*>(mapping_addr);
+
+ // Make sure that a valid |mapping_addr| was read.
+ if (!file_header || file_header->e_phentsize != sizeof(ElfW(Phdr))) {
+ return 1;
+ }
+
+ // Find the ELF segment header for the NOTES section.
+ for (int i = 0; i < info->dlpi_phnum; ++i) {
+ const ElfW(Phdr)& segment_header = info->dlpi_phdr[i];
+ if (segment_header.p_type == PT_NOTE) {
+ const void* note = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr);
+ const void* note_end = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr + segment_header.p_memsz);
+ ReadBuildIDData* read_data = reinterpret_cast<ReadBuildIDData*>(data);
+ read_data->success =
+ GetBuildIdFromNotes(note, note_end, read_data->build_id);
+ }
+ }
+ return 1;
+}
+
+} // namespace
+
+bool ReadBuildID(std::vector<uint8_t>* build_id) {
+ ReadBuildIDData data;
+ data.build_id = build_id;
+ data.success = false;
+
+#if defined(OS_CHROMEOS)
+ dl_iterate_phdr(FindNotesAndGetBuildID, &data);
+#endif // defined(OS_CHROMEOS)
+
+ return data.success;
+}
+
+} // namespace gnu_build_id_reader
+} // namespace leak_detector
+} // namespace metrics
« 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