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 <my_global.h>
20
#include "stacktrace.h"
23
#include <my_pthread.h>
25
#ifdef HAVE_STACKTRACE
33
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
37
void safe_print_str(const char* name, const char* val, int max_len)
39
char *heap_end= (char*) sbrk(0);
40
fprintf(stderr, "%s at %p ", name, val);
44
fprintf(stderr, " is invalid pointer\n");
48
fprintf(stderr, "= ");
49
for (; max_len && PTR_SANE(val) && *val; --max_len)
50
fputc(*val++, stderr);
54
#ifdef TARGET_OS_LINUX
57
#define SIGRETURN_FRAME_OFFSET 17
61
#define SIGRETURN_FRAME_OFFSET 23
64
#if defined(__alpha__) && defined(__GNUC__)
66
The only way to backtrace without a symbol table on alpha
67
is to find stq fp,N(sp), and the first byte
68
of the instruction opcode will give us the value of N. From this
69
we can find where the old value of fp is stored
72
#define MAX_INSTR_IN_FUNC 10000
74
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
77
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
79
uchar* p = (uchar*)pc;
80
if (p[2] == 222 && p[3] == 35)
82
return (uchar**)((uchar*)fp - *(short int*)p);
88
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
91
for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
94
if (p[1] == 0 && p[2] == 94 && p[3] == -73)
96
uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
102
#endif /* defined(__alpha__) && defined(__GNUC__) */
104
#if BACKTRACE_DEMANGLE
105
static void my_demangle_symbols(char **addrs, int n)
108
char *begin, *end, *demangled;
110
for (i= 0; i < n; i++)
113
begin= strchr(addrs[i], '(');
114
end= begin ? strchr(begin, '+') : NULL;
118
*begin++= *end++= '\0';
119
demangled= my_demangle(begin, &status);
120
if (!demangled || status)
129
fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
131
fprintf(stderr, "%s\n", addrs[i]);
138
static void backtrace_current_thread(void)
141
char **strings= NULL;
142
int n = backtrace(addrs, array_elements(addrs));
143
#if BACKTRACE_DEMANGLE
144
if ((strings= backtrace_symbols(addrs, n)))
146
my_demangle_symbols(strings, n);
150
#if HAVE_BACKTRACE_SYMBOLS_FD
153
backtrace_symbols_fd(addrs, n, fileno(stderr));
160
void print_stacktrace(uchar* stack_bottom, ulong thread_stack)
163
backtrace_current_thread();
167
uint frame_count = 0, sigreturn_frame_count;
168
#if defined(__alpha__) && defined(__GNUC__)
174
__asm __volatile__ ("movl %%ebp,%0"
179
__asm __volatile__ ("movq %%rbp,%0"
183
#if defined(__alpha__) && defined(__GNUC__)
184
__asm __volatile__ ("mov $30,%0"
190
fprintf(stderr, "frame pointer is NULL, did you compile with\n\
191
-fomit-frame-pointer? Aborting backtrace!\n");
195
if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
197
ulong tmp= min(0x10000,thread_stack);
198
/* Assume that the stack starts at the previous even 65K */
199
stack_bottom= (uchar*) (((ulong) &fp + tmp) &
201
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
203
if (fp > (uchar**) stack_bottom ||
204
fp < (uchar**) stack_bottom - thread_stack)
206
fprintf(stderr, "Bogus stack limit or frame pointer,\
207
fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
208
fp, stack_bottom, thread_stack);
212
fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
213
#if defined(__alpha__) && defined(__GNUC__)
214
fprintf(stderr, "Warning: Alpha stacks are difficult -\
215
will be taking some wild guesses, stack trace may be incorrect or \
216
terminate abruptly\n");
217
/* On Alpha, we need to get pc */
218
__asm __volatile__ ("bsr %0, do_next; do_next: "
221
#endif /* __alpha__ */
223
/* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
224
sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
226
while (fp < (uchar**) stack_bottom)
228
#if defined(__i386__) || defined(__x86_64__)
229
uchar** new_fp = (uchar**)*fp;
230
fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
231
*(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
232
#endif /* defined(__386__) || defined(__x86_64__) */
234
#if defined(__alpha__) && defined(__GNUC__)
235
uchar** new_fp = find_prev_fp(pc, fp);
236
if (frame_count == sigreturn_frame_count - 1)
243
pc = find_prev_pc(pc, fp);
245
fprintf(stderr, "%p\n", pc);
248
fprintf(stderr, "Not smart enough to deal with the rest\
255
fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
258
#endif /* defined(__alpha__) && defined(__GNUC__) */
261
fprintf(stderr, "New value of fp=%p failed sanity check,\
262
terminating stack trace!\n", new_fp);
269
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
273
"Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
274
"and follow instructions on how to resolve the stack trace.\n"
275
"Resolved stack trace is much more helpful in diagnosing the\n"
276
"problem, so please do resolve it\n");
278
#endif /* TARGET_OS_LINUX */
279
#endif /* HAVE_STACKTRACE */
281
/* Produce a core for the thread */
283
void write_core(int sig)
285
signal(sig, SIG_DFL);
288
For GCOV build, crashing will prevent the writing of code coverage
289
information from this process, causing gcov output to be incomplete.
290
So we force the writing of coverage information here before terminating.
292
extern void __gcov_flush(void);
295
pthread_kill(pthread_self(), sig);
296
#if defined(P_MYID) && !defined(SCO)
297
/* On Solaris, the above kill is not enough */
298
sigsend(P_PID,P_MYID,sig);