Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

retsnoop: make func call trace and call stack modes independent #69

Merged
merged 1 commit into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions src/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ static const struct argp_option opts[] = {

/* Running mode configuration */
{ .flags = OPTION_DOC, "RUNMODE\n=========================" },
{ "call-stack", 'E', NULL, 0, "Capture and emit call stacks (default mode)" },
{ "trace", 'T', NULL, 0, "Capture and emit function call traces" },
{ "capture-args", 'A', NULL, 0, "Capture and emit function arguments" },
{ "lbr", 'B', "SPEC", OPTION_ARG_OPTIONAL,
Expand Down Expand Up @@ -113,7 +114,8 @@ static const struct argp_option opts[] = {
"Skip tracing processes with given name" },
{ "longer", 'L', "MS", 0,
"Only emit stacks that took at least a given amount of milliseconds" },
{ "success-stacks", 'S', NULL, 0, "Emit any stack, successful or not" },
{ "success-stacks", 'S', "VALUE", OPTION_ARG_OPTIONAL,
"Specify whether emitting non-erroring (successful) call stacks is allowed" },
{ "allow-errors", 'x', "ERROR", 0, "Record stacks only with specified errors" },
{ "deny-errors", 'X', "ERROR", 0, "Ignore stacks that have specified errors" },

Expand Down Expand Up @@ -393,7 +395,7 @@ static enum debug_feat parse_config_arg(const char *arg)

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
int i, j, err;
int i, j, err, val;

switch (key) {
case 'h':
Expand All @@ -417,6 +419,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
else if (!env.debug_extra)
env.debug_extra = true;
break;
case 'E':
env.emit_call_stack = true;
break;
case 'T':
env.emit_func_trace = true;
break;
Expand Down Expand Up @@ -537,6 +542,11 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
return err;
break;
case 'x':
if (env.emit_success_stacks > 0) {
elog("Can't specify -S/-Sy and -x arguments at the same time!\n");
return -EINVAL;
}
env.emit_success_stacks = -1; /* force failing stacks only */
err = str_to_err(arg);
if (err < 0)
return err;
Expand All @@ -562,7 +572,21 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
err_mask_set(env.deny_error_mask, err);
break;
case 'S':
env.emit_success_stacks = true;
if (arg && strcasecmp(arg, "y") == 0) {
val = +1;
} else if (arg && strcasecmp(arg, "n") == 0) {
val = -1;
} else if (!arg) {
val = +1;
} else {
elog("Unrecognized -S%s argument, only -S, -Sy, or -Sn are supported!\n", arg);
return -EINVAL;
}
if (env.emit_success_stacks != 0 && env.emit_success_stacks != val) {
elog("Conflicting combination of -S/-Sn/-Sy and -x arguments specified!\n");
return -EINVAL;
}
env.emit_success_stacks = val;
break;
case 'M':
if (env.attach_mode != ATTACH_DEFAULT) {
Expand Down
20 changes: 16 additions & 4 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,26 @@ enum debug_feat {
};

struct env {
/* two main modes of operation; if only emit_func_trace is specified,
* we default to capturing all (including non-erroring) sessions
*/
bool emit_call_stack;
bool emit_func_trace;

bool capture_args;
bool use_lbr;

bool show_version;
bool show_config_help;
bool verbose;
bool debug;
bool debug_extra;
bool dry_run;
bool emit_success_stacks;
bool emit_func_trace;
bool capture_args;
enum attach_mode attach_mode;
enum debug_feat debug_feats;
bool use_lbr;
long lbr_flags;
int lbr_max_cnt;

const char *vmlinux_path;
int pid;
int longer_than_ms;
Expand Down Expand Up @@ -105,6 +111,12 @@ struct env {
int allow_comm_cnt;
int deny_comm_cnt;

/* default 0 will depend on allow_call_stack and allow_func_trace settings;
* +1 forces success stacks capture;
* -1 forces unsuccessful stacks only capture;
*/
int emit_success_stacks;

int allow_error_cnt;
bool has_error_filter;
uint64_t allow_error_mask[(MAX_ERRNO + 1) / 64];
Expand Down
41 changes: 23 additions & 18 deletions src/logic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1148,23 +1148,6 @@ static int handle_session_end(struct ctx *dctx, struct session *sess, const stru
s->depth, s->max_depth, s->saved_depth, s->saved_max_depth);
}

fstack_n = filter_fstack(dctx, fstack, s);
if (fstack_n < 0) {
fprintf(stderr, "FAILURE DURING FILTERING FUNCTION STACK!!! %d\n", fstack_n);
ret = -EINVAL;
goto out_purge;
}
kstack_n = filter_kstack(dctx, kstack, s);
if (kstack_n < 0) {
fprintf(stderr, "FAILURE DURING FILTERING KERNEL STACK!!! %d\n", kstack_n);
ret = -EINVAL;
goto out_purge;
}
if (env.debug) {
printf("FSTACK (%d items):\n", fstack_n);
printf("KSTACK (%d items out of original %ld):\n", kstack_n, s->kstack_sz / 8);
}

ts_to_str(ktime_to_ts(sess->start_ts), ts1, sizeof(ts1));
ts_to_str(ktime_to_ts(r->emit_ts), ts2, sizeof(ts2));
printf("%s -> %s TID/PID %d/%d (%s/%s):\n", ts1, ts2, sess->pid, sess->tgid,
Expand All @@ -1183,6 +1166,26 @@ static int handle_session_end(struct ctx *dctx, struct session *sess, const stru
print_ft_items(dctx, &stack_items1);
}

if (!env.emit_call_stack && !env.use_lbr)
goto skip_call_stack;

fstack_n = filter_fstack(dctx, fstack, s);
if (fstack_n < 0) {
fprintf(stderr, "FAILURE DURING FILTERING FUNCTION STACK!!! %d\n", fstack_n);
ret = -EINVAL;
goto out_purge;
}
kstack_n = filter_kstack(dctx, kstack, s);
if (kstack_n < 0) {
fprintf(stderr, "FAILURE DURING FILTERING KERNEL STACK!!! %d\n", kstack_n);
ret = -EINVAL;
goto out_purge;
}
if (env.debug) {
printf("FSTACK (%d items):\n", fstack_n);
printf("KSTACK (%d items out of original %ld):\n", kstack_n, s->kstack_sz / 8);
}

/* Determine address range of deepest nested function */
if (fstack_n > 0) {
const struct fstack_item *fitem = &fstack[fstack_n - 1];
Expand All @@ -1204,8 +1207,10 @@ static int handle_session_end(struct ctx *dctx, struct session *sess, const stru
}

/* Emit combined fstack/kstack + errors stack trace */
output_call_stack(dctx, sess, fstack, fstack_n, kstack, kstack_n);
if (env.emit_call_stack)
output_call_stack(dctx, sess, fstack, fstack_n, kstack, kstack_n);

skip_call_stack:
if (r->dropped_records) {
printf("WARNING! Sample data incomplete! %d record%s dropped. Consider increasing --ringbuf-map-size.\n",
r->dropped_records, r->dropped_records == 1 ? "" : "s");
Expand Down
6 changes: 3 additions & 3 deletions src/retsnoop.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,12 @@ struct {

const volatile bool verbose = false;
const volatile bool extra_verbose = false;
const volatile bool use_lbr = true;
const volatile int targ_tgid = -1;
const volatile bool emit_success_stacks = false;
const volatile bool emit_call_stack = true;
const volatile bool emit_func_trace = true;
const volatile bool emit_success_stacks = false;
const volatile bool capture_args = true;
const volatile bool capture_raw_ptrs = true;
const volatile bool use_lbr = true;
const volatile bool use_kprobes = true;

const volatile int args_max_total_args_sz;
Expand Down
13 changes: 11 additions & 2 deletions src/retsnoop.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,15 @@ int main(int argc, char **argv, char **envp)
goto cleanup_silent;
}
#endif
if (!env.emit_func_trace)
env.emit_call_stack = true;
/* default setting for success stacks, resolve based on call stack vs func trace modes */
if (env.emit_success_stacks == 0) {
if (env.emit_call_stack)
env.emit_success_stacks = -1;
else
env.emit_success_stacks = +1;
}

/* Open BPF skeleton */
env.ctx.skel = skel = retsnoop_bpf__open();
Expand Down Expand Up @@ -384,8 +393,7 @@ int main(int argc, char **argv, char **envp)
/* turn on extra bpf_printk()'s on BPF side */
skel->rodata->verbose = env.debug_feats & DEBUG_BPF;
skel->rodata->extra_verbose = (env.debug_feats & DEBUG_BPF) && env.debug_extra;
skel->rodata->targ_tgid = env.pid;
skel->rodata->emit_success_stacks = env.emit_success_stacks;
skel->rodata->emit_success_stacks = env.emit_success_stacks > 0;
skel->rodata->duration_ns = env.longer_than_ms * 1000000ULL;
skel->rodata->use_kprobes = env.attach_mode != ATTACH_FENTRY;
memset(skel->rodata->spaces, ' ', sizeof(skel->rodata->spaces) - 1);
Expand Down Expand Up @@ -424,6 +432,7 @@ int main(int argc, char **argv, char **envp)
if (env.use_lbr && env.verbose)
printf("LBR capture enabled.\n");

skel->rodata->emit_call_stack = env.emit_call_stack;
skel->rodata->emit_func_trace = env.emit_func_trace;

att_opts.verbose = env.verbose;
Expand Down