#!/bin/bash # # This is a wrapper for the elf-size-report.awk script which prints a detailed report # of memory segment allocations and usage in a given ELF file, based on gcc 'size' output. # This script sets up memory segment information needed by the awk script. # If more than one .elf file is given, then a comparison (delta memory use) report is # also performed using elf-size-compare.awk. # Currently supports some STMicro & Atmel ARM MCUs. May not work with all placement strategies. # # Usage: # [VAR=value] ./elf-memory-report.sh [options] [file.elf] [file2.elf] [...] # # Where VAR is any of the CAPITALIZED variables below. More than one can be specified, # and any VAR can also be set in the environment. # SIZE : gcc binutils 'size' command to use, default is "arm-none-eabi-size". # MCU : # Specifies MCU model on which to base default segment location/size parameters. Also see "--mcu=" option. # MEM_START_ & MEM_SIZE_ : (read code below for defaults) # Allows specifying additional/custom segment information, eg. MEM_SIZE_FLASH=768 # # Options can be one or more of the following: # --mcu= # Set MCU type. Same as setting the MCU env. variable, and overrides it. # --skip-data # Some linker scripts duplicate .data in the output (eg: .data and .data_run). # Set this option to skip .data from being counted in RAM a 2nd time # (it is always shown as being in Flash). # --compare-only # When specifying multiple elf files, only show the final comparison report. # --no-compare # Opposite and exclusive of previous option, that is, do NOT show comparison report (only size reports). # # If an elf file is not specified on the command line, this script will prompt for one. # # Examples: # MCU="STM32F439xI" MEM_SIZE_SDRAM2=8192 ./elf-memory-report.sh path/to/firmware.elf # ./elf-memory-report.sh --mcu ATSAM3S4C --compare-only firmware_new.elf firmware_old.elf # set -k && ./elf-memory-report.sh MCU=STM32F427VG --skip-data firmware.elf # (the -k switch allows variable assignment anywhere on the command line) # c:\cygwin\bin\bash -kc './elf-memory-report.sh --mcu ATSAM3S8C "c:\windows\path\with spaces\firmware.elf"' # # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # Copyright (c)2016 Maxim Paperno # Copyright (c)2017 OpenTX # # -- gcc binutils 'size' command to use : ${SIZE:="arm-none-eabi-size"} # -- MCU type, if defined will set certain memory defaults # e.g. STM32F205xE or ATSAM3S4C : ${MCU:="unknown"} # -- process options compare=2 skip_data=0 for i in "$@" ; do case $i in --mcu=*) MCU="${i#*=}"; shift;; --skip-data) skip_data=1; shift;; --compare-only) compare=1; shift;; --no-compare) compare=0; shift;; esac done # -- make sure gawk is installed : ${AWKCMD:=""} if gawk --version >/dev/null 2>&1; then [[ "$OSTYPE" == "darwin"* ]] && AWKCMD="gawk -nf" else echo "GAWK is required, exiting." exit 1 fi # -- defaults which may change based on MCU default_flash_addr=0x08000000 default_flash_sz=1024 # KB default_ccm_sz=0 default_ram1_sz=128 default_ram2_sz=0 default_ram3_sz=0 # -- Set defaults based on MCU type if [[ $MCU != "unknown" ]] ; then mcu_brand=${MCU:0:2} # ST or AT if [[ $mcu_brand == "ST" && ${#MCU} -ge 7 ]] ; then # e.g.: STM32F427VG stm_series=${MCU:6:1} # 4 stm_ser_ex=${MCU:7:1} # 2 stm_flash=${MCU:10:1} # G default_ram1_sz=112 default_ram2_sz=16 case $stm_flash in "I") default_flash_sz=2048;; "G") default_flash_sz=1024;; "E") default_flash_sz=512;; "C") default_flash_sz=256;; esac if (( $stm_series == 4 )) ; then default_ccm_sz=64 if (( $stm_ser_ex >= 2 )) ; then default_ram3_sz=64 fi fi elif [[ $mcu_brand == "AT" && ${#MCU} -ge 9 ]] ; then # e.g.: ATSAM3S4C atm_series=${MCU:5:4} # 3S4C default_flash_addr=0x00400000 case $atm_series in "3S8C") default_flash_sz=512; default_ram1_sz=64;; "3S4C") default_flash_sz=256; default_ram1_sz=48;; "3S2C") default_flash_sz=128; default_ram1_sz=32;; esac else echo "MCU type unrecognized, exiting." exit 1 fi fi # -- target memory locations in hex : ${MEM_START_FLASH:=$default_flash_addr} : ${MEM_START_CCRAM:=0x10000000} : ${MEM_START_SRAM1:=0x20000000} : ${MEM_START_SRAM2:=0x2001c000} : ${MEM_START_SRAM3:=0x20020000} : ${MEM_START_PSRAM1:=0x60000000} : ${MEM_START_SDRAM1:=0xC0000000} : ${MEM_START_SDRAM2:=0xD0000000} # -- target memory sizes in KB : ${MEM_SIZE_FLASH:=$default_flash_sz} : ${MEM_SIZE_CCRAM:=$default_ccm_sz} : ${MEM_SIZE_SRAM1:=$default_ram1_sz} : ${MEM_SIZE_SRAM2:=$default_ram2_sz} : ${MEM_SIZE_SRAM3:=$default_ram3_sz} : ${MEM_SIZE_PSRAM1:=0} : ${MEM_SIZE_SDRAM1:=0} : ${MEM_SIZE_SDRAM2:=0} # -- prompt for elf file if not on command line if [[ -z "$@" ]] ; then read -p "Elf file(s): " ELF_FILES else ELF_FILES=$@ fi # -- Set arrays for awk script. The segments should be in increasing address order. names=("Flash" "CCRAM" "SRAM1" "SRAM2" "SRAM3" "PSRAM1" "SDRAM1" "SDRAM2") addrs=(${MEM_START_FLASH} ${MEM_START_CCRAM} ${MEM_START_SRAM1} ${MEM_START_SRAM2} ${MEM_START_SRAM3} \ ${MEM_START_PSRAM1} ${MEM_START_SDRAM1} ${MEM_START_SDRAM2}) sizes=(${MEM_SIZE_FLASH} ${MEM_SIZE_CCRAM} ${MEM_SIZE_SRAM1} ${MEM_SIZE_SRAM2} ${MEM_SIZE_SRAM3} \ ${MEM_SIZE_PSRAM1} ${MEM_SIZE_SDRAM1} ${MEM_SIZE_SDRAM2}) base_dir="$(dirname "$BASH_SOURCE")" base_dir="${base_dir%%[[:space:]]}" # sometimes we get trailing \n # -- run the ARM size command for each elf file and send output to awk script all_output="" file_cnt=0 for elf in "$@"; do if [[ ! -f "$elf" ]] ; then echo "ELF file \"$elf\" not found." continue fi #${SIZE} -A -x ${elf} escelf="${elf//\\//}" output=`${SIZE} -A -x ${elf} | ${AWKCMD} "${base_dir}/elf-size-report.awk" \ -v mcu="${MCU}" \ -v elf="${escelf}" \ -v skip_data=${skip_data} \ -v names="${names[*]}" \ -v addrs="${addrs[*]}" \ -v sizes="${sizes[*]}"` if (( compare != 1 )) ; then echo "$output" echo fi file_cnt+=1 all_output+="${output}\n" done # -- if more than one elf file was given, also run a comparison report if (( file_cnt > 1 && compare )) ; then echo "$all_output" | ${AWKCMD} "${base_dir}/elf-size-compare.awk" fi