from collections import namedtuple, OrderedDict
import command
+import io
import os
import re
import shutil
import tools
+ELF_TOOLS = True
+try:
+ from elftools.elf.elffile import ELFFile
+ from elftools.elf.sections import SymbolTableSection
+except: # pragma: no cover
+ ELF_TOOLS = False
+
# This is enabled from control.py
debug = False
Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
+# Information about an ELF file:
+# data: Extracted program contents of ELF file (this would be loaded by an
+# ELF loader when reading this file
+# load: Load address of code
+# entry: Entry address of code
+# memsize: Number of bytes in memory occupied by loading this ELF file
+ElfInfo = namedtuple('ElfInfo', ['data', 'load', 'entry', 'memsize'])
+
def GetSymbols(fname, patterns):
"""Get the symbols from an ELF file
stdout = command.Output('cc', '-static', '-nostdlib', '-Wl,--build-id=none',
'-m32','-T', lds_file, '-o', elf_fname, s_file)
shutil.rmtree(outdir)
+
+def DecodeElf(data, location):
+ """Decode an ELF file and return information about it
+
+ Args:
+ data: Data from ELF file
+ location: Start address of data to return
+
+ Returns:
+ ElfInfo object containing information about the decoded ELF file
+ """
+ file_size = len(data)
+ with io.BytesIO(data) as fd:
+ elf = ELFFile(fd)
+ data_start = 0xffffffff;
+ data_end = 0;
+ mem_end = 0;
+ virt_to_phys = 0;
+
+ for i in range(elf.num_segments()):
+ segment = elf.get_segment(i)
+ if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
+ skipped = 1 # To make code-coverage see this line
+ continue
+ start = segment['p_paddr']
+ mend = start + segment['p_memsz']
+ rend = start + segment['p_filesz']
+ data_start = min(data_start, start)
+ data_end = max(data_end, rend)
+ mem_end = max(mem_end, mend)
+ if not virt_to_phys:
+ virt_to_phys = segment['p_paddr'] - segment['p_vaddr']
+
+ output = bytearray(data_end - data_start)
+ for i in range(elf.num_segments()):
+ segment = elf.get_segment(i)
+ if segment['p_type'] != 'PT_LOAD' or not segment['p_memsz']:
+ skipped = 1 # To make code-coverage see this line
+ continue
+ start = segment['p_paddr']
+ offset = 0
+ if start < location:
+ offset = location - start
+ start = location
+ # A legal ELF file can have a program header with non-zero length
+ # but zero-length file size and a non-zero offset which, added
+ # together, are greater than input->size (i.e. the total file size).
+ # So we need to not even test in the case that p_filesz is zero.
+ # Note: All of this code is commented out since we don't have a test
+ # case for it.
+ size = segment['p_filesz']
+ #if not size:
+ #continue
+ #end = segment['p_offset'] + segment['p_filesz']
+ #if end > file_size:
+ #raise ValueError('Underflow copying out the segment. File has %#x bytes left, segment end is %#x\n',
+ #file_size, end)
+ output[start - data_start:start - data_start + size] = (
+ segment.data()[offset:])
+ return ElfInfo(output, data_start, elf.header['e_entry'] + virt_to_phys,
+ mem_end - data_start)
self.assertEqual(expected_text + expected_data, data)
shutil.rmtree(outdir)
+ def testDecodeElf(self):
+ """Test for the MakeElf function"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ outdir = tempfile.mkdtemp(prefix='elf.')
+ expected_text = b'1234'
+ expected_data = b'wxyz'
+ elf_fname = os.path.join(outdir, 'elf')
+ elf.MakeElf(elf_fname, expected_text, expected_data)
+ data = tools.ReadFile(elf_fname)
+
+ load = 0xfef20000
+ entry = load + 2
+ expected = expected_text + expected_data
+ self.assertEqual(elf.ElfInfo(expected, load, entry, len(expected)),
+ elf.DecodeElf(data, 0))
+ self.assertEqual(elf.ElfInfo(b'\0\0' + expected[2:],
+ load, entry, len(expected)),
+ elf.DecodeElf(data, load + 2))
+ #shutil.rmtree(outdir)
+
if __name__ == '__main__':
unittest.main()