~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/stacktrace.c

  • Committer: Monty Taylor
  • Date: 2008-08-01 23:59:59 UTC
  • mto: (236.1.42 codestyle)
  • mto: This revision was merged to the branch mainline in revision 261.
  • Revision ID: monty@inaugust.com-20080801235959-n8ypy9r5aohown77
Gettext error compiles and passes test!

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 "stacktrace.h"
 
20
 
 
21
#include <signal.h>
 
22
#include <mysys/my_pthread.h>
 
23
#include <mystrings/m_string.h>
 
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);
 
200
    fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", (void *)fp);
 
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",
 
207
            (void *)fp, (void *)stack_bottom, thread_stack);
 
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,\
 
261
 terminating stack trace!\n", (void *)new_fp);
 
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
}