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