summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am15
-rw-r--r--sql/mysqld.cc292
-rw-r--r--sql/stacktrace.c215
-rw-r--r--sql/stacktrace.h51
4 files changed, 321 insertions, 252 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 596a1d3acf7..774ef06f17c 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -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 \
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 503a45a8da0..c9e19b65a6c 100644
--- a/sql/mysqld.cc
+++ b/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
@@ -1125,236 +1126,33 @@ 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
// mutex - so we keep things simple
if (segfaulted)
- {
- fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
- exit(1);
- }
+ {
+ fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
+ exit(1);
+ }
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 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);
+ }
+#endif /* 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",
- thread_count);
- }
-#ifdef LINUX_STACK_TRACE
+#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
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 */
diff --git a/sql/stacktrace.h b/sql/stacktrace.h
new file mode 100644
index 00000000000..b6c0ec43a0f
--- /dev/null
+++ b/sql/stacktrace.h
@@ -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