mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +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
|
Running binman
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
First install prerequisites, e.g.
|
||||||
|
|
||||||
|
sudo apt-get install python-pyelftools python3-pyelftools
|
||||||
|
|
||||||
Type:
|
Type:
|
||||||
|
|
||||||
binman -b <board_name>
|
binman -b <board_name>
|
||||||
|
|
|
@ -9,6 +9,7 @@ from __future__ import print_function
|
||||||
|
|
||||||
from collections import namedtuple, OrderedDict
|
from collections import namedtuple, OrderedDict
|
||||||
import command
|
import command
|
||||||
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -17,11 +18,26 @@ import tempfile
|
||||||
|
|
||||||
import tools
|
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
|
# This is enabled from control.py
|
||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
|
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):
|
def GetSymbols(fname, patterns):
|
||||||
"""Get the symbols from an ELF file
|
"""Get the symbols from an ELF file
|
||||||
|
@ -225,3 +241,64 @@ SECTIONS
|
||||||
stdout = command.Output('cc', '-static', '-nostdlib', '-Wl,--build-id=none',
|
stdout = command.Output('cc', '-static', '-nostdlib', '-Wl,--build-id=none',
|
||||||
'-m32','-T', lds_file, '-o', elf_fname, s_file)
|
'-m32','-T', lds_file, '-o', elf_fname, s_file)
|
||||||
shutil.rmtree(outdir)
|
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)
|
self.assertEqual(expected_text + expected_data, data)
|
||||||
shutil.rmtree(outdir)
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue