blob: fd008fe29879faff47e9bfd743d154b50ad8edb1 [file] [log] [blame]
Meng Huae7b91b2009-11-05 16:10:50 -06001#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"
Bruce Beare6cc49232010-10-13 16:11:15 -07008#include "utility.h"
Meng Huae7b91b2009-11-05 16:10:50 -06009
10#include <linux/elf.h>
11
12// Compare func for qsort
13static 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
19static 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 */
44struct 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
Bruce Beare6cc49232010-10-13 16:11:15 -070053 XLOG("Creating symbol table for %s\n", filename);
Meng Huae7b91b2009-11-05 16:10:50 -060054 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
Bruce Beare6cc49232010-10-13 16:11:15 -070074 int sym_idx = -1;
Meng Huae7b91b2009-11-05 16:10:50 -060075 int dynsym_idx = -1;
76 int i;
77
78 for(i = 0; i < hdr->e_shnum; i++) {
Bruce Beare6cc49232010-10-13 16:11:15 -070079 if(shdr[i].sh_type == SHT_SYMTAB ) {
80 sym_idx = i;
81 }
Meng Huae7b91b2009-11-05 16:10:50 -060082 if(shdr[i].sh_type == SHT_DYNSYM ) {
83 dynsym_idx = i;
84 }
85 }
Bruce Beare6cc49232010-10-13 16:11:15 -070086 if ((dynsym_idx == -1) && (sym_idx == -1)) {
Meng Huae7b91b2009-11-05 16:10:50 -060087 goto out_unmap;
88 }
89
Meng Huae7b91b2009-11-05 16:10:50 -060090 table = malloc(sizeof(struct symbol_table));
91 if(!table) {
92 goto out_unmap;
93 }
Bruce Beare6cc49232010-10-13 16:11:15 -070094 table->name = strdup(filename);
Meng Huae7b91b2009-11-05 16:10:50 -060095 table->num_symbols = 0;
96
Mike Dodd584b8e32010-12-14 12:16:23 -080097 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;
Bruce Beare6cc49232010-10-13 16:11:15 -0700103
Mike Dodd584b8e32010-12-14 12:16:23 -0800104 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 }
Meng Huae7b91b2009-11-05 16:10:50 -0600110
Mike Dodd584b8e32010-12-14 12:16:23 -0800111 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 }
Bruce Beare6cc49232010-10-13 16:11:15 -0700117
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 XLOG("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 XLOG("Symbol count: %d\n", symbol_count);
143 }
Meng Huae7b91b2009-11-05 16:10:50 -0600144
145 // Now, create an entry in our symbol table structure for each symbol...
Mike Dodd584b8e32010-12-14 12:16:23 -0800146 table->num_symbols += symbol_count + dynsymbol_count;
Meng Huae7b91b2009-11-05 16:10:50 -0600147 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
Bruce Beare6cc49232010-10-13 16:11:15 -0700154
Meng Huae7b91b2009-11-05 16:10:50 -0600155 int j = 0;
Bruce Beare6cc49232010-10-13 16:11:15 -0700156 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 XLOG("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 XLOG("name: %s, addr: %x, size: %x\n",
180 table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
181 j++;
182 }
Meng Huae7b91b2009-11-05 16:10:50 -0600183 }
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
189out_unmap:
190 munmap(base, length);
191
192out_close:
193 close(fd);
194
195out:
196 return table;
197}
198
199/*
200 * Free a symbol table
201 *
202 * Parameters:
203 * table - Table to free
204 */
205void 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 */
233const 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}