binman: Add support for outputing a map file

It is useful to be able to see a list of regions in each image produced by
binman. Add a -m option to output this information in a '.map' file
alongside the image file.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2018-06-01 09:38:20 -06:00
parent 7ae5f315b3
commit 3b0c3821d6
8 changed files with 88 additions and 6 deletions

View File

@ -548,6 +548,25 @@ At present this feature is only supported in SPL. In principle it is possible
to fill in such symbols in U-Boot proper, as well.
Map files
---------
The -m option causes binman to output a .map file for each image that it
generates. This shows the position and size of each entry. For example:
Position Size Name
00000000 00000010 section@0
00000000 00000004 u-boot
00000010 00000010 section@1
00000000 00000004 u-boot
This shows a hierarchical image with two sections, each with a single entry. The
positions of the sections are absolute hex byte offsets within the image. The
positions of the entries are relative to their respective sections. The size of
each entry is also shown, in bytes (hex). The indentation shows the entries
nested inside their sections.
Code coverage
-------------
@ -628,7 +647,6 @@ Some ideas:
'Access to binman entry positions at run time' above
- Use of-platdata to make the information available to code that is unable
to use device tree (such as a very small SPL image)
- Write an image map to a text file
- Allow easy building of images by specifying just the board name
- Produce a full Python binding for libfdt (for upstream)
- Add an option to decode an image into the constituent binaries

View File

@ -301,3 +301,12 @@ class Section(object):
def GetEntries(self):
return self._entries
def WriteMap(self, fd, indent):
"""Write a map of the section to a .map file
Args:
fd: File to write the map to
"""
for entry in self._entries.values():
entry.WriteMap(fd, indent)

View File

@ -30,6 +30,8 @@ def ParseArgs(argv):
help='Add a path to a directory to use for input files')
parser.add_option('-H', '--full-help', action='store_true',
default=False, help='Display the README file')
parser.add_option('-m', '--map', action='store_true',
default=False, help='Output a map file for each image')
parser.add_option('-O', '--outdir', type='string',
action='store', help='Path to directory to use for intermediate and '
'output files')

View File

@ -112,6 +112,8 @@ def Binman(options, args):
image.ProcessEntryContents()
image.WriteSymbols()
image.BuildImage()
if options.map:
image.WriteMap()
finally:
tools.FinaliseOutputDir()
finally:

View File

@ -4,6 +4,8 @@
# Base class for all entries
#
from __future__ import print_function
# importlib was introduced in Python 2.7 but there was a report of it not
# working in 2.7.12, so we work around this:
# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html
@ -50,6 +52,7 @@ class Entry(object):
self.section = section
self.etype = etype
self._node = node
self.name = node and node.name or 'none'
self.pos = None
self.size = None
self.contents_size = 0
@ -229,3 +232,13 @@ class Entry(object):
this function and raise if there is a problem.
"""
pass
def WriteMap(self, fd, indent):
"""Write a map of the entry to a .map file
Args:
fd: File to write the map to
indent: Curent indent level of map (0=none, 1=one level, etc.)
"""
print('%s%08x %08x %s' % (' ' * indent, self.pos, self.size,
self.name), file=fd)

View File

@ -48,3 +48,12 @@ class Entry_section(Entry):
def CheckPosition(self):
self._section.CheckEntries()
def WriteMap(self, fd, indent):
"""Write a map of the section to a .map file
Args:
fd: File to write the map to
"""
super(Entry_section, self).WriteMap(fd, indent)
self._section.WriteMap(fd, indent + 1)

View File

@ -146,16 +146,19 @@ class TestFunctional(unittest.TestCase):
# options.verbosity = tout.DEBUG
return control.Binman(options, args)
def _DoTestFile(self, fname, debug=False):
def _DoTestFile(self, fname, debug=False, map=False):
"""Run binman with a given test file
Args:
fname: Device-tree source filename to use (e.g. 05_simple.dts)
debug: True to enable debugging output
map: True to output map files for the images
"""
args = ['-p', '-I', self._indir, '-d', self.TestFile(fname)]
if debug:
args.append('-D')
if map:
args.append('-m')
return self._DoBinman(*args)
def _SetupDtb(self, fname, outfile='u-boot.dtb'):
@ -180,7 +183,7 @@ class TestFunctional(unittest.TestCase):
TestFunctional._MakeInputFile(outfile, data)
return data
def _DoReadFileDtb(self, fname, use_real_dtb=False):
def _DoReadFileDtb(self, fname, use_real_dtb=False, map=False):
"""Run binman and return the resulting image
This runs binman with a given test file and then reads the resulting
@ -195,11 +198,13 @@ class TestFunctional(unittest.TestCase):
the u-boot-dtb entry. Normally this is not needed and the
test contents (the U_BOOT_DTB_DATA string) can be used.
But in some test we need the real contents.
map: True to output map files for the images
Returns:
Tuple:
Resulting image contents
Device tree contents
Map data showing contents of image (or None if none)
"""
dtb_data = None
# Use the compiled test file as the u-boot-dtb input
@ -207,15 +212,21 @@ class TestFunctional(unittest.TestCase):
dtb_data = self._SetupDtb(fname)
try:
retcode = self._DoTestFile(fname)
retcode = self._DoTestFile(fname, map=map)
self.assertEqual(0, retcode)
# Find the (only) image, read it and return its contents
image = control.images['image']
fname = tools.GetOutputFilename('image.bin')
self.assertTrue(os.path.exists(fname))
if map:
map_fname = tools.GetOutputFilename('image.map')
with open(map_fname) as fd:
map_data = fd.read()
else:
map_data = None
with open(fname) as fd:
return fd.read(), dtb_data
return fd.read(), dtb_data, map_data
finally:
# Put the test file back
if use_real_dtb:
@ -815,7 +826,7 @@ class TestFunctional(unittest.TestCase):
"""Test that we can cope with an image without microcode (e.g. qemu)"""
with open(self.TestFile('u_boot_no_ucode_ptr')) as fd:
TestFunctional._MakeInputFile('u-boot', fd.read())
data, dtb = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
data, dtb, _ = self._DoReadFileDtb('44_x86_optional_ucode.dts', True)
# Now check the device tree has no microcode
self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
@ -929,5 +940,15 @@ class TestFunctional(unittest.TestCase):
expected = U_BOOT_DATA + '!' * 12 + U_BOOT_DATA + 'a' * 12 + '&' * 8
self.assertEqual(expected, data)
def testMap(self):
"""Tests outputting a map of the images"""
_, _, map_data = self._DoReadFileDtb('55_sections.dts', map=True)
self.assertEqual('''Position Size Name
00000000 00000010 section@0
00000000 00000004 u-boot
00000010 00000010 section@1
00000000 00000004 u-boot
''', map_data)
if __name__ == "__main__":
unittest.main()

View File

@ -98,3 +98,11 @@ class Image:
def GetEntries(self):
return self._section.GetEntries()
def WriteMap(self):
"""Write a map of the image to a .map file"""
filename = '%s.map' % self._name
fname = tools.GetOutputFilename(filename)
with open(fname, 'w') as fd:
print('%8s %8s %s' % ('Position', 'Size', 'Name'), file=fd)
self._section.WriteMap(fd, 0)