[PATCH v2 1/5] unwind-libdw: add -kk/--stack-traces=source option
Masatake YAMATO
yamato at redhat.com
Sun Nov 19 05:30:21 UTC 2023
This change adds source code information to stack traces printed with
-k option if strace links to libdw.
An example output:
exit_group(0) = ?
+++ exited with 0 +++
> /usr/lib64/libc.so.6(_exit+0x1d) [0xdb44d] ../sysdeps/unix/sysv/linux/_exit.c:30
> /usr/lib64/libc.so.6(__run_exit_handlers+0x125) [0x40165] /usr/src/debug/glibc-2.37-4.fc38.x86_64/stdlib/exit.c:134
> /usr/lib64/libc.so.6(exit+0x1d) [0x402ed] /usr/src/debug/glibc-2.37-4.fc38.x86_64/stdlib/exit.c:141
> /usr/lib64/libc.so.6(__libc_start_call_main+0x80) [0x27b50] ../sysdeps/nptl/libc_start_call_main.h:74
> /usr/lib64/libc.so.6(__libc_start_main@@GLIBC_2.34+0x8a) [0x27c0a] ../csu/libc-start.c:360
> /usr/bin/ls(_start+0x24) [0x6d54]
This change also adds --stack-traces=symbol option as an alias for the
original -k/--stack-traces options.
NOTE: If the target program is built with clang, -gdwarf-aranges option
must be specified in addition to -g for making -kk option work.
See https://sourceware.org/bugzilla/show_bug.cgi?id=30948 ahout this
limitation.
* NEWS: Mention this.
* doc/strace.1.in: Document this.
* src/defs.h (stack_trace_modes): New enum.
(stack_trace_modes::STACK_TRACE_OFF,STACK_TRACE_ON,
STACK_TRACE_WITH_SRCINFO): New enumerators.
(stack_trace_enabled): Rename this variabel declaration to...
(stack_trace_mode): ... this. The type is also changed from bool to
enum stack_trace_modes.
(unwind_init): Add a bool parameter.
* src/filter_seccomp.c (traced_by_seccomp): Use the new variable name,
stack_trace_mode.
* src/strace.c (stack_trace_enabled): Rename this variabel to...
(stack_trace_mode): ... this.
[ENABLE_STACKTRACE]/[USE_LIBDW] (K_OPT): Add "kk" option.
[ENABLE_STACKTRACE] (usage): Print --stack-traces=symbol options.
[ENABLE_STACKTRACE]/[USE_LIBDW] (usage): Print -kk and
--strack-traces=source options.
[ENABLE_STACKTRACE] (after_successful_attach): Use the new variable
name, stack_trace_mode.
(GETOPT_STACK): New enumerator.
(init::longopts): Let --stack-traces take an option argument. Use
GETOPT_STACK as the val for --stack-traces.
[ENABLE_STACKTRACE] (init): Handle -kk and --stack-traces=source
options.
(init): Pass ture to unwind_init() if -kk or --stack-traces=source is
given.
(print_stopped): Use the new variable
name, stack_trace_mode.
* src/syscall.c (update_personality): Use the new variable
name, stack_trace_mode.
(syscall_entering_trace): Ditto.
(syscall_exiting_trace): Ditto.
* src/unwind.h (unwind_call_action_fn): add parameters
source_filename and source_line as parameters.
(struct unwind_unwinder_t::init): Add a bool parameter.
* src/unwind.c (unwind_init): Add with_srcinfo parameter and
pass it to init method of backend.
(STACK_ENTRY_SYMBOL_WITH_SRCINFO_FMT): New format string for
printing stack trace entries with source code information.
(print_call_cb): Add source_filename and source_line as
parameters. Build stack trace entries with
STACK_ENTRY_SYMBOL_WITH_SRCINFO_FMT if source_filename is given.
(queue_put): Add source_filename and source_line as parameters.
Pass them to sprint_call_or_error().
(queue_put_call): Do the same as queue_put.
(queue_put_error): Pass NULL as source_filename, 0 as source_line to
queue_put().
* src/unwind-libdw.c (struct cache_entry::source_filename,
struct cache_entry::source_line): New members.
(with_srcinfo): New file local variable.
(init): Set with_srcinfo.
(frame_callback): Get source information for pc from
dwfl_module_getsrc() and dwfl_lineinfo(). Pass the source information
to call_action method and fill the source_filename and source_line members
of cache entry.
* src/unwind-libunwind.c (init, print_stack_frame): Adjust the code to
the updated interface declared in unwind.h.
* tests/Makefile.am (check_SCRIPTS): add strace-kk.test.
(check_DATA): strace-kk.expected.
[ENABLE_STACKTRACE]/[USE_LIBDW] (STACKTRACE_TESTS): add
strace-kk.test.
* tests/strace-k.test: Add KOPT_SHORT and KOPT_LONG variables
to make the test case reusable for testing -kk option. Don't
hardcode -k and --stack-traces. Add a new pattern for
testing -kk/--stack-traces=source.
* tests/strace-kk.expected: New file.
* tests/strace-kk.test: New test case.
* tests/options-syntax.test: update expecting output.
Changes in v2:
* fold too long lines,
* withdraw the changes of diagnostics about combining -kk and -c,
* update the error messages in src/strace.c (init::k::STACK_TRACE_ON,
(init::k::GETOPT_STACK),
* use "source" as a specifier to enable "stack traces with source
information" instead of "+source",
* fix a typo about the short option (s/K/k/) in the man page, add
* add comments about description about -k/-kk option.
Signed-off-by: Masatake YAMATO <yamato at redhat.com>
---
NEWS | 2 ++
doc/strace.1.in | 15 ++++++--
src/defs.h | 11 ++++--
src/filter_seccomp.c | 2 +-
src/strace.c | 72 +++++++++++++++++++++++++++++++++------
src/syscall.c | 6 ++--
src/unwind-libdw.c | 26 ++++++++++++--
src/unwind-libunwind.c | 5 +--
src/unwind.c | 49 +++++++++++++++++++++-----
src/unwind.h | 10 ++++--
tests/Makefile.am | 5 +++
tests/options-syntax.test | 2 ++
tests/strace-k.test | 38 ++++++++++++++++++---
tests/strace-kk.expected | 2 ++
tests/strace-kk.test | 13 +++++++
15 files changed, 219 insertions(+), 39 deletions(-)
create mode 100644 tests/strace-kk.expected
create mode 100755 tests/strace-kk.test
diff --git a/NEWS b/NEWS
index a93bf7105..ddedc3bb1 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@ Noteworthy changes in release ?.? (????-??-??)
==============================================
* Improvements
+ * Implemented -kk/--stack-traces=source option.
+ The option requires libdw backend.
Noteworthy changes in release 6.6 (2023-10-31)
==============================================
diff --git a/doc/strace.1.in b/doc/strace.1.in
index 1f4d5f375..f61afc982 100644
--- a/doc/strace.1.in
+++ b/doc/strace.1.in
@@ -38,7 +38,11 @@
strace \- trace system calls and signals
.SH SYNOPSIS
.SY strace
-.if '@ENABLE_STACKTRACE_FALSE@'#' .OP \-ACdffhikqqrtttTvVwxxyyYzZ
+.\" -kk option is available:
+.if '@ENABLE_STACKTRACE_FALSE@'#' .if '@USE_LIBDW_FALSE@'#' .OP \-ACdffhikkqqrtttTvVwxxyyYzZ
+.\" only -k option is available:
+.if '@ENABLE_STACKTRACE_FALSE@'#' .if '@USE_LIBUNWIND_FALSE@'#' .OP \-ACdffhikqqrtttTvVwxxyyYzZ
+.\" no -k option is available:
.if '@ENABLE_STACKTRACE_TRUE@'#' .OP \-ACdffhiqqrtttTvVwxxyyYzZ
.OP \-a column
.OP \-b execve
@@ -996,9 +1000,16 @@ Print the syscall number.
.if '@ENABLE_STACKTRACE_FALSE@'#' .TP
.if '@ENABLE_STACKTRACE_FALSE@'#' .B \-k
.if '@ENABLE_STACKTRACE_FALSE@'#' .TQ
-.if '@ENABLE_STACKTRACE_FALSE@'#' .B \-\-stack\-traces
+.if '@ENABLE_STACKTRACE_FALSE@'#' .B \-\-stack\-traces [= symbol ]
.if '@ENABLE_STACKTRACE_FALSE@'#' Print the execution stack trace of the traced
.if '@ENABLE_STACKTRACE_FALSE@'#' processes after each system call.
+.if '@USE_LIBDW_FALSE@'#' .TP
+.if '@USE_LIBDW_FALSE@'#' .B \-kk
+.if '@USE_LIBDW_FALSE@'#' .TQ
+.if '@USE_LIBDW_FALSE@'#' .B \-\-stack\-traces [= source ]
+.if '@USE_LIBDW_FALSE@'#' Print the execution stack trace and source code inforamation of the traced
+.if '@USE_LIBDW_FALSE@'#' processes after each system call. This option expects the target program is compiled
+.if '@USE_LIBDW_FALSE@'#' with appropriate debug options: "\-g" (gcc), or "\-g \-gdwarf-aranges" (clang).
.TP
.BI "\-o " filename
.TQ
diff --git a/src/defs.h b/src/defs.h
index 6632a21d8..6f1f25680 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -544,11 +544,16 @@ enum xflag_opts {
extern unsigned xflag;
extern bool followfork;
extern bool output_separately;
+enum stack_trace_modes {
+ STACK_TRACE_OFF,
+ STACK_TRACE_ON,
+ STACK_TRACE_WITH_SRCINFO,
+};
# ifdef ENABLE_STACKTRACE
/* if this is true do the stack trace for every system call */
-extern bool stack_trace_enabled;
+extern enum stack_trace_modes stack_trace_mode;
# else
-# define stack_trace_enabled 0
+# define stack_trace_mode STACK_TRACE_OFF
# endif
extern unsigned max_strlen;
extern unsigned os_release;
@@ -1560,7 +1565,7 @@ extern void print_ticks_d(int64_t val, long freq, unsigned int precision);
extern void print_clock_t(uint64_t val);
# ifdef ENABLE_STACKTRACE
-extern void unwind_init(void);
+extern void unwind_init(bool);
extern void unwind_tcb_init(struct tcb *);
extern void unwind_tcb_fin(struct tcb *);
extern void unwind_tcb_print(struct tcb *);
diff --git a/src/filter_seccomp.c b/src/filter_seccomp.c
index 219adc33c..4a2be745a 100644
--- a/src/filter_seccomp.c
+++ b/src/filter_seccomp.c
@@ -257,7 +257,7 @@ traced_by_seccomp(unsigned int scno, unsigned int p)
{
unsigned int always_trace_flags =
TRACE_INDIRECT_SUBCALL | TRACE_SECCOMP_DEFAULT |
- (stack_trace_enabled ? MEMORY_MAPPING_CHANGE : 0) |
+ (stack_trace_mode ? MEMORY_MAPPING_CHANGE : 0) |
(is_number_in_set(DECODE_PID_COMM, decode_pid_set) ?
COMM_CHANGE : 0);
return sysent_vec[p][scno].sys_flags & always_trace_flags ||
diff --git a/src/strace.c b/src/strace.c
index 9aa0eda11..f63adc043 100644
--- a/src/strace.c
+++ b/src/strace.c
@@ -51,7 +51,7 @@ extern char *optarg;
#ifdef ENABLE_STACKTRACE
/* if this is true do the stack trace for every system call */
-bool stack_trace_enabled;
+enum stack_trace_modes stack_trace_mode;
#endif
#define my_tkill(tid, sig) syscall(__NR_tkill, (tid), (sig))
@@ -270,7 +270,11 @@ static void
usage(void)
{
#ifdef ENABLE_STACKTRACE
+# ifdef USE_LIBDW
+# define K_OPT "kk"
+# else
# define K_OPT "k"
+# endif
#else
# define K_OPT ""
#endif
@@ -394,9 +398,15 @@ Output format:\n\
"
#ifdef ENABLE_STACKTRACE
"\
- -k, --stack-traces\n\
+ -k, --stack-traces[=symbol]\n\
obtain stack trace between each syscall\n\
"
+#ifdef USE_LIBDW
+"\
+ -kk, --stack-traces=source\n\
+ obtain stack trace and source info between each syscall\n\
+"
+#endif
#endif
"\
-n, --syscall-number\n\
@@ -944,7 +954,7 @@ after_successful_attach(struct tcb *tcp, const unsigned int flags)
}
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled)
+ if (stack_trace_mode)
unwind_tcb_init(tcp);
#endif
}
@@ -1096,7 +1106,7 @@ droptcb(struct tcb *tcp)
free_tcb_priv_data(tcp);
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled)
+ if (stack_trace_mode)
unwind_tcb_fin(tcp);
#endif
@@ -2276,6 +2286,7 @@ init(int argc, char *argv[])
GETOPT_OUTPUT_SEPARATELY,
GETOPT_PIDNS_TRANSLATION,
GETOPT_SYSCALL_LIMIT,
+ GETOPT_STACK,
GETOPT_TS,
GETOPT_TIPS,
GETOPT_ARGV0,
@@ -2315,7 +2326,7 @@ init(int argc, char *argv[])
{ "instruction-pointer", no_argument, 0, 'i' },
{ "interruptible", required_argument, 0, 'I' },
{ "kill-on-exit", no_argument, 0, GETOPT_KILL_ON_EXIT },
- { "stack-traces", no_argument, 0, 'k' },
+ { "stack-traces" , optional_argument, 0, GETOPT_STACK },
{ "syscall-limit", required_argument, 0, GETOPT_SYSCALL_LIMIT },
{ "syscall-number", no_argument, 0, 'n' },
{ "output", required_argument, 0, 'o' },
@@ -2453,12 +2464,51 @@ init(int argc, char *argv[])
break;
case 'k':
#ifdef ENABLE_STACKTRACE
- stack_trace_enabled = true;
+ switch (stack_trace_mode) {
+ case STACK_TRACE_OFF:
+ stack_trace_mode = STACK_TRACE_ON;
+ break;
+ case STACK_TRACE_ON:
+# ifdef USE_LIBDW
+ stack_trace_mode = STACK_TRACE_WITH_SRCINFO;
+# else
+ error_msg_and_die("Stack traces with "
+ "source line information (-kk/"
+ "--stack-traces=source option) "
+ "are not supported by this "
+ "build of strace");
+# endif /* USE_LIBDW */
+ break;
+ default:
+ error_msg_and_die("Too many -k options");
+ }
+#else
+ error_msg_and_die("Stack traces (-k/--stack-traces "
+ "option) are not supported by this "
+ "build of strace");
+#endif /* ENABLE_STACKTRACE */
+ break;
+ case GETOPT_STACK:
+#ifdef ENABLE_STACKTRACE
+ if (optarg == NULL || strcmp(optarg, "symbol") == 0)
+ stack_trace_mode = STACK_TRACE_ON;
+ else if (strcmp(optarg, "source") == 0) {
+# ifdef USE_LIBDW
+ stack_trace_mode = STACK_TRACE_WITH_SRCINFO;
+# else
+ error_msg_and_die("Stack traces with "
+ "source line information "
+ "(-kk/--stack-traces=source option) "
+ "are not supported by this "
+ "build of strace");
+# endif /* USE_LIBDW */
+ } else
+ error_opt_arg(c, lopt, optarg);
#else
error_msg_and_die("Stack traces (-k/--stack-traces "
"option) are not supported by this "
"build of strace");
-#endif
+#endif /* ENABLE_STACKTRACE */
break;
case GETOPT_KILL_ON_EXIT:
opt_kill_on_exit = true;
@@ -2791,7 +2841,7 @@ init(int argc, char *argv[])
if (iflag)
error_msg("-i/--instruction-pointer has no effect "
"with -c/--summary-only");
- if (stack_trace_enabled)
+ if (stack_trace_mode)
error_msg("-k/--stack-traces has no effect "
"with -c/--summary-only");
if (nflag)
@@ -2847,8 +2897,8 @@ init(int argc, char *argv[])
set_sighandler(SIGCHLD, SIG_DFL, ¶ms_for_tracee.child_sa);
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled)
- unwind_init();
+ if (stack_trace_mode)
+ unwind_init(stack_trace_mode == STACK_TRACE_WITH_SRCINFO);
#endif
/* See if they want to run as another user. */
@@ -3302,7 +3352,7 @@ print_stopped(struct tcb *tcp, const siginfo_t *si, const unsigned int sig)
line_ended();
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled)
+ if (stack_trace_mode)
unwind_tcb_print(tcp);
#endif
}
diff --git a/src/syscall.c b/src/syscall.c
index def95476f..6d9e843fe 100644
--- a/src/syscall.c
+++ b/src/syscall.c
@@ -268,7 +268,7 @@ update_personality(struct tcb *tcp, unsigned int personality)
}
# if defined(ENABLE_STACKTRACE) && !defined(USE_LIBUNWIND)
- if (stack_trace_enabled) {
+ if (stack_trace_mode) {
unwind_tcb_fin(tcp);
unwind_tcb_init(tcp);
}
@@ -662,7 +662,7 @@ syscall_entering_trace(struct tcb *tcp, unsigned int *sig)
}
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled &&
+ if (stack_trace_mode &&
!check_exec_syscall(tcp) &&
tcp_sysent(tcp)->sys_flags & STACKTRACE_CAPTURE_ON_ENTER) {
unwind_tcb_capture(tcp);
@@ -1026,7 +1026,7 @@ syscall_exiting_trace(struct tcb *tcp, struct timespec *ts, int res)
line_ended();
#ifdef ENABLE_STACKTRACE
- if (stack_trace_enabled)
+ if (stack_trace_mode)
unwind_tcb_print(tcp);
#endif
return 0;
diff --git a/src/unwind-libdw.c b/src/unwind-libdw.c
index 8befa6bd9..211982a98 100644
--- a/src/unwind-libdw.c
+++ b/src/unwind-libdw.c
@@ -36,6 +36,9 @@ struct cache_entry {
GElf_Off off;
Dwarf_Addr true_offset;
+ const char *source_filename;
+ int source_line;
+
/* replacement */
unsigned long long last_use;
};
@@ -48,6 +51,7 @@ struct ctx {
static unsigned long long mapping_generation = 1;
static unsigned long long uwcache_clock;
+static bool with_srcinfo;
static void
update_mapping_generation(struct tcb *tcp, void *unused)
@@ -56,8 +60,9 @@ update_mapping_generation(struct tcb *tcp, void *unused)
}
static void
-init(void)
+init(bool with_srcinfo_)
{
+ with_srcinfo = with_srcinfo_;
mmap_notify_register_client(update_mapping_generation, NULL);
}
@@ -184,7 +189,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
if (find_bucket(user_data->ctx, pc, &ce)) {
user_data->call_action(user_data->data,
ce->modname, ce->symname,
- ce->off, ce->true_offset);
+ ce->off, ce->true_offset,
+ ce->source_filename, ce->source_line);
} else {
Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
@@ -195,14 +201,26 @@ frame_callback(Dwfl_Frame *state, void *arg)
const char *symname = NULL;
GElf_Sym sym;
Dwarf_Addr true_offset = pc;
+ const char *source_filename = NULL;
+ int source_line = 0;
modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
NULL, NULL, NULL);
symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
NULL, NULL, NULL);
dwfl_module_relocate_address(mod, &true_offset);
+ if (with_srcinfo) {
+ Dwfl_Line *dwfl_line;
+
+ dwfl_line = dwfl_module_getsrc(mod, pc);
+ if (dwfl_line)
+ source_filename = dwfl_lineinfo(dwfl_line, NULL,
+ &source_line, NULL,
+ NULL, NULL);
+ }
user_data->call_action(user_data->data, modname, symname,
- off, true_offset);
+ off, true_offset,
+ source_filename, source_line);
ce->generation = mapping_generation;
ce->pc = pc;
@@ -210,6 +228,8 @@ frame_callback(Dwfl_Frame *state, void *arg)
ce->symname = symname;
ce->off = off;
ce->true_offset = true_offset;
+ ce->source_filename = source_filename;
+ ce->source_line = source_line;
ce->last_use = uwcache_clock++;
}
}
diff --git a/src/unwind-libunwind.c b/src/unwind-libunwind.c
index 9da084307..ce0ca66fa 100644
--- a/src/unwind-libunwind.c
+++ b/src/unwind-libunwind.c
@@ -14,7 +14,7 @@
static unw_addr_space_t libunwind_as;
static void
-init(void)
+init(bool unused_with_srcinfo)
{
mmap_cache_enable();
@@ -90,7 +90,8 @@ print_stack_frame(struct tcb *tcp,
entry->binary_filename,
*symbol_name,
function_offset,
- true_offset);
+ true_offset,
+ NULL, 0);
return 0;
}
diff --git a/src/unwind.c b/src/unwind.c
index 7f00b5fb5..8f5528628 100644
--- a/src/unwind.c
+++ b/src/unwind.c
@@ -37,10 +37,10 @@ static void queue_print(struct unwind_queue_t *queue);
static const char asprintf_error_str[] = "???";
void
-unwind_init(void)
+unwind_init(bool with_srcinfo)
{
if (unwinder.init)
- unwinder.init();
+ unwinder.init(with_srcinfo);
}
void
@@ -82,6 +82,14 @@ unwind_tcb_fin(struct tcb *tcp)
* /lib64/libc.so.6(__libc_start_main+0xed) [0x7fa2f8a5976d]
* ./a.out() [0x400569]
*/
+#define STACK_ENTRY_SYMBOL_WITH_SRCINFO_FMT(SYM)\
+ " > %s(%s+0x%lx) [0x%lx] %s:%d\n", \
+ binary_filename, \
+ (SYM), \
+ (unsigned long) function_offset, \
+ true_offset, \
+ source_filename, \
+ source_line
#define STACK_ENTRY_SYMBOL_FMT(SYM) \
" > %s(%s+0x%lx) [0x%lx]\n", \
binary_filename, \
@@ -103,7 +111,9 @@ print_call_cb(void *dummy,
const char *binary_filename,
const char *symbol_name,
unwind_function_offset_t function_offset,
- unsigned long true_offset)
+ unsigned long true_offset,
+ const char *source_filename,
+ int source_line)
{
if (symbol_name && (symbol_name[0] != '\0')) {
#ifdef USE_DEMANGLE
@@ -111,7 +121,13 @@ print_call_cb(void *dummy,
cplus_demangle(symbol_name,
DMGL_AUTO | DMGL_PARAMS);
#endif
- tprintf_string(STACK_ENTRY_SYMBOL_FMT(
+ source_filename
+ ? tprintf_string(STACK_ENTRY_SYMBOL_WITH_SRCINFO_FMT(
+#ifdef USE_DEMANGLE
+ demangled_name ? demangled_name :
+#endif
+ symbol_name))
+ : tprintf_string(STACK_ENTRY_SYMBOL_FMT(
#ifdef USE_DEMANGLE
demangled_name ? demangled_name :
#endif
@@ -146,6 +162,8 @@ sprint_call_or_error(const char *binary_filename,
const char *symbol_name,
unwind_function_offset_t function_offset,
unsigned long true_offset,
+ const char *source_filename,
+ int source_line,
const char *error)
{
char *output_line = NULL;
@@ -157,8 +175,15 @@ sprint_call_or_error(const char *binary_filename,
cplus_demangle(symbol_name,
DMGL_AUTO | DMGL_PARAMS);
#endif
- n = asprintf(&output_line,
- STACK_ENTRY_SYMBOL_FMT(
+ n = source_filename
+ ? asprintf(&output_line,
+ STACK_ENTRY_SYMBOL_WITH_SRCINFO_FMT(
+#ifdef USE_DEMANGLE
+ demangled_name ? demangled_name :
+#endif
+ symbol_name))
+ : asprintf(&output_line,
+ STACK_ENTRY_SYMBOL_FMT(
#ifdef USE_DEMANGLE
demangled_name ? demangled_name :
#endif
@@ -193,6 +218,8 @@ queue_put(struct unwind_queue_t *queue,
const char *symbol_name,
unwind_function_offset_t function_offset,
unsigned long true_offset,
+ const char *source_filename,
+ int source_line,
const char *error)
{
struct call_t *call;
@@ -202,6 +229,8 @@ queue_put(struct unwind_queue_t *queue,
symbol_name,
function_offset,
true_offset,
+ source_filename,
+ source_line,
error);
call->next = NULL;
@@ -219,13 +248,17 @@ queue_put_call(void *queue,
const char *binary_filename,
const char *symbol_name,
unwind_function_offset_t function_offset,
- unsigned long true_offset)
+ unsigned long true_offset,
+ const char *source_filename,
+ int source_line)
{
queue_put(queue,
binary_filename,
symbol_name,
function_offset,
true_offset,
+ source_filename,
+ source_line,
NULL);
}
@@ -234,7 +267,7 @@ queue_put_error(void *queue,
const char *error,
unsigned long ip)
{
- queue_put(queue, NULL, NULL, 0, ip, error);
+ queue_put(queue, NULL, NULL, 0, ip, NULL, 0, error);
}
static void
diff --git a/src/unwind.h b/src/unwind.h
index d36b3282d..952917c10 100644
--- a/src/unwind.h
+++ b/src/unwind.h
@@ -23,7 +23,13 @@ typedef void (*unwind_call_action_fn)(void *data,
const char *binary_filename,
const char *symbol_name,
unwind_function_offset_t function_offset,
- unsigned long true_offset);
+ unsigned long true_offset,
+ /* source information:
+ * source_filename can be NULL.
+ * In that case, source_line is never referenced. */
+ const char *source_filename,
+ int source_line
+ );
typedef void (*unwind_error_action_fn)(void *data,
const char *error,
unsigned long true_offset);
@@ -32,7 +38,7 @@ struct unwind_unwinder_t {
const char *name;
/* Initialize the unwinder. */
- void (*init)(void);
+ void (*init)(bool);
/* Make/destroy the context data attached to tcb. */
void * (*tcb_init)(struct tcb *);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d74674b20..5bec13c91 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -490,6 +490,9 @@ include gen_tests.am
if ENABLE_STACKTRACE
STACKTRACE_TESTS = strace-k.test strace-k-p.test
+if USE_LIBDW
+STACKTRACE_TESTS += strace-kk.test
+endif
if USE_DEMANGLE
STACKTRACE_TESTS += strace-k-demangle.test
endif
@@ -693,6 +696,7 @@ check_SCRIPTS = \
strace-k-demangle.test \
strace-k-p.test \
strace-k.test \
+ strace-kk.test \
syntax.sh \
# end of check_SCRIPTS
@@ -749,6 +753,7 @@ check_DATA = \
strace-k-demangle.expected \
strace-k-p.expected \
strace-k.expected \
+ strace-kk.expected \
strace-r.expected \
strace.supp \
strauss_body.exp \
diff --git a/tests/options-syntax.test b/tests/options-syntax.test
index da18662b9..f437cafba 100755
--- a/tests/options-syntax.test
+++ b/tests/options-syntax.test
@@ -418,6 +418,8 @@ check_e_using_grep 'ptrace_setoptions = 0x[[:xdigit:]]+' --debug /
if [ -z "$compiled_with_stacktrace" ]; then
check_e "Stack traces (-k/--stack-traces option) are not supported by this build of strace" -k
check_e "Stack traces (-k/--stack-traces option) are not supported by this build of strace" --stack-traces
+ check_e "Stack traces (-k/--stack-traces option) are not supported by this build of strace" --stack-traces=symbol
+ check_e "Stack traces (-k/--stack-traces option) are not supported by this build of strace" --stack-traces=source
fi
args='-p 2147483647'
diff --git a/tests/strace-k.test b/tests/strace-k.test
index b303df6b4..d8dd68041 100755
--- a/tests/strace-k.test
+++ b/tests/strace-k.test
@@ -12,6 +12,8 @@
. "${srcdir=.}/init.sh"
: "${ATTACH_MODE=0}"
+: "${KOPT_SHORT=-k}"
+: "${KOPT_LONG=--stack-traces}"
# strace -k is implemented using /proc/$pid/maps
[ -f /proc/self/maps ] ||
@@ -43,13 +45,13 @@ if [ "x${ATTACH_MODE}" = "x1" ]; then
fail_ 'set_ptracer_any failed'
done
- run_strace --trace=chdir --stack-trace --attach="$tracee_pid"
+ run_strace --trace=chdir ${KOPT_LONG} --attach="$tracee_pid"
else
- run_strace -e chdir -k $args
+ run_strace -e chdir ${KOPT_SHORT} $args
fi
expected="$srcdir/$NAME.expected"
-awk '
+awk_script_common='
/^[^ ]/ {
if (out != "")
print out
@@ -68,12 +70,40 @@ awk '
}
}
+'
+
+awk_script_symbol='
/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) / && !stop {
sym = gensub(/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) .*$/, "\\1", 1)
out = out " " sym
if (sym == "main")
stop = 1
-}' "$LOG" > "$OUT"
+}
+
+'
+
+awk_script_source='
+/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) \[0x[a-f0-9]+\] ([^:]+):([0-9]+)$/ && !stop {
+ sym = gensub(/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) .*$/, "\\1", 1)
+ if (sym == "main" || sym ~ /f[0-9]/) {
+ file = gensub(/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) \[0x[a-f0-9]+\] ([^:]+):([0-9]+)$/, "\\2", 1)
+ line = gensub(/^ >[^(]+\(([^+]+)\+0x[a-f0-9]+\) \[0x[a-f0-9]+\] ([^:]+):([0-9]+)$/, "\\3", 1)
+ sub(".*/", "", file)
+ out = out " " sym "<" file ":" line ">"
+ if (sym == "main")
+ stop = 1
+ }
+}
+
+'
+
+if [ "${KOPT_LONG}" = "--stack-traces" ]; then
+ awk_script="${awk_script_common}${awk_script_symbol}"
+else
+ awk_script="${awk_script_common}${awk_script_source}"
+fi
+
+awk "${awk_script}" "$LOG" > "$OUT"
LC_ALL=C grep -E -x -f "$expected" < "$OUT" > /dev/null || {
cat >&2 <<__EOF__
diff --git a/tests/strace-kk.expected b/tests/strace-kk.expected
new file mode 100644
index 000000000..f070db89f
--- /dev/null
+++ b/tests/strace-kk.expected
@@ -0,0 +1,2 @@
+chdir f3<stack-fcall-3.c:18> f2<stack-fcall-2.c:15> f1<stack-fcall-1.c:15> f0<stack-fcall-0.c:15> main<stack-fcall.c:25>
+SIGURG f3<stack-fcall-3.c:21> f2<stack-fcall-2.c:15> f1<stack-fcall-1.c:15> f0<stack-fcall-0.c:15> main<stack-fcall.c:25>
diff --git a/tests/strace-kk.test b/tests/strace-kk.test
new file mode 100755
index 000000000..032a34992
--- /dev/null
+++ b/tests/strace-kk.test
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# Ensure that strace -kk works.
+#
+# Copyright (c) 2023 The strace developers.
+# All rights reserved.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+KOPT_SHORT=-kk
+KOPT_LONG=--stack-traces=source
+
+. "${srcdir=.}"/strace-k.test
--
2.41.0
More information about the Strace-devel
mailing list