0cf107be0fadcffb31ed376e00983ff706236453
[centaur.git] / src / libelfu / model / symtab.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libelfu/libelfu.h>
5
6
7 int elfu_mSymtabLookupSymToAddr(ElfuElf *me, ElfuScn *msst, ElfuSym *sym, GElf_Addr *result)
8 {
9   char *symname = ELFU_SYMSTR(msst, sym->name);
10
11   switch (sym->type) {
12     case STT_NOTYPE:
13     case STT_OBJECT:
14     case STT_FUNC:
15       if (sym->shndx == SHN_UNDEF) {
16         return -1;
17       } else if (sym->shndx == SHN_ABS) {
18         *result = sym->value;
19         return 0;
20       } else if (sym->shndx == SHN_COMMON) {
21         return -1;
22       } else {
23         ElfuScn *newscn;
24
25         assert (sym->scnptr);
26         newscn = elfu_mScnByOldscn(me, sym->scnptr);
27         assert(newscn);
28         *result = newscn->shdr.sh_addr + sym->value;
29         return 0;
30       }
31       break;
32     case STT_SECTION:
33       assert(sym->scnptr);
34       assert(elfu_mScnByOldscn(me, sym->scnptr));
35       *result = elfu_mScnByOldscn(me, sym->scnptr)->shdr.sh_addr;
36       return 0;
37     case STT_FILE:
38       ELFU_WARN("elfu_mSymtabLookupSymToAddr: Symbol type FILE is not supported.\n");
39       return -1;
40     default:
41       ELFU_WARN("elfu_mSymtabLookupSymToAddr: Unknown symbol type %d for %s.\n", sym->type, symname);
42       return -1;
43   }
44 }
45
46
47
48 char* elfu_mSymtabSymToName(ElfuScn *msst, ElfuSym *sym)
49 {
50   assert(msst);
51   assert(sym);
52
53   return ELFU_SYMSTR(msst, sym->name);
54 }
55
56
57
58 ElfuSym* elfu_mSymtabIndexToSym(ElfuScn *msst, GElf_Word entry)
59 {
60   GElf_Word i;
61   ElfuSym *sym;
62
63   assert(msst);
64   assert(entry > 0);
65   assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
66
67   sym = CIRCLEQ_FIRST(&msst->symtab.syms);
68   for (i = 1; i < entry; i++) {
69     sym = CIRCLEQ_NEXT(sym, elem);
70   }
71
72   return sym;
73 }
74
75
76
77 /* Look up a value in the symbol table section *msst which is in *me. */
78 GElf_Addr elfu_mSymtabLookupAddrByName(ElfuElf *me, ElfuScn *msst, char *name)
79 {
80   ElfuSym *sym;
81
82   assert(me);
83   assert(msst);
84   assert(name);
85   assert(strlen(name) > 0);
86   assert(!CIRCLEQ_EMPTY(&msst->symtab.syms));
87
88   CIRCLEQ_FOREACH(sym, &msst->symtab.syms, elem) {
89     char *symname = ELFU_SYMSTR(msst, sym->name);
90
91     if (!strcmp(symname, name)) {
92       goto SYMBOL_FOUND;
93     }
94   }
95   return 0;
96
97
98   SYMBOL_FOUND:
99
100   switch (sym->type) {
101     case STT_NOTYPE:
102     case STT_OBJECT:
103     case STT_FUNC:
104       if (sym->scnptr) {
105         GElf_Addr a = sym->value;
106         a += me->ehdr.e_type == ET_REL ? sym->scnptr->shdr.sh_addr : 0;
107         return a;
108       } else if (sym->shndx == SHN_UNDEF) {
109         return 0;
110       } else if (sym->shndx == SHN_ABS) {
111         return sym->value;
112       } else {
113         ELFU_WARN("elfu_mSymtabLookupAddrByName: Symbol binding COMMON is not supported, using 0.\n");
114         return 0;
115       }
116       break;
117     default:
118       return 0;
119   }
120 }
121
122
123
124 /* Convert symtab from memory model to elfclass specific format */
125 void elfu_mSymtabFlatten(ElfuElf *me)
126 {
127   ElfuSym *sym;
128   size_t numsyms = 0;
129
130   elfu_mLayoutAuto(me);
131
132   /* Update section indexes and count symbols */
133   CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
134     if (sym->scnptr) {
135       sym->shndx = elfu_mScnIndex(me, sym->scnptr);
136     }
137
138     numsyms++;
139   }
140
141   /* Copy symbols to elfclass-specific format */
142   if (me->elfclass == ELFCLASS32) {
143     size_t newsize = (numsyms + 1) * sizeof(Elf32_Sym);
144     size_t i;
145
146     if (me->symtab->databuf) {
147       free(me->symtab->databuf);
148     }
149     me->symtab->databuf = malloc(newsize);
150     assert(me->symtab->databuf);
151
152     me->symtab->shdr.sh_size = newsize;
153     memset(me->symtab->databuf, 0, newsize);
154
155     i = 1;
156     CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
157       Elf32_Sym *es = ((Elf32_Sym*)me->symtab->databuf) + i;
158
159       es->st_name = sym->name;
160       es->st_value = sym->value;
161       es->st_size = sym->size;
162       es->st_info = ELF32_ST_INFO(sym->bind, sym->type);
163       es->st_other = sym->other;
164       es->st_shndx = sym->shndx;
165
166       i++;
167     }
168   } else if (me->elfclass == ELFCLASS64) {
169     size_t newsize = (numsyms + 1) * sizeof(Elf64_Sym);
170     size_t i;
171
172     if (me->symtab->databuf) {
173       free(me->symtab->databuf);
174     }
175     me->symtab->databuf = malloc(newsize);
176     assert(me->symtab->databuf);
177
178     me->symtab->shdr.sh_size = newsize;
179     memset(me->symtab->databuf, 0, newsize);
180
181     i = 1;
182     CIRCLEQ_FOREACH(sym, &me->symtab->symtab.syms, elem) {
183       Elf64_Sym *es = ((Elf64_Sym*)me->symtab->databuf) + i;
184
185       es->st_name = sym->name;
186       es->st_value = sym->value;
187       es->st_size = sym->size;
188       es->st_info = ELF64_ST_INFO(sym->bind, sym->type);
189       es->st_other = sym->other;
190       es->st_shndx = sym->shndx;
191
192       i++;
193     }
194   } else {
195     /* Unknown elfclass */
196     assert(0);
197   }
198
199   elfu_mLayoutAuto(me);
200 }