How to Dig into Firmware Code Size

Every firmware engineer has run out of code space at some point or another. Whether they are trying to cram in another feature, or to make enough space for A/B firmware updates more code space is always better.


This is a companion discussion topic for the original entry at https://interrupt.memfault.com/blog/best-firmware-size-tools

Hi,

First of all, thanks a lot for this article, it’s very helpful!
My question is - does the pacover tool works also on axf files? if yes, how do I need to prepare my codebase?

Hi @ngotes

The puncover tool works on any file that was built with debug information and stored in the ELF file format.

.axf (and .out) files usually use the ELF format so you should just be able to follow the instructions as is.

You can easily check to see if the file is in the ELF format by checking to see if the file starts with the EI_MAG header which is 0x7F followed by ‘E’, ‘L’, ‘F’. For example, here’s an axf file I generated recently using the NXP MCUXpressoIDE:

xxd lpcxpresso55s69_freertos_blinky_s.axf  | head -1
00000000: 7f45 4c46 0101 0100 0000 0000 0000 0000  .ELF............

You can use a tool like readelf to check and see if the ELF was compiled with debug information. If it was there will be debug_* sections in the file, i.e

arm-none-eabi-readelf -S lpcxpresso55s69_freertos_blinky_s.axf | grep debug
  [10] .debug_info       PROGBITS        00000000 02fe60 01dab9 00      0   0  1
  [11] .debug_abbrev     PROGBITS        00000000 04d919 003287 00      0   0  1
  [12] .debug_aranges    PROGBITS        00000000 050ba0 0009d8 00      0   0  1
  [13] .debug_ranges     PROGBITS        00000000 051578 000948 00      0   0  1
  [14] .debug_macro      PROGBITS        00000000 051ec0 01a019 00      0   0  1
  [15] .debug_line       PROGBITS        00000000 06bed9 008c00 00      0   0  1
  [16] .debug_str        PROGBITS        00000000 074ad9 0d42f3 01  MS  0   0  1
  [19] .debug_frame      PROGBITS        00000000 148ef8 002a44 00      0   0  4
  [20] .debug_loc        PROGBITS        00000000 14b93c 0009d1 00      0   0  1

Hi @chrisc

Thanks a lot for the detailed answer.
It works fine on both files!

Great! Glad to hear it!

well, the puncover do not works with Windows 10…
:unamused:

@rdmeneze Could you share more information? What problem did you run into? It should work fine provided you have the right tools installed.

I’m using the same configuration that you described at the post.

well, look the error bellow:

(venv) C:\sources\git\tools\puncover>python runner.py --arm_tools_dir=c:\arm\8-2019-q3-update --elf_file c:\sources\git\fw\imetos\iMetos3_RTX\iMetosEcoD3_Full_Debug\iMetos3_RTX.elf
DEPRECATED: argument --arm_tools_dir will be removed, use --gcc_tools_base instead.
parsing ELF at c:\sources\git\fw\imetos\iMetos3_RTX\iMetosEcoD3_Full_Debug\iMetos3_RTX.elf
Traceback (most recent call last):
File “runner.py”, line 11, in
main()
File “C:\sources\git\tools\puncover\puncover\puncover.py”, line 58, in main
builder.build_if_needed()
File “C:\sources\git\tools\puncover\puncover\builders.py”, line 32, in build_if_needed
self.build()
File “C:\sources\git\tools\puncover\puncover\builders.py”, line 22, in build
self.collector.parse_elf(self.get_elf_path())
File “C:\sources\git\tools\puncover\puncover\collector.py”, line 306, in parse_elf
self.parse_assembly_text(“”.join(self.gcc_tools.get_assembly_lines(elf_file)))
File “C:\sources\git\tools\puncover\puncover\gcc_tools.py”, line 27, in get_assembly_lines
return self.gcc_tool_lines(‘objdump’, [‘-dslw’, os.path.basename(elf_file)], os.path.dirname(elf_file))
File “C:\sources\git\tools\puncover\puncover\gcc_tools.py”, line 23, in gcc_tool_lines
proc = subprocess.Popen([self.gcc_tool_path(name)] + args, stdout=subprocess.PIPE, cwd=cwd)
File “C:\sources\git\tools\puncover\puncover\gcc_tools.py”, line 18, in gcc_tool_path
raise Exception(“Could not find %s” % path)
Exception: Could not find c:\arm\8-2019-q3-update\bin/arm-none-eabi-objdump

There seem to be a couple of solutions that you could patch on top of puncover in this Github Issue to get Windows to work: https://github.com/HBehrens/puncover/issues/37.

If you have any favorite tools to explore code size on Windows, I’d love to link them in this post.

hey there. I wanted to use puncover for a msp430 gcc toolchain. Is this specifically made for arm controllers? because i get the following error message:

raise Exception("Could not find %s" % path)

Exception: Could not find C:…\msp430-gcc-8.3.0.16_win32\bin/arm-none-eabi-objdump

this file is in my case named: msp430-elf-objdump

@donar I believe it’s only ever been tested with ARM, but you may be able to get it to work by setting the --gcc_tools_base path rather than the --arm_tools_dir flag. Something like --gcc_tools_base=C:\...msp430-gcc-8.3.0.16_win32\bin\msp430-none-eabi-

