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