~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
17
#define DONT_DEFINE_VOID 1
18
19
#include "stacktrace.h"
20
21
#include <signal.h>
212.5.13 by Monty Taylor
Moved my_sys/my_pthread/my_nosys and mysys_err to mysys.
22
#include <mysys/my_pthread.h>
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
23
#include <mystrings/m_string.h>
1 by brian
clean slate
24
#ifdef HAVE_STACKTRACE
25
#include <unistd.h>
26
#include <strings.h>
27
28
#if HAVE_EXECINFO_H
29
#include <execinfo.h>
30
#endif
31
32
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
33
34
char *heap_start;
35
36
void safe_print_str(const char* name, const char* val, int max_len)
37
{
38
  char *heap_end= (char*) sbrk(0);
39
  fprintf(stderr, "%s at %p ", name, val);
40
41
  if (!PTR_SANE(val))
42
  {
43
    fprintf(stderr, " is invalid pointer\n");
44
    return;
45
  }
46
47
  fprintf(stderr, "= ");
48
  for (; max_len && PTR_SANE(val) && *val; --max_len)
49
    fputc(*val++, stderr);
50
  fputc('\n', stderr);
51
}
52
53
#ifdef TARGET_OS_LINUX
54
55
#ifdef __i386__
56
#define SIGRETURN_FRAME_OFFSET 17
57
#endif
58
59
#ifdef __x86_64__
60
#define SIGRETURN_FRAME_OFFSET 23
61
#endif
62
63
#if defined(__alpha__) && defined(__GNUC__)
64
/*
65
  The only way to backtrace without a symbol table on alpha
66
  is to find stq fp,N(sp), and the first byte
67
  of the instruction opcode will give us the value of N. From this
68
  we can find where the old value of fp is stored
69
*/
70
71
#define MAX_INSTR_IN_FUNC  10000
72
73
inline uchar** find_prev_fp(uint32* pc, uchar** fp)
74
{
75
  int i;
76
  for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
77
  {
78
    uchar* p = (uchar*)pc;
79
    if (p[2] == 222 &&  p[3] == 35)
80
    {
81
      return (uchar**)((uchar*)fp - *(short int*)p);
82
    }
83
  }
84
  return 0;
85
}
86
87
inline uint32* find_prev_pc(uint32* pc, uchar** fp)
88
{
89
  int i;
90
  for (i = 0; i < MAX_INSTR_IN_FUNC; ++i,--pc)
91
  {
92
    char* p = (char*)pc;
93
    if (p[1] == 0 && p[2] == 94 &&  p[3] == -73)
94
    {
95
      uint32* prev_pc = (uint32*)*((fp+p[0]/sizeof(fp)));
96
      return prev_pc;
97
    }
98
  }
99
  return 0;
100
}
101
#endif /* defined(__alpha__) && defined(__GNUC__) */
102
103
#if BACKTRACE_DEMANGLE
104
static void my_demangle_symbols(char **addrs, int n)
105
{
106
  int status, i;
107
  char *begin, *end, *demangled;
108
109
  for (i= 0; i < n; i++)
110
  {
111
    demangled= NULL;
112
    begin= strchr(addrs[i], '(');
113
    end= begin ? strchr(begin, '+') : NULL;
114
115
    if (begin && end)
116
    {
117
      *begin++= *end++= '\0';
118
      demangled= my_demangle(begin, &status);
119
      if (!demangled || status)
120
      {
121
        demangled= NULL;
122
        begin[-1]= '(';
123
        end[-1]= '+';
124
      }
125
    }
126
127
    if (demangled)
128
      fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
129
    else
130
      fprintf(stderr, "%s\n", addrs[i]);
131
  }
132
}
133
#endif
134
135
136
#if HAVE_BACKTRACE
137
static void backtrace_current_thread(void)
138
{
139
  void *addrs[128];
140
  char **strings= NULL;
141
  int n = backtrace(addrs, array_elements(addrs));
142
#if BACKTRACE_DEMANGLE
143
  if ((strings= backtrace_symbols(addrs, n)))
144
  {
145
    my_demangle_symbols(strings, n);
146
    free(strings);
147
  }
148
#endif
149
#if HAVE_BACKTRACE_SYMBOLS_FD
150
  if (!strings)
151
  {
152
    backtrace_symbols_fd(addrs, n, fileno(stderr));
153
  }
154
#endif
155
}
156
#endif
157
158
159
void  print_stacktrace(uchar* stack_bottom, ulong thread_stack)
160
{
161
#if HAVE_BACKTRACE
162
  backtrace_current_thread();
163
  return;
164
#endif
165
  uchar** fp;
166
  uint frame_count = 0, sigreturn_frame_count;
167
#if defined(__alpha__) && defined(__GNUC__)
168
  uint32* pc;
169
#endif
170
171
172
#ifdef __i386__
173
  __asm __volatile__ ("movl %%ebp,%0"
174
		      :"=r"(fp)
175
		      :"r"(fp));
176
#endif
177
#ifdef __x86_64__
178
  __asm __volatile__ ("movq %%rbp,%0"
179
		      :"=r"(fp)
180
		      :"r"(fp));
181
#endif
182
#if defined(__alpha__) && defined(__GNUC__) 
183
  __asm __volatile__ ("mov $30,%0"
184
		      :"=r"(fp)
185
		      :"r"(fp));
186
#endif
187
  if (!fp)
188
  {
189
    fprintf(stderr, "frame pointer is NULL, did you compile with\n\
190
-fomit-frame-pointer? Aborting backtrace!\n");
191
    return;
192
  }
193
194
  if (!stack_bottom || (uchar*) stack_bottom > (uchar*) &fp)
195
  {
196
    ulong tmp= min(0x10000,thread_stack);
197
    /* Assume that the stack starts at the previous even 65K */
198
    stack_bottom= (uchar*) (((ulong) &fp + tmp) &
199
			  ~(ulong) 0xFFFF);
77.1.54 by Monty Taylor
More warnings cleanups.
200
    fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", (void *)fp);
1 by brian
clean slate
201
  }
202
  if (fp > (uchar**) stack_bottom ||
203
      fp < (uchar**) stack_bottom - thread_stack)
204
  {
205
    fprintf(stderr, "Bogus stack limit or frame pointer,\
206
 fp=%p, stack_bottom=%p, thread_stack=%ld, aborting backtrace.\n",
77.1.54 by Monty Taylor
More warnings cleanups.
207
	    (void *)fp, (void *)stack_bottom, thread_stack);
1 by brian
clean slate
208
    return;
209
  }
210
211
  fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
212
#if defined(__alpha__) && defined(__GNUC__)
213
  fprintf(stderr, "Warning: Alpha stacks are difficult -\
214
 will be taking some wild guesses, stack trace may be incorrect or \
215
 terminate abruptly\n");
216
  /* On Alpha, we need to get pc */
217
  __asm __volatile__ ("bsr %0, do_next; do_next: "
218
		      :"=r"(pc)
219
		      :"r"(pc));
220
#endif  /* __alpha__ */
221
222
  /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
223
  sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
224
225
  while (fp < (uchar**) stack_bottom)
226
  {
227
#if defined(__i386__) || defined(__x86_64__)
228
    uchar** new_fp = (uchar**)*fp;
229
    fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
230
	    *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
231
#endif /* defined(__386__)  || defined(__x86_64__) */
232
233
#if defined(__alpha__) && defined(__GNUC__)
234
    uchar** new_fp = find_prev_fp(pc, fp);
235
    if (frame_count == sigreturn_frame_count - 1)
236
    {
237
      new_fp += 90;
238
    }
239
240
    if (fp && pc)
241
    {
242
      pc = find_prev_pc(pc, fp);
243
      if (pc)
244
	fprintf(stderr, "%p\n", pc);
245
      else
246
      {
247
	fprintf(stderr, "Not smart enough to deal with the rest\
248
 of this stack\n");
249
	goto end;
250
      }
251
    }
252
    else
253
    {
254
      fprintf(stderr, "Not smart enough to deal with the rest of this stack\n");
255
      goto end;
256
    }
257
#endif /* defined(__alpha__) && defined(__GNUC__) */
258
    if (new_fp <= fp )
259
    {
260
      fprintf(stderr, "New value of fp=%p failed sanity check,\
77.1.54 by Monty Taylor
More warnings cleanups.
261
 terminating stack trace!\n", (void *)new_fp);
1 by brian
clean slate
262
      goto end;
263
    }
264
    fp = new_fp;
265
    ++frame_count;
266
  }
267
268
  fprintf(stderr, "Stack trace seems successful - bottom reached\n");
269
270
end:
271
  fprintf(stderr,
272
          "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
273
          "and follow instructions on how to resolve the stack trace.\n"
274
          "Resolved stack trace is much more helpful in diagnosing the\n"
275
          "problem, so please do resolve it\n");
276
}
277
#endif /* TARGET_OS_LINUX */
278
#endif /* HAVE_STACKTRACE */
279
280
/* Produce a core for the thread */
281
282
void write_core(int sig)
283
{
284
  signal(sig, SIG_DFL);
285
#ifdef HAVE_gcov
286
  /*
287
    For GCOV build, crashing will prevent the writing of code coverage
288
    information from this process, causing gcov output to be incomplete.
289
    So we force the writing of coverage information here before terminating.
290
  */
291
  extern void __gcov_flush(void);
292
  __gcov_flush();
293
#endif
294
  pthread_kill(pthread_self(), sig);
295
#if defined(P_MYID) && !defined(SCO)
296
  /* On Solaris, the above kill is not enough */
297
  sigsend(P_PID,P_MYID,sig);
298
#endif
299
}