From 280cb1f706e3f2df36f22af0b3c8429e8edf897d Mon Sep 17 00:00:00 2001 From: Thierry Laurion Date: Sun, 16 Mar 2025 13:37:37 -0400 Subject: [PATCH] functions: Improve TRACE_FUNC and DEBUG_STACK: provide full call stack traces in output Signed-off-by: Thierry Laurion --- initrd/etc/functions | 58 ++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/initrd/etc/functions b/initrd/etc/functions index 61fb34fe..12ea4450 100644 --- a/initrd/etc/functions +++ b/initrd/etc/functions @@ -512,25 +512,53 @@ DO_WITH_DEBUG() { return "$exit_status" } -# Trace the current script and function. +# TRACE_FUNC outputs the function call stack in a readable format. +# It helps debug the execution path leading to the current function. +# +# The format of the output is: +# main(/path/to/script:line) -> function1(/path/to/file:line) -> function2(/path/to/file:line) +# +# Usage: +# Call TRACE_FUNC within any function to print the call hierarchy. TRACE_FUNC() { - # Index [1] for BASH_SOURCE and FUNCNAME give us the caller location. - # FUNCNAME is 'main' if called from a script outside any function. - # BASH_LINENO is offset by 1, it provides the line that the - # corresponding FUNCNAME was _called from_, so BASH_LINENO[0] is the - # location of the caller. - TRACE "${BASH_SOURCE[1]}(${BASH_LINENO[0]}): ${FUNCNAME[1]}" + local i stack_trace="" + + # Traverse the call stack from the earliest caller to the direct caller of TRACE_FUNC + for ((i=${#FUNCNAME[@]}-1; i>1; i--)); do + stack_trace+="${FUNCNAME[i]}(${BASH_SOURCE[i]}:${BASH_LINENO[i-1]}) -> " + done + + # Append the direct caller (without extra " -> " at the end) + stack_trace+="${FUNCNAME[1]}(${BASH_SOURCE[1]}:${BASH_LINENO[0]})" + + # Print the final trace output + TRACE "${stack_trace}" } -# Show the entire current call stack in debug output - useful if a catastrophic -# error or something very unexpected occurs, like totally invalid parameters. +# DEBUG_STACK prints the entire call stack for debugging purposes. +# This function provides more detailed output than TRACE_FUNC, which is useful +# for diagnosing errors, tracking function calls, or understanding unexpected behavior. +# +# The output format: +# call stack: (N frames) +# - 0 - /path/to/file(line): function_name +# - 1 - /path/to/file(line): function_name +# +# Usage: +# Call DEBUG_STACK anywhere to display the full stack trace. DEBUG_STACK() { - local FRAMES - FRAMES="${#FUNCNAME[@]}" - DEBUG "call stack: ($((FRAMES - 1)) frames)" - # Don't print DEBUG_STACK itself, start from 1 - for i in $(seq 1 "$((FRAMES - 1))"); do - DEBUG "- $((i - 1)) - ${BASH_SOURCE[$i]}(${BASH_LINENO[$((i - 1))]}): ${FUNCNAME[$i]}" + local SKIP_FIRST=0 + + # If TRACE_FUNC called DEBUG_STACK, remove it from the stack to avoid redundancy. + [[ "${FUNCNAME[1]}" == "TRACE_FUNC" ]] && SKIP_FIRST=1 + + # Get the total number of stack frames + local FRAMES="${#FUNCNAME[@]}" + DEBUG "call stack: ($((FRAMES - 1 - SKIP_FIRST)) frames)" + + # Iterate through the stack and print each function call with file and line number + for i in $(seq $((1 + SKIP_FIRST)) "$((FRAMES - 1))"); do + DEBUG "- $((i - 1 - SKIP_FIRST)) - ${BASH_SOURCE[$i]}(${BASH_LINENO[$((i - 1))]}): ${FUNCNAME[$i]}" done }