zephyr/scripts/truesize

175 lines
5.6 KiB
Python
Executable File

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