ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PeSymbolTable.C
Go to the documentation of this file.
1 /* Windows PE COFF Symbol Tables (SgAsmCoffSymbolTable and related objects) */
2 
3 #include "sage3basic.h"
4 
5 /* Constructor reads symbol table entries beginning at entry 'i'. We can't pass an array of COFFSymbolEntry_disk structs
6  * because the disk size is 18 bytes, which is not properly aligned according to the C standard. Therefore we pass the actual
7  * section and table index. The symbol occupies the specified table slot and st_num_aux_entries additional slots. */
8 void
10 {
11  static const bool debug = false;
12  COFFSymbol_disk disk;
13  symtab->read_content_local(idx * COFFSymbol_disk_size, &disk, COFFSymbol_disk_size);
14  if (disk.st_zero == 0) {
16  if (p_st_name_offset < 4) throw FormatError("name collides with size field");
17  std::string s = strtab->read_content_local_str(p_st_name_offset);
18  set_name(new SgAsmBasicString(s));
19  } else {
20  char temp[9];
21  memcpy(temp, disk.st_name, 8);
22  temp[8] = '\0';
23  set_name(new SgAsmBasicString(temp));
24  p_st_name_offset = 0;
25  }
26 
32 
33  /* Bind to section number. We can do this now because we've already parsed the PE Section Table */
34  ROSE_ASSERT(fhdr->get_section_table()!=NULL);
35  if (p_st_section_num > 0) {
37  ROSE_ASSERT(p_bound != NULL);
38  }
39 
40  /* Make initial guesses for storage class, type, and definition state. We'll adjust them after reading aux entries. */
43  switch (p_st_storage_class) {
44  case 0: p_binding = SYM_NO_BINDING; break; /*none*/
45  case 1: p_binding = SYM_LOCAL; break; /*stack*/
46  case 2: p_binding = SYM_GLOBAL; break; /*extern*/
47  case 3: p_binding = SYM_GLOBAL; break; /*static*/
48  case 4: p_binding = SYM_LOCAL; break; /*register*/
49  case 5: p_binding = SYM_GLOBAL; break; /*extern def*/
50  case 6: p_binding = SYM_LOCAL; break; /*label*/
51  case 7: p_binding = SYM_LOCAL; break; /*label(undef)*/
52  case 8: p_binding = SYM_LOCAL; break; /*struct member*/
53  case 9: p_binding = SYM_LOCAL; break; /*formal arg*/
54  case 10: p_binding = SYM_LOCAL; break; /*struct tag*/
55  case 11: p_binding = SYM_LOCAL; break; /*union member*/
56  case 12: p_binding = SYM_GLOBAL; break; /*union tag*/
57  case 13: p_binding = SYM_GLOBAL; break; /*typedef*/
58  case 14: p_binding = SYM_GLOBAL; break; /*static(undef)*/
59  case 15: p_binding = SYM_GLOBAL; break; /*enum tag*/
60  case 16: p_binding = SYM_LOCAL; break; /*enum member*/
61  case 17: p_binding = SYM_GLOBAL; break; /*register param*/
62  case 18: p_binding = SYM_LOCAL; break; /*bit field*/
63  case 100: p_binding = SYM_GLOBAL; break; /*block(bb or eb)*/
64  case 101: p_binding = SYM_GLOBAL; break; /*function*/
65  case 102: p_binding = SYM_LOCAL; break; /*struct end*/
66  case 103: p_binding = SYM_GLOBAL; break; /*file*/
67  case 104: p_binding = SYM_GLOBAL; break; /*section*/
68  case 105: p_binding = SYM_WEAK; break; /*weak extern*/
69  case 107: p_binding = SYM_LOCAL; break; /*CLR token*/
70  case 0xff: p_binding = SYM_GLOBAL; break; /*end of function*/
71  }
72  switch (p_st_type & 0xf0) {
73  case 0x00: p_type = SYM_NO_TYPE; break; /*none*/
74  case 0x10: p_type = SYM_DATA; break; /*ptr*/
75  case 0x20: p_type = SYM_FUNC; break; /*function*/
76  case 0x30: p_type = SYM_ARRAY; break; /*array*/
77  }
78 
79  /* Read additional aux entries. We keep this as 'char' to avoid alignment problems. */
80  if (p_st_num_aux_entries > 0) {
81  p_aux_data = symtab->read_content_local_ucl((idx+1)*COFFSymbol_disk_size, p_st_num_aux_entries * COFFSymbol_disk_size);
82 
83  if (get_type() == SYM_FUNC && p_st_section_num > 0) {
84  /* Function */
85  unsigned bf_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
86  unsigned size = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[4]));
87  unsigned lnum_ptr = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
88  unsigned next_fn_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12]));
89  unsigned res1 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
90  set_size(size);
91  if (debug) {
92  fprintf(stderr, "COFF aux func %s: bf_idx=%u, size=%u, lnum_ptr=%u, next_fn_idx=%u, res1=%u\n",
93  escapeString(p_st_name).c_str(), bf_idx, size, lnum_ptr, next_fn_idx, res1);
94  }
95 
96  } else if (p_st_storage_class == 101 /*function*/ && (0 == p_st_name.compare(".bf") || 0 == p_st_name.compare(".ef"))) {
97  /* Beginning/End of function */
98  unsigned res1 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
99  unsigned lnum = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[4])); /*line num within source file*/
100  unsigned res2 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[6]));
101  unsigned res3 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
102  unsigned next_bf = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12])); /*only for .bf; reserved in .ef*/
103  unsigned res4 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
104  if (debug) {
105  fprintf(stderr, "COFF aux %s: res1=%u, lnum=%u, res2=%u, res3=%u, next_bf=%u, res4=%u\n",
106  escapeString(p_st_name).c_str(), res1, lnum, res2, res3, next_bf, res4);
107  }
108 
109  } else if (p_st_storage_class == 2/*external*/ && p_st_section_num == 0/*undef*/ && get_value()==0) {
110  /* Weak External */
111  unsigned sym2_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
112  unsigned flags = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[4]));
113  unsigned res1 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
114  unsigned res2 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12]));
115  unsigned res3 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
116  if (debug) {
117  fprintf(stderr, "COFF aux weak %s: sym2_idx=%u, flags=%u, res1=%u, res2=%u, res3=%u\n",
118  escapeString(p_st_name).c_str(), sym2_idx, flags, res1, res2, res3);
119  }
120 
121  } else if (p_st_storage_class == 103/*file*/ && 0 == p_st_name.compare(".file")) {
122  /* This symbol is a file. The file name is stored in the aux data as either the name itself or an offset
123  * into the string table. Replace the fake ".file" with the real file name. */
124  const COFFSymbol_disk *d = (const COFFSymbol_disk*) &(p_aux_data[0]);
125  if (0 == d->st_zero) {
126  rose_addr_t fname_offset = ByteOrder::le_to_host(d->st_offset);
127  if (fname_offset < 4) throw FormatError("name collides with size field");
128  set_name(new SgAsmBasicString(strtab->read_content_local_str(fname_offset)));
129  if (debug) {
130  fprintf(stderr, "COFF aux file: offset=%"PRIu64", name=\"%s\"\n",
131  fname_offset, get_name()->get_string(true).c_str());
132  }
133  } else {
134  /* Aux data contains a NUL-padded name; the NULs (if any) are not part of the name. */
135  ROSE_ASSERT(p_st_num_aux_entries == 1);
136  char fname[COFFSymbol_disk_size+1];
137  memcpy(fname, &(p_aux_data[0]), COFFSymbol_disk_size);
138  fname[COFFSymbol_disk_size] = '\0';
139  set_name(new SgAsmBasicString(fname));
140  if (debug)
141  fprintf(stderr, "COFF aux file: inline-name=\"%s\"\n", get_name()->get_string(true).c_str());
142  }
144 
145  } else if (p_st_storage_class == 3/*static*/ && NULL != fhdr->get_file()->get_section_by_name(p_st_name, '$')) {
146  /* Section */
147  unsigned size = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0])); /*same as section header SizeOfRawData */
148  unsigned nrel = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[4])); /*number of relocations*/
149  unsigned nln_ents = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[6])); /*number of line number entries */
150  unsigned cksum = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
151  unsigned sect_id = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[12])); /*1-base index into section table*/
152  unsigned comdat = p_aux_data[14]; /*comdat selection number if section is a COMDAT section*/
153  unsigned res1 = p_aux_data[15];
154  unsigned res2 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
155  set_size(size);
157  if (debug) {
158  fprintf(stderr,
159  "COFF aux section: size=%u, nrel=%u, nln_ents=%u, cksum=%u, sect_id=%u, comdat=%u, res1=%u, res2=%u\n",
160  size, nrel, nln_ents, cksum, sect_id, comdat, res1, res2);
161  }
162 
163  } else if (p_st_storage_class==3/*static*/ && (p_st_type & 0xf)==0/*null*/ &&
164  get_value()==0 && NULL!=fhdr->get_file()->get_section_by_name(p_st_name)) {
165  /* COMDAT section */
166  /*FIXME: not implemented yet*/
167  fprintf(stderr, "COFF aux comdat %s: (FIXME) not implemented yet\n", escapeString(p_st_name).c_str());
168  hexdump(stderr, (rose_addr_t) symtab->get_offset()+(idx+1)*COFFSymbol_disk_size, " ", p_aux_data);
169 
170  } else {
171  fprintf(stderr, "COFF aux unknown %s: (FIXME) st_storage_class=%u, st_type=0x%02x, st_section_num=%d\n",
173  hexdump(stderr, symtab->get_offset()+(idx+1)*COFFSymbol_disk_size, " ", p_aux_data);
174  }
175  }
176 
177 }
178 
179 /* Encode a symbol back into disk format */
180 void *
182 {
183  if (0 == p_st_name_offset) {
184  /* Name is stored in entry */
185  memset(disk->st_name, 0, sizeof(disk->st_name));
186  ROSE_ASSERT(p_st_name.size() <= sizeof(disk->st_name));
187  memcpy(disk->st_name, p_st_name.c_str(), p_st_name.size());
188  } else {
189  /* Name is an offset into the string table */
190  disk->st_zero = 0;
192  }
193 
194  // ByteOrder::host_to_le(get_value(), &(disk->st_value));
200  return disk;
201 }
202 
203 /* Print some debugging info */
204 void
205 SgAsmCoffSymbol::dump(FILE *f, const char *prefix, ssize_t idx) const
206 {
207  char p[4096], ss[128], tt[128];
208  const char *s=NULL, *t=NULL;
209  if (idx>=0) {
210  sprintf(p, "%sCOFFSymbol[%zd].", prefix, idx);
211  } else {
212  sprintf(p, "%sCOFFSymbol.", prefix);
213  }
214 
215  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
216 
217 
218  SgAsmGenericSymbol::dump(f, p, -1);
219 
220  switch (p_st_section_num) {
221  case 0: s = "external, not assigned"; break;
222  case -1: s = "absolute value"; break;
223  case -2: s = "general debug, no section"; break;
224  default: sprintf(ss, "%d", p_st_section_num); s = ss; break;
225  }
226  fprintf(f, "%s%-*s = %s\n", p, w, "st_section_num", s);
227 
228  switch (p_st_type & 0xf0) {
229  case 0x00: s = "none"; break;
230  case 0x10: s = "pointer"; break;
231  case 0x20: s = "function"; break;
232  case 0x30: s = "array"; break;
233  default:
234  sprintf(ss, "%u", p_st_type >> 8);
235  s = ss;
236  break;
237  }
238  switch (p_st_type & 0xf) {
239  case 0x00: t = "none"; break;
240  case 0x01: t = "void"; break;
241  case 0x02: t = "char"; break;
242  case 0x03: t = "short"; break;
243  case 0x04: t = "int"; break;
244  case 0x05: t = "long"; break;
245  case 0x06: t = "float"; break;
246  case 0x07: t = "double"; break;
247  case 0x08: t = "struct"; break;
248  case 0x09: t = "union"; break;
249  case 0x0a: t = "enum"; break;
250  case 0x0b: t = "enum member"; break;
251  case 0x0c: t = "byte"; break;
252  case 0x0d: t = "2-byte word"; break;
253  case 0x0e: t = "unsigned int"; break;
254  case 0x0f: t = "4-byte unsigned"; break;
255  default:
256  sprintf(tt, "%u", p_st_type & 0xf);
257  t = tt;
258  break;
259  }
260  fprintf(f, "%s%-*s = %s / %s\n", p, w, "st_type", s, t);
261 
262  switch (p_st_storage_class) {
263  case 0: s = "none"; t = ""; break;
264  case 1: s = "auto variable"; t = "stack frame offset"; break;
265  case 2: s = "external"; t = "size or section offset"; break;
266  case 3: s = "static"; t = "offset in section or section name"; break;
267  case 4: s = "register"; t = "register number"; break;
268  case 5: s = "extern_def"; t = ""; break;
269  case 6: s = "label"; t = "offset in section"; break;
270  case 7: s = "label(undef)"; t = ""; break;
271  case 8: s = "struct member"; t = "member number"; break;
272  case 9: s = "formal arg"; t = "argument number"; break;
273  case 10: s = "struct tag"; t = "tag name"; break;
274  case 11: s = "union member"; t = "member number"; break;
275  case 12: s = "union tag"; t = "tag name"; break;
276  case 13: s = "typedef"; t = ""; break;
277  case 14: s = "static(undef)"; t = ""; break;
278  case 15: s = "enum tag"; t = ""; break;
279  case 16: s = "enum member"; t = "member number"; break;
280  case 17: s = "register param"; t = ""; break;
281  case 18: s = "bit field"; t = "bit number"; break;
282  case 19: s = "auto arg"; t = ""; break;
283  case 20: s = "dummy entry (EOB)"; t=""; break;
284  case 100: s = "block(bb,eb)"; t = "relocatable address"; break;
285  case 101: s = "function"; t = "nlines or size"; break;
286  case 102: s = "struct end"; t = ""; break;
287  case 103: s = "file"; t = ""; break;
288  case 104: s = "section/line#"; t = ""; break;
289  case 105: s = "weak extern"; t = ""; break;
290  case 106: s = "ext in dmert pub lib";t=""; break;
291  case 107: s = "CLR token"; t = ""; break;
292  case 0xff: s = "end of function"; t = ""; break;
293  default:
294  sprintf(ss, "%u", p_st_storage_class);
295  s = ss;
296  t = "";
297  break;
298  }
299  fprintf(f, "%s%-*s = %s\n", p, w, "st_storage_class", s);
300  fprintf(f, "%s%-*s = \"%s\"\n", p, w, "st_name", escapeString(p_st_name).c_str());
301  fprintf(f, "%s%-*s = %u\n", p, w, "st_num_aux_entries", p_st_num_aux_entries);
302  fprintf(f, "%s%-*s = %zu bytes\n", p, w, "aux_data", p_aux_data.size());
303  hexdump(f, 0, std::string(p)+"aux_data at ", p_aux_data);
304 }
305 
306 /* Constructor */
307 void
309 {
310  set_synthesized(true);
311  set_name(new SgAsmBasicString("COFF Symbols"));
313 
315  p_symbols->set_parent(this);
316 }
317 
320 {
321  /* Set the section size according to the number of entries indicated in the header. */
322  SgAsmPEFileHeader *fhdr = dynamic_cast<SgAsmPEFileHeader*>(get_header());
323  ROSE_ASSERT(fhdr!=NULL);
324  set_offset(fhdr->get_e_coff_symtab());
326 
328 
329  /* The string table immediately follows the symbols. The first four bytes of the string table are the size of the
330  * string table in little endian. */
332  p_strtab = new SgAsmGenericSection(fhdr->get_file(), fhdr);
333  p_strtab->set_offset(strtab_offset);
334  p_strtab->set_size(sizeof(uint32_t));
335  p_strtab->set_synthesized(true);
336  p_strtab->set_name(new SgAsmBasicString("COFF Symbol Strtab"));
338  p_strtab->parse();
339 
340  uint32_t word;
341  p_strtab->read_content(0, &word, sizeof word);
342  rose_addr_t strtab_size = ByteOrder::le_to_host(word);
343  if (strtab_size < sizeof(uint32_t))
344  throw FormatError("COFF symbol table string table size is less than four bytes");
345  p_strtab->extend(strtab_size - sizeof(uint32_t));
346 
347  /* Parse symbols until we've parsed the required number or we run off the end of the section. */
348  for (size_t i = 0; i < fhdr->get_e_coff_nsyms(); i++) {
349  try {
350  SgAsmCoffSymbol *symbol = new SgAsmCoffSymbol(fhdr, this, p_strtab, i);
351  i += symbol->get_st_num_aux_entries();
352  p_symbols->get_symbols().push_back(symbol);
353  } catch (const ShortRead &e) {
354  fprintf(stderr, "SgAsmCoffSymbolTable::parse: warning: read past end of section \"%s\" [%d]\n"
355  " symbol #%zu at file offset 0x%08"PRIx64"\n"
356  " skipping %zu symbols (including this one)\n",
357  get_name()->get_string(true).c_str(), get_id(),
358  i, e.offset,
359  fhdr->get_e_coff_nsyms()-i);
360  break;
361  }
362  }
363 
364  return this;
365 }
366 
369 size_t
371 {
372  size_t nsyms = p_symbols->get_symbols().size();
373  size_t nslots = nsyms;
374  for (size_t i=0; i<nsyms; i++) {
375  SgAsmCoffSymbol *symbol = p_symbols->get_symbols()[i];
376  nslots += symbol->get_st_num_aux_entries();
377  }
378  return nslots;
379 }
380 
381 /* Write symbol table back to disk */
382 void
383 SgAsmCoffSymbolTable::unparse(std::ostream &f) const
384 {
385  rose_addr_t spos = 0; /*section offset*/
386 
387  for (size_t i=0; i < p_symbols->get_symbols().size(); i++) {
388  SgAsmCoffSymbol *symbol = p_symbols->get_symbols()[i];
390  symbol->encode(&disk);
391  spos = write(f, spos, SgAsmCoffSymbol::COFFSymbol_disk_size, &disk);
392  spos = write(f, (rose_addr_t) spos, symbol->get_aux_data());
393  }
394  if (get_strtab())
395  get_strtab()->unparse(f);
396 }
397 
398 /* Print some debugging info */
399 void
400 SgAsmCoffSymbolTable::dump(FILE *f, const char *prefix, ssize_t idx) const
401 {
402  char p[4096];
403  if (idx>=0) {
404  sprintf(p, "%sCOFFSymtab[%zd].", prefix, idx);
405  } else {
406  sprintf(p, "%sCOFFSymtab.", prefix);
407  }
408 
409 
410  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
411 
412  SgAsmGenericSection::dump(f, p, -1);
413  fprintf(f, "%s%-*s = %zu symbols\n", p, w, "size", p_symbols->get_symbols().size());
414  for (size_t i = 0; i < p_symbols->get_symbols().size(); i++) {
415  p_symbols->get_symbols()[i]->dump(f, p, i);
416  }
417 
418  if (variantT() == V_SgAsmCoffSymbolTable) //unless a base class
419  hexdump(f, 0, std::string(p)+"data at ", p_data);
420 }