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