summaryrefslogtreecommitdiff
path: root/tools/binman/elf.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/binman/elf.py')
-rw-r--r--tools/binman/elf.py129
1 files changed, 129 insertions, 0 deletions
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
new file mode 100644
index 00000000000..80ff2253f03
--- /dev/null
+++ b/tools/binman/elf.py
@@ -0,0 +1,129 @@
+# Copyright (c) 2016 Google, Inc
+# Written by Simon Glass <sjg@chromium.org>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Handle various things related to ELF images
+#
+
+from collections import namedtuple, OrderedDict
+import command
+import os
+import re
+import struct
+
+import tools
+
+# This is enabled from control.py
+debug = False
+
+Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
+
+
+def GetSymbols(fname, patterns):
+ """Get the symbols from an ELF file
+
+ Args:
+ fname: Filename of the ELF file to read
+ patterns: List of regex patterns to search for, each a string
+
+ Returns:
+ None, if the file does not exist, or Dict:
+ key: Name of symbol
+ value: Hex value of symbol
+ """
+ stdout = command.Output('objdump', '-t', fname, raise_on_error=False)
+ lines = stdout.splitlines()
+ if patterns:
+ re_syms = re.compile('|'.join(patterns))
+ else:
+ re_syms = None
+ syms = {}
+ syms_started = False
+ for line in lines:
+ if not line or not syms_started:
+ if 'SYMBOL TABLE' in line:
+ syms_started = True
+ line = None # Otherwise code coverage complains about 'continue'
+ continue
+ if re_syms and not re_syms.search(line):
+ continue
+
+ space_pos = line.find(' ')
+ value, rest = line[:space_pos], line[space_pos + 1:]
+ flags = rest[:7]
+ parts = rest[7:].split()
+ section, size = parts[:2]
+ if len(parts) > 2:
+ name = parts[2]
+ syms[name] = Symbol(section, int(value, 16), int(size,16),
+ flags[1] == 'w')
+ return syms
+
+def GetSymbolAddress(fname, sym_name):
+ """Get a value of a symbol from an ELF file
+
+ Args:
+ fname: Filename of the ELF file to read
+ patterns: List of regex patterns to search for, each a string
+
+ Returns:
+ Symbol value (as an integer) or None if not found
+ """
+ syms = GetSymbols(fname, [sym_name])
+ sym = syms.get(sym_name)
+ if not sym:
+ return None
+ return sym.address
+
+def LookupAndWriteSymbols(elf_fname, entry, image):
+ """Replace all symbols in an entry with their correct values
+
+ The entry contents is updated so that values for referenced symbols will be
+ visible at run time. This is done by finding out the symbols positions in
+ the entry (using the ELF file) and replacing them with values from binman's
+ data structures.
+
+ Args:
+ elf_fname: Filename of ELF image containing the symbol information for
+ entry
+ entry: Entry to process
+ image: Image which can be used to lookup symbol values
+ """
+ fname = tools.GetInputFilename(elf_fname)
+ syms = GetSymbols(fname, ['image', 'binman'])
+ if not syms:
+ return
+ base = syms.get('__image_copy_start')
+ if not base:
+ return
+ for name, sym in syms.iteritems():
+ if name.startswith('_binman'):
+ msg = ("Image '%s': Symbol '%s'\n in entry '%s'" %
+ (image.GetPath(), name, entry.GetPath()))
+ offset = sym.address - base.address
+ if offset < 0 or offset + sym.size > entry.contents_size:
+ raise ValueError('%s has offset %x (size %x) but the contents '
+ 'size is %x' % (entry.GetPath(), offset,
+ sym.size, entry.contents_size))
+ if sym.size == 4:
+ pack_string = '<I'
+ elif sym.size == 8:
+ pack_string = '<Q'
+ else:
+ raise ValueError('%s has size %d: only 4 and 8 are supported' %
+ (msg, sym.size))
+
+ # Look up the symbol in our entry tables.
+ value = image.LookupSymbol(name, sym.weak, msg)
+ if value is not None:
+ value += base.address
+ else:
+ value = -1
+ pack_string = pack_string.lower()
+ value_bytes = struct.pack(pack_string, value)
+ if debug:
+ print('%s:\n insert %s, offset %x, value %x, length %d' %
+ (msg, name, offset, value, len(value_bytes)))
+ entry.data = (entry.data[:offset] + value_bytes +
+ entry.data[offset + sym.size:])