ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ElfStringTable.C
Go to the documentation of this file.
1 /* ELF String Tables
2  *
3  * String tables are represented with two main classes:
4  *
5  * SgAsmElfStringSection is an SgAsmElfSection that contains a string table. It points to an SgAsmElfStrtab.
6  *
7  * SgAsmElfStrtab is a class representing the string table contained in an SgAsmElfStringSection. It inherits from
8  * SgAsmGenericStrtab. An SgAsmElfStrtab points back to the SgAsmElfStringSection that contains it.
9  */
10 
11 #include "sage3basic.h"
12 
14 void
16 {
17  get_name()->set_string("ELF String Table");
18  if (get_size()==0)
19  set_size(1);
20  p_strtab = new SgAsmElfStrtab(this);
21 }
22 
26 {
28  ROSE_ASSERT(p_strtab);
29  p_strtab->get_freelist().clear(); /*because set_size() during construction added to the free list*/
30  p_strtab->parse();
31  return this;
32 }
33 
38 bool
40 {
41  bool reallocated = SgAsmElfSection::reallocate();
42  if (get_strtab()->reallocate(false))
43  reallocated = true;
44 
45  /* Update parts of the section and segment tables not updated by superclass */
47  if (secent)
49 
50  return reallocated;
51 }
52 
54 void
55 SgAsmElfStringSection::unparse(std::ostream &f) const
56 {
57  get_strtab()->unparse(f);
58  unparse_holes(f);
59 }
60 
63 void
65 {
66  rose_addr_t orig_size = get_size();
68  SgAsmGenericStrtab *strtab = get_strtab();
69 
70  if (strtab) {
71  if (get_size() > orig_size) {
72  /* Add new address space to string table free list */
73  rose_addr_t n = get_size() - orig_size;
74  strtab->get_freelist().insert(Extent(orig_size, n));
75  } else if (get_size() < orig_size) {
76  /* Remove deleted address space from string table free list */
77  rose_addr_t n = orig_size - get_size();
78  strtab->get_freelist().erase(Extent(get_size(), n));
79  }
80  }
81 }
82 
84 void
85 SgAsmElfStringSection::dump(FILE *f, const char *prefix, ssize_t idx) const
86 {
87  char p[4096];
88  if (idx>=0) {
89  sprintf(p, "%sElfStringSection[%zd].", prefix, idx);
90  } else {
91  sprintf(p, "%sElfStringSection.", prefix);
92  }
93 
94  SgAsmElfSection::dump(f, p, -1);
95 
96  ROSE_ASSERT(get_strtab()!=NULL);
97  get_strtab()->dump(f, p, -1);
98 
99  if (variantT() == V_SgAsmElfStringSection) //unless a base class
100  hexdump(f, 0, std::string(p)+"data at ", p_data);
101 }
102 
103 
105 void
107 {
108  ROSE_ASSERT(get_container());
109  if (get_container()->get_size()==0)
110  get_container()->set_size(1);
111  p_dont_free = create_storage(0, false);
112 }
113 
118 {
120  ROSE_ASSERT(get_container());
121  if (get_container()->get_size()>0) {
122  unsigned char first_byte;
123  get_container()->read_content_local(0, &first_byte, 1);
124  if (first_byte=='\0') {
125  if (p_dont_free) {
126  ROSE_ASSERT(0==p_dont_free->get_offset());
127  } else {
128  p_dont_free = create_storage(0, false);
129  }
130  } else if (p_dont_free) {
131  p_dont_free = NULL;
132  }
133  }
134  return this;
135 }
136 
142 {
143  for (referenced_t::iterator i = p_storage_list.begin(); i != p_storage_list.end(); ++i) {
144  SgAsmStringStorage *storage = *i;
145  storage->set_strtab(NULL);
147  }
148  p_storage_list.clear();
149  p_dont_free = NULL; /*FIXME: can't delete for same reason as in SgAsmStoredString destructor. (RPM 2008-09-05) */
150 }
151 
157 {
158  ROSE_ASSERT(offset!=SgAsmGenericString::unallocated);
159 
160  /* Has this string already been created? If so, return previous storage object. However, never share the empty_string at
161  * offset zero created when this string table was constructed because the ELF spec says it needs to stay there whether
162  * referenced or not. */
163  if (shared) {
164  for (referenced_t::iterator i=p_storage_list.begin(); i!=p_storage_list.end(); i++) {
165  if ((*i)->get_offset()==offset && (*i) != p_dont_free)
166  return *i;
167  }
168  }
169 
170  /* Create a new storage object at this offset. */
171  SgAsmStringStorage *storage = NULL;
172  if (0==offset && 0==get_container()->get_data().size()) {
173  ROSE_ASSERT(get_container()->get_size()>=1);
174  storage = new SgAsmStringStorage(this, "", 0);
175  } else {
176  std::string s = get_container()->read_content_local_str(offset);
177  storage = new SgAsmStringStorage(this, s, offset);
178  }
179 
180  /* It's a bad idea to free (e.g., modify) strings before we've identified all the strings in the table. Consider
181  * the case where offset 1 is "domain" and offset 3 is "main" (i.e., they overlap). If we modify "main" before knowing
182  * about "domain" then we'll end up freeing the last part of "domain" (and possibly replacing it with something else)!
183  *
184  * The only time we can guarantee this is OK is when the new storage points to the same file location as "dont_free"
185  * since the latter is guaranteed to never be freed or shared. This exception is used when creating a new, unallocated
186  * string (see SgAsmStoredString(SgAsmGenericStrtab,const std::string&)). */
187  if (p_num_freed>0 && (!p_dont_free || offset!=p_dont_free->get_offset())) {
188  fprintf(stderr,
189  "SgAsmElfStrtab::create_storage(%"PRIu64"): %zu other string%s (of %zu created) in [%d] \"%s\""
190  " %s been modified and/or reallocated!\n",
191  offset, p_num_freed, 1==p_num_freed?"":"s", p_storage_list.size(),
192  get_container()->get_id(), get_container()->get_name()->get_string(true).c_str(),
193  1==p_num_freed?"has":"have");
194  ROSE_ASSERT(0==p_num_freed);
195  }
196 
197  p_storage_list.push_back(storage);
198  set_isModified(true);
199  return storage;
200 }
201 
203 void
205 {
206  ROSE_ASSERT(p_dont_free && storage!=p_dont_free && storage->get_offset()==p_dont_free->get_offset());
207  std::string s = get_container()->read_content_local_str(offset);
208  storage->set_offset(offset);
209  storage->set_string(s);
210 }
211 
216  return storage->get_string().size() + 1;
217 }
218 
225 void
227 {
228  ROSE_ASSERT(storage->get_offset()==SgAsmGenericString::unallocated);
229  size_t need = storage->get_string().size();
230  for (size_t i=0; i<p_storage_list.size(); i++) {
231  SgAsmStringStorage *existing = p_storage_list[i];
232  if (existing->get_offset()!=SgAsmGenericString::unallocated) {
233  size_t have = existing->get_string().size();
234  if (need<=have && 0==existing->get_string().compare(have-need, need, storage->get_string())) {
235  /* An existing string ends with the new string. */
236  storage->set_offset(existing->get_offset() + (have-need));
237  return;
238  } else if (need>have && existing->get_offset()>=need-have &&
239  0==storage->get_string().compare(need-have, have, existing->get_string())) {
240  /* New string ends with an existing string. Check for, and allocate, free space. */
241  rose_addr_t offset = existing->get_offset() - (need-have); /* positive diffs checked above */
242  if (get_freelist().subtract_from(Extent(offset, need-have)).size()==0) {
243  get_freelist().allocate_at(Extent(offset, need-have));
244  storage->set_offset(offset);
245  return;
246  }
247  }
248  }
249  }
250 }
251 
253 void
254 SgAsmElfStrtab::unparse(std::ostream &f) const
255 {
256  SgAsmGenericSection *container = get_container();
257 
258  /* Write strings with NUL termination. Shared strings will be written more than once, but that's OK. */
259  for (size_t i=0; i<p_storage_list.size(); i++) {
260  SgAsmStringStorage *storage = p_storage_list[i];
261  ROSE_ASSERT(storage->get_offset()!=SgAsmGenericString::unallocated);
262  rose_addr_t at = container->write(f, storage->get_offset(), storage->get_string());
263  container->write(f, at, '\0');
264  }
265 
266  /* Fill free areas with zero */
267  for (ExtentMap::const_iterator i=get_freelist().begin(); i!=get_freelist().end(); ++i) {
268  container->write(f, i->first.first(), std::string(i->first.size(), '\0'));
269  }
270 }