#! /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 ") 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])