ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GenericString.C
Go to the documentation of this file.
1 /* Strings. Uniform treatment for strings stored in a binary file and strings generated on the fly. */
2 
3 #include "sage3basic.h"
4 
5 std::string
7 {
8  ROSE_ASSERT(!"should have been pure virtual if ROSETTA supported that.");
9  abort();
10 
11  // DQ (11/27/2009): MSVC requires a return stmt for any non-void return type of a function.
12  return "error in SgAsmGenericString::get_string()";
13 }
14 
15 void
16 SgAsmGenericString::set_string(const std::string &s)
17 {
18  ROSE_ASSERT(!"should have been pure virtual if ROSETTA supported that.");
19  abort();
20 }
21 
22 void
24 {
25  ROSE_ASSERT(!"should have been pure virtual if ROSETTA supported that.");
26  abort();
27 }
28 
29 void
30 SgAsmGenericString::dump(FILE*, const char *prefix, ssize_t idx) const
31 {
32  ROSE_ASSERT(!"should have been pure virtual if ROSETTA supported that.");
33  abort();
34 }
35 
36 /* Constructor */
37 void
39 {
40 #if 0
41  fprintf(stderr, "SgAsmBasicString::ctor this=0x%08lx\n", (unsigned long)this);
42  if (this==(void*)0x685998)
43  abort(); /*DEBUGGING (rpm 2008-10-10)*/
44 #endif
45 }
46 
47 /* Override ROSETTA because generated code doesn't match virtual signature in base class */
48 std::string
50 {
51  if (escape)
52  return escapeString(p_string);
53  return p_string;
54 }
55 void
56 SgAsmBasicString::set_string(const std::string &s)
57 {
58  if (p_string!=s)
59  set_isModified(true);
60  p_string = s;
61 }
62 void
64 {
65  fprintf(stderr, "SgAsmBasicString::set_string(rose_addr_t offset=%"PRIu64"): not supported\n", offset);
66  abort();
67 }
68 
69 /* Print some debugging info */
70 void
71 SgAsmBasicString::dump(FILE *f, const char *prefix, ssize_t idx) const
72 {
73  char p[4096];
74  if (idx>=0) {
75  sprintf(p, "%sBasicString[%zd].", prefix, idx);
76  } else {
77  sprintf(p, "%sBasicString.", prefix);
78  }
79  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
80  fprintf(f, "%s%-*s = \"%s\"\n", p, w, "value", get_string(true).c_str());
81 }
82 
83 /* Stored String constructors/destructor */
84 void
86 {
87  p_storage = strtab->create_storage(offset, shared);
88 }
89 void
90 SgAsmStoredString::ctor(SgAsmGenericStrtab *strtab, const std::string &s)
91 {
92  p_storage = strtab->create_storage(0, false);
93  set_string(s);
94 }
95 void
97 {
98  p_storage = storage;
99 }
100 #if 0
101 // DQ (9/9/2008): Use the destructor built automatically by ROSETTA.
103 {
104 #if 0 /* FIXME: Strings may share storage, so we can't free it. (RPM 2008-09-03) */
105  /* Free storage if it isn't associated with a string table. */
106  if (p_storage && NULL==p_storage->strtab)
107  delete p_storage;
108 #endif
109  p_storage = NULL;
110 }
111 #endif
112 
114 std::string
116 {
117  std::string retval = get_storage()->get_string();
118  if (escape)
119  retval = escapeString(retval);
120  return retval;
121 }
122 
127 {
128  if (NULL==get_storage())
129  return unallocated;
130  if (get_storage()->get_offset() == unallocated) {
132  ROSE_ASSERT(strtab!=NULL);
133  strtab->reallocate(false);
134  ROSE_ASSERT(get_storage()->get_offset() != unallocated);
135  }
136  return get_storage()->get_offset();
137 }
138 
142 {
143  return get_storage()->get_strtab();
144 }
145 
147 void
148 SgAsmStoredString::set_string(const std::string &s)
149 {
150  if (get_string()==s) return; /* no change in value */
151  set_isModified(true);
152  SgAsmStringStorage *storage = get_storage();
153  ROSE_ASSERT(storage!=NULL); /* we don't even know which string table! */
154  storage->get_strtab()->free(storage);
155  storage->set_string(s);
156 }
157 
159 void
161 {
162  set_isModified(true);
163  SgAsmStringStorage *storage = get_storage();
164  ROSE_ASSERT(storage!=NULL); /* we don't even know which string table! */
165  storage->get_strtab()->rebind(storage, offset);
166 }
167 
168 /* Print some debugging info */
169 void
170 SgAsmStoredString::dump(FILE *f, const char *prefix, ssize_t idx) const
171 {
172  char p[4096];
173  if (idx>=0) {
174  sprintf(p, "%sStoredString[%zd].", prefix, idx);
175  } else {
176  sprintf(p, "%sStoredString.", prefix);
177  }
178  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
179 
180  fprintf(f, "%s%-*s = 0x%08lx\n", p, w, "storage", (unsigned long)get_storage());
181  if (get_storage())
182  get_storage()->dump(f, p, -1);
183 }
184 
185 /* Print some debugging info */
186 void
187 SgAsmStringStorage::dump(FILE *f, const char *prefix, ssize_t idx) const
188 {
189  char p[4096];
190  if (idx>=0) {
191  sprintf(p, "%sStringStorage[%zd].", prefix, idx);
192  } else {
193  sprintf(p, "%sStringStorage.", prefix);
194  }
195  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
196 
197  fprintf(f, "%s%-*s =", p, w, "sec,offset,val");
198  SgAsmGenericStrtab *strtab = get_strtab();
199  if (strtab) {
200  fprintf(f, " section [%d] \"%s\"",
201  strtab->get_container()->get_id(),
202  strtab->get_container()->get_name()->get_string(true).c_str());
203  } else {
204  fputs(" no section", f);
205  }
206  if (!strtab || get_offset()==SgAsmGenericString::unallocated) {
207  fputs(", not allocated", f);
208  } else {
209  fprintf(f, ", offset 0x%08"PRIx64" (%"PRIu64")", get_offset(), get_offset());
210  }
211  fprintf(f, ", \"%s\"\n", escapeString(get_string()).c_str());
212 }
213 
217 {
218  SgAsmStringStorage *storage = create_storage(offset, shared);
219  return new SgAsmStoredString(storage);
220 }
221 
224 void
226 {
227  ROSE_ASSERT(storage!=NULL);
228  ROSE_ASSERT(storage!=p_dont_free);
229  rose_addr_t old_offset = storage->get_offset();
230  if (old_offset!=SgAsmGenericString::unallocated) {
231  set_isModified(true);
233  free(old_offset, storage->get_string().size()+1);
234  }
235 }
236 
240 void
242 {
243  if (offset==SgAsmGenericString::unallocated || 0==size)
244  return;
245 
246  ROSE_ASSERT(offset+size <= get_container()->get_size());
247  set_isModified(true);
248 
249  /* Make sure area is not already in free list. The freelist.insert() handles this gracefully, but if we're freeing
250  * something that's already in the list then we have a logic error somewhere. */
251  ROSE_ASSERT(!get_freelist().overlaps(Extent(offset, size)));
252 
253  /* Preserve anything that's still referenced. The caller should have assigned SgAsmStoredString::unalloced to the "offset"
254  * member of the string storage to indicate that it's memory in the string table is no longer in use. */
255  ExtentMap s_extents;
256  for (size_t i=0; i<p_storage_list.size(); i++) {
257  SgAsmStringStorage *storage = p_storage_list[i];
259  s_extents.insert(Extent(storage->get_offset(), get_storage_size(storage)));
260  }
261  ExtentMap to_free = s_extents.subtract_from(Extent(offset, size));
262 
263  /* Add un-refrened extents to free list. */
264  get_freelist().insert_ranges(to_free);
265 }
266 
270 void
272 {
273  SgAsmGenericSection *container = get_container();
274  SgAsmGenericFile *file = container->get_file();
275  bool is_tracking = file->get_tracking_references();
276  set_isModified(true);
277 
278  /* Mark all storage objects as being unallocated. Never free the dont_free storage (if any). */
279  for (size_t i=0; i<p_storage_list.size(); i++) {
281  p_num_freed++;
283  }
284  }
285 
286  /* Mark holes as referenced */
287  if (blow_away_holes) {
288  file->set_tracking_references(true);
289  file->mark_referenced_extent(container->get_offset(), container->get_size());
290  file->set_tracking_references(is_tracking);
291  }
292 
293  /* The free list is everything that's been referenced in the container section. */
294  get_freelist() = container->get_referenced_extents();
295 
296  /* Remove the empty string from the free list */
297  if (p_dont_free)
299 }
300 
304 bool
306 {
307  bool reallocated = false;
308  SgAsmGenericSection *container = get_container();
309  rose_addr_t extend_size = 0; /* amount by which to extend string table */
310 
311  /* Get list of strings that need to be allocated and sort by descending size. */
312  std::vector<size_t> map;
313  for (size_t i=0; i<p_storage_list.size(); i++) {
314  SgAsmStringStorage *storage = p_storage_list[i];
316  map.push_back(i);
317  }
318  }
319  for (size_t i=1; i<map.size(); i++) {
320  for (size_t j=0; j<i; j++) {
321  if (p_storage_list[map[j]]->get_string().size() < p_storage_list[map[i]]->get_string().size()) {
322  size_t x = map[i];
323  map[i] = map[j];
324  map[j] = x;
325  }
326  }
327  }
328 
329  /* Allocate from largest to smallest so we have the best chance of finding overlaps */
330  for (size_t i=0; i<map.size(); i++) {
331  SgAsmStringStorage *storage = p_storage_list[map[i]];
332  ROSE_ASSERT(storage->get_offset()==SgAsmGenericString::unallocated);
333 
334  /* We point empty strings at the dont_free storage if possible. */
335  if (storage->get_string()=="" && p_dont_free) {
336  ROSE_ASSERT(p_dont_free->get_string()=="");
337  storage->set_offset(0);
338  }
339 
340  /* If there's already a string with the same value then they can share space in the string table. They're still
341  * considered two separate strings, so changing one doesn't affect the other. */
343  for (size_t j=0; j<p_storage_list.size(); j++) {
344  SgAsmStringStorage *previous = p_storage_list[j];
345  if (previous->get_offset()!=SgAsmGenericString::unallocated && previous->get_string()==storage->get_string()) {
346  storage->set_offset(previous->get_offset());
347  break;
348  }
349  }
350  }
351 
352  /* Some string tables may be able to overlap strings. For instance, ELF can overlap "domain" and "main" since it
353  * encodes strings with NUL termination. */
355  allocate_overlap(storage);
356 
357  /* If we couldn't share another string then try to allocate from free space (avoiding holes) */
359  try {
360  Extent e = get_freelist().allocate_best_fit(storage->get_string().size()+1);
361  rose_addr_t new_offset = e.first();
362  storage->set_offset(new_offset);
363  } catch(std::bad_alloc &x) {
364  /* nothing large enough on the free list */
365  }
366  }
367 
368  /* If no free space area large enough then prepare to extend the section. */
370  extend_size += storage->get_string().size() + 1;
371  }
372  }
373 
374  /* If we were unable to allocate everything and there's still free space then it may be possible to reallocate all
375  * strings in order to repack the table and avoid internal fragmentation. */
376  //FIXME (RPM 2008-09-25)
377 
378  /* Change string table size as necessary. */
379  if (extend_size>0) {
380  /* The string table isn't large enough, so make it larger by extending the section that contains the table. The
381  * containing section's "set_size" method should add the new space to the string table's free list. If our recursion
382  * level is more than two calls deep then something went horribly wrong! */
383  static bool recursive=false;
384  ROSE_ASSERT(!recursive);
385  recursive = reallocated = true;
386  try {
387  container->get_file()->shift_extend(container, 0, extend_size);
388  reallocate(false);
389  recursive = false;
390  } catch (...) {
391  recursive = false;
392  throw;
393  }
394  } else if (shrink && get_freelist().size()>0) {
395  /* See if we can release any address space and shrink the containing section. The containing section's "set_size"
396  * method will adjust the free list by removing some bytes from it. */
397  Extent hi = get_freelist().rbegin()->first;
398  if (hi.first() + hi.size() == container->get_size())
399  container->set_size(hi.first());
400  }
401 
402  if (reallocated)
403  set_isModified(true);
404  return reallocated;
405 }
406 
409 const ExtentMap&
411 {
412  return p_freelist;
413 }
414 ExtentMap&
416 {
417  return p_freelist;
418 }
419 
420 /* Print some debugging info */
421 void
422 SgAsmGenericStrtab::dump(FILE *f, const char *prefix, ssize_t idx) const
423 {
424  SgAsmGenericSection *container = get_container();
425 
426  char p[4096];
427  if (idx>=0) {
428  sprintf(p, "%sStrtab[%zd].", prefix, idx);
429  } else {
430  sprintf(p, "%sStrtab.", prefix);
431  }
432  int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
433 
434  if (container) {
435  fprintf(f, "%s%-*s = [%d] \"%s\"\n", p, w, "container",
436  container->get_id(), container->get_name()->get_string(true).c_str());
437  } else {
438  fprintf(f, "%s%-*s = <null>\n", p, w, "container");
439  }
440 
441  fprintf(f, "%s%-*s =", p, w, "dont_free");
442  for (size_t i=0; i<p_storage_list.size(); ++i) {
443  if (p_storage_list[i] == p_dont_free)
444  fprintf(f, " p_storage_list[%zu]", i);
445  }
446  fputc('\n', f);
447 
448  fprintf(f, "%s%-*s = %zu strings\n", p, w, "referenced", p_storage_list.size());
449  for (size_t i=0; i<p_storage_list.size(); i++) {
450  p_storage_list[i]->dump(f, p, i);
451  }
452 
453  fprintf(f, "%s%-*s = %"PRIu64" free regions\n", p, w, "freelist", get_freelist().size());
454  get_freelist().dump_extents(f, p, "freelist");
455 }