def _get_segments(self): elf_file = UnpreparedElfFile() sections = [UnpreparedElfSection(elf_file, "test1", data=ByteArray("test1 data")), UnpreparedElfSection(elf_file, "test2", data=ByteArray("test2 data"))] empty_sec_seg = SectionedElfSegment(None) full_sec_seg = SectionedElfSegment(elf_file, sections=sections) head_seg = HeaderElfSegment(None) prep_head_seg = HeaderElfSegment(None) prep_head_seg.prepare(37, PROG_HEADER_SIZE) data = ByteArray("pants") full_data_seg = DataElfSegment(None, vaddr=DATA_BASE, paddr=PHYS_BASE, data=data) nobits_data_seg = DataElfSegment(None, vaddr=DATA_BASE, paddr=PHYS_BASE, data=data, memsz=10) return empty_sec_seg, full_sec_seg, head_seg, prep_head_seg, full_data_seg, nobits_data_seg
def test_prepare(self): ef = UnpreparedElfFile() segment = SectionedElfSegment(None, align=0x1) new_sect = UnpreparedElfSection(None, "pants") ef.add_section(new_sect) segment.add_section(new_sect) ef.add_segment(segment) ef.add_segment(HeaderElfSegment(None)) ef = ef.prepare(32, '<')
def test_has_sections(self): seg = DataElfSegment() self.assertEquals(seg.has_sections(), False) seg = SectionedElfSegment(sections=[]) self.assertEquals(seg.has_sections(), True) seg = HeaderElfSegment() self.assertEquals(seg.has_sections(), False)
def test_getmemsz(self): seg = DataElfSegment() self.assertRaises(InvalidArgument, seg.get_memsz) data = ByteArray() data.memsz = 10 seg.set_data(data) self.assertEquals(seg.get_memsz(), 10) seg = HeaderElfSegment() self.assertRaises(Unprepared, seg.get_memsz)
def test_get_section(self): ef = SectionedElfSegment(sections=[]) self.assertEquals(ef.get_sections(), []) data = ByteArray("pants") ef = DataElfSegment(data=data) self.assertRaises(InvalidArgument, ef.get_sections) seg = HeaderElfSegment() self.assertRaises(InvalidArgument, seg.get_sections)
def test_add_section(self): ef = UnpreparedElfFile() sect = UnpreparedElfSection() ef.add_section(sect) self.assertEqual(ef.sections[-1], sect) seg = HeaderElfSegment() self.assertRaises(InvalidArgument, seg.add_section, sect) seg = DataElfSegment() self.assertRaises(InvalidArgument, seg.add_section, sect)
def test_getfilesz(self): seg = DataElfSegment() self.assertRaises(InvalidArgument, seg.get_filesz) data = ByteArray("1234567890") data.memsz = 10 seg.set_data(data) self.assertEquals(seg.get_filesz(), 10) seg = HeaderElfSegment() self.assertRaises(Unprepared, seg.get_filesz) seg = SectionedElfSegment() self.assertEqual(seg.get_filesz(), 0)
def test_prepare(self): ef = DataElfSegment() ef.prepare(37) self.assertEqual(ef.prepared, True) self.assertEqual(ef.offset, 37) self.assertRaises(InvalidArgument, ef.prepare, 12) ef = DataElfSegment() self.assertRaises(InvalidArgument, ef.prepare, 37, 12) ef = HeaderElfSegment() self.assertRaises(InvalidArgument, ef.prepare, 12) ef.prepare(37, 12) self.assertEqual(ef.get_memsz(), 12) self.assertEqual(ef.offset, 37)
def test_remove_section(self): seg = SectionedElfSegment() section = UnpreparedElfSection() self.assertRaises(InvalidArgument, seg.remove_section, section) seg.add_section(section) self.assertEqual(section in seg.sections, True) seg.remove_section(section) self.assertEqual(section in seg.sections, False) self.assertRaises(InvalidArgument, seg.remove_section, section) seg = DataElfSegment() data = ByteArray("foo") seg.set_data(data) self.assertRaises(InvalidArgument, seg.remove_section, None) seg = HeaderElfSegment() self.assertRaises(InvalidArgument, seg.remove_section, None)
def test_copy(self): seg = DataElfSegment() new_seg = seg.copy() seg = SectionedElfSegment() seg.sections = [UnpreparedElfSection("test")] new_seg = seg.copy() seg = DataElfSegment() seg._data = ByteArray() new_seg = seg.copy() seg = DataElfSegment() seg.prepare(34) new_seg = seg.copy() seg = HeaderElfSegment() new_Seg = seg.copy()
def test_copy_into(self): elf_from = UnpreparedElfFile() elf_to = UnpreparedElfFile() seg = DataElfSegment(elf_from, ByteArray("pants")) new_seg = seg.copy_into(elf_to) seg = SectionedElfSegment(elf_from) seg.sections = [UnpreparedElfSection(elf_from, "test")] new_seg = seg.copy_into(elf_to) seg = DataElfSegment(elf_from, ByteArray("pants")) seg._data = ByteArray() new_seg = seg.copy_into(elf_to) seg = DataElfSegment(elf_from, ByteArray("pants")) seg.prepare(34) new_seg = seg.copy_into(elf_to) seg = HeaderElfSegment(elf_from) new_seg = seg.copy_into(elf_to)
def _initialise_segments(self, hdr, f, prepare): """Initialise instance from program headers.""" # Now load all the program headers # # "The time has come," the developer said, "to talk of many # things: Of section to segment mapping and scatter load, of # cabbages and kings, and why the RVCT linker is on drugs and # whether pigs have wings." # # There are two ways of determining which sections belong in a # segment: # # 1) In most cases a section is in a segment if its virtual # address range falls in the virtual address range of the # segment. These segments tend to contain multiple # PROGBITS sections and may end with a NOBITS section. # # 2) In the case of segments build with RVCT's scatter load # support the virtual address of the included sections can # be anywhere in memory. In this case a section is in the # segment if its data file offset falls in the offset range # of the segment. These segments can contain multiple # PROGBITS and NOBITS sections in any order. The file size # of the segment is the filesize of all of the PROGBITS # sections. The memory size of the segment is the sum of # the size of all of the sections, not the difference # between the lowest and highest virtual addresses. # # Some other things about ELF files that you need to know: # # a) Segments can overlap, and sections can appear in multiple # segments. # # b) Some sections do not appear in any segments. These tend # to be the symbol table and other debugging data. # # c) The offsets of NOBITS sections tend to be the same as the # offset for the next PROGBITS section, even if it is in # the next segment. However, sometimes NOBITS sections # appear at the beginning of a segment. # # d) The address offset from the start of a segment and the # file offset from the start of the segment are not # necessarily the same. # # Therefore, to map sections to segments involves two passes: # # 1) Find all of the sections that fall in the segment virtual # address range. # # 2) Find all of the remaining sections that fall in the file # offset range. If any are found then mark the segment as # a scatter-load segment. # # The file size and memory size of a segment depends on # whether or not it is a scatter load segment. For scatter # load files, the section that has the latest offset from the # beginning of the section is used, while for non-scatter-load # segments, the section with the largest virtual address is # used. # # File offsets cannot be used for both types of segments # because broken linkers can produce sections with # inconsistant virtual address to file offset mappings and # this will make elfweaver produce segments with incorrect # file sizes or memory sizes. # # "O Readers," said the developer, "You've had a pleasant run! # Shall we start the code again?" But answer came there none-- # And this was scarcely odd, because no-one would read this far # for fun. phoff = hdr.e_phoff self._ph_offset = phoff self.segments = [] # Short circuit the return. if hdr.e_phoff == 0: return ph_list = self._get_headers(hdr, f, ELF_PH_CLASSES, hdr.e_phoff, hdr.e_phentsize, hdr.e_phnum) phentsize = hdr.e_phentsize sheaders = self._get_section_headers(hdr, f) for ph in ph_list: # Map segments to sections, pass 1. if ph.p_type != PT_PHDR: sects = [] for (section, sh) in zip(self.sections, sheaders): # See if the section's virtual address range falls within # the virtual address range of the segment. low = ph.p_vaddr high = low + ph.p_memsz addr = section.address if low <= addr < high and addr + section.get_size() <= high: section.set_in_segment_offset(sh.sh_offset - ph.p_offset) sects.append(section) if sects == []: data = f.get_data(ph.p_offset, ph.p_filesz) data.memsz = ph.p_memsz es = DataElfSegment(ph=ph, data=data) else: es = SectionedElfSegment(ph=ph, sections=sects) else: es = HeaderElfSegment(ph=ph) self.segments.append(es) # Map segments to sections, pass 2 for ph, es in zip(ph_list, self.segments): if ph.p_type != PT_PHDR: for (section, sh) in zip(self.sections, sheaders): # Scatter-load sections do not appear in # multiple segments, so skip sections that # are already in some segment. if section.is_in_segment(): continue # See if the section's file offset range # falls within the file offset range of # the segment. Remember that the trailing # BSS section can have the offset of the # next section if ph.p_offset <= sh.sh_offset <= ph.p_offset + ph.p_filesz and \ ((section.type == SHT_NOBITS and sh.sh_offset != ph.p_offset) or \ (section.type != SHT_NOBITS and section.get_size() > 0 and \ sh.sh_offset + section.get_size() <= ph.p_offset + ph.p_filesz)): section.set_in_segment_offset(sh.sh_offset - ph.p_offset) es.add_section(section) es.set_scatter_load() prog_header_size = None else: prog_header_size = phentsize * hdr.e_phnum # Now mark the segment as prepared. if prepare: es.prepare(ph.p_offset, prog_header_size)