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