ROSE  0.9.6a
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ElfSegmentTable.C
Go to the documentation of this file.
1 /* ELF Segment Tables (SgAsmElfSegmentTable and related classes) */
2 #include "sage3basic.h"
3 #include "stringify.h"
4 
5 using namespace rose;
6 
8 void
9 SgAsmElfSegmentTableEntry::ctor(ByteOrder::Endianness sex, const struct Elf32SegmentTableEntry_disk *disk)
10 {
11  p_type = (SegmentType)ByteOrder::disk_to_host(sex, disk->p_type);
12  p_offset = ByteOrder::disk_to_host(sex, disk->p_offset);
13  p_vaddr = ByteOrder::disk_to_host(sex, disk->p_vaddr);
14  p_paddr = ByteOrder::disk_to_host(sex, disk->p_paddr);
15  p_filesz = ByteOrder::disk_to_host(sex, disk->p_filesz);
16  p_memsz = ByteOrder::disk_to_host(sex, disk->p_memsz);
17  p_flags = (SegmentFlags)ByteOrder::disk_to_host(sex, disk->p_flags);
18  p_align = ByteOrder::disk_to_host(sex, disk->p_align);
19 }
20 
22 void
24 {
33 }
34 
36 void *
38 {
39  ByteOrder::host_to_disk(sex, p_type, &(disk->p_type));
41  ByteOrder::host_to_disk(sex, p_vaddr, &(disk->p_vaddr));
42  ByteOrder::host_to_disk(sex, p_paddr, &(disk->p_paddr));
44  ByteOrder::host_to_disk(sex, p_memsz, &(disk->p_memsz));
45  ByteOrder::host_to_disk(sex, p_flags, &(disk->p_flags));
46  ByteOrder::host_to_disk(sex, p_align, &(disk->p_align));
47  return disk;
48 }
49 void *
51 {
52  ByteOrder::host_to_disk(sex, p_type, &(disk->p_type));
54  ByteOrder::host_to_disk(sex, p_vaddr, &(disk->p_vaddr));
55  ByteOrder::host_to_disk(sex, p_paddr, &(disk->p_paddr));
57  ByteOrder::host_to_disk(sex, p_memsz, &(disk->p_memsz));
58  ByteOrder::host_to_disk(sex, p_flags, &(disk->p_flags));
59  ByteOrder::host_to_disk(sex, p_align, &(disk->p_align));
60  return disk;
61 }
62 
64 void
66 {
67  set_offset(section->get_offset());
68  set_filesz(section->get_size());
69  set_vaddr(section->get_mapped_preferred_va());
70  set_memsz(section->get_mapped_size());
71  set_align(section->is_mapped() ? section->get_mapped_alignment() : section->get_file_alignment());
72 
73  if (section->get_mapped_rperm()) {
74  set_flags((SegmentFlags)(p_flags | PF_RPERM));
75  } else {
76  set_flags((SegmentFlags)(p_flags & ~PF_RPERM));
77  }
78  if (section->get_mapped_wperm()) {
79  set_flags((SegmentFlags)(p_flags | PF_WPERM));
80  } else {
81  set_flags((SegmentFlags)(p_flags & ~PF_WPERM));
82  }
83  if (section->get_mapped_xperm()) {
84  set_flags((SegmentFlags)(p_flags | PF_XPERM));
85  } else {
86  set_flags((SegmentFlags)(p_flags & ~PF_XPERM));
87  }
88 
89  if (isSgAsmElfNoteSection(section)) {
90  set_type(PT_NOTE);
91  }
92 }
93 
95 void
96 SgAsmElfSegmentTableEntry::dump(FILE *f, const char *prefix, ssize_t idx) const
97 {
98  char p[4096];
99  if (idx>=0) {
100  sprintf(p, "%sElfSegmentTableEntry[%zd].", prefix, idx);
101  } else {
102  sprintf(p, "%sElfSegmentTableEntry.", prefix);
103  }
104  const int w = std::max(1, DUMP_FIELD_WIDTH-(int)strlen(p));
105 
106  fprintf(f, "%s%-*s = %zu\n", p, w, "index", p_index);
107  fprintf(f, "%s%-*s = 0x%08x = %s\n", p, w, "type", p_type, to_string(p_type).c_str());
108  fprintf(f, "%s%-*s = 0x%08x ", p, w, "flags", p_flags);
109  fputc(p_flags & PF_RPERM ? 'r' : '-', f);
110  fputc(p_flags & PF_WPERM ? 'w' : '-', f);
111  fputc(p_flags & PF_XPERM ? 'x' : '-', f);
112  if (p_flags & PF_OS_MASK) fputs(" os", f);
113  if (p_flags & PF_PROC_MASK) fputs(" proc", f);
114  if (p_flags & PF_RESERVED) fputs(" *", f);
115  fputc('\n', f);
116  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes into file\n", p, w, "offset", p_offset, p_offset);
117  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64")\n", p, w, "vaddr", p_vaddr, p_vaddr);
118  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64")\n", p, w, "paddr", p_paddr, p_paddr);
119  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes\n", p, w, "filesz", p_filesz, p_filesz);
120  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes\n", p, w, "memsz", p_memsz, p_memsz);
121  fprintf(f, "%s%-*s = 0x%08"PRIx64" (%"PRIu64") bytes\n", p, w, "align", p_align, p_align);
122  if (p_extra.size()>0) {
123  fprintf(f, "%s%-*s = %zu bytes\n", p, w, "extra", p_extra.size());
124  hexdump(f, 0, std::string(p)+"extra at ", p_extra);
125  }
126 }
127 
128 std::string
130 {
131 #ifndef _MSC_VER
133 #else
134  ROSE_ASSERT(false);
135  return "";
136 #endif
137 }
138 
139 std::string
141 {
142  std::string str;
143  for( size_t i=0; (1u << i) <= PF_RPERM; ++i){
144  if( i!= 0)
145  str += ' ';
146  if(val & (1 << i)){
147  switch(1 << i){
148  case PF_XPERM: str += "EXECUTE";break;
149  case PF_WPERM: str += "WRITE"; break;
150  case PF_RPERM: str += "READ";break;
151  };
152  }
153  }
154  uint32_t os = (val & ~(uint32_t)(PF_OS_MASK));
155  uint32_t proc = (val & ~(uint32_t)(PF_PROC_MASK));
156  uint32_t rest = (val & ~(uint32_t)(PF_RESERVED));
157 
158  if(os){
159  char buf[64];
160  snprintf(buf,sizeof(buf),"os flags(%2x)", os >> 20);
161  str += buf;
162  }
163 
164  if(proc){
165  char buf[64];
166  snprintf(buf,sizeof(buf),"proc flags(%1x)", proc >> 28);
167  str += buf;
168  }
169 
170  if(rest){
171  char buf[64];
172  snprintf(buf,sizeof(buf),"unknown(%x)", rest);
173  str += buf;
174  }
175 
176  return str;
177 
178 }
179 
180 
182 void
184 {
185  /* There can be only one ELF Segment Table */
186  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
187  ROSE_ASSERT(fhdr);
188  ROSE_ASSERT(fhdr->get_segment_table()==NULL);
189  fhdr->set_segment_table(this);
190 
191  set_synthesized(true); /* the segment table isn't part of any explicit section */
192  set_name(new SgAsmBasicString("ELF Segment Table"));
193  set_purpose(SP_HEADER);
194 
195  fhdr->set_segment_table(this);
196 }
197 
202 {
204 
205  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
206  ROSE_ASSERT(fhdr!=NULL);
207  ByteOrder::Endianness sex = fhdr->get_sex();
208 
209  size_t ent_size, struct_size, opt_size, nentries;
210  calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries);
211  ROSE_ASSERT(opt_size==fhdr->get_phextrasz() && nentries==fhdr->get_e_phnum());
212 
213  /* If the current size is very small (0 or 1 byte) then we're coming straight from the constructor and the parsing should
214  * also extend this section to hold all the entries. Otherwise the caller must have assigned a specific size for a good
215  * reason and we should leave that alone, reading zeros if the entries extend beyond the defined size. */
216  if (get_size()<=1 && get_size()<nentries*ent_size)
217  extend(nentries*ent_size - get_size());
218 
219  rose_addr_t offset=0; /* w.r.t. the beginning of this section */
220  for (size_t i=0; i<nentries; i++, offset+=ent_size) {
221  /* Read/decode the segment header */
222  SgAsmElfSegmentTableEntry *shdr = NULL;
223  if (4==fhdr->get_word_size()) {
225  read_content_local(offset, &disk, struct_size);
226  shdr = new SgAsmElfSegmentTableEntry(sex, &disk);
227  } else {
229  read_content_local(offset, &disk, struct_size);
230  shdr = new SgAsmElfSegmentTableEntry(sex, &disk);
231  }
232  shdr->set_index(i);
233  if (opt_size>0)
234  shdr->get_extra() = read_content_local_ucl(offset+struct_size, opt_size);
235 
236  /* Null segments are just unused slots in the table; no real section to create */
238  continue;
239 
240  /* Create SgAsmElfSection objects for each ELF Segment. However, if the ELF Segment Table describes a segment
241  * that's the same offset and size as a section from the Elf Section Table (and the memory mappings are
242  * consistent) then use the preexisting section instead of creating a new one. */
243  SgAsmElfSection *s = NULL;
245  for (size_t j=0; !s && j<possible.size(); j++) {
246  if (possible[j]->get_offset()!=shdr->get_offset() || possible[j]->get_size()!=shdr->get_filesz())
247  continue; /*different file extent*/
248  if (possible[j]->is_mapped()) {
249  if (possible[j]->get_mapped_preferred_rva()!=shdr->get_vaddr() ||
250  possible[j]->get_mapped_size()!=shdr->get_memsz())
251  continue; /*different mapped address or size*/
252  unsigned section_perms = (possible[j]->get_mapped_rperm() ? 0x01 : 0x00) |
253  (possible[j]->get_mapped_wperm() ? 0x02 : 0x00) |
254  (possible[j]->get_mapped_xperm() ? 0x04 : 0x00);
255  unsigned segment_perms = (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_RPERM ? 0x01 : 0x00) |
256  (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_WPERM ? 0x02 : 0x00) |
257  (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_XPERM ? 0x04 : 0x00);
258  if (section_perms != segment_perms)
259  continue; /*different mapped permissions*/
260  }
261 
262  /* Found a match. Set memory mapping params only. */
263  s = dynamic_cast<SgAsmElfSection*>(possible[j]);
264  if (!s) continue; /*potential match was not from the ELF Section or Segment table*/
265  if (s->get_segment_entry()) continue; /*potential match is assigned to some other segment table entry*/
266  s->init_from_segment_table(shdr, true); /*true=>set memory mapping params only*/
267  }
268 
269  /* Create a new segment if no matching section was found. */
270  if (!s) {
272  s = new SgAsmElfNoteSection(fhdr);
273  } else {
274  s = new SgAsmElfSection(fhdr);
275  }
276  s->init_from_segment_table(shdr);
277  s->parse();
278  }
279  }
280  return this;
281 }
282 
294 {
295  ROSE_ASSERT(section!=NULL);
296  ROSE_ASSERT(section->get_file()==get_file());
297  ROSE_ASSERT(section->get_header()==get_header());
298  ROSE_ASSERT(section->get_segment_entry()==NULL); /* must not be in the segment table yet */
299 
300  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
301  ROSE_ASSERT(fhdr);
302 
303  /* Assign a slot in the segment table */
304  int idx = fhdr->get_e_phnum();
305  fhdr->set_e_phnum(idx+1);
306 
307  /* Create a new segment table entry */
309  shdr->set_index(idx);
310  shdr->update_from_section(section);
311  section->set_segment_entry(shdr);
312 
313  return shdr;
314 }
315 
319 SgAsmElfSegmentTable::calculate_sizes(size_t *entsize, size_t *required, size_t *optional, size_t *entcount) const
320 {
321  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
322  ROSE_ASSERT(fhdr!=NULL);
323 
324  size_t struct_size = 0;
325  size_t extra_size = fhdr->get_phextrasz();
326  size_t entry_size = 0;
327  size_t nentries = 0;
328 
329  /* Size of required part of each entry */
330  if (4==fhdr->get_word_size()) {
332  } else if (8==fhdr->get_word_size()) {
334  } else {
335  throw FormatError("bad ELF word size");
336  }
337 
338  /* Entire entry should be at least large enough for the required part. */
339  entry_size = struct_size;
340 
341  /* Size of optional parts. If we've parsed the table then use the largest optional part, otherwise assume the entry from
342  * the ELF File Header is correct. */
344  for (size_t i=0; i<sections.size(); i++) {
345  SgAsmElfSection *elfsec = dynamic_cast<SgAsmElfSection*>(sections[i]);
346  if (elfsec && elfsec->get_segment_entry()) {
347  nentries++;
348  extra_size = std::max(extra_size, elfsec->get_segment_entry()->get_extra().size());
349  }
350  }
351 
352  /* Total number of entries. Either we haven't parsed the segment table yet (nor created the segments it defines) or we
353  * have. In the former case we use the setting from the ELF File Header, otherwise we just count the number of segments
354  * that have associated segment table entry pointers. */
355  if (0==nentries)
356  nentries = fhdr->get_e_phnum();
357 
358  /* Return values */
359  if (entsize)
360  *entsize = entry_size;
361  if (required)
362  *required = struct_size;
363  if (optional)
364  *optional = extra_size;
365  if (entcount)
366  *entcount = nentries;
367  return entry_size * nentries;
368 }
369 
371 bool
373 {
374  bool reallocated = false;
375 
376  /* Resize based on word size from ELF File Header */
377  size_t opt_size, nentries;
378  rose_addr_t need = calculate_sizes(NULL, NULL, &opt_size, &nentries);
379  if (need < get_size()) {
380  if (is_mapped()) {
381  ROSE_ASSERT(get_mapped_size()==get_size());
382  set_mapped_size(need);
383  }
384  set_size(need);
385  reallocated = true;
386  } else if (need > get_size()) {
387  get_file()->shift_extend(this, 0, need-get_size(), SgAsmGenericFile::ADDRSP_ALL, SgAsmGenericFile::ELASTIC_HOLE);
388  reallocated = true;
389  }
390 
391  /* Update data members in the ELF File Header. No need to return true for these changes. */
392  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
393  fhdr->set_phextrasz(opt_size);
394  fhdr->set_e_phnum(nentries);
395 
396  return reallocated;
397 }
398 
400 void
401 SgAsmElfSegmentTable::unparse(std::ostream &f) const
402 {
403  SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header());
404  ROSE_ASSERT(fhdr!=NULL);
405  ByteOrder::Endianness sex = fhdr->get_sex();
407 
408  /* Write the segments first */
409  for (size_t i=0; i<sections.size(); i++)
410  sections[i]->unparse(f);
411  unparse_holes(f);
412 
413  /* Calculate sizes. The ELF File Header should have been updated in reallocate() prior to unparsing. */
414  size_t ent_size, struct_size, opt_size, nentries;
415  calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries);
416  ROSE_ASSERT(fhdr->get_phextrasz()==opt_size);
417  ROSE_ASSERT(fhdr->get_e_phnum()==nentries);
418 
419  /* Write the segment table entries */
420  for (size_t i=0; i < sections.size(); ++i) {
421  SgAsmElfSection *section = dynamic_cast<SgAsmElfSection*>(sections[i]);
422  ROSE_ASSERT(section!=NULL);
423  SgAsmElfSegmentTableEntry *shdr = section->get_segment_entry();
424  ROSE_ASSERT(shdr!=NULL);
425  ROSE_ASSERT(shdr->get_offset()==section->get_offset()); /*segment table entry should have been updated in reallocate()*/
426 
427  int id = shdr->get_index();
428  ROSE_ASSERT(id>=0 && (size_t)id<nentries);
429 
432  void *disk = NULL;
433 
434  if (4==fhdr->get_word_size()) {
435  disk = shdr->encode(sex, &disk32);
436  } else if (8==fhdr->get_word_size()) {
437  disk = shdr->encode(sex, &disk64);
438  } else {
439  ROSE_ASSERT(!"invalid word size");
440  }
441 
442  /* The disk struct */
443  rose_addr_t spos = write(f, id*ent_size, struct_size, disk);
444  if (shdr->get_extra().size() > 0)
445  write(f, spos, shdr->get_extra());
446  }
447 }
448 
450 void
451 SgAsmElfSegmentTable::dump(FILE *f, const char *prefix, ssize_t idx) const
452 {
453  char p[4096];
454  if (idx>=0) {
455  sprintf(p, "%sSegmentTable[%zd].", prefix, idx);
456  } else {
457  sprintf(p, "%sSegmentTable.", prefix);
458  }
459 
460  SgAsmGenericSection::dump(f, p, -1);
461 
462  if (variantT() == V_SgAsmElfSegmentTable) //unless a base class
463  hexdump(f, 0, std::string(p)+"data at ", p_data);
464 }