~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/stacktrace.cc

Merged Padraig.

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 "drizzled/global.h"
 
21
#include "stacktrace.h"
 
22
 
 
23
#include <signal.h>
 
24
#include <mysys/my_pthread.h>
 
25
#include <mystrings/m_string.h>
 
26
#ifdef HAVE_STACKTRACE
 
27
#include <unistd.h>
 
28
#include <strings.h>
 
29
 
 
30
#if HAVE_EXECINFO_H
 
31
#include <execinfo.h>
 
32
#endif
 
33
 
 
34
#define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
 
35
 
 
36
char *heap_start;
 
37
 
 
38
void safe_print_str(const char* name, const char* val, int max_len)
 
39
{
 
40
  char *heap_end= (char*) sbrk(0);
 
41
  fprintf(stderr, "%s at %p ", name, val);
 
42
 
 
43
  if (!PTR_SANE(val))
 
44
  {
 
45
    fprintf(stderr, " is invalid pointer\n");
 
46
    return;
 
47
  }
 
48
 
 
49
  fprintf(stderr, "= ");
 
50
  for (; max_len && PTR_SANE(val) && *val; --max_len)
 
51
    fputc(*val++, stderr);
 
52
  fputc('\n', stderr);
 
53
}
 
54
 
 
55
#ifdef TARGET_OS_LINUX
 
56
 
 
57
#ifdef __i386__
 
58
#define SIGRETURN_FRAME_OFFSET 17
 
59
#endif
 
60
 
 
61
#ifdef __x86_64__
 
62
#define SIGRETURN_FRAME_OFFSET 23
 
63
#endif
 
64
 
 
65
 
 
66
#if BACKTRACE_DEMANGLE
 
67
static void my_demangle_symbols(char **addrs, int n)
 
68
{
 
69
  int status, i;
 
70
  char *begin, *end, *demangled;
 
71
 
 
72
  for (i= 0; i < n; i++)
 
73
  {
 
74
    demangled= NULL;
 
75
    begin= strchr(addrs[i], '(');
 
76
    end= begin ? strchr(begin, '+') : NULL;
 
77
 
 
78
    if (begin && end)
 
79
    {
 
80
      *begin++= *end++= '\0';
 
81
      demangled= my_demangle(begin, &status);
 
82
      if (!demangled || status)
 
83
      {
 
84
        demangled= NULL;
 
85
        begin[-1]= '(';
 
86
        end[-1]= '+';
 
87
      }
 
88
    }
 
89
 
 
90
    if (demangled)
 
91
      fprintf(stderr, "%s(%s+%s\n", addrs[i], demangled, end);
 
92
    else
 
93
      fprintf(stderr, "%s\n", addrs[i]);
 
94
  }
 
95
}
 
96
#endif
 
97
 
 
98
 
 
99
#if HAVE_BACKTRACE
 
100
static void backtrace_current_thread(void)
 
101
{
 
102
  void *addrs[128];
 
103
  char **strings= NULL;
 
104
  int n = backtrace(addrs, array_elements(addrs));
 
105
#if BACKTRACE_DEMANGLE
 
106
  if ((strings= backtrace_symbols(addrs, n)))
 
107
  {
 
108
    my_demangle_symbols(strings, n);
 
109
    free(strings);
 
110
  }
 
111
#endif
 
112
#if HAVE_BACKTRACE_SYMBOLS_FD
 
113
  if (!strings)
 
114
  {
 
115
    backtrace_symbols_fd(addrs, n, fileno(stderr));
 
116
  }
 
117
#endif
 
118
}
 
119
#endif
 
120
 
 
121
 
 
122
void  print_stacktrace(unsigned char* stack_bottom, size_t thread_stack)
 
