ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GenericFile.C
Go to the documentation of this file.
1 /* Generic Binary Files (SgAsmGenericFile and associated classes). */
2 
3 // tps (01/14/2010) : Switching from rose.h to sage3.
4 //#include "fileoffsetbits.h"
5 #include "sage3basic.h"
6 #include "AsmUnparser_compat.h"
7 #include "MemoryMap.h"
8 
9 #include <boost/math/common_factor.hpp>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 
16 void
18 {
19  ROSE_ASSERT(this != NULL);
20 
21  ROSE_ASSERT(p_fd == -1);
22  ROSE_ASSERT(p_holes == NULL);
23  ROSE_ASSERT(p_truncate_zeros == false);
24 
25  ROSE_ASSERT(p_headers == NULL);
27  ROSE_ASSERT(p_headers != NULL);
28  p_headers->set_parent(this);
29 
30  ROSE_ASSERT(p_holes == NULL);
32  ROSE_ASSERT(p_holes != NULL);
33  p_holes->set_parent(this);
34 }
35 
38 SgAsmGenericFile::parse(std::string fileName)
39 {
40  ROSE_ASSERT(p_fd < 0); /*can call parse() only once per object*/
41 
42  set_name(fileName);
43  p_fd = open(fileName.c_str(), O_RDONLY);
44  if (p_fd<0 || fstat(p_fd, &p_sb)<0) {
45  std::string mesg = "Could not open binary file";
46  throw FormatError(mesg + ": " + strerror(errno));
47  }
48  size_t nbytes = p_sb.st_size;
49 
50  /* To be more portable across operating systems, read the file into memory rather than mapping it. */
51  unsigned char *mapped = new unsigned char[nbytes];
52  if (!mapped)
53  throw FormatError("Could not allocate memory for binary file");
54  ssize_t nread = read(p_fd, mapped, nbytes);
55  if (nread<0 || (size_t)nread!=nbytes)
56  {
57  delete [] mapped;
58  throw FormatError("Could not read entire binary file");
59  }
60 
61  /* Decode the memory if necessary */
63  if (dc) {
64  unsigned char *new_mapped = dc->decode(mapped, &nbytes);
65  if (new_mapped!=mapped) {
66  delete[] mapped;
67  mapped = new_mapped;
68  }
69  }
70 
71  /* Make file contents available through an STL vector without actually reading the file */
72  p_data = SgFileContentList(mapped, nbytes);
73  return this;
74 }
75 
76 /* Destructs by closing and unmapping the file and destroying all sections, headers, etc. */
78 {
79  /* AST child nodes have already been deleted if we're called from SageInterface::deleteAST() */
80 
81  /* Unmap and close */
82  unsigned char *mapped = p_data.pool();
83  if (mapped && p_data.size()>0)
84  delete[] mapped;
85  p_data.clear();
86 
87  if ( p_fd >= 0 )
88  close(p_fd);
89 }
90 
94 {
95  return p_data.size();
96 }
97 
101 {
102  rose_addr_t retval=0;
104  for (SgAsmGenericSectionPtrList::iterator i=sections.begin(); i!=sections.end(); ++i) {
105  retval = std::max(retval, (*i)->get_end_offset());
106  }
107  return retval;
108 }
109 
111 void
113 {
114  if (get_tracking_references()) {
115  p_referenced_extents.insert(Extent(offset, size));
116  delete p_unreferenced_cache;
117  p_unreferenced_cache = NULL;
118  }
119 }
120 
122 const ExtentMap &
124 {
125  if (!p_unreferenced_cache) {
128  }
129  return *p_unreferenced_cache;
130 }
131 
137 size_t
139 {
140  size_t retval;
141  if (offset+size <= p_data.size()) {
142  retval = size;
143  } else if (offset > p_data.size()) {
144  if (strict)
145  throw ShortRead(NULL, offset, size);
146  retval = 0;
147  } else {
148  if (strict)
149  throw ShortRead(NULL, p_data.size(), offset+size - (p_data.size()+offset));
150  retval = p_data.size() - offset;
151  }
152  if (retval>0)
153  memcpy(dst_buf, &(p_data[offset]), retval);
155  mark_referenced_extent(offset, retval);
156  memset((char*)dst_buf+retval, 0, size-retval);
157  return retval;
158 }
159 
164 size_t
165 SgAsmGenericFile::read_content(const MemoryMap *map, rose_addr_t start_va, void *dst_buf, rose_addr_t size, bool strict)
166 {
167  ROSE_ASSERT(map!=NULL);
168 
169  /* Note: This is the same algorithm as used by MemoryMap::read() except we do it here so that we have an opportunity
170  * to track the file byte references. */
171  size_t ncopied = 0;
172  while (ncopied < size) {
173  rose_addr_t va = start_va + ncopied;
174  size_t nread = map->read1((uint8_t*)dst_buf+ncopied, va, size-ncopied, MemoryMap::MM_PROT_NONE);
175  if (0==nread) break;
176 
177  if (get_tracking_references()) {
178  assert(map->exists(va));
179  std::pair<Extent, MemoryMap::Segment> me = map->at(va);
180  if (me.second.get_buffer()->get_data_ptr()==&(get_data()[0])) {
181  /* We are tracking file reads and this segment does, indeed, point into the file. */
182  size_t file_offset = me.second.get_buffer_offset(me.first, va);
183  mark_referenced_extent(file_offset, nread);
184  }
185  }
186 
187  ncopied += nread;
188  }
189 
190  if (ncopied<size) {
191  if (strict)
192  throw MemoryMap::NotMapped("SgAsmGenericFile::read_content() no mapping", map, start_va+ncopied);
193  memset((char*)dst_buf+ncopied, 0, size-ncopied); /*zero pad result if necessary*/
194  }
195  return ncopied;
196 }
197 
203 std::string
205 {
206  static char *buf=NULL;
207  static size_t nalloc=0;
208  size_t nused=0;
209 
210  /* Note: reading one byte at a time might not be the most efficient way to do this, but it does cause the referenced bytes
211  * to be tracked very precisely. */
212  while (1) {
213  if (nused >= nalloc) {
214  nalloc = std::max((size_t)32, 2*nalloc);
215  buf = (char*)realloc(buf, nalloc);
216  ROSE_ASSERT(buf!=NULL);
217  }
218 
219  unsigned char byte;
220  read_content(map, va+nused, &byte, 1, strict); /*might throw RvaSizeMap::NotMapped or return a NUL*/
221  if (!byte)
222  return std::string(buf, nused);
223  buf[nused++] = byte;
224  }
225 }
226 
232 std::string
234 {
235  static char *buf=NULL;
236  static size_t nalloc=0;
237  size_t nused=0;
238 
239  /* Note: reading one byte at a time might not be the most efficient way to do this, but it does cause the referenced bytes
240  * to be tracked very precisely. */
241  while (1) {
242  if (nused >= nalloc) {
243  nalloc = std::max((size_t)32, 2*nalloc);
244  buf = (char*)realloc(buf, nalloc);
245  ROSE_ASSERT(buf!=NULL);
246  }
247 
248  unsigned char byte;
249  read_content(offset+nused, &byte, 1, strict); /*might throw ShortRead or return a NUL*/
250  if (!byte)
251  return std::string(buf, nused);
252  buf[nused++] = byte;
253  }
254 }
255 
262 {
263  if (offset+size <= p_data.size()) {
264  return SgFileContentList(p_data, offset, size);
265  } else {
266  throw ShortRead(NULL, offset, size);
267  }
268 }
269 
271 void
273 {
274  ROSE_ASSERT(p_headers!=NULL);
275  p_headers->set_isModified(true);
276 
277 #ifndef NDEBUG
278  /* New header must not already be present. */
279  for (size_t i=0; i< p_headers->get_headers().size(); i++) {
280  ROSE_ASSERT(p_headers->get_headers()[i] != header);
281  }
282 #endif
283  header->set_parent(p_headers);
284  p_headers->get_headers().push_back(header);
285 }
286 
288 void
290 {
291  if (hdr!=NULL) {
292  ROSE_ASSERT(p_headers != NULL);
293  SgAsmGenericHeaderPtrList::iterator i = find(p_headers->get_headers().begin(), p_headers->get_headers().end(), hdr);
294  if (i != p_headers->get_headers().end()) {
295  p_headers->get_headers().erase(i);
296  p_headers->set_isModified(true);
297  }
298  }
299 }
300 
302 void
304 {
305  ROSE_ASSERT(p_holes!=NULL);
306  p_holes->set_isModified(true);
307 
308 #ifndef NDEBUG
309  /* New hole must not already be present. */
310  for (size_t i=0; i< p_holes->get_sections().size(); i++) {
311  ROSE_ASSERT(p_holes->get_sections()[i] != hole);
312  }
313 #endif
314  hole->set_parent(p_holes);
315  p_holes->get_sections().push_back(hole);
316 }
317 
319 void
321 {
322  if (hole!=NULL) {
323  ROSE_ASSERT(p_holes!=NULL);
324  SgAsmGenericSectionPtrList::iterator i = find(p_holes->get_sections().begin(), p_holes->get_sections().end(), hole);
325  if (i != p_holes->get_sections().end()) {
326  p_holes->get_sections().erase(i);
327  p_holes->set_isModified(true);
328  }
329  }
330 }
331 
334 SgAsmGenericFile::get_sections(bool include_holes) const
335 {
337 
338  /* Start with headers and holes */
339  retval.insert(retval.end(), p_headers->get_headers().begin(), p_headers->get_headers().end());
340  if (include_holes)
341  retval.insert(retval.end(), p_holes->get_sections().begin(), p_holes->get_sections().end());
342 
343  /* Add sections pointed to by headers. */
344  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
345  if ((*i)->get_sections()!=NULL) {
346  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections()->get_sections();
347  retval.insert(retval.end(), recurse.begin(), recurse.end());
348  }
349  }
350  return retval;
351 }
352 
356 {
359  for (size_t i=0; i<all.size(); i++) {
360  if (all[i]->is_mapped())
361  retval.push_back(all[i]);
362  }
363  return retval;
364 }
365 
369 {
371 
372  /* Holes */
373  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
374  if ((*i)->get_id()==id)
375  retval.push_back(*i);
376  }
377 
378  /* Headers and their sections */
379  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
380  if ((*i)->get_id()==id)
381  retval.push_back(*i);
382  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_id(id);
383  retval.insert(retval.end(), recurse.begin(), recurse.end());
384  }
385  return retval;
386 }
387 
391 SgAsmGenericFile::get_section_by_id(int id, size_t *nfound/*optional*/) const
392 {
394  if (nfound) *nfound = possible.size();
395  return possible.size()==1 ? possible[0] : NULL;
396 }
397 
400 SgAsmGenericFile::get_sections_by_name(std::string name, char sep/*or NUL*/) const
401 {
403 
404  /* Truncate name */
405  if (sep) {
406  size_t pos = name.find(sep);
407  if (pos!=name.npos)
408  name.erase(pos);
409  }
410 
411  /* Holes */
412  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
413  std::string secname = (*i)->get_name()->get_string();
414  if (sep) {
415  size_t pos = secname.find(sep);
416  if (pos!=secname.npos)
417  secname.erase(pos);
418  }
419  if (0==secname.compare(name))
420  retval.push_back(*i);
421  }
422 
423  /* Headers and their sections */
424  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
425  std::string secname = (*i)->get_name()->get_string();
426  if (sep) {
427  size_t pos = secname.find(sep);
428  if (pos!=secname.npos)
429  secname.erase(pos);
430  }
431  if (0==secname.compare(name))
432  retval.push_back(*i);
433 
434  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_name(name, sep);
435  retval.insert(retval.end(), recurse.begin(), recurse.end());
436  }
437  return retval;
438 }
439 
444 SgAsmGenericFile::get_section_by_name(const std::string &name, char sep/*or NUL*/, size_t *nfound/*optional*/) const
445 {
446  SgAsmGenericSectionPtrList possible = get_sections_by_name(name, sep);
447  if (nfound) *nfound = possible.size();
448  return possible.size()==1 ? possible[0] : NULL;
449 }
450 
454 {
456 
457  /* Holes */
458  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
459  if (offset >= (*i)->get_offset() &&
460  offset < (*i)->get_offset()+(*i)->get_size() &&
461  offset-(*i)->get_offset() + size <= (*i)->get_size())
462  retval.push_back(*i);
463  }
464 
465  /* Headers and their sections */
466  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
467  if (offset >= (*i)->get_offset() &&
468  offset < (*i)->get_offset()+(*i)->get_size() &&
469  offset-(*i)->get_offset() + size <= (*i)->get_size())
470  retval.push_back(*i);
471  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_offset(offset, size);
472  retval.insert(retval.end(), recurse.begin(), recurse.end());
473  }
474  return retval;
475 }
476 
481 {
482  SgAsmGenericSectionPtrList possible = get_sections_by_offset(offset, size);
483  if (nfound) *nfound = possible.size();
484  return possible.size()==1 ? possible[0] : NULL;
485 }
486 
491 {
493 
494  /* Holes (probably not mapped anyway) */
495  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
496  if ((*i)->is_mapped() &&
497  rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size())
498  retval.push_back(*i);
499  }
500 
501  /* Headers and their sections */
502  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
503  if ((*i)->is_mapped() &&
504  rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size())
505  retval.push_back(*i);
506  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_rva(rva);
507  retval.insert(retval.end(), recurse.begin(), recurse.end());
508  }
509  return retval;
510 }
511 
515 SgAsmGenericFile::get_section_by_rva(rose_addr_t rva, size_t *nfound/*optional*/) const
516 {
518  if (nfound) *nfound = possible.size();
519  return possible.size()==1 ? possible[0] : NULL;
520 }
521 
526 {
528 
529  /* Holes (probably not mapped anyway) */
530  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
531  rose_addr_t rva = va; /* Holes don't belong to any header and therefore have a zero base_va */
532  if ((*i)->is_mapped() &&
533  rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size())
534  retval.push_back(*i);
535  }
536 
537  /* Headers and their sections */
538  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
539  /* Headers probably aren't mapped, but just in case... */
540  rose_addr_t rva = va; /* Headers don't belong to any header and therefore have a zero base_va */
541  if ((*i)->is_mapped() &&
542  rva >= (*i)->get_mapped_preferred_rva() && rva < (*i)->get_mapped_preferred_rva() + (*i)->get_mapped_size())
543  retval.push_back(*i);
544 
545  /* Header sections */
546  const SgAsmGenericSectionPtrList &recurse = (*i)->get_sections_by_va(va, true);
547  retval.insert(retval.end(), recurse.begin(), recurse.end());
548  }
549  return retval;
550 }
551 
555 SgAsmGenericFile::get_section_by_va(rose_addr_t va, size_t *nfound/*optional*/) const
556 {
558  if (nfound) *nfound = possible.size();
559  return possible.size()==1 ? possible[0] : NULL;
560 }
561 
566 SgAsmGenericFile::get_best_section_by_va(rose_addr_t va, size_t *nfound/*optional*/) const
567 {
568  const SgAsmGenericSectionPtrList &candidates = get_sections_by_va(va);
569  if (nfound)
570  *nfound = candidates.size();
571  return best_section_by_va(candidates, va);
572 }
573 
584 {
585  SgAsmGenericSection *best = NULL;
586  rose_addr_t file_offset = 0;
587  for (SgAsmGenericSectionPtrList::const_iterator si=sections.begin(); si!=sections.end(); ++si) {
588  SgAsmGenericSection *section = *si;
589  if (!section->is_mapped() || va<section->get_mapped_actual_va() ||
590  va>=section->get_mapped_actual_va()+section->get_mapped_size()) {
591  // section does not contain virtual address
592  } else if (!best) {
593  best = section;
594  file_offset = section->get_offset() + (va - section->get_mapped_actual_va());
595  } else if (file_offset != section->get_offset() + (va - section->get_mapped_actual_va())) {
596  return NULL; // error
597  } else if (best->get_mapped_size() > section->get_mapped_size()) {
598  best = section;
599  } else if (best->get_name()->get_string().empty() && !section->get_name()->get_string().empty()) {
600  best = section;
601  } else {
602  // prefer section defined earlier
603  }
604  }
605  return best;
606 }
607 
612 {
613  // This function is implemented for use in:
614  // "DisassemblerCommon::AsmFileWithData::getSectionOfAddress(uint64_t addr)"
615  // It supports a more restrictive selection of valid sections to associate with
616  // a given address so that we can avoid disassembly of sections that are not code.
617 
618  const std::vector<SgAsmGenericSection*> &possible = get_sections_by_va(va);
619 
620  if (0 == possible.size())
621  {
622  return NULL;
623  }
624  else
625  {
626  if (1 == possible.size())
627  {
628  // printf ("Only one alternative: va = %p possible[0] id = %d name = %s (return %s) \n",
629  // (void*)va,possible[0]->get_id(),possible[0]->get_name().c_str(),(possible[0]->get_id() < 0) ? "NULL" : "it");
630  // return possible[0];
631  if (possible[0]->get_id() < 0)
632  return NULL;
633  else
634  return possible[0];
635  }
636  }
637 
638 #if 0
639  printf ("Select from %zu alternatives \n",possible.size());
640  for (size_t i = 0; i < possible.size(); i++)
641  {
642  printf (" va = %p possible[%zu] id = %d name = %s \n",(void*)va,i,possible[i]->get_id(),possible[i]->get_name().c_str());
643  }
644 #endif
645 
646  /* Choose the "best" section to return. */
647  SgAsmGenericSection *best = possible[0];
648  rose_addr_t fo0 = possible[0]->get_va_offset(va);
649  for (size_t i = 1; i < possible.size(); i++)
650  {
651  if (fo0 != possible[i]->get_va_offset(va))
652  return NULL; /* all possible sections must map the VA to the same file offset */
653 
654  if (best->get_id() < 0 && possible[i]->get_id() > 0)
655  {
656  best = possible[i]; /*prefer sections defined in a section or object table*/
657  }
658  else
659  if (best->get_mapped_size() > possible[i]->get_mapped_size())
660  {
661  best = possible[i]; /*prefer sections with a smaller mapped size*/
662  }
663  else
664  if (best->get_name()->get_string().size()==0 && possible[i]->get_name()->get_string().size()>0)
665  {
666  best = possible[i]; /*prefer sections having a name*/
667  }
668  else
669  {
670  /* prefer section defined earlier*/
671 
672  }
673  }
674 
675  ROSE_ASSERT(best != NULL);
676 
677  // Add a few things that we just don't want to disassemble
678  if (best->get_name()->get_string() == "ELF Segment Table")
679  return NULL;
680 
681  // printf (" best: va = %p id = %d name = %s \n",(void*)va,best->get_id(),best->get_name().c_str());
682 
683  return best;
684 }
685 
690 {
691  rose_addr_t found = ~(rose_addr_t)0;
692  const SgAsmGenericSectionPtrList &sections = get_sections();
693  for (SgAsmGenericSectionPtrList::const_iterator i=sections.begin(); i!=sections.end(); ++i) {
694  if ((*i)->get_offset() >= offset && (*i)->get_offset() < found)
695  found = (*i)->get_offset();
696  }
697  return found;
698 }
699 
736 void
738 {
739  ROSE_ASSERT(s!=NULL);
740  ROSE_ASSERT(s->get_file()==this);
741  ROSE_ASSERT((space & (ADDRSP_FILE|ADDRSP_MEMORY)) != 0);
742 
743  const bool debug = false;
744  static size_t ncalls=0;
745  char p[256];
746 
747  if (debug) {
748  const char *space_s="unknown";
749  if (space & ADDRSP_FILE) {
750  space_s = "file";
751  } else if (space & ADDRSP_MEMORY) {
752  space_s = "memory";
753  }
754  sprintf(p, "SgAsmGenericFile::shift_extend[%zu]: ", ncalls++);
755  fprintf(stderr, "%s -- START --\n", p);
756  fprintf(stderr, "%s S = [%d] \"%s\"\n", p, s->get_id(), s->get_name()->get_string(true).c_str());
757  fprintf(stderr, "%s %s Sa=0x%08"PRIx64" (%"PRIu64"), Sn=0x%08"PRIx64" (%"PRIu64")\n", p, space_s, sa, sa, sn, sn);
758  fprintf(stderr, "%s elasticity = %s\n", p, (ELASTIC_NONE==elasticity ? "none" :
759  ELASTIC_UNREF==elasticity ? "unref" :
760  ELASTIC_HOLE==elasticity ? "unref+holes" :
761  "unknown"));
762  }
763 
764  /* No-op case */
765  if (0==sa && 0==sn) {
766  if (debug) {
767  fprintf(stderr, "%s No change necessary.\n", p);
768  fprintf(stderr, "%s -- END --\n", p);
769  }
770  return;
771  }
772 
773  bool filespace = (space & ADDRSP_FILE)!=0;
774  bool memspace = (space & ADDRSP_MEMORY)!=0;
775  rose_addr_t align=1, aligned_sa, aligned_sasn;
776  SgAsmGenericSectionPtrList neighbors, villagers;
777  ExtentMap amap; /* address mappings for all extents */
778  Extent sp;
779 
780  /* Get a list of all sections that may need to be adjusted. */
782  switch (elasticity) {
783  case ELASTIC_NONE:
784  case ELASTIC_UNREF:
785  all = filespace ? get_sections() : get_mapped_sections();
786  break;
787  case ELASTIC_HOLE:
788  all = filespace ? get_sections(false) : get_mapped_sections();
789  break;
790  }
791  if (debug) {
792  fprintf(stderr, "%s Following sections are in 'all' set:\n", p);
793  for (size_t i=0; i<all.size(); i++) {
794  Extent ep;
795  if (filespace) {
796  ep = all[i]->get_file_extent();
797  } else {
798  ROSE_ASSERT(all[i]->is_mapped());
799  ep = all[i]->get_mapped_preferred_extent();
800  }
801  fprintf(stderr, "%s 0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64" [%d] \"%s\"\n",
802  p, ep.relaxed_first(), ep.size(), ep.relaxed_first()+ep.size(), all[i]->get_id(),
803  all[i]->get_name()->get_string(true).c_str());
804  }
805  }
806 
807  for (size_t pass=0; pass<2; pass++) {
808  if (debug) {
809  fprintf(stderr, "%s -- %s --\n",
810  p, 0==pass?"FIRST PASS":"SECOND PASS (after making a larger hole)");
811  }
812 
813  /* S offset and size in file or memory address space */
814  if (filespace) {
815  sp = s->get_file_extent();
816  } else if (!memspace || !s->is_mapped()) {
817  return; /*nothing to do*/
818  } else {
819  sp = s->get_mapped_preferred_extent();
820  }
821 
822  /* Build address map */
823  for (size_t i=0; i<all.size(); i++) {
824  if (filespace) {
825  amap.insert(all[i]->get_file_extent());
826  } else {
827  ROSE_ASSERT(all[i]->is_mapped());
828  amap.insert(all[i]->get_mapped_preferred_extent());
829  }
830  }
831  if (debug) {
832  fprintf(stderr, "%s Address map:\n", p);
833  amap.dump_extents(stderr, (std::string(p)+" ").c_str(), "amap");
834  fprintf(stderr, "%s Extent of S:\n", p);
835  fprintf(stderr, "%s start=0x%08"PRIx64" size=0x%08"PRIx64" end=0x%08"PRIx64"\n",
836  p, sp.relaxed_first(), sp.size(), sp.relaxed_first()+sp.size());
837  }
838 
839  /* Neighborhood (nhs) of S is a single extent. However, if S is zero size then nhs might be empty. The neighborhood of
840  * S is S plus all sections that overlap with S and all sections that are right-contiguous with S. */
841  ExtentMap nhs_map;
842  for (ExtentMap::iterator amapi=amap.begin(); amapi!=amap.end(); ++amapi) {
843  if (amapi->first.relaxed_first() <= sp.relaxed_first()+sp.size() &&
844  amapi->first.relaxed_first()+amapi->first.size() > sp.relaxed_first())
845  nhs_map.insert(amapi->first, amapi->second);
846  }
847  if (debug) {
848  fprintf(stderr, "%s Neighborhood of S:\n", p);
849  nhs_map.dump_extents(stderr, (std::string(p)+" ").c_str(), "nhs_map");
850  }
851  Extent nhs;
852  if (nhs_map.size()>0) {
853  assert(nhs_map.nranges()==1);
854  nhs = nhs_map.begin()->first;
855  } else {
856  nhs = sp;
857  }
858 
859  /* What sections are in the neighborhood (including S), and right of the neighborhood? */
860  neighbors.clear(); /*sections in neighborhood*/
861  neighbors.push_back(s);
862  villagers.clear(); /*sections right of neighborhood*/
863  if (debug)
864  fprintf(stderr, "%s Ignoring left (L) sections:\n", p);
865  for (size_t i=0; i<all.size(); i++) {
866  SgAsmGenericSection *a = all[i];
867  if (a==s) continue; /*already pushed onto neighbors*/
868  Extent ap;
869  if (filespace) {
870  ap = a->get_file_extent();
871  } else if (!a->is_mapped()) {
872  continue;
873  } else {
874  ap = a->get_mapped_preferred_extent();
875  }
876  switch (ExtentMap::category(ap, nhs)) {
877  case 'L':
878  if (debug)
879  fprintf(stderr, "%s L 0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64" [%d] \"%s\"\n",
880  p, ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size(),
881  a->get_id(), a->get_name()->get_string(true).c_str());
882  break;
883  case 'R':
884  if (ap.relaxed_first()==nhs.relaxed_first()+nhs.size() && 0==ap.size()) {
885  /* Empty sections immediately right of the neighborhood of S should actually be considered part of the
886  * neighborhood rather than right of it. */
887  neighbors.push_back(a);
888  } else if (elasticity!=ELASTIC_NONE) {
889  /* If holes are elastic then treat things right of the hole as being part of the right village; otherwise
890  * add those sections to the neighborhood of S even though they fall outside 'nhs' (it's OK because this
891  * partitioning of sections is the only thing we use 'nhs' for anyway. */
892  villagers.push_back(a);
893  } else if ('L'==ExtentMap::category(ap, sp)) {
894  /*ignore sections left of S*/
895  } else {
896  neighbors.push_back(a);
897  }
898  break;
899  default:
900  if ('L'!=ExtentMap::category(ap, sp)) /*ignore sections left of S*/
901  neighbors.push_back(a);
902  break;
903  }
904  }
905  if (debug) {
906  fprintf(stderr, "%s Neighbors:\n", p);
907  for (size_t i=0; i<neighbors.size(); i++) {
908  SgAsmGenericSection *a = neighbors[i];
909  Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
910  rose_addr_t align = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
911  char cat = ExtentMap::category(ap, sp);
912  fprintf(stderr, "%s %c %c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
913  p, cat, 0==ap.relaxed_first() % (align?align:1) ? ' ' : '!',
914  ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
915  if (strchr("RICE", cat)) {
916  fprintf(stderr, " align=0x%08"PRIx64, align);
917  } else {
918  fputs(" ", stderr);
919  }
920  fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
921  }
922  if (villagers.size()>0) fprintf(stderr, "%s Villagers:\n", p);
923  for (size_t i=0; i<villagers.size(); i++) {
924  SgAsmGenericSection *a = villagers[i];
925  Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
926  rose_addr_t align = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
927  fprintf(stderr, "%s %c %c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
928  p, ExtentMap::category(ap, sp), /*cat should always be R*/
929  0==ap.relaxed_first() % (align?align:1) ? ' ' : '!',
930  ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
931  fputs(" ", stderr);
932  fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
933  }
934  }
935 
936  /* Adjust Sa to satisfy all alignment constraints in neighborhood(S) for sections that will move (cats R, I, C, and E). */
937  align = 1;
938  for (size_t i=0; i<neighbors.size(); i++) {
939  SgAsmGenericSection *a = neighbors[i];
940  Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
941  if (strchr("RICE", ExtentMap::category(ap, sp))) {
942  rose_addr_t x = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
943  align = boost::math::lcm(align, x?x:1);
944  }
945  }
946  aligned_sa = (sa/align + (sa%align?1:0))*align;
947  aligned_sasn = ((sa+sn)/align + ((sa+sn)%align?1:0))*align;
948  if (debug) {
949  fprintf(stderr, "%s Alignment LCM = 0x%08"PRIx64" (%"PRIu64")\n", p, align, align);
950  fprintf(stderr, "%s Aligned Sa = 0x%08"PRIx64" (%"PRIu64")\n", p, aligned_sa, aligned_sa);
951  fprintf(stderr, "%s Aligned Sa+Sn = 0x%08"PRIx64" (%"PRIu64")\n", p, aligned_sasn, aligned_sasn);
952  }
953 
954  /* Are there any sections to the right of neighborhood(S)? If so, find the one with the lowest start address and use
955  * that to define the size of the hole right of neighborhood(S). */
956  if (0==villagers.size()) break;
957  SgAsmGenericSection *after_hole = NULL;
958  Extent hp(0, 0);
959  for (size_t i=0; i<villagers.size(); i++) {
960  SgAsmGenericSection *a = villagers[i];
961  Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
962  if (!after_hole || ap.relaxed_first()<hp.relaxed_first()) {
963  after_hole = a;
964  hp = ap;
965  }
966  }
967  ROSE_ASSERT(after_hole);
968  ROSE_ASSERT(hp.relaxed_first() > nhs.relaxed_first()+nhs.size());
969  rose_addr_t hole_size = hp.relaxed_first() - (nhs.relaxed_first()+nhs.size());
970  if (debug) {
971  fprintf(stderr, "%s hole size = 0x%08"PRIx64" (%"PRIu64"); need 0x%08"PRIx64" (%"PRIu64"); %s\n",
972  p, hole_size, hole_size, aligned_sasn, aligned_sasn,
973  hole_size>=aligned_sasn ? "large enough" : "not large enough");
974  }
975  if (hole_size >= aligned_sasn) break;
976  rose_addr_t need_more = aligned_sasn - hole_size;
977 
978  /* Hole is not large enough. We need to recursively move things that are right of our neighborhood, then recompute the
979  * all-sections address map and neighborhood(S). */
980  ROSE_ASSERT(0==pass); /*logic problem since the recursive call should have enlarged the hole enough*/
981  if (debug) {
982  fprintf(stderr, "%s Calling recursively to increase hole size by 0x%08"PRIx64" (%"PRIu64") bytes\n",
983  p, need_more, need_more);
984  }
985  shift_extend(after_hole, need_more, 0, space, elasticity);
986  if (debug) fprintf(stderr, "%s Returned from recursive call\n", p);
987  }
988 
989  /* Consider sections that are in the same neighborhood as S */
990  if (debug) fprintf(stderr, "%s -- ADJUSTING --\n", p);
991  bool resized_mem = false;
992  for (size_t i=0; i<neighbors.size(); i++) {
993  SgAsmGenericSection *a = neighbors[i];
994  Extent ap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
995  switch (ExtentMap::category(ap, sp)) {
996  case 'L':
997  break;
998  case 'R':
999  if (filespace) {
1000  a->set_offset(a->get_offset()+aligned_sasn);
1001  } else {
1002  a->set_mapped_preferred_rva(a->get_mapped_preferred_rva()+aligned_sasn);
1003  }
1004  break;
1005  case 'C': /*including S itself*/
1006  case 'E':
1007  if (filespace) {
1008  a->set_offset(a->get_offset()+aligned_sa);
1009  a->set_size(a->get_size()+sn);
1010  if (memspace && !resized_mem && a->is_mapped()) {
1011  shift_extend(a, 0, sn, ADDRSP_MEMORY, elasticity);
1012  resized_mem = true;
1013  }
1014  } else {
1016  a->set_mapped_size(a->get_mapped_size()+sn);
1017  }
1018  break;
1019  case 'O':
1020  if (ap.relaxed_first()==sp.relaxed_first()) {
1021  if (filespace) {
1022  a->set_offset(a->get_offset()+aligned_sa);
1023  a->set_size(a->get_size()+sn);
1024  } else {
1026  a->set_mapped_size(a->get_mapped_size()+sn);
1027  }
1028  } else {
1029  if (filespace) {
1030  a->set_size(a->get_size()+aligned_sasn);
1031  if (memspace && !resized_mem && a->is_mapped()) {
1032  shift_extend(a, 0, aligned_sasn, ADDRSP_MEMORY, elasticity);
1033  resized_mem = true;
1034  }
1035  } else {
1036  a->set_mapped_size(a->get_mapped_size()+aligned_sasn);
1037  }
1038  }
1039  break;
1040  case 'I':
1041  if (filespace) {
1042  a->set_offset(a->get_offset()+aligned_sa);
1043  } else {
1045  }
1046  break;
1047  case 'B':
1048  if (filespace) {
1049  a->set_size(a->get_size()+sn);
1050  if (memspace && !resized_mem && a->is_mapped()) {
1051  shift_extend(a, 0, sn, ADDRSP_MEMORY, elasticity);
1052  resized_mem = true;
1053  }
1054  } else {
1055  a->set_mapped_size(a->get_size()+sn);
1056  }
1057  break;
1058  default:
1059  ROSE_ASSERT(!"invalid extent category");
1060  break;
1061  }
1062  if (debug) {
1063  const char *space_name = filespace ? "file" : "mem";
1064  rose_addr_t x = filespace ? a->get_file_alignment() : a->get_mapped_alignment();
1065  fprintf(stderr, "%s %4s-%c %c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
1066  p, space_name, ExtentMap::category(ap, sp),
1067  0==ap.relaxed_first()%(x?x:1)?' ':'!',
1068  ap.relaxed_first(), ap.size(), ap.relaxed_first()+ap.size());
1069  Extent newap = filespace ? a->get_file_extent() : a->get_mapped_preferred_extent();
1070  fprintf(stderr, " -> %c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
1071  0==newap.relaxed_first()%(x?x:1)?' ':'!',
1072  newap.relaxed_first(), newap.size(), newap.relaxed_first()+newap.size());
1073  fprintf(stderr, " [%2d] \"%s\"\n", a->get_id(), a->get_name()->get_string(true).c_str());
1074  }
1075  }
1076  if (debug) fprintf(stderr, "%s -- END --\n", p);
1077 }
1078 
1083 void
1084 SgAsmGenericFile::dump_all(bool in_cwd, const char *ext)
1085 {
1086  if (!ext)
1087  ext = ".dump";
1088  std::string dump_name = get_name() + ext;
1089  if (in_cwd) {
1090  size_t slash = dump_name.find_last_of('/');
1091  if (slash!=dump_name.npos)
1092  dump_name.replace(0, slash+1, "");
1093  }
1094  dump_all(dump_name);
1095 }
1096 
1098 void
1099 SgAsmGenericFile::dump_all(const std::string &dump_name)
1100 {
1101  FILE *dumpFile = fopen(dump_name.c_str(), "wb");
1102  ROSE_ASSERT(dumpFile != NULL);
1103  try {
1104  // The file type should be the first; test harness depends on it
1105  fprintf(dumpFile, "%s\n", format_name());
1106 
1107  // A table describing the sections of the file
1108  dump(dumpFile);
1109 
1110  // Detailed info about each section
1111  const SgAsmGenericSectionPtrList &sections = get_sections();
1112  for (size_t i = 0; i < sections.size(); i++) {
1113  fprintf(dumpFile, "Section [%zd]:\n", i);
1114  ROSE_ASSERT(sections[i] != NULL);
1115  sections[i]->dump(dumpFile, " ", -1);
1116  }
1117 
1118  /* Dump interpretations that point only to this file. */
1119  SgBinaryComposite *binary = SageInterface::getEnclosingNode<SgBinaryComposite>(this);
1120  ROSE_ASSERT(binary!=NULL);
1122  for (size_t i=0; i<interps.size(); i++) {
1123  SgAsmGenericFilePtrList interp_files = interps[i]->get_files();
1124  if (interp_files.size()==1 && interp_files[0]==this) {
1125  std::string assembly = unparseAsmInterpretation(interps[i]);
1126  fputs(assembly.c_str(), dumpFile);
1127  }
1128  }
1129 
1130  } catch(...) {
1131  fclose(dumpFile);
1132  throw;
1133  }
1134  fclose(dumpFile);
1135 }
1136 
1137 /* Print basic info about the sections of a file */
1138 void
1140 {
1141  fprintf(f, "Encoding: %s\n", get_data_converter() ? escapeString(get_data_converter()->name()).c_str() : "none");
1142 
1144  if (sections.size()==0) {
1145  fprintf(f, "No sections defined for file.\n");
1146  return;
1147  }
1148 
1149  /* Sort sections by offset (lowest to highest), then size (largest to smallest but zero-sized entries first) */
1150  for (size_t i = 1; i < sections.size(); i++) {
1151  for (size_t j=0; j<i; j++) {
1152  if (sections[j]->get_offset() == sections[i]->get_offset()) {
1153  rose_addr_t size_i = sections[i]->get_size();
1154  if (0==size_i) size_i = ~(rose_addr_t)0;
1155  rose_addr_t size_j = sections[j]->get_size();
1156  if (0==size_j) size_j = ~(rose_addr_t)0;
1157  if (size_j < size_i) {
1158  SgAsmGenericSection *x = sections[j];
1159  sections[j] = sections[i];
1160  sections[i] = x;
1161  }
1162  } else if (sections[j]->get_offset() > sections[i]->get_offset()) {
1163  SgAsmGenericSection *x = sections[j];
1164  sections[j] = sections[i];
1165  sections[i] = x;
1166  }
1167  }
1168  }
1169 
1170  /* Print results */
1171  fprintf(f, "File sections:\n");
1172  fprintf(f, " Flg File-Addr File-Size File-End Base-VA Start-RVA Virt-Size End-RVA Perm ID Name\n");
1173  fprintf(f, " --- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---- --- -----------------\n");
1174  rose_addr_t high_water = 0;
1175  for (size_t i=0; i<sections.size(); i++) {
1176  SgAsmGenericSection *section = sections[i];
1177 
1178  /* Does section overlap with any other (before or after)? */
1179  char overlap[4] = " "; /* status characters: overlap prior, overlap subsequent, hole */
1180  for (size_t j=0; overlap[0]==' ' && j<i; j++) {
1181  if (sections[j]->get_offset()+sections[j]->get_size() > section->get_offset()) {
1182  overlap[0] = '<';
1183  }
1184  }
1185  for (size_t j=i+1; overlap[1]==' ' && j<sections.size(); j++) {
1186  if (section->get_offset()+section->get_size() > sections[j]->get_offset()) {
1187  overlap[1] = '>';
1188  }
1189  }
1190 
1191  /* Is there a hole before section[i]? */
1192  if (high_water < section->get_offset()) {
1193  overlap[2] = 'H'; /* truly unaccounted region of the file */
1194  } else if (i>0 && sections[i-1]->get_offset()+sections[i-1]->get_size() < section->get_offset()) {
1195  overlap[2] = 'h'; /* unaccounted only if overlaps are not allowed */
1196  }
1197  high_water = std::max(high_water, section->get_offset() + section->get_size());
1198  fprintf(f, " %3s", overlap);
1199 
1200  /* File addresses */
1201  fprintf(f, "%c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
1202  section->get_file_alignment()==0 || section->get_offset()%section->get_file_alignment()==0?' ':'!',
1203  section->get_offset(), section->get_size(), section->get_offset()+section->get_size());
1204 
1205  /* Mapped addresses */
1206  if (section->is_mapped()) {
1207  fprintf(f, " %c0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64" 0x%08"PRIx64,
1208  (section->get_mapped_alignment()==0 ||
1209  section->get_mapped_preferred_rva()%section->get_mapped_alignment()==0?' ':'!'),
1210  section->get_base_va(), section->get_mapped_preferred_rva(), section->get_mapped_size(),
1211  section->get_mapped_preferred_rva()+section->get_mapped_size());
1212  } else {
1213  fprintf(f, " %*s", 4*11, "");
1214  }
1215 
1216  /* Permissions */
1217  if (section->is_mapped()) {
1218  fprintf(f, " %c%c%c ",
1219  section->get_mapped_rperm()?'r':'-',
1220  section->get_mapped_wperm()?'w':'-',
1221  section->get_mapped_xperm()?'x':'-');
1222  } else {
1223  fputs(" ", f);
1224  }
1225 
1226  /* Section ID, name */
1227  if (section->get_id()>=0) {
1228  fprintf(f, " %3d", section->get_id());
1229  } else {
1230  fputs(" ", f);
1231  }
1232  fprintf(f, " %s\n", section->get_name()->get_string(true).c_str());
1233  }
1234 
1235  char overlap[4] = " ";
1236  if (high_water < get_current_size()) {
1237  overlap[2] = 'H';
1238  } else if (sections.back()->get_offset() + sections.back()->get_size() < get_current_size()) {
1239  overlap[2] = 'h';
1240  }
1241  fprintf(f, " %3s 0x%08"PRIx64"%*s EOF", overlap, get_current_size(), 76, "");
1242  if (get_current_size()!=p_data.size())
1243  fprintf(f, " (original EOF was 0x%08zx)", p_data.size());
1244  if (get_truncate_zeros())
1245  fputs(" [ztrunc]", f);
1246  fputc('\n', f);
1247  fprintf(f, " --- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---- --- -----------------\n");
1248 
1249  /* Show what part of the file has not been referenced */
1251  if (holes.size()>0) {
1252  fprintf(f, "These parts of the file have not been referenced during parsing:\n");
1253  holes.dump_extents(f, " ", "", false);
1254  }
1255 }
1256 
1260 void
1262 {
1263  /* Get the list of file extents referenced by all file sections */
1264  ExtentMap refs;
1266  for (SgAsmGenericSectionPtrList::iterator i=sections.begin(); i!=sections.end(); ++i) {
1267  refs.insert(Extent((*i)->get_offset(), (*i)->get_size()));
1268  }
1269 
1270  /* The hole extents are everything other than the sections */
1271  ExtentMap holes = refs.subtract_from(Extent(0, p_data.size()));
1272 
1273  /* Create the sections representing the holes */
1274  for (ExtentMap::iterator i=holes.begin(); i!=holes.end(); ++i) {
1275  Extent e = i->first;
1276  SgAsmGenericSection *hole = new SgAsmGenericSection(this, NULL);
1277  hole->set_offset(e.first());
1278  hole->set_size(e.size());
1279  hole->parse();
1280  hole->set_synthesized(true);
1281  hole->set_name(new SgAsmBasicString("hole"));
1283  add_hole(hole);
1284  }
1285 }
1286 
1288 void
1290 {
1291  set_isModified(true);
1292 
1294  for (size_t i=0; i<to_delete.size(); i++) {
1295  SgAsmGenericSection *hole = to_delete[i];
1297  }
1298 
1299  /* Destructor for holes should have removed links to those holes. */
1300  ROSE_ASSERT(get_holes()->get_sections().size()==0);
1301 }
1302 
1304 void
1306 {
1307  bool reallocated;
1308  do {
1309  reallocated = false;
1310 
1311  /* holes */
1312  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i) {
1313  if ((*i)->reallocate())
1314  reallocated = true;
1315  }
1316 
1317  /* file headers (and indirectly, all that they reference) */
1318  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i) {
1319  if ((*i)->reallocate())
1320  reallocated = true;
1321  }
1322  } while (reallocated);
1323 }
1324 
1329 void
1330 SgAsmGenericFile::unparse(std::ostream &f) const
1331 {
1332  if (get_neuter()) {
1333  f.seekp(0);
1334  f <<"NOTE: ROSE is refusing to create a binary file for this AST.\n"
1335  <<" See SgAsmGenericFile::set_neuter() for details.\n";
1336  return;
1337  }
1338 
1339 #if 0
1340  /* This is only for debugging -- fill the file with something other than zero so we have a better chance of making sure
1341  * that all data is written back to the file, including things that are zero. */
1342  rose_addr_t remaining = get_current_size();
1343  unsigned char buf[4096];
1344  memset(buf, 0xaa, sizeof buf);
1345  while (remaining>=sizeof buf) {
1346  f.write((const char*)buf, sizeof buf);
1347  ROSE_ASSERT(f);
1348  remaining -= sizeof buf;
1349  }
1350  f.write((const char*)buf, remaining);
1351  ROSE_ASSERT(f);
1352 #endif
1353 
1354  /* Write unreferenced sections (i.e., "holes") back to disk */
1355  for (SgAsmGenericSectionPtrList::iterator i=p_holes->get_sections().begin(); i!=p_holes->get_sections().end(); ++i)
1356  (*i)->unparse(f);
1357 
1358  /* Write file headers (and indirectly, all that they reference) */
1359  for (SgAsmGenericHeaderPtrList::iterator i=p_headers->get_headers().begin(); i!=p_headers->get_headers().end(); ++i)
1360  (*i)->unparse(f);
1361 
1362  /* Extend the file to the full size. The unparser will not write zero bytes at the end of a file because some files
1363  * actually use the fact that sections that extend past the EOF will be zero padded. For the time being we'll extend the
1364  * file to its full size. */
1365  if (!get_truncate_zeros())
1366  extend_to_eof(f);
1367 }
1368 
1370 void
1371 SgAsmGenericFile::extend_to_eof(std::ostream &f) const
1372 {
1373  f.seekp(0, std::ios::end);
1374  if (f.tellp()<(off_t)get_current_size()) {
1375  f.seekp(get_current_size()-1);
1376  const char zero = '\0';
1377  f.write(&zero, 1);
1378  }
1379 }
1380 
1381 
1384 const char *
1386 {
1387  return p_headers->get_headers().back()->format_name();
1388 }
1389 
1393 {
1394  SgAsmGenericHeader *retval = NULL;
1395  for (size_t i = 0; i < p_headers->get_headers().size(); i++) {
1396  if (p_headers->get_headers()[i]->get_exec_format()->get_family() == efam) {
1397  ROSE_ASSERT(NULL == retval);
1398  retval = p_headers->get_headers()[i];
1399  }
1400  }
1401 
1402  return retval;
1403 }