/*
* This file is part of ltrace.
- * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
+ * 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
#include <unistd.h>
#include <errno.h>
#include <assert.h>
+#include <inttypes.h>
#include "output.h"
#include "demangle.h"
#include "type.h"
#include "value.h"
#include "value_dict.h"
+#include "filter.h"
+#include "debug.h"
+
+#if defined(HAVE_LIBDW)
+#include "dwarf_prototypes.h"
+#endif
static struct process *current_proc = NULL;
static size_t current_depth = 0;
&& lib->type == LT_LIBTYPE_DSO
&& snip_period(buf));
+#if defined(HAVE_LIBDW)
+ // DWARF data fills in the gaps in the .conf files, so I don't
+ // check for lib->protolib==NULL here
+ if (lib->dwfl != NULL &&
+ (filter_matches_library(options.plt_filter, lib ) ||
+ filter_matches_library(options.static_filter, lib ) ||
+ filter_matches_library(options.export_filter, lib )))
+ import_DWARF_prototypes(lib);
+ else
+ debug(DEBUG_FUNCTION,
+ "Filter didn't match prototype '%s' in lib '%s'. "
+ "Not importing",
+ name, lib->soname);
+#endif
+
if (lib->protolib == NULL)
lib->protolib = protolib_cache_default(&g_protocache,
buf, 0);
account_output(¤t_column, fprintf(options.output, "("));
- struct prototype *func = lookup_symbol_prototype(proc, libsym);
+ struct prototype *func = lookup_symbol_prototype(proc->leader, libsym);
if (func == NULL) {
fail:
account_output(¤t_column, fprintf(options.output, "???"));
stel->out.need_delim = need_delim;
}
+#if defined(HAVE_LIBDW)
+/* Prints information about one frame of a thread. Called by
+ dwfl_getthread_frames in output_right. Returns 1 when done (max
+ number of frames reached). Returns -1 on error. Returns 0 on
+ success (if there are more frames in the thread, call us again). */
+static int
+frame_callback (Dwfl_Frame *state, void *arg)
+{
+ Dwarf_Addr pc;
+ bool isactivation;
+
+ int *frames = (int *) arg;
+
+ 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);
+ const char *modname = NULL;
+ const char *symname = NULL;
+ GElf_Off off = 0;
+ if (mod != NULL) {
+ GElf_Sym sym;
+ modname = dwfl_module_info(mod, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ symname = dwfl_module_addrinfo(mod, pc, &off, &sym,
+ NULL, NULL, NULL);
+ }
+
+ /* This mimics the output produced by libunwind below. */
+ fprintf(options.output, " > %s(%s+0x%" PRIx64 ") [%" PRIx64 "]\n",
+ modname, symname, off, pc);
+
+ /* See if we can extract the source line too and print it on
+ the next line if we can find it. */
+ if (mod != NULL) {
+ Dwfl_Line *l = dwfl_module_getsrc(mod, pc);
+ if (l != NULL) {
+ int line, col;
+ line = col = -1;
+ const char *src = dwfl_lineinfo(l, NULL, &line, &col,
+ NULL, NULL);
+ if (src != NULL) {
+ fprintf(options.output, "\t%s", src);
+ if (line > 0) {
+ fprintf(options.output, ":%d", line);
+ if (col > 0)
+ fprintf(options.output,
+ ":%d", col);
+ }
+ fprintf(options.output, "\n");
+ }
+
+ }
+ }
+
+ /* Max number of frames to print reached? */
+ if ((*frames)-- == 0)
+ return 1;
+
+ return 0;
+}
+#endif /* defined(HAVE_LIBDW) */
+
void
output_right(enum tof type, struct process *proc, struct library_symbol *libsym,
struct timedelta *spent)
/* Fetch & enter into dictionary the retval first, so that
* other values can use it in expressions. */
struct value retval;
- int own_retval = 0;
+ bool own_retval = false;
if (context != NULL) {
value_init(&retval, proc, NULL, func->return_info, 0);
- own_retval = 1;
+ own_retval = true;
if (fetch_retval(context, type, proc, func->return_info,
&retval) < 0)
value_set_type(&retval, NULL, 0);
else if (stel->arguments != NULL
- && val_dict_push_named(stel->arguments, &retval,
- "retval", 0) == 0)
- own_retval = 0;
+ && val_dict_push_named(stel->arguments, &retval,
+ "retval", 0) == 0)
+ own_retval = false;
}
if (stel->arguments != NULL)
!= sizeof(arch_addr_t))]);
unw_init_remote(&cursor, proc->unwind_as, proc->unwind_priv);
while (unwind_depth) {
- unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip);
- unw_get_proc_name(&cursor, fn_name, sizeof(fn_name),
- (unw_word_t *) &function_offset);
+
+ int rc = unw_get_reg(&cursor, UNW_REG_IP,
+ (unw_word_t *) &ip);
+ if (rc < 0) {
+ fprintf(options.output, " > Error: %s\n",
+ unw_strerror(rc));
+ goto cont;
+ }
/* We are looking for the library with the base address
* closest to the current ip. */
lib = lib->next;
}
- fprintf(options.output, " > %s(%s+0x%p) [%p]\n",
+ rc = unw_get_proc_name(&cursor, fn_name,
+ sizeof(fn_name),
+ (unw_word_t *) &function_offset);
+ if (rc == 0 || rc == -UNW_ENOMEM)
+ fprintf(options.output, " > %s(%s+%p) [%p]\n",
lib_name, fn_name, function_offset, ip);
+ else
+ fprintf(options.output, " > %s(??\?) [%p]\n",
+ lib_name, ip);
+ cont:
if (unw_step(&cursor) <= 0)
break;
unwind_depth--;
}
#endif /* defined(HAVE_LIBUNWIND) */
+#if defined(HAVE_LIBDW)
+ if (options.bt_depth > 0 && proc->leader->dwfl != NULL) {
+ int frames = options.bt_depth;
+ if (dwfl_getthread_frames(proc->leader->dwfl, proc->pid,
+ frame_callback, &frames) < 0) {
+ // Only print an error if we couldn't show anything.
+ // Otherwise just show there might be more...
+ if (frames == options.bt_depth)
+ fprintf(stderr,
+ "dwfl_getthread_frames tid %d: %s\n",
+ proc->pid, dwfl_errmsg(-1));
+ else
+ fprintf(options.output, " > [...]\n");
+ }
+ fprintf(options.output, "\n");
+ }
+#endif /* defined(HAVE_LIBDW) */
+
current_proc = NULL;
current_column = 0;
}