~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/stacktrace.cc

Merge Joe, plus I updated the tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems, Inc.
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
#include "config.h"
 
21
#include "drizzled/stacktrace.h"
 
22
#include <cstddef>
 
23
 
 
24
#include <signal.h>
 
25
#include "drizzled/internal/my_pthread.h"
 
26
#include "drizzled/internal/m_string.h"
 
27
#ifdef HAVE_STACKTRACE
 
28
#include <unistd.h>
 
29
#include <strings.h>
 
30
 
 
31
#if HAVE_EXECINFO_H
 
32
#include <execinfo.h>
 
33
#endif
 
34
 
 
35
#include <cstring>
 
36
#include <cstdio>
 
37
#include <algorithm>
 
38
 
 
39
#if defined(BACKTRACE_DEMANGLE)
 
40
# include <cxxabi.h>
 
41
#endif
 
42
 
 
43
#include "drizzled/definitions.h"
 
44
 
 
45
using namespace std;
 
46
 
 
47
namespace drizzled
 
48
{
 
49
 
 
50
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
 
51
 
 
52
char *heap_start;
 
53
 
 
54
void safe_print_str(const char* name, const char* val, int max_len)
 
55
{
 
56
  char *heap_end= (char*) sbrk(0);
 
57
  fprintf(stderr, "%s at %p ", name, val);
 
58
 
 
59
  if (!PTR_SANE(val))
 
60
  {
 
61
    fprintf(stderr, " is invalid pointer\n");
 
62
    return;
 
63
  }
 
64
 
 
65
  fprintf(stderr, "= ");
 
66
  for (; max_len && PTR_SANE(val) && *val; --max_len)
 
67
    fputc(*val++, stderr);
 
68
  fputc('\n', stderr);
 
69
}
 
70
 
 
71
#ifdef TARGET_OS_LINUX
 
72
 
 
73
#ifdef __i386__
 
74
#define SIGRETURN_FRAME_OFFSET 17
 
75
#endif
 
76
 
 
77
#ifdef __x86_64__
 
78
#define SIGRETURN_FRAME_OFFSET 23
 
79
#endif
 
80
 
 
81
#if defined(BACKTRACE_DEMANGLE)
 
82
 
 
83
static inline char *my_demangle(const char *mangled_name, int *status)
 
84
{
 
85
  return abi::__cxa_demangle(mangled_name, NULL, NULL, status);
 
86
}
 
87
 
 
88
static void my_demangle_symbols(char **addrs, int n)
 
89
{
 
90
  int status, i;
 
91
  char *begin, *end, *demangled;
 
92
 
 
93
  for (i= 0; i < n; i++)
 
94
  {
 
95
    demangled= NULL;
 
96
    begin= strchr(addrs[i], '(');
 
97
    end= begin ? strchr(begin, '+') : NULL;
 
98
 
 
99
    if (begin && end)
 
100
    {
 
101
      *begin++= *end++= '\0';
 
102
      demangled= my_demangle(begin, &status);
 
103
      if (!demangled || status)
 
104
      {
 
105
        demangled= NULL;
 
106
        begin[-1]= '(';
 
107
        end[-1]= '+';
 
108
      }
 
109
    }
 
110
 
 
111
    if (demangled)
 
112
      fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
 
113
    else
 
114
      fprintf(stderr, "%s\n", addrs[i]);
 
115
  }
 
116
}
 
117
#endif
 
118
 
 
119
 
 
120
#if HAVE_BACKTRACE
 
121
static void backtrace_current_thread(void)
 
122
{
 
123
  void *addrs[128];
 
124
  char **strings= NULL;
 
125
  int n = backtrace(addrs, array_elements(addrs));
 
126
#if BACKTRACE_DEMANGLE
 
127
  if ((strings= backtrace_symbols(addrs, n)))
 
128
  {
 
129
    my_demangle_symbols(strings, n);
 
130
    free(strings);
 
131
  }
 
132
#endif
 
133
#if HAVE_BACKTRACE_SYMBOLS_FD
 
134
  if (!strings)
 
135
  {
 
136
    backtrace_symbols_fd(addrs, n, fileno(stderr));
 
137
  }
 
138
#endif
 
139
}
 
140
#endif
 
141
 
 
142
 
 
143
void  print_stacktrace(unsigned char* stack_bottom, size_t thread_stack)
 
144
{
 
145
#if HAVE_BACKTRACE
 
146
  backtrace_current_thread();
 
147
  return;
 
148
#endif
 
149
  unsigned char** fp;
 
150
  uint32_t frame_count = 0, sigreturn_frame_count;
 
151
 
 
152
#ifdef __i386__
 
153
  __asm __volatile__ ("movl %%ebp,%0"
 
154
                      :"=r"(fp)
 
155
                      :"r"(fp));
 
156
#endif
 
157
#ifdef __x86_64__
 
158
  __asm __volatile__ ("movq %%rbp,%0"
 
159
                      :"=r"(fp)
 
160
                      :"r"(fp));
 
161
#endif
 
162
  if (!fp)
 
163
  {
 
164
    fprintf(stderr, "frame pointer is NULL, did you compile with\n\
 
165
-fomit-frame-pointer? Aborting backtrace!\n");
 
166
    return;
 
167
  }
 
168
 
 
169
  if (!stack_bottom || (unsigned char*) stack_bottom > (unsigned char*) &fp)
 
170
  {
 
171
    ulong tmp= min((size_t)0x10000,thread_stack);
 
172
    /* Assume that the stack starts at the previous even 65K */
 
173
    stack_bottom= (unsigned char*) (((ulong) &fp + tmp) &
 
174
                          ~(ulong) 0xFFFF);
 
175
    fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", (void *)fp);
 
176
  }
 
177
  if (fp > (unsigned char**) stack_bottom ||
 
178
      fp < (unsigned char**) stack_bottom - thread_stack)
 
179
  {
 
180
    fprintf(stderr, "Bogus stack limit or frame pointer,\
 
181
 fp=%p, stack_bottom=%p, thread_stack=%"PRIu64", aborting backtrace.\n",
 
182
            (void *)fp, (void *)stack_bottom, (uint64_t)thread_stack);
 
183
    return;
 
184
  }
 
185
 
 
186
  fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
 
187
 
 
188
  /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
 
189
  sigreturn_frame_count = internal::thd_lib_detected == THD_LIB_LT ? 2 : 1;
 
190
 
 
191
  while (fp < (unsigned char**) stack_bottom)
 
192
  {
 
193
#if defined(__i386__) || defined(__x86_64__)
 
194
    unsigned char** new_fp = (unsigned char**)*fp;
 
195
    fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
 
196
            *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
 
197
#endif /* defined(__386__)  || defined(__x86_64__) */
 
198
 
 
199
    if (new_fp <= fp )
 
200
    {
 
201
      fprintf(stderr, "New value of fp=%p failed sanity check,\
 
202
 terminating stack trace!\n", (void *)new_fp);
 
203
      goto end;
 
204
    }
 
205
    fp = new_fp;
 
206
    ++frame_count;
 
207
  }
 
208
 
 
209
  fprintf(stderr, "Stack trace seems successful - bottom reached\n");
 
210
 
 
211
end:
 
212
  fprintf(stderr,
 
213
          "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
 
214
          "and follow instructions on how to resolve the stack trace.\n"
 
215
          "Resolved stack trace is much more helpful in diagnosing the\n"
 
216
          "problem, so please do resolve it\n");
 
217
}
 
218
#endif /* TARGET_OS_LINUX */
 
219
 
 
220
} /* namespace drizzled */
 
221
 
 
222
#endif /* HAVE_STACKTRACE */
 
223
 
 
224
/* Produce a core for the thread */
 
225
 
 
226
namespace drizzled
 
227
{
 
228
 
 
229
void write_core(int sig)
 
230
{
 
231
  signal(sig, SIG_DFL);
 
232
#ifdef HAVE_gcov
 
233
  /*
 
234
    For GCOV build, crashing will prevent the writing of code coverage
 
235
    information from this process, causing gcov output to be incomplete.
 
236
    So we force the writing of coverage information here before terminating.
 
237
  */
 
238
  extern void __gcov_flush(void);
 
239
  __gcov_flush();
 
240
#endif
 
241
  pthread_kill(pthread_self(), sig);
 
242
#if defined(P_MYID) && !defined(SCO)
 
243
  /* On Solaris, the above kill is not enough */
 
244
  sigsend(P_PID,P_MYID,sig);
 
245
#endif
 
246
}
 
247
 
 
248
} /* namespace drizzled */