[PATCH 7/9] unwind: add libdw as a unwinder

Dmitry V. Levin ldv at altlinux.org
Thu Mar 15 17:28:05 UTC 2018


On Wed, Mar 14, 2018 at 02:28:12AM +0900, Masatake YAMATO wrote:
[...]
> diff --git a/stacktrace-libdw.c b/stacktrace-libdw.c
> new file mode 100644
> index 00000000..e69de29b
> diff --git a/unwind-libdw.c b/unwind-libdw.c
> new file mode 100644
> index 00000000..f46f5ca1
> --- /dev/null
> +++ b/unwind-libdw.c
> @@ -0,0 +1,203 @@
> +/*
> + * This file is mostly based on git commit
> + * dfefa9f057857735a073ea655f5cb34351032c8e
> + * of ltrace submitted by Mark Wielaard <mjw at redhat.com>
> + *
> + * https://anonscm.debian.org/cgit/collab-maint/ltrace.git/commit/?id=dfefa9f057857735a073ea655f5cb34351032c8e
> + *
> + * The commit changes proc.c and output.c files of ltrace
> + */
> +
> +/*
> + * Copyright notice of output.c
> + */
> +/*
> + * This file is part of ltrace.
> + * Copyright (C) 2011,2012,2013,2014 Petr Machata, Red Hat Inc.
> + * Copyright (C) 2010 Joe Damato
> + * Copyright (C) 1997,1998,1999,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes
> + * Copyright (C) 2006 Paul Gilliam, IBM Corporation
> + * Copyright (C) 2006 Ian Wienand

As this piece of code is authored by Mark Wielaard, it's likely
Copyright (c) 2014 Mark Wielaard <mjw at redhat.com>

Other honorable people have nothing to do with ltrace commit
dfefa9f057857735a073ea655f5cb34351032c8e

[...]
> +/*
> + * Copyright notice of proc.c
> + */
> +/*
> + * This file is part of ltrace.
> + * Copyright (C) 2011,2012,2013,2014 Petr Machata, Red Hat Inc.
> + * Copyright (C) 2010 Joe Damato
> + * Copyright (C) 1998,2009 Juan Cespedes

Likewise.

> +#include "defs.h"
> +#include "unwind.h"
> +
> +#include "mmap_cache.h"
> +#include <elfutils/libdwfl.h>
> +
> +static void *
> +tcb_init(struct tcb *tcp)
> +{
> +	int r;
> +	const char *msg = NULL;
> +	static const Dwfl_Callbacks proc_callbacks = {
> +		.find_elf = dwfl_linux_proc_find_elf,
> +		.find_debuginfo = dwfl_standard_find_debuginfo

Are we going to print debuginfo based information?
If not, shouldn't find_no_debuginfo be specified instead?

> +	};
> +	Dwfl *dwfl;
> +
> +	dwfl = dwfl_begin(&proc_callbacks);

Dwfl *dwfl = dwfl_begin(&proc_callbacks);

> +	if (dwfl == NULL)
> +		error_msg_and_die("Couldn't initialize libdwfl unwinding "
> +				  "for process %d: %s\n", tcp->pid,
> +				  dwfl_errmsg(-1));

The error is not tracee specific, there is no need to print tcp->pid.

> +
> +	r = dwfl_linux_proc_attach(dwfl, tcp->pid, true);
> +
> +	if (r < 0)
> +		msg = dwfl_errmsg(-1);
> +	else if (r > 0)
> +		msg = strerror(r);
> +
> +	if (msg)
> +		error_msg_and_die("Couldn't initialize libdwfl unwinding "
> +				  "for process %d: %s\n", tcp->pid, msg);

I don't think this error condition is fatal.  What if the tracee just
disappeared right before dwfl_linux_proc_attach?

> +
> +	return dwfl;
> +}
> +
> +static void
> +tcb_fin(struct tcb *tcp)
> +{
> +	Dwfl *dwfl = tcp->unwind_ctx;
> +
> +	dwfl_end(dwfl);

dwfl_end(tcp->unwind_ctx);

> +}
> +
> +struct frame_user_data {
> +	unwind_call_action_fn call_action;
> +	unwind_error_action_fn error_action;
> +	void *data;
> +	int stack_depth;
> +};
> +
> +static int
> +frame_callback(Dwfl_Frame *state, void *arg)
> +{
> +	struct frame_user_data *user_data = arg;
> +	Dwarf_Addr pc;
> +	bool isactivation;
> +
> +	int *frames = &(user_data->stack_depth);
> +
> +	if (!dwfl_frame_pc(state, &pc, &isactivation))
> +		return -1;
> +
> +	if (!isactivation)
> +		pc--;
> +
> +	Dwfl *dwfl = dwfl_thread_dwfl(dwfl_frame_thread(state));
> +	Dwfl_Module *mod = dwfl_addrmodule(dwfl, pc);
> +	GElf_Off off = 0;
> +
> +	if (mod != NULL) {
> +		const char *modname = NULL;
> +		const char *symname = NULL;
> +		GElf_Sym sym;
> +		Dwarf_Addr true_offset = pc;
> +
> +		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);
> +		user_data->call_action(user_data->data, modname, symname,
> +				       off, true_offset);
> +	}
> +	/* Max number of frames to print reached? */
> +	if ((*frames)-- == 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +static void
> +tcb_walk(struct tcb *tcp,
> +	 unwind_call_action_fn call_action,
> +	 unwind_error_action_fn error_action,
> +	 void *data)
> +{
> +	struct frame_user_data user_data = {
> +		.call_action = call_action,
> +		.error_action = error_action,
> +		.data = data,
> +		.stack_depth = 256,
> +	};
> +	if (dwfl_getthread_frames(tcp->unwind_ctx, tcp->pid,
> +				  frame_callback, &user_data) < 0) {
> +		if (user_data.stack_depth == 256)
> +			error_action(data, "too many stack frames", 0);
> +		else
> +			perror_msg("Can't walk the stack of process %d: %s",
> +				   tcp->pid, dwfl_errmsg(-1));

As frame_callback decrements user_data.stack_depth, this doesn't look correct.

> +
> +	}
> +}
> +
> +static void
> +tcb_flush_cache(struct tcb *tcp)
> +{
> +	int r;
> +	Dwfl *dwfl = tcp->unwind_ctx;
> +
> +	r = dwfl_linux_proc_report(dwfl, tcp->pid);
> +	if (r < 0)
> +		error_msg_and_die("Error at dwfl_linux_proc_report pid %lld: %s",
> +				  (long long)tcp->pid, dwfl_errmsg(-1));
> +	else if (r > 0)
> +		error_msg_and_die("Error at dwfl_linux_proc_report pid %lld",
> +				  (long long)tcp->pid);
> +
> +	if (dwfl_report_end(dwfl, NULL, NULL) != 0)
> +		error_msg_and_die("dwfl_report_end: %s", dwfl_errmsg(-1));

I don't think these error conditions are fatal.
What if the tracee just disappeared right before one of these calls?


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20180315/4df3ab2e/attachment.bin>


More information about the Strace-devel mailing list