blob: 80ff2253f039f8e566cc9854bf608ddf11b5b9e2 [file] [log] [blame]
Simon Glassb50e5612017-11-13 18:54:54 -07001# Copyright (c) 2016 Google, Inc
2# Written by Simon Glass <sjg@chromium.org>
3#
4# SPDX-License-Identifier: GPL-2.0+
5#
6# Handle various things related to ELF images
7#
8
9from collections import namedtuple, OrderedDict
10import command
11import os
12import re
13import struct
14
15import tools
16
Simon Glass7fe91732017-11-13 18:55:00 -070017# This is enabled from control.py
18debug = False
19
Simon Glassb50e5612017-11-13 18:54:54 -070020Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak'])
21
Simon Glassb50e5612017-11-13 18:54:54 -070022
23def GetSymbols(fname, patterns):
24 """Get the symbols from an ELF file
25
26 Args:
27 fname: Filename of the ELF file to read
28 patterns: List of regex patterns to search for, each a string
29
30 Returns:
31 None, if the file does not exist, or Dict:
32 key: Name of symbol
33 value: Hex value of symbol
34 """
35 stdout = command.Output('objdump', '-t', fname, raise_on_error=False)
36 lines = stdout.splitlines()
37 if patterns:
38 re_syms = re.compile('|'.join(patterns))
39 else:
40 re_syms = None
41 syms = {}
42 syms_started = False
43 for line in lines:
44 if not line or not syms_started:
45 if 'SYMBOL TABLE' in line:
46 syms_started = True
47 line = None # Otherwise code coverage complains about 'continue'
48 continue
49 if re_syms and not re_syms.search(line):
50 continue
51
52 space_pos = line.find(' ')
53 value, rest = line[:space_pos], line[space_pos + 1:]
54 flags = rest[:7]
55 parts = rest[7:].split()
56 section, size = parts[:2]
57 if len(parts) > 2:
58 name = parts[2]
59 syms[name] = Symbol(section, int(value, 16), int(size,16),
60 flags[1] == 'w')
61 return syms
62
63def GetSymbolAddress(fname, sym_name):
64 """Get a value of a symbol from an ELF file
65
66 Args:
67 fname: Filename of the ELF file to read
68 patterns: List of regex patterns to search for, each a string
69
70 Returns:
71 Symbol value (as an integer) or None if not found
72 """
73 syms = GetSymbols(fname, [sym_name])
74 sym = syms.get(sym_name)
75 if not sym:
76 return None
77 return sym.address
Simon Glass19790632017-11-13 18:55:01 -070078
79def LookupAndWriteSymbols(elf_fname, entry, image):
80 """Replace all symbols in an entry with their correct values
81
82 The entry contents is updated so that values for referenced symbols will be
83 visible at run time. This is done by finding out the symbols positions in
84 the entry (using the ELF file) and replacing them with values from binman's
85 data structures.
86
87 Args:
88 elf_fname: Filename of ELF image containing the symbol information for
89 entry
90 entry: Entry to process
91 image: Image which can be used to lookup symbol values
92 """
93 fname = tools.GetInputFilename(elf_fname)
94 syms = GetSymbols(fname, ['image', 'binman'])
95 if not syms:
96 return
97 base = syms.get('__image_copy_start')
98 if not base:
99 return
100 for name, sym in syms.iteritems():
101 if name.startswith('_binman'):
102 msg = ("Image '%s': Symbol '%s'\n in entry '%s'" %
103 (image.GetPath(), name, entry.GetPath()))
104 offset = sym.address - base.address
105 if offset < 0 or offset + sym.size > entry.contents_size:
106 raise ValueError('%s has offset %x (size %x) but the contents '
107 'size is %x' % (entry.GetPath(), offset,
108 sym.size, entry.contents_size))
109 if sym.size == 4:
110 pack_string = '<I'
111 elif sym.size == 8:
112 pack_string = '<Q'
113 else:
114 raise ValueError('%s has size %d: only 4 and 8 are supported' %
115 (msg, sym.size))
116
117 # Look up the symbol in our entry tables.
118 value = image.LookupSymbol(name, sym.weak, msg)
119 if value is not None:
120 value += base.address
121 else:
122 value = -1
123 pack_string = pack_string.lower()
124 value_bytes = struct.pack(pack_string, value)
125 if debug:
126 print('%s:\n insert %s, offset %x, value %x, length %d' %
127 (msg, name, offset, value, len(value_bytes)))
128 entry.data = (entry.data[:offset] + value_bytes +
129 entry.data[offset + sym.size:])