| // Copyright 2021 The Fuchsia Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifdef __linux__ | |
| #include <elf.h> | |
| #include <link.h> | |
| #include <stddef.h> | |
| #include <stdio.h> | |
| #include <algorithm> | |
| #include "buildid.h" | |
| static int iter(struct dl_phdr_info *info, size_t sz, void *vctx) { | |
| char *out = reinterpret_cast<char *>(vctx); | |
| // Observed on linux: dlpi_name for the main process is empty | |
| if (strlen(info->dlpi_name) != 0) { | |
| return 0; | |
| } | |
| for (size_t i = 0; i < info->dlpi_phnum; i++) { | |
| if (info->dlpi_phdr[i].p_type != PT_NOTE) { | |
| continue; | |
| } | |
| uintptr_t note_ptr = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; | |
| uintptr_t end = note_ptr + info->dlpi_phdr[i].p_memsz; | |
| while (note_ptr + sizeof(ElfW(Nhdr)) < end) { | |
| auto note = reinterpret_cast<ElfW(Nhdr) *>(note_ptr); | |
| auto name = reinterpret_cast<char *>(note_ptr + sizeof(ElfW(Nhdr))); | |
| if (note->n_type == NT_GNU_BUILD_ID && note->n_namesz == 4 && memcmp(name, "GNU", 4) == 0) { | |
| uint8_t *build_id = | |
| reinterpret_cast<uint8_t *>(note_ptr + sizeof(ElfW(Nhdr)) + note->n_namesz); | |
| for (size_t i = 0; i < std::min(16u, note->n_descsz); i++) { | |
| sprintf(&out[i * 2], "%02x", build_id[i]); | |
| } | |
| return std::min(32u, note->n_descsz * 2); | |
| } | |
| note_ptr = note_ptr + sizeof(ElfW(Nhdr)) + note->n_namesz + note->n_descsz; | |
| } | |
| } | |
| return 0; | |
| } | |
| int get_build_id(char out[33]) { return dl_iterate_phdr(iter, out); } | |
| #endif |