1*83d290c5STom Rini# SPDX-License-Identifier: GPL-2.0+ 2b50e5611SSimon Glass# Copyright (c) 2016 Google, Inc 3b50e5611SSimon Glass# Written by Simon Glass <sjg@chromium.org> 4b50e5611SSimon Glass# 5b50e5611SSimon Glass# Handle various things related to ELF images 6b50e5611SSimon Glass# 7b50e5611SSimon Glass 8b50e5611SSimon Glassfrom collections import namedtuple, OrderedDict 9b50e5611SSimon Glassimport command 10b50e5611SSimon Glassimport os 11b50e5611SSimon Glassimport re 12b50e5611SSimon Glassimport struct 13b50e5611SSimon Glass 14b50e5611SSimon Glassimport tools 15b50e5611SSimon Glass 167fe9173bSSimon Glass# This is enabled from control.py 177fe9173bSSimon Glassdebug = False 187fe9173bSSimon Glass 19b50e5611SSimon GlassSymbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) 20b50e5611SSimon Glass 21b50e5611SSimon Glass 22b50e5611SSimon Glassdef GetSymbols(fname, patterns): 23b50e5611SSimon Glass """Get the symbols from an ELF file 24b50e5611SSimon Glass 25b50e5611SSimon Glass Args: 26b50e5611SSimon Glass fname: Filename of the ELF file to read 27b50e5611SSimon Glass patterns: List of regex patterns to search for, each a string 28b50e5611SSimon Glass 29b50e5611SSimon Glass Returns: 30b50e5611SSimon Glass None, if the file does not exist, or Dict: 31b50e5611SSimon Glass key: Name of symbol 32b50e5611SSimon Glass value: Hex value of symbol 33b50e5611SSimon Glass """ 34b50e5611SSimon Glass stdout = command.Output('objdump', '-t', fname, raise_on_error=False) 35b50e5611SSimon Glass lines = stdout.splitlines() 36b50e5611SSimon Glass if patterns: 37b50e5611SSimon Glass re_syms = re.compile('|'.join(patterns)) 38b50e5611SSimon Glass else: 39b50e5611SSimon Glass re_syms = None 40b50e5611SSimon Glass syms = {} 41b50e5611SSimon Glass syms_started = False 42b50e5611SSimon Glass for line in lines: 43b50e5611SSimon Glass if not line or not syms_started: 44b50e5611SSimon Glass if 'SYMBOL TABLE' in line: 45b50e5611SSimon Glass syms_started = True 46b50e5611SSimon Glass line = None # Otherwise code coverage complains about 'continue' 47b50e5611SSimon Glass continue 48b50e5611SSimon Glass if re_syms and not re_syms.search(line): 49b50e5611SSimon Glass continue 50b50e5611SSimon Glass 51b50e5611SSimon Glass space_pos = line.find(' ') 52b50e5611SSimon Glass value, rest = line[:space_pos], line[space_pos + 1:] 53b50e5611SSimon Glass flags = rest[:7] 54b50e5611SSimon Glass parts = rest[7:].split() 55b50e5611SSimon Glass section, size = parts[:2] 56b50e5611SSimon Glass if len(parts) > 2: 57b50e5611SSimon Glass name = parts[2] 58b50e5611SSimon Glass syms[name] = Symbol(section, int(value, 16), int(size,16), 59b50e5611SSimon Glass flags[1] == 'w') 60b50e5611SSimon Glass return syms 61b50e5611SSimon Glass 62b50e5611SSimon Glassdef GetSymbolAddress(fname, sym_name): 63b50e5611SSimon Glass """Get a value of a symbol from an ELF file 64b50e5611SSimon Glass 65b50e5611SSimon Glass Args: 66b50e5611SSimon Glass fname: Filename of the ELF file to read 67b50e5611SSimon Glass patterns: List of regex patterns to search for, each a string 68b50e5611SSimon Glass 69b50e5611SSimon Glass Returns: 70b50e5611SSimon Glass Symbol value (as an integer) or None if not found 71b50e5611SSimon Glass """ 72b50e5611SSimon Glass syms = GetSymbols(fname, [sym_name]) 73b50e5611SSimon Glass sym = syms.get(sym_name) 74b50e5611SSimon Glass if not sym: 75b50e5611SSimon Glass return None 76b50e5611SSimon Glass return sym.address 7719790632SSimon Glass 7819790632SSimon Glassdef LookupAndWriteSymbols(elf_fname, entry, image): 7919790632SSimon Glass """Replace all symbols in an entry with their correct values 8019790632SSimon Glass 8119790632SSimon Glass The entry contents is updated so that values for referenced symbols will be 8219790632SSimon Glass visible at run time. This is done by finding out the symbols positions in 8319790632SSimon Glass the entry (using the ELF file) and replacing them with values from binman's 8419790632SSimon Glass data structures. 8519790632SSimon Glass 8619790632SSimon Glass Args: 8719790632SSimon Glass elf_fname: Filename of ELF image containing the symbol information for 8819790632SSimon Glass entry 8919790632SSimon Glass entry: Entry to process 9019790632SSimon Glass image: Image which can be used to lookup symbol values 9119790632SSimon Glass """ 9219790632SSimon Glass fname = tools.GetInputFilename(elf_fname) 9319790632SSimon Glass syms = GetSymbols(fname, ['image', 'binman']) 9419790632SSimon Glass if not syms: 9519790632SSimon Glass return 9619790632SSimon Glass base = syms.get('__image_copy_start') 9719790632SSimon Glass if not base: 9819790632SSimon Glass return 9919790632SSimon Glass for name, sym in syms.iteritems(): 10019790632SSimon Glass if name.startswith('_binman'): 10119790632SSimon Glass msg = ("Image '%s': Symbol '%s'\n in entry '%s'" % 10219790632SSimon Glass (image.GetPath(), name, entry.GetPath())) 10319790632SSimon Glass offset = sym.address - base.address 10419790632SSimon Glass if offset < 0 or offset + sym.size > entry.contents_size: 10519790632SSimon Glass raise ValueError('%s has offset %x (size %x) but the contents ' 10619790632SSimon Glass 'size is %x' % (entry.GetPath(), offset, 10719790632SSimon Glass sym.size, entry.contents_size)) 10819790632SSimon Glass if sym.size == 4: 10919790632SSimon Glass pack_string = '<I' 11019790632SSimon Glass elif sym.size == 8: 11119790632SSimon Glass pack_string = '<Q' 11219790632SSimon Glass else: 11319790632SSimon Glass raise ValueError('%s has size %d: only 4 and 8 are supported' % 11419790632SSimon Glass (msg, sym.size)) 11519790632SSimon Glass 11619790632SSimon Glass # Look up the symbol in our entry tables. 11719790632SSimon Glass value = image.LookupSymbol(name, sym.weak, msg) 11819790632SSimon Glass if value is not None: 11919790632SSimon Glass value += base.address 12019790632SSimon Glass else: 12119790632SSimon Glass value = -1 12219790632SSimon Glass pack_string = pack_string.lower() 12319790632SSimon Glass value_bytes = struct.pack(pack_string, value) 12419790632SSimon Glass if debug: 12519790632SSimon Glass print('%s:\n insert %s, offset %x, value %x, length %d' % 12619790632SSimon Glass (msg, name, offset, value, len(value_bytes))) 12719790632SSimon Glass entry.data = (entry.data[:offset] + value_bytes + 12819790632SSimon Glass entry.data[offset + sym.size:]) 129