ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ExecDOS.C
Go to the documentation of this file.
1 /* Copyright 2008 Lawrence Livermore National Security, LLC */
2 
3 #include "sage3basic.h"
4 
6 // MS-DOS Real Mode File Header
8 
11 void
13 {
14  ROSE_ASSERT(get_file()!=NULL);
15  ROSE_ASSERT(get_size()>0);
16 
17  set_name(new SgAsmBasicString("DOS File Header"));
18  set_synthesized(true);
20 
21  /* Magic number */
22  p_magic.clear();
23  p_magic.push_back('M');
24  p_magic.push_back('Z');
25 
26  /* Executable Format */
27  ROSE_ASSERT(p_exec_format!=NULL);
36 
38 }
39 
41 bool
43 {
44  /* Turn off byte reference tracking for the duration of this function. We don't want our testing the file contents to
45  * affect the list of bytes that we've already referenced or which we might reference later. */
46  bool was_tracking = file->get_tracking_references();
47  file->set_tracking_references(false);
48 
49  try {
50  unsigned char magic[2];
51  file->read_content(0, magic, sizeof magic);
52  if ('M'!=magic[0] || 'Z'!=magic[1])
53  throw 1;
54  } catch (...) {
55  file->set_tracking_references(was_tracking);
56  return false;
57  }
58  file->set_tracking_references(was_tracking);
59  return true;
60 }
61 
65 SgAsmDOSFileHeader::parse(bool define_rm_section)
66 {
68 
69  /* Read header from file */
70  DOSFileHeader_disk disk;
71  if (sizeof(disk)>get_size())
72  extend(sizeof(disk)-get_size());
73  read_content_local(0, &disk, sizeof disk);
74 
75  /* Check magic number early.
76  * Some old compilers were little-endian ignorant and stored "ZM", but we will ignore this [DQ]. */
77  if (disk.e_magic[0]!='M' || disk.e_magic[1]!='Z')
78  throw FormatError("Bad DOS magic number");
79 
80  /* Decode file format */
96 
97  /* Magic number */
98  p_magic.clear();
99  p_magic.push_back(disk.e_magic[0]);
100  p_magic.push_back(disk.e_magic[1]);
101 
102  /* The DOS File Header is followed by optional relocation entries */
103  if (p_e_nrelocs>0) {
104  SgAsmGenericSection *relocs = new SgAsmGenericSection(get_file(), this);
105  relocs->set_offset(p_e_relocs_offset);
106  relocs->set_size(p_e_nrelocs * sizeof(DOSRelocEntry_disk));
107  relocs->parse();
108  relocs->set_name(new SgAsmBasicString("DOS relocation table"));
109  relocs->set_synthesized(true);
110  relocs->set_purpose(SP_HEADER);
111  set_relocs(relocs);
112  }
113 
114  /* DOS real-mode text/data/etc. */
115  if (define_rm_section)
117 
118  /* Entry point */
119  p_base_va = 0;
121 
122  return this;
123 }
124 
128 void
130 {
131  /* Find the DOS Extended Header */
132  SgAsmDOSFileHeader *dos1 = this;
133  SgAsmDOSExtendedHeader *dos2 = NULL;
134  const SgAsmGenericSectionPtrList &sections = dos1->get_sections()->get_sections();
135  for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); !dos2 && si!=sections.end(); si++)
136  dos2 = isSgAsmDOSExtendedHeader(*si);
137 
138  /* Update DOS File Header with info about the real-mode text+data section. */
139  size_t header_size = dos1->get_size() + (dos2 ? dos2->get_size() : 0);
140  size_t total_size = header_size + (p_rm_section ? p_rm_section->get_size() : 0);
141  p_e_header_paragraphs = (header_size + 15) / 16; /* rounded up to next paragraph */
142  p_e_total_pages = (total_size + 511) / 512; /* rounded up to next page */
143  p_e_last_page_size = total_size % 512;
144 }
145 
146 /* Encode the DOS file header into disk format */
147 void *
149 {
150  for (size_t i=0; i<NELMTS(disk->e_magic); i++)
151  disk->e_magic[i] = get_magic()[i];
158  ByteOrder::host_to_le(p_e_ss, &(disk->e_ss));
159  ByteOrder::host_to_le(p_e_sp, &(disk->e_sp));
161  ByteOrder::host_to_le(p_e_ip, &(disk->e_ip));
162  ByteOrder::host_to_le(p_e_cs, &(disk->e_cs));
166  return disk;
167 }
168 
171 bool
173 {
174  bool reallocated = SgAsmGenericHeader::reallocate();
175 
176  rose_addr_t need = sizeof(DOSFileHeader_disk);
177  if (need < get_size()) {
178  if (is_mapped()) {
179  ROSE_ASSERT(get_mapped_size()==get_size());
180  set_mapped_size(need);
181  }
182  set_size(need);
183  reallocated = true;
184  } else if (need > get_size()) {
186  reallocated = true;
187  }
188 
189  if (p_relocs)
192 
193  return reallocated;
194 }
195 
196 /* Write the DOS file header back to disk */
197 void
198 SgAsmDOSFileHeader::unparse(std::ostream &f) const
199 {
200  /* Unparse each section reachable from the DOS File Header (e.g., the Extended DOS Header) */
201  SgAsmDOSExtendedHeader *dos2 = NULL;
202  for (SgAsmGenericSectionPtrList::iterator i=p_sections->get_sections().begin(); i!=p_sections->get_sections().end(); ++i) {
203  if (!dos2)
204  dos2 = isSgAsmDOSExtendedHeader(*i);
205  (*i)->unparse(f);
206  }
207 
208  /* Some sanity checks:
209  * 1. DOS File Header must be at the beginning of the file.
210  * 2. DOS Extended Header, if present, must immediately follow DOS File Header
211  * 3. DOS Real-Mode Text/Data section must immediately follow headers */
212  ROSE_ASSERT(0==get_offset());
213  ROSE_ASSERT(!dos2 || dos2->get_offset()==get_size());
214 // ROSE_ASSERT(get_size()+(dos2?dos2->get_size():0) < (size_t)p_e_header_paragraphs*16);
215 // ROSE_ASSERT(!p_rm_section || p_rm_section->get_offset()==(size_t)p_e_header_paragraphs*16);
216 
217  /* Unparse the header itself */
218  DOSFileHeader_disk disk;
219  encode(&disk);
220  write(f, 0, sizeof(disk), &disk);
221 }
222 
228 {
229  ROSE_ASSERT(NULL == p_rm_section);
230 
231  rose_addr_t rm_offset = p_e_header_paragraphs * 16;
232  rose_addr_t rm_end = p_e_total_pages * 512;
233  if (p_e_total_pages>0)
234  rm_end -= 512 - (p_e_last_page_size%512);
235 
236  rose_addr_t rm_size = rm_end>rm_offset ? rm_end-rm_offset : 0;
237  if (rm_size == 0)
238  return NULL;
239 
240  if (max_offset>0) {
241  if (max_offset < rm_offset) {
242  rm_size = 0;
243  } else if (rm_offset + rm_size > max_offset) {
244  rm_size = max_offset - rm_offset;
245  }
246  }
247 
248  try {
250  p_rm_section->set_offset(rm_offset);
251  p_rm_section->set_size(rm_size);
252  p_rm_section->parse();
253  } catch (ShortRead &p_ex) {
254  /* If the offset or size is out of bounds for the file then assume that the real-mode section does not exist. This
255  * can indicate that the DOS header is being used for something other than a DOS header. See
256  * http://www.phreedom.org/solar/code/tinype/ for some examples of overlapping the DOS header with the PE header. */
257  return NULL;
258  }
259 
260  p_rm_section->set_name(new SgAsmBasicString("DOS real-mode text/data"));
264  p_rm_section->set_mapped_actual_va(0); /*will be assigned by Loader*/
265  p_rm_section->set_mapped_size(rm_size);
269  return p_rm_section;
270 }
271 
272 /* Print some debugging info */
273 void
274 SgAsmDOSFileHeader::dump(FILE *f, const char *prefix, ssize_t idx) const
275 {
276  char p[4096];
277  if (idx>=0) {
278  sprintf(p, "%sDOSFileHeader[%zd].", prefix, idx);
279  } else {
280  sprintf(p, "%sDOSFileHeader.", prefix);
281  }
282 
283  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
284 
285  SgAsmGenericHeader::dump(f, p, -1);
286  fprintf(f, "%s%-*s = %u bytes\n", p, w, "e_last_page_size", p_e_last_page_size);
287  fprintf(f, "%s%-*s = %u 512-byte pages\n", p, w, "e_total_pages", p_e_total_pages);
288  fprintf(f, "%s%-*s = %u relocations\n", p, w, "e_nrelocs", p_e_nrelocs);
289  fprintf(f, "%s%-*s = %u 16-byte paragraphs\n", p, w, "e_header_paragraphs", p_e_header_paragraphs);
290  fprintf(f, "%s%-*s = %u 16-byte paragraphs\n", p, w, "e_minalloc", p_e_minalloc);
291  fprintf(f, "%s%-*s = %u 16-byte paragraphs\n", p, w, "e_maxalloc", p_e_maxalloc);
292  fprintf(f, "%s%-*s = 0x%08u (%u)\n", p, w, "e_ss", p_e_ss, p_e_ss);
293  fprintf(f, "%s%-*s = 0x%08u (%u)\n", p, w, "e_sp", p_e_sp, p_e_sp);
294  fprintf(f, "%s%-*s = %u (zero implies not used)\n",p, w, "e_cksum", p_e_cksum);
295  fprintf(f, "%s%-*s = 0x%08u (%u)\n", p, w, "e_ip", p_e_ip, p_e_ip);
296  fprintf(f, "%s%-*s = 0x%08u (%u)\n", p, w, "e_cs", p_e_cs, p_e_cs);
297  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64")\n", p, w, "e_relocs_offset", p_e_relocs_offset, p_e_relocs_offset);
298  fprintf(f, "%s%-*s = %u\n", p, w, "e_overlay", p_e_overlay);
299  fprintf(f, "%s%-*s = 0x%08u (%u)\n", p, w, "e_res1", p_e_res1, p_e_res1);
300  if (p_relocs) {
301  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "relocs",
302  p_relocs->get_id(), p_relocs->get_name()->get_string(true).c_str());
303  } else {
304  fprintf(f, "%s%-*s = none\n", p, w, "relocs");
305  }
306  if (p_rm_section) {
307  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "rm_section",
308  p_rm_section->get_id(), p_rm_section->get_name()->get_string(true).c_str());
309  } else {
310  fprintf(f, "%s%-*s = none\n", p, w, "rm_section");
311  }
312 
313  hexdump(f, 0, std::string(p)+"data at ", p_data);
314 }
316 // Extended DOS File Header
317 // This is normally tacked onto the end of a DOS File Header when the executable is PE, NE, LE, or LX. We treat it as a
318 // section belonging to the DOS File Header. The PE, NE, LE and LX File Header IR nodes usually also point to this section.
320 
323 void
325 {
326  set_name(new SgAsmBasicString("DOS Extended Header"));
328  set_synthesized(true);
331 }
332 
336 {
338 
339  /* Read header from file */
341  read_content_local(0, &disk, sizeof disk);
342 
343  /* Decode file format */
344  ROSE_ASSERT(get_header()!=NULL); /*should be the DOS File Header*/
345  ROSE_ASSERT(ByteOrder::ORDER_LSB==get_header()->get_sex());
355 
356  return this;
357 }
358 
359 /* Encode the extended header back into disk format */
360 void *
362 {
372  return disk;
373 }
374 
375 /* Write an extended header back to disk */
376 void
377 SgAsmDOSExtendedHeader::unparse(std::ostream &f) const
378 {
380  encode(&disk);
381  write(f, 0, sizeof disk, &disk);
382 }
383 
384 void
385 SgAsmDOSExtendedHeader::dump(FILE *f, const char *prefix, ssize_t idx) const
386 {
387  char p[4096];
388  if (idx>=0) {
389  sprintf(p, "%sDOSExtendedHeader[%zd].", prefix, idx);
390  } else {
391  sprintf(p, "%sDOSExtendedHeader.", prefix);
392  }
393 
394  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
395 
396  SgAsmGenericSection::dump(f, p, -1);
397  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res1", p_e_res1, p_e_res1);
398  fprintf(f, "%s%-*s = %u\n", p, w, "e_oemid", p_e_oemid);
399  fprintf(f, "%s%-*s = %u\n", p, w, "e_oeminfo", p_e_oeminfo);
400  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res2", p_e_res2, p_e_res2);
401  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res3", p_e_res3, p_e_res3);
402  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res4", p_e_res4, p_e_res4);
403  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res5", p_e_res5, p_e_res5);
404  fprintf(f, "%s%-*s = 0x%08x (%u)\n", p, w, "e_res6", p_e_res6, p_e_res6);
405  fprintf(f, "%s%-*s = %"PRIu64" byte offset (0x%"PRIx64")\n", p, w, "e_lfanew", p_e_lfanew,p_e_lfanew);
406 
407  if (variantT() == V_SgAsmDOSExtendedHeader) //unless a base class
408  hexdump(f, 0, std::string(p)+"data at ", p_data);
409 }