#!/usr/bin/env bash # build-aux/lint-bin - Lint final binary images # # Copyright (C) 2025 Luke T. Shumaker # SPDX-License-Identifier: AGPL-3.0-or-later set -euE -o pipefail shopt -s extglob # There are several exisi files we can use: # # Binaries: # - ${elf} : firmware image with debug symbols and relocationd data # - ${elf%.elf}.bin : raw firmware image # - ${elf%.elf}.hex : .bin as Intel HEX # - ${elf%.elf}.uf2 : .bin as USB Flashing Format (UF2) # # Textual info: # - ${elf%.elf}.dis : `objdump --section-headers ${elf}; objdump --disassemble ${elf}; picotool coprodis --quiet ${elf}` # - ${elf}.map : `ld --print-map` info # Input is `ld --print-map` format. # # Output is a series of lines in the format "symbol location size # source". Whitespace may seem silly. objdump_globals() { sed -E -n '/^ \.t?(data|bss)\./{ / 0x/{ p; D; }; N; s/\n/ /; p; }' <"$1" } lint_globals() { local in_mapfile in_mapfile=$1 local rel_base rel_base=${in_mapfile#build/*/} rel_base=${rel_base%/*} local topdir topdir=$PWD { echo 'Source Symbol Size' objdump_globals "$in_mapfile" | { cd "$rel_base" total=0 while read -r symbol addr size source; do if (( addr == 0 )); then continue fi case "$source" in /*) # libg.a(whatever.o) -> libg.a source="${source%(*)}" # resolve `..` components source="$(realpath --canonicalize-missing --no-symlinks -- "$source")" ;; CMakeFiles/*.dir/*.@(obj|o)) # CMakeFiles/sbc_harnes_objs.dir/... source="${source#CMakeFiles/*.dir/}" source="${source%.@(obj|o)}" source="${source//__/..}" source="$(realpath --canonicalize-missing --no-symlinks --relative-to="$topdir" -- "$source")" ;; esac printf '%s %s 0x%04x\n' "$source" "$symbol" "$size" total=$((total + size)) done printf '~ Total 0x%04x\n' "$total" } | LC_COLLATE=C sort } | column -t } main() { local elf for elf in "$@"; do { echo 'Global variables:' lint_globals "${elf}.map" | sed 's/^/ /' } > "${elf%.elf}.lint.globals" done } main "$@"