X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=output.c;h=8d378ea42c5ab250449b757ef80c3b9f0f76305c;hb=150e91ca55bd5d3935c1d865327c676a6b5c9ce7;hp=edf4522ac9ed385434dae2a4286675bdfe6091b0;hpb=517f5529d7008eba87b8b2fee5ec9ec0a5075f6e;p=platform%2Fupstream%2Fltrace.git diff --git a/output.c b/output.c index edf4522..8d378ea 100644 --- a/output.c +++ b/output.c @@ -1,6 +1,6 @@ /* * 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 @@ -33,6 +33,7 @@ #include #include #include +#include #include "output.h" #include "demangle.h" @@ -44,16 +45,18 @@ #include "param.h" #include "proc.h" #include "prototype.h" +#include "summary.h" #include "type.h" #include "value.h" #include "value_dict.h" +#include "filter.h" +#include "debug.h" -/* TODO FIXME XXX: include in common.h: */ -extern struct timeval current_time_spent; - -struct dict *dict_opt_c = NULL; +#if defined(HAVE_LIBDW) +#include "dwarf_prototypes.h" +#endif -static struct process *current_proc = 0; +static struct process *current_proc = NULL; static size_t current_depth = 0; static int current_column = 0; @@ -210,6 +213,21 @@ library_get_prototype(struct library *lib, const char *name) && 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); @@ -498,9 +516,8 @@ void output_left(enum tof type, struct process *proc, struct library_symbol *libsym) { - if (options.summary) { - return; - } + assert(! options.summary); + if (current_proc) { fprintf(options.output, " \n"); current_column = 0; @@ -535,7 +552,7 @@ output_left(enum tof type, struct process *proc, 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, "???")); @@ -572,70 +589,88 @@ output_left(enum tof type, struct process *proc, stel->out.need_delim = need_delim; } -static void -free_stringp_cb(const char **stringp, void *data) +#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) { - free((char *)*stringp); -} + Dwarf_Addr pc; + bool isactivation; -void -output_right(enum tof type, struct process *proc, struct library_symbol *libsym) -{ - struct prototype *func = lookup_symbol_prototype(proc, libsym); - if (func == NULL) - return; + int *frames = (int *) arg; -again: - if (options.summary) { - if (dict_opt_c == NULL) { - dict_opt_c = malloc(sizeof(*dict_opt_c)); - if (dict_opt_c == NULL) { - oom: - fprintf(stderr, - "Can't allocate memory for " - "keeping track of -c.\n"); - free(dict_opt_c); - options.summary = 0; - goto again; - } - DICT_INIT(dict_opt_c, char *, struct opt_c_struct, - dict_hash_string, dict_eq_string, NULL); - } + 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); + } - struct opt_c_struct *st - = DICT_FIND_REF(dict_opt_c, &libsym->name, - struct opt_c_struct); - if (st == NULL) { - const char *na = strdup(libsym->name); - struct opt_c_struct new_st = {.count = 0, .tv = {0, 0}}; - if (na == NULL - || DICT_INSERT(dict_opt_c, &na, &new_st) < 0) { - free((char *)na); - DICT_DESTROY(dict_opt_c, const char *, - struct opt_c_struct, - free_stringp_cb, NULL, NULL); - goto oom; + /* 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"); } - st = DICT_FIND_REF(dict_opt_c, &libsym->name, - struct opt_c_struct); - assert(st != NULL); - } - if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) { - st->tv.tv_usec += current_time_spent.tv_usec - 1000000; - st->tv.tv_sec++; - } else { - st->tv.tv_usec += current_time_spent.tv_usec; } - st->count++; - st->tv.tv_sec += current_time_spent.tv_sec; - return; } - if (current_proc && (current_proc != proc || - current_depth != proc->callstack_depth)) { + /* 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) +{ + assert(! options.summary); + + struct prototype *func = lookup_symbol_prototype(proc, libsym); + if (func == NULL) + return; + + if (current_proc != NULL + && (current_proc != proc + || current_depth != proc->callstack_depth)) { fprintf(options.output, " \n"); - current_proc = 0; + current_proc = NULL; } if (current_proc != proc) { begin_of_line(proc, type == LT_TOF_FUNCTIONR, 1); @@ -658,17 +693,17 @@ again: /* 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) @@ -689,10 +724,12 @@ again: value_destroy(&retval); if (opt_T) { + assert(spent != NULL); fprintf(options.output, " <%lu.%06d>", - (unsigned long)current_time_spent.tv_sec, - (int)current_time_spent.tv_usec); + (unsigned long) spent->tm.tv_sec, + (int) spent->tm.tv_usec); } + fprintf(options.output, "\n"); #if defined(HAVE_LIBUNWIND) @@ -713,9 +750,14 @@ again: != 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. */ @@ -735,9 +777,17 @@ again: 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--; @@ -746,7 +796,25 @@ again: } #endif /* defined(HAVE_LIBUNWIND) */ - current_proc = 0; +#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; }