mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
binman: Add a function to decode an ELF file
Add a function which decodes an ELF file, working out where in memory each part of the data should be written. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
f58558a5ae
commit
d8d40748dd
3 changed files with 102 additions and 0 deletions
|
@ -181,6 +181,10 @@ the configuration of the Intel-format descriptor.
|
|||
Running binman
|
||||
--------------
|
||||
|
||||
First install prerequisites, e.g.
|
||||
|
||||
sudo apt-get install python-pyelftools python3-pyelftools
|
||||
|
||||
Type:
|
||||
|
||||
binman -b <board_name>
|
||||
|
|
|
@ -9,6 +9,7 @@ from __future__ import print_function
|
|||
|
||||
from collections import namedtuple, OrderedDict
|
||||
import command
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
|
@ -17,11 +18,26 @@ import tempfile
|
|||
|
||||
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
|
||||
|
@ -225,3 +241,64 @@ SECTIONS
|
|||
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)
|
||||
|
|
|
@ -156,6 +156,27 @@ class TestElf(unittest.TestCase):
|
|||
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()
|
||||
|
|
Loading…
Reference in a new issue