bool SgAsmElfSection::reallocate() { bool reallocated = false; SgAsmElfSectionTableEntry *sechdr = get_section_entry(); SgAsmElfSegmentTableEntry *seghdr = get_segment_entry(); /* Change section size if this section was defined in the ELF Section Table */ if (sechdr!=NULL) { rose_addr_t need = calculate_sizes(NULL, NULL, NULL, NULL); if (need < get_size()) { if (is_mapped()) { ROSE_ASSERT(get_mapped_size()==get_size()); set_mapped_size(need); } set_size(need); reallocated = true; } else if (need > get_size()) { get_file()->shift_extend(this, 0, need-get_size(), SgAsmGenericFile::ADDRSP_ALL, SgAsmGenericFile::ELASTIC_HOLE); reallocated = true; } } /* Update entry in the ELF Section Table and/or ELF Segment Table */ if (sechdr) sechdr->update_from_section(this); if (seghdr) seghdr->update_from_section(this); return reallocated; }
/** Attaches a previously unattached ELF Segment (SgAsmElfSection) to the ELF Segment Table (SgAsmElfSegmentTable). This * method complements SgAsmElfSection::init_from_segment_table. This method initializes the segment table from the segment * while init_from_segment_table() initializes the segment from the segment table. * * ELF Segments are represented by SgAsmElfSection objects since ELF Segments and ELF Sections overlap very much in their * features and thus should share an interface. An SgAsmElfSection can appear in the ELF Section Table and/or the ELF Segment * Table and you can determine where it was located by calling get_section_entry() and get_segment_entry(). * * Returns the new segment table entry linked into the AST. */ SgAsmElfSegmentTableEntry * SgAsmElfSegmentTable::add_section(SgAsmElfSection *section) { ROSE_ASSERT(section!=NULL); ROSE_ASSERT(section->get_file()==get_file()); ROSE_ASSERT(section->get_header()==get_header()); ROSE_ASSERT(section->get_segment_entry()==NULL); /* must not be in the segment table yet */ SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header()); ROSE_ASSERT(fhdr); /* Assign a slot in the segment table */ int idx = fhdr->get_e_phnum(); fhdr->set_e_phnum(idx+1); /* Create a new segment table entry */ SgAsmElfSegmentTableEntry *shdr = new SgAsmElfSegmentTableEntry; shdr->set_index(idx); shdr->update_from_section(section); section->set_segment_entry(shdr); return shdr; }
/** Write the segment table to disk. */ void SgAsmElfSegmentTable::unparse(std::ostream &f) const { SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header()); ROSE_ASSERT(fhdr!=NULL); ByteOrder sex = fhdr->get_sex(); SgAsmGenericSectionPtrList sections = fhdr->get_segtab_sections(); /* Write the segments first */ for (size_t i=0; i<sections.size(); i++) sections[i]->unparse(f); unparse_holes(f); /* Calculate sizes. The ELF File Header should have been updated in reallocate() prior to unparsing. */ size_t ent_size, struct_size, opt_size, nentries; calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries); ROSE_ASSERT(fhdr->get_phextrasz()==opt_size); ROSE_ASSERT(fhdr->get_e_phnum()==nentries); /* Write the segment table entries */ for (size_t i=0; i < sections.size(); ++i) { SgAsmElfSection *section = dynamic_cast<SgAsmElfSection*>(sections[i]); ROSE_ASSERT(section!=NULL); SgAsmElfSegmentTableEntry *shdr = section->get_segment_entry(); ROSE_ASSERT(shdr!=NULL); ROSE_ASSERT(shdr->get_offset()==section->get_offset()); /*segment table entry should have been updated in reallocate()*/ int id = shdr->get_index(); ROSE_ASSERT(id>=0 && (size_t)id<nentries); SgAsmElfSegmentTableEntry::Elf32SegmentTableEntry_disk disk32; SgAsmElfSegmentTableEntry::Elf64SegmentTableEntry_disk disk64; void *disk = NULL; if (4==fhdr->get_word_size()) { disk = shdr->encode(sex, &disk32); } else if (8==fhdr->get_word_size()) { disk = shdr->encode(sex, &disk64); } else { ROSE_ASSERT(!"invalid word size"); } /* The disk struct */ rose_addr_t spos = write(f, id*ent_size, struct_size, disk); if (shdr->get_extra().size() > 0) write(f, spos, shdr->get_extra()); } }
/** Parses an ELF Segment (Program Header) Table and constructs and parses all segments reachable from the table. The section * is extended as necessary based on the number of entries and teh size of each entry. */ SgAsmElfSegmentTable * SgAsmElfSegmentTable::parse() { SgAsmGenericSection::parse(); SgAsmElfFileHeader *fhdr = dynamic_cast<SgAsmElfFileHeader*>(get_header()); ROSE_ASSERT(fhdr!=NULL); ByteOrder sex = fhdr->get_sex(); size_t ent_size, struct_size, opt_size, nentries; calculate_sizes(&ent_size, &struct_size, &opt_size, &nentries); ROSE_ASSERT(opt_size==fhdr->get_phextrasz() && nentries==fhdr->get_e_phnum()); /* If the current size is very small (0 or 1 byte) then we're coming straight from the constructor and the parsing should * also extend this section to hold all the entries. Otherwise the caller must have assigned a specific size for a good * reason and we should leave that alone, reading zeros if the entries extend beyond the defined size. */ if (get_size()<=1 && get_size()<nentries*ent_size) extend(nentries*ent_size - get_size()); rose_addr_t offset=0; /* w.r.t. the beginning of this section */ for (size_t i=0; i<nentries; i++, offset+=ent_size) { /* Read/decode the segment header */ SgAsmElfSegmentTableEntry *shdr = NULL; if (4==fhdr->get_word_size()) { SgAsmElfSegmentTableEntry::Elf32SegmentTableEntry_disk disk; read_content_local(offset, &disk, struct_size); shdr = new SgAsmElfSegmentTableEntry(sex, &disk); } else { SgAsmElfSegmentTableEntry::Elf64SegmentTableEntry_disk disk; read_content_local(offset, &disk, struct_size); shdr = new SgAsmElfSegmentTableEntry(sex, &disk); } shdr->set_index(i); if (opt_size>0) shdr->get_extra() = read_content_local_ucl(offset+struct_size, opt_size); /* Null segments are just unused slots in the table; no real section to create */ if (SgAsmElfSegmentTableEntry::PT_NULL == shdr->get_type()) continue; /* Create SgAsmElfSection objects for each ELF Segment. However, if the ELF Segment Table describes a segment * that's the same offset and size as a section from the Elf Section Table (and the memory mappings are * consistent) then use the preexisting section instead of creating a new one. */ SgAsmElfSection *s = NULL; SgAsmGenericSectionPtrList possible = fhdr->get_file()->get_sections_by_offset(shdr->get_offset(), shdr->get_filesz()); for (size_t j=0; !s && j<possible.size(); j++) { if (possible[j]->get_offset()!=shdr->get_offset() || possible[j]->get_size()!=shdr->get_filesz()) continue; /*different file extent*/ if (possible[j]->is_mapped()) { if (possible[j]->get_mapped_preferred_rva()!=shdr->get_vaddr() || possible[j]->get_mapped_size()!=shdr->get_memsz()) continue; /*different mapped address or size*/ unsigned section_perms = (possible[j]->get_mapped_rperm() ? 0x01 : 0x00) | (possible[j]->get_mapped_wperm() ? 0x02 : 0x00) | (possible[j]->get_mapped_xperm() ? 0x04 : 0x00); unsigned segment_perms = (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_RPERM ? 0x01 : 0x00) | (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_WPERM ? 0x02 : 0x00) | (shdr->get_flags() & SgAsmElfSegmentTableEntry::PF_XPERM ? 0x04 : 0x00); if (section_perms != segment_perms) continue; /*different mapped permissions*/ } /* Found a match. Set memory mapping params only. */ s = dynamic_cast<SgAsmElfSection*>(possible[j]); if (!s) continue; /*potential match was not from the ELF Section or Segment table*/ if (s->get_segment_entry()) continue; /*potential match is assigned to some other segment table entry*/ s->init_from_segment_table(shdr, true); /*true=>set memory mapping params only*/ } /* Create a new segment if no matching section was found. */ if (!s) { if (SgAsmElfSegmentTableEntry::PT_NOTE == shdr->get_type()) { s = new SgAsmElfNoteSection(fhdr); } else { s = new SgAsmElfSection(fhdr); } s->init_from_segment_table(shdr); s->parse(); } } return this; }