mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Cleanup up stacktrace code
Updated qsort source from glibc. Add debugging of keycache when EXTRA_DEBUG is specified
This commit is contained in:
@ -43451,18 +43451,23 @@ your actual @strong{MySQL} server either way. Free of charge. See
|
||||
Created by Laurent Bossavit of NetDIVE.
|
||||
@strong{NOTE:} Doesn't work with Access2!
|
||||
|
||||
@item @uref{http://www.mysql.com/Downloads/Contrib/msql2mysqlWrapper-1.0.tgz, /msql2mysqlWrapper 1.0}
|
||||
@item @uref{http://www.mysql.com/Downloads/Contrib/mdb2sql.bas, mdb2sql.bas}
|
||||
Converter from Access97 to @strong{MySQL} by Moshe Gurvich.
|
||||
|
||||
@item @uref{http://www.mysql.com/Downloads/Contrib/msql2mysqlWrapper-1.0.tgz, msql2mysqlWrapper 1.0}
|
||||
A C wrapper from @code{mSQL} to @strong{MySQL}. By @email{alfred@@sb.net}
|
||||
|
||||
@item @uref{http://www.mysql.com/Downloads/Contrib/sqlconv.pl, sqlconv.pl}
|
||||
A simple script that can be used to copy fields from one @strong{MySQL} table to
|
||||
another in bulk. Basically, you can run @code{mysqldump} and pipe it to
|
||||
A simple script that can be used to copy fields from one @strong{MySQL} table
|
||||
to another in bulk. Basically, you can run @code{mysqldump} and pipe it to
|
||||
the @code{sqlconv.pl} script. The script will parse through the
|
||||
@code{mysqldump} output and will rearrange the fields so they can be
|
||||
inserted into a new table. An example is when you want to create a new
|
||||
table for a different site you are working on, but the table is just a
|
||||
bit different (that is - fields in different order, etc.).
|
||||
By Steve Shreeve.
|
||||
@item @uref{http://www.mysql.com/Downloads/Contrib/oracledump, oracledump}
|
||||
Perl program to convert Oracle databases to @strong{MySQL}. By Johan Andersson.
|
||||
@end itemize
|
||||
|
||||
@appendixsec Using MySQL with Other Products
|
||||
|
3
bdb/dist/Makefile.in
vendored
3
bdb/dist/Makefile.in
vendored
@ -997,3 +997,6 @@ strerror@o@: $(srcdir)/clib/strerror.c
|
||||
$(CC) $(CFLAGS) $?
|
||||
vsnprintf@o@: $(srcdir)/clib/vsnprintf.c
|
||||
$(CC) $(CFLAGS) $?
|
||||
|
||||
# Don't update the files from bitkeeper
|
||||
%::SCCS/s.%
|
||||
|
@ -232,7 +232,7 @@ static inline void link_file_to_changed(SEC_LINK *next)
|
||||
}
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
#if !defined(DBUG_OFF) && !defined(EXTRA_DEBUG)
|
||||
#define DBUG_OFF /* This should work */
|
||||
#endif
|
||||
|
||||
|
155
mysys/mf_qsort.c
155
mysys/mf_qsort.c
@ -1,40 +1,28 @@
|
||||
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
||||
/* Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA */
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Plug-compatible replacement for UNIX qsort.
|
||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
||||
Written by Douglas C. Schmidt (schmidt@ics.uci.edu)
|
||||
Optimized and modyfied for mysys by monty.
|
||||
|
||||
This file is part of GNU CC.
|
||||
|
||||
GNU QSORT 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 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
GNU QSORT 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 GNU QSORT; see the file COPYING. If not, write to
|
||||
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
/*
|
||||
Modifications by monty:
|
||||
- Uses mysys include files
|
||||
- Small fixes to make the it a bit faster
|
||||
- Can be compiled with a cmp function that takes one extra argument.
|
||||
*/
|
||||
|
||||
#include "mysys_priv.h"
|
||||
|
||||
@ -46,24 +34,22 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#endif
|
||||
|
||||
/* Byte-wise swap two items of size SIZE. */
|
||||
#define SWAP(A,B,SIZE) do {int sz=(int)(SIZE); char *a = (A); char *b = (B); \
|
||||
do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0)
|
||||
|
||||
/* Copy SIZE bytes from item B to item A. */
|
||||
#define COPY(A,B,SIZE) {int sz = (int) (SIZE); do { *(A)++ = *(B)++; } while (--sz); }
|
||||
|
||||
/* This should be replaced by a standard ANSI macro. */
|
||||
#define BYTES_PER_WORD 8
|
||||
|
||||
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
||||
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
|
||||
#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
|
||||
#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
|
||||
#define STACK_NOT_EMPTY (stack < top)
|
||||
#define SWAP(a, b, size) \
|
||||
do \
|
||||
{ \
|
||||
register size_t __size = (size); \
|
||||
register char *__a = (a), *__b = (b); \
|
||||
do \
|
||||
{ \
|
||||
char __tmp = *__a; \
|
||||
*__a++ = *__b; \
|
||||
*__b++ = __tmp; \
|
||||
} while (--__size > 0); \
|
||||
} while (0)
|
||||
|
||||
/* Discontinue quicksort algorithm when partition gets below this size.
|
||||
This particular magic number was chosen to work best on a Sparc SLC. */
|
||||
#define MAX_THRESH 12
|
||||
This particular magic number was chosen to work best on a Sun 4/260. */
|
||||
#define MAX_THRESH 8
|
||||
|
||||
/* Stack node declarations used to store unfulfilled partition obligations. */
|
||||
typedef struct
|
||||
@ -72,6 +58,12 @@ typedef struct
|
||||
char *hi;
|
||||
} stack_node;
|
||||
|
||||
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
||||
#define STACK_SIZE (8 * sizeof(unsigned long int))
|
||||
#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
|
||||
#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
|
||||
#define STACK_NOT_EMPTY (stack < top)
|
||||
|
||||
/* Order size using quicksort. This implementation incorporates
|
||||
four optimizations discussed in Sedgewick:
|
||||
|
||||
@ -88,7 +80,7 @@ typedef struct
|
||||
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
||||
insertion sort to order the MAX_THRESH items within each partition.
|
||||
This is a big win, since insertion sort is faster for small, mostly
|
||||
sorted array segements.
|
||||
sorted array segments.
|
||||
|
||||
4. The larger of the two sub-partitions is always pushed onto the
|
||||
stack first, with the algorithm then concentrating on the
|
||||
@ -111,34 +103,31 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
/* Allocating SIZE bytes for a pivot buffer facilitates a better
|
||||
algorithm below since we can do comparisons directly on the pivot.
|
||||
*/
|
||||
int max_thresh = (int) (MAX_THRESH * size);
|
||||
size_t max_thresh = (size_t) (MAX_THRESH * size);
|
||||
if (total_elems <= 1)
|
||||
SORT_RETURN; /* Crashes on MSDOS if continues */
|
||||
|
||||
if (total_elems > MAX_THRESH)
|
||||
{
|
||||
char *lo = base_ptr;
|
||||
char *hi = lo + size * (total_elems - 1);
|
||||
char *hi = &lo[size * (total_elems - 1)];
|
||||
stack_node stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
|
||||
stack_node *top = stack + 1;
|
||||
char *pivot_buffer = (char *) my_alloca ((int) size);
|
||||
char *pivot = (char *) my_alloca ((int) size);
|
||||
#ifdef HAVE_purify
|
||||
stack[0].lo=stack[0].hi=0;
|
||||
#endif
|
||||
|
||||
while (STACK_NOT_EMPTY)
|
||||
{
|
||||
char *left_ptr;
|
||||
char *right_ptr;
|
||||
{
|
||||
char *pivot = pivot_buffer;
|
||||
do
|
||||
{
|
||||
char *left_ptr,*right_ptr;
|
||||
|
||||
/* Select median value from among LO, MID, and HI. Rearrange
|
||||
LO and HI so the three values are sorted. This lowers the
|
||||
probability of picking a pathological pivot value and
|
||||
skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
|
||||
|
||||
char *mid = lo + size * (((uint) (hi - lo) / (uint) size) >> 1);
|
||||
char *mid = lo + size * (((ulong) (hi - lo) / (ulong) size) >> 1);
|
||||
|
||||
if (CMP(hi,lo) < 0)
|
||||
SWAP (hi, lo, size);
|
||||
@ -146,9 +135,8 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
SWAP (mid, lo, size);
|
||||
else if (CMP (hi, mid) < 0)
|
||||
SWAP (mid, hi, size);
|
||||
COPY (pivot, mid, size);
|
||||
pivot = pivot_buffer;
|
||||
}
|
||||
memcpy (pivot, mid, size);
|
||||
|
||||
left_ptr = lo + size;
|
||||
right_ptr = hi - size;
|
||||
|
||||
@ -175,36 +163,38 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
right_ptr -= size;
|
||||
break;
|
||||
}
|
||||
else
|
||||
break; /* left_ptr > right_ptr */
|
||||
}
|
||||
while (left_ptr <= right_ptr);
|
||||
}
|
||||
|
||||
|
||||
/* Set up pointers for next iteration. First determine whether
|
||||
left and right partitions are below the threshold size. If so,
|
||||
ignore one or both. Otherwise, push the larger partition's
|
||||
bounds on the stack and continue sorting the smaller one. */
|
||||
|
||||
if ((right_ptr - lo) <= max_thresh)
|
||||
if ((size_t) (right_ptr - lo) <= max_thresh)
|
||||
{
|
||||
if ((hi - left_ptr) <= max_thresh) /* Ignore both small parts. */
|
||||
POP (lo, hi);
|
||||
else /* Ignore small left part. */
|
||||
if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||
POP (lo, hi); /* Ignore both small partitions. */
|
||||
else
|
||||
lo = left_ptr; /* Ignore small left part. */
|
||||
}
|
||||
else if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||
hi = right_ptr; /* Ignore small right partition. */
|
||||
else if ((right_ptr - lo) > (hi - left_ptr))
|
||||
{
|
||||
PUSH (lo, right_ptr); /* Push larger left part */
|
||||
lo = left_ptr;
|
||||
}
|
||||
else if ((hi - left_ptr) <= max_thresh) /* Ignore small right part. */
|
||||
hi = right_ptr;
|
||||
else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left part */
|
||||
else
|
||||
{
|
||||
PUSH (lo, right_ptr);
|
||||
lo = left_ptr;
|
||||
}
|
||||
else /* Push larger right part */
|
||||
{
|
||||
PUSH (left_ptr, hi);
|
||||
PUSH (left_ptr, hi); /* Push larger right part */
|
||||
hi = right_ptr;
|
||||
}
|
||||
}
|
||||
my_afree(pivot_buffer);
|
||||
} while (STACK_NOT_EMPTY);
|
||||
my_afree(pivot);
|
||||
}
|
||||
|
||||
/* Once the BASE_PTR array is partially sorted by quicksort the rest
|
||||
@ -215,9 +205,9 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
|
||||
{
|
||||
char *end_ptr = (char*) base_ptr + size * (total_elems - 1);
|
||||
char *run_ptr;
|
||||
char *tmp_ptr = (char*) base_ptr;
|
||||
char *thresh = min (end_ptr, (char*) base_ptr + max_thresh);
|
||||
register char *run_ptr;
|
||||
|
||||
/* Find smallest element in first threshold and place it at the
|
||||
array's beginning. This is the smallest array element,
|
||||
@ -230,18 +220,18 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
if (tmp_ptr != (char*) base_ptr)
|
||||
SWAP (tmp_ptr, (char*) base_ptr, size);
|
||||
|
||||
/* Insertion sort, running from left-hand-side up to `right-hand-side.'
|
||||
Pretty much straight out of the original GNU qsort routine. */
|
||||
/* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||
|
||||
for (run_ptr = (char*) base_ptr + size;
|
||||
(tmp_ptr = run_ptr += size) <= end_ptr; )
|
||||
(run_ptr += size) <= end_ptr; )
|
||||
{
|
||||
while (CMP (run_ptr, tmp_ptr -= size) < 0) ;
|
||||
|
||||
if ((tmp_ptr += size) != run_ptr)
|
||||
if (CMP (run_ptr, (tmp_ptr = run_ptr-size)) < 0)
|
||||
{
|
||||
char *trav;
|
||||
while (CMP (run_ptr, tmp_ptr -= size) < 0) ;
|
||||
tmp_ptr += size;
|
||||
|
||||
/* Shift down all smaller elements, put found element in 'run_ptr' */
|
||||
for (trav = run_ptr + size; --trav >= run_ptr;)
|
||||
{
|
||||
char c = *trav;
|
||||
@ -252,7 +242,6 @@ qsort_t qsort(void *base_ptr, size_t total_elems, size_t size, qsort_cmp cmp)
|
||||
*hi = c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SORT_RETURN;
|
||||
|
@ -54,7 +54,8 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
||||
ha_gemini.h opt_range.h opt_ft.h \
|
||||
sql_select.h structs.h table.h sql_udf.h hash_filo.h\
|
||||
lex.h lex_symbol.h sql_acl.h sql_crypt.h md5.h \
|
||||
log_event.h mini_client.h sql_repl.h slave.h
|
||||
log_event.h mini_client.h sql_repl.h slave.h \
|
||||
stacktrace.h
|
||||
mysqld_SOURCES = sql_lex.cc \
|
||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
|
||||
@ -67,17 +68,19 @@ mysqld_SOURCES = sql_lex.cc \
|
||||
sql_base.cc table.cc sql_select.cc sql_insert.cc \
|
||||
sql_update.cc sql_delete.cc \
|
||||
procedure.cc item_uniq.cc sql_test.cc \
|
||||
log.cc init.cc derror.cc sql_acl.cc unireg.cc \
|
||||
log.cc log_event.cc init.cc derror.cc sql_acl.cc \
|
||||
unireg.cc \
|
||||
time.cc opt_range.cc opt_sum.cc opt_ft.cc \
|
||||
records.cc filesort.cc handler.cc \
|
||||
ha_isam.cc ha_isammrg.cc ha_heap.cc \
|
||||
ha_myisam.cc ha_myisammrg.cc ha_berkeley.cc \
|
||||
ha_innobase.cc ha_gemini.cc \
|
||||
ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
|
||||
ha_berkeley.cc ha_innobase.cc ha_gemini.cc \
|
||||
ha_isam.cc ha_isammrg.cc \
|
||||
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
|
||||
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
|
||||
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
|
||||
slave.cc sql_repl.cc \
|
||||
md5.c log_event.cc mini_client.cc mini_client_errors.c
|
||||
mini_client.cc mini_client_errors.c \
|
||||
md5.c stacktrace.c
|
||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||
mysqlbinlog_SOURCES = mysqlbinlog.cc mini_client.cc net_serv.cc \
|
||||
|
278
sql/mysqld.cc
278
sql/mysqld.cc
@ -20,6 +20,7 @@
|
||||
#include <my_dir.h>
|
||||
#include "sql_acl.h"
|
||||
#include "slave.h"
|
||||
#include "stacktrace.h"
|
||||
#ifdef HAVE_BERKELEY_DB
|
||||
#include "ha_berkeley.h"
|
||||
#endif
|
||||
@ -1124,217 +1125,13 @@ static void start_signal_handler(void)
|
||||
|
||||
#else /* if ! __WIN__ && ! __EMX__ */
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
static sig_handler write_core(int sig);
|
||||
|
||||
#if defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))
|
||||
#define LINUX_STACK_TRACE
|
||||
#endif
|
||||
|
||||
#ifdef LINUX_STACK_TRACE
|
||||
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
|
||||
|
||||
extern char* __bss_start;
|
||||
static char* heap_start, *heap_end;
|
||||
|
||||
inline __volatile__ void print_str(const char* name,
|
||||
const char* val, int max_len)
|
||||
{
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef LINUX_STACK_TRACE
|
||||
#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
|
||||
|
||||
inline __volatile__ void trace_stack()
|
||||
{
|
||||
uchar **stack_bottom;
|
||||
uchar** fp;
|
||||
LINT_INIT(fp);
|
||||
LINT_INIT(stack_bottom);
|
||||
|
||||
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");
|
||||
THD* thd = current_thd;
|
||||
uint frame_count = 0;
|
||||
#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 (!thd)
|
||||
{
|
||||
fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", fp);
|
||||
/* Assume that the stack starts at the previous even 65K */
|
||||
ulong tmp= min(0x10000,thread_stack);
|
||||
stack_bottom= (uchar**) (((ulong) &stack_bottom + tmp) &
|
||||
~(ulong) 0xFFFF);
|
||||
}
|
||||
else
|
||||
stack_bottom = (uchar**) thd->thread_stack;
|
||||
if (fp > stack_bottom || fp < 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
|
||||
uint32* pc;
|
||||
__asm __volatile__ ("bsr %0, do_next; do_next: "
|
||||
:"=r"(pc)
|
||||
:"r"(pc));
|
||||
#endif /* __alpha__ */
|
||||
|
||||
while (fp < stack_bottom)
|
||||
{
|
||||
#ifdef __i386__
|
||||
uchar** new_fp = (uchar**)*fp;
|
||||
fprintf(stderr, "%p\n", frame_count == SIGRETURN_FRAME_COUNT ?
|
||||
*(fp+17) : *(fp+1));
|
||||
#endif
|
||||
#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 print_glob_vars;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Not smart enough to deal with the rest of\
|
||||
this stack\n");
|
||||
goto print_glob_vars;
|
||||
}
|
||||
#endif
|
||||
if (new_fp <= fp )
|
||||
{
|
||||
fprintf(stderr, "New value of fp=%p failed sanity check,\
|
||||
terminating stack trace!\n", new_fp);
|
||||
goto print_glob_vars;
|
||||
}
|
||||
fp = new_fp;
|
||||
++frame_count;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Stack trace seems successful - bottom reached\n");
|
||||
|
||||
print_glob_vars:
|
||||
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");
|
||||
fprintf(stderr, "Trying to get some variables.\n\
|
||||
Some pointers may be invalid and cause the dump to abort...\n");
|
||||
heap_end = (char*)sbrk(0);
|
||||
print_str("thd->query", thd->query, 1024);
|
||||
fprintf(stderr, "thd->thread_id = %ld\n", thd->thread_id);
|
||||
fprintf(stderr, "Successfully dumped variables, if you ran with --log,\n\
|
||||
take a look at the details of what thread %ld did to cause the crash.\n\
|
||||
In some cases of really bad corruption, this value may be invalid\n",
|
||||
thd->thread_id);
|
||||
fprintf(stderr, "Please use the information above to create a repeatable\n\
|
||||
test case for the crash, and send it to bugs@lists.mysql.com\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
||||
#endif
|
||||
|
||||
static sig_handler handle_segfault(int sig)
|
||||
{
|
||||
THD *thd=current_thd;
|
||||
// strictly speaking, one needs a mutex here
|
||||
// but since we have got SIGSEGV already, things are a mess
|
||||
// so not having the mutex is not as bad as possibly using a buggy
|
||||
@ -1348,13 +1145,14 @@ static sig_handler handle_segfault(int sig)
|
||||
segfaulted = 1;
|
||||
fprintf(stderr,"\
|
||||
mysqld got signal %d;\n\
|
||||
This could be because you hit a bug. It is also possible that \n\
|
||||
this binary or one of the libraries it was linked agaist is \n\
|
||||
corrupt, improperly built, or misconfigured. This error can also be\n\
|
||||
caused by malfunctioning hardware.", sig);
|
||||
fprintf(stderr, "We will try our best to scrape up some info\n\
|
||||
that will hopefully help diagnose the problem, but since we have already\n\
|
||||
crashed, something is definitely wrong and this may fail\n");
|
||||
This could be because you hit a bug. It is also possible that this binary\n\
|
||||
or one of the libraries it was linked agaist is corrupt, improperly built,\n\
|
||||
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
|
||||
sig);
|
||||
fprintf(stderr, "\
|
||||
We will try our best to scrape up some info that will hopefully help diagnose\n\
|
||||
the problem, but since we have already crashed, something is definitely wrong\n\
|
||||
and this may fail\n\n");
|
||||
fprintf(stderr, "key_buffer_size=%ld\n", keybuff_size);
|
||||
fprintf(stderr, "record_buffer=%ld\n", my_default_record_cache_size);
|
||||
fprintf(stderr, "sort_buffer=%ld\n", sortbuff_size);
|
||||
@ -1365,42 +1163,47 @@ crashed, something is definitely wrong and this may fail\n");
|
||||
key_buffer_size + (record_buffer + sort_buffer)*max_connections = %ld K\n\
|
||||
bytes of memory\n", (keybuff_size + (my_default_record_cache_size +
|
||||
sortbuff_size) * max_connections)/ 1024);
|
||||
fprintf(stderr, "Hope that's ok, if not, decrease some variables in the\n\
|
||||
equation\n");
|
||||
fprintf(stderr, "Hope that's ok, if not, decrease some variables in the equation\n\n");
|
||||
|
||||
#if defined(HAVE_LINUXTHREADS)
|
||||
|
||||
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
|
||||
{
|
||||
fprintf(stderr, "You seem to be running 32-bit Linux and\n\
|
||||
have %d concurrent connections. If you have not\n\
|
||||
changed STACK_SIZE in LinuxThreads and build the binary yourself,\n\
|
||||
LinuxThreads is quite likely to steal a part of global heap for a \n\
|
||||
thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n",
|
||||
fprintf(stderr, "\
|
||||
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
|
||||
If you have not changed STACK_SIZE in LinuxThreads and build the binary \n\
|
||||
yourself, LinuxThreads is quite likely to steal a part of global heap for\n\
|
||||
the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
|
||||
thread_count);
|
||||
}
|
||||
#ifdef LINUX_STACK_TRACE
|
||||
#endif /* HAVE_LINUXTHREADS */
|
||||
|
||||
#ifdef HAVE_STACKTRACE
|
||||
if(!(test_flags & TEST_NO_STACKTRACE))
|
||||
trace_stack();
|
||||
print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0,
|
||||
thread_stack);
|
||||
if (thd)
|
||||
{
|
||||
fprintf(stderr, "Trying to get some variables.\n\
|
||||
Some pointers may be invalid and cause the dump to abort...\n");
|
||||
safe_print_str("thd->query", thd->query, 1024);
|
||||
fprintf(stderr, "thd->thread_id=%ld\n", thd->thread_id);
|
||||
fprintf(stderr, "\n
|
||||
Successfully dumped variables, if you ran with --log, take a look at the\n\
|
||||
details of what thread %ld did to cause the crash. In some cases of really\n\
|
||||
bad corruption, the above values may be invalid\n\n",
|
||||
thd->thread_id);
|
||||
}
|
||||
fprintf(stderr, "\
|
||||
Please use the information above to create a repeatable test case for the\n\
|
||||
crash, and send it to bugs@lists.mysql.com\n");
|
||||
fflush(stderr);
|
||||
#endif /* LINUX_STACK_TRACE */
|
||||
#endif /* HAVE_STACKTRACE */
|
||||
|
||||
if (test_flags & TEST_CORE_ON_SIGNAL)
|
||||
write_core(sig);
|
||||
#endif /* HAVE_LINUXTHREADS */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Produce a core for the thread */
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
static sig_handler write_core(int sig)
|
||||
{
|
||||
signal(sig, SIG_DFL);
|
||||
if (fork() != 0) exit(1); // Abort main program
|
||||
// Core will be written at exit
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void init_signals(void)
|
||||
{
|
||||
@ -1413,12 +1216,9 @@ static void init_signals(void)
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
|
||||
|
||||
#ifdef LINUX_STACK_TRACE
|
||||
heap_start = (char*)&__bss_start;
|
||||
#endif
|
||||
|
||||
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
|
||||
{
|
||||
init_stacktrace();
|
||||
sa.sa_handler=handle_segfault;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
#ifdef SIGBUS
|
||||
|
215
sql/stacktrace.c
Normal file
215
sql/stacktrace.c
Normal file
@ -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 */
|
51
sql/stacktrace.h
Normal file
51
sql/stacktrace.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* 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 */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LINUXTHREADS
|
||||
#if defined(HAVE_STACKTRACE) || (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__)))
|
||||
#undef HAVE_STACKTRACE
|
||||
#define HAVE_STACKTRACE
|
||||
|
||||
extern char* __bss_start;
|
||||
extern char* heap_start;
|
||||
|
||||
#define init_stacktrace() { heap_start = (char*) &__bss_start; }
|
||||
void print_stacktrace(gptr stack_bottom, ulong thread_stack);
|
||||
void safe_print_str(const char* name, const char* val, int max_len);
|
||||
#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
|
||||
|
||||
#define HAVE_WRITE_CORE
|
||||
void write_core(int sig);
|
||||
#endif /* HAVE_LINUXTHREADS */
|
||||
|
||||
/* Define empty prototypes for functions that are not implemented */
|
||||
#ifndef HAVE_STACKTRACE
|
||||
#define init_stacktrace() {}
|
||||
#define print_stacktrace(A,B) {}
|
||||
#define safe_print_str(A,B,C) {}
|
||||
#endif /* HAVE_STACKTRACE */
|
||||
|
||||
#ifndef HAVE_WRITE_CORE
|
||||
#define write_core(A) {}
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user