]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
binman: Support finding symbols in sub-sections
authorSimon Glass <sjg@chromium.org>
Thu, 7 Jan 2021 04:35:15 +0000 (21:35 -0700)
committerSimon Glass <sjg@chromium.org>
Sat, 30 Jan 2021 21:25:41 +0000 (14:25 -0700)
At present binman only supports resolving symbols in the same section as
the binary that uses it. This is quite limited because we often need to
group entries into different sections.

Enhance the algorithm to search the entire image for symbols.

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/elf.py
tools/binman/elf_test.py
tools/binman/etype/section.py
tools/binman/ftest.py
tools/binman/image.py
tools/binman/test/187_symbols_sub.dts [new file with mode: 0644]

index 249074a334a14848f73d9e32480a182af05c30d2..03b49d7163c553d733878a6b070ef3697160b2d0 100644 (file)
@@ -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()
index e3d218a89e92ee414fd4fa8af41e0c23e6087c31..7a128018d9f0b9488c72f354dac86930338bd547 100644 (file)
@@ -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
index 3dd5f58c4c200c2c09677c03c601e3665f431516..9c6334c450440df183eb4b2c1b52e05a8d846228 100644 (file)
@@ -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
index e753a342c8f808666dde0630b045b24014f3ca50..5016060ea6858a878c46e2f0ff6d544cc965830b 100644 (file)
@@ -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('<LQLL', 0x00, 0x1c, 0x28, 0x04)
+        expected = (sym_values + U_BOOT_SPL_DATA[20:] +
+                    tools.GetBytes(0xff, 1) + U_BOOT_DATA + sym_values +
+                    U_BOOT_SPL_DATA[20:])
+        self.assertEqual(expected, data)
+
 
 if __name__ == "__main__":
     unittest.main()
index d65ab887b80ec9d3f0b9e0ea40a6314f8da95d85..3622efc6862cd6a9b35e3fe16fdedb7e64adfe1c 100644 (file)
@@ -324,3 +324,48 @@ class Image(section.Entry_section):
             _DoLine(lines, _EntryToStrings(entry))
             selected_entries.append(entry)
         return selected_entries, lines, widths
+
+    def LookupImageSymbol(self, sym_name, optional, msg, base_addr):
+        """Look up a symbol in an ELF file
+
+        Looks up a symbol in an ELF file. Only entry types which come from an
+        ELF image can be used by this function.
+
+        This searches through this image including all of its subsections.
+
+        At present the only entry properties supported are:
+            offset
+            image_pos - 'base_addr' is added if this is not an end-at-4gb image
+            size
+
+        Args:
+            sym_name: Symbol name in the ELF file to look up in the format
+                _binman_<entry>_prop_<property> where <entry> is the name of
+                the entry and <property> is the property to find (e.g.
+                _binman_u_boot_prop_offset). As a special case, you can append
+                _any to <entry> 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 (file)
index 0000000..54511a7
--- /dev/null
@@ -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";
+               };
+       };
+};