tl;dr: Bash runs the debug trap one extra time when invoking a function to allow breaking on the function itself rather than its first command. Here's from the source code's execute_function used to invoke a bash function:
/* Run the debug trap here so we can trap at the start of a function's
execution rather than the execution of the body's first command. */
Source diving time
Here is the code that executes debug traps:
int run_debug_trap () {
/* (...) */
trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
I put a breakpoint on that line, trap.c:1081
as of today, and had a look at the backtraces:
First instance
Breakpoint 1, run_debug_trap () at trap.c:1081
1081 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
(gdb) where
#0 run_debug_trap () at trap.c:1081
#1 0x000055555559fd3d in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4056
#2 0x0000555555599fd7 in execute_command_internal (command=0x5555558aae08, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x555555899148) at execute_cmd.c:807
#3 0x00005555555995c1 in execute_command (command=0x5555558aae08) at execute_cmd.c:405
#4 0x0000555555583c9e in reader_loop () at eval.c:180
#5 0x0000555555581794 in main (argc=2, argv=0x7fffffffe4d8, env=0x7fffffffe4f0) at shell.c:792
(gdb) up
#1 0x000055555559fd3d in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4056
4056 result = run_debug_trap ();
(gdb) print *simple_command->words->word
$3 = {word = 0x5555558a5268 "foo", flags = 0}
In other words, this is the simple command foo
. So far so good.
Second instance
Breakpoint 1, run_debug_trap () at trap.c:1081
1081 trap_exit_value = _run_trap_internal (DEBUG_TRAP, "debug trap");
(gdb) where
#0 run_debug_trap () at trap.c:1081
#1 0x00005555555a170a in execute_function (var=0x5555558ab648, words=0x5555558aac28, flags=0, fds_to_close=0x555555899148, async=0, subshell=0) at execute_cmd.c:4787
#2 0x00005555555a1c68 in execute_builtin_or_function (words=0x5555558aac28, builtin=0x0, var=0x5555558ab648, redirects=0x0, fds_to_close=0x555555899148, flags=0) at execute_cmd.c:5030
#3 0x00005555555a0660 in execute_simple_command (simple_command=0x5555558aacc8, pipe_in=-1, pipe_out=-1, async=0, fds_to_close=0x555555899148) at execute_cmd.c:4330
#4 0x0000555555599fd7 in execute_command_internal (command=0x5555558aae08, asynchronous=0, pipe_in=-1, pipe_out=-1, fds_to_close=0x555555899148) at execute_cmd.c:807
#5 0x00005555555995c1 in execute_command (command=0x5555558aae08) at execute_cmd.c:405
#6 0x0000555555583c9e in reader_loop () at eval.c:180
#7 0x0000555555581794 in main (argc=2, argv=0x7fffffffe4d8, env=0x7fffffffe4f0) at shell.c:792
This is more interesting. We're still executing the simple command foo
from before, but it's triggering again! Why though? Let's have a look at the call site, execute_cmd.c:4787:
/* Run the debug trap here so we can trap at the start of a function's
execution rather than the execution of the body's first command. */
showing_function_line = 1;
save_current = currently_executing_command;
result = run_debug_trap ();
In other words, Bash appears to intentionally run the debug trap one additional time for the purpose of breaking on a function rather than its first command.
Third instance
Is unsurprisingly the function's echo
command, so I won't include it.