-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathsymbols_linux.h
178 lines (154 loc) · 5.33 KB
/
symbols_linux.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#ifdef __linux__
#include "symbols.h"
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
class SymbolDesc {
private:
const char* _addr;
const char* _desc;
public:
SymbolDesc(const char* s) {
_addr = s;
_desc = strchr(_addr, ' ');
}
const char* addr() { return (const char*)strtoul(_addr, NULL, 16); }
char type() { return _desc != NULL ? _desc[1] : 0; }
const char* name() { return _desc + 3; }
};
class MemoryMapDesc {
private:
const char* _addr;
const char* _end;
const char* _perm;
const char* _offs;
const char* _dev;
const char* _inode;
const char* _file;
public:
MemoryMapDesc(const char* s) {
_addr = s;
_end = strchr(_addr, '-') + 1;
_perm = strchr(_end, ' ') + 1;
_offs = strchr(_perm, ' ') + 1;
_dev = strchr(_offs, ' ') + 1;
_inode = strchr(_dev, ' ') + 1;
_file = strchr(_inode, ' ');
if (_file != NULL) {
while (*_file == ' ') _file++;
}
}
const char* file() { return _file; }
bool isReadable() { return _perm[0] == 'r'; }
bool isExecutable() { return _perm[2] == 'x'; }
const char* addr() { return (const char*)strtoul(_addr, NULL, 16); }
const char* end() { return (const char*)strtoul(_end, NULL, 16); }
unsigned long offs() { return strtoul(_offs, NULL, 16); }
unsigned long inode() { return strtoul(_inode, NULL, 10); }
unsigned long dev() {
char* colon;
unsigned long major = strtoul(_dev, &colon, 16);
unsigned long minor = strtoul(colon + 1, NULL, 16);
return major << 8 | minor;
}
};
#ifdef __LP64__
const unsigned char ELFCLASS_SUPPORTED = ELFCLASS64;
typedef Elf64_Ehdr ElfHeader;
typedef Elf64_Shdr ElfSection;
typedef Elf64_Phdr ElfProgramHeader;
typedef Elf64_Nhdr ElfNote;
typedef Elf64_Sym ElfSymbol;
typedef Elf64_Rel ElfRelocation;
typedef Elf64_Dyn ElfDyn;
#define ELF_R_TYPE ELF64_R_TYPE
#define ELF_R_SYM ELF64_R_SYM
#else
const unsigned char ELFCLASS_SUPPORTED = ELFCLASS32;
typedef Elf32_Ehdr ElfHeader;
typedef Elf32_Shdr ElfSection;
typedef Elf32_Phdr ElfProgramHeader;
typedef Elf32_Nhdr ElfNote;
typedef Elf32_Sym ElfSymbol;
typedef Elf32_Rel ElfRelocation;
typedef Elf32_Dyn ElfDyn;
#define ELF_R_TYPE ELF32_R_TYPE
#define ELF_R_SYM ELF32_R_SYM
#endif // __LP64__
#if defined(__x86_64__)
# define R_GLOB_DAT R_X86_64_GLOB_DAT
#elif defined(__i386__)
# define R_GLOB_DAT R_386_GLOB_DAT
#elif defined(__arm__) || defined(__thumb__)
# define R_GLOB_DAT R_ARM_GLOB_DAT
#elif defined(__aarch64__)
# define R_GLOB_DAT R_AARCH64_GLOB_DAT
#elif defined(__PPC64__)
# define R_GLOB_DAT R_PPC64_GLOB_DAT
#else
# error "Compiling on unsupported arch"
#endif
#ifdef __musl__
static const bool MUSL = true;
#else
static const bool MUSL = false;
#endif // __musl__
class ElfParser {
private:
CodeCache* _cc;
const char* _base;
const char* _file_name;
size_t _length;
bool _relocate_dyn;
ElfHeader* _header;
const char* _sections;
const char* _vaddr_diff;
ElfParser(CodeCache* cc, const char* base, const void* addr, const char* file_name, size_t length, bool relocate_dyn) {
_cc = cc;
_base = base;
_file_name = file_name;
_length = length;
_relocate_dyn = relocate_dyn && base != nullptr;
_header = (ElfHeader*)addr;
_sections = (const char*)addr + _header->e_shoff;
}
bool validHeader() {
unsigned char* ident = _header->e_ident;
return ident[0] == 0x7f && ident[1] == 'E' && ident[2] == 'L' && ident[3] == 'F'
&& ident[4] == ELFCLASS_SUPPORTED && ident[5] == ELFDATA2LSB && ident[6] == EV_CURRENT
&& _header->e_shstrndx != SHN_UNDEF;
}
ElfSection* section(int index) {
return (ElfSection*)(_sections + index * _header->e_shentsize);
}
const char* at(ElfSection* section) {
return (const char*)_header + section->sh_offset;
}
const char* at(ElfProgramHeader* pheader) {
return _header->e_type == ET_EXEC ? (const char*)pheader->p_vaddr : _vaddr_diff + pheader->p_vaddr;
}
char* dyn_ptr(ElfDyn* dyn) {
// GNU dynamic linker relocates pointers in the dynamic section, while musl doesn't.
// Also, [vdso] is not relocated, and its vaddr may differ from the load address.
if (_relocate_dyn || (char*)dyn->d_un.d_ptr < _base) {
return (char*)_vaddr_diff + dyn->d_un.d_ptr;
} else {
return (char*)dyn->d_un.d_ptr;
}
}
ElfSection* findSection(uint32_t type, const char* name);
ElfProgramHeader* findProgramHeader(uint32_t type);
void calcVirtualLoadAddress();
void parseDynamicSection();
void parseDwarfInfo();
uint32_t getSymbolCount(uint32_t* gnu_hash);
void loadSymbols(bool use_debug);
bool loadSymbolsUsingBuildId();
bool loadSymbolsUsingDebugLink();
void loadSymbolTable(const char* symbols, size_t total_size, size_t ent_size, const char* strings);
void addRelocationSymbols(ElfSection* reltab, const char* plt);
public:
static void parseProgramHeaders(CodeCache* cc, const char* base, const char* end, bool relocate_dyn);
static bool parseFile(CodeCache* cc, const char* base, const char* file_name, bool use_debug);
};
#endif //__linux__