• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdlib.h>
2 #include <fcntl.h>
3 #include <string.h>
4 #include <sys/stat.h>
5 #include <sys/mman.h>
6 
7 #include "symbol_table.h"
8 #include "utility.h"
9 
10 #include <linux/elf.h>
11 
12 // Compare func for qsort
qcompar(const void * a,const void * b)13 static int qcompar(const void *a, const void *b)
14 {
15     return ((struct symbol*)a)->addr - ((struct symbol*)b)->addr;
16 }
17 
18 // Compare func for bsearch
bcompar(const void * addr,const void * element)19 static int bcompar(const void *addr, const void *element)
20 {
21     struct symbol *symbol = (struct symbol*)element;
22 
23     if((unsigned int)addr < symbol->addr) {
24         return -1;
25     }
26 
27     if((unsigned int)addr - symbol->addr >= symbol->size) {
28         return 1;
29     }
30 
31     return 0;
32 }
33 
34 /*
35  *  Create a symbol table from a given file
36  *
37  *  Parameters:
38  *      filename - Filename to process
39  *
40  *  Returns:
41  *      A newly-allocated SymbolTable structure, or NULL if error.
42  *      Free symbol table with symbol_table_free()
43  */
symbol_table_create(const char * filename)44 struct symbol_table *symbol_table_create(const char *filename)
45 {
46     struct symbol_table *table = NULL;
47 
48     // Open the file, and map it into memory
49     struct stat sb;
50     int length;
51     char *base;
52 
53     XLOG2("Creating symbol table for %s\n", filename);
54     int fd = open(filename, O_RDONLY);
55 
56     if(fd < 0) {
57         goto out;
58     }
59 
60     fstat(fd, &sb);
61     length = sb.st_size;
62 
63     base = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
64 
65     if(!base) {
66         goto out_close;
67     }
68 
69     // Parse the file header
70     Elf32_Ehdr *hdr = (Elf32_Ehdr*)base;
71     Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
72 
73     // Search for the dynamic symbols section
74     int sym_idx = -1;
75     int dynsym_idx = -1;
76     int i;
77 
78     for(i = 0; i < hdr->e_shnum; i++) {
79         if(shdr[i].sh_type == SHT_SYMTAB ) {
80             sym_idx = i;
81         }
82         if(shdr[i].sh_type == SHT_DYNSYM ) {
83             dynsym_idx = i;
84         }
85     }
86     if ((dynsym_idx == -1) && (sym_idx == -1)) {
87         goto out_unmap;
88     }
89 
90     table = malloc(sizeof(struct symbol_table));
91     if(!table) {
92         goto out_unmap;
93     }
94     table->name = strdup(filename);
95     table->num_symbols = 0;
96 
97     Elf32_Sym *dynsyms = NULL;
98     Elf32_Sym *syms = NULL;
99     int dynnumsyms = 0;
100     int numsyms = 0;
101     char *dynstr = NULL;
102     char *str = NULL;
103 
104     if (dynsym_idx != -1) {
105         dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
106         dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
107         int dynstr_idx = shdr[dynsym_idx].sh_link;
108         dynstr = base + shdr[dynstr_idx].sh_offset;
109     }
110 
111     if (sym_idx != -1) {
112         syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
113         numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
114         int str_idx = shdr[sym_idx].sh_link;
115         str = base + shdr[str_idx].sh_offset;
116     }
117 
118     int symbol_count = 0;
119     int dynsymbol_count = 0;
120 
121     if (dynsym_idx != -1) {
122         // Iterate through the dynamic symbol table, and count how many symbols
123         // are actually defined
124         for(i = 0; i < dynnumsyms; i++) {
125             if(dynsyms[i].st_shndx != SHN_UNDEF) {
126                 dynsymbol_count++;
127             }
128         }
129         XLOG2("Dynamic Symbol count: %d\n", dynsymbol_count);
130     }
131 
132     if (sym_idx != -1) {
133         // Iterate through the symbol table, and count how many symbols
134         // are actually defined
135         for(i = 0; i < numsyms; i++) {
136             if((syms[i].st_shndx != SHN_UNDEF) &&
137                 (strlen(str+syms[i].st_name)) &&
138                 (syms[i].st_value != 0) && (syms[i].st_size != 0)) {
139                 symbol_count++;
140             }
141         }
142         XLOG2("Symbol count: %d\n", symbol_count);
143     }
144 
145     // Now, create an entry in our symbol table structure for each symbol...
146     table->num_symbols += symbol_count + dynsymbol_count;
147     table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
148     if(!table->symbols) {
149         free(table);
150         table = NULL;
151         goto out_unmap;
152     }
153 
154 
155     int j = 0;
156     if (dynsym_idx != -1) {
157         // ...and populate them
158         for(i = 0; i < dynnumsyms; i++) {
159             if(dynsyms[i].st_shndx != SHN_UNDEF) {
160                 table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
161                 table->symbols[j].addr = dynsyms[i].st_value;
162                 table->symbols[j].size = dynsyms[i].st_size;
163                 XLOG2("name: %s, addr: %x, size: %x\n",
164                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
165                 j++;
166             }
167         }
168     }
169 
170     if (sym_idx != -1) {
171         // ...and populate them
172         for(i = 0; i < numsyms; i++) {
173             if((syms[i].st_shndx != SHN_UNDEF) &&
174                 (strlen(str+syms[i].st_name)) &&
175                 (syms[i].st_value != 0) && (syms[i].st_size != 0)) {
176                 table->symbols[j].name = strdup(str + syms[i].st_name);
177                 table->symbols[j].addr = syms[i].st_value;
178                 table->symbols[j].size = syms[i].st_size;
179                 XLOG2("name: %s, addr: %x, size: %x\n",
180                     table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
181                 j++;
182             }
183         }
184     }
185 
186     // Sort the symbol table entries, so they can be bsearched later
187     qsort(table->symbols, table->num_symbols, sizeof(struct symbol), qcompar);
188 
189 out_unmap:
190     munmap(base, length);
191 
192 out_close:
193     close(fd);
194 
195 out:
196     return table;
197 }
198 
199 /*
200  * Free a symbol table
201  *
202  * Parameters:
203  *     table - Table to free
204  */
symbol_table_free(struct symbol_table * table)205 void symbol_table_free(struct symbol_table *table)
206 {
207     int i;
208 
209     if(!table) {
210         return;
211     }
212 
213     for(i=0; i<table->num_symbols; i++) {
214         free(table->symbols[i].name);
215     }
216 
217     free(table->symbols);
218     free(table);
219 }
220 
221 /*
222  * Search for an address in the symbol table
223  *
224  * Parameters:
225  *      table - Table to search in
226  *      addr - Address to search for.
227  *
228  * Returns:
229  *      A pointer to the Symbol structure corresponding to the
230  *      symbol which contains this address, or NULL if no symbol
231  *      contains it.
232  */
symbol_table_lookup(struct symbol_table * table,unsigned int addr)233 const struct symbol *symbol_table_lookup(struct symbol_table *table, unsigned int addr)
234 {
235     if(!table) {
236         return NULL;
237     }
238 
239     return bsearch((void*)addr, table->symbols, table->num_symbols, sizeof(struct symbol), bcompar);
240 }
241