Skip to content

Commit

Permalink
perf debug: Add function symbols to dump_stack
Browse files Browse the repository at this point in the history
Symbolize stack traces by creating a live machine. Add this
functionality to dump_stack and switch dump_stack users to use
it. Switch TUI to use it. Add stack traces to the child test function
which can be useful to diagnose blocked code.

Example output:
```
$ perf test -vv PERF_RECORD_
...
  7: PERF_RECORD_* events & perf_sample fields:
  7: PERF_RECORD_* events & perf_sample fields                       : Running (1 active)
^C
Signal (2) while running tests.
Terminating tests with the same signal
Internal test harness failure. Completing any started tests:
:  7: PERF_RECORD_* events & perf_sample fields:

---- unexpected signal (2) ----
    #0 0x55788c6210a3 in child_test_sig_handler builtin-test.c:0
    #1 0x7fc12fe49df0 in __restore_rt libc_sigaction.c:0
    #2 0x7fc12fe99687 in __internal_syscall_cancel cancellation.c:64
    #3 0x7fc12fee5f7a in clock_nanosleep@GLIBC_2.2.5 clock_nanosleep.c:72
    #4 0x7fc12fef1393 in __nanosleep nanosleep.c:26
    #5 0x7fc12ff02d68 in __sleep sleep.c:55
    #6 0x55788c63196b in test__PERF_RECORD perf-record.c:0
    #7 0x55788c620fb0 in run_test_child builtin-test.c:0
    #8 0x55788c5bd18d in start_command run-command.c:127
    #9 0x55788c621ef3 in __cmd_test builtin-test.c:0
    #10 0x55788c6225bf in cmd_test ??:0
    #11 0x55788c5afbd0 in run_builtin perf.c:0
    #12 0x55788c5afeeb in handle_internal_command perf.c:0
    #13 0x55788c52b383 in main ??:0
    #14 0x7fc12fe33ca8 in __libc_start_call_main libc_start_call_main.h:74
    #15 0x7fc12fe33d65 in __libc_start_main@@GLIBC_2.34 libc-start.c:128
    #16 0x55788c52b9d1 in _start ??:0

---- unexpected signal (2) ----
    #0 0x55788c6210a3 in child_test_sig_handler builtin-test.c:0
    #1 0x7fc12fe49df0 in __restore_rt libc_sigaction.c:0
    #2 0x7fc12fea3a14 in pthread_sigmask@GLIBC_2.2.5 pthread_sigmask.c:45
    #3 0x7fc12fe49fd9 in __GI___sigprocmask sigprocmask.c:26
    #4 0x7fc12ff2601b in __longjmp_chk longjmp.c:36
    #5 0x55788c6210c0 in print_test_result.isra.0 builtin-test.c:0
    #6 0x7fc12fe49df0 in __restore_rt libc_sigaction.c:0
    #7 0x7fc12fe99687 in __internal_syscall_cancel cancellation.c:64
    #8 0x7fc12fee5f7a in clock_nanosleep@GLIBC_2.2.5 clock_nanosleep.c:72
    #9 0x7fc12fef1393 in __nanosleep nanosleep.c:26
    #10 0x7fc12ff02d68 in __sleep sleep.c:55
    #11 0x55788c63196b in test__PERF_RECORD perf-record.c:0
    #12 0x55788c620fb0 in run_test_child builtin-test.c:0
    #13 0x55788c5bd18d in start_command run-command.c:127
    #14 0x55788c621ef3 in __cmd_test builtin-test.c:0
    #15 0x55788c6225bf in cmd_test ??:0
    #16 0x55788c5afbd0 in run_builtin perf.c:0
    #17 0x55788c5afeeb in handle_internal_command perf.c:0
    #18 0x55788c52b383 in main ??:0
    #19 0x7fc12fe33ca8 in __libc_start_call_main libc_start_call_main.h:74
    #20 0x7fc12fe33d65 in __libc_start_main@@GLIBC_2.34 libc-start.c:128
    #21 0x55788c52b9d1 in _start ??:0
  7: PERF_RECORD_* events & perf_sample fields                       : Skip (permissions)
```

Signed-off-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250624210500.2121303-1-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
  • Loading branch information
Ian Rogers authored and Namhyung Kim committed Jun 25, 2025
1 parent 51f4c00 commit 9c9f4a2
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 13 deletions.
15 changes: 14 additions & 1 deletion tools/perf/tests/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*/
#include <fcntl.h>
#include <errno.h>
#ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h>
#endif
#include <poll.h>
#include <unistd.h>
#include <setjmp.h>
Expand Down Expand Up @@ -231,6 +234,16 @@ static jmp_buf run_test_jmp_buf;

