ROSE  0.11.2.0
ExecNE.C
1 /* Copyright 2008 Lawrence Livermore National Security, LLC */
2 #include <rosePublicConfig.h>
3 #ifdef ROSE_BUILD_BINARY_ANALYSIS_SUPPORT
4 #include "sage3basic.h"
5 
6 #include "Diagnostics.h"
7 
8 // In order to efficiently (in terms of amount of code) parse a file format that's defined for a different architecture, we
9 // need to occassionally take addresses of structs that don't follow alignment rules for this architecture.
10 #pragma GCC diagnostic ignored "-Waddress-of-packed-member"
11 
12 using namespace Rose::Diagnostics;
13 
14 // Added to support RTI support in ROSE (not implemented)
15 std::ostream & operator<< (std::ostream & os, const SgAsmNERelocEntry::iref_type & x)
16  {
17  printf("Error: operator<< not implemented! \n");
18  ROSE_ASSERT(false);
19 
20  return os;
21  }
22 
23 std::ostream & operator<<(std::ostream & os, const SgAsmNERelocEntry::iord_type & x)
24  {
25  return os;
26  }
27 
28 std::ostream & operator<<(std::ostream & os, const SgAsmNERelocEntry::iname_type & x)
29  {
30  return os;
31  }
32 
33 std::ostream & operator<<(std::ostream & os, const SgAsmNERelocEntry::osfixup_type & x)
34  {
35  return os;
36  }
37 
38 
39 SgAsmNERelocEntry::iref_type::iref_type()
40  {
41  sect_idx = 0;
42  res1 = 0;
43  tgt_offset = 0;
44  }
45 
46 SgAsmNERelocEntry::iord_type::iord_type()
47  {
48  modref = 0;
49  ordinal = 0;
50  addend = 0;
51  }
52 
53 SgAsmNERelocEntry::iname_type::iname_type()
54  {
55  modref = 0;
56  nm_off = 0;
57  addend = 0;
58  }
59 
60 SgAsmNERelocEntry::osfixup_type::osfixup_type()
61  {
62  type = 0;
63  res3 = 0;
64  }
65 
66 
68 // NE File Header
70 
71 void
72 SgAsmNEFileHeader::ctor(SgAsmGenericFile *f, rose_addr_t offset)
73 {
74  set_offset(offset);
75  set_size(sizeof(NEFileHeader_disk));
76  grab_content();
77 
78  set_name(new SgAsmBasicString("NE File Header"));
79  set_synthesized(true);
80  set_purpose(SP_HEADER);
81 
82  // DQ (8/16/2008): Added code to set SgAsmPEFileHeader as parent of input SgAsmGenericFile
83  f->set_parent(this);
84 
85  NEFileHeader_disk fh;
86  read_content_local(0, &fh, sizeof fh);
87 
88  /* Check magic number early */
89  if (fh.e_magic[0] != 'N' || fh.e_magic[1] != 'E')
90  throw FormatError("Bad NE magic number");
91 
92  /* Decode file header */
93  p_e_linker_major = ByteOrder::le_to_host(fh.e_linker_major);
94  p_e_linker_minor = ByteOrder::le_to_host(fh.e_linker_minor);
95  p_e_entrytab_rfo = ByteOrder::le_to_host(fh.e_entrytab_rfo);
96  p_e_entrytab_size = ByteOrder::le_to_host(fh.e_entrytab_size);
97  p_e_checksum = ByteOrder::le_to_host(fh.e_checksum);
98  p_e_flags1 = ByteOrder::le_to_host(fh.e_flags1);
99  p_e_autodata_sn = ByteOrder::le_to_host(fh.e_autodata_sn);
100  p_e_bss_size = ByteOrder::le_to_host(fh.e_bss_size);
101  p_e_stack_size = ByteOrder::le_to_host(fh.e_stack_size);
102  p_e_csip = ByteOrder::le_to_host(fh.e_csip);
103  p_e_sssp = ByteOrder::le_to_host(fh.e_sssp);
104  p_e_nsections = ByteOrder::le_to_host(fh.e_nsections);
105  p_e_nmodrefs = ByteOrder::le_to_host(fh.e_nmodrefs);
106  p_e_nnonresnames = ByteOrder::le_to_host(fh.e_nnonresnames);
107  p_e_sectab_rfo = ByteOrder::le_to_host(fh.e_sectab_rfo);
108  p_e_rsrctab_rfo = ByteOrder::le_to_host(fh.e_rsrctab_rfo);
109  p_e_resnametab_rfo = ByteOrder::le_to_host(fh.e_resnametab_rfo);
110  p_e_modreftab_rfo = ByteOrder::le_to_host(fh.e_modreftab_rfo);
111  p_e_importnametab_rfo = ByteOrder::le_to_host(fh.e_importnametab_rfo);
112  p_e_nonresnametab_offset = ByteOrder::le_to_host(fh.e_nonresnametab_offset);
113  p_e_nmovable_entries = ByteOrder::le_to_host(fh.e_nmovable_entries);
114  p_e_sector_align = ByteOrder::le_to_host(fh.e_sector_align);
115  p_e_nresources = ByteOrder::le_to_host(fh.e_nresources);
116  p_e_exetype = ByteOrder::le_to_host(fh.e_exetype);
117  p_e_flags2 = ByteOrder::le_to_host(fh.e_flags2);
118  p_e_fastload_sector = ByteOrder::le_to_host(fh.e_fastload_sector);
119  p_e_fastload_nsectors = ByteOrder::le_to_host(fh.e_fastload_nsectors);
120  p_e_res1 = ByteOrder::le_to_host(fh.e_res1);
121  p_e_winvers = ByteOrder::le_to_host(fh.e_winvers);
122 
123  /* Magic number */
124  for (size_t i = 0; i < sizeof(fh.e_magic); ++i)
125  p_magic.push_back(fh.e_magic[i]);
126 
127  /* File format */
128  p_exec_format->set_family(FAMILY_NE);
129  p_exec_format->set_purpose(p_e_flags1 & HF1_LIBRARY ? PURPOSE_LIBRARY : PURPOSE_EXECUTABLE);
130  p_exec_format->set_sex(ByteOrder::ORDER_LSB);
131  p_exec_format->set_abi(ABI_NT);
132  p_exec_format->set_abi_version(0);
133  p_exec_format->set_word_size(2);
134  ROSE_ASSERT(p_e_linker_major <= 0xff && p_e_linker_minor <= 0xff);
135  p_exec_format->set_version((p_e_linker_major<<8) | p_e_linker_minor);
136  p_exec_format->set_is_current_version(true); /*FIXME*/
137 
138  /* Target architecture */
139  switch (p_e_exetype) {
140  case 0:
141  set_isa(ISA_UNSPECIFIED);
142  break;
143  case 1:
144  throw FormatError("use of reserved value for Windows NE header e_exetype");
145  case 2:
146  set_isa(ISA_IA32_386);
147  break;
148  case 3:
149  case 4:
150  throw FormatError("use of reserved value for Windows NE header e_exetype");
151  default:
152  set_isa(ISA_OTHER);
153  break;
154  }
155 
156  /* Entry point */
157 // entry_rva = e_entrypoint_rva; /*FIXME*/
158 }
159 
163 bool
165 {
166  /* Turn off byte reference tracking for the duration of this function. We don't want our testing the file contents to
167  * affect the list of bytes that we've already referenced or which we might reference later. */
168  bool was_tracking = file->get_tracking_references();
169  file->set_tracking_references(false);
170 
171  try {
172  /* Check DOS File Header magic number at beginning of the file */
173  unsigned char dos_magic[2];
174  file->read_content(0, dos_magic, sizeof dos_magic);
175  if ('M'!=dos_magic[0] || 'Z'!=dos_magic[1])
176  throw 1;
177 
178  /* Read four-byte offset of potential PE File Header at offset 0x3c */
179  uint32_t lfanew_disk;
180  file->read_content(0x3c, &lfanew_disk, sizeof lfanew_disk);
181  rose_addr_t ne_offset = ByteOrder::le_to_host(lfanew_disk);
182 
183  /* Look for the NE File Header magic number */
184  unsigned char ne_magic[2];
185  file->read_content(ne_offset, ne_magic, sizeof ne_magic);
186  if ('N'!=ne_magic[0] || 'E'!=ne_magic[1])
187  throw 1;
188  } catch (...) {
189  file->set_tracking_references(was_tracking);
190  return false;
191  }
192 
193  file->set_tracking_references(was_tracking);
194  return true;
195 }
196 
197 /* Encode the NE header into disk format */
198 void *
199 SgAsmNEFileHeader::encode(SgAsmNEFileHeader::NEFileHeader_disk *disk) const
200 {
201  for (size_t i = 0; i < NELMTS(disk->e_magic); i++)
202  disk->e_magic[i] = get_magic()[i];
203  ByteOrder::host_to_le(p_e_linker_major, &(disk->e_linker_major));
204  ByteOrder::host_to_le(p_e_linker_minor, &(disk->e_linker_minor));
205  ByteOrder::host_to_le(p_e_entrytab_rfo, &(disk->e_entrytab_rfo));
206  ByteOrder::host_to_le(p_e_entrytab_size, &(disk->e_entrytab_size));
207  ByteOrder::host_to_le(p_e_checksum, &(disk->e_checksum));
208  ByteOrder::host_to_le(p_e_flags1, &(disk->e_flags1));
209  ByteOrder::host_to_le(p_e_autodata_sn, &(disk->e_autodata_sn));
210  ByteOrder::host_to_le(p_e_bss_size, &(disk->e_bss_size));
211  ByteOrder::host_to_le(p_e_stack_size, &(disk->e_stack_size));
212  ByteOrder::host_to_le(p_e_csip, &(disk->e_csip));
213  ByteOrder::host_to_le(p_e_sssp, &(disk->e_sssp));
214  ByteOrder::host_to_le(p_e_nsections, &(disk->e_nsections));
215  ByteOrder::host_to_le(p_e_nmodrefs, &(disk->e_nmodrefs));
216  ByteOrder::host_to_le(p_e_nnonresnames, &(disk->e_nnonresnames));
217  ByteOrder::host_to_le(p_e_sectab_rfo, &(disk->e_sectab_rfo));
218  ByteOrder::host_to_le(p_e_rsrctab_rfo, &(disk->e_rsrctab_rfo));
219  ByteOrder::host_to_le(p_e_resnametab_rfo, &(disk->e_resnametab_rfo));
220  ByteOrder::host_to_le(p_e_modreftab_rfo, &(disk->e_modreftab_rfo));
221  ByteOrder::host_to_le(p_e_importnametab_rfo, &(disk->e_importnametab_rfo));
222  ByteOrder::host_to_le(p_e_nonresnametab_offset, &(disk->e_nonresnametab_offset));
223  ByteOrder::host_to_le(p_e_nmovable_entries, &(disk->e_nmovable_entries));
224  ByteOrder::host_to_le(p_e_sector_align, &(disk->e_sector_align));
225  ByteOrder::host_to_le(p_e_nresources, &(disk->e_nresources));
226  ByteOrder::host_to_le(p_e_exetype, &(disk->e_exetype));
227  ByteOrder::host_to_le(p_e_flags2, &(disk->e_flags2));
228  ByteOrder::host_to_le(p_e_fastload_sector, &(disk->e_fastload_sector));
229  ByteOrder::host_to_le(p_e_fastload_nsectors, &(disk->e_fastload_nsectors));
230  ByteOrder::host_to_le(p_e_res1, &(disk->e_res1));
231  ByteOrder::host_to_le(p_e_winvers, &(disk->e_winvers));
232 
233  return disk;
234 }
235 
236 /* Write the NE file header back to disk and all that it references */
237 void
238 SgAsmNEFileHeader::unparse(std::ostream &f) const
239 {
241  encode(&fh);
242  write(f, 0, sizeof fh, &fh);
243 
244  /* The extended DOS header */
245  if (p_dos2_header)
246  p_dos2_header->unparse(f);
247 
248  /* The section table and all the non-synthesized sections */
249  if (p_section_table)
250  p_section_table->unparse(f);
251 
252  /* Sections defined in the NE file header */
253  if (p_resname_table)
254  p_resname_table->unparse(f);
255  if (p_nonresname_table)
256  p_nonresname_table->unparse(f);
257  if (p_module_table)
258  p_module_table->unparse(f);
259  if (p_entry_table)
260  p_entry_table->unparse(f);
261 }
262 
263 /* Print some debugging information */
264 void
265 SgAsmNEFileHeader::dump(FILE *f, const char *prefix, ssize_t idx) const
266 {
267  char p[4096];
268  if (idx>=0) {
269  sprintf(p, "%sNEFileHeader[%zd].", prefix, idx);
270  } else {
271  sprintf(p, "%sNEFileHeader.", prefix);
272  }
273 
274  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
275 
276  SgAsmGenericHeader::dump(f, p, -1);
277  fprintf(f, "%s%-*s = %u\n", p, w, "e_linker_major", p_e_linker_major);
278  fprintf(f, "%s%-*s = %u\n", p, w, "e_linker_minor", p_e_linker_minor);
279  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_entrytab_rfo",
280  p_e_entrytab_rfo, p_e_entrytab_rfo+p_offset);
281  fprintf(f, "%s%-*s = %" PRIu64 " bytes\n", p, w, "e_entrytab_size", p_e_entrytab_size);
282  fprintf(f, "%s%-*s = 0x%08x\n", p, w, "e_checksum", p_e_checksum);
283  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "e_flags1", p_e_flags1);
284  fprintf(f, "%s%-*s = %u (1-origin)\n", p, w, "e_autodata_sn", p_e_autodata_sn);
285  fprintf(f, "%s%-*s = %u bytes\n", p, w, "e_bss_size", p_e_bss_size);
286  fprintf(f, "%s%-*s = %u bytes\n", p, w, "e_stack_size", p_e_stack_size);
287  fprintf(f, "%s%-*s = 0x%08x\n", p, w, "e_csip", p_e_csip);
288  fprintf(f, "%s%-*s = 0x%08x\n", p, w, "e_sssp", p_e_sssp);
289  fprintf(f, "%s%-*s = %u\n", p, w, "e_nsections", p_e_nsections);
290  fprintf(f, "%s%-*s = %u\n", p, w, "e_nmodrefs", p_e_nmodrefs);
291  fprintf(f, "%s%-*s = %u\n", p, w, "e_nnonresnames", p_e_nnonresnames);
292  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_sectab_rfo",
293  p_e_sectab_rfo, p_e_sectab_rfo+p_offset);
294  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_rsrctab_rfo",
295  p_e_rsrctab_rfo, p_e_rsrctab_rfo+p_offset);
296  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_resnametab_rfo",
297  p_e_resnametab_rfo, p_e_resnametab_rfo+p_offset);
298  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_modreftab_rfo",
299  p_e_modreftab_rfo, p_e_modreftab_rfo+p_offset);
300  fprintf(f, "%s%-*s = %" PRIu64 " (%" PRIu64 " abs)\n", p, w, "e_importnametab_rfo",
301  p_e_importnametab_rfo, p_e_importnametab_rfo+p_offset);
302  fprintf(f, "%s%-*s = %" PRIu64 " byte offset\n", p, w, "e_nonresnametab_offset", p_e_nonresnametab_offset);
303  fprintf(f, "%s%-*s = %u entries\n", p, w, "e_nmovable_entries", p_e_nmovable_entries);
304  fprintf(f, "%s%-*s = %u (log2)\n", p, w, "e_sector_align", p_e_sector_align);
305  fprintf(f, "%s%-*s = %u\n", p, w, "e_nresources", p_e_nresources);
306  fprintf(f, "%s%-*s = %u\n", p, w, "e_exetype", p_e_exetype);
307  fprintf(f, "%s%-*s = 0x%02x\n", p, w, "e_flags2", p_e_flags2);
308  fprintf(f, "%s%-*s = sector %" PRIu64 "\n", p, w, "e_fastload_sector", p_e_fastload_sector);
309  fprintf(f, "%s%-*s = %" PRIu64 " sectors\n", p, w, "e_fastload_nsectors", p_e_fastload_nsectors);
310  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "e_res1", p_e_res1);
311  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "e_winvers", p_e_winvers);
312 
313  if (p_dos2_header) {
314  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "dos2_header",
315  p_dos2_header->get_id(), p_dos2_header->get_name()->get_string(true).c_str());
316  } else {
317  fprintf(f, "%s%-*s = none\n", p, w, "dos2_header");
318  }
319  if (p_section_table) {
320  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "section_table",
321  p_section_table->get_id(), p_section_table->get_name()->get_string(true).c_str());
322  } else {
323  fprintf(f, "%s%-*s = none\n", p, w, "section_table");
324  }
325  if (p_resname_table) {
326  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "resname_table",
327  p_resname_table->get_id(), p_resname_table->get_name()->get_string(true).c_str());
328  } else {
329  fprintf(f, "%s%-*s = none\n", p, w, "resname_table");
330  }
331  if (p_nonresname_table) {
332  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "nonresname_table",
333  p_nonresname_table->get_id(), p_nonresname_table->get_name()->get_string(true).c_str());
334  } else {
335  fprintf(f, "%s%-*s = none\n", p, w, "nonresname_table");
336  }
337  if (p_module_table) {
338  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "module_table",
339  p_module_table->get_id(), p_module_table->get_name()->get_string(true).c_str());
340  } else {
341  fprintf(f, "%s%-*s = none\n", p, w, "module_table");
342  }
343  if (p_entry_table) {
344  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "entry_table",
345  p_entry_table->get_id(), p_entry_table->get_name()->get_string(true).c_str());
346  } else {
347  fprintf(f, "%s%-*s = none\n", p, w, "entry_table");
348  }
349 }
350 
352 // NE Section Table
354 
355 void
356 SgAsmNESectionTableEntry::ctor(const NESectionTableEntry_disk *disk)
357 {
358  p_sector = ByteOrder::le_to_host(disk->sector);
359  p_physical_size = ByteOrder::le_to_host(disk->physical_size);
360  if (0==p_physical_size && p_sector!=0) p_physical_size = 64*1024;
361  p_flags = ByteOrder::le_to_host(disk->flags);
362  p_virtual_size = ByteOrder::le_to_host(disk->virtual_size);
363  if (0==p_virtual_size) p_virtual_size = 64*1024;
364 }
365 
366 /* Encodes a section table entry back into disk format. */
367 void *
368 SgAsmNESectionTableEntry::encode(NESectionTableEntry_disk *disk) const
369 {
370  ByteOrder::host_to_le(p_sector, &(disk->sector));
371  unsigned x_physical_size = p_physical_size==64*1024 ? 0 : p_physical_size;
372  ByteOrder::host_to_le(x_physical_size, &(disk->physical_size));
373  ByteOrder::host_to_le(p_flags, &(disk->flags));
374  unsigned x_virtual_size = p_virtual_size==64*1024 ? 0 : p_virtual_size;
375  ByteOrder::host_to_le(x_virtual_size, &(disk->virtual_size));
376  return disk;
377 }
378 
379 /* Prints some debugging info */
380 void
381 SgAsmNESectionTableEntry::dump(FILE *f, const char *prefix, ssize_t idx, SgAsmNEFileHeader *fhdr) const
382 {
383  char p[4096];
384  if (idx>=0) {
385  sprintf(p, "%sNESectionTableEntry[%zd].", prefix, idx);
386  } else {
387  sprintf(p, "%sNESectionTableEntry.", prefix);
388  }
389 
390  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
391 
392 
393  fprintf(f, "%s%-*s = %u", p, w, "sector", p_sector);
394  if (fhdr)
395  fprintf(f, " (%" PRIu64 " byte offset)", (rose_addr_t) p_sector << fhdr->get_e_sector_align());
396  fputc('\n', f);
397  fprintf(f, "%s%-*s = %" PRIu64 " bytes\n", p, w, "physical_size", p_physical_size);
398  fprintf(f, "%s%-*s = %" PRIu64 " bytes\n", p, w, "virtual_size", p_virtual_size);
399  fprintf(f, "%s%-*s = 0x%08x", p, w, "flags", p_flags);
400  switch (p_flags & SF_TYPE_MASK) {
401  case SF_CODE: fputs(" code", f); break;
402  case SF_DATA: fputs(" data", f); break;
403  case SF_ALLOC: fputs(" alloc", f); break;
404  case SF_LOAD: fputs(" load", f); break;
405  default: fprintf(f, " type=%u", p_flags & SF_TYPE_MASK); break;
406  }
407  if (p_flags & SF_MOVABLE) fputs(" movable", f);
408  if (p_flags & SF_PURE) fputs(" pure", f);
409  if (p_flags & SF_PRELOAD) fputs(" preload", f);
410  if (p_flags & SF_NOT_WRITABLE) fputs(" const", f);
411  if (p_flags & SF_RELOCINFO) fputs(" reloc", f);
412  if (p_flags & SF_DISCARDABLE) fputs(" discardable", f);
413  if (p_flags & SF_DISCARD) fputs(" discard", f);
414  if (p_flags & SF_RESERVED) fputs(" *", f);
415  fputc('\n', f);
416 }
417 
418 /* Write section back to disk */
419 void
420 SgAsmNESection::unparse(std::ostream &f) const
421 {
423  if (p_reloc_table)
424  p_reloc_table->unparse(f);
425 }
426 
427 /* Print some debugging info. */
428 void
429 SgAsmNESection::dump(FILE *f, const char *prefix, ssize_t idx) const
430 {
431  char p[4096];
432  if (idx>=0) {
433  sprintf(p, "%sNESection[%zd].", prefix, idx);
434  } else {
435  sprintf(p, "%sNESection.", prefix);
436  }
437 
438  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
439 
440  SgAsmGenericSection::dump(f, p, -1);
441  SgAsmNEFileHeader *fhdr = dynamic_cast<SgAsmNEFileHeader*>(get_header());
442  p_st_entry->dump(f, p, -1, fhdr);
443  if (p_reloc_table) {
444  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "reloc_table",
445  p_reloc_table->get_id(), p_reloc_table->get_name()->get_string(true).c_str());
446  } else {
447  fprintf(f, "%s%-*s = none\n", p, w, "reloc_table");
448  }
449 }
450 
451 /* Constructor */
452 void
453 SgAsmNESectionTable::ctor()
454 {
455  SgAsmNEFileHeader *fhdr = dynamic_cast<SgAsmNEFileHeader*>(get_header());
456  ROSE_ASSERT(fhdr!=NULL);
457  set_offset(fhdr->get_end_offset());
458  set_size(fhdr->get_e_nsections() * sizeof(SgAsmNESectionTableEntry::NESectionTableEntry_disk));
459 
460  grab_content();
461 
462  set_synthesized(true);
463  set_name(new SgAsmBasicString("NE Section Table"));
464  set_purpose(SP_HEADER);
465 
466  const size_t entsize = sizeof(SgAsmNESectionTableEntry::NESectionTableEntry_disk);
467 
468  for (size_t i = 0; i < fhdr->get_e_nsections(); i++) {
469  /* Parse the section table entry */
471  read_content_local(i*entsize, &disk, entsize);
473 
474  /* The section */
475  rose_addr_t section_offset = entry->get_sector() << fhdr->get_e_sector_align();
476  SgAsmNESection *section = new SgAsmNESection(fhdr);
477  section->set_offset(section_offset);
478  section->set_size(0==section_offset ? 0 : entry->get_physical_size());
479  section->grab_content();
480  section->set_synthesized(false);
481  section->set_id(i+1); /*numbered starting at 1, not zero*/
482  section->set_purpose(SP_PROGRAM);
483  section->set_st_entry(entry);
484 
485  /* All NE sections are mapped. Their desired address is apparently based on their file offset. */
486  rose_addr_t mapped_rva = section_offset - fhdr->get_offset();
487  section->set_mapped_preferred_rva(mapped_rva);
488  section->set_mapped_actual_va(0); /*assigned by Loader*/
489  section->set_mapped_size(entry->get_virtual_size());
490 
491  unsigned section_type = entry->get_flags() & SgAsmNESectionTableEntry::SF_TYPE_MASK;
492  if (0 == section_offset) {
493  section->set_name(new SgAsmBasicString(".bss"));
494  section->set_mapped_rperm(true);
495  section->set_mapped_wperm(entry->get_flags() & SgAsmNESectionTableEntry::SF_NOT_WRITABLE ? false : true);
496  section->set_mapped_xperm(false);
497  } else if (0 == section_type) {
498  section->set_name(new SgAsmBasicString(".text"));
499  section->set_mapped_rperm(true);
500  section->set_mapped_wperm(entry->get_flags() & SgAsmNESectionTableEntry::SF_NOT_WRITABLE ? false : true);
501  section->set_mapped_xperm(true);
502  } else if (section_type & SgAsmNESectionTableEntry::SF_DATA) {
503  section->set_name(new SgAsmBasicString(".data"));
504  section->set_mapped_rperm(true);
505  section->set_mapped_wperm(entry->get_flags() & (SgAsmNESectionTableEntry::SF_PRELOAD |
506  SgAsmNESectionTableEntry::SF_NOT_WRITABLE) ? false : true);
507  section->set_mapped_xperm(false);
508  }
509 
510  if (entry->get_flags() & SgAsmNESectionTableEntry::SF_RELOCINFO) {
511  SgAsmNERelocTable *relocs = new SgAsmNERelocTable(fhdr, section);
512  section->set_reloc_table(relocs);
513  }
514  }
515 }
516 
517 /* Writes the section table back to disk along with each of the sections. */
518 void
519 SgAsmNESectionTable::unparse(std::ostream &f) const
520 {
521  SgAsmNEFileHeader *fhdr = dynamic_cast<SgAsmNEFileHeader*>(get_header());
522  ROSE_ASSERT(fhdr!=NULL);
523  SgAsmGenericSectionPtrList sections = fhdr->get_sections()->get_sections();
524 
525  for (size_t i=0; i<sections.size(); i++) {
526  if (sections[i]->get_id()>=0) {
527  SgAsmNESection *section = dynamic_cast<SgAsmNESection*>(sections[i]);
528 
529  /* Write the table entry */
530  ROSE_ASSERT(section->get_id()>0); /*ID's are 1-origin in NE*/
531  size_t slot = section->get_id()-1;
532  SgAsmNESectionTableEntry *shdr = section->get_st_entry();
534  shdr->encode(&disk);
535  write(f, slot*sizeof(disk), sizeof disk, &disk);
536 
537  /* Write the section and it's optional relocation table */
538  section->unparse(f);
539  if (section->get_reloc_table())
540  section->get_reloc_table()->unparse(f);
541  }
542  }
543 }
544 
545 /* Prints some debugging info */
546 void
547 SgAsmNESectionTable::dump(FILE *f, const char *prefix, ssize_t idx) const
548 {
549  char p[4096];
550  if (idx>=0) {
551  sprintf(p, "%sNESectionTable[%zd].", prefix, idx);
552  } else {
553  sprintf(p, "%sNESectionTable.", prefix);
554  }
555  SgAsmGenericSection::dump(f, p, -1);
556 }
557 
559 // NE Resident and Non-Resident Name Tables
561 
562 /* Constructor assumes SgAsmGenericSection is zero bytes long so far */
563 void
564 SgAsmNENameTable::ctor(rose_addr_t offset)
565 {
566  set_offset(offset);
567  set_size(0);
568  grab_content();
569 
570  set_synthesized(true);
571  set_name(new SgAsmBasicString("NE Name Table"));
572  set_purpose(SP_HEADER);
573 
574  SgAsmNEFileHeader *fhdr = dynamic_cast<SgAsmNEFileHeader*>(get_header());
575  ROSE_ASSERT(fhdr!=NULL);
576 
577  /* Resident exported procedure names, until we hit a zero length name. The first name
578  * is for the library itself and the corresponding ordinal has no meaning. */
579  rose_addr_t at = 0;
580  while (1) {
581  extend(1);
582  unsigned char byte;
583  read_content_local(at++, &byte, 1);
584  size_t length = byte;
585  if (0==length) break;
586 
587  extend(length);
588  char *buf = new char[length];
589  read_content_local(at, buf, length);
590  p_names.push_back(std::string(buf, length));
591  delete[] buf;
592  at += length;
593 
594  extend(2);
595  uint16_t u16_disk;
596  read_content_local(at, &u16_disk, 2);
597  p_ordinals.push_back(ByteOrder::le_to_host(u16_disk));
598  at += 2;
599  }
600 }
601 
602 /* Writes the section back to disk. */
603 void
604 SgAsmNENameTable::unparse(std::ostream &f) const
605 {
606  rose_addr_t spos=0; /*section offset*/
607  ROSE_ASSERT(p_names.size() == p_ordinals.size());
608 
609  for (size_t i = 0; i < p_names.size(); i++) {
610  /* Name length */
611  ROSE_ASSERT(p_names[i].size() <= 0xff);
612  unsigned char len = p_names[i].size();
613  spos = write(f, spos, len);
614 
615  /* Name */
616  spos = write(f, spos, p_names[i]);
617 
618  /* Ordinal */
619  ROSE_ASSERT(p_ordinals[i]<=0xffff);
620  uint16_t ordinal_le;
621  ByteOrder::host_to_le(p_ordinals[i], &ordinal_le);
622  spos = write(f, spos, sizeof ordinal_le, &ordinal_le);
623  }
624 
625  /* Zero-terminated */
626  write(f, spos, '\0');
627 }
628 
629 /* Prints some debugging info */
630 void
631 SgAsmNENameTable::dump(FILE *f, const char *prefix, ssize_t idx) const
632 {
633  char p[4096];
634  if (idx>=0) {
635  sprintf(p, "%sNENameTable[%zd].", prefix, idx);
636  } else {
637  sprintf(p, "%sNENameTable.", prefix);
638  }
639 
640  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
641 
642  SgAsmGenericSection::dump(f, p, -1);
643  ROSE_ASSERT(p_names.size() == p_ordinals.size());
644  for (size_t i = 0; i < p_names.size(); i++) {
645  fprintf(f, "%s%-*s = [%zd] \"%s\"\n", p, w, "names", i, escapeString(p_names[i]).c_str());
646  fprintf(f, "%s%-*s = [%zd] %u\n", p, w, "ordinals", i, p_ordinals[i]);
647  }
648 }
649 
650 /* Returns all names associated with a particular ordinal */
651 std::vector<std::string>
652 SgAsmNENameTable::get_names_by_ordinal(unsigned ordinal)
653 {
654  std::vector<std::string> retval;
655  for (size_t i = 0; i < p_ordinals.size(); i++) {
656  if (p_ordinals[i] == ordinal) {
657  retval.push_back(p_names[i]);
658  }
659  }
660  return retval;
661 }
662 
664 // NE Module Reference Table
666 
667 /* Constructor */
668 void
669 SgAsmNEModuleTable::ctor(rose_addr_t offset, rose_addr_t size)
670 {
671  set_offset(offset);
672  set_size(size);
673  grab_content();
674 
675  set_synthesized(true);
676  set_name(new SgAsmBasicString("NE Module Reference Table"));
677  set_purpose(SP_HEADER);
678 
679  SgAsmNEFileHeader *fhdr = dynamic_cast<SgAsmNEFileHeader*>(get_header());
680  ROSE_ASSERT(fhdr!=NULL);
681 
682  ROSE_ASSERT(NULL != p_strtab);
683 
684  for (rose_addr_t at = 0; at < get_size(); at += 2) {
685  uint16_t u16_disk;
686  read_content_local(at, &u16_disk, 2);
687  rose_addr_t name_offset = ByteOrder::le_to_host(u16_disk);
688  p_name_offsets.push_back(name_offset);
689  p_names.push_back(p_strtab->get_string(name_offset));
690  }
691 
692  /* Add libraries to file header */
693  for (size_t i = 0; i < p_names.size(); i++) {
694  fhdr->add_dll(new SgAsmGenericDLL(new SgAsmBasicString(p_names[i])));
695  }
696 }
697 
698 /* Writes the section back to disk. */
699 void
700 SgAsmNEModuleTable::unparse(std::ostream &f) const
701 {
702  rose_addr_t spos = 0; /*section offset*/
703  p_strtab->unparse(f);
704 
705  for (size_t i = 0; i < p_name_offsets.size(); i++) {
706  uint16_t name_offset_le;
707  ByteOrder::host_to_le(p_name_offsets[i], &name_offset_le);
708  spos = write(f, spos, sizeof name_offset_le, &name_offset_le);
709  }
710 }
711 
712 /* Prints some debugging info */
713 void
714 SgAsmNEModuleTable::dump(FILE *f, const char *prefix, ssize_t idx) const
715 {
716  char p[4096];
717  if (idx>=0) {
718  sprintf(p, "%sNEModuleTable[%zd].", prefix, idx);
719  } else {
720  sprintf(p, "%sNEModuleTable.", prefix);
721  }
722 
723  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
724 
725  SgAsmGenericSection::dump(f, p, -1);
726 
727  if (p_strtab) {
728  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "strtab",
729  p_strtab->get_id(), p_strtab->get_name()->get_string(true).c_str());
730  } else {
731  fprintf(f, "%s%-*s = none\n", p, w, "strtab");
732  }
733 
734  for (size_t i = 0; i < p_names.size(); i++) {
735  fprintf(f, "%s%-*s = [%" PRIuPTR "] (offset %" PRIu64 ", %" PRIuPTR " bytes) \"%s\"\n",
736  p, w, "name", i, p_name_offsets[i], p_names[i].size(), escapeString(p_names[i]).c_str());
737  }
738 }
739 
741 // NE String Table
743 
744 /* Constructor. We don't parse out the strings here because we want to keep track of what strings are actually referenced by
745  * other parts of the file. We can get that information with the congeal() method. */
746 void
747 SgAsmNEStringTable::ctor(rose_addr_t offset, rose_addr_t size)
748 {
749  set_offset(offset);
750  set_size(size);
751  grab_content();
752 
753  set_synthesized(true);
754  set_name(new SgAsmBasicString("NE String Table"));
755  set_purpose(SP_HEADER);
756 }
757 
758 /* Returns the string whose size indicator is at the specified offset within the table. There's nothing that prevents OFFSET
759  * from pointing to some random location within the string table (but we will throw an exception if offset or the described
760  * following string falls outside the string table). */
761 std::string
762 SgAsmNEStringTable::get_string(rose_addr_t offset)
763 {
764  unsigned char byte;
765  read_content_local(offset, &byte, 1);
766  size_t length = byte;
767 
768  char *buf = new char[length];
769  read_content_local(offset+1, buf, length);
770  std::string retval(buf, length);
771  delete[] buf;
772  return retval;
773 }
774 
775 /* Prints some debugging info */
776 void
777 SgAsmNEStringTable::dump(FILE *f, const char *prefix, ssize_t idx) const
778 {
779  char p[4096];
780  if (idx>=0) {
781  sprintf(p, "%sNEStringTable[%zd].", prefix, idx);
782  } else {
783  sprintf(p, "%sNEStringTable.", prefix);
784  }
785 
786  SgAsmGenericSection::dump(f, p, -1);
787 
788 #if 0 /*Can't parse strings because it would affect the list of referenced bytes*/
789  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
790  bool was_congealed = get_congealed();
791  congeal();
792  rose_addr_t at=0;
793  for (size_t i=0; at<get_size(); i++) {
794  std::string s = get_string(at);
795  char label[64];
796  sprintf(label, "string-at-%" PRIu64, at);
797  fprintf(f, "%s%-*s = [%" PRIuPTR "] (offset %" PRIu64 ", %" PRIuPTR " bytes) \"%s\"\n",
798  p, w, "string", i, at, s.size(), s.c_str());
799  at += 1 + s.size();
800  }
801  if (!was_congealed)
802  uncongeal();
803 #endif
804 }
805 
807 // NE Entry Table
809 
810 /* Print some debugging info */
811 void
812 SgAsmNEEntryPoint::dump(FILE *f, const char *prefix, ssize_t idx) const
813 {
814  char p[4096];
815  if (idx>=0) {
816  sprintf(p, "%sNEEntryPoint[%zd].", prefix, idx);
817  } else {
818  sprintf(p, "%sNEEntryPoint.", prefix);
819  }
820 
821  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
822 
823  if (0 == p_section_idx) {
824  fprintf(f, "%s%-*s = %s\n", p, w, "type", "unused");
825  ROSE_ASSERT(SgAsmNEEntryPoint::EF_ZERO == p_flags);
826  ROSE_ASSERT(0 == p_int3f);
827  ROSE_ASSERT(0 == p_section_offset);
828  } else {
829  fprintf(f, "%s%-*s = %s\n", p, w, "type", 0 == p_int3f ? "fixed" : "movable");
830  fprintf(f, "%s%-*s = 0x%02x", p, w, "flags", p_flags);
831  if (p_flags & EF_EXPORTED) fputs(" exported", f);
832  if (p_flags & EF_GLOBAL) fputs(" global", f);
833  if (p_flags & EF_RESERVED) fputs(" *", f);
834  fputc('\n', f);
835  if (p_int3f)
836  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "int3f", p_int3f);
837  fprintf(f, "%s%-*s = %d\n", p, w, "section_idx", p_section_idx);
838  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "section_offset", p_section_offset);
839  }
840 }
841 
842 /* Constructor */
843 void
844 SgAsmNEEntryTable::ctor(rose_addr_t offset, rose_addr_t size)
845 {
846  set_offset(offset);
847  set_size(size);
848  grab_content();
849 
850  set_synthesized(true);
851  set_name(new SgAsmBasicString("NE Entry Table"));
852  set_purpose(SP_HEADER);
853 
854  unsigned char byte;
855  uint16_t u16_disk;
856 
857  rose_addr_t at = 0;
858  read_content_local(at++, &byte, 1);
859  size_t bundle_nentries = byte;
860  while (bundle_nentries > 0) {
861  p_bundle_sizes.push_back(bundle_nentries);
862  read_content_local(at++, &byte, 1);
863  unsigned segment_indicator = byte;
864  if (0 == segment_indicator) {
865  /* Unused entries */
866  for (size_t i = 0; i < bundle_nentries; i++) {
867  p_entries.push_back(new SgAsmNEEntryPoint());
868  }
869  } else if (0xff == segment_indicator) {
870  /* Movable segment entries. */
871  for (size_t i = 0; i < bundle_nentries; i++, at+=6) {
872  read_content_local(at, &byte, 1);
873  SgAsmNEEntryPoint::NEEntryFlags flags = (SgAsmNEEntryPoint::NEEntryFlags)byte;
874  read_content_local(at+1, &u16_disk, 2);
875  unsigned int3f = ByteOrder::le_to_host(u16_disk);
876  ROSE_ASSERT(int3f!=0); /*because we use zero to indicate a fixed entry in unparse()*/
877  read_content_local(at+3, &byte, 1);
878  unsigned segno = byte;
879  read_content_local(at+4, &u16_disk, 2);
880  unsigned segoffset = ByteOrder::le_to_host(u16_disk);
881  p_entries.push_back(new SgAsmNEEntryPoint(flags, int3f, segno, segoffset));
882  }
883  } else {
884  /* Fixed segment entries */
885  for (size_t i = 0; i < bundle_nentries; i++, at+=3) {
886  read_content_local(at, &byte, 1);
887  SgAsmNEEntryPoint::NEEntryFlags flags = (SgAsmNEEntryPoint::NEEntryFlags)byte;
888  read_content_local(at+1, &u16_disk, 2);
889  unsigned segoffset = ByteOrder::le_to_host(u16_disk);
890  p_entries.push_back(new SgAsmNEEntryPoint(flags, 0, segment_indicator, segoffset));
891  }
892  }
893 
894  read_content_local(at++, &byte, 1);
895  bundle_nentries = byte;
896  }
897 }
898 
899 /* Populates the entry_rvas vector of the NE header based on the contents of this Entry Table. The Section (Object) Table must
900  * have already been parsed and nonsynthesized sections constructed. */
901 void
902 SgAsmNEEntryTable::populate_entries()
903 {
904  SgAsmGenericHeader *fhdr = get_header();
905  for (size_t i=0; i < p_entries.size(); i++) {
906  const SgAsmNEEntryPoint & entry = *(p_entries[i]);
907  SgAsmGenericSection *section = NULL;
908  if (0 == entry.get_section_idx()) {
909  /* Unused entry */
910  } else if (NULL == (section = get_file()->get_section_by_id(entry.get_section_idx()))) {
911  mlog[WARN] <<"ignoring bad entry section_idx\n"; // FIXME[Robb P. Matzke 2015-07-07]
912  entry.dump(stderr, " ", i);
913  } else {
914  ROSE_ASSERT(section->is_mapped());
915  rose_addr_t entry_rva = section->get_mapped_preferred_rva() + entry.get_section_offset();
916  fhdr->add_entry_rva(entry_rva);
917 #if 0 /*DEBUGGING*/
918  /* Entry points often have names. Here's how to get them. */
919  SgAsmNEFileHeader *ne_header = dynamic_cast<SgAsmNEFileHeader*>(fhdr);
920  SgAsmNENameTable *nametab = ne_header->get_nonresname_table();
921  std::vector<std::string> names = nametab->get_names_by_ordinal(i+1);
922  fprintf(stderr, "ROBB: entry[%" PRIuPTR "] (ordinal %" PRIuPTR ")\n", i, i+1);
923  for (size_t j = 0; j < p_names.size(); j++) {
924  fprintf(stderr, "ROBB: name=\"%s\"\n", p_names[j].c_str());
925  }
926 #endif
927  }
928  }
929 }
930 
931 /* Write section back to disk */
932 void
933 SgAsmNEEntryTable::unparse(std::ostream &f) const
934 {
935  rose_addr_t spos=0; /*section offset*/
936 
937  for (size_t bi=0, ei=0; bi < p_bundle_sizes.size(); ei += p_bundle_sizes[bi++]) {
938  ROSE_ASSERT(p_bundle_sizes[bi] > 0 && p_bundle_sizes[bi] <= 0xff);
939  unsigned char n = p_bundle_sizes[bi];
940  spos = write(f, spos, n);
941 
942  ROSE_ASSERT(ei + p_bundle_sizes[bi] <= p_entries.size());
943  if (0 == p_entries[ei]->get_section_idx()) {
944  /* Unused entries */
945  spos = write(f, spos, '\0');
946  } else if (0 == p_entries[ei]->get_int3f()) {
947  /* Fixed entries */
948  ROSE_ASSERT(p_entries[ei]->get_section_idx() <= 0xff);
949  unsigned char n = p_entries[ei]->get_section_idx();
950  spos = write(f, spos, n);
951  for (size_t i = 0; i < p_bundle_sizes[bi]; i++) {
952  ROSE_ASSERT(p_entries[ei]->get_section_idx() == p_entries[ei+i]->get_section_idx());
953  ROSE_ASSERT(p_entries[ei+i]->get_int3f() == 0);
954  ROSE_ASSERT(p_entries[ei+i]->get_flags() <= 0xff);
955  n = p_entries[ei+i]->get_flags();
956  spos = write(f, spos, n);
957  uint16_t eoff_le;
958  ByteOrder::host_to_le(p_entries[ei+i]->get_section_offset(), &eoff_le);
959  spos = write(f, spos, sizeof eoff_le, &eoff_le);
960  }
961  } else {
962  /* Movable entries */
963  spos = write(f, spos, '\377');
964  for (size_t i = 0; i < p_bundle_sizes[bi]; i++) {
965  ROSE_ASSERT(p_entries[ei+i]->get_section_idx() > 0);
966  ROSE_ASSERT(p_entries[ei+i]->get_int3f() != 0);
967  ROSE_ASSERT(p_entries[ei+i]->get_flags() <= 0xff);
968  n = p_entries[ei+i]->get_flags();
969  spos = write(f, spos, n);
970  uint16_t word;
971  ByteOrder::host_to_le(p_entries[ei+i]->get_int3f(), &word);
972  spos = write(f, spos, sizeof word, &word);
973  ROSE_ASSERT(p_entries[ei+i]->get_section_idx() <= 0xff);
974  n = p_entries[ei+i]->get_section_idx();
975  spos = write(f, spos, n);
976  ByteOrder::host_to_le(p_entries[ei+i]->get_section_offset(), &word);
977  spos = write(f, spos, sizeof word, &word);
978  }
979  }
980  }
981  write(f, spos, '\0');
982 }
983 
984 /* Print some debugging info */
985 void
986 SgAsmNEEntryTable::dump(FILE *f, const char *prefix, ssize_t idx) const
987 {
988  char p[4096];
989  if (idx>=0) {
990  sprintf(p, "%sNEEntryTable[%zd].", prefix, idx);
991  } else {
992  sprintf(p, "%sNEEntryTable.", prefix);
993  }
994 
995  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
996 
997  SgAsmGenericSection::dump(f, p, -1);
998  fprintf(f, "%s%-*s = %" PRIuPTR " bundles\n", p, w, "nbundles", p_bundle_sizes.size());
999  for (size_t i = 0; i < p_bundle_sizes.size(); i++) {
1000  fprintf(f, "%s%-*s = [%" PRIuPTR "] %" PRIuPTR " entries\n", p, w, "bundle_size", i, p_bundle_sizes[i]);
1001  }
1002  for (size_t i = 0; i < p_entries.size(); i++) {
1003  p_entries[i]->dump(f, p, i);
1004  }
1005 }
1006 
1008 // NE Relocation Table
1010 
1011 /* Constructor. */
1012 void
1013 SgAsmNERelocEntry::ctor(SgAsmGenericSection *relocs, rose_addr_t at, rose_addr_t *rec_size/*out*/)
1014 {
1015  unsigned char byte;
1016  uint16_t u16_disk;
1017  uint32_t u32_disk;
1018 
1019  rose_addr_t orig_at = at;
1020  ROSE_ASSERT(at == relocs->get_size()); /*the section is extended as we parse*/
1021 
1022  /* Only the low nibble is used for source type; the high nibble is modifier bits */
1023  relocs->extend(1);
1024  relocs->read_content_local(at++, &byte, 1);
1025  unsigned n = byte;
1026  p_src_type = (SgAsmNERelocEntry::NERelocSrcType)(n & 0x0f);
1027  p_modifier = (SgAsmNERelocEntry::NERelocModifiers)(n>>8);
1028 
1029  /* The target type (3 bits), additive flag (1 bit), and target flags */
1030  relocs->extend(1);
1031  relocs->read_content_local(at++, &byte, 1);
1032  n = byte;
1033  p_tgt_type = (SgAsmNERelocEntry::NERelocTgtType)(n & 0x03);
1034  p_flags = (SgAsmNERelocEntry::NERelocFlags)(n>>2);
1035 
1036  /* src_offset is the byte offset into the source section that needs to be patched. If this is an additive relocation then
1037  * the source will be patched by adding the target value to the value stored at the source. Otherwise the target value is
1038  * written to the source and the old contents of the source contains the next source offset, until we get 0xffff. */
1039  relocs->extend(2);
1040  relocs->read_content_local(at, &u16_disk, 2);
1041  p_src_offset = ByteOrder::le_to_host(u16_disk);
1042  at += 2;
1043 
1044  switch (p_tgt_type) {
1045  case RF_TGTTYPE_IREF:
1046  /* Internal reference */
1047  relocs->extend(4);
1048  relocs->read_content_local(at++, &byte, 1);
1049  p_iref.sect_idx = byte;
1050  relocs->read_content_local(at++, &byte, 1);
1051  p_iref.res1 = byte;
1052  relocs->read_content_local(at, &u16_disk, 2);
1053  p_iref.tgt_offset = ByteOrder::le_to_host(u16_disk);
1054  at += 2;
1055  break;
1056  case RF_TGTTYPE_IORD:
1057  /* Imported ordinal */
1058  relocs->extend(4);
1059  relocs->read_content_local(at, &u16_disk, 2);
1060  p_iord.modref = ByteOrder::le_to_host(u16_disk);
1061  relocs->read_content_local(at+2, &u16_disk, 2);
1062  p_iord.ordinal = ByteOrder::le_to_host(u16_disk);
1063  at += 4;
1064  if (p_flags & RF_2EXTRA) {
1065  if (p_flags & RF_32ADD) {
1066  relocs->extend(4);
1067  relocs->read_content_local(at+8, &u32_disk, 4);
1068  p_iord.addend = ByteOrder::le_to_host(u32_disk);
1069  at += 4;
1070  } else {
1071  relocs->extend(2);
1072  relocs->read_content_local(at+8, &u16_disk, 2);
1073  p_iord.addend = ByteOrder::le_to_host(u16_disk);
1074  at += 2;
1075  }
1076  } else {
1077  p_iord.addend = 0;
1078  }
1079  break;
1080  case RF_TGTTYPE_INAME:
1081  /* Imported name */
1082  relocs->extend(4);
1083  relocs->read_content_local(at, &u16_disk, 2);
1084  p_iname.modref = ByteOrder::le_to_host(u16_disk);
1085  relocs->read_content_local(at+2, &u16_disk, 2);
1086  p_iname.nm_off = ByteOrder::le_to_host(u16_disk);
1087  at += 4;
1088  if (p_flags & RF_2EXTRA) {
1089  if (p_flags & RF_32ADD) {
1090  relocs->extend(4);
1091  relocs->read_content_local(at+8, &u32_disk, 4);
1092  p_iname.addend = ByteOrder::le_to_host(u32_disk);
1093  at += 4;
1094  } else {
1095  relocs->extend(2);
1096  relocs->read_content_local(at+8, &u16_disk, 2);
1097  p_iname.addend = ByteOrder::le_to_host(u16_disk);
1098  at += 2;
1099  }
1100  } else {
1101  p_iname.addend = 0;
1102  }
1103  break;
1104  case RF_TGTTYPE_OSFIXUP:
1105  /* Operating system fixup */
1106  relocs->extend(4);
1107  relocs->read_content_local(at, &u16_disk, 2);
1108  p_osfixup.type = ByteOrder::le_to_host(u16_disk);
1109  relocs->read_content_local(at+2, &u16_disk, 2);
1110  p_osfixup.res3 = ByteOrder::le_to_host(u16_disk);
1111  at += 4;
1112  break;
1113  }
1114 
1115  if (rec_size)
1116  *rec_size = at - orig_at;
1117 }
1118 
1119 /* Write entry back to disk at the specified section and section offset, returning new offset */
1120 rose_addr_t
1121 SgAsmNERelocEntry::unparse(std::ostream &f, const SgAsmGenericSection *section, rose_addr_t spos) const
1122 {
1123  unsigned char byte;
1124  byte = (p_modifier << 8) | (p_src_type & 0x0f);
1125  spos = section->write(f, spos, byte);
1126  byte = (p_flags << 2) | (p_tgt_type & 0x03);
1127  spos = section->write(f, spos, byte);
1128 
1129  uint16_t word;
1130  uint32_t dword;
1131  ByteOrder::host_to_le(p_src_offset, &word);
1132  spos = section->write(f, spos, sizeof word, &word);
1133 
1134  switch (p_tgt_type) {
1135  case RF_TGTTYPE_IREF:
1136  ByteOrder::host_to_le(p_iref.sect_idx, &byte);
1137  spos = section->write(f, spos, byte);
1138  ByteOrder::host_to_le(p_iref.res1, &byte);
1139  spos = section->write(f, spos, byte);
1140  ByteOrder::host_to_le(p_iref.tgt_offset, &word);
1141  spos = section->write(f, spos, sizeof word, &word);
1142  break;
1143  case RF_TGTTYPE_IORD:
1144  ByteOrder::host_to_le(p_iord.modref, &word);
1145  spos = section->write(f, spos, sizeof word, &word);
1146  ByteOrder::host_to_le(p_iord.ordinal, &word);
1147  spos = section->write(f, spos, sizeof word, &word);
1148  if (p_flags & RF_2EXTRA) {
1149  if (p_flags & RF_32ADD) {
1150  ByteOrder::host_to_le(p_iord.addend, &dword);
1151  spos = section->write(f, spos, sizeof dword, &dword);
1152  } else {
1153  ByteOrder::host_to_le(p_iord.addend, &word);
1154  spos = section->write(f, spos, sizeof word, &word);
1155  }
1156  } else {
1157  ROSE_ASSERT(p_iord.addend==0);
1158  }
1159  break;
1160  case RF_TGTTYPE_INAME:
1161  ByteOrder::host_to_le(p_iname.modref, &word);
1162  spos = section->write(f, spos, sizeof word, &word);
1163  ByteOrder::host_to_le(p_iname.nm_off, &word);
1164  spos = section->write(f, spos, sizeof word, &word);
1165  if (p_flags & RF_2EXTRA) {
1166  if (p_flags & RF_32ADD) {
1167  ByteOrder::host_to_le(p_iname.addend, &dword);
1168  spos = section->write(f, spos, sizeof dword, &dword);
1169  } else {
1170  ByteOrder::host_to_le(p_iname.addend, &word);
1171  spos = section->write(f, spos, sizeof word, &word);
1172  }
1173  } else {
1174  ROSE_ASSERT(p_iname.addend==0);
1175  }
1176  break;
1177  case RF_TGTTYPE_OSFIXUP:
1178  ByteOrder::host_to_le(p_osfixup.type, &word);
1179  spos = section->write(f, spos, sizeof word, &word);
1180  ByteOrder::host_to_le(p_osfixup.res3, &word);
1181  spos = section->write(f, spos, sizeof word, &word);
1182  break;
1183  default:
1184  ROSE_ASSERT(!"unknown relocation target type");
1185  }
1186  return spos;
1187 }
1188 
1189 /* Print some debugging info */
1190 void
1191 SgAsmNERelocEntry::dump(FILE *f, const char *prefix, ssize_t idx) const
1192 {
1193  char p[4096];
1194  if (idx>=0) {
1195  sprintf(p, "%sRelocEntry[%zd].", prefix, idx);
1196  } else {
1197  sprintf(p, "%sRelocEntry.", prefix);
1198  }
1199 
1200  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
1201 
1202  const char *s;
1203  switch (p_src_type) {
1204  case RF_SRCTYPE_8OFF: s = "byte offset"; break;
1205  case RF_SRCTYPE_WORDSEG: s = "16-bit selector"; break;
1206  case RF_SRCTYPE_16PTR: s = "16-bit pointer"; break;
1207  case RF_SRCTYPE_16OFF: s = "16-bit offset"; break;
1208  case RF_SRCTYPE_32PTR: s = "32-bit pointer"; break;
1209  case RF_SRCTYPE_32OFF: s = "32-bit offset"; break;
1210  case RF_SRCTYPE_NEARCALL: s = "near call/jump"; break;
1211  case RF_SRCTYPE_48PTR: s = "48-bit pointer"; break;
1212  case RF_SRCTYPE_32OFF_b: s = "32-bit offset"; break;
1213  default: s = "unknown"; break;
1214  }
1215  fprintf(f, "%s%-*s = %u (%s)\n", p, w, "src_type", p_src_type, s);
1216 
1217  switch (p_modifier) {
1218  case RF_MODIFIER_SINGLE: s = "single"; break;
1219  case RF_MODIFIER_MULTI: s = "multiple"; break;
1220  default: s = "unknown"; break;
1221  }
1222  fprintf(f, "%s%-*s = 0x%04u (%s)\n", p, w, "modifier", p_modifier, s);
1223 
1224  switch (p_tgt_type) {
1225  case RF_TGTTYPE_IREF: s = "internal reference"; break;
1226  case RF_TGTTYPE_IORD: s = "imported ordinal"; break;
1227  case RF_TGTTYPE_INAME: s = "imported name"; break;
1228  case RF_TGTTYPE_OSFIXUP: s = "OS fixup"; break;
1229  default: s = "unknown"; break;
1230  }
1231  fprintf(f, "%s%-*s = %u (%s)\n", p, w, "tgt_type", p_tgt_type, s);
1232 
1233  fprintf(f, "%s%-*s = 0x%04x", p, w, "flags", p_flags);
1234  if (p_flags & RF_ADDITIVE) fputs(" additive", f);
1235  if (p_flags & RF_2EXTRA) fputs(" 2-extra", f);
1236  if (p_flags & RF_32ADD) fputs(" 32-add", f);
1237  if (p_flags & RF_16SECTION) fputs(" 16-sect", f);
1238  if (p_flags & RF_8ORDINAL) fputs(" 8-ordinal", f);
1239  fputc('\n', f);
1240 
1241  fprintf(f, "%s%-*s = 0x%08" PRIx64 "\n", p, w, "src_offset", p_src_offset);
1242 
1243  switch (p_tgt_type) {
1244  case RF_TGTTYPE_IREF:
1245  fprintf(f, "%s%-*s = %u\n", p, w, "sect_idx", p_iref.sect_idx);
1246  fprintf(f, "%s%-*s = 0x%02x\n", p, w, "res3", p_iref.res1);
1247  fprintf(f, "%s%-*s = 0x%08" PRIx64 "\n", p, w, "tgt_offset", p_iref.tgt_offset);
1248  break;
1249  case RF_TGTTYPE_IORD:
1250  fprintf(f, "%s%-*s = %u\n", p, w, "modref", p_iord.modref);
1251  fprintf(f, "%s%-*s = %u\n", p, w, "ordinal", p_iord.ordinal);
1252  fprintf(f, "%s%-*s = %" PRIu64 "\n", p, w, "addend", p_iord.addend);
1253  break;
1254  case RF_TGTTYPE_INAME:
1255  fprintf(f, "%s%-*s = %u\n", p, w, "modref", p_iname.modref);
1256  fprintf(f, "%s%-*s = %u\n", p, w, "nm_off", p_iname.nm_off);
1257  fprintf(f, "%s%-*s = %" PRIu64 "\n", p, w, "addend", p_iname.addend);
1258  break;
1259  case RF_TGTTYPE_OSFIXUP:
1260  fprintf(f, "%s%-*s = %u\n", p, w, "type", p_osfixup.type);
1261  fprintf(f, "%s%-*s = 0x%04x\n", p, w, "res3", p_osfixup.res3);
1262  break;
1263  default:
1264  ROSE_ASSERT(!"unknown relocation target type");
1265  }
1266 }
1267 
1268 /* Constructor. We don't know how large the relocation table is until we're parsing it (specifically, after we've read the
1269  * number of entries stored in the first two bytes), therefore the section should have an initial size of zero and we extend
1270  * it as we parse it. */
1271 void
1272 SgAsmNERelocTable::ctor(SgAsmNESection *section)
1273 {
1274  ROSE_ASSERT(section!=NULL);
1275  set_offset(section->get_offset() + section->get_size()); /*reloc section begins immediately after section payload*/
1276  set_size(0);
1277  grab_content();
1278 
1279  char name[64];
1280  sprintf(name, "NE Relocation Table %" PRIu64, p_offset);
1281  set_synthesized(true);
1282  set_name(new SgAsmBasicString(name));
1283  set_purpose(SP_HEADER);
1284 
1285  ROSE_ASSERT(0 == get_size());
1286 
1287  rose_addr_t at = 0, reloc_size = 0;
1288 
1289  extend(2);
1290  uint16_t u16_disk;
1291  read_content_local(at, &u16_disk, 2);
1292  size_t nrelocs = ByteOrder::le_to_host(u16_disk);
1293  at += 2;
1294 
1295  for (size_t i = 0; i < nrelocs; i++, at += reloc_size) {
1296  p_entries.push_back(new SgAsmNERelocEntry(this, at, &reloc_size));
1297  }
1298 }
1299 
1300 /* Write relocation table back to disk */
1301 void
1302 SgAsmNERelocTable::unparse(std::ostream &f) const
1303 {
1304  rose_addr_t spos=0; /*section offset*/
1305  uint16_t size_le;
1306  ByteOrder::host_to_le(p_entries.size(), &size_le);
1307  spos = write(f, spos, sizeof size_le, &size_le);
1308 
1309  for (size_t i = 0; i < p_entries.size(); i++) {
1310  spos = p_entries[i]->unparse(f, this, spos);
1311  }
1312 }
1313 
1314 /* Print some debugging info */
1315 void
1316 SgAsmNERelocTable::dump(FILE *f, const char *prefix, ssize_t idx) const
1317 {
1318  char p[4096];
1319  if (idx>=0) {
1320  sprintf(p, "%sNERelocTable[%zd].", prefix, idx);
1321  } else {
1322  sprintf(p, "%sNERelocTable.", prefix);
1323  }
1324 
1325  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
1326 
1327  SgAsmGenericSection::dump(f, p, -1);
1328  fprintf(f, "%s%-*s = %" PRIuPTR " entries\n", p, w, "size", p_entries.size());
1329  for (size_t i = 0; i < p_entries.size(); i++) {
1330  p_entries[i]->dump(f, p, i);
1331  }
1332 }
1333 
1335 
1336 /* Parses the structure of an NE file and adds the information to the SgAsmGenericFile. */
1338 SgAsmNEFileHeader::parse(SgAsmDOSFileHeader *dos_header)
1339 {
1340  ROSE_ASSERT(dos_header);
1341  SgAsmGenericFile *ef = dos_header->get_file();
1342  ROSE_ASSERT(ef);
1343 
1344  /* NE files extend the DOS header with some additional info */
1345  SgAsmDOSExtendedHeader *dos2_header = new SgAsmDOSExtendedHeader(dos_header);
1346  dos2_header->set_offset(dos_header->get_size());
1347  dos2_header->parse();
1348 
1349  /* The NE header */
1350  SgAsmNEFileHeader *ne_header = new SgAsmNEFileHeader(ef, dos2_header->get_e_lfanew());
1351  ne_header->set_dos2_header(dos2_header);
1352 
1353  /* Sections defined by the NE file header */
1354  if (ne_header->get_e_resnametab_rfo() > 0) {
1355  rose_addr_t resnames_offset = ne_header->get_offset() + ne_header->get_e_resnametab_rfo();
1356  SgAsmNENameTable *resnames = new SgAsmNENameTable(ne_header, resnames_offset);
1357  resnames->set_name(new SgAsmBasicString("NE Resident Name Table"));
1358  ne_header->set_resname_table(resnames);
1359  }
1360  if (ne_header->get_e_modreftab_rfo() > 0 && ne_header->get_e_importnametab_rfo() > ne_header->get_e_modreftab_rfo()) {
1361  /* Imported Name Table must be read before the Module Reference Table since the latter references the former. However,
1362  * the Imported Name Table comes immediately after the Module Reference Table and before the Entry Table in the file. */
1363  ROSE_ASSERT(ne_header->get_e_importnametab_rfo() > 0);
1364  ROSE_ASSERT(ne_header->get_e_entrytab_rfo() > ne_header->get_e_importnametab_rfo());
1365  rose_addr_t strtab_offset = ne_header->get_offset() + ne_header->get_e_importnametab_rfo();
1366  rose_addr_t strtab_size = ne_header->get_e_entrytab_rfo() - ne_header->get_e_importnametab_rfo();
1367  SgAsmNEStringTable *strtab = new SgAsmNEStringTable(ne_header, strtab_offset, strtab_size);
1368 
1369  /* Module reference table */
1370  rose_addr_t modref_offset = ne_header->get_offset() + ne_header->get_e_modreftab_rfo();
1371  rose_addr_t modref_size = ne_header->get_e_importnametab_rfo() - ne_header->get_e_modreftab_rfo();
1372  SgAsmNEModuleTable *modtab = new SgAsmNEModuleTable(ne_header, strtab, modref_offset, modref_size);
1373  ne_header->set_module_table(modtab);
1374  }
1375  if (ne_header->get_e_entrytab_rfo() > 0 && ne_header->get_e_entrytab_size() > 0) {
1376  rose_addr_t enttab_offset = ne_header->get_offset() + ne_header->get_e_entrytab_rfo();
1377  rose_addr_t enttab_size = ne_header->get_e_entrytab_size();
1378  SgAsmNEEntryTable *enttab = new SgAsmNEEntryTable(ne_header, enttab_offset, enttab_size);
1379  ne_header->set_entry_table(enttab);
1380  }
1381  if (ne_header->get_e_nonresnametab_offset() > 0) {
1382  SgAsmNENameTable *nonres = new SgAsmNENameTable(ne_header, ne_header->get_e_nonresnametab_offset());
1383  nonres->set_name(new SgAsmBasicString("NE Non-Resident Name Table"));
1384  ne_header->set_nonresname_table(nonres);
1385  }
1386 
1387  /* Construct the section table and its sections (non-synthesized sections) */
1388  ne_header->set_section_table(new SgAsmNESectionTable(ne_header));
1389 
1390  // DQ (11/8/2008): Note that "enttab" appears twice as a variable name in this function (in different nested scopes)
1391  /* NE files have multiple entry points that are defined in the Entry Table */
1392  if (SgAsmNEEntryTable *enttab = ne_header->get_entry_table())
1393  enttab->populate_entries();
1394 
1395  return ne_header;
1396 }
1397 
1398 #endif
SgAsmGenericFile * get_file() const
Property: File to which this section belongs.
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.
Contiguous region of a file.
rose_addr_t get_e_lfanew() const
Property: lfanew.
void set_mapped_xperm(bool)
Property: Whether mapped with execute permission.
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:604
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.
const SgAsmGenericSectionPtrList & get_sections() const
Property: List of section pointers.
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.
ROSE_DLL_API int set_name(SgInitializedName *initializedNameNode, SgName new_name)
set_name of symbol in symbol table.
rose_addr_t write(std::ostream &f, rose_addr_t offset, size_t bufsize, const void *buf) const
Write data to a file section.
void set_mapped_rperm(bool)
Property: Whether mapped with read permission.
bool is_mapped() const
Whether section desires to be mapped to memory.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:265
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:429
Represents the file header for DOS executables.
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:519
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.
static bool is_NE(SgAsmGenericFile *)
Return true if the file looks like it might be an NE file according to the magic number.
Definition: ExecNE.C:164
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:700
Base class for container file headers.
void set_synthesized(bool)
Property: Whether section really exists.
rose_addr_t get_size() const
Property: Size of section in file in bytes.
Base class for dynamically linked library information.
void grab_content()
Saves a reference to the original file data for a section based on the section's current offset and s...
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:1302
void set_mapped_wperm(bool)
Property: Whether mapped with write permission.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:1316
DOS exteded header.
virtual void set_size(rose_addr_t)
Property: Size of section in file in bytes.
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:238
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:986
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:631
void add_entry_rva(const rose_rva_t &rva)
Append an RVA to the list of entry points.
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:420
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:777
void set_purpose(SectionPurpose)
Property: General contents of the section.
void set_id(int)
Property: Non-unique section ID or negative.
rose_addr_t get_end_offset() const
File offset for end of section.
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:547
virtual void set_mapped_size(rose_addr_t)
Property: Mapped size.
Warning messages that indicate an unusual situation from which the program was able to fully recover...
Definition: Message.h:328
rose_addr_t get_mapped_preferred_rva() const
Property: Relative virtual address where section prefers to be mapped.
void extend(rose_addr_t nbytes)
Extend a section by some number of bytes during the construction and/or parsing phase.
SgAsmGenericSectionList * get_sections() const
Property: List of file sections.
Controls diagnostic messages from ROSE.
Definition: Diagnostics.h:290
int get_id() const
Property: Non-unique section ID or negative.
virtual void unparse(std::ostream &) const ROSE_OVERRIDE
Write a section back to the file.
Definition: ExecNE.C:933
virtual void dump(FILE *, const char *prefix, ssize_t idx) const ROSE_OVERRIDE
Print some debugging info.
Definition: ExecNE.C:714
void set_name(SgAsmGenericString *s)
Property: Non-unique name of section.
Base class for binary files.