From: Willy Tarreau Date: Fri, 22 Jan 2021 12:52:41 +0000 (+0100) Subject: MINOR: debug: extract the backtrace dumping code to its own function X-Git-Tag: v2.4-dev6~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=123fc9786a570187e8221f7f359b39b03667a14c;p=thirdparty%2Fhaproxy.git MINOR: debug: extract the backtrace dumping code to its own function The backtrace dumping code was located into the thread dump function but it looks particularly convenient to be able to call it to produce a dump in other situations, so let's move it to its own function and make sure it's called last in the function so that we can benefit from tail merging to save one entry. --- diff --git a/include/haproxy/debug.h b/include/haproxy/debug.h index f25680d4b8..12456b5f59 100644 --- a/include/haproxy/debug.h +++ b/include/haproxy/debug.h @@ -28,6 +28,7 @@ extern volatile unsigned long threads_to_dump; extern unsigned int debug_commands_issued; void ha_task_dump(struct buffer *buf, const struct task *task, const char *pfx); void ha_thread_dump(struct buffer *buf, int thr, int calling_tid); +void ha_dump_backtrace(struct buffer *buf, const char *prefix); void ha_thread_dump_all_to_trash(); void ha_panic(); diff --git a/src/debug.c b/src/debug.c index 3202814732..465def2648 100644 --- a/src/debug.c +++ b/src/debug.c @@ -52,6 +52,75 @@ static unsigned int debug_prng() return y; } +/* dumps a backtrace of the current thread that is appended to buffer . + * Lines are prefixed with the string which may be empty (used for + * indenting). It is recommended to use this at a function's tail so that + * the function does not appear in the call stack. + */ +void ha_dump_backtrace(struct buffer *buf, const char *prefix) +{ + struct buffer bak; + char pfx2[100]; + void *callers[100]; + int j, nptrs; + const void *addr; + int dump = 0; + + nptrs = my_backtrace(callers, sizeof(callers)/sizeof(*callers)); + if (!nptrs) + return; + + if (snprintf(pfx2, sizeof(pfx2), "%s| ", prefix) > sizeof(pfx2)) + pfx2[0] = 0; + + /* The call backtrace_symbols_fd(callers, nptrs, STDOUT_FILENO would + * produce similar output to the following: + */ + chunk_appendf(buf, "%scall trace(%d):\n", prefix, nptrs); + for (j = 0; (j < nptrs || dump < 2); j++) { + if (j == nptrs && !dump) { + /* we failed to spot the starting point of the + * dump, let's start over dumping everything we + * have. + */ + dump = 2; + j = 0; + } + bak = *buf; + dump_addr_and_bytes(buf, pfx2, callers[j], 8); + addr = resolve_sym_name(buf, ": ", callers[j]); + if (dump == 0) { + /* dump not started, will start *after* + * ha_thread_dump_all_to_trash and ha_panic + */ + if (addr == ha_thread_dump_all_to_trash || addr == ha_panic) + dump = 1; + *buf = bak; + continue; + } + + if (dump == 1) { + /* starting */ + if (addr == ha_thread_dump_all_to_trash || addr == ha_panic) { + *buf = bak; + continue; + } + dump = 2; + } + + if (dump == 2) { + /* dumping */ + if (addr == run_poll_loop || addr == main || addr == run_tasks_from_lists) { + dump = 3; + *buf = bak; + break; + } + } + /* OK, line dumped */ + chunk_appendf(buf, "\n"); + } +} + /* Dumps to the buffer some known information for the desired thread, and * optionally extra info for the current thread. The dump will be appended to * the buffer, so the caller is responsible for preliminary initializing it. @@ -103,63 +172,11 @@ void ha_thread_dump(struct buffer *buf, int thr, int calling_tid) if (stuck) { /* We only emit the backtrace for stuck threads in order not to * waste precious output buffer space with non-interesting data. + * Please leave this as the last instruction in this function + * so that the compiler uses tail merging and the current + * function does not appear in the stack. */ - struct buffer bak; - void *callers[100]; - int j, nptrs; - const void *addr; - int dump = 0; - - nptrs = my_backtrace(callers, sizeof(callers)/sizeof(*callers)); - - /* The call backtrace_symbols_fd(callers, nptrs, STDOUT_FILENO) - would produce similar output to the following: */ - - if (nptrs) - chunk_appendf(buf, " call trace(%d):\n", nptrs); - - for (j = 0; nptrs && (j < nptrs || dump < 2); j++) { - if (j == nptrs && !dump) { - /* we failed to spot the starting point of the - * dump, let's start over dumping everything we - * have. - */ - dump = 2; - j = 0; - } - bak = *buf; - dump_addr_and_bytes(buf, " | ", callers[j], 8); - addr = resolve_sym_name(buf, ": ", callers[j]); - if (dump == 0) { - /* dump not started, will start *after* - * ha_thread_dump_all_to_trash and ha_panic - */ - if (addr == ha_thread_dump_all_to_trash || addr == ha_panic) - dump = 1; - *buf = bak; - continue; - } - - if (dump == 1) { - /* starting */ - if (addr == ha_thread_dump_all_to_trash || addr == ha_panic) { - *buf = bak; - continue; - } - dump = 2; - } - - if (dump == 2) { - /* dumping */ - if (addr == run_poll_loop || addr == main || addr == run_tasks_from_lists) { - dump = 3; - *buf = bak; - break; - } - } - /* OK, line dumped */ - chunk_appendf(buf, "\n"); - } + ha_dump_backtrace(buf, " "); } }