| #! /usr/bin/env python |
| |
| # |
| # Copyright (c) 2015 Wind River Systems, Inc. |
| # |
| # Redistribution and use in source and binary forms, with or without |
| # modification, are permitted provided that the following conditions are met: |
| # |
| # 1) Redistributions of source code must retain the above copyright notice, |
| # this list of conditions and the following disclaimer. |
| # |
| # 2) Redistributions in binary form must reproduce the above copyright notice, |
| # this list of conditions and the following disclaimer in the documentation |
| # and/or other materials provided with the distribution. |
| # |
| # 3) Neither the name of Wind River Systems nor the names of its contributors |
| # may be used to endorse or promote products derived from this software without |
| # specific prior written permission. |
| # |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| # POSSIBILITY OF SUCH DAMAGE. |
| # |
| |
| # Arguments: |
| # - name of ELF image |
| |
| # Output: |
| # - sends section and RAM/ROM usage to standard output |
| |
| import os |
| import sys |
| import subprocess |
| |
| xip_rom_size = 0 # XIP ROM usage in bytes |
| xip_ram_size = 0 # XIP RAM usage in bytes |
| ram_size = 0 # non-XIP RAM usage in bytes |
| |
| objdump_list = [] # data gleaned from "objdump -h" |
| |
| |
| def is_xip(filename): |
| """ Determine if image is configured for XIP """ |
| |
| # Search for CONFIG_XIP in the ELF's list of symbols using NM and AWK. |
| # GREP can not be used as it returns an error if the symbol is not found. |
| is_xip_command = "nm " + filename + " | awk '/CONFIG_XIP/ { print $3 }'" |
| |
| is_xip_output = subprocess.check_output(is_xip_command, shell=True) |
| |
| return (len(is_xip_output) != 0) |
| |
| |
| def calculate_sizes(filename): |
| """ Calculate RAM and ROM usage by section """ |
| |
| global ram_size |
| global xip_rom_size |
| global xip_ram_size |
| |
| objdump_command = "objdump -h " + filename |
| objdump_output = subprocess.check_output(objdump_command, |
| shell=True).splitlines() |
| |
| for line in objdump_output: |
| words = line.split() |
| |
| if (len(words) == 0): # Skip lines that are too short |
| continue |
| |
| index = words[0] |
| if (not index[0].isdigit()): # Skip lines that do not start |
| continue # with a digit |
| |
| name = words[1] # Skip lines with section names |
| if (name[0] == '.'): # starting with '.' |
| continue |
| |
| size = int(words[2], 16) |
| phys_addr = int(words[4], 16) |
| |
| # Add section to memory use totals (for both non-XIP and XIP scenarios) |
| # |
| # In an XIP image, the following sections are placed into ROM: |
| # text, ctors, rodata and datas |
| # In an XIP image, the following sections are placed into RAM: |
| # datas, bss and noinit |
| # In a non-XIP image, the following sections are placed into RAM |
| # text, ctors, rodata, datas, bss and noinit |
| # |
| # Unrecognized section names are tagged with the '*' character |
| # and are not included in the calculations. |
| |
| ram_size += size |
| |
| if ((name == "text") or (name == "ctors") or (name == "rodata")): |
| xip_rom_size += size |
| elif (name == "datas"): |
| xip_rom_size += size |
| xip_ram_size += size |
| elif ((name == "bss") or (name == "noinit")): |
| xip_ram_size += size |
| else: |
| name += "*" # Unrecognized section |
| ram_size -= size # Undo the calculation |
| |
| objdump_list.append("%-17s 0x%08x %8d %5x" % |
| (name, phys_addr, size, size)) |
| |
| |
| def display_sizes(filename): |
| """ Display the section and memory usage """ |
| |
| print("SECTION NAME ADDRESS SIZE HEX") |
| |
| for line in objdump_list: |
| print(line) |
| print |
| |
| if (is_xip(filename)): |
| print("Total: %d bytes (ROM) + %d bytes (RAM)" % |
| (xip_rom_size, xip_ram_size)) |
| else: |
| print("Total: %d bytes (RAM)" % ram_size) |
| |
| |
| def is_elf(filename): |
| """ Determine if 'filename' is an ELF image file """ |
| |
| magic = 0 |
| |
| with open(filename, "rb") as f: |
| magic = f.read(4) |
| |
| return (magic == "\x7fELF") |
| |
| |
| def display_help(): |
| """ Display tool help information """ |
| |
| print("Usage: truesize <elf_file>") |
| print("Display section information and calculated memory usage.") |
| print("Unrecognized sections are tagged with '*' and are not included") |
| print("in the calculations.") |
| |
| |
| def sanitize_arguments(): |
| """ Perform sanity checks on the command line arguments """ |
| |
| # Ensures that the correct number of arguments is supplied to the tool and |
| # that the specified file is an ELF image. |
| |
| if ((len(sys.argv) != 2) or (not is_elf(sys.argv[1]))): |
| display_help() |
| sys.exit(1) |
| |
| |
| ############################################################################### |
| # |
| # TRUESIZE MAINLINE |
| # |
| |
| |
| sanitize_arguments() |
| calculate_sizes(sys.argv[1]) |
| display_sizes(sys.argv[1]) |