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.
|
Created by Laurent Bossavit of NetDIVE.
|
||||||
@strong{NOTE:} Doesn't work with Access2!
|
@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}
|
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}
|
@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
|
A simple script that can be used to copy fields from one @strong{MySQL} table
|
||||||
another in bulk. Basically, you can run @code{mysqldump} and pipe it to
|
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
|
the @code{sqlconv.pl} script. The script will parse through the
|
||||||
@code{mysqldump} output and will rearrange the fields so they can be
|
@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
|
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
|
table for a different site you are working on, but the table is just a
|
||||||
bit different (that is - fields in different order, etc.).
|
bit different (that is - fields in different order, etc.).
|
||||||
By Steve Shreeve.
|
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
|
@end itemize
|
||||||
|
|
||||||
@appendixsec Using MySQL with Other Products
|
@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) $?
|
$(CC) $(CFLAGS) $?
|
||||||
vsnprintf@o@: $(srcdir)/clib/vsnprintf.c
|
vsnprintf@o@: $(srcdir)/clib/vsnprintf.c
|
||||||
$(CC) $(CFLAGS) $?
|
$(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 */
|
#define DBUG_OFF /* This should work */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
159
mysys/mf_qsort.c
159
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
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Library General Public
|
modify it under the terms of the GNU Library General Public License as
|
||||||
License as published by the Free Software Foundation; either
|
published by the Free Software Foundation; either version 2 of the
|
||||||
version 2 of the License, or (at your option) any later version.
|
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
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Library General Public License for more details.
|
Library General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
You should have received a copy of the GNU Library General Public
|
||||||
License along with this library; if not, write to the Free
|
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
MA 02111-1307, USA */
|
Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
/* Plug-compatible replacement for UNIX qsort.
|
/*
|
||||||
Copyright (C) 1989 Free Software Foundation, Inc.
|
Modifications by monty:
|
||||||
Written by Douglas C. Schmidt (schmidt@ics.uci.edu)
|
- Uses mysys include files
|
||||||
Optimized and modyfied for mysys by monty.
|
- Small fixes to make the it a bit faster
|
||||||
|
- Can be compiled with a cmp function that takes one extra argument.
|
||||||
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. */
|
|
||||||
|
|
||||||
#include "mysys_priv.h"
|
#include "mysys_priv.h"
|
||||||
|
|
||||||
@ -46,31 +34,35 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Byte-wise swap two items of size SIZE. */
|
/* Byte-wise swap two items of size SIZE. */
|
||||||
#define SWAP(A,B,SIZE) do {int sz=(int)(SIZE); char *a = (A); char *b = (B); \
|
#define SWAP(a, b, size) \
|
||||||
do { char _temp = *a;*a++ = *b;*b++ = _temp;} while (--sz);} while (0)
|
do \
|
||||||
|
{ \
|
||||||
/* Copy SIZE bytes from item B to item A. */
|
register size_t __size = (size); \
|
||||||
#define COPY(A,B,SIZE) {int sz = (int) (SIZE); do { *(A)++ = *(B)++; } while (--sz); }
|
register char *__a = (a), *__b = (b); \
|
||||||
|
do \
|
||||||
/* This should be replaced by a standard ANSI macro. */
|
{ \
|
||||||
#define BYTES_PER_WORD 8
|
char __tmp = *__a; \
|
||||||
|
*__a++ = *__b; \
|
||||||
/* The next 4 #defines implement a very fast in-line stack abstraction. */
|
*__b++ = __tmp; \
|
||||||
#define STACK_SIZE (BYTES_PER_WORD * sizeof (long))
|
} while (--__size > 0); \
|
||||||
#define PUSH(LOW,HIGH) do {top->lo = LOW;top++->hi = HIGH;} while (0)
|
} while (0)
|
||||||
#define POP(LOW,HIGH) do {LOW = (--top)->lo;HIGH = top->hi;} while (0)
|
|
||||||
#define STACK_NOT_EMPTY (stack < top)
|
|
||||||
|
|
||||||
/* Discontinue quicksort algorithm when partition gets below this size.
|
/* Discontinue quicksort algorithm when partition gets below this size.
|
||||||
This particular magic number was chosen to work best on a Sparc SLC. */
|
This particular magic number was chosen to work best on a Sun 4/260. */
|
||||||
#define MAX_THRESH 12
|
#define MAX_THRESH 8
|
||||||
|
|
||||||
/* Stack node declarations used to store unfulfilled partition obligations. */
|
/* Stack node declarations used to store unfulfilled partition obligations. */
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
char *lo;
|
char *lo;
|
||||||
char *hi;
|
char *hi;
|
||||||
} stack_node;
|
} 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
|
/* Order size using quicksort. This implementation incorporates
|
||||||
four optimizations discussed in Sedgewick:
|
four optimizations discussed in Sedgewick:
|
||||||
@ -88,7 +80,7 @@ typedef struct
|
|||||||
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
|
||||||
insertion sort to order the MAX_THRESH items within each partition.
|
insertion sort to order the MAX_THRESH items within each partition.
|
||||||
This is a big win, since insertion sort is faster for small, mostly
|
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
|
4. The larger of the two sub-partitions is always pushed onto the
|
||||||
stack first, with the algorithm then concentrating on 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
|
/* Allocating SIZE bytes for a pivot buffer facilitates a better
|
||||||
algorithm below since we can do comparisons directly on the pivot.
|
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)
|
if (total_elems <= 1)
|
||||||
SORT_RETURN; /* Crashes on MSDOS if continues */
|
SORT_RETURN; /* Crashes on MSDOS if continues */
|
||||||
|
|
||||||
if (total_elems > MAX_THRESH)
|
if (total_elems > MAX_THRESH)
|
||||||
{
|
{
|
||||||
char *lo = base_ptr;
|
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 stack[STACK_SIZE]; /* Largest size needed for 32-bit int!!! */
|
||||||
stack_node *top = stack + 1;
|
stack_node *top = stack + 1;
|
||||||
char *pivot_buffer = (char *) my_alloca ((int) size);
|
char *pivot = (char *) my_alloca ((int) size);
|
||||||
#ifdef HAVE_purify
|
#ifdef HAVE_purify
|
||||||
stack[0].lo=stack[0].hi=0;
|
stack[0].lo=stack[0].hi=0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (STACK_NOT_EMPTY)
|
do
|
||||||
{
|
|
||||||
char *left_ptr;
|
|
||||||
char *right_ptr;
|
|
||||||
{
|
|
||||||
char *pivot = pivot_buffer;
|
|
||||||
{
|
{
|
||||||
|
char *left_ptr,*right_ptr;
|
||||||
|
|
||||||
/* Select median value from among LO, MID, and HI. Rearrange
|
/* Select median value from among LO, MID, and HI. Rearrange
|
||||||
LO and HI so the three values are sorted. This lowers the
|
LO and HI so the three values are sorted. This lowers the
|
||||||
probability of picking a pathological pivot value and
|
probability of picking a pathological pivot value and
|
||||||
skips a comparison for both the LEFT_PTR and RIGHT_PTR. */
|
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)
|
if (CMP(hi,lo) < 0)
|
||||||
SWAP (hi, lo, size);
|
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);
|
SWAP (mid, lo, size);
|
||||||
else if (CMP (hi, mid) < 0)
|
else if (CMP (hi, mid) < 0)
|
||||||
SWAP (mid, hi, size);
|
SWAP (mid, hi, size);
|
||||||
COPY (pivot, mid, size);
|
memcpy (pivot, mid, size);
|
||||||
pivot = pivot_buffer;
|
|
||||||
}
|
|
||||||
left_ptr = lo + size;
|
left_ptr = lo + size;
|
||||||
right_ptr = hi - 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;
|
right_ptr -= size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
break; /* left_ptr > right_ptr */
|
||||||
}
|
}
|
||||||
while (left_ptr <= right_ptr);
|
while (left_ptr <= right_ptr);
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up pointers for next iteration. First determine whether
|
/* Set up pointers for next iteration. First determine whether
|
||||||
left and right partitions are below the threshold size. If so,
|
left and right partitions are below the threshold size. If so,
|
||||||
ignore one or both. Otherwise, push the larger partition's
|
ignore one or both. Otherwise, push the larger partition's
|
||||||
bounds on the stack and continue sorting the smaller one. */
|
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. */
|
if ((size_t) (hi - left_ptr) <= max_thresh)
|
||||||
POP (lo, hi);
|
POP (lo, hi); /* Ignore both small partitions. */
|
||||||
else /* Ignore small left part. */
|
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;
|
lo = left_ptr;
|
||||||
}
|
}
|
||||||
else if ((hi - left_ptr) <= max_thresh) /* Ignore small right part. */
|
else
|
||||||
hi = right_ptr;
|
|
||||||
else if ((right_ptr - lo) > (hi - left_ptr)) /* Push larger left part */
|
|
||||||
{
|
{
|
||||||
PUSH (lo, right_ptr);
|
PUSH (left_ptr, hi); /* Push larger right part */
|
||||||
lo = left_ptr;
|
|
||||||
}
|
|
||||||
else /* Push larger right part */
|
|
||||||
{
|
|
||||||
PUSH (left_ptr, hi);
|
|
||||||
hi = right_ptr;
|
hi = right_ptr;
|
||||||
}
|
}
|
||||||
}
|
} while (STACK_NOT_EMPTY);
|
||||||
my_afree(pivot_buffer);
|
my_afree(pivot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Once the BASE_PTR array is partially sorted by quicksort the rest
|
/* 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 *end_ptr = (char*) base_ptr + size * (total_elems - 1);
|
||||||
char *run_ptr;
|
|
||||||
char *tmp_ptr = (char*) base_ptr;
|
char *tmp_ptr = (char*) base_ptr;
|
||||||
char *thresh = min (end_ptr, (char*) base_ptr + max_thresh);
|
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
|
/* Find smallest element in first threshold and place it at the
|
||||||
array's beginning. This is the smallest array element,
|
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)
|
if (tmp_ptr != (char*) base_ptr)
|
||||||
SWAP (tmp_ptr, (char*) base_ptr, size);
|
SWAP (tmp_ptr, (char*) base_ptr, size);
|
||||||
|
|
||||||
/* Insertion sort, running from left-hand-side up to `right-hand-side.'
|
/* Insertion sort, running from left-hand-side up to right-hand-side. */
|
||||||
Pretty much straight out of the original GNU qsort routine. */
|
|
||||||
|
|
||||||
for (run_ptr = (char*) base_ptr + size;
|
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 (CMP (run_ptr, (tmp_ptr = run_ptr-size)) < 0)
|
||||||
|
|
||||||
if ((tmp_ptr += size) != run_ptr)
|
|
||||||
{
|
{
|
||||||
char *trav;
|
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;)
|
for (trav = run_ptr + size; --trav >= run_ptr;)
|
||||||
{
|
{
|
||||||
char c = *trav;
|
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;
|
*hi = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SORT_RETURN;
|
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 \
|
ha_gemini.h opt_range.h opt_ft.h \
|
||||||
sql_select.h structs.h table.h sql_udf.h hash_filo.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 \
|
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 \
|
mysqld_SOURCES = sql_lex.cc \
|
||||||
item.cc item_sum.cc item_buff.cc item_func.cc \
|
item.cc item_sum.cc item_buff.cc item_func.cc \
|
||||||
item_cmpfunc.cc item_strfunc.cc item_timefunc.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_base.cc table.cc sql_select.cc sql_insert.cc \
|
||||||
sql_update.cc sql_delete.cc \
|
sql_update.cc sql_delete.cc \
|
||||||
procedure.cc item_uniq.cc sql_test.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 \
|
time.cc opt_range.cc opt_sum.cc opt_ft.cc \
|
||||||
records.cc filesort.cc handler.cc \
|
records.cc filesort.cc handler.cc \
|
||||||
ha_isam.cc ha_isammrg.cc ha_heap.cc \
|
ha_heap.cc ha_myisam.cc ha_myisammrg.cc \
|
||||||
ha_myisam.cc ha_myisammrg.cc ha_berkeley.cc \
|
ha_berkeley.cc ha_innobase.cc ha_gemini.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_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
|
||||||
sql_load.cc mf_iocache.cc field_conv.cc sql_show.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 \
|
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
|
||||||
slave.cc sql_repl.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_SOURCES = gen_lex_hash.cc
|
||||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||||
mysqlbinlog_SOURCES = mysqlbinlog.cc mini_client.cc net_serv.cc \
|
mysqlbinlog_SOURCES = mysqlbinlog.cc mini_client.cc net_serv.cc \
|
||||||
|
280
sql/mysqld.cc
280
sql/mysqld.cc
@ -20,6 +20,7 @@
|
|||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
#include "sql_acl.h"
|
#include "sql_acl.h"
|
||||||
#include "slave.h"
|
#include "slave.h"
|
||||||
|
#include "stacktrace.h"
|
||||||
#ifdef HAVE_BERKELEY_DB
|
#ifdef HAVE_BERKELEY_DB
|
||||||
#include "ha_berkeley.h"
|
#include "ha_berkeley.h"
|
||||||
#endif
|
#endif
|
||||||
@ -1124,217 +1125,13 @@ static void start_signal_handler(void)
|
|||||||
|
|
||||||
#else /* if ! __WIN__ && ! __EMX__ */
|
#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
|
#ifdef HAVE_LINUXTHREADS
|
||||||
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
#define UNSAFE_DEFAULT_LINUX_THREADS 200
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static sig_handler handle_segfault(int sig)
|
static sig_handler handle_segfault(int sig)
|
||||||
{
|
{
|
||||||
|
THD *thd=current_thd;
|
||||||
// strictly speaking, one needs a mutex here
|
// strictly speaking, one needs a mutex here
|
||||||
// but since we have got SIGSEGV already, things are a mess
|
// 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
|
// 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;
|
segfaulted = 1;
|
||||||
fprintf(stderr,"\
|
fprintf(stderr,"\
|
||||||
mysqld got signal %d;\n\
|
mysqld got signal %d;\n\
|
||||||
This could be because you hit a bug. It is also possible that \n\
|
This could be because you hit a bug. It is also possible that this binary\n\
|
||||||
this binary or one of the libraries it was linked agaist is \n\
|
or one of the libraries it was linked agaist is corrupt, improperly built,\n\
|
||||||
corrupt, improperly built, or misconfigured. This error can also be\n\
|
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
|
||||||
caused by malfunctioning hardware.", sig);
|
sig);
|
||||||
fprintf(stderr, "We will try our best to scrape up some info\n\
|
fprintf(stderr, "\
|
||||||
that will hopefully help diagnose the problem, but since we have already\n\
|
We will try our best to scrape up some info that will hopefully help diagnose\n\
|
||||||
crashed, something is definitely wrong and this may fail\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, "key_buffer_size=%ld\n", keybuff_size);
|
||||||
fprintf(stderr, "record_buffer=%ld\n", my_default_record_cache_size);
|
fprintf(stderr, "record_buffer=%ld\n", my_default_record_cache_size);
|
||||||
fprintf(stderr, "sort_buffer=%ld\n", sortbuff_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\
|
key_buffer_size + (record_buffer + sort_buffer)*max_connections = %ld K\n\
|
||||||
bytes of memory\n", (keybuff_size + (my_default_record_cache_size +
|
bytes of memory\n", (keybuff_size + (my_default_record_cache_size +
|
||||||
sortbuff_size) * max_connections)/ 1024);
|
sortbuff_size) * max_connections)/ 1024);
|
||||||
fprintf(stderr, "Hope that's ok, if not, decrease some variables in the\n\
|
fprintf(stderr, "Hope that's ok, if not, decrease some variables in the equation\n\n");
|
||||||
equation\n");
|
|
||||||
|
|
||||||
#if defined(HAVE_LINUXTHREADS)
|
#if defined(HAVE_LINUXTHREADS)
|
||||||
|
if (sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
|
||||||
if(sizeof(char*) == 4 && thread_count > UNSAFE_DEFAULT_LINUX_THREADS)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "You seem to be running 32-bit Linux and\n\
|
fprintf(stderr, "\
|
||||||
have %d concurrent connections. If you have not\n\
|
You seem to be running 32-bit Linux and have %d concurrent connections.\n\
|
||||||
changed STACK_SIZE in LinuxThreads and build the binary yourself,\n\
|
If you have not changed STACK_SIZE in LinuxThreads and build the binary \n\
|
||||||
LinuxThreads is quite likely to steal a part of global heap for a \n\
|
yourself, LinuxThreads is quite likely to steal a part of global heap for\n\
|
||||||
thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n",
|
the thread stack. Please read http://www.mysql.com/doc/L/i/Linux.html\n\n",
|
||||||
thread_count);
|
thread_count);
|
||||||
}
|
}
|
||||||
#ifdef LINUX_STACK_TRACE
|
#endif /* HAVE_LINUXTHREADS */
|
||||||
|
|
||||||
|
#ifdef HAVE_STACKTRACE
|
||||||
if(!(test_flags & TEST_NO_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);
|
fflush(stderr);
|
||||||
#endif /* LINUX_STACK_TRACE */
|
#endif /* HAVE_STACKTRACE */
|
||||||
|
|
||||||
if (test_flags & TEST_CORE_ON_SIGNAL)
|
if (test_flags & TEST_CORE_ON_SIGNAL)
|
||||||
write_core(sig);
|
write_core(sig);
|
||||||
#endif /* HAVE_LINUXTHREADS */
|
|
||||||
exit(1);
|
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)
|
static void init_signals(void)
|
||||||
{
|
{
|
||||||
@ -1413,12 +1216,9 @@ static void init_signals(void)
|
|||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
sigprocmask(SIG_SETMASK,&sa.sa_mask,NULL);
|
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))
|
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
|
||||||
{
|
{
|
||||||
|
init_stacktrace();
|
||||||
sa.sa_handler=handle_segfault;
|
sa.sa_handler=handle_segfault;
|
||||||
sigaction(SIGSEGV, &sa, NULL);
|
sigaction(SIGSEGV, &sa, NULL);
|
||||||
#ifdef SIGBUS
|
#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