blob: 9d96bcaa09397e3d77e7cff0abda9ea52ea60279 [file] [log] [blame]
Chris Kay197b1022023-08-16 21:31:41 +01001#!/usr/bin/env bash
2
3#
4# Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
5#
6# SPDX-License-Identifier: BSD-3-Clause
7#
8
9# Dump the current call stack.
10#
11# This function takes no arguments, and prints the call stack of the script at
12# the point at which it was called.
13dump_stack() {(
14 set +x
15
16 for ((i = 1; i < ${#FUNCNAME[@]}; i++)); do
17 local function="${FUNCNAME[$((i + 1))]:-<unknown>}"
18 local line="${BASH_LINENO[$i]}"
19 local source="${BASH_SOURCE[$((i + 1))]:-<unknown>}"
20
21 echo -e "[$i]: ${source}:${line} (${function})"
22 done
23)}
24
25# Dump the process tree.
26#
27# This function takes no arguments, and prints the process tree of the current
28# process. This can be useful for, for example, determining the arguments that
29# the script has been called with.
30dump_process_tree() {
31 ps --forest --no-headers --format command
32}
33
34# Dump the complete program state.
35#
36# This function takes no arguments, and combines the output of the `dump_stack`
37# and `dump_process_tree` functions.
38dump() {(
39 set +x
40
41 echo "Process tree:"
42 echo
43
44 dump_process_tree | while IFS= read -r line; do
45 echo " ${line}"
46 done
47
48 echo
49 echo "Call stack:"
50 echo
51
52 dump_stack | while read -r line; do
53 echo " ${line}"
54 done
55)}
56
57# Generate an error backtrace.
58#
59# This function dumps the backtrace at the point at which the function is
60# called, with additional information about the command that failed.
61#
62# This is best used as a trap handler (e.g. `trap backtrace ERR`) rather than by
63# being called directly. If you want to explicitly dump the script state, prefer
64# to use the `dump` function instead.
65backtrace() {
66 local error=$?
67 local command=${BASH_COMMAND}
68
69 (
70 set +x
71
72 echo "" >&2
73 echo "ERROR: Command at ${BASH_SOURCE[1]:-<unknown>}:${BASH_LINENO[0]} exited with error ${error}:" >&2
74 echo "ERROR:" >&2
75
76 echo "${command}" | while IFS= read -r line; do
77 echo "ERROR: ${line}" >&2
78 done
79
80 echo "ERROR:" >&2
81
82 dump | while IFS= read -r line; do
83 echo "ERROR: ${line}" >&2
84 done
85 )
86}