diff options
author | monty@donna.mysql.fi <> | 2001-05-14 01:12:40 +0300 |
---|---|---|
committer | monty@donna.mysql.fi <> | 2001-05-14 01:12:40 +0300 |
commit | 329382c1e5065fa06554eee17479bb303869dcda (patch) | |
tree | cb1a5610599f1fc83e5df7ee8022395b7899f909 /sql/stacktrace.c | |
parent | a4289cc0c8208098c7cb0602c368237bb53cb1a7 (diff) | |
download | mariadb-git-329382c1e5065fa06554eee17479bb303869dcda.tar.gz |
Cleanup up stacktrace code
Updated qsort source from glibc.
Add debugging of keycache when EXTRA_DEBUG is specified
Diffstat (limited to 'sql/stacktrace.c')
-rw-r--r-- | sql/stacktrace.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/sql/stacktrace.c b/sql/stacktrace.c new file mode 100644 index 00000000000..ba5bc9d2e85 --- /dev/null +++ b/sql/stacktrace.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2000 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <global.h> +#include "stacktrace.h" +#include <signal.h> + +#ifdef HAVE_STACKTRACE +#include <unistd.h> + +#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end) + +char *heap_start; + +void safe_print_str(const char* name, const char* val, int max_len) +{ + char *heap_end= (char*) sbrk(0); + fprintf(stderr, "%s at %p ", name, val); + + if (!PTR_SANE(val)) + { + fprintf(stderr, " is invalid pointer\n"); + return; + } + + fprintf(stderr, "= "); + for(; max_len && PTR_SANE(val) && *val; --max_len) + fputc(*val++, stderr); + fputc('\n', stderr); +} + +#ifdef HAVE_LINUXTHREADS +#define SIGRETURN_FRAME_COUNT 1 + +#if defined(__alpha__) && defined(__GNUC__) +/* + The only way to backtrace without a symbol table on alpha + is to find stq fp,N(sp), and the first byte + of the instruction opcode will give us the value of N. From this + we can find where the old value of fp is stored +*/ + +#define MAX_INSTR_IN_FUNC 10000 + +inline uchar** find_prev_fp(uint32* pc, uchar** fp) +{ + int i; + for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + { + uchar* p = (uchar*)pc; + if (p[2] == 222 && p[3] == 35) + { + return (uchar**)((uchar*)fp - *(short int*)p); + } + } + return 0; +} + +inline uint32* find_prev_pc(uint32* pc, uchar** fp) +{ + int i; + for(i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc) + { + char* p = (char*)pc; + if (p[1] == 0 && p[2] == 94 && p[3] == -73) + { + uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp))); + return prev_pc; + } + } + return 0; +} +#endif /* defined(__alpha__) && defined(__GNUC__) */ + + +void print_stacktrace(gptr stack_bottom, ulong thread_stack) +{ + uchar** fp; + uint frame_count = 0; +#if defined(__alpha__) && defined(__GNUC__) + uint32* pc; +#endif + LINT_INIT(fp); + + fprintf(stderr,"\ +Attempting backtrace. You can use the following information to find out\n\ +where mysqld died. If you see no messages after this, something went\n\ +terribly wrong...\n"); +#ifdef __i386__ + __asm __volatile__ ("movl %%ebp,%0" + :"=r"(fp) + :"r"(fp)); + if (!fp) + { + fprintf(stderr, "frame pointer (ebp) is NULL, did you compile with\n\ +-fomit-frame-pointer? Aborting backtrace!\n"); + return; + } +#endif +#if defined(__alpha__) && defined(__GNUC__) + __asm __volatile__ ("mov $15,%0" + :"=r"(fp) + :"r"(fp)); + if (!fp) + { + fprintf(stderr, "frame pointer (fp) is NULL, did you compile with\n\ +-fomit-frame-pointer? Aborting backtrace!\n"); + return; + } +#endif /* __alpha__ */ + + if (!stack_bottom) + { + ulong tmp= min(0x10000,thread_stack); + /* Assume that the stack starts at the previous even 65K */ + stack_bottom= (gptr) (((ulong) &fp + tmp) & + ~(ulong) 0xFFFF); + fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp); + } + if (fp > (uchar**) stack_bottom || + fp < (uchar**) stack_bottom - thread_stack) + { + fprintf(stderr, "Bogus stack limit or frame pointer,\ + fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n", + fp, stack_bottom, thread_stack); + return; + } + + fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n"); +#if defined(__alpha__) && defined(__GNUC__) + fprintf(stderr, "Warning: Alpha stacks are difficult -\ + will be taking some wild guesses, stack trace may be incorrect or \ + terminate abruptly\n"); + // On Alpha, we need to get pc + __asm __volatile__ ("bsr %0, do_next; do_next: " + :"=r"(pc) + :"r"(pc)); +#endif /* __alpha__ */ + + while (fp < (uchar**) stack_bottom) + { +#ifdef __i386__ + uchar** new_fp = (uchar**)*fp; + fprintf(stderr, "%p\n", frame_count == SIGRETURN_FRAME_COUNT ? + *(fp+17) : *(fp+1)); +#endif /* __386__ */ + +#if defined(__alpha__) && defined(__GNUC__) + uchar** new_fp = find_prev_fp(pc, fp); + if (frame_count == SIGRETURN_FRAME_COUNT - 1) + { + new_fp += 90; + } + + if (fp && pc) + { + pc = find_prev_pc(pc, fp); + if (pc) + fprintf(stderr, "%p\n", pc); + else + { + fprintf(stderr, "Not smart enough to deal with the rest\ + of this stack\n"); + goto end; + } + } + else + { + fprintf(stderr, "Not smart enough to deal with the rest of this stack\n"); + goto end; + } +#endif /* defined(__alpha__) && defined(__GNUC__) */ + if (new_fp <= fp ) + { + fprintf(stderr, "New value of fp=%p failed sanity check,\ + terminating stack trace!\n", new_fp); + goto end; + } + fp = new_fp; + ++frame_count; + } + + fprintf(stderr, "Stack trace seems successful - bottom reached\n"); + +end: + fprintf(stderr, "Please read http://www.mysql.com/doc/U/s/Using_stack_trace.html and follow instructions on how to resolve the stack trace. Resolved\n\ +stack trace is much more helpful in diagnosing the problem, so please do \n\ +resolve it\n"); +} +#endif /* HAVE_LINUXTHREADS */ +#endif /* HAVE_STACKTRACE */ + +/* Produce a core for the thread */ + +#ifdef HAVE_WRITE_CORE +void write_core(int sig) +{ + signal(sig, SIG_DFL); + if (fork() != 0) exit(1); // Abort main program + // Core will be written at exit +} +#endif /* HAVE_WRITE_CORE */ |