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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
/* symtab.c
* This file is part of decomp - a disassembler. This file contains
* routines for parsing the symbol table.
*
* Copyright (C) 2001 Jonathan duSaint <dusaint@earthlink.net>
*
* Started around 10 December 2001.
*/
#include <stdio.h>
#include <string.h>
#include <elf.h>
#include "decomp.h"
#define LOCAL_LABEL_SIZE 32
/* create_mem_ref
* Internal subroutine. Creates a symbol of type TYPE at virtual address
* VADDR and inserts it into SYMTAB, returning the new symbol.
*/
struct symtab *
create_mem_ref (hash_t symtab, unsigned long vaddr, enum symbol_type type)
{
static unsigned long label_value = 0;
struct symtab *sym;
sym = xmalloc (sizeof (struct symtab));
sym->name = xmalloc (LOCAL_LABEL_SIZE);
sprintf (sym->name, "L%ld", label_value++);
sym->address = vaddr;
sym->size = 0;
sym->idx = 0;
sym->type = type;
hash_add (symtab, vaddr, sym);
return sym;
}
/* create_jump_ref
* This is called when there is a jmp or a call instruction with
* an unnamed destination. A local label is created and
* inserted into SYMTAB with the key VADDR.
*/
struct symtab *
create_jump_ref (hash_t symtab, unsigned long vaddr)
{
return create_mem_ref (symtab, vaddr, LOCAL_UNKNOWN);
}
/* create_data_ref
* This is used to create a label for unnamed data that is referenced
* somewhere in code.
*/
struct symtab *
create_data_ref (hash_t symtab, unsigned long vaddr)
{
return create_mem_ref (symtab, vaddr, LOCAL_DATA);
}
#define N_SECTION_LIMITS 64
struct section_limits {
unsigned long low;
unsigned long high;
};
struct section_limits **limits = NULL;
/* check_is_data
* If VADDR is a virtual address value that is within a data section,
* then return 1, otherwise return 0.
*/
int
check_is_data (unsigned long vaddr)
{
int k = -1;
if (debug)
printf ("checking limit %#lx... ", vaddr);
while (limits[++k] != NULL)
if (vaddr >= limits[k]->low && vaddr <= limits[k]->high)
{
if (debug)
printf ("ok\n");
return 1;
}
if (debug)
printf ("no\n");
return 0;
}
/* put_data_limits
* Store the start and end virtual address of a section so that value
* references in code can be determined to be in a data section or not.
*/
void
put_data_limits (unsigned long low, unsigned long high)
{
int k = -1;
if (limits == NULL)
limits = xmalloc (sizeof (struct section_limits *) * N_SECTION_LIMITS);
/* find an empty slot */
while (limits[++k] != NULL);
limits[k] = xmalloc (sizeof (struct section_limits));
limits[k]->low = low;
limits[k]->high = high;
if (debug)
printf ("adding section limits: %#lx - %#lx\n", low, high);
}
/* has_precedence
* Determine if SYM has precedence over OLD_SYM.
*/
int
has_precedence (struct symtab *sym, struct symtab *old_sym)
{
return ((sym->type < LOCAL_UNKNOWN && old_sym->type >= LOCAL_UNKNOWN)
|| (sym->size > 0 && old_sym->size == 0));
}
/* read_strtab
* Read the string table from the object file, if it exists.
*/
char *
read_strtab (struct file_info *fi)
{
switch (fi->file_type)
{
case FT_ELF:
return elf_read_strtab (fi);
/* case FT_AOUT: */
/* return aout_read_strtab (fi); */
case FT_PE:
return pe_read_strtab (fi);
case FT_NE:
return ne_read_strtab (fi);
case FT_MZ:
return mz_read_strtab (fi);
/* case FT_COM: */
/* return com_read_strtab (fi); */
default:
;
}
return NULL;
}
/* get_next_symbol
* Get the next symbol from the object file and return it as a struct symtab.
*/
struct symtab *
get_next_symbol (struct file_info *fi, char *strtab)
{
switch (fi->file_type)
{
case FT_ELF:
return elf_get_next_symbol (fi, strtab);
/* case FT_AOUT: */
/* return aout_get_next_symbol (fi, strtab); */
case FT_PE:
return pe_get_next_symbol (fi, strtab);
case FT_NE:
return ne_get_next_symbol (fi, strtab);
case FT_MZ:
return mz_get_next_symbol (fi, strtab);
/* case FT_COM: */
/* return com_get_next_symbol (fi, strtab); */
default:
;
}
return NULL;
}
/* read_symtab
* Read the symbol table in the object file if it exists.
*/
hash_t
read_symtab (struct file_info *fi)
{
unsigned long k;
char *strtab;
hash_t symtab;
struct symtab *sym, *old_sym;
symtab = hash_new (0);
/* if this program has been stripped, return an empty hash table */
if (fi->symtab == NULL) return symtab;
if (fi->symtab->section_name == 0) return symtab;
/* read in the strtab */
strtab = read_strtab (fi);
/* read in the symtab */
fseek (fi->fp, fi->symtab->section_offset, SEEK_SET);
for (k = 0; k < fi->symtab->section_size / fi->symtab->entsize; k++)
{
sym = get_next_symbol (fi, strtab);
if (sym == NULL) continue;
/* check if there is already a symbol at this location */
/* check the logic here */
old_sym = hash_get (symtab, sym->address);
if (old_sym != NULL)
{
if (has_precedence (sym, old_sym))
{
hash_remove (symtab, old_sym->address);
hash_add (symtab, sym->address, sym);
}
}
else
hash_add (symtab, sym->address, sym);
}
xfree (strtab);
/*if (debug)
hash_print (symtab);*/
return (symtab);
}
/* clean_symtab
* Clean up and deallocate the symbol table.
*/
void
clean_symtab (hash_t symtab)
{
unsigned long key;
struct symtab *sym;
hash_walk (NULL);
while ((key = hash_walk (symtab)) != HASH_END)
{
sym = hash_remove (symtab, key);
xfree (sym->name);
xfree (sym);
}
hash_delete (symtab);
}
|