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 f25680d..12456b5 100644
--- a/include/haproxy/debug.h
+++ b/include/haproxy/debug.h
@@ -28,6 +28,7 @@
 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 3202814..465def2 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -52,6 +52,75 @@
         return y;
 }
 
+/* dumps a backtrace of the current thread that is appended to buffer <buf>.
+ * Lines are prefixed with the string <prefix> 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 @@
 	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, "             ");
 	}
 }