diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 249074a334..03b49d7163 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -132,7 +132,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section): (msg, sym.size)) # Look up the symbol in our entry tables. - value = section.LookupSymbol(name, sym.weak, msg, base.address) + value = section.GetImage().LookupImageSymbol(name, sym.weak, msg, + base.address) if value is None: value = -1 pack_string = pack_string.lower() diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index e3d218a89e..7a128018d9 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -45,10 +45,12 @@ class FakeSection: def GetPath(self): return 'section_path' - def LookupSymbol(self, name, weak, msg, base_addr): + def LookupImageSymbol(self, name, weak, msg, base_addr): """Fake implementation which returns the same value for all symbols""" return self.sym_value + def GetImage(self): + return self def BuildElfTestFiles(target_dir): """Build ELF files used for testing in binman diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py index 3dd5f58c4c..9c6334c450 100644 --- a/tools/binman/etype/section.py +++ b/tools/binman/etype/section.py @@ -385,7 +385,7 @@ class Entry_section(Entry): return entry.GetData() source_entry.Raise("Cannot find entry for node '%s'" % node.name) - def LookupSymbol(self, sym_name, optional, msg, base_addr): + def LookupSymbol(self, sym_name, optional, msg, base_addr, entries=None): """Look up a symbol in an ELF file Looks up a symbol in an ELF file. Only entry types which come from an @@ -428,18 +428,20 @@ class Entry_section(Entry): (msg, sym_name)) entry_name, prop_name = m.groups() entry_name = entry_name.replace('_', '-') - entry = self._entries.get(entry_name) + if not entries: + entries = self._entries + entry = entries.get(entry_name) if not entry: if entry_name.endswith('-any'): root = entry_name[:-4] - for name in self._entries: + for name in entries: if name.startswith(root): rest = name[len(root):] if rest in ['', '-img', '-nodtb']: - entry = self._entries[name] + entry = entries[name] if not entry: err = ("%s: Entry '%s' not found in list (%s)" % - (msg, entry_name, ','.join(self._entries.keys()))) + (msg, entry_name, ','.join(entries.keys()))) if optional: print('Warning: %s' % err, file=sys.stderr) return None @@ -648,3 +650,32 @@ class Entry_section(Entry): """ for entry in self._entries.values(): entry.CheckMissing(missing_list) + + def _CollectEntries(self, entries, entries_by_name, add_entry): + """Collect all the entries in an section + + This builds up a dict of entries in this section and all subsections. + Entries are indexed by path and by name. + + Since all paths are unique, entries will not have any conflicts. However + entries_by_name make have conflicts if two entries have the same name + (e.g. with different parent sections). In this case, an entry at a + higher level in the hierarchy will win over a lower-level entry. + + Args: + entries: dict to put entries: + key: entry path + value: Entry object + entries_by_name: dict to put entries + key: entry name + value: Entry object + add_entry: Entry to add + """ + entries[add_entry.GetPath()] = add_entry + to_add = add_entry.GetEntries() + if to_add: + for entry in to_add.values(): + entries[entry.GetPath()] = entry + for entry in to_add.values(): + self._CollectEntries(entries, entries_by_name, entry) + entries_by_name[add_entry.name] = add_entry diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index e753a342c8..5016060ea6 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -4139,6 +4139,21 @@ class TestFunctional(unittest.TestCase): } self.assertEqual(expected, props) + def testSymbolsSubsection(self): + """Test binman can assign symbols from a subsection""" + elf_fname = self.ElfTestFile('u_boot_binman_syms') + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start') + self.assertEqual(syms['_binman_u_boot_spl_prop_offset'].address, addr) + + self._SetupSplElf('u_boot_binman_syms') + data = self._DoReadFile('187_symbols_sub.dts') + sym_values = struct.pack('_prop_ where is the name of + the entry and is the property to find (e.g. + _binman_u_boot_prop_offset). As a special case, you can append + _any to to have it search for any matching entry. E.g. + _binman_u_boot_any_prop_offset will match entries called u-boot, + u-boot-img and u-boot-nodtb) + optional: True if the symbol is optional. If False this function + will raise if the symbol is not found + msg: Message to display if an error occurs + base_addr: Base address of image. This is added to the returned + image_pos in most cases so that the returned position indicates + where the targeted entry/binary has actually been loaded. But + if end-at-4gb is used, this is not done, since the binary is + already assumed to be linked to the ROM position and using + execute-in-place (XIP). + + Returns: + Value that should be assigned to that symbol, or None if it was + optional and not found + + Raises: + ValueError if the symbol is invalid or not found, or references a + property which is not supported + """ + entries = OrderedDict() + entries_by_name = {} + self._CollectEntries(entries, entries_by_name, self) + return self.LookupSymbol(sym_name, optional, msg, base_addr, + entries_by_name) diff --git a/tools/binman/test/187_symbols_sub.dts b/tools/binman/test/187_symbols_sub.dts new file mode 100644 index 0000000000..54511a7371 --- /dev/null +++ b/tools/binman/test/187_symbols_sub.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + section { + pad-byte = <0xff>; + u-boot-spl { + }; + + u-boot { + offset = <24>; + }; + }; + + u-boot-spl2 { + type = "u-boot-spl"; + }; + }; +};