123
{
 
124
#if HAVE_BACKTRACE
 
125
  backtrace_current_thread();
 
126
  return;
 
127
#endif
 
128
  unsigned char** fp;
 
129
  uint32_t frame_count = 0, sigreturn_frame_count;
 
130
 
 
131
#ifdef __i386__
 
132
  __asm __volatile__ ("movl %%ebp,%0"
 
133
                      :"=r"(fp)
 
134
                      :"r"(fp));
 
135
#endif
 
136
#ifdef __x86_64__
 
137
  __asm __volatile__ ("movq %%rbp,%0"
 
138
                      :"=r"(fp)
 
139
                      :"r"(fp));
 
140
#endif
 
141
  if (!fp)
 
142
  {
 
143
    fprintf(stderr, "frame pointer is NULL, did you compile with\n\
 
144
-fomit-frame-pointer? Aborting backtrace!\n");
 
145
    return;
 
146
  }
 
147
 
 
148
  if (!stack_bottom || (unsigned char*) stack_bottom > (unsigned char*) &fp)
 
149
  {
 
150
    ulong tmp= cmin(0x10000,thread_stack);
 
151
    /* Assume that the stack starts at the previous even 65K */
 
152
    stack_bottom= (unsigned char*) (((ulong) &fp + tmp) &
 
153
                          ~(ulong) 0xFFFF);
 
154
    fprintf(stderr, "Cannot determine thread, fp=%p, backtrace may not be correct.\n", (void *)fp);
 
155
  }
 
156
  if (fp > (unsigned char**) stack_bottom ||
 
157
      fp < (unsigned char**) stack_bottom - thread_stack)
 
158
  {
 
159
    fprintf(stderr, "Bogus stack limit or frame pointer,\
 
160
 fp=%p, stack_bottom=%p, thread_stack=%"PRIu64", aborting backtrace.\n",
 
161
            (void *)fp, (void *)stack_bottom, (uint64_t)thread_stack);
 
162
    return;
 
163
  }
 
164
 
 
165
  fprintf(stderr, "Stack range sanity check OK, backtrace follows:\n");
 
166
 
 
167
  /* We are 1 frame above signal frame with NPTL and 2 frames above with LT */
 
168
  sigreturn_frame_count = thd_lib_detected == THD_LIB_LT ? 2 : 1;
 
169
 
 
170
  while (fp < (unsigned char**) stack_bottom)
 
171
  {
 
172
#if defined(__i386__) || defined(__x86_64__)
 
173
    unsigned char** new_fp = (unsigned char**)*fp;
 
174
    fprintf(stderr, "%p\n", frame_count == sigreturn_frame_count ?
 
175
            *(fp + SIGRETURN_FRAME_OFFSET) : *(fp + 1));
 
176
#endif /* defined(__386__)  || defined(__x86_64__) */
 
177
 
 
178
    if (new_fp <= fp )
 
179
    {
 
180
      fprintf(stderr, "New value of fp=%p failed sanity check,\
 
181
 terminating stack trace!\n", (void *)new_fp);
 
182
      goto end;
 
183
    }
 
184
    fp = new_fp;
 
185
    ++frame_count;
 
186
  }
 
187
 
 
188
  fprintf(stderr, "Stack trace seems successful - bottom reached\n");
 
189
 
 
190
end:
 
191
  fprintf(stderr,
 
192
          "Please read http://dev.mysql.com/doc/refman/5.1/en/resolve-stack-dump.html\n"
 
193
          "and follow instructions on how to resolve the stack trace.\n"
 
194
          "Resolved stack trace is much more helpful in diagnosing the\n"
 
195
          "problem, so please do resolve it\n");
 
196
}
 
197
#endif /* TARGET_OS_LINUX */
 
198
#endif /* HAVE_STACKTRACE */
 
199
 
 
200
/* Produce a core for the thread */
 
201
 
 
202
void write_core(int sig)
 
203
{
 
204
  signal(sig, SIG_DFL);
 
205
#ifdef HAVE_gcov
 
206
  /*
 
207
    For GCOV build, crashing will prevent the writing of code coverage
 
208
    information from this process, causing gcov output to be incomplete.
 
209
    So we force the writing of coverage information here before terminating.
 
210
  */
 
211
  extern void __gcov_flush(void);
 
212
  __gcov_flush();
 
213
#endif
 
214
  pthread_kill(pthread_self(), sig);
 
215
#if defined(P_MYID) && !defined(SCO)
 
216
  /* On Solaris, the above kill is not enough */
 
217
  sigsend(P_PID,P_MYID,sig);
 
218
#endif
 
219
}