]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: debug: detect call instructions and show the branch target in backtraces
authorWilly Tarreau <w@1wt.eu>
Mon, 14 Apr 2025 18:06:48 +0000 (20:06 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 14 Apr 2025 18:06:48 +0000 (20:06 +0200)
In backtraces, sometimes it's difficult to know what was called by a
given point, because some functions can be fairly long making one
doubt about the correct pointer of unresolved ones, others might
just use a tail branch instead of a call + return, etc. On common
architectures (x86 and aarch64), it's not difficult to detect and
decode a relative call, so let's do it on both of these platforms
and show the branch location after a '>'. Example:

x86_64:
   call trace(19):
   |       0x6bd644 <64 8b 38 e8 ac f7 ff ff]: debug_handler+0x84/0x95 > ha_thread_dump_one
   | 0x7feb3e5383a0 <00 00 00 00 0f 1f 40 00]: libpthread:+0x123a0
   | 0x7feb3e53748b <c0 b8 03 00 00 00 0f 05]: libpthread:__close+0x3b/0x8b
   |       0x7619e4 <44 89 ff e8 fc 97 d4 ff]: _fd_delete_orphan+0x1d4/0x1d6 > main-0x2130
   |       0x743862 <8b 7f 68 e8 8e e1 01 00]: sock_conn_ctrl_close+0x12/0x54 > fd_delete
   |       0x5ac822 <c0 74 05 4c 89 e7 ff d0]: main+0xff512
   |       0x5bc85c <48 89 ef e8 04 fc fe ff]: main+0x10f54c > main+0xff150
   |       0x5be410 <4c 89 e7 e8 c0 e1 ff ff]: main+0x111100 > main+0x10f2c0
   |       0x6ae6a4 <28 00 00 00 00 ff 51 58]: cli_io_handler+0x31524
   |       0x6aeab4 <7c 24 08 e8 fc fa ff ff]: sc_destroy+0x14/0x2a4 > cli_io_handler+0x31430
   |       0x6c685d <48 89 ef e8 43 82 fe ff]: process_chk_conn+0x51d/0x1927 > sc_destroy

aarch64:
   call trace(15):
   | 0xaaaaad0c1540 <60 6a 60 b8 c3 fd ff 97]: debug_handler+0x9c/0xbc > ha_thread_dump_one
   | 0xffffa8c177ac <c2 e0 3b d5 1f 20 03 d5]: linux-vdso:__kernel_rt_sigreturn
   | 0xaaaaad0b0964 <c0 03 5f d6 d2 ff ff 97]: cli_io_handler+0x28e44 > sedesc_new
   | 0xaaaaad0b22a4 <00 00 80 d2 94 f9 ff 97]: sc_new_from_strm+0x1c/0x54 > cli_io_handler+0x28dd0
   | 0xaaaaad0167e8 <21 00 80 52 a9 6e 02 94]: stream_new+0x258/0x67c > sc_new_from_strm
   | 0xaaaaad0b21f8 <e1 03 13 aa e7 90 fd 97]: sc_new_from_endp+0x38/0xc8 > stream_new
   | 0xaaaaacfda628 <21 18 40 f9 e7 5e 03 94]: main+0xcaca8 > sc_new_from_endp
   | 0xaaaaacfdb95c <42 c0 00 d1 02 f3 ff 97]: main+0xcbfdc > main+0xc8be0
   | 0xaaaaacfdd3f0 <e0 03 13 aa f5 f7 ff 97]: h1_io_cb+0xd0/0xb90 > main+0xcba40

src/debug.c

index b0effdd4b749c35bf5423e83d7027a80ecbddcef..29339413f22e1ec127e42365e7ae4e2fbe3d8e6a 100644 (file)
@@ -209,6 +209,24 @@ void ha_dump_backtrace(struct buffer *buf, const char *prefix, int dump)
                bak = *buf;
                dump_addr_and_bytes(buf, pfx2, callers[j], -8);
                addr = resolve_sym_name(buf, ": ", callers[j]);
+
+#if defined(__i386__) || defined(__x86_64__)
+               /* Try to decode a relative call (0xe8 + 32-bit signed ofs) */
+               if (may_access(callers[j] - 5) && may_access(callers[j] - 1) &&
+                   *((uchar*)(callers[j] - 5)) == 0xe8) {
+                       int ofs = *((int *)(callers[j] - 4));
+                       const void *addr2 = callers[j] + ofs;
+                       resolve_sym_name(buf, " > ", addr2);
+               }
+#elif defined(__aarch64__)
+               /* Try to decode a relative call (0x9X + 26-bit signed ofs) */
+               if (may_access(callers[j] - 4) && may_access(callers[j] - 1) &&
+                   (*((int*)(callers[j] - 4)) & 0xFC000000) == 0x94000000) {
+                       int ofs = (*((int *)(callers[j] - 4)) << 6) >> 4; // 26-bit signed immed*4
+                       const void *addr2 = callers[j] - 4 + ofs;
+                       resolve_sym_name(buf, " > ", addr2);
+               }
+#endif
                if ((dump & 3) == 0) {
                        /* dump not started, will start *after* ha_thread_dump_one(),
                         * ha_panic and ha_backtrace_to_stderr