static void child_test_sig_handler(int sig)
{
#ifdef HAVE_BACKTRACE_SUPPORT
void *stackdump[32];
size_t stackdump_size;
#endif

fprintf(stderr, "\n---- unexpected signal (%d) ----\n", sig);
#ifdef HAVE_BACKTRACE_SUPPORT
stackdump_size = backtrace(stackdump, ARRAY_SIZE(stackdump));
__dump_stack(stderr, stackdump, stackdump_size);
#endif
siglongjmp(run_test_jmp_buf, sig);
}

Expand All @@ -244,7 +257,7 @@ static int run_test_child(struct child_process *process)

err = sigsetjmp(run_test_jmp_buf, 1);
if (err) {
fprintf(stderr, "\n---- unexpected signal (%d) ----\n", err);
/* Received signal. */
err = err > 0 ? -err : -1;
goto err_out;
}
Expand Down
2 changes: 1 addition & 1 deletion tools/perf/ui/tui/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static void ui__signal_backtrace(int sig)

printf("-------- backtrace --------\n");
size = backtrace(stackdump, ARRAY_SIZE(stackdump));
backtrace_symbols_fd(stackdump, size, STDOUT_FILENO);
__dump_stack(stdout, stackdump, size);

exit(0);
}
Expand Down
68 changes: 57 additions & 11 deletions tools/perf/util/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@
#ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h>
#endif
#include "addr_location.h"
#include "color.h"
#include "event.h"
#include "debug.h"
#include "event.h"
#include "machine.h"
#include "map.h"
#include "print_binary.h"
#include "srcline.h"
#include "symbol.h"
#include "synthetic-events.h"
#include "target.h"
#include "thread.h"
#include "trace-event.h"
#include "ui/helpline.h"
#include "ui/ui.h"
Expand Down Expand Up @@ -298,21 +305,60 @@ void perf_debug_setup(void)
libapi_set_print(pr_warning_wrapper, pr_warning_wrapper, pr_debug_wrapper);
}

void __dump_stack(FILE *file, void **stackdump, size_t stackdump_size)
{
/* TODO: async safety. printf, malloc, etc. aren't safe inside a signal handler. */
pid_t pid = getpid();
struct machine *machine = machine__new_live(/*kernel_maps=*/false, pid);
struct thread *thread = NULL;

if (machine)
thread = machine__find_thread(machine, pid, pid);

#ifdef HAVE_BACKTRACE_SUPPORT
if (!machine || !thread) {
/*
* Backtrace functions are async signal safe. Fall back on them
* if machine/thread creation fails.
*/
backtrace_symbols_fd(stackdump, stackdump_size, fileno(file));
machine__delete(machine);
return;
}
#endif

for (size_t i = 0; i < stackdump_size; i++) {
struct addr_location al;
u64 addr = (u64)(uintptr_t)stackdump[i];
bool printed = false;

addr_location__init(&al);
if (thread && thread__find_map(thread, PERF_RECORD_MISC_USER, addr, &al)) {
al.sym = map__find_symbol(al.map, al.addr);
if (al.sym) {
fprintf(file, " #%zd %p in %s ", i, stackdump[i], al.sym->name);
printed = true;
}
}
if (!printed)
fprintf(file, " #%zd %p ", i, stackdump[i]);

map__fprintf_srcline(al.map, al.addr, "", file);
fprintf(file, "\n");
addr_location__exit(&al);
}
thread__put(thread);
machine__delete(machine);
}

/* Obtain a backtrace and print it to stdout. */
#ifdef HAVE_BACKTRACE_SUPPORT
void dump_stack(void)
{
void *array[16];
size_t size = backtrace(array, ARRAY_SIZE(array));
char **strings = backtrace_symbols(array, size);
size_t i;

printf("Obtained %zd stack frames.\n", size);

for (i = 0; i < size; i++)
printf("%s\n", strings[i]);
void *stackdump[32];
size_t size = backtrace(stackdump, ARRAY_SIZE(stackdump));

free(strings);
__dump_stack(stdout, stackdump, size);
}
#else
void dump_stack(void) {}
Expand Down
1 change: 1 addition & 0 deletions tools/perf/util/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ void debug_set_display_time(bool set);
void perf_debug_setup(void);
int perf_quiet_option(void);

void __dump_stack(FILE *file, void **stackdump, size_t stackdump_size);
void dump_stack(void);
void sighandler_dump_stack(int sig);

Expand Down

0 comments on commit 9c9f4a2

Please sign in to comment.