1
/* Copyright (C) 2000 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
17
#define DONT_DEFINE_VOID 1
19
#include "stacktrace.h"
22
#include <mysys/my_pthread.h>
23
#include <mystrings/m_string.h>
24
#ifdef HAVE_STACKTRACE
32
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
36
void safe_print_str(const char* name, const char* val, int max_len)
38
char *heap_end= (char*) sbrk(0);
39
fprintf(stderr, "%s at %p ", name, val);
43
fprintf(stderr, " is invalid pointer\n");
47
fprintf(stderr, "= ");
48
for (; max_len && PTR_SANE(val) && *val; --max_len)
49
fputc(*val++, stderr);
53
#ifdef TARGET_OS_LINUX
56
#define SIGRETURN_FRAME_OFFSET 17
60
#define SIGRETURN_FRAME_OFFSET 23
63
#if defined(__alpha__) && defined(__GNUC__)
65
The only way to backtrace without a symbol table on alpha
66
is to find stq fp,N(sp), and the first byte
67
of the instruction opcode will give us the value of N. From this
68
we can find where the old value of fp is stored
71
#define MAX_INSTR_IN_FUNC 10000
73
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
76
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
78
uchar* p = (uchar*)pc;
79
if (p[2] == 222 && p[3] == 35)
81
return (uchar**)((uchar*)fp - *(short int*)p);
87
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
90
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
93
if (p[1] == 0 && p[2] == 94 && p[3] == -73)
95
uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
101
#endif /* defined(__alpha__) && defined(__GNUC__) */
103
#if BACKTRACE_DEMANGLE
104
static void my_demangle_symbols(char **addrs, int n)
107
char *begin, *end, *demangled;
109
for (i= 0; i < n; i++)
112
begin= strchr(addrs[i], '(');
113
end= begin ? strchr(begin, '+') : NULL;
117
*begin++= *end++= '\0';
118
demangled= my_demangle(begin, &status);
119
if (!demangled || status)
128
fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
130
fprintf(stderr, "%s\n", addrs[i]);
137
static void backtrace_current_thread(void)
140
char **strings= NULL;
141
int n = backtrace(addrs, array_elements(addrs));
142
#if BACKTRACE_DEMANGLE
143
if ((strings= backtrace_symbols(addrs, n)))
145
my_demangle_symbols(strings, n);
149
#if HAVE_BACKTRACE_SYMBOLS_FD
152
backtrace_symbols_fd(addrs, n, fileno(stderr));
159
void print_stacktrace(uchar* stack_bottom, ulong thread_stack)
162
backtrace_current_thread();
166
uint frame_count = 0, sigreturn_frame_count;
167
#if defined(__alpha__) && defined(__GNUC__)
173
__asm __volatile__ ("movl %%ebp,%0"
178
__asm __volatile__ ("movq %%rbp,%0"
182
#if defined(__alpha__) && defined(__GNUC__)
183
__asm __volatile__ ("mov $30,%0"
189
fprintf(stderr, "frame pointer is NULL, did you compile with\n\
190
-fomit-frame-pointer? Aborting backtrace!\n");
194
if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
196
ulong tmp= min(0x10000,thread_stack);
197
/* Assume that the stack starts at the previous even 65K */
198
stack_bottom= (uchar*) (((ulong) &fp + tmp) &
200
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", (void *)fp);
202
if (fp > (uchar**) stack_bottom ||
203
fp < (uchar**) stack_bottom - thread_stack)
205
fprintf(stderr, "Bogus stack limit or frame pointer,\
206
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
207
(void *)fp, (void *)stack_bottom, thread_stack);
211
fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
212
#if defined(__alpha__) && defined(__GNUC__)
213
fprintf(stderr, "Warning: Alpha stacks are difficult -\
214
will be taking some wild guesses, stack trace may be incorrect or \
215
terminate abruptly\n");
216
/* On Alpha, we need to get pc */
217
__asm __volatile__ ("bsr %0, do_next; do_next: "
220
#endif /* __alpha__ */
222
/* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
223
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
225
while (fp < (uchar**) stack_bottom)
227
#if defined(__i386__) || defined(__x86_64__)
228
uchar** new_fp = (uchar**)*fp;
229
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
230
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
231
#endif /* defined(__386__) || defined(__x86_64__) */
233
#if defined(__alpha__) && defined(__GNUC__)
234
uchar** new_fp = find_prev_fp(pc, fp);
235
if (frame_count == sigreturn_frame_count - 1)
242
pc = find_prev_pc(pc, fp);
244
fprintf(stderr, "%p\n", pc);
247
fprintf(stderr, "Not smart enough to deal with the rest\
254
fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
257
#endif /* defined(__alpha__) && defined(__GNUC__) */
260
fprintf(stderr, "New value of fp=%p failed sanity check,\
261
terminating stack trace!\n", (void *)new_fp);
268
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
272
"Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
273
"and follow instructions on how to resolve the stack trace.\n"
274
"Resolved stack trace is much more helpful in diagnosing the\n"
275
"problem, so please do resolve it\n");
277
#endif /* TARGET_OS_LINUX */
278
#endif /* HAVE_STACKTRACE */
280
/* Produce a core for the thread */
282
void write_core(int sig)
284
signal(sig, SIG_DFL);
287
For GCOV build, crashing will prevent the writing of code coverage
288
information from this process, causing gcov output to be incomplete.
289
So we force the writing of coverage information here before terminating.
291
extern void __gcov_flush(void);
294
pthread_kill(pthread_self(), sig);
295
#if defined(P_MYID) && !defined(SCO)
296
/* On Solaris, the above kill is not enough */
297
sigsend(P_PID,P_MYID,sig);