ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PeStringTable.C
Go to the documentation of this file.
1 /* String Tables (SgAsmPEStringSection and SgAsmCoffStrtab and related classes) */
2 
3 #include "sage3basic.h"
4 
5 
7 // String Table Sections
8 //
9 // SgAsmPEStringTable is derived from SgAsmPESection, which is derived in turn from SgAsmGenericSection. A PE String Table
10 // Section points to a COFF String Table (SgAsmCoffStrtab) that is contained in the section.
12 
13 /* Constructor */
14 void
16 {
17  get_name()->set_string("PE String Table");
18  p_strtab = new SgAsmCoffStrtab(this);
19 }
20 
23 {
25  ROSE_ASSERT(p_strtab);
26  p_strtab->parse();
27  return this;
28 }
29 
30 /* Reallocate space for the string table if necessary. Note that reallocation is lazy here -- we don't shrink the section,
31  * we only enlarge it (if you want the section to shrink then call SgAsmGenericStrtab::reallocate(bool) with a true value
32  * rather than calling this function. SgAsmPEStringSection::reallocate is called in response to unparsing a file and gives
33  * the string table a chance to extend its container section if it needs to allocate more space for strings. */
34 bool
36 {
37  return get_strtab()->reallocate(false);
38 }
39 
40 /* Unparse an ElfStringSection by unparsing the ElfStrtab */
41 void
42 SgAsmPEStringSection::unparse(std::ostream &f) const
43 {
44  get_strtab()->unparse(f);
45  unparse_holes(f);
46 }
47 
48 /* Augments superclass to make sure free list and such are adjusted properly */
49 void
51 {
52  rose_addr_t orig_size = get_size();
53  SgAsmPESection::set_size(newsize);
54  SgAsmGenericStrtab *strtab = get_strtab();
55 
56  if (get_size() > orig_size) {
57  /* Add new address space to string table free list */
58  rose_addr_t n = get_size() - orig_size;
59  strtab->get_freelist().insert(Extent(orig_size, n));
60  } else if (get_size() < orig_size) {
61  /* Remove deleted address space from string table free list */
62  rose_addr_t n = orig_size - get_size();
63  strtab->get_freelist().erase(Extent(get_size(), n));
64  }
65 }
66 
67 /* Print some debugging info */
68 void
69 SgAsmPEStringSection::dump(FILE *f, const char *prefix, ssize_t idx) const
70 {
71  char p[4096];
72  if (idx>=0) {
73  sprintf(p, "%sPEStringSection[%zd].", prefix, idx);
74  } else {
75  sprintf(p, "%sPEStringSection.", prefix);
76  }
77 
78  SgAsmPESection::dump(f, p, -1);
79 
80  ROSE_ASSERT(get_strtab()!=NULL);
81  get_strtab()->dump(f, p, -1);
82 
83  if (variantT() == V_SgAsmPEStringSection) //unless a base class
84  hexdump(f, 0, std::string(p)+"data at ", p_data);
85 }
86 
88 // String Tables
89 //
90 // An SgAsmCoffStrtab is a COFF String Table, inheriting from SgAsmGenericStrtab. String tables point to the
91 // SgAsmGenericSection that contains them.
93 
94 /* Free StringStorage objects associated with this string table. It may not be safe to blow them away yet since other objects
95  * may still have SgAsmStoredStrings pointing to these storage objects. So instead, we will mark all this strtab's storage
96  * objects as no longer being associated with a string table. This allows the SgAsmStoredString objects to still function
97  * properly and their destructors (~SgAsmStoredString) will free their storage. */
99 {
100  for (referenced_t::iterator i = p_storage_list.begin(); i != p_storage_list.end(); ++i) {
101  SgAsmStringStorage *storage = *i;
102  storage->set_strtab(NULL);
104  }
105  p_storage_list.clear();
106  p_dont_free = NULL; /*FIXME: can't delete for same reason as in SgAsmStoredString destructor. (RPM 2008-09-05) */
107 }
108 
109 /* Creates the storage item for the string at the specified offset. If "shared" is true then attempt to re-use a previous storage
110  * object, otherwise create a new one. Each storage object is considered to be a separate string, therefore when two strings
111  * share the same storage object, changing one string changes the other. */
114 {
115  ROSE_ASSERT(offset!=SgAsmGenericString::unallocated);
116  SgAsmGenericSection *container = get_container();
117 
118  /* Has the string already been created? */
119  if (shared) {
120  for (referenced_t::iterator i=p_storage_list.begin(); i!=p_storage_list.end(); ++i) {
121  if ((*i)->get_offset()==offset && (*i)!=p_dont_free)
122  return *i;
123  }
124  }
125 
126  /* Read string length byte */
127  unsigned char byte;
128  container->read_content_local(offset, &byte, 1);
129  unsigned len = byte;
130 
131  /* Make sure new storage isn't inside some other string. (We don't support nested strings in COFF where the length byte of
132  * the nested string is one of the characters of the outer string.) */
133  for (referenced_t::iterator i=p_storage_list.begin(); i!=p_storage_list.end(); ++i) {
134  ROSE_ASSERT((*i)->get_offset()==SgAsmGenericString::unallocated ||
135  offset + 1 + len <= (*i)->get_offset() ||
136  offset >= 1 + (*i)->get_string().size());
137  }
138 
139  /* Create storage object */
140  char *buf = new char[len];
141  container->read_content_local(offset+1, buf, len);
142  SgAsmStringStorage *storage = new SgAsmStringStorage(this, std::string(buf, len), offset);
143  delete[] buf;
144 
145  /* It's a bad idea to free (e.g., modify) strings before we've identified all the strings in the table. Consider
146  * the case where two strings have the same value and point to the same offset (i.e., they share storage). If we modify one
147  * before we know about the other then (at best) we modify the other one also.
148  *
149  * The only time we can guarantee this is OK is when the new storage points to the same file location as "dont_free"
150  * since the latter is guaranteed to never be freed or shared. This exception is used when creating a new, unallocated
151  * string (see SgAsmStoredString(SgAsmGenericStrtab,const std::string&)). */
152  if (p_num_freed>0 && (!p_dont_free || offset!=p_dont_free->get_offset())) {
153  fprintf(stderr,
154  "SgAsmCoffStrtab::create_storage(%"PRIu64"): %zu other string%s (of %zu created) in [%d] \"%s\""
155  " %s been modified and/or reallocated!\n",
156  offset, p_num_freed, 1==p_num_freed?"":"s", p_storage_list.size(),
157  container->get_id(), container->get_name()->get_string(true).c_str(),
158  1==p_num_freed?"has":"have");
159  ROSE_ASSERT(0==p_num_freed);
160  }
161 
162  set_isModified(true);
163  p_storage_list.push_back(storage);
164  return storage;
165 }
166 
167 /* Returns the number of bytes required to store the string in the string table. This is one (the length byte) plus the
168  * length of the string. */
171  return 1 + storage->get_string().size();
172 }
173 
174 /* Write string table back to disk. Free space is zeroed out; holes are left as they are. */
175 void
176 SgAsmCoffStrtab::unparse(std::ostream &f) const
177 {
178  SgAsmGenericSection *container = get_container();
179 
180  /* Write length coded strings. Shared strings will be written more than once, but that's OK. */
181  for (size_t i=0; i<p_storage_list.size(); i++) {
182  SgAsmStringStorage *storage = p_storage_list[i];
183  ROSE_ASSERT(storage->get_offset()!=SgAsmGenericString::unallocated);
184  rose_addr_t at = container->write(f, storage->get_offset(), storage->get_string());
185  container->write(f, at, '\0');
186  }
187 
188  /* Fill free areas with zero */
189  for (ExtentMap::const_iterator i=get_freelist().begin(); i!=get_freelist().end(); ++i) {
190  container->write(f, i->first.first(), std::string(i->first.size(), '\0'));
191  }
192 }