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