1 | // SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. |
2 | // |
3 | // SPDX-License-Identifier: GPL-3.0-or-later |
4 | |
5 | #include <assert.h> |
6 | #include <stdio.h> |
7 | #include <unistd.h> |
8 | #include <inttypes.h> |
9 | #include <sys/stat.h> |
10 | #include <fcntl.h> |
11 | |
12 | #include "elf_helper.h" |
13 | #include "easylogging++.h" |
14 | |
15 | static void get_debug_file(const unsigned char* id, char* buffer) |
16 | { |
17 | /* |
18 | file /usr/lib/x86_64-linux-gnu/ld-2.24.so: |
19 | ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, |
20 | BuildID[sha1]=095935d2da92389e2991f2b56d14dab9e6978696, stripped |
21 | file /lib/debug/.build-id/09/5935d2da92389e2991f2b56d14dab9e6978696.debug: |
22 | ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, |
23 | BuildID[sha1]=095935d2da92389e2991f2b56d14dab9e6978696, not stripped |
24 | */ |
25 | char* walk = buffer; |
26 | walk += sprintf(walk, "/lib/debug/.build-id/%02x/" , id[0]); |
27 | for (int i = 1; i<20; ++i) { |
28 | walk += sprintf(walk, "%02x" , id[i]); |
29 | } |
30 | strcpy(walk, ".debug" ); |
31 | } |
32 | |
33 | SymbolFile::SymbolFile(uintptr_t base, const char* filename, bool use_dwarf) |
34 | { |
35 | char debug_file[256]; |
36 | |
37 | m_searched = false; |
38 | m_base = base; |
39 | |
40 | auto fd = open(filename, O_RDONLY); |
41 | if (fd <= 0) { |
42 | m_valid = false; |
43 | return; |
44 | } |
45 | |
46 | try { |
47 | m_elf = elf::elf{elf::create_mmap_loader(fd)}; |
48 | } |
49 | catch (const std::runtime_error& e) { |
50 | LOG(DEBUG) << " runtime_error:" << e.what() |
51 | << ", when parse " << filename; |
52 | } |
53 | catch(...) { |
54 | LOG(DEBUG) << "unknown exception when parse " << filename; |
55 | } |
56 | |
57 | if (use_dwarf) { |
58 | try { |
59 | const elf::section& sec = m_elf.get_section(".debug_info" ); |
60 | if (sec.valid()) { |
61 | m_dwarf = dwarf::dwarf{dwarf::elf::create_loader(m_elf)}; |
62 | } |
63 | else { |
64 | // try to load from /lib/.build-id |
65 | const elf::section& buildid = m_elf.get_section(".note.gnu.build-id" ); |
66 | if (buildid.valid()) { |
67 | const void* data = buildid.data(); |
68 | get_debug_file((const unsigned char*)data + 16, debug_file); |
69 | auto fd2 = open(debug_file, O_RDONLY); |
70 | if (fd2 > 0) { |
71 | m_elf2 = elf::elf{elf::create_mmap_loader(fd2)}; |
72 | |
73 | //FIXME: cannot read past end of DWARF section |
74 | m_dwarf = dwarf::dwarf{dwarf::elf::create_loader(m_elf2)}; |
75 | } |
76 | } |
77 | } |
78 | } |
79 | catch (const std::runtime_error& e) { |
80 | LOG(DEBUG) << " runtime_error:" << e.what() |
81 | << ", when parse " << filename; |
82 | } |
83 | catch(...) { |
84 | LOG(DEBUG) << "unknown exception when parse " << filename; |
85 | } |
86 | } |
87 | |
88 | if (m_elf.valid()) { |
89 | const elf::section& sec = m_elf.get_section(".dynsym" ); |
90 | if (sec.valid()) { |
91 | m_dynsym = sec.as_symtab(); |
92 | m_valid = true; |
93 | } |
94 | const elf::section& sec2 = m_elf.get_section(".symtab" ); |
95 | if (sec2.valid()) { |
96 | m_symtab = sec2.as_symtab(); |
97 | m_valid = true; |
98 | } |
99 | } |
100 | |
101 | #ifdef _DEBUG2 |
102 | LOG(DEBUG) << "SymbolFile constructor " << filename << ", base=" << HEX(base); |
103 | #endif |
104 | } |
105 | |
106 | SymbolFile::~SymbolFile(void) |
107 | { |
108 | } |
109 | |
110 | inline bool _sym_address(const elf::symtab& tabs, uintptr_t base, |
111 | const char *name, unsigned long *addr, elf::stt type) |
112 | { |
113 | for (auto sym : tabs) { |
114 | if (sym.get_name() == name) { |
115 | auto &d = sym.get_data(); |
116 | // TODO: can we support multiple kinds of symbol |
117 | if (d.type() == type) { |
118 | if (d.value > 0x3fffff) { |
119 | *addr = d.value; |
120 | } |
121 | else { |
122 | *addr = base + d.value; |
123 | } |
124 | return true; |
125 | } |
126 | } |
127 | } |
128 | return false; |
129 | } |
130 | |
131 | bool SymbolFile::get_sym_address(const char *name, unsigned long *addr, elf::stt type) |
132 | { |
133 | if (m_dynsym.valid()) { |
134 | if (_sym_address(m_dynsym, m_base, name, addr, type)) return true; |
135 | } |
136 | if (m_symtab.valid()) { |
137 | if (_sym_address(m_symtab, m_base, name, addr, type)) return true; |
138 | } |
139 | |
140 | return false; |
141 | } |
142 | |