Let me know if that works!

@francois Thanks for the answer. I get the following output, and after jumping over the python code I think it will not work without changes

C:\repos\python\puncoverTest\venv\Scripts>puncover.exe --gcc_tools_base=C:/ti/ccs920/ccs/tools/compiler/msp430-gcc-8.3.0.16_win32/bin/ --elf_file C:\Users\baerch\workspace_v9_2\testCCode\Debug\testCCode.out
parsing ELF at C:\Users\baerch\workspace_v9_2\testCCode\Debug\testCCode.out
Traceback (most recent call last):
File “C:\repos\python\puncoverTest\venv\Scripts\puncover-script.py”, line 11, in
load_entry_point(‘puncover==0.0.1’, ‘console_scripts’, ‘puncover’)()
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\puncover.py”, line 58, in main
builder.build_if_needed()
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\builders.py”, line 32, in build_if_needed
self.build()
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\builders.py”, line 22, in build
self.collector.parse_elf(self.get_elf_path())
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\collector.py”, line 306, in parse_elf
self.parse_assembly_text("".join(self.gcc_tools.get_assembly_lines(elf_file)))
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\gcc_tools.py”, line 27, in get_assembly_lines
return self.gcc_tool_lines(‘objdump’, [’-dslw’, os.path.basename(elf_file)], os.path.dirname(elf_file))
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\gcc_tools.py”, line 23, in gcc_tool_lines
proc = subprocess.Popen([self.gcc_tool_path(name)] + args, stdout=subprocess.PIPE, cwd=cwd)
File “C:\repos\python\puncoverTest\venv\lib\site-packages\puncover\gcc_tools.py”, line 18, in gcc_tool_path
raise Exception(“Could not find %s” % path)
Exception: Could not find C:/ti/ccs920/ccs/tools/compiler/msp430-gcc-8.3.0.16_win32/bin/objdump

You can find a patch to make it work on Windows on this Github issue: https://github.com/HBehrens/puncover/issues/37

Main problem is that all the gcc stuff is named with the prefix : msp430-elf-…exe.
After I renamed all the needed files I got the error message: AttributeError: ‘Collector’ object has no attribute ‘parse_size_line_re’

Hi all,

Since this is the best documentation on how to use puncover, I’d like to add some corrections that were necessary to get things working (ran through the article yesterday).

  1. Please use upstream https://github.com/HBehrens/puncover version instead of the memfault fork (not clear why one should use the memfault version, other than tox support).
  2. To install, after checkout: python3 ./setup.py install --user . This will handle all of the requirements and install puncover to user controlled directory (/home/user/.local/bin/puncover over here, on Ubuntu). puncover should then be executable just by the program name (~/.local/bin/ should be already in your PATH). Using python2.7 will not work. Running setup like this replaces the Setting up for puncover section in the article.
  3. I’m not sure whether -fdebug-prefix-map is required anymore. Things seem to work here without it with build_dir option to puncover.
  4. Since the article came out, puncover learned to also collate the build time generated stack usage information. Add -fstack-usage option to your GCC runs to get the *.su files that puncover will collect.

I use the following command line for a project that is built in the source directory (yes I know it’s bad, but it’s just a sandbox for playing):
puncover --gcc_tools_base /home/user/local/gcc-arm-none-eabi-8-2019-q3-update/bin/arm-none-eabi- --elf_file ${PWD}/generic-test.elf --build_dir ${PWD}

Important bit here being that the expected format for the new gcc_tools_base is a prefix, not just a path (compared to the old arm_tools_dir). The paths to the puncover options also need to be absolute.

After this, you should have nice interactively navigatable view into stack, static SRAM and code space usage.

1 Like

I got puncover from HBehrens’ repository and installed it successfully. But I cannot get the output in a webpage. How could I figure out what’s wrong here?

Looks like the instructions for Puncover are out of date now. I think you just need to ‘pip install -e .’ from the cloned repo.

A post was split to a new topic: BSS section larger than expected

Hi, I tried out puncover and really like the interface, however the code size reporting is not accurate for me. Some symbols are reported with a lower code size (compared to the size reported by nm), resulting in around 10% lower than the actual total size. I don’t understand the cause yet, but someone else in GitHub has a similar issue: use map files instead of output from nm as a source of symbols and sizes · Issue #41 · HBehrens/puncover · GitHub. If someone has an idea, I would be interested.

Bloaty reports the sizes accurately, however I found the usage a bit confusing and not as powerful as the GUI of puncover. Nevertheless it could be strong basis for a visual tool.

There is one more tool I would like to share: GitHub - ARMmbed/mbed-os-linker-report: Post-processing of linker output to calculate and visualize memory usage for elf-sections. This one comes from the Mbed community and has a very useful pie chart visualization. However this also suffers from the same inaccuracy issue with puncover. Maybe they use the same tooling underneath, I didn’t look into it that much.

Hi, thanks for your nice article.
Puncover seems a very nice tool. But it doesn’t show me anything in the stack column. Folders are also unknown!

Any idea what is wrong here?

PS: I used these flags, in my make file:
CFLAGS += -fstack-usage
CFLAGS += -fdebug-prefix-map=/=