diff options
author | Milan Crha <mcrha@redhat.com> | 2018-07-18 17:13:25 +0200 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2018-07-18 17:13:25 +0200 |
commit | 6e130c43ac6a45c18ed434448c24aa2886e0186b (patch) | |
tree | bb710deb671b8c371688cd53863cec7c362a7b4e | |
parent | 98f13365247bc4e2c9bd4e94fc78a26d4303a460 (diff) | |
download | evolution-data-server-6e130c43ac6a45c18ed434448c24aa2886e0186b.tar.gz |
[CamelDebug] Change when backtraces are demangled in pointer tracker
-rw-r--r-- | src/camel/camel-debug.c | 167 | ||||
-rw-r--r-- | src/camel/camel-debug.h | 2 |
2 files changed, 146 insertions, 23 deletions
diff --git a/src/camel/camel-debug.c b/src/camel/camel-debug.c index 132c73dbb..e51dd2764 100644 --- a/src/camel/camel-debug.c +++ b/src/camel/camel-debug.c @@ -284,6 +284,8 @@ free_pt_data (gpointer ptr) g_free (ptd); } +static void demangle_bt (GString *bt); + static void dump_left_ptrs_cb (gpointer key, gpointer value, @@ -294,7 +296,11 @@ dump_left_ptrs_cb (gpointer key, gboolean have_info = ptd && ptd->info; gboolean have_bt = ptd && ptd->backtrace && ptd->backtrace->str && *ptd->backtrace->str; + if (have_bt) + demangle_bt (ptd->backtrace); + *left = (*left) - 1; + g_print (" %p %s%s%s%s%s%s\n", key, have_info ? "(" : "", have_info ? ptd->info : "", have_info ? ")" : "", have_bt ? "\n" : "", have_bt ? ptd->backtrace->str : "", have_bt && *left > 0 ? "\n" : ""); } @@ -337,6 +343,9 @@ dump_by_backtrace_cb (gpointer key, gboolean have_info = ptd && ptd->info; gboolean have_bt = ptd && ptd->backtrace && ptd->backtrace->str && *ptd->backtrace->str; + if (have_bt) + demangle_bt (ptd->backtrace); + *left = (*left) - 1; g_print (" %d x %s%s%s%s%s%s\n", count, have_info ? "(" : "", have_info ? ptd->info : "", have_info ? ")" : "", have_bt ? "\n" : "", have_bt ? ptd->backtrace->str : "", have_bt && *left > 0 ? "\n" : ""); @@ -519,6 +528,81 @@ addr_lookup (gpointer addr, #endif /* HAVE_BACKTRACE_SYMBOLS */ +static void +demangle_bt (GString *bt) +{ +#ifdef HAVE_BACKTRACE_SYMBOLS + gchar **btparts; + gint ii; + gboolean any_changed = FALSE; + + if (!bt || !bt->len) + return; + + btparts = g_strsplit (bt->str, "\n", -1); + if (!btparts) + return; + + g_string_truncate (bt, 0); + + for (ii = 0; btparts[ii]; ii++) { + gint lineno = -1; + const gchar *file_path = NULL; + const gchar *str, *bt_sym; + gpointer btptr = NULL; + + if (!g_str_has_prefix (btparts[ii], "0x") || + !strchr (btparts[ii], '\t') || + sscanf (btparts[ii], "%p\t", &btptr) != 1) { + btptr = NULL; + } + + if (btptr) { + bt_sym = strchr (btparts[ii], '\t'); + if (bt_sym) + bt_sym++; + } else { + bt_sym = NULL; + } + + if (!bt_sym || !*bt_sym) { + if (bt->len) + g_string_append_c (bt, '\n'); + g_string_append (bt, btparts[ii]); + continue; + } + + str = addr_lookup (btptr, &file_path, &lineno, bt_sym); + + if (!str) { + str = btparts[ii]; + file_path = NULL; + lineno = -1; + } + + if (!str) + continue; + + any_changed = TRUE; + if (bt->len) + g_string_append (bt, "\n\t by "); + g_string_append (bt, str); + if (str != btparts[ii]) + g_string_append (bt, "()"); + + if (file_path && lineno > 0) { + const gchar *lastsep = strrchr (file_path, G_DIR_SEPARATOR); + g_string_append_printf (bt, " at %s:%d", lastsep ? lastsep + 1 : file_path, lineno); + } + } + + g_strfreev (btparts); + + if (bt->len != 0 && any_changed) + g_string_insert (bt, 0, "\t at "); +#endif /* HAVE_BACKTRACE_SYMBOLS */ +} + static GString * get_current_backtrace (void) { @@ -539,27 +623,9 @@ get_current_backtrace (void) bt_str = g_string_new (""); for (ii = 2; ii < nptrs; ii++) { - gint lineno = -1; - const gchar *file_path = NULL; - const gchar *str = addr_lookup (bt[ii], &file_path, &lineno, bt_syms[ii]); - if (!str) { - str = bt_syms[ii]; - file_path = NULL; - lineno = -1; - } - if (!str) - continue; - if (bt_str->len) - g_string_append (bt_str, "\n\t by "); - g_string_append (bt_str, str); - if (str != bt_syms[ii]) - g_string_append (bt_str, "()"); - - if (file_path && lineno > 0) { - const gchar *lastsep = strrchr (file_path, G_DIR_SEPARATOR); - g_string_append_printf (bt_str, " at %s:%d", lastsep ? lastsep + 1 : file_path, lineno); - } + g_string_append (bt_str, "\n"); + g_string_append_printf (bt_str, "%p\t%s", bt[ii], bt_syms[ii]); } g_free (bt_syms); @@ -567,8 +633,6 @@ get_current_backtrace (void) if (bt_str->len == 0) { g_string_free (bt_str, TRUE); bt_str = NULL; - } else { - g_string_insert (bt_str, 0, "\t at "); } return bt_str; @@ -681,21 +745,78 @@ camel_pointer_tracker_dump (void) /** * camel_debug_get_backtrace: * - * Gets current backtrace leading to this function call. + * Gets current backtrace leading to this function call and demangles it. * * Returns: Current backtrace, or %NULL, if cannot determine it. * * Note: Getting backtraces only works if the library was * configured with --enable-backtraces. * + * See also camel_debug_get_raw_backtrace() + * * Since: 3.12 **/ GString * camel_debug_get_backtrace (void) { + GString *bt; + + bt = get_current_backtrace (); + + if (!bt) + return NULL; + + demangle_bt (bt); + + return bt; +} + +/** + * camel_debug_get_raw_backtrace: + * + * Gets current raw backtrace leading to this function call. + * This is quicker than camel_debug_get_backtrace(), because it + * doesn't demangle the backtrace. To demangle it (replace addresses + * with actual function calls and eventually line numbers, if + * available) call camel_debug_demangle_backtrace(). + * + * Returns: Current raw backtrace, or %NULL, if cannot determine it. + * + * Note: Getting backtraces only works if the library was + * configured with --enable-backtraces. + * + * See also camel_debug_get_backtrace() + * + * Since: 3.30 + **/ +GString * +camel_debug_get_raw_backtrace (void) +{ return get_current_backtrace (); } +/** + * camel_debug_demangle_backtrace: + * @bt: (inout) (nullable): a #GString with a raw backtrace, or %NULL + * + * Demangles @bt, possibly got from camel_debug_get_raw_backtrace(), by + * replacing addresses with actual function calls and eventually line numbers, if + * available. It modifies lines of @bt, but skips those it cannot parse. + * + * Note: Getting backtraces only works if the library was + * configured with --enable-backtraces. + * + * See also camel_debug_get_raw_backtrace() + * + * Since: 3.30 + **/ +void +camel_debug_demangle_backtrace (GString *bt) +{ + if (bt) + demangle_bt (bt); +} + G_LOCK_DEFINE_STATIC (ref_unref_backtraces); static GQueue *ref_unref_backtraces = NULL; static guint total_ref_unref_backtraces = 0; diff --git a/src/camel/camel-debug.h b/src/camel/camel-debug.h index 62163e383..416a84146 100644 --- a/src/camel/camel-debug.h +++ b/src/camel/camel-debug.h @@ -147,6 +147,8 @@ void camel_pointer_tracker_untrack (gpointer ptr); void camel_pointer_tracker_dump (void); GString * camel_debug_get_backtrace (void); +GString * camel_debug_get_raw_backtrace (void); +void camel_debug_demangle_backtrace (GString *bt); void camel_debug_ref_unref_push_backtrace (const GString *backtrace, |