mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-29 08:02:08 +00:00
MINOR: debug: improve backtrace() on aarch64 and possibly other systems
It happens that on aarch64 backtrace() only returns one entry (tested with gcc 4.7.4, 5.5.0 and 7.4.1). Probably that it refrains from unwinding the stack due to the risk of hitting a bad pointer. Here we can use may_access() to know when it's safe, so we can actually unwind the stack without taking risks. It happens that the faulting function (the one just after the signal handler) is not listed here, very likely because the signal handler uses a special stack and did not create a new frame. So this patch creates a new my_backtrace() function in standard.h that either calls backtrace() or does its own unrolling. The choice depends on HA_HAVE_WORKING_BACKTRACE which is set in compat.h based on the build target.
This commit is contained in:
parent
cdd8074433
commit
13faf16e1e
@ -207,6 +207,22 @@ typedef struct { } empty_t;
|
||||
#define HA_HAVE_CRYPT_R
|
||||
#endif
|
||||
|
||||
/* some backtrace() implementations are broken or incomplete, in this case we
|
||||
* can replace them. We must not do it all the time as some are more accurate
|
||||
* than ours.
|
||||
*/
|
||||
#ifdef USE_BACKTRACE
|
||||
#if defined(__aarch64__)
|
||||
/* on aarch64 at least from gcc-4.7.4 to 7.4.1 we only get a single entry, which
|
||||
* is pointless. Ours works though it misses the faulty function itself,
|
||||
* probably due to an alternate stack for the signal handler which does not
|
||||
* create a new frame hence doesn't store the caller's return address.
|
||||
*/
|
||||
#else
|
||||
#define HA_HAVE_WORKING_BACKTRACE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* _COMMON_COMPAT_H */
|
||||
|
||||
/*
|
||||
|
@ -22,6 +22,11 @@
|
||||
#ifndef _COMMON_STANDARD_H
|
||||
#define _COMMON_STANDARD_H
|
||||
|
||||
#ifdef USE_BACKTRACE
|
||||
#define _GNU_SOURCE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -1487,6 +1492,31 @@ void dump_hex(struct buffer *out, const char *pfx, const void *buf, int len, int
|
||||
int may_access(const void *ptr);
|
||||
void *resolve_sym_name(struct buffer *buf, const char *pfx, void *addr);
|
||||
|
||||
#if defined(USE_BACKTRACE)
|
||||
/* Note that this may result in opening libgcc() on first call, so it may need
|
||||
* to have been called once before chrooting.
|
||||
*/
|
||||
static forceinline int my_backtrace(void **buffer, int max)
|
||||
{
|
||||
#ifdef HA_HAVE_WORKING_BACKTRACE
|
||||
return backtrace(buffer, max);
|
||||
#else
|
||||
const struct frame {
|
||||
const struct frame *next;
|
||||
void *ra;
|
||||
} *frame;
|
||||
int count;
|
||||
|
||||
frame = __builtin_frame_address(0);
|
||||
for (count = 0; count < max && may_access(frame) && may_access(frame->ra);) {
|
||||
buffer[count++] = frame->ra;
|
||||
frame = frame->next;
|
||||
}
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* same as realloc() except that ptr is also freed upon failure */
|
||||
static inline void *my_realloc2(void *ptr, size_t size)
|
||||
{
|
||||
|
@ -11,11 +11,6 @@
|
||||
*/
|
||||
|
||||
|
||||
#ifdef USE_BACKTRACE
|
||||
#define _GNU_SOURCE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
@ -105,7 +100,7 @@ void ha_thread_dump(struct buffer *buf, int thr, int calling_tid)
|
||||
void *addr;
|
||||
int dump = 0;
|
||||
|
||||
nptrs = backtrace(callers, sizeof(callers)/sizeof(*callers));
|
||||
nptrs = my_backtrace(callers, sizeof(callers)/sizeof(*callers));
|
||||
|
||||
/* The call backtrace_symbols_fd(callers, nptrs, STDOUT_FILENO)
|
||||
would produce similar output to the following: */
|
||||
@ -770,7 +765,7 @@ static int init_debug()
|
||||
* ready in memory for later use.
|
||||
*/
|
||||
void *callers[1];
|
||||
backtrace(callers, sizeof(callers)/sizeof(*callers));
|
||||
my_backtrace(callers, sizeof(callers)/sizeof(*callers));
|
||||
#endif
|
||||
sa.sa_handler = NULL;
|
||||
sa.sa_sigaction = debug_handler;
|
||||
|
Loading…
Reference in New Issue
Block a user