2 #include <featureTests.h>
3 #ifdef ROSE_ENABLE_BINARY_ANALYSIS
4 #include "sage3basic.h"
6 #include <Rose/Diagnostics.h>
10 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
23 ASSERT_not_null(fhdr);
24 ASSERT_not_null(symtab);
25 ASSERT_not_null(strtab);
29 static uint8_t zeroRecord[COFFSymbol_disk_size];
30 memset(zeroRecord, 0,
sizeof zeroRecord);
33 if (0 == memcmp(&disk, zeroRecord, COFFSymbol_disk_size))
34 throw FormatError(
"zero symbol record");
36 if (disk.st_zero == 0) {
37 p_st_name_offset = ByteOrder::le_to_host(disk.st_offset);
38 if (p_st_name_offset < 4)
39 throw FormatError(
"name collides with size field");
44 memcpy(temp, disk.st_name, 8);
50 p_st_name =
get_name()->get_string();
51 p_st_section_num = ByteOrder::le_to_host(disk.st_section_num);
52 p_st_type = ByteOrder::le_to_host(disk.st_type);
53 p_st_storage_class = ByteOrder::le_to_host(disk.st_storage_class);
54 p_st_num_aux_entries = ByteOrder::le_to_host(disk.st_num_aux_entries);
58 if (p_st_section_num > 0) {
62 <<
" is not bound to any section (section " <<p_st_section_num <<
")\n";
67 p_value = ByteOrder::le_to_host(disk.st_value);
68 p_def_state = SYM_DEFINED;
69 switch (p_st_storage_class) {
70 case 0: p_binding = SYM_NO_BINDING;
break;
71 case 1: p_binding = SYM_LOCAL;
break;
72 case 2: p_binding = SYM_GLOBAL;
break;
73 case 3: p_binding = SYM_GLOBAL;
break;
74 case 4: p_binding = SYM_LOCAL;
break;
75 case 5: p_binding = SYM_GLOBAL;
break;
76 case 6: p_binding = SYM_LOCAL;
break;
77 case 7: p_binding = SYM_LOCAL;
break;
78 case 8: p_binding = SYM_LOCAL;
break;
79 case 9: p_binding = SYM_LOCAL;
break;
80 case 10: p_binding = SYM_LOCAL;
break;
81 case 11: p_binding = SYM_LOCAL;
break;
82 case 12: p_binding = SYM_GLOBAL;
break;
83 case 13: p_binding = SYM_GLOBAL;
break;
84 case 14: p_binding = SYM_GLOBAL;
break;
85 case 15: p_binding = SYM_GLOBAL;
break;
86 case 16: p_binding = SYM_LOCAL;
break;
87 case 17: p_binding = SYM_GLOBAL;
break;
88 case 18: p_binding = SYM_LOCAL;
break;
89 case 100: p_binding = SYM_GLOBAL;
break;
90 case 101: p_binding = SYM_GLOBAL;
break;
91 case 102: p_binding = SYM_LOCAL;
break;
92 case 103: p_binding = SYM_GLOBAL;
break;
93 case 104: p_binding = SYM_GLOBAL;
break;
94 case 105: p_binding = SYM_WEAK;
break;
95 case 107: p_binding = SYM_LOCAL;
break;
96 case 0xff: p_binding = SYM_GLOBAL;
break;
98 switch (p_st_type & 0xf0) {
99 case 0x00: p_type = SYM_NO_TYPE;
break;
100 case 0x10: p_type = SYM_DATA;
break;
101 case 0x20: p_type = SYM_FUNC;
break;
102 case 0x30: p_type = SYM_ARRAY;
break;
106 debug <<
"COFF symbol entry #" <<idx <<
" before AUX parsing"
107 <<
": p_st_name_offset=" <<p_st_name_offset
109 <<
", p_st_section_num=" <<p_st_section_num
110 <<
", p_st_type=" <<p_st_type
111 <<
", p_st_storage_class=" <<p_st_storage_class
112 <<
", p_st_num_aux_entries=" <<p_st_num_aux_entries
113 <<
", p_value=" <<p_value
114 <<
", p_def_state=" <<p_def_state
115 <<
", p_binding=" <<p_binding
116 <<
", p_type=" <<p_type <<
"\n";
120 if (p_st_num_aux_entries > 0) {
121 p_aux_data = symtab->
read_content_local_ucl((idx+1)*COFFSymbol_disk_size, p_st_num_aux_entries * COFFSymbol_disk_size);
123 if (2 == p_st_storage_class && get_type() == SYM_FUNC && p_st_section_num > 0) {
125 unsigned bf_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
126 unsigned size = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[4]));
127 unsigned lnum_ptr = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
128 unsigned next_fn_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12]));
129 unsigned res1 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
131 SAWYER_MESG(debug) <<
"COFF aux func " <<escapeString(p_st_name) <<
": bf_idx=" <<bf_idx
133 <<
", next_fn_idx=" <<next_fn_idx <<
", res1=" <<res1 <<
"\n";
135 }
else if (p_st_storage_class == 101 && (p_st_name ==
".bf" || p_st_name ==
".ef")) {
137 unsigned res1 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
138 unsigned lnum = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[4]));
139 unsigned res2 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[6]));
140 unsigned res3 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
141 unsigned next_bf = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12]));
142 unsigned res4 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
143 SAWYER_MESG(debug) <<
"COFF aux " <<escapeString(p_st_name) <<
": res1=" <<res1 <<
", lnum=" <<lnum
144 <<
", res2=" <<res2 <<
", res3=" <<res3 <<
", next_bf=" <<next_bf <<
", res4=" <<res4 <<
"\n";
146 }
else if (p_st_storage_class == 2 && p_st_section_num == 0 && get_value()==0) {
148 unsigned sym2_idx = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
149 unsigned flags = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[4]));
150 unsigned res1 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
151 unsigned res2 = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[12]));
152 unsigned res3 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
153 SAWYER_MESG(debug) <<
"COFF aux weak " <<escapeString(p_st_name) <<
": sym2_idx=" <<sym2_idx
154 <<
", flags=" <<flags <<
", res1=" <<res1 <<
", res2=" <<res2 <<
", res3=" <<res3 <<
"\n";
156 }
else if (p_st_storage_class == 103 && 0 == p_st_name.compare(
".file")) {
159 const COFFSymbol_disk *d = (
const COFFSymbol_disk*) &(p_aux_data[0]);
160 if (0 == d->st_zero) {
161 rose_addr_t fname_offset = ByteOrder::le_to_host(d->st_offset);
162 if (fname_offset < 4)
163 throw FormatError(
"name collides with size field");
165 SAWYER_MESG(debug) <<
"COFF aux file: offset=" <<fname_offset
166 <<
", name=\"" <<
get_name()->get_string(
true) <<
"\"\n";
170 ASSERT_require(p_st_num_aux_entries == 1);
171 char fname[COFFSymbol_disk_size+1];
172 memcpy(fname, &(p_aux_data[0]), COFFSymbol_disk_size);
173 fname[COFFSymbol_disk_size] =
'\0';
175 SAWYER_MESG(debug) <<
"COFF aux file: inline-name=\"" <<
get_name()->get_string(
true) <<
"\"\n";
181 unsigned size = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[0]));
182 unsigned nrel = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[4]));
183 unsigned nln_ents = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[6]));
184 unsigned cksum = ByteOrder::le_to_host(*(uint32_t*)&(p_aux_data[8]));
185 unsigned sect_id = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[12]));
186 unsigned comdat = p_aux_data[14];
187 unsigned res1 = p_aux_data[15];
188 unsigned res2 = ByteOrder::le_to_host(*(uint16_t*)&(p_aux_data[16]));
190 set_type(SYM_SECTION);
191 SAWYER_MESG(debug) <<
"COFF aux section: size=" <<size <<
", nrel=" <<nrel <<
", nln_ents=" <<nln_ents
192 <<
", cksum=" <<cksum <<
", sect_id=" <<sect_id <<
", comdat=" <<comdat
193 <<
", res1=" <<res1 <<
", res2=" <<res2 <<
"\n";
195 }
else if (p_st_storage_class==3 && (p_st_type & 0xf)==0 &&
200 debug <<
"COFF aux comdat " <<escapeString(p_st_name) <<
": aux record ignored\n";
201 hexdump(debug, (rose_addr_t) symtab->
get_offset()+(idx+1)*COFFSymbol_disk_size,
" ", p_aux_data);
206 mlog[WARN] <<
"COFF aux unknown " <<escapeString(p_st_name)
207 <<
": st_storage_class=" <<p_st_storage_class
208 <<
", st_type=" <<p_st_type <<
", st_section_num=" <<p_st_section_num <<
"\n";
209 hexdump(
mlog[WARN], symtab->
get_offset()+(idx+1)*COFFSymbol_disk_size,
" ", p_aux_data);
217 SgAsmCoffSymbol::encode(COFFSymbol_disk *disk)
const
219 if (0 == p_st_name_offset) {
221 memset(disk->st_name, 0,
sizeof(disk->st_name));
222 ROSE_ASSERT(p_st_name.size() <=
sizeof(disk->st_name));
223 memcpy(disk->st_name, p_st_name.c_str(), p_st_name.size());
227 ByteOrder::host_to_le(p_st_name_offset, &(disk->st_offset));
231 ByteOrder::host_to_le(p_value, &(disk->st_value));
232 ByteOrder::host_to_le(p_st_section_num, &(disk->st_section_num));
233 ByteOrder::host_to_le(p_st_type, &(disk->st_type));
234 ByteOrder::host_to_le(p_st_storage_class, &(disk->st_storage_class));
235 ByteOrder::host_to_le(p_st_num_aux_entries, &(disk->st_num_aux_entries));
243 char p[4096], ss[128], tt[128];
244 const char *s=NULL, *t=NULL;
246 sprintf(p,
"%sCOFFSymbol[%zd].", prefix, idx);
248 sprintf(p,
"%sCOFFSymbol.", prefix);
251 const int w = std::max(1, DUMP_FIELD_WIDTH-(
int)strlen(p));
256 switch (p_st_section_num) {
257 case 0: s =
"external, not assigned";
break;
258 case -1: s =
"absolute value";
break;
259 case -2: s =
"general debug, no section";
break;
260 default: sprintf(ss,
"%d", p_st_section_num); s = ss;
break;
262 fprintf(f,
"%s%-*s = %s\n", p, w,
"st_section_num", s);
264 switch (p_st_type & 0xf0) {
265 case 0x00: s =
"none";
break;
266 case 0x10: s =
"pointer";
break;
267 case 0x20: s =
"function";
break;
268 case 0x30: s =
"array";
break;
270 sprintf(ss,
"%u", p_st_type >> 8);
274 switch (p_st_type & 0xf) {
275 case 0x00: t =
"none";
break;
276 case 0x01: t =
"void";
break;
277 case 0x02: t =
"char";
break;
278 case 0x03: t =
"short";
break;
279 case 0x04: t =
"int";
break;
280 case 0x05: t =
"long";
break;
281 case 0x06: t =
"float";
break;
282 case 0x07: t =
"double";
break;
283 case 0x08: t =
"struct";
break;
284 case 0x09: t =
"union";
break;
285 case 0x0a: t =
"enum";
break;
286 case 0x0b: t =
"enum member";
break;
287 case 0x0c: t =
"byte";
break;
288 case 0x0d: t =
"2-byte word";
break;
289 case 0x0e: t =
"unsigned int";
break;
290 case 0x0f: t =
"4-byte unsigned";
break;
292 sprintf(tt,
"%u", p_st_type & 0xf);
296 fprintf(f,
"%s%-*s = %s / %s\n", p, w,
"st_type", s, t);
298 switch (p_st_storage_class) {
299 case 0: s =
"none"; t =
"";
break;
300 case 1: s =
"auto variable"; t =
"stack frame offset";
break;
301 case 2: s =
"external"; t =
"size or section offset";
break;
302 case 3: s =
"static"; t =
"offset in section or section name";
break;
303 case 4: s =
"register"; t =
"register number";
break;
304 case 5: s =
"extern_def"; t =
"";
break;
305 case 6: s =
"label"; t =
"offset in section";
break;
306 case 7: s =
"label(undef)"; t =
"";
break;
307 case 8: s =
"struct member"; t =
"member number";
break;
308 case 9: s =
"formal arg"; t =
"argument number";
break;
309 case 10: s =
"struct tag"; t =
"tag name";
break;
310 case 11: s =
"union member"; t =
"member number";
break;
311 case 12: s =
"union tag"; t =
"tag name";
break;
312 case 13: s =
"typedef"; t =
"";
break;
313 case 14: s =
"static(undef)"; t =
"";
break;
314 case 15: s =
"enum tag"; t =
"";
break;
315 case 16: s =
"enum member"; t =
"member number";
break;
316 case 17: s =
"register param"; t =
"";
break;
317 case 18: s =
"bit field"; t =
"bit number";
break;
318 case 19: s =
"auto arg"; t =
"";
break;
319 case 20: s =
"dummy entry (EOB)"; t=
"";
break;
320 case 100: s =
"block(bb,eb)"; t =
"relocatable address";
break;
321 case 101: s =
"function"; t =
"nlines or size";
break;
322 case 102: s =
"struct end"; t =
"";
break;
323 case 103: s =
"file"; t =
"";
break;
324 case 104: s =
"section/line#"; t =
"";
break;
325 case 105: s =
"weak extern"; t =
"";
break;
326 case 106: s =
"ext in dmert pub lib";t=
"";
break;
327 case 107: s =
"CLR token"; t =
"";
break;
328 case 0xff: s =
"end of function"; t =
"";
break;
330 sprintf(ss,
"%u", p_st_storage_class);
335 fprintf(f,
"%s%-*s = %s\n", p, w,
"st_storage_class", s);
336 fprintf(f,
"%s%-*s = \"%s\"\n", p, w,
"st_name", escapeString(p_st_name).c_str());
337 fprintf(f,
"%s%-*s = %u\n", p, w,
"st_num_aux_entries", p_st_num_aux_entries);
338 fprintf(f,
"%s%-*s = %" PRIuPTR
" bytes\n", p, w,
"aux_data", p_aux_data.size());
339 hexdump(f, 0, std::string(p)+
"aux_data at ", p_aux_data);
344 SgAsmCoffSymbolTable::ctor()
346 set_synthesized(
true);
348 set_purpose(SP_SYMTAB);
355 SgAsmCoffSymbolTable::parse()
359 ROSE_ASSERT(fhdr!=NULL);
363 SgAsmGenericSection::parse();
367 rose_addr_t strtab_offset = get_offset() + fhdr->
get_e_coff_nsyms() * SgAsmCoffSymbol::COFFSymbol_disk_size;
370 p_strtab->set_size(
sizeof(uint32_t));
371 p_strtab->set_synthesized(
true);
373 p_strtab->set_purpose(SP_HEADER);
377 p_strtab->read_content(0, &word,
sizeof word);
378 rose_addr_t strtab_size = ByteOrder::le_to_host(word);
379 if (strtab_size <
sizeof(uint32_t))
380 throw FormatError(
"COFF symbol table string table size is less than four bytes");
381 p_strtab->extend(strtab_size -
sizeof(uint32_t));
387 i += symbol->get_st_num_aux_entries();
388 p_symbols->get_symbols().push_back(symbol);
389 }
catch (
const FormatError &e) {
390 mlog[
WARN] <<
"SgAsmCoffSymbolTable::parse: invalid symbol: " <<e.what() <<
"\n"
391 <<
" in section \"" <<
get_name()->get_string(
true) <<
"\"[" <<get_id() <<
"]\n"
392 <<
" symbol #" <<i <<
" at file offset "
394 <<
" discarding this symbol\n";
395 }
catch (
const ShortRead &e) {
396 mlog[
WARN] <<
"SgAsmCoffSymbolTable::parse: read past end of section \"" <<
get_name()->get_string(
true) <<
"\""
397 <<
"[" <<get_id() <<
"]\n"
400 <<
" (including this one)\n";
413 size_t nsyms = p_symbols->get_symbols().size();
414 size_t nslots = nsyms;
415 for (
size_t i=0; i<nsyms; i++) {
417 nslots += symbol->get_st_num_aux_entries();
426 rose_addr_t spos = 0;
428 for (
size_t i=0; i < p_symbols->get_symbols().size(); i++) {
431 symbol->encode(&disk);
432 spos = write(f, spos, SgAsmCoffSymbol::COFFSymbol_disk_size, &disk);
433 spos = write(f, (rose_addr_t) spos, symbol->get_aux_data());
436 get_strtab()->unparse(f);
445 sprintf(p,
"%sCOFFSymtab[%zd].", prefix, idx);
447 sprintf(p,
"%sCOFFSymtab.", prefix);
451 const int w = std::max(1, DUMP_FIELD_WIDTH-(
int)strlen(p));
454 fprintf(f,
"%s%-*s = %" PRIuPTR
" symbols\n", p, w,
"size", p_symbols->get_symbols().size());
455 for (
size_t i = 0; i < p_symbols->get_symbols().size(); i++) {
456 p_symbols->get_symbols()[i]->dump(f, p, i);
459 if (variantT() == V_SgAsmCoffSymbolTable)
460 hexdump(f, 0, std::string(p)+
"data at ", p_data);
std::string read_content_local_str(rose_addr_t rel_offset, bool strict=true)
Reads a string from the file.
SgAsmGenericFile * get_file() const
Property: File to which this section belongs.
String associated with a binary file.
Contiguous region of a file.
std::string plural(T n, const std::string &plural_phrase, const std::string &singular_phrase="")
Helpful way to print singular or plural words.
SgUnsignedCharList read_content_local_ucl(rose_addr_t rel_offset, rose_addr_t size)
Reads content of a section and returns it as a container.
virtual void unparse(std::ostream &) const
Write a section back to the file.
ROSE_DLL_API Sawyer::Message::Facility mlog
Diagnostic facility for the ROSE library as a whole.
size_t read_content_local(rose_addr_t rel_offset, void *dst_buf, rose_addr_t size, bool strict=true)
Reads data from a file.
void set_parent(SgNode *parent)
All nodes in the AST contain a reference to a parent node.
SgAsmGenericSection * get_section_by_name(const std::string &, char sep=0, size_t *nfound=0) const
Find section by name.
rose_addr_t get_offset() const
Property: Offset to start of section in file.
std::string get_name(const SgNode *node)
Generate a useful name to describe the SgNode.
Main namespace for the ROSE library.
ROSE_UTIL_API std::string cEscape(const std::string &, char context= '"')
Escapes characters that are special to C/C++.
ROSE_DLL_API int set_name(SgInitializedName *initializedNameNode, SgName new_name)
set_name of symbol in symbol table.
virtual void set_offset(rose_addr_t)
Property: Offset to start of section in file.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const
Print some debugging info.
virtual void dump(FILE *f, const char *prefix, ssize_t idx) const $ROSE_OVERRIDE
Print some debugging info.
size_t get_nslots() const
Returns the number of COFF Symbol Table slots occupied by the symbol table.
ROSE_UTIL_API std::string addrToString(uint64_t value, size_t nbits=0)
Convert a virtual address to a string.
Warning messages that indicate an unusual situation from which the program was able to fully recover...
Converts text to messages.
Controls diagnostic messages from ROSE.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const
Print some debugging info.
SgAsmGenericSection * get_section_by_id(int id, size_t *nfound=0) const
Find section with specified ID.