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