summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-01 14:53:58 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2025-03-01 17:25:04 -0700
commit6fedfe71cfab86aecf4168ecf35961bf88ce0438 (patch)
tree0c1d961f46881a8fb1bf46b23fdb2c927624309a
parent902a7661cfed71b1f50aa95bac9345883cb435cc (diff)
lint-bin: (dry-run) lint that list of functions matches stack.c.gen
-rwxr-xr-xbuild-aux/lint-bin40
-rwxr-xr-xbuild-aux/stack.c.gen13
2 files changed, 52 insertions, 1 deletions
diff --git a/build-aux/lint-bin b/build-aux/lint-bin
index ffc2a12..0b955de 100755
--- a/build-aux/lint-bin
+++ b/build-aux/lint-bin
@@ -18,6 +18,15 @@ shopt -s extglob
# Textual info:
# - ${elf%.elf}.dis : `objdump --section-headers ${elf}; objdump --disassemble ${elf}; picotool coprodis --quiet ${elf}`
# - ${elf}.map : `ld --print-map` info
+# - ${elf%.elf}_stack.c : `stack.c.gen`
+
+RED=$(tput setaf 1)
+RESET=$(tput sgr0)
+
+err() {
+ printf "${RED}%s${RESET}: %s\n" "$1" "$2" >&2
+ #r=1
+}
# Input is `ld --print-map` format.
#
@@ -27,6 +36,14 @@ objdump_globals() {
sed -E -n '/^ \.t?(data|bss)\./{ / 0x/{ p; D; }; N; s/\n/ /; p; }' <"$1"
}
+readelf_funcs() {
+ local in_elffile
+ in_elffile=$1
+
+ readelf --syms --wide -- "$in_elffile" |
+ awk '$4 == "FUNC" { print $8 }'
+}
+
lint_globals() {
local in_mapfile
in_mapfile=$1
@@ -72,14 +89,37 @@ lint_globals() {
} | column -t
}
+lint_stack() {
+ local in_elffile
+ in_elffile=$1
+
+ IFS=''
+ while read -r line; do
+ func=${line#$'\t'}
+ if [[ $line == $'\t'* ]]; then
+ err "$in_elffile" "function in binary but not _stack.c: ${func}"
+ else
+ err "$in_elffile" "function in _stack.c but not binary: ${func}"
+ fi
+ done < <(
+ comm -3 \
+ <(sed -En 's/^included: (.*:)?//p' "${in_elffile%.elf}_stack.c" | sort -u) \
+ <(readelf_funcs "$in_elffile" | sed 's/\.part\.[0-9]*$//' | sort -u))
+}
+
main() {
+ r=0
+
local elf
for elf in "$@"; do
{
echo 'Global variables:'
lint_globals "${elf}.map" | sed 's/^/ /'
} > "${elf%.elf}.lint.globals"
+ lint_stack "$elf" &> "${elf%.elf}.lint.stack"
done
+
+ return $r
}
main "$@"
diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen
index f851afe..2965c00 100755
--- a/build-aux/stack.c.gen
+++ b/build-aux/stack.c.gen
@@ -142,6 +142,8 @@ class AnalyzeResult(typing.NamedTuple):
missing: set[str]
dynamic: set[str]
+ included_funcs: set[str]
+
class Application(typing.Protocol):
def extra_nodes(self) -> typing.Collection[Node]: ...
@@ -246,6 +248,7 @@ def analyze(
missing: set[str] = set()
dynamic: set[str] = set()
+ included_funcs: set[str] = set()
dbg = False
@@ -288,6 +291,7 @@ def analyze(
print(f"//dbg: {funcname}\t{node.nstatic}")
if node.usage_kind == "dynamic" or node.ndynamic > 0:
dynamic.add(app.location_xform(funcname))
+ included_funcs.add(funcname)
return node.nstatic + max(
[
0,
@@ -312,7 +316,9 @@ def analyze(
nsum += cnt * n
groups[grp_name] = AnalyzeResultGroup(rows=rows, nmax=nmax, nsum=nsum)
- return AnalyzeResult(groups=groups, missing=missing, dynamic=dynamic)
+ return AnalyzeResult(
+ groups=groups, missing=missing, dynamic=dynamic, included_funcs=included_funcs
+ )
################################################################################
@@ -1094,6 +1100,11 @@ def main(
print(f"warning: dynamic-stack-usage: {funcname}")
print("*/")
+ print("")
+ print("/*")
+ for funcname in sorted(result.included_funcs):
+ print(f"included: {funcname}")
+ print("*/")
if __name__ == "__main__":