ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GenericSection.C
Go to the documentation of this file.
1 /* Generic Sections. SgAsmGenericSection serves as a base class for all binary file formats that divide a file into contiguous
2  * parts. The SgAsmGenericSection class describes such a part. Most binary formats will subclass this. */
3 
4 #include "sage3basic.h"
5 #include "stringify.h"
6 #include "MemoryMap.h"
7 
8 using namespace rose;
9 
14 void
16 {
17  ROSE_ASSERT(ef != NULL);
18 
19  ROSE_ASSERT(p_name==NULL);
20  p_name = new SgAsmBasicString("");
21  p_name->set_parent(this);
22 
23  /* Add this section to the header's section list */
24  if (hdr)
25  hdr->add_section(this);
26 }
27 
28 /* Destructor must remove section/header link */
30 {
31  SgAsmGenericFile* ef = get_file();
32  SgAsmGenericHeader *hdr = get_header();
33 
34  /* See constructor comment. This deletes both halves of the header/section link. */
35  if (hdr) {
36  hdr->remove_section(this);
37  set_header(NULL);
38  }
39 
40  /* See comment in ROSETTA/src/binaryInstruction.C. We need to explicitly delete the section name. */
41  if (p_name) {
43  p_name = NULL;
44  }
45 
46  /* FIXME: holes should probably be their own class, which would make the file/hole bidirectional linking more like the
47  * header/section bidirectional links (RPM 2008-09-02) */
48  ef->remove_hole(this);
49 
50  /* Delete children */
51  p_file = NULL; // deleted by SageInterface::deleteAST()
52 
53  /* If the section has allocated its own local pool for the p_data member (rather than pointing into the SgAsmGenericFile)
54  * then free that now. */
55  if (local_data_pool!=NULL) {
56  free(local_data_pool);
57  local_data_pool = NULL;
58  }
59 }
60 
72 bool
74 {
75  bool changed = false;
76 
77  if (get_file_alignment()>0) {
78  rose_addr_t old_offset = get_offset();
79  rose_addr_t new_offset = ALIGN_UP(old_offset, get_file_alignment());
80  set_offset(new_offset);
81  changed = changed ? true : (old_offset!=new_offset);
82  }
83 
84  if (is_mapped() && get_mapped_alignment()>0) {
85  rose_addr_t old_rva = get_mapped_preferred_rva();
86  rose_addr_t new_rva = ALIGN_UP(old_rva, get_mapped_alignment());
87  set_mapped_preferred_rva(new_rva);
88  changed = changed ? true : (old_rva!=new_rva);
89  }
90 
91  return changed;
92 }
93 
97 void
99 {
100  SgAsmGenericFile *ef = get_file();
101  ROSE_ASSERT(ef);
102 
103  if (get_offset()<=ef->get_orig_size()) {
104  if (get_offset()+get_size()<=ef->get_orig_size()) {
105  p_data = ef->content(get_offset(), get_size());
106  } else {
107  p_data = ef->content(get_offset(), ef->get_orig_size()-get_offset());
108  }
109  }
110 }
111 
117 unsigned char *
119 {
120  if (local_data_pool!=NULL)
121  free(local_data_pool);
122  local_data_pool = (unsigned char*)calloc(nbytes, 1);
123  p_data = SgSharedVector<unsigned char>(local_data_pool, nbytes);
124  return &(p_data[0]);
125 }
126 
130 {
131  return p_name;
132 }
133 
136 void
138 {
139  if (s!=p_name) {
140  if (p_name) {
141  p_name->set_parent(NULL);
142  SageInterface::deleteAST(p_name);
143  }
144  p_name = s;
145  if (p_name)
146  p_name->set_parent(this);
147  set_isModified(true);
148  }
149 }
150 
154 std::string
156 {
157  if (p_short_name.empty())
158  return get_name() ? get_name()->get_string() : std::string();
159  return p_short_name;
160 }
161 
163 void
165 {
166  p_short_name = name;
167 }
168 
173 {
174  return p_size;
175 }
176 
179 void
181 {
182  if (p_size!=size)
183  set_isModified(true);
184  p_size = size;
185 }
186 
190 {
191  return p_offset;
192 }
193 
196 void
198 {
199  if (p_offset!=offset)
200  set_isModified(true);
201  p_offset = offset;
202 }
203 
207 {
208  return get_offset() + get_size();
209 }
210 
212 Extent
214 {
215  return Extent(get_offset(), get_size());
216 }
217 
219 bool
221 {
222  return (get_mapped_preferred_rva()!=0 || get_mapped_size()!=0 ||
223  get_mapped_rperm() || get_mapped_wperm() || get_mapped_xperm());
224 }
225 
227 void
229 {
230  set_mapped_size(0);
231  set_mapped_preferred_rva(0);
232  set_mapped_actual_va(0);
233  set_mapped_rperm(false);
234  set_mapped_wperm(false);
235  set_mapped_xperm(false);
236 }
237 
241 {
242  ROSE_ASSERT(this != NULL);
243  return p_mapped_size;
244 }
245 
248 void
250 {
251  ROSE_ASSERT(this != NULL);
252  if (p_mapped_size!=size)
253  set_isModified(true);
254  p_mapped_size = size;
255 }
256 
260 {
261  ROSE_ASSERT(this != NULL);
262  return p_mapped_preferred_rva;
263 }
264 
266 void
268 {
269  ROSE_ASSERT(this != NULL);
270  if (p_mapped_preferred_rva!=a)
271  set_isModified(true);
272  p_mapped_preferred_rva = a;
273 }
274 
278 {
279  ROSE_ASSERT(this != NULL);
280  if (is_mapped())
281  return get_base_va() + get_mapped_preferred_rva();
282  return 0;
283 }
284 
288 {
289  ROSE_ASSERT(this != NULL);
290 
291  if (isSgAsmGenericHeader(this))
292  return isSgAsmGenericHeader(this)->get_base_va();
293 
294  SgAsmGenericHeader *hdr = get_header();
295  return hdr ? hdr->get_base_va() : 0;
296 }
297 
299 Extent
301 {
302  ROSE_ASSERT(this != NULL);
303  return Extent(get_mapped_preferred_rva(), get_mapped_size());
304 }
305 
311 size_t
312 SgAsmGenericSection::read_content(rose_addr_t start_offset, void *dst_buf, rose_addr_t size, bool strict)
313 {
314  SgAsmGenericFile *file = get_file();
315  ROSE_ASSERT(file!=NULL);
316  return file->read_content(start_offset, dst_buf, size, strict);
317 }
318 
326 size_t
327 SgAsmGenericSection::read_content(const MemoryMap *map, rose_addr_t start_va, void *dst_buf, rose_addr_t size, bool strict)
328 {
329  SgAsmGenericFile *file = get_file();
330  ROSE_ASSERT(file!=NULL);
331  return file->read_content(map, start_va, dst_buf, size, strict);
332 }
333 
338 size_t
339 SgAsmGenericSection::read_content_local(rose_addr_t start_offset, void *dst_buf, rose_addr_t size, bool strict)
340 {
341  size_t retval;
342  SgAsmGenericFile *file = get_file();
343  ROSE_ASSERT(file!=NULL);
344  if (start_offset > get_size()) {
345  if (strict)
346  throw ShortRead(this, start_offset, size);
347  retval = 0;
348  } else if (start_offset+size > get_size()) {
349  if (strict)
350  throw ShortRead(this, get_size(), start_offset+size-get_size());
351  retval = get_size() - start_offset;
352  } else {
353  retval = size;
354  }
355 
356  file->read_content(get_offset()+start_offset, dst_buf, retval, true);
357  memset((char*)dst_buf+retval, 0, size-retval);
358  return retval;
359 }
360 
365 {
366  SgUnsignedCharList retval;
367  unsigned char *buf = new unsigned char[size];
368  read_content_local(rel_offset, buf, size, false); /*zero pads; never throws*/
369  for (size_t i=0; i<size; i++)
370  retval.push_back(buf[i]);
371  delete[] buf;
372  return retval;
373 }
374 
379 std::string
381 {
382  SgAsmGenericFile *file = get_file();
383  ROSE_ASSERT(file!=NULL);
384  return file->read_content_str(map, start_va, strict);
385 }
386 
390 std::string
392 {
393  SgAsmGenericFile *file = get_file();
394  ROSE_ASSERT(file!=NULL);
395  return file->read_content_str(abs_offset, strict);
396 }
397 
401 std::string
403 {
404  static char *buf=NULL;
405  static size_t nalloc=0;
406  size_t nused=0;
407 
408  while (1) {
409  if (nused >= nalloc) {
410  nalloc = std::max((size_t)32, 2*nalloc);
411  buf = (char*)realloc(buf, nalloc);
412  ROSE_ASSERT(buf!=NULL);
413  }
414 
415  unsigned char byte;
416  read_content_local(rel_offset+nused, &byte, 1, strict);
417  if (!byte)
418  return std::string(buf, nused);
419  buf[nused++] = byte;
420  }
421 }
422 
426 uint64_t
428 {
429  int shift=0;
430  uint64_t retval=0;
431  while (1) {
432  unsigned char byte;
433  read_content_local(*rel_offset, &byte, 1, strict);
434  *rel_offset += 1;
435  ROSE_ASSERT(shift<64);
436  retval |= (byte & 0x7f) << shift;
437  shift += 7;
438  if (0==(byte & 0x80))
439  break;
440  }
441  return retval;
442 }
443 
447 int64_t
449 {
450  int shift=0;
451  int64_t retval=0;
452  while (1) {
453  unsigned char byte;
454  read_content_local(*rel_offset, &byte, 1, strict);
455  *rel_offset += 1;
456  ROSE_ASSERT(shift<64);
457  retval |= (byte & 0x7f) << shift;
458  shift += 7;
459  if (0==(byte & 0x80))
460  break;
461  }
462  retval = (retval << (64-shift)) >> (64-shift); /*sign extend*/
463  return retval;
464 }
465 
480 SgAsmGenericSection::write(std::ostream &f, rose_addr_t offset, size_t bufsize, const void *buf) const
481 {
482  size_t nwrite, nzero;
483 
484  ROSE_ASSERT(this != NULL);
485 
486  /* Don't write past end of section */
487  if (offset>=get_size()) {
488  nwrite = 0;
489  nzero = bufsize;
490  } else if (offset+bufsize<=get_size()) {
491  nwrite = bufsize;
492  nzero = 0;
493  } else {
494  nwrite = get_size() - offset;
495  nzero = bufsize - nwrite;
496  }
497 
498  /* Don't write past end of current EOF if we can help it. */
499  f.seekp(0, std::ios::end);
500  rose_addr_t filesize = f.tellp();
501  while (nwrite>0 && 0==((const char*)buf)[nwrite-1] && get_offset()+offset+nwrite>filesize)
502  --nwrite;
503 
504  /* Write bytes to file. This is a good place to set a break point if you're trying to figure out what section is writing
505  * to a particular file address. For instance, if byte 0x7c is incorrect in the unparsed file you would set a conditional
506  * breakpoint for o<=0x7c && o+nwrite>0x7c */
507  ROSE_ASSERT(f);
508  off_t o = get_offset() + offset;
509  f.seekp(o);
510  ROSE_ASSERT(f);
511  f.write((const char*)buf, nwrite);
512  ROSE_ASSERT(f);
513 
514  /* Check that truncated data is all zero and fail if it isn't */
515  for (size_t i=nwrite; i<bufsize; i++) {
516  if (((const char*)buf)[i]) {
517  char mesg[1024];
518  sprintf(mesg, "non-zero value truncated: buf[0x%zx]=0x%02x", i, ((const unsigned char*)buf)[i]);
519  fprintf(stderr, "SgAsmGenericSection::write: error: %s", mesg);
520  fprintf(stderr, " in [%d] \"%s\"\n", get_id(), get_name()->get_string(true).c_str());
521  fprintf(stderr, " section is at file offset 0x%08"PRIx64" (%"PRIu64"), size 0x%"PRIx64" (%"PRIu64") bytes\n",
522  get_offset(), get_offset(), get_size(), get_size());
523  fprintf(stderr, " write %zu byte%s at section offset 0x%08"PRIx64"\n", bufsize, 1==bufsize?"":"s", offset);
524  fprintf(stderr, " ");
525  HexdumpFormat hf;
526  hf.prefix = " ";
527  hexdump(stderr, get_offset()+offset, (const unsigned char*)buf, bufsize, hf);
528  fprintf(stderr, "\n");
529  throw SgAsmGenericFile::ShortWrite(this, offset, bufsize, mesg);
530  }
531  }
532 
533  return offset+bufsize;
534 }
535 
536 /* See related method above */
539 {
540  if (0==buf.size())
541  return 0;
542  return write(f, offset, buf.size(), &(buf[0]));
543 }
544 
545 /* See related method above */
548 {
549  if (0==buf.size())
550  return 0;
551  return write(f, offset, buf.size(), (void*)&(buf[0]));
552 }
553 
554 /* See related method above. */
556 SgAsmGenericSection::write(std::ostream &f, rose_addr_t offset, const std::string &str) const
557 {
558  return write(f, offset, str.size(), &(str[0]));
559 }
560 
561 /* See related method above. */
563 SgAsmGenericSection::write(std::ostream &f, rose_addr_t offset, char c) const
564 {
565  return write(f, offset, 1, &c);
566 }
567 
570 SgAsmGenericSection::write_uleb128(unsigned char *buf, rose_addr_t offset, uint64_t val) const
571 {
572  if (val==0) {
573  buf[offset++] = 0;
574  } else {
575  while (val) {
576  unsigned char byte = val & 0x7f;
577  val >>= 7;
578  if (val!=0)
579  byte |= 0x80;
580  buf[offset++] = byte;
581  }
582  }
583  return offset;
584 }
585 
588 SgAsmGenericSection::write_sleb128(unsigned char *buf, rose_addr_t offset, int64_t val) const
589 {
590  if (val==0) {
591  buf[offset++] = 0;
592  } else if (val==-1) {
593  buf[offset++] = 0x7f;
594  } else {
595  while (val!=0 && val!=-1) {
596  unsigned char byte = (uint64_t)val & 0x7f;
597  val >>= 7; /*sign extending*/
598  if (val!=0 && val!=-1)
599  byte |= 0x80;
600  buf[offset++] = byte;
601  }
602  }
603  return offset;
604 }
605 
608 ExtentMap
610 {
611  ExtentMap retval;
612  if (0==get_size())
613  return retval;
614 
615  Extent s(get_offset(), get_size());
616  const ExtentMap &file_extents = get_file()->get_referenced_extents();
617  for (ExtentMap::const_iterator i=file_extents.begin(); i!=file_extents.end(); i++) {
618  Extent e = i->first;
619  if (e.contained_in(s)) {
620  retval.insert(Extent(e.first()-get_offset(), e.size()));
621  } else if (e.left_of(s) || e.right_of(s)) {
622  /*void*/
623  } else if (e.contains(s)) {
624  retval.insert(Extent(0, get_size()));
625  } else if (e.begins_before(s)) {
626  retval.insert(Extent(0, e.first()+e.size()-get_offset()));
627  } else if (e.ends_after(s)) {
628  retval.insert(Extent(e.first()-get_offset(), get_offset()+get_size()-e.first()));
629  } else {
630  assert(!"invalid extent overlap category");
631  abort();
632  }
633  }
634  return retval;
635 }
636 
637 ExtentMap
639 {
640  return get_referenced_extents().subtract_from(Extent(0, get_size())); /*complement*/
641 }
642 
648 void
650 {
651  ROSE_ASSERT(get_file() != NULL);
652  ROSE_ASSERT(get_file()->get_tracking_references()); /*can only be called during the parsing phase*/
653  rose_addr_t new_size = get_size() + size;
654 
655  /* Ending file address for section using new size, limited by total file size */
656  rose_addr_t new_end = std::min(get_file()->get_orig_size(), get_offset()+new_size);
657  if (get_offset()<=new_end) {
658  p_data.resize(new_end-get_offset());
659  } else {
660  ROSE_ASSERT(0==p_data.size());
661  }
662 
663  if (p_size!=new_size)
664  set_isModified(true);
665  p_size = new_size;
666 }
667 
671 {
672  try {
673  SgAsmGenericHeader *retval = dynamic_cast<SgAsmGenericHeader*>(this);
674  return retval;
675  } catch(...) {
676  return NULL;
677  }
678 }
679 
682 void
683 SgAsmGenericSection::unparse(std::ostream &f) const
684 {
685 #if 0
686  /* FIXME: for now we print the names of all sections we dump using this method. Eventually most of these sections will
687  * have subclasses that override this method. */
688  fprintf(stderr, "SgAsmGenericSection::unparse(FILE*) for section [%d] \"%s\"\n", id, name.c_str());
689 #endif
690 
691  write(f, 0, p_data);
692 }
693 
695 void
696 SgAsmGenericSection::unparse(std::ostream &f, const ExtentMap &map) const
697 {
698  for (ExtentMap::const_iterator i=map.begin(); i!=map.end(); ++i) {
699  Extent e = i->first;
700  assert(e.first()+e.size() <= get_size());
701  const unsigned char *extent_data;
702  size_t nwrite;
703  if (e.first() >= p_data.size()) {
704  extent_data = NULL;
705  nwrite = 0;
706  } else if (e.first() + e.size() > p_data.size()) {
707  extent_data = &p_data[e.first()];
708  nwrite = p_data.size() - e.first();
709  } else {
710  extent_data = &p_data[e.first()];
711  nwrite = e.size();
712  }
713  if (extent_data)
714  write(f, e.first(), e.size(), extent_data);
715  }
716 }
717 
719 void
721 {
722 #if 0 /*DEBUGGING*/
723  ExtentMap holes = get_unreferenced_extents();
724  fprintf(stderr, "Section \"%s\", 0x%"PRIx64" bytes\n", get_name()->get_string(true).c_str(), get_size());
725  holes.dump_extents(stderr, " ", "");
726 #endif
727 // unparse(f, get_unreferenced_extents());
728 }
729 
735 {
736  return get_va_offset(rva + get_base_va());
737 }
738 
744 {
745  ROSE_ASSERT(is_mapped());
746  ROSE_ASSERT(va >= get_base_va());
747  rose_addr_t rva = va - get_base_va();
748  ROSE_ASSERT(rva >= get_mapped_preferred_rva());
749  return get_offset() + (rva - get_mapped_preferred_rva());
750 }
751 
753 void
755  const SgAsmGenericSectionPtrList &slist)
756 {
757  for (size_t i=0; i<slist.size(); i++) {
758  SgAsmGenericSection *s = slist[i];
759  if (s->is_mapped() && rva>=s->get_mapped_preferred_rva() && rva<s->get_mapped_preferred_rva()+s->get_mapped_size()) {
761  fprintf(f, "%-*s is 0x%08"PRIx64" (%"PRIu64") bytes into section [%d] \"%s\"\n",
762  DUMP_FIELD_WIDTH, prefix.c_str(), offset, offset, s->get_id(), s->get_name()->get_string(true).c_str());
763  }
764  }
765 }
766 
767 /* Print some debugging info */
768 void
769 SgAsmGenericSection::dump(FILE *f, const char *prefix, ssize_t idx) const
770 {
771  char p[4096];
772  if (idx>=0) {
773  sprintf(p, "%sSection[%zd].", prefix, idx);
774  } else {
775  sprintf(p, "%sSection.", prefix);
776  }
777 
778  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
779 
780  fprintf(f, "%s%-*s = \"%s\"", p, w, "name", p_name->get_string(true).c_str());
781  if (!p_short_name.empty())
782  fprintf(f, " (%s)", p_short_name.c_str());
783  fprintf(f, "\n");
784  fprintf(f, "%s%-*s = %d\n", p, w, "id", p_id);
785  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes into file\n", p, w, "offset", p_offset, p_offset);
786  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes\n", p, w, "size", get_size(), get_size());
787  if (0==get_file_alignment()) {
788  fprintf(f, "%s%-*s = not specified\n", p, w, "file_alignment");
789  } else {
790  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") %s\n", p, w, "file_alignment",
791  get_file_alignment(), get_file_alignment(),
792  0==get_offset()%get_file_alignment()?"satisfied":"NOT SATISFIED");
793  }
794  fprintf(f, "%s%-*s = %s\n", p, w, "synthesized", p_synthesized?"yes":"no");
795  if (p_header) {
796  fprintf(f, "%s%-*s = \"%s\"\n", p, w, "header", p_header->get_name()->get_string(true).c_str());
797  } else {
798  fprintf(f, "%s%-*s = not associated\n", p, w, "header");
799  }
800 
801  std::string purpose = stringifySgAsmGenericSectionSectionPurpose(p_purpose);
802  fprintf(f, "%s%-*s = %s\n", p, w, "purpose", purpose.c_str());
803 
804  if (is_mapped()) {
805  fprintf(f, "%s%-*s = rva=0x%08"PRIx64", size=%"PRIu64" bytes\n", p, w, "mapped", p_mapped_preferred_rva, p_mapped_size);
806  if (0==get_mapped_alignment()) {
807  fprintf(f, "%s%-*s = not specified\n", p, w, "mapped_alignment");
808  } else {
809  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") %s\n", p, w, "mapped_alignment",
810  get_mapped_alignment(), get_mapped_alignment(),
811  0==get_mapped_preferred_rva()%get_mapped_alignment()?"satisfied":"NOT SATISFIED");
812  }
813  fprintf(f, "%s%-*s = %c%c%c\n", p, w, "permissions",
814  get_mapped_rperm()?'r':'-', get_mapped_wperm()?'w':'-', get_mapped_xperm()?'x':'-');
815  } else {
816  fprintf(f, "%s%-*s = <not mapped>\n", p, w, "mapped");
817  }
818 
819  fprintf(f, "%s%-*s = %s\n", p, w, "contains_code", get_contains_code()?"true":"false");
820  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") \n", p, w, "mapped_actual_va", p_mapped_actual_va, p_mapped_actual_va);
821 
822  // DQ (8/31/2008): Output the contents if this not derived from (there is likely a
823  // better implementation if the hexdump function was a virtual member function).
824  if (variantT() == V_SgAsmGenericSection) {
825  hexdump(f, 0, std::string(p)+"data at ", p_data);
826  }
827 }