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
15static 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
33SymbolFile::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
106SymbolFile::~SymbolFile(void)
107{
108}
109
110inline 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
131bool 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