xref: /aosp_15_r20/external/libchrome/base/debug/elf_reader_linux.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/debug/elf_reader_linux.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <arpa/inet.h>
8*635a8641SAndroid Build Coastguard Worker #include <elf.h>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include <vector>
11*635a8641SAndroid Build Coastguard Worker 
12*635a8641SAndroid Build Coastguard Worker #include "base/bits.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/containers/span.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/sha1.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
16*635a8641SAndroid Build Coastguard Worker 
17*635a8641SAndroid Build Coastguard Worker namespace base {
18*635a8641SAndroid Build Coastguard Worker namespace debug {
19*635a8641SAndroid Build Coastguard Worker 
20*635a8641SAndroid Build Coastguard Worker namespace {
21*635a8641SAndroid Build Coastguard Worker 
22*635a8641SAndroid Build Coastguard Worker #if __SIZEOF_POINTER__ == 4
23*635a8641SAndroid Build Coastguard Worker using Ehdr = Elf32_Ehdr;
24*635a8641SAndroid Build Coastguard Worker using Dyn = Elf32_Dyn;
25*635a8641SAndroid Build Coastguard Worker using Half = Elf32_Half;
26*635a8641SAndroid Build Coastguard Worker using Nhdr = Elf32_Nhdr;
27*635a8641SAndroid Build Coastguard Worker using Phdr = Elf32_Phdr;
28*635a8641SAndroid Build Coastguard Worker using Word = Elf32_Word;
29*635a8641SAndroid Build Coastguard Worker #else
30*635a8641SAndroid Build Coastguard Worker using Ehdr = Elf64_Ehdr;
31*635a8641SAndroid Build Coastguard Worker using Dyn = Elf64_Dyn;
32*635a8641SAndroid Build Coastguard Worker using Half = Elf64_Half;
33*635a8641SAndroid Build Coastguard Worker using Nhdr = Elf64_Nhdr;
34*635a8641SAndroid Build Coastguard Worker using Phdr = Elf64_Phdr;
35*635a8641SAndroid Build Coastguard Worker using Word = Elf64_Word;
36*635a8641SAndroid Build Coastguard Worker #endif
37*635a8641SAndroid Build Coastguard Worker 
38*635a8641SAndroid Build Coastguard Worker using ElfSegment = span<const char>;
39*635a8641SAndroid Build Coastguard Worker 
ElfSegmentBuildIDNoteAsString(const ElfSegment & segment)40*635a8641SAndroid Build Coastguard Worker Optional<std::string> ElfSegmentBuildIDNoteAsString(const ElfSegment& segment) {
41*635a8641SAndroid Build Coastguard Worker   const void* section_end = segment.data() + segment.size_bytes();
42*635a8641SAndroid Build Coastguard Worker   const Nhdr* note_header = reinterpret_cast<const Nhdr*>(segment.data());
43*635a8641SAndroid Build Coastguard Worker   while (note_header < section_end) {
44*635a8641SAndroid Build Coastguard Worker     if (note_header->n_type == NT_GNU_BUILD_ID)
45*635a8641SAndroid Build Coastguard Worker       break;
46*635a8641SAndroid Build Coastguard Worker     note_header = reinterpret_cast<const Nhdr*>(
47*635a8641SAndroid Build Coastguard Worker         reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) +
48*635a8641SAndroid Build Coastguard Worker         bits::Align(note_header->n_namesz, 4) +
49*635a8641SAndroid Build Coastguard Worker         bits::Align(note_header->n_descsz, 4));
50*635a8641SAndroid Build Coastguard Worker   }
51*635a8641SAndroid Build Coastguard Worker 
52*635a8641SAndroid Build Coastguard Worker   if (note_header >= section_end || note_header->n_descsz != kSHA1Length)
53*635a8641SAndroid Build Coastguard Worker     return nullopt;
54*635a8641SAndroid Build Coastguard Worker 
55*635a8641SAndroid Build Coastguard Worker   const uint8_t* guid = reinterpret_cast<const uint8_t*>(note_header) +
56*635a8641SAndroid Build Coastguard Worker                         sizeof(Nhdr) + bits::Align(note_header->n_namesz, 4);
57*635a8641SAndroid Build Coastguard Worker 
58*635a8641SAndroid Build Coastguard Worker   uint32_t dword = htonl(*reinterpret_cast<const int32_t*>(guid));
59*635a8641SAndroid Build Coastguard Worker   uint16_t word1 = htons(*reinterpret_cast<const int16_t*>(guid + 4));
60*635a8641SAndroid Build Coastguard Worker   uint16_t word2 = htons(*reinterpret_cast<const int16_t*>(guid + 6));
61*635a8641SAndroid Build Coastguard Worker   std::string identifier;
62*635a8641SAndroid Build Coastguard Worker   identifier.reserve(kSHA1Length * 2);  // as hex string
63*635a8641SAndroid Build Coastguard Worker   SStringPrintf(&identifier, "%08X%04X%04X", dword, word1, word2);
64*635a8641SAndroid Build Coastguard Worker   for (size_t i = 8; i < note_header->n_descsz; ++i)
65*635a8641SAndroid Build Coastguard Worker     StringAppendF(&identifier, "%02X", guid[i]);
66*635a8641SAndroid Build Coastguard Worker 
67*635a8641SAndroid Build Coastguard Worker   return identifier;
68*635a8641SAndroid Build Coastguard Worker }
69*635a8641SAndroid Build Coastguard Worker 
FindElfSegments(const void * elf_mapped_base,uint32_t segment_type)70*635a8641SAndroid Build Coastguard Worker std::vector<ElfSegment> FindElfSegments(const void* elf_mapped_base,
71*635a8641SAndroid Build Coastguard Worker                                         uint32_t segment_type) {
72*635a8641SAndroid Build Coastguard Worker   const char* elf_base = reinterpret_cast<const char*>(elf_mapped_base);
73*635a8641SAndroid Build Coastguard Worker   if (strncmp(elf_base, ELFMAG, SELFMAG) != 0)
74*635a8641SAndroid Build Coastguard Worker     return std::vector<ElfSegment>();
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker   const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
77*635a8641SAndroid Build Coastguard Worker   const Phdr* phdrs =
78*635a8641SAndroid Build Coastguard Worker       reinterpret_cast<const Phdr*>(elf_base + elf_header->e_phoff);
79*635a8641SAndroid Build Coastguard Worker   std::vector<ElfSegment> segments;
80*635a8641SAndroid Build Coastguard Worker   for (Half i = 0; i < elf_header->e_phnum; ++i) {
81*635a8641SAndroid Build Coastguard Worker     if (phdrs[i].p_type == segment_type)
82*635a8641SAndroid Build Coastguard Worker       segments.push_back({elf_base + phdrs[i].p_offset, phdrs[i].p_filesz});
83*635a8641SAndroid Build Coastguard Worker   }
84*635a8641SAndroid Build Coastguard Worker   return segments;
85*635a8641SAndroid Build Coastguard Worker }
86*635a8641SAndroid Build Coastguard Worker 
87*635a8641SAndroid Build Coastguard Worker }  // namespace
88*635a8641SAndroid Build Coastguard Worker 
ReadElfBuildId(const void * elf_base)89*635a8641SAndroid Build Coastguard Worker Optional<std::string> ReadElfBuildId(const void* elf_base) {
90*635a8641SAndroid Build Coastguard Worker   // Elf program headers can have multiple PT_NOTE arrays.
91*635a8641SAndroid Build Coastguard Worker   std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_NOTE);
92*635a8641SAndroid Build Coastguard Worker   if (segs.empty())
93*635a8641SAndroid Build Coastguard Worker     return nullopt;
94*635a8641SAndroid Build Coastguard Worker   Optional<std::string> id;
95*635a8641SAndroid Build Coastguard Worker   for (const ElfSegment& seg : segs) {
96*635a8641SAndroid Build Coastguard Worker     id = ElfSegmentBuildIDNoteAsString(seg);
97*635a8641SAndroid Build Coastguard Worker     if (id)
98*635a8641SAndroid Build Coastguard Worker       return id;
99*635a8641SAndroid Build Coastguard Worker   }
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker   return nullopt;
102*635a8641SAndroid Build Coastguard Worker }
103*635a8641SAndroid Build Coastguard Worker 
ReadElfLibraryName(const void * elf_base)104*635a8641SAndroid Build Coastguard Worker Optional<std::string> ReadElfLibraryName(const void* elf_base) {
105*635a8641SAndroid Build Coastguard Worker   std::vector<ElfSegment> segs = FindElfSegments(elf_base, PT_DYNAMIC);
106*635a8641SAndroid Build Coastguard Worker   if (segs.empty())
107*635a8641SAndroid Build Coastguard Worker     return nullopt;
108*635a8641SAndroid Build Coastguard Worker   DCHECK_EQ(1u, segs.size());
109*635a8641SAndroid Build Coastguard Worker 
110*635a8641SAndroid Build Coastguard Worker   const ElfSegment& dynamic_seg = segs.front();
111*635a8641SAndroid Build Coastguard Worker   const Dyn* dynamic_start = reinterpret_cast<const Dyn*>(dynamic_seg.data());
112*635a8641SAndroid Build Coastguard Worker   const Dyn* dynamic_end = reinterpret_cast<const Dyn*>(
113*635a8641SAndroid Build Coastguard Worker       dynamic_seg.data() + dynamic_seg.size_bytes());
114*635a8641SAndroid Build Coastguard Worker   Optional<std::string> soname;
115*635a8641SAndroid Build Coastguard Worker   Word soname_strtab_offset = 0;
116*635a8641SAndroid Build Coastguard Worker   const char* strtab_addr = 0;
117*635a8641SAndroid Build Coastguard Worker   for (const Dyn* dynamic_iter = dynamic_start; dynamic_iter < dynamic_end;
118*635a8641SAndroid Build Coastguard Worker        ++dynamic_iter) {
119*635a8641SAndroid Build Coastguard Worker     if (dynamic_iter->d_tag == DT_STRTAB) {
120*635a8641SAndroid Build Coastguard Worker       strtab_addr =
121*635a8641SAndroid Build Coastguard Worker           dynamic_iter->d_un.d_ptr + reinterpret_cast<const char*>(elf_base);
122*635a8641SAndroid Build Coastguard Worker     } else if (dynamic_iter->d_tag == DT_SONAME) {
123*635a8641SAndroid Build Coastguard Worker       soname_strtab_offset = dynamic_iter->d_un.d_val;
124*635a8641SAndroid Build Coastguard Worker     }
125*635a8641SAndroid Build Coastguard Worker   }
126*635a8641SAndroid Build Coastguard Worker   if (soname_strtab_offset && strtab_addr)
127*635a8641SAndroid Build Coastguard Worker     return std::string(strtab_addr + soname_strtab_offset);
128*635a8641SAndroid Build Coastguard Worker   return nullopt;
129*635a8641SAndroid Build Coastguard Worker }
130*635a8641SAndroid Build Coastguard Worker 
131*635a8641SAndroid Build Coastguard Worker }  // namespace debug
132*635a8641SAndroid Build Coastguard Worker }  // namespace base
133