~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to sql/stacktrace.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}