ROSE  0.9.9.14
PeFileHeader.C
1 /* Windows PE file header (SgAsmPEFileHeader and related classes) */
2 #include "sage3basic.h"
3 #include "MemoryMap.h"
4 #include "Diagnostics.h"
5 
6 using namespace rose;
7 using namespace rose::Diagnostics;
8 using namespace rose::BinaryAnalysis;
9 
10 /* The __attribute__ mechanism is only supported by GNU compilers */
11 #ifndef __GNUC__
12 #define __attribute__(x) /*NOTHING*/
13 #define __attribute(x) /*NOTHING*/
14 #endif
15 
18 std::string
20 {
21  const char *full="", *abbr="";
22  switch (idx) {
23  case PAIR_EXPORTS: full="Export Table"; abbr="Exports"; break;
24  case PAIR_IMPORTS: full="Import Table"; abbr="Imports"; break;
25  case PAIR_RESOURCES: full="Resource Table"; abbr="Rsrc"; break;
26  case PAIR_EXCEPTIONS: full="Exception Table"; abbr="Excpns"; break;
27  case PAIR_CERTIFICATES: full="Certificate Table"; abbr="Certs"; break;
28  case PAIR_BASERELOCS: full="Base Relocation Table"; abbr="BaseReloc"; break;
29  case PAIR_DEBUG: full="Debug"; abbr="Debug"; break;
30  case PAIR_ARCHITECTURE: full="Architecture"; abbr="Arch"; break;
31  case PAIR_GLOBALPTR: full="Global Ptr"; abbr="GlobPtr"; break;
32  case PAIR_TLS: full="TLS Table"; abbr="TLS"; break;
33  case PAIR_LOADCONFIG: full="Load Config Table"; abbr="LCT"; break;
34  case PAIR_BOUNDIMPORT: full="Bound Import Table"; abbr="BIT"; break;
35  case PAIR_IAT: full="Import Address Table"; abbr="IAT"; break;
36  case PAIR_DELAYIMPORT: full="Delay Import Descriptor"; abbr="DID"; break;
37  case PAIR_CLRRUNTIME: full="CLR Runtime Header"; abbr="CLRHdr"; break;
38  case PAIR_RESERVED15: full="Reserved Pair 15"; abbr="Pair15"; break;
39  // default: NOT PRESENT (it would prevent compiler warnings for newly added enum members)
40  }
41 
42  if (short_name)
43  *short_name = abbr;
44  return full;
45 }
46 
47 /* Construct a new PE File Header with default values. */
48 void
49 SgAsmPEFileHeader::ctor()
50 {
51  ROSE_ASSERT(get_file()!=NULL);
52  ROSE_ASSERT(get_size()>0);
53 
54  set_name(new SgAsmBasicString("PE File Header"));
55  set_synthesized(true);
56  set_purpose(SP_HEADER);
57 
58  p_rvasize_pairs = new SgAsmPERVASizePairList(this);
59 
60  /* Magic number */
61  p_magic.clear();
62  p_magic.push_back('P');
63  p_magic.push_back('E');
64  p_magic.push_back('\0');
65  p_magic.push_back('\0');
66 
67  /* Executable Format */
68  ROSE_ASSERT(p_exec_format!=NULL);
69  p_exec_format->set_family(FAMILY_PE);
70  p_exec_format->set_purpose(PURPOSE_EXECUTABLE);
71  p_exec_format->set_sex(ByteOrder::ORDER_LSB);
72  p_exec_format->set_word_size(4);
73  p_exec_format->set_version(0);
74  p_exec_format->set_is_current_version(true);
75  p_exec_format->set_abi(ABI_NT);
76  p_exec_format->set_abi_version(0);
77 
78  /* Default instruction architecture */
79  p_e_cpu_type = 0x014c; /*i386*/
80  p_isa = ISA_IA32_386;
81 
82  p_e_time = time(NULL);
83  p_e_nt_hdr_size = sizeof(PE32OptHeader_disk);
84 }
85 
89 bool
91 {
92  /* Turn off byte reference tracking for the duration of this function. We don't want our testing the file contents to
93  * affect the list of bytes that we've already referenced or which we might reference later. */
94  bool was_tracking = file->get_tracking_references();
95  file->set_tracking_references(false);
96 
97  try {
98  /* Check DOS File Header magic number at beginning of the file */
99  unsigned char dos_magic[2];
100  file->read_content(0, dos_magic, sizeof dos_magic);
101  if ('M'!=dos_magic[0] || 'Z'!=dos_magic[1])
102  throw 1;
103 
104  /* Read four-byte offset of potential PE File Header at offset 0x3c */
105  uint32_t lfanew_disk;
106  file->read_content(0x3c, &lfanew_disk, sizeof lfanew_disk);
107  rose_addr_t pe_offset = ByteOrder::le_to_host(lfanew_disk);
108 
109  /* Look for the PE File Header magic number */
110  unsigned char pe_magic[4];
111  file->read_content(pe_offset, pe_magic, sizeof pe_magic);
112  if ('P'!=pe_magic[0] || 'E'!=pe_magic[1] || '\0'!=pe_magic[2] || '\0'!=pe_magic[3])
113  throw 1;
114  } catch (...) {
115  file->set_tracking_references(was_tracking);
116  return false;
117  }
118 
119  file->set_tracking_references(was_tracking);
120  return true;
121 }
122 
127 {
128  SgAsmGenericHeader::parse();
129 
130  /* Read header, zero padding if the file isn't large enough */
131  PEFileHeader_disk fh;
132  if (sizeof(fh)>get_size())
133  extend(sizeof(fh)-get_size());
134  if (sizeof(fh)!=read_content_local(0, &fh, sizeof fh, false))
135  mlog[WARN] <<"SgAsmPEFileHeader::parse: short read of PE header at byte "
136  <<StringUtility::addrToString(get_offset()) <<"\n";
137 
138  /* Check magic number before getting too far */
139  if (fh.e_magic[0]!='P' || fh.e_magic[1]!='E' || fh.e_magic[2]!='\0' || fh.e_magic[3]!='\0')
140  throw FormatError("Bad PE magic number");
141 
142  /* Decode COFF file header */
143  p_e_cpu_type = ByteOrder::le_to_host(fh.e_cpu_type);
144  p_e_nsections = ByteOrder::le_to_host(fh.e_nsections);
145  p_e_time = ByteOrder::le_to_host(fh.e_time);
146  p_e_coff_symtab = ByteOrder::le_to_host(fh.e_coff_symtab);
147  p_e_coff_nsyms = ByteOrder::le_to_host(fh.e_coff_nsyms);
148  p_e_nt_hdr_size = ByteOrder::le_to_host(fh.e_nt_hdr_size);
149  p_e_flags = ByteOrder::le_to_host(fh.e_flags);
150 
151  /* Read the "Optional Header" (optional in the sense that not all files have one, but required for an executable), the
152  * size of which is stored in the e_nt_hdr_size of the main PE file header. According to
153  * http://www.phreedom.org/solar/code/tinype the Windows loader honors the e_nt_hdr_size even when set to smaller than the
154  * smallest possible documented size of the optional header. Also it's possible for the optional header to extend beyond
155  * the end of the file, in which case that part should be read as zero. */
156  PE32OptHeader_disk oh32;
157  rose_addr_t need32 = sizeof(PEFileHeader_disk) + std::min(p_e_nt_hdr_size, (rose_addr_t)(sizeof oh32));
158  if (need32>get_size())
159  extend(need32-get_size());
160  if (sizeof(oh32)!=read_content_local(sizeof fh, &oh32, sizeof oh32, false))
161  mlog[WARN] <<"SgAsmPEFileHeader::parse: short read of PE Optional Header at byte "
162  <<StringUtility::addrToString(get_offset() + sizeof(fh)) <<"\n";
163  p_e_opt_magic = ByteOrder::le_to_host(oh32.e_opt_magic);
164 
165  /* File format changes from ctor() */
166  p_exec_format->set_purpose(p_e_flags & HF_PROGRAM ? PURPOSE_EXECUTABLE : PURPOSE_LIBRARY);
167  p_exec_format->set_word_size(0x010b==p_e_opt_magic? 4 : 8);
168 
169  /* Decode the optional header. */
170  rose_addr_t entry_rva;
171  if (4==p_exec_format->get_word_size()) {
172  p_e_lmajor = ByteOrder::le_to_host(oh32.e_lmajor);
173  p_e_lminor = ByteOrder::le_to_host(oh32.e_lminor);
174  p_e_code_size = ByteOrder::le_to_host(oh32.e_code_size);
175  p_e_data_size = ByteOrder::le_to_host(oh32.e_data_size);
176  p_e_bss_size = ByteOrder::le_to_host(oh32.e_bss_size);
177  entry_rva = ByteOrder::le_to_host(oh32.e_entrypoint_rva);
178  p_e_code_rva = ByteOrder::le_to_host(oh32.e_code_rva);
179  p_e_data_rva = ByteOrder::le_to_host(oh32.e_data_rva);
180  p_base_va = ByteOrder::le_to_host(oh32.e_image_base);
181  p_e_section_align = ByteOrder::le_to_host(oh32.e_section_align);
182  p_e_file_align = ByteOrder::le_to_host(oh32.e_file_align);
183  p_e_os_major = ByteOrder::le_to_host(oh32.e_os_major);
184  p_e_os_minor = ByteOrder::le_to_host(oh32.e_os_minor);
185  p_e_user_major = ByteOrder::le_to_host(oh32.e_user_major);
186  p_e_user_minor = ByteOrder::le_to_host(oh32.e_user_minor);
187  p_e_subsys_major = ByteOrder::le_to_host(oh32.e_subsys_major);
188  p_e_subsys_minor = ByteOrder::le_to_host(oh32.e_subsys_minor);
189  p_e_reserved9 = ByteOrder::le_to_host(oh32.e_reserved9);
190  p_e_image_size = ByteOrder::le_to_host(oh32.e_image_size);
191  p_e_header_size = ByteOrder::le_to_host(oh32.e_header_size);
192  p_e_file_checksum = ByteOrder::le_to_host(oh32.e_file_checksum);
193  p_e_subsystem = ByteOrder::le_to_host(oh32.e_subsystem);
194  p_e_dll_flags = ByteOrder::le_to_host(oh32.e_dll_flags);
195  p_e_stack_reserve_size = ByteOrder::le_to_host(oh32.e_stack_reserve_size);
196  p_e_stack_commit_size = ByteOrder::le_to_host(oh32.e_stack_commit_size);
197  p_e_heap_reserve_size = ByteOrder::le_to_host(oh32.e_heap_reserve_size);
198  p_e_heap_commit_size = ByteOrder::le_to_host(oh32.e_heap_commit_size);
199  p_e_loader_flags = ByteOrder::le_to_host(oh32.e_loader_flags);
200  p_e_num_rvasize_pairs = ByteOrder::le_to_host(oh32.e_num_rvasize_pairs);
201  } else if (8==p_exec_format->get_word_size()) {
202  /* We guessed wrong. This is a 64-bit header, not 32-bit. */
203  PE64OptHeader_disk oh64;
204  rose_addr_t need64 = sizeof(PEFileHeader_disk) + std::min(p_e_nt_hdr_size, (rose_addr_t)(sizeof oh64));
205  if (need64>get_size())
206  extend(need64-get_size());
207  if (sizeof(oh64)!=read_content_local(sizeof fh, &oh64, sizeof oh64))
208  mlog[WARN] <<"SgAsmPEFileHeader::parse: short read of PE Optional Header at byte "
209  <<StringUtility::addrToString(get_offset() + sizeof(fh)) <<"\n";
210  p_e_lmajor = ByteOrder::le_to_host(oh64.e_lmajor);
211  p_e_lminor = ByteOrder::le_to_host(oh64.e_lminor);
212  p_e_code_size = ByteOrder::le_to_host(oh64.e_code_size);
213  p_e_data_size = ByteOrder::le_to_host(oh64.e_data_size);
214  p_e_bss_size = ByteOrder::le_to_host(oh64.e_bss_size);
215  entry_rva = ByteOrder::le_to_host(oh64.e_entrypoint_rva);
216  p_e_code_rva = ByteOrder::le_to_host(oh64.e_code_rva);
217  // p_e_data_rva = ByteOrder::le_to_host(oh.e_data_rva); /* not in PE32+ */
218  p_base_va = ByteOrder::le_to_host(oh64.e_image_base);
219  p_e_section_align = ByteOrder::le_to_host(oh64.e_section_align);
220  p_e_file_align = ByteOrder::le_to_host(oh64.e_file_align);
221  p_e_os_major = ByteOrder::le_to_host(oh64.e_os_major);
222  p_e_os_minor = ByteOrder::le_to_host(oh64.e_os_minor);
223  p_e_user_major = ByteOrder::le_to_host(oh64.e_user_major);
224  p_e_user_minor = ByteOrder::le_to_host(oh64.e_user_minor);
225  p_e_subsys_major = ByteOrder::le_to_host(oh64.e_subsys_major);
226  p_e_subsys_minor = ByteOrder::le_to_host(oh64.e_subsys_minor);
227  p_e_reserved9 = ByteOrder::le_to_host(oh64.e_reserved9);
228  p_e_image_size = ByteOrder::le_to_host(oh64.e_image_size);
229  p_e_header_size = ByteOrder::le_to_host(oh64.e_header_size);
230  p_e_file_checksum = ByteOrder::le_to_host(oh64.e_file_checksum);
231  p_e_subsystem = ByteOrder::le_to_host(oh64.e_subsystem);
232  p_e_dll_flags = ByteOrder::le_to_host(oh64.e_dll_flags);
233  p_e_stack_reserve_size = ByteOrder::le_to_host(oh64.e_stack_reserve_size);
234  p_e_stack_commit_size = ByteOrder::le_to_host(oh64.e_stack_commit_size);
235  p_e_heap_reserve_size = ByteOrder::le_to_host(oh64.e_heap_reserve_size);
236  p_e_heap_commit_size = ByteOrder::le_to_host(oh64.e_heap_commit_size);
237  p_e_loader_flags = ByteOrder::le_to_host(oh64.e_loader_flags);
238  p_e_num_rvasize_pairs = ByteOrder::le_to_host(oh64.e_num_rvasize_pairs);
239  } else {
240  throw FormatError("unrecognized Windows PE optional header magic number");
241  }
242 
243  /* Magic number */
244  p_magic.clear();
245  for (size_t i = 0; i < sizeof(fh.e_magic); ++i)
246  p_magic.push_back(fh.e_magic[i]);
247 
248  /* File format */
249  ROSE_ASSERT(p_e_lmajor <= 0xffff && p_e_lminor <= 0xffff);
250  p_exec_format->set_version((p_e_lmajor << 16) | p_e_lminor);
251  p_exec_format->set_is_current_version(true); /*FIXME*/
252 
253  /* Target architecture */
254  switch (p_e_cpu_type) {
255  case 0x0000:
256  set_isa(ISA_UNSPECIFIED);
257  break;
258  case 0x014c:
259  set_isa(ISA_IA32_386);
260  break;
261  case 0x014d:
262  set_isa(ISA_IA32_486);
263  break;
264  case 0x014e:
265  set_isa(ISA_IA32_Pentium);
266  break;
267  case 0x0162:
268  set_isa(ISA_MIPS_MarkI); /* R2000, R3000 */
269  break;
270  case 0x0163:
271  set_isa(ISA_MIPS_MarkII); /* R6000 */
272  break;
273  case 0x0166:
274  set_isa(ISA_MIPS_MarkIII); /* R4000 */
275  break;
276  case 0x01a2: /*Hitachi SH3*/
277  case 0x01a3: /*Hitachi SH3 with FPU*/
278  case 0x01a6: /*Hitachi SH4*/
279  case 0x01a8: /*Hitachi SH5*/
280  set_isa(ISA_Hitachi_SH);
281  break;
282  case 0x01c0:
283  set_isa(ISA_ARM_Family);
284  break;
285  case 0x01d3:
286  set_isa(ISA_Matsushita_AM33);
287  break;
288  case 0x01f0: /*w/o FPU*/
289  case 0x01f1: /*with FPU*/
290  set_isa(ISA_PowerPC);
291  break;
292  case 0x0200:
293  set_isa(ISA_IA64_Family);
294  break;
295  case 0x0266:
296  set_isa(ISA_MIPS_16);
297  break;
298  case 0x0366:
299  set_isa(ISA_MIPS_FPU);
300  break;
301  case 0x0466:
302  set_isa(ISA_MIPS_16FPU);
303  break;
304  case 0x0ebc:
305  set_isa(ISA_EFI_ByteCode);
306  break;
307  case 0x8664:
308  set_isa(ISA_X8664_Family);
309  break;
310  case 0x9041:
311  set_isa(ISA_Mitsubishi_M32R);
312  break;
313  default:
314  mlog[WARN] <<"SgAsmPEFileHeader::parse: warning: unrecognized e_cputype = "
315  <<StringUtility::toHex2(p_e_cpu_type, 16) <<"\n";
316  set_isa(ISA_OTHER);
317  break;
318  }
319 
320  /* The NT loader normally maps this file header at the header's base virtual address. */
321  set_mapped_preferred_rva(0);
322  set_mapped_actual_va(0); /* will be assigned by BinaryLoader */
323  set_mapped_size(p_e_header_size);
324  set_mapped_alignment(0);
325  set_mapped_rperm(true);
326  set_mapped_wperm(false);
327  set_mapped_xperm(false);
328 
329  /* Entry point. We will eventually bind the entry point to a particular section (in SgAsmPEFileHeader::parse) so that if
330  * sections are rearranged, extended, etc. the entry point will be updated automatically. */
331  add_entry_rva(entry_rva);
332 
333  /* The PE File Header has a fixed-size component followed by some number of RVA/Size pairs. The add_rvasize_pairs() will
334  * extend the header and parse the RVA/Size pairs. */
335  if (get_e_num_rvasize_pairs() > 1000) {
336  mlog[WARN] <<"PE File Header contains an unreasonable number of Rva/Size pairs. Limiting to 1000.\n";
337  set_e_num_rvasize_pairs(1000);
338  }
339  add_rvasize_pairs();
340 
341  /* Construct the section table and its sections (non-synthesized sections). The specification says that the section table
342  * comes after the optional (NT) header, which in turn comes after the fixed part of the PE header. The size of the
343  * optional header is indicated in the fixed header. */
344  rose_addr_t secttab_offset = get_offset() + sizeof(PEFileHeader_disk) + get_e_nt_hdr_size();
345  rose_addr_t secttab_size = get_e_nsections() * sizeof(SgAsmPESectionTableEntry::PESectionTableEntry_disk);
346  SgAsmPESectionTable *secttab = new SgAsmPESectionTable(this);
347  secttab->set_offset(secttab_offset);
348  secttab->set_size(secttab_size);
349  secttab->parse();
350  set_section_table(secttab);
351 
352  /* Parse the COFF symbol table */
353  if (get_e_coff_symtab() && get_e_coff_nsyms()) {
354  SgAsmCoffSymbolTable *symtab = new SgAsmCoffSymbolTable(this);
355  symtab->set_offset(get_e_coff_symtab());
356  symtab->parse();
357  set_coff_symtab(symtab);
358  }
359 
360  /* Associate RVAs with particular sections so that if a section's mapping is changed the RVA gets adjusted automatically. */
361  ROSE_ASSERT(get_entry_rvas().size()==1);
362  get_entry_rvas()[0].bind(this);
363  set_e_code_rva(get_e_code_rva().bind(this));
364  set_e_data_rva(get_e_data_rva().bind(this));
365 
366  /* Turn header-specified tables (RVA/Size pairs) into generic sections */
367  create_table_sections();
368  return this;
369 }
370 
371 /* Encode the PE header into disk format */
372 void *
373 SgAsmPEFileHeader::encode(PEFileHeader_disk *disk) const
374 {
375  for (size_t i=0; i<NELMTS(disk->e_magic); i++)
376  disk->e_magic[i] = get_magic()[i];
377  ByteOrder::host_to_le(p_e_cpu_type, &(disk->e_cpu_type));
378  ByteOrder::host_to_le(p_e_nsections, &(disk->e_nsections));
379  ByteOrder::host_to_le(p_e_time, &(disk->e_time));
380  ByteOrder::host_to_le(p_e_coff_symtab, &(disk->e_coff_symtab));
381  ByteOrder::host_to_le(p_e_coff_nsyms, &(disk->e_coff_nsyms));
382  ByteOrder::host_to_le(p_e_nt_hdr_size, &(disk->e_nt_hdr_size));
383  ByteOrder::host_to_le(p_e_flags, &(disk->e_flags));
384 
385  return disk;
386 }
387 void *
388 SgAsmPEFileHeader::encode(PE32OptHeader_disk *disk) const
389 {
390  ByteOrder::host_to_le(p_e_opt_magic, &(disk->e_opt_magic));
391  ByteOrder::host_to_le(p_e_lmajor, &(disk->e_lmajor));
392  ByteOrder::host_to_le(p_e_lminor, &(disk->e_lminor));
393  ByteOrder::host_to_le(p_e_code_size, &(disk->e_code_size));
394  ByteOrder::host_to_le(p_e_data_size, &(disk->e_data_size));
395  ByteOrder::host_to_le(p_e_bss_size, &(disk->e_bss_size));
396  ByteOrder::host_to_le(get_entry_rva(), &(disk->e_entrypoint_rva));
397  ByteOrder::host_to_le(p_e_code_rva, &(disk->e_code_rva));
398  ByteOrder::host_to_le(p_e_data_rva, &(disk->e_data_rva));
399  ByteOrder::host_to_le(get_base_va(), &(disk->e_image_base));
400  ByteOrder::host_to_le(p_e_section_align, &(disk->e_section_align));
401  ByteOrder::host_to_le(p_e_file_align, &(disk->e_file_align));
402  ByteOrder::host_to_le(p_e_os_major, &(disk->e_os_major));
403  ByteOrder::host_to_le(p_e_os_minor, &(disk->e_os_minor));
404  ByteOrder::host_to_le(p_e_user_major, &(disk->e_user_major));
405  ByteOrder::host_to_le(p_e_user_minor, &(disk->e_user_minor));
406  ByteOrder::host_to_le(p_e_subsys_major, &(disk->e_subsys_major));
407  ByteOrder::host_to_le(p_e_subsys_minor, &(disk->e_subsys_minor));
408  ByteOrder::host_to_le(p_e_reserved9, &(disk->e_reserved9));
409  ByteOrder::host_to_le(p_e_image_size, &(disk->e_image_size));
410  ByteOrder::host_to_le(p_e_header_size, &(disk->e_header_size));
411  ByteOrder::host_to_le(p_e_file_checksum, &(disk->e_file_checksum));
412  ByteOrder::host_to_le(p_e_subsystem, &(disk->e_subsystem));
413  ByteOrder::host_to_le(p_e_dll_flags, &(disk->e_dll_flags));
414  ByteOrder::host_to_le(p_e_stack_reserve_size, &(disk->e_stack_reserve_size));
415  ByteOrder::host_to_le(p_e_stack_commit_size, &(disk->e_stack_commit_size));
416  ByteOrder::host_to_le(p_e_heap_reserve_size, &(disk->e_heap_reserve_size));
417  ByteOrder::host_to_le(p_e_heap_commit_size, &(disk->e_heap_commit_size));
418  ByteOrder::host_to_le(p_e_loader_flags, &(disk->e_loader_flags));
419  ByteOrder::host_to_le(p_e_num_rvasize_pairs, &(disk->e_num_rvasize_pairs));
420 
421  return disk;
422 }
423 void *
424 SgAsmPEFileHeader::encode(PE64OptHeader_disk *disk) const
425 {
426  ByteOrder::host_to_le(p_e_opt_magic, &(disk->e_opt_magic));
427  ByteOrder::host_to_le(p_e_lmajor, &(disk->e_lmajor));
428  ByteOrder::host_to_le(p_e_lminor, &(disk->e_lminor));
429  ByteOrder::host_to_le(p_e_code_size, &(disk->e_code_size));
430  ByteOrder::host_to_le(p_e_data_size, &(disk->e_data_size));
431  ByteOrder::host_to_le(p_e_bss_size, &(disk->e_bss_size));
432  ByteOrder::host_to_le(get_entry_rva(), &(disk->e_entrypoint_rva));
433  ByteOrder::host_to_le(p_e_code_rva, &(disk->e_code_rva));
434  // ByteOrder::host_to_le(p_e_data_rva, &(disk->e_data_rva)); /* not present in PE32+ */
435  ByteOrder::host_to_le(get_base_va(), &(disk->e_image_base));
436  ByteOrder::host_to_le(p_e_section_align, &(disk->e_section_align));
437  ByteOrder::host_to_le(p_e_file_align, &(disk->e_file_align));
438  ByteOrder::host_to_le(p_e_os_major, &(disk->e_os_major));
439  ByteOrder::host_to_le(p_e_os_minor, &(disk->e_os_minor));
440  ByteOrder::host_to_le(p_e_user_major, &(disk->e_user_major));
441  ByteOrder::host_to_le(p_e_user_minor, &(disk->e_user_minor));
442  ByteOrder::host_to_le(p_e_subsys_major, &(disk->e_subsys_major));
443  ByteOrder::host_to_le(p_e_subsys_minor, &(disk->e_subsys_minor));
444  ByteOrder::host_to_le(p_e_reserved9, &(disk->e_reserved9));
445  ByteOrder::host_to_le(p_e_image_size, &(disk->e_image_size));
446  ByteOrder::host_to_le(p_e_header_size, &(disk->e_header_size));
447  ByteOrder::host_to_le(p_e_file_checksum, &(disk->e_file_checksum));
448  ByteOrder::host_to_le(p_e_subsystem, &(disk->e_subsystem));
449  ByteOrder::host_to_le(p_e_dll_flags, &(disk->e_dll_flags));
450  ByteOrder::host_to_le(p_e_stack_reserve_size, &(disk->e_stack_reserve_size));
451  ByteOrder::host_to_le(p_e_stack_commit_size, &(disk->e_stack_commit_size));
452  ByteOrder::host_to_le(p_e_heap_reserve_size, &(disk->e_heap_reserve_size));
453  ByteOrder::host_to_le(p_e_heap_commit_size, &(disk->e_heap_commit_size));
454  ByteOrder::host_to_le(p_e_loader_flags, &(disk->e_loader_flags));
455  ByteOrder::host_to_le(p_e_num_rvasize_pairs, &(disk->e_num_rvasize_pairs));
456 
457  return disk;
458 }
459 
461 void
463 {
464  ROSE_ASSERT(get_rvasize_pairs()!=NULL);
465  ROSE_ASSERT(section->get_parent()!=NULL);
466  ROSE_ASSERT(isSgAsmPEFileHeader(section->get_header())!=NULL);
467 
468  switch (idx) {
469  case PAIR_EXPORTS:
470  case PAIR_IMPORTS:
471  case PAIR_RESOURCES:
472  case PAIR_EXCEPTIONS:
473  case PAIR_CERTIFICATES:
474  case PAIR_BASERELOCS:
475  case PAIR_DEBUG:
476  case PAIR_ARCHITECTURE:
477  case PAIR_GLOBALPTR:
478  case PAIR_TLS:
479  case PAIR_LOADCONFIG:
480  case PAIR_BOUNDIMPORT:
481  case PAIR_IAT:
482  case PAIR_DELAYIMPORT:
483  case PAIR_CLRRUNTIME:
484  case PAIR_RESERVED15:
485  break;
486  default:
487  mlog[WARN] <<"SgAsmPEFileHeader::set_rvasize_pair: index " <<idx <<" exceeds specification limit\n";
488  }
489 
490  /* Extend array of rva/size pairs if necessary */
491  if ((size_t)idx>=get_rvasize_pairs()->get_pairs().size()) {
492  get_rvasize_pairs()->get_pairs().resize(idx+1, NULL);
493  for (size_t i=0; i<=(size_t)idx; i++) {
494  if (NULL==get_rvasize_pairs()->get_pairs()[i]) {
495  SgAsmPERVASizePair *pair = new SgAsmPERVASizePair(get_rvasize_pairs(), 0, 0);
496  get_rvasize_pairs()->get_pairs()[i] = pair;
497  }
498  }
499  }
500 
501  SgAsmPERVASizePair *pair = get_rvasize_pairs()->get_pairs()[idx];
502  ROSE_ASSERT(pair!=NULL);
503  pair->set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section));
504  pair->set_e_size(section->get_mapped_size());
505  pair->set_section(section);
506 
507  /* If the section has no name then give it one based on the RVA/Size index. This is mostly for convenience and debugging
508  * since the name is never stored in the file. */
509  if (section->get_name()->get_string().empty()) {
510  const char *short_name;
511  section->get_name()->set_string(rvasize_pair_name(idx, &short_name));
512  section->set_short_name(short_name);
513  }
514 }
515 
517 void
519 {
520  for (size_t i=0; i<get_rvasize_pairs()->get_pairs().size(); i++) {
521  SgAsmPERVASizePair *pair = get_rvasize_pairs()->get_pairs()[i];
522  SgAsmGenericSection *section = pair->get_section();
523  if (section) {
524  pair->set_e_rva(rose_rva_t(section->get_mapped_preferred_rva(), section));
525  pair->set_e_size(section->get_mapped_size());
526  }
527  }
528 }
529 
530 /* Adds the RVA/Size pairs to the end of the PE file header */
531 void
532 SgAsmPEFileHeader::add_rvasize_pairs()
533 {
534  rose_addr_t pairs_offset = get_size();
535  rose_addr_t pairs_size = p_e_num_rvasize_pairs * sizeof(SgAsmPERVASizePair::RVASizePair_disk);
537 
538  ROSE_ASSERT(p_rvasize_pairs != NULL);
539  ROSE_ASSERT(p_rvasize_pairs->get_pairs().size()==0);
540  p_rvasize_pairs->set_isModified(true);
541 
542  extend(pairs_size);
543  for (size_t i = 0; i < p_e_num_rvasize_pairs; i++, pairs_offset += sizeof pairs_disk) {
544  if (sizeof(pairs_disk)!=read_content_local(pairs_offset, &pairs_disk, sizeof pairs_disk, false))
545  mlog[WARN] <<"SgAsmPEFileHeader::add_rvasize_pairs: RVA/Size pair " <<i
546  <<" at file offset " <<StringUtility::addrToString(get_offset()+pairs_offset)
547  <<" extends beyond the end of file (assuming 0/0)\n";
548  p_rvasize_pairs->get_pairs().push_back(new SgAsmPERVASizePair(p_rvasize_pairs, &pairs_disk));
549  }
550 }
551 
552 /* Looks at the RVA/Size pairs in the PE header and creates an SgAsmGenericSection object for each one. This must be done
553  * after we build the mapping from virtual addresses to file offsets. */
554 void
555 SgAsmPEFileHeader::create_table_sections()
556 {
557 
558  /* First, only create the sections. */
559  for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
560  SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
561  if (0==pair->get_e_size())
562  continue;
563 
564  /* Table names come from PE file specification and are hard coded by RVA/Size pair index */
565  const char *tabname_short;
566  std::string tabname = rvasize_pair_name((PairPurpose)i, &tabname_short);
567 
568  /* Find the starting offset in the file.
569  * FIXME: We have a potential problem here in that ROSE sections are always contiguous in the file but a section created
570  * from an RVA/Size pair is not necessarily contiguous in the file. Normally such sections are in fact
571  * contiguous and we'll just ignore this for now. In any case, as long as these sections only ever read their
572  * data via the same MemoryMap that we use here, everything should be fine. [RPM 2009-08-17] */
573  rose_addr_t pair_va = get_base_va() + pair->get_e_rva();
574  MemoryMap::Ptr map = get_loader_map();
575  ROSE_ASSERT(map!=NULL);
576  if (!map->baseSize(pair_va, pair->get_e_size()).exists(Sawyer::Container::MATCH_WHOLE)) {
577  mlog[WARN] <<"SgAsmPEFileHeader::create_table_sections: pair-" <<i
578  <<", rva=" <<StringUtility::addrToString(pair->get_e_rva().get_rva())
579  <<", size=" <<StringUtility::plural(pair->get_e_size(), "bytes")
580  <<" \"" <<StringUtility::cEscape(tabname) <<"\":"
581  <<" unable to find a mapping for the virtual address (skipping)\n";
582  continue;
583  }
584  const MemoryMap::Node &me = *map->at(pair_va).findNode();
585  rose_addr_t file_offset = me.value().offset() + pair_va - me.key().least();
586 
587  /* Create the new section */
588  SgAsmGenericSection *tabsec = NULL;
589  switch (i) {
590  case 0: {
591  /* Sometimes export sections are represented by a ".edata" section, and sometimes they're represented by an
592  * RVA/Size pair, sometimes both point to the same part of the file, and sometimes the RVA/Size pair points to
593  * a different part of the file. We don't want the exports duplicated in the AST, so we only create this table
594  * as exports if we haven't already seen some other export section. */
595  SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
596  bool seen_exports = false;
597  for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_exports && si!=sections.end(); ++si)
598  seen_exports = isSgAsmPEExportSection(*si);
599  if (seen_exports) {
600  tabsec = new SgAsmGenericSection(get_file(), this);
601  } else {
602  tabsec = new SgAsmPEExportSection(this);
603  }
604  break;
605  }
606  case 1: {
607  /* Sometimes import sections are represented by a ".idata" section, and sometimes they're represented by an
608  * RVA/Size pair, and sometimes both point to the same part of the file. We don't want the imports duplicated
609  * in the AST, so we only create this table as imports if we haven't already seen some other import section. */
610  SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
611  bool seen_imports = false;
612  for (SgAsmGenericSectionPtrList::iterator si=sections.begin(); !seen_imports && si!=sections.end(); ++si)
613  seen_imports = isSgAsmPEImportSection(*si);
614  if (seen_imports) {
615  tabsec = new SgAsmGenericSection(get_file(), this);
616  } else {
617  tabsec = new SgAsmPEImportSection(this);
618  }
619  break;
620  }
621  default: {
622  tabsec = new SgAsmGenericSection(get_file(), this);
623  break;
624  }
625  }
626  tabsec->set_name(new SgAsmBasicString(tabname));
627  tabsec->set_short_name(tabname_short);
628  tabsec->set_synthesized(true);
629  tabsec->set_purpose(SP_HEADER);
630 
631  tabsec->set_offset(file_offset);
632  tabsec->set_size(pair->get_e_size());
633  tabsec->set_file_alignment(1);
634 
635  tabsec->set_mapped_alignment(1);
636  tabsec->set_mapped_preferred_rva(pair->get_e_rva().get_rva());
637  tabsec->set_mapped_actual_va(pair->get_e_rva().get_rva()+get_base_va()); /*FIXME: not sure this is correct. [RPM 2009-09-11]*/
638  tabsec->set_mapped_size(pair->get_e_size());
639  tabsec->set_mapped_rperm(true);
640  tabsec->set_mapped_wperm(false);
641  tabsec->set_mapped_xperm(false);
642  pair->set_section(tabsec);
643  pair->set_e_rva(pair->get_e_rva().set_section(tabsec));
644  }
645 
646  /* Now parse the sections */
647  for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++) {
648  SgAsmPERVASizePair *pair = p_rvasize_pairs->get_pairs()[i];
649  SgAsmGenericSection *tabsec = pair->get_section();
650  if (tabsec)
651  tabsec->parse();
652  }
653 }
654 
655 /* Change size of PE header based on word size */
656 bool
658 {
659  struct Resources {
660  unsigned char *oh;
661  Resources(): oh(NULL) {}
662  ~Resources() { delete[] oh; }
663  } r;
664 
665  bool reallocated = SgAsmGenericHeader::reallocate();
666 
667  /* Resize if necessary */
668  rose_addr_t need = sizeof(PEFileHeader_disk);
669  if (4==get_word_size()) {
670  need += sizeof(PE32OptHeader_disk);
671  } else if (8==get_word_size()) {
672  need += sizeof(PE64OptHeader_disk);
673  } else {
674  throw FormatError("unsupported PE word size");
675  }
676  need += p_rvasize_pairs->get_pairs().size() * sizeof(SgAsmPERVASizePair::RVASizePair_disk);
677  if (need<get_size()) {
678  if (is_mapped()) {
679  ROSE_ASSERT(get_mapped_size()==get_size());
680  set_mapped_size(need);
681  }
682  set_size(need);
683  reallocated = true;
684  } else if (need>get_size()) {
685  get_file()->shift_extend(this, 0, need-get_size(), SgAsmGenericFile::ADDRSP_ALL, SgAsmGenericFile::ELASTIC_HOLE);
686  reallocated = true;
687  }
688 
689  /* Make sure the RVA/Size pairs at the end of the header are consistent with the sections to which they point. Reallocate()
690  * has already been called recursively for the sections. */
691  update_rvasize_pairs();
692 
693  /* Make sure header is consistent with sections. Reallocate() has already been called recursively for the sections.
694  * Count the number of sections in the table and update the header's e_nsections member. */
695  if (p_section_table) {
696  ROSE_ASSERT(p_section_table->get_header()==this);
697  SgAsmGenericSectionList *all = get_sections();
698  p_e_nsections = 0;
699  for (size_t i=0; i<all->get_sections().size(); i++) {
700  SgAsmPESection *pesec = dynamic_cast<SgAsmPESection*>(all->get_sections()[i]);
701  if (pesec && pesec->get_section_entry()!=NULL)
702  p_e_nsections++;
703  }
704 
705  rose_addr_t header_size = alignUp(p_section_table->get_offset() + p_section_table->get_size(),
706  (rose_addr_t)(p_e_file_align>0 ? p_e_file_align : 1));
707 #if 1
708  /* The PE Specification regarding e_header_size (known as "SizeOfHeader" on page 14 of "Microsoft Portable Executable
709  * and Common Object File Format Specification: Revision 8.1 February 15, 2008" is not always followed. We recompute
710  * it here as being the minimum RVA from all the sections defined in the PE Section Table, but not smaller
711  * than the value according to the specification. This alternate value is kept if it's already in the parse tree,
712  * otherwise we use the correct value. (RPM 2008-10-21) */
713  rose_addr_t min_offset = 0;
714  for (size_t i=0, nfound=0; i<all->get_sections().size(); i++) {
715  SgAsmPESection *pesec = dynamic_cast<SgAsmPESection*>(all->get_sections()[i]);
716  if (pesec && pesec->get_section_entry()!=NULL) {
717  if (0==nfound++) {
718  min_offset = pesec->get_offset();
719  } else {
720  min_offset = std::min(min_offset, pesec->get_offset() );
721  }
722  }
723  }
724 
725  rose_addr_t header_size2 = std::max(header_size, min_offset);
726  if (p_e_header_size==header_size2)
727  header_size = header_size2;
728 
729  /* If the original header size was zero then don't change that--leave it at zero. Some tiny executables have a zero
730  * value here and as a result, since this is near the end of the NT Optional Header, they can truncate the file and
731  * the loader will fill the optional header with zeros when reading. (RPM 2008-11-11) */
732  if (p_e_header_size==0)
733  header_size = 0;
734 #endif
735  p_e_header_size = header_size;
736  }
737 
738  /* The size of the optional header. If there's a section table then we use its offset to calculate the optional header
739  * size in order to be compatible with the PE loader. Otherwise use the actual optional header size. */
740  if (p_section_table) {
741  ROSE_ASSERT(p_section_table->get_offset() >= get_offset() + sizeof(PEFileHeader_disk));
742  p_e_nt_hdr_size = p_section_table->get_offset() - (get_offset() + sizeof(PEFileHeader_disk));
743  } else if (4==get_word_size()) {
744  p_e_nt_hdr_size = sizeof(PE32OptHeader_disk);
745  } else if (8==get_word_size()) {
746  p_e_nt_hdr_size = sizeof(PE64OptHeader_disk);
747  } else {
748  throw FormatError("invalid PE word size");
749  }
750 
751  /* Update COFF symbol table related data members in the file header */
752  if (get_coff_symtab()) {
753  ROSE_ASSERT(get_coff_symtab()->get_header()==this);
754  set_e_coff_symtab(get_coff_symtab()->get_offset());
755  set_e_coff_nsyms(get_coff_symtab()->get_nslots());
756  }
757 
758  /* Update some additional header fields */
759  set_e_num_rvasize_pairs(get_rvasize_pairs()->get_pairs().size());
760  set_e_opt_magic(4==get_word_size() ? 0x010b : 0x020b);
761  set_e_lmajor((get_exec_format()->get_version() >> 16) & 0xffff);
762  set_e_lminor(get_exec_format()->get_version() & 0xffff);
763 
764  /* Adjust the COFF Header's e_nt_hdr_size to accommodate the NT Optional Header in such a way that EXEs from tinype.com
765  * don't change (i.e., don't increase e_nt_hdr_size if the bytes beyond it are zero anyway, and if they aren't then adjust
766  * it as little as possible. The RVA/Size pairs are considered to be part of the NT Optional Header. */
767  size_t oh_size = p_rvasize_pairs->get_pairs().size() * sizeof(SgAsmPERVASizePair::RVASizePair_disk);
768  if (4==get_word_size()) {
769  oh_size += sizeof(PE32OptHeader_disk);
770  } else if (8==get_word_size()) {
771  oh_size += sizeof(PE64OptHeader_disk);
772  } else {
773  throw FormatError("unsupported PE word size");
774  }
775  r.oh = new unsigned char[oh_size];
776  if (4==get_word_size()) {
777  encode((PE32OptHeader_disk*)r.oh);
778  } else if (8==get_word_size()) {
779  encode((PE64OptHeader_disk*)r.oh);
780  } else {
781  throw FormatError("unsupported PE word size");
782  }
783  while (oh_size>p_e_nt_hdr_size) {
784  if (0!=r.oh[oh_size-1]) break;
785  --oh_size;
786  }
787  set_e_nt_hdr_size(oh_size);
788  return reallocated;
789 }
790 
791 /* Write the PE file header back to disk and all that it references */
792 void
793 SgAsmPEFileHeader::unparse(std::ostream &f) const
794 {
795  struct Resources {
796  unsigned char *oh;
797  Resources(): oh(NULL) {}
798  ~Resources() { delete[] oh; }
799  } r;
800 
801  /* Write unreferenced areas back to the file before anything else. */
802  unparse_holes(f);
803 
804  /* Write sections in the order of specialization, from least specialized to most specialized. This gives more specialized
805  * sections a chance to overwrite the less specialized sections. */
806  const SgAsmGenericSectionPtrList &sections = get_sections()->get_sections();
807  for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
808  if (V_SgAsmGenericSection==(*si)->variantT())
809  (*si)->unparse(f);
810  }
811  for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
812  if (V_SgAsmPESection==(*si)->variantT())
813  (*si)->unparse(f);
814  }
815  for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
816  if (V_SgAsmGenericSection!=(*si)->variantT() && V_SgAsmPESection!=(*si)->variantT())
817  (*si)->unparse(f);
818  }
819 
820  /* Encode the "NT Optional Header" before the COFF Header since the latter depends on the former. Adjust the COFF Header's
821  * e_nt_hdr_size to accommodate the NT Optional Header in such a way that EXEs from tinype.com don't change (i.e., don't
822  * increase e_nt_hdr_size if the bytes beyond it are zero anyway, and if they aren't then adjust it as little as possible.
823  * The RVA/Size pairs are considered to be part of the NT Optional Header. */
824  size_t oh_size = p_rvasize_pairs->get_pairs().size() * sizeof(SgAsmPERVASizePair::RVASizePair_disk);
825  size_t rvasize_offset; /*offset with respect to "oh" buffer allocated below*/
826  if (4==get_word_size()) {
827  oh_size += sizeof(PE32OptHeader_disk);
828  } else if (8==get_word_size()) {
829  oh_size += sizeof(PE64OptHeader_disk);
830  } else {
831  throw FormatError("unsupported PE word size");
832  }
833  r.oh = new unsigned char[oh_size];
834  if (4==get_word_size()) {
835  encode((PE32OptHeader_disk*)r.oh);
836  rvasize_offset = sizeof(PE32OptHeader_disk);
837  } else if (8==get_word_size()) {
838  encode((PE64OptHeader_disk*)r.oh);
839  rvasize_offset = sizeof(PE64OptHeader_disk);
840  } else {
841  throw FormatError("unsupported PE word size");
842  }
843  for (size_t i=0; i<p_rvasize_pairs->get_pairs().size(); i++, rvasize_offset+=sizeof(SgAsmPERVASizePair::RVASizePair_disk)) {
844  SgAsmPERVASizePair::RVASizePair_disk *rvasize_disk = (SgAsmPERVASizePair::RVASizePair_disk*)(r.oh+rvasize_offset);
845  p_rvasize_pairs->get_pairs()[i]->encode(rvasize_disk);
846  }
847  while (oh_size>p_e_nt_hdr_size) {
848  if (0!=r.oh[oh_size-1]) break;
849  --oh_size;
850  }
851  ROSE_ASSERT(p_e_nt_hdr_size==oh_size); /*set in reallocate()*/
852 
853  /* Write the fixed-length COFF Header */
854  PEFileHeader_disk fh;
855  encode(&fh);
856  rose_addr_t spos = write(f, 0, sizeof fh, &fh);
857 
858  /* Write the following "NT Optional Header" */
859  spos = write(f, spos, oh_size, r.oh);
860 }
861 
862 /* Print some debugging information */
863 void
864 SgAsmPEFileHeader::dump(FILE *f, const char *prefix, ssize_t idx) const
865 {
866  char p[4096];
867  if (idx>=0) {
868  sprintf(p, "%sPEFileHeader[%zd].", prefix, idx);
869  } else {
870  sprintf(p, "%sPEFileHeader.", prefix);
871  }
872 
873  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
874  time_t t = p_e_time;
875  char time_str[128];
876  struct tm *tm = localtime(&t);
877  if (tm) {
878  strftime(time_str, sizeof time_str, "%c", tm);
879  } else {
880  strcpy(time_str, "INVALID");
881  }
882 
883  SgAsmGenericHeader::dump(f, p, -1);
884  fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_cpu_type", p_e_cpu_type, p_e_cpu_type);
885  fprintf(f, "%s%-*s = %u\n", p, w, "e_nsections", p_e_nsections);
886  fprintf(f, "%s%-*s = %u (%s)\n", p, w, "e_time", p_e_time, time_str);
887  fprintf(f, "%s%-*s = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, w, "e_coff_symtab", p_e_coff_symtab, p_e_coff_symtab);
888  fprintf(f, "%s%-*s = %u\n", p, w, "e_coff_nsyms", p_e_coff_nsyms);
889  if (p_coff_symtab) {
890  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "coff_symtab",
891  p_coff_symtab->get_id(), p_coff_symtab->get_name()->get_string(true).c_str());
892  } else {
893  fprintf(f, "%s%-*s = none\n", p, w, "coff_symtab");
894  }
895  fprintf(f, "%s%-*s = 0x%08" PRIx64 " (%" PRIu64 ")\n", p, w, "e_nt_hdr_size", p_e_nt_hdr_size, p_e_nt_hdr_size);
896  fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_flags", p_e_flags, p_e_flags);
897  fprintf(f, "%s%-*s = 0x%04x %s\n", p, w, "e_opt_magic", p_e_opt_magic,
898  0x10b == p_e_opt_magic ? "PE32" : (0x20b == p_e_opt_magic ? "PE32+" : "other"));
899  fprintf(f, "%s%-*s = %u.%u\n", p, w, "linker_vers", p_e_lmajor, p_e_lminor);
900  fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_code_size", p_e_code_size, p_e_code_size);
901  fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_data_size", p_e_data_size, p_e_data_size);
902  fprintf(f, "%s%-*s = 0x%08x (%u) bytes\n", p, w, "e_bss_size", p_e_bss_size, p_e_bss_size);
903  fprintf(f, "%s%-*s = %s\n", p, w, "e_code_rva", p_e_code_rva.to_string().c_str());
904  fprintf(f, "%s%-*s = %s\n", p, w, "e_data_rva", p_e_data_rva.to_string().c_str());
905  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_section_align", p_e_section_align, p_e_section_align);
906  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_file_align", p_e_file_align, p_e_file_align);
907  fprintf(f, "%s%-*s = %u.%u\n", p, w, "os_vers", p_e_os_major, p_e_os_minor);
908  fprintf(f, "%s%-*s = %u.%u\n", p, w, "user_vers", p_e_user_major, p_e_user_minor);
909  fprintf(f, "%s%-*s = %u.%u\n", p, w, "subsys_vers", p_e_subsys_major, p_e_subsys_minor);
910  fprintf(f, "%s%-*s = %u\n", p, w, "e_reserved9", p_e_reserved9);
911  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_image_size", p_e_image_size, p_e_image_size);
912  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_header_size", p_e_header_size, p_e_header_size);
913  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_file_checksum", p_e_file_checksum, p_e_file_checksum);
914  fprintf(f, "%s%-*s = %u\n", p, w, "e_subsystem", p_e_subsystem);
915  fprintf(f, "%s%-*s = 0x%04x (%u)\n", p, w, "e_dll_flags", p_e_dll_flags, p_e_dll_flags);
916  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_stack_reserve_size",
917  p_e_stack_reserve_size, p_e_stack_reserve_size);
918  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_stack_commit_size", p_e_stack_commit_size, p_e_stack_commit_size);
919  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_heap_reserve_size", p_e_heap_reserve_size, p_e_heap_reserve_size);
920  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_heap_commit_size", p_e_heap_commit_size, p_e_heap_commit_size);
921  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_loader_flags", p_e_loader_flags, p_e_loader_flags);
922  fprintf(f, "%s%-*s = %u\n", p, w, "e_num_rvasize_pairs", p_e_num_rvasize_pairs);
923  for (unsigned i = 0; i < p_rvasize_pairs->get_pairs().size(); i++) {
924  char p2[256];
925  int nprint __attribute__((unused)) = snprintf(p2, sizeof p2, "%s.pair[%d].", p, i);
926  assert((size_t)nprint<sizeof p2);
927  w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p2));
928  fprintf(f, "%s%-*s = rva %s,\tsize 0x%08" PRIx64 " (%" PRIu64 ")\n", p2, w, "..",
929  p_rvasize_pairs->get_pairs()[i]->get_e_rva().to_string().c_str(),
930  p_rvasize_pairs->get_pairs()[i]->get_e_size(), p_rvasize_pairs->get_pairs()[i]->get_e_size());
931  }
932  if (p_section_table) {
933  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "section_table",
934  p_section_table->get_id(), p_section_table->get_name()->get_string(true).c_str());
935  } else {
936  fprintf(f, "%s%-*s = none\n", p, w, "section_table");
937  }
938 
939  if (variantT() == V_SgAsmPEFileHeader) //unless a base class
940  hexdump(f, 0, std::string(p)+"data at ", p_data);
941 
942  /* Show the simulated loader memory map */
943  const MemoryMap::Ptr map = get_loader_map();
944  if (map) {
945  map->dump(f, (std::string(p)+"loader_map: ").c_str());
946  } else {
947  fprintf(f, "%s%-*s = not defined\n", p, w, "loader_map");
948  }
949 }
List of pointers to file sections.
void update_rvasize_pairs()
Update all the RVA/Size pair info from the section to which it points.
Definition: PeFileHeader.C:518
String associated with a binary file.
size_t read_content(rose_addr_t offset, void *dst_buf, rose_addr_t size, bool strict=true)
Reads data from a file.
Definition: GenericFile.C:128
Contiguous region of a file.
void set_e_size(rose_addr_t)
Property: Size.
void set_short_name(const std::string &)
Property: Abbreviated name.
rose_addr_t get_e_size() const
Property: Size.
std::string rvasize_pair_name(PairPurpose, const char **short_name)
Convert an RVA/Size Pair index number into a section name.
Definition: PeFileHeader.C:19
SgAsmGenericSection * get_section() const
Property: Section.
Definition: PeRvaSizePair.C:45
void set_mapped_xperm(bool)
Property: Whether mapped with execute permission.
rose_addr_t get_rva() const
Returns the numeric RVA.
Definition: Rva.C:85
A file section containing a list of PE Import Directories.
rose_addr_t get_mapped_size() const
Property: Mapped size.
virtual SgAsmPEFileHeader * parse()
Initialize the header with information parsed from the file and construct and parse everything that's...
AddressMapConstraints< const AddressMap > at(Address x) const
Constraint: anchor point.
Definition: AddressMap.h:1082
void dump(FILE *, const char *prefix="") const
Prints the contents of the map for debugging.
Definition: MemoryMap.C:717
static bool is_PE(SgAsmGenericFile *)
Return true if the file looks like it might be a PE file according to the magic number.
Definition: PeFileHeader.C:90
void set_mapped_actual_va(rose_addr_t)
Property: Virtual address where ROSE maps this section.
rose_addr_t get_offset() const
Property: Offset to start of section in file.
virtual void set_mapped_preferred_rva(rose_addr_t)
Property: Relative virtual address where section prefers to be mapped.
Base class for PE sections.
void set_section(SgAsmGenericSection *)
Sets or removes the section associated with an RVA/size pair.
Definition: PeRvaSizePair.C:28
SgAsmGenericHeader * get_header() const
Property: File header that owns this section.
virtual bool reallocate()
Allow all sections to reallocate themselves.
void set_mapped_rperm(bool)
Property: Whether mapped with read permission.
virtual void set_size(rose_addr_t)
Property: Size of section in file in bytes.
File format for an RVA/Size pair.
void set_file_alignment(rose_addr_t)
Property: Required file alignment.
std::string plural(T n, const std::string &plural_word, const std::string &singular_word="")
Helpful way to print singular or plural words.
SgAsmGenericString * get_name() const
Property: Non-unique name of section.
rose_rva_t get_e_rva() const
Property: RVA.
void set_synthesized(bool)
Property: Whether section really exists.
AddressMapConstraints< const AddressMap > baseSize(Address base, Address size) const
Constraint: address lower and upper bounds.
Definition: AddressMap.h:1188
SgAsmPESectionTableEntry * get_section_entry() const
Property: Section table entry.
A relative virtual address optionally associated with a SgAsmSection.
Definition: Cxx_Grammar.h:6643
void set_mapped_wperm(bool)
Property: Whether mapped with write permission.
PairPurpose
Reason for each rva/size pair in the PE header.
virtual void set_offset(rose_addr_t)
Property: Offset to start of section in file.
Binary analysis.
ROSE_UTIL_API std::string addrToString(uint64_t value, size_t nbits=0)
Convert a virtual address to a string.
ROSE_DLL_API Sawyer::Message::Facility mlog
Diagnostic facility for the ROSE library as a whole.
rose_rva_t & set_section(SgAsmGenericSection *section)
Changes the section binding.
Definition: Rva.C:118
Unreferenced and "hole" sections are elastic.
void set_purpose(SectionPurpose)
Property: General contents of the section.
List of SgAsmPERVASizePair AST nodes.
virtual void unparse(std::ostream &) const
Write a section back to the file.
ROSE_UTIL_API std::string toHex2(uint64_t value, size_t nbits, bool show_unsigned_decimal=true, bool show_signed_decimal=true, uint64_t decimal_threshold=256)
Convert a number to a hexadecimal and decimal string.
Export file section.
void set_e_rva(rose_rva_t)
Property: RVA.
void set_mapped_alignment(rose_addr_t)
Property: Alignment in virtual memory.
T alignUp(T address, T alignment)
Align address downward to boundary.
Definition: MemoryMap.h:25
Windows PE file header.
Warning messages that indicate an unusual situation from which the program was able to fully recover...
Definition: Message.h:325
SgNode * get_parent() const
Access function for parent node.
rose_addr_t get_mapped_preferred_rva() const
Property: Relative virtual address where section prefers to be mapped.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const
Print some debugging info.
Controls diagnostic messages from ROSE.
Definition: Diagnostics.h:264
virtual void set_string(const std::string &s)
Property: String value.
Definition: GenericString.C:18
Main namespace for the ROSE library.
virtual void set_mapped_size(rose_addr_t)
Property: Mapped size.
virtual std::string get_string(bool escape=false) const
Property: String value.
Definition: GenericString.C:8
void set_rvasize_pair(PairPurpose, SgAsmPESection *)
Define an RVA/Size pair in the PE file header.
Definition: PeFileHeader.C:462
ROSE_UTIL_API std::string cEscape(const std::string &)
Escapes characters that are special to C/C++.
void set_name(SgAsmGenericString *s)
Property: Non-unique name of section.
Base class for binary files.