diff --git a/configs/baremetal.h b/configs/baremetal.h new file mode 100644 index 000000000..11cb579d7 --- /dev/null +++ b/configs/baremetal.h @@ -0,0 +1,117 @@ +/** + * \file baremetal.h + * + * \brief Test configuration for minimal baremetal Mbed TLS builds + * based on the following primitives: + * - ECDHE-ECDSA only + * - Elliptic curve SECP256R1 only + * - SHA-256 only + * - AES-CCM-8 only + * + * The library compiles in this configuration, but the example + * programs `ssl_client2` and `ssl_server2` require the + * modifications from `baremetal_test.h`. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_BAREMETAL_CONFIG_H +#define MBEDTLS_BAREMETAL_CONFIG_H + +#define MBEDTLS_HAVE_TIME +#define MBEDTLS_HAVE_TIME_DATE + +/* Symmetric crypto: AES-CCM only */ +#define MBEDTLS_CIPHER_C +#define MBEDTLS_AES_C +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_AES_FEWER_TABLES +#define MBEDTLS_CCM_C + +/* Asymmetric crypto: Single-curve ECC only. */ +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_ECDH_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_ECP_WINDOW_SIZE 2 +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 +#define MBEDTLS_ECP_MAX_BITS 256 +#define MBEDTLS_MPI_MAX_SIZE 32 // 256 bits is 32 bytes + +/* Key exchanges */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + +/* Digests - just SHA-256 */ +#define MBEDTLS_MD_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA256_SMALLER + +/* TLS options */ +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_TLS_C +#define MBEDTLS_SSL_PROTO_TLS1_2 +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define MBEDTLS_SSL_SESSION_TICKETS +#define MBEDTLS_SSL_COOKIE_C +#define MBEDTLS_SSL_PROTO_DTLS +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/* X.509 CRT parsing */ +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#define MBEDTLS_ASN1_PARSE_C + +/* X.509 CSR writing */ +#define MBEDTLS_X509_CSR_WRITE_C +#define MBEDTLS_X509_CREATE_C +#define MBEDTLS_ASN1_WRITE_C + +/* RNG and PRNG */ +#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_ENTROPY_C +#define MBEDTLS_HMAC_DRBG_C + +#define MBEDTLS_OID_C +#define MBEDTLS_PLATFORM_C + +/* I/O buffer configuration */ +#define MBEDTLS_SSL_MAX_CONTENT_LEN 2048 + +/* Server-side only */ +#define MBEDTLS_SSL_TICKET_C +#define MBEDTLS_SSL_SRV_C + +#if defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include + +#endif /* MBEDTLS_BAREMETAL_CONFIG_H */ diff --git a/configs/baremetal_test.h b/configs/baremetal_test.h new file mode 100644 index 000000000..82c0ed17c --- /dev/null +++ b/configs/baremetal_test.h @@ -0,0 +1,63 @@ +/** + * \file baremetal_test.h + * + * \brief This file contains minimal modifications to the + * baremetal configuration `baremetal.h` which allows + * example programs to compile and run. + * + * It should be used as the `MBEDTLS_USER_CONFIG_FILE` + * in builds using `baremetal.h`. + */ +/* + * Copyright (C) 2006-2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_BAREMETAL_USER_CONFIG_H +#define MBEDTLS_BAREMETAL_USER_CONFIG_H + +/* We need test CRTs to be able to run ssl_client2 and ssl_server2. */ +#define MBEDTLS_CERTS_C +/* For the network context used by ssl_client2 and ssl_server2. */ +#define MBEDTLS_NET_C +/* Debug output */ +#define MBEDTLS_DEBUG_C + +/* We don't have DER-encoded test CRTs yet. */ +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_BASE64_C +/* We don't have Secp256r1 test CRTs at the moment. */ +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED + +/* Correct ECP configuration values */ +#undef MBEDTLS_ECP_MAX_BITS +#undef MBEDTLS_MPI_MAX_SIZE +#define MBEDTLS_ECP_MAX_BITS 384 +#define MBEDTLS_MPI_MAX_SIZE 48 + +/* ssl_client2 and ssl_server2 use CTR-DRBG so far. */ +#define MBEDTLS_CTR_DRBG_C + +/* The ticket implementation hardcodes AES-GCM */ +#define MBEDTLS_GCM_C + +/* Use Mbed TLS' timer implementation for Linux. */ +#define MBEDTLS_TIMING_C + +#undef MBEDTLS_NO_PLATFORM_ENTROPY + +#endif /* MBEDTLS_BAREMETAL_USER_CONFIG_H */ diff --git a/scripts/baremetal.sh b/scripts/baremetal.sh new file mode 100755 index 000000000..9ab40aacd --- /dev/null +++ b/scripts/baremetal.sh @@ -0,0 +1,366 @@ +#!/bin/sh + +# baremetal.sh +# +# This file is part of mbed TLS (https://tls.mbed.org) +# +# Copyright (c) 2019, ARM Limited, All Rights Reserved +# +# Purpose +# +# * Create a baremetal library-only build (omitting the tests and +# example programs, which have stronger configuration requirements) +# for a Cortex-M target in a minimal configuration, and generate +# code-size statistics. +# By default, the script uses configs/baremetal.h and targets Cortex-M0+, +# and outputs the code-size statistics as `rom.COMMIT_HASH`. +# +# * Create a 32-bit host-build of library, tests and example programs +# in a 'baremetal' base configuration minimally modified to allow +# running tests and example programs, and obtain heap usage statistics +# of a test run of ssl_client2 and ssl_server2. This can be used as +# an estimate for heap usage of 32-bit baremetal applications using Mbed TLS. +# +# By default, the script uses configs/baremetal.h as the base configuration +# modified by configs/baremetal_test.h, and emits the heap usage statistics +# as `massif.COMMIT_HASH`. +# + +set -eu + +if [ -d include/mbedtls ]; then :; else + echo "$0: must be run from root" >&2 + exit 1 +fi + +if grep -i cmake Makefile >/dev/null; then + echo "$0: not compatible with cmake" >&2 + exit 1 +fi + +# The 'baremetal' configuration to test +: ${BAREMETAL_CONFIG:=./configs/baremetal.h} +CFLAGS_CONFIG="-DMBEDTLS_CONFIG_FILE='\"../$BAREMETAL_CONFIG\"'" + +# The modifications to the 'baremetal' configuration which allows +# tests and example programs to build and execute. +: ${BAREMETAL_USER_CONFIG:=./configs/baremetal_test.h} +CFLAGS_USER_CONFIG="-DMBEDTLS_USER_CONFIG_FILE='\"../$BAREMETAL_USER_CONFIG\"'" + +: ${ARMC5_BIN_DIR:=""} +: ${ARMC6_BIN_DIR:=""} +if [ -n "$ARMC5_BIN_DIR" ]; then + ARMC5_BIN_DIR="$ARMC5_BIN_DIR/" +fi + +if [ -n "$ARMC6_BIN_DIR" ]; then + ARMC6_BIN_DIR="$ARMC6_BIN_DIR/" +fi + +: ${NAME:=$(git rev-parse HEAD)} +: ${GCC_CC:=arm-none-eabi-gcc} +: ${GCC_AR:=arm-none-eabi-ar} +: ${ARMC6_CC:="${ARMC6_BIN_DIR}armclang"} +: ${ARMC6_AR:="${ARMC6_BIN_DIR}armar"} +: ${ARMC5_CC:="${ARMC5_BIN_DIR}armcc"} +: ${ARMC5_AR:="${ARMC5_BIN_DIR}armar"} + +date=$( date +%Y-%m-%d-%H-%M-%S ) + +baremetal_build_gcc() +{ + echo "Cleanup..." + make clean + + echo "Create 32-bit library-only baremetal build (GCC, config: $BAREMETAL_CONFIG)" + gcc_ver=$($GCC_CC --version | head -n 1 | sed -n 's/^.*\([0-9]\.[0-9]\.[0-9]\).*$/\1/p') + + CFLAGS_BAREMETAL="-Os -mthumb -mcpu=cortex-m0plus" + CFLAGS="$CFLAGS_BAREMETAL $CFLAGS_CONFIG" + + $GCC_CC --version + + echo "GCC version: $gcc_ver" + echo "Flags: $CFLAGS_BAREMETAL" + make CC=$GCC_CC AR=$GCC_AR CFLAGS="$CFLAGS" lib -j > /dev/null + + ROM_OUT_FILE="rom_files__${date}__${NAME}__gcc_${gcc_ver}" + ROM_OUT_SYMS="rom_syms__${date}__${NAME}__gcc_${gcc_ver}" + echo "Generate file statistics..." + ./scripts/extract_codesize_stats.sh --info "gcc_${gcc_ver}" --name $NAME --files > $ROM_OUT_FILE + echo "Generate symbol statistics..." + ./scripts/extract_codesize_stats.sh --info "gcc_${gcc_ver}" --name $NAME --syms > $ROM_OUT_SYMS + + echo "ROM statistics written to:" + echo "* $ROM_OUT_FILE" + echo "* $ROM_OUT_SYMS" +} + +baremetal_build_armc5() +{ + echo "Cleanup..." + make clean + + echo "Create 32-bit library-only baremetal build (ARMC5, Config: $BAREMETAL_CONFIG)" + armc5_ver=$($ARMC5_CC | sed -n 's/.*ARM Compiler \([^ ]*\)$/\1/p') + + CFLAGS_BAREMETAL="-Ospace --thumb --cpu Cortex-m0plus" + CFLAGS="$CFLAGS_BAREMETAL $CFLAGS_CONFIG" + WARNING_CFLAGS="--strict --c99" + + echo "ARMC5 version: $armc5_ver" + echo "Flags: $WARNING_CFLAGS $CFLAGS_BAREMETAL" + make WARNING_CFLAGS="$WARNING_CFLAGS" CC=$ARMC5_CC AR=$ARMC5_AR CFLAGS="$CFLAGS" lib -j > /dev/null + + ROM_OUT_FILE="rom_files__${date}__${NAME}__armc5_${armc5_ver}" + ROM_OUT_SYMS="rom_syms__${date}__${NAME}__armc5_${armc5_ver}" + echo "Generate file statistics..." + ./scripts/extract_codesize_stats.sh --info "armc5_${armc5_ver}" --name $NAME --files > $ROM_OUT_FILE + echo "Generate symbol statistics..." + ./scripts/extract_codesize_stats.sh --info "armc5_${armc5_ver}" --name $NAME --syms > $ROM_OUT_SYMS + + echo "ROM statistics written to:" + echo "* $ROM_OUT_FILE" + echo "* $ROM_OUT_SYMS" +} + +baremetal_build_armc6() +{ + echo "Cleanup..." + make clean + + echo "Create 32-bit library-only baremetal build (ARMC6, Config: $BAREMETAL_CONFIG)" + armc6_ver=$($ARMC6_CC --version | sed -n 's/.*ARM Compiler \([^ ]*\)$/\1/p') + + CFLAGS_BAREMETAL="-Os --target=arm-arm-none-eabi -mthumb -mcpu=cortex-m0plus" + CFLAGS="$CFLAGS_BAREMETAL $CFLAGS_CONFIG" + WARNING_CFLAGS="-xc -std=c99" + + echo "ARMC6 version: $armc6_ver" + echo "Flags: $WARNING_CFLAGS $CFLAGS_BAREMETAL" + make WARNING_CFLAGS="$WARNING_CFLAGS" CC=$ARMC6_CC AR=$ARMC6_AR CFLAGS="$CFLAGS" lib -j > /dev/null + + ROM_OUT_FILE="rom_files__${date}__${NAME}__armc6_${armc6_ver}" + ROM_OUT_SYMS="rom_syms__${date}__${NAME}__armc6_${armc6_ver}" + echo "Generate file statistics..." + ./scripts/extract_codesize_stats.sh --info "armc6_${armc6_ver}" --name $NAME --files > $ROM_OUT_FILE + echo "Generate symbol statistics..." + ./scripts/extract_codesize_stats.sh --info "armc6_${armc6_ver}" --name $NAME --syms > $ROM_OUT_SYMS + + echo "ROM statistics written to:" + echo "* $ROM_OUT_FILE" + echo "* $ROM_OUT_SYMS" +} + +# 32-bit host-build of library, tests and example programs, +# + heap usage measurements. +baremetal_ram_build() { + : ${BASE_CFLAGS:="-g -m32 -fstack-usage"} + echo "Create 32-bit host-build (Config: $BAREMETAL_CONFIG + $BAREMETAL_USER_CONFIG)" + + echo "Cleanup..." + make clean + + CFLAGS="$BASE_CFLAGS $CFLAGS_CONFIG $CFLAGS_USER_CONFIG" + + echo "Modifications: $BAREMETAL_USER_CONFIG" + cat $BAREMETAL_USER_CONFIG | grep "^#define" | awk '{print "* " $0 }' + + echo "Build (flags: $CFLAGS)..." + make CFLAGS="$CFLAGS" -j > /dev/null + echo "" +} + +# usage: +# - `baremetal_ram_heap 0` for heap usage only +# - `baremetal_ram_heap 1` for heap and stack usage +baremetal_ram_heap() { + + : ${CLI:=./programs/ssl/ssl_client2} + : ${CLI_PARAMS:="dtls=1"} + : ${SRV:=./programs/ssl/ssl_server2} + : ${SRV_PARAMS:="dtls=1 renegotiation=1 auth_mode=required"} + : ${VALGRIND:=valgrind} + : ${VALGRIND_MASSIF_PARAMS="--time-unit=B --threshold=0.01 --detailed-freq=1"} + + if [ $1 -eq 1 ]; then + RAM_HEAP_OUT="ram_heap_stack__${date}__$NAME" + VALGRIND_MASSIF_PARAMS="--stacks=yes $VALGRIND_MASSIF_PARAMS" + else + RAM_HEAP_OUT="ram_heap__${date}__$NAME" + fi + + SRV_CMD="$SRV server_addr=127.0.0.1 server_port=4433 debug_level=4 $SRV_PARAMS" + CLI_CMD="$CLI server_addr=127.0.0.1 server_port=4433 $CLI_PARAMS" + + # Piece together valgrind cmd line + VALGRIND_BASE="$VALGRIND --tool=massif $VALGRIND_MASSIF_PARAMS" + + FUNC_IGNORE="" + FUNC_IGNORE="__fopen_internal $FUNC_IGNORE" + FUNC_IGNORE="_IO_file_doallocate $FUNC_IGNORE" + FUNC_IGNORE="strdup $FUNC_IGNORE" + FUNC_IGNORE="__tzstring_len $FUNC_IGNORE" + FUNC_IGNORE="__tzfile_read $FUNC_IGNORE" + + VALGRIND_IGNORE="" + for func in $FUNC_IGNORE; do + echo "* Valgrind ignore: $func" + VALGRIND_IGNORE="--ignore-fn=$func $VALGRIND_IGNORE" + done + + VALGRIND_CMD="$VALGRIND_BASE $VALGRIND_IGNORE --massif-out-file=${RAM_HEAP_OUT} -- $CLI_CMD" + + $SRV_CMD > /dev/null 2>&1 & + SRV_PID=$! + echo "Server started, PID $SRV_PID" + + $VALGRIND_CMD > /dev/null 2>&1 & + VAL_PID=$! + echo "Valgrind massif started, PID $VAL_PID" + + wait $VAL_PID + echo "Valgrind done, killing server" + kill $SRV_PID + echo "Done" + + if `cat $RAM_HEAP_OUT | grep '???'` >/dev/null 2>&1; then + echo "Warning: Unrecognized symbols in massif output file - does your version of `valgrind` support 32-bit builds?" + fi + + printf "Max heap usage: " + ./scripts/massif_max.pl $RAM_HEAP_OUT + echo "SUCCESS - Heap usage statistics written to: $RAM_HEAP_OUT\n" +} + +baremetal_ram_stack() { + : ${CLI:=./programs/ssl/ssl_client2} + : ${CLI_PARAMS:="dtls=1"} + : ${SRV:=./programs/ssl/ssl_server2} + : ${SRV_PARAMS:="dtls=1 renegotiation=1 auth_mode=required"} + : ${VALGRIND:=valgrind} + : ${VALGRIND_CALLGRIND_PARAMS:="--separate-callers=100"} + + RAM_CALLGRIND_OUT="ram_callgrind__${date}__$NAME" + RAM_STACK_OUT="ram_stack__${date}__$NAME" + + SRV_CMD="$SRV server_addr=127.0.0.1 server_port=4433 debug_level=4 $SRV_PARAMS" + CLI_CMD="$CLI server_addr=127.0.0.1 server_port=4433 $CLI_PARAMS" + + VALGRIND_BASE="$VALGRIND --tool=callgrind $VALGRIND_CALLGRIND_PARAMS" + VALGRIND_CMD="$VALGRIND_BASE --callgrind-out-file=${RAM_CALLGRIND_OUT} $CLI_CMD" + + $SRV_CMD > /dev/null 2>&1 & + SRV_PID=$! + echo "Server started, PID $SRV_PID" + + $VALGRIND_CMD > /dev/null 2>&1 & + VAL_PID=$! + echo "Valgrind callgrind started, PID $VAL_PID" + + wait $VAL_PID + echo "Valgrind done, killing server" + kill $SRV_PID + echo "Done" + + # Extract callgraphs from source files directly + RAM_CALLGRAPH_OUT="" + if [ -x "$(command -v cflow)" ]; then + RAM_CALLGRAPH_OUT="ram_cflow__${date}__$NAME" + cflow library/*.c > $RAM_CALLGRAPH_OUT 2> /dev/null + fi + + # Merge stack usage files + cat library/*.su > ${RAM_STACK_OUT}_unsorted + sort -r -k2 -n ${RAM_STACK_OUT}_unsorted > $RAM_STACK_OUT + rm ${RAM_STACK_OUT}_unsorted + + echo "SUCCESS" + echo "* Stack usage statistics written to $RAM_STACK_OUT" + echo "* Callgrind output written to $RAM_CALLGRIND_OUT" + if [ -n $RAM_CALLGRAPH_OUT ]; then + echo "* Static call graph written to $RAM_CALLGRAPH_OUT" + fi +} + +show_usage() { + echo "Usage: $0 [--rom [--gcc] [--armc5] [--armc6]|--ram [--stack] [--heap]]" +} + +test_build=0 +raw_build=0 + +build_gcc=0 +build_armc5=0 +build_armc6=0 + +measure_heap=0 +measure_stack=0 + +while [ $# -gt 0 ]; do + case "$1" in + --gcc) build_gcc=1;; + --armc5) build_armc5=1;; + --armc6) build_armc6=1;; + --ram) test_build=1;; + --rom) raw_build=1;; + --heap) measure_heap=1;; + --stack) measure_stack=1;; + -*) + echo >&2 "Unknown option: $1" + show_usage + exit 1 + ;; + esac + shift +done + +if [ "$test_build" -eq 0 ] && + [ "$raw_build" -eq 0 ]; then + echo "Need to set either --ram or --rom" + show_usage + exit 1 +fi + +if [ "$test_build" -eq 1 ]; then + + if [ "$measure_heap" -eq 0 ] && + [ "$measure_stack" -eq 0 ]; then + echo "Need to set either --heap or --stack with --ram" + show_usage + exit 1 + fi + + baremetal_ram_build + + if [ "$measure_heap" -eq 1 ]; then + baremetal_ram_heap 0 + baremetal_ram_heap 1 + fi + + if [ "$measure_stack" -eq 1 ]; then + baremetal_ram_stack + fi + +fi + +if [ "$raw_build" -eq 1 ]; then + + if [ "$build_gcc" -eq 0 ] && + [ "$build_armc5" -eq 0 ] && + [ "$build_armc6" -eq 0 ]; then + echo "Need to set either --gcc, --armc5 or --armc6 with --rom" + show_usage + exit 1 + fi + + if [ "$build_gcc" -eq 1 ]; then + baremetal_build_gcc + fi + if [ "$build_armc5" -eq 1 ]; then + baremetal_build_armc5 + fi + if [ "$build_armc6" -eq 1 ]; then + baremetal_build_armc6 + fi +fi diff --git a/scripts/extract_codesize_stats.sh b/scripts/extract_codesize_stats.sh new file mode 100755 index 000000000..33d1c7bb6 --- /dev/null +++ b/scripts/extract_codesize_stats.sh @@ -0,0 +1,123 @@ +#!/bin/sh +# generate_codesize_stats.sh +# +# This file is part of mbed TLS (https://tls.mbed.org) +# +# Copyright (c) 2019, ARM Limited, All Rights Reserved +# +# Purpose +# +# Generate static memory usage statistics for an Mbed TLS build. +# + +set -eu + +if [ -d include/mbedtls ]; then :; else + echo "$0: must be run from root" >&2 + exit 1 +fi + +if grep -i cmake Makefile >/dev/null; then + echo "$0: not compatible with cmake" >&2 + exit 1 +fi + +BUILD_DIR="./library" + +LIBFILES=$( ls $BUILD_DIR/*.a ) +OBJFILES=$( ls $BUILD_DIR/*.o ) + +SUMMARY_ONLY=0 +LIMIT=9999 + +print_usage() { + echo "\nExtract static memory usage statistics for an Mbed TLS build.\n" + echo "Usage: $0 [options]" + echo " --files\tGenerate per-file code-size statistics." + echo " --syms\tGenerate per-symbol code-size statistics." + echo " -l|--limit num\tPrint only the largest 'num' symbols of the given type. (Default: $LIMIT) " + echo " -h|--help\tPrint this help." + echo " -d|--dir=BUILD_DIR\tThe build directory containing the 'library' folder (default: ${BUILD_DIR})" +} + +get_options() { + while [ $# -gt 0 ]; do + case "$1" in + -d|--dir) + shift; BUILD_DIR=$1 + ;; + -h|--help) + print_usage + exit 0 + ;; + --files) + FILE_STATS=1 + ;; + --syms) + SYM_STATS=1 + ;; + -l|--limit) + shift; LIMIT=$1 + ;; + -n|--name) + shift; name=$1 + ;; + -i|--info) + shift; info=$1 + ;; + *) + echo "Unknown argument: $1" + print_usage + exit 1 + ;; + esac + shift + done +} + +FILE_STATS=0 +SYM_STATS=0 +name="unnamed" +info="noinfo" +get_options "$@" + +date=$( date +%Y-%m-%d-%H-%M-%S ) + +report_syms() { + file=$(basename $1) + type=$2 + stat=$(nm --line-numbers --radix=d --size-sort --reverse $1 | + grep " [$3] " | + sort --reverse | + head -n $LIMIT | + awk -v type="$type" -v info="$info" -v name="$name" -v date="$date" -v file="$file" \ + '{ printf( "%10s %42s %12s %20s %8s %6d %s\n", date, name, info, file, type, $1, $3 ); }') + if [ -n "$stat" ]; then + echo "$stat" + fi +} + +# Report static memory usage (RAM and ROM) +if [ $FILE_STATS -eq 1 ]; then + for file_full in $LIBFILES; do + file=$(basename $file_full) + size --radix=10 $file_full | + sort -s -n -k 1,1 | + tail -n +2 | + sed -n '/^[ ]*0/!p' | + awk -v info="$info" -v name="$name" -v date="$date" '{ printf( "%10s %42s %12s %20s %6d %6d %6d\n", date, name, info, $6, $1, $2, $3 ); }' | + awk -v info="$info" -v name="$name" -v date="$date" -v file="$file" '{print $0; sum_text += $5; sum_data += $6; sum_bss += $7} + END { printf( "%10s %42s %12s %20s %6d %6d %6d\n\n", date, name, info, file, sum_text, sum_data, sum_bss ); }' + done +fi + +if [ $SYM_STATS -eq 1 ]; then + SYMTYPES="CODE-tT DATA-dD RODATA-rR BSS-bB" + for symtype in $SYMTYPES; do + type=${symtype%*-*} + specifier=${symtype#*-*} + for file_full in $OBJFILES; do + report_syms "$file_full" $type $specifier + done + done +fi