~ubuntu-branches/ubuntu/wily/google-perftools/wily

« back to all changes in this revision

Viewing changes to src/stacktrace_x86-inl.h

  • Committer: Bazaar Package Importer
  • Author(s): Daigo Moriwaki
  • Date: 2009-09-19 00:10:06 UTC
  • mto: (3.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 9.
  • Revision ID: james.westby@ubuntu.com-20090919001006-m997dckgoqs3sru9
Tags: upstream-1.4
ImportĀ upstreamĀ versionĀ 1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
// Author: Sanjay Ghemawat
32
32
//
33
33
// Produce stack trace
34
 
 
 
34
//
 
35
// NOTE: there is code duplication between
 
36
// GetStackTrace, GetStackTraceWithContext, GetStackFrames and
 
37
// GetStackFramesWithContext. If you update one, update them all.
 
38
//
 
39
// There is no easy way to avoid this, because inlining
 
40
// interferes with skip_count, and there is no portable
 
41
// way to turn inlining off, or force it always on.
 
42
 
 
43
#include "config.h"
 
44
 
 
45
#include <stdlib.h>   // for NULL
 
46
#include <assert.h>
 
47
#if HAVE_UCONTEXT_H
 
48
#include <ucontext.h>  // for ucontext_t
 
49
#endif
 
50
#ifdef HAVE_STDINT_H
35
51
#include <stdint.h>   // for uintptr_t
36
 
#include <stdlib.h>   // for NULL
37
 
 
38
 
#if !defined(WIN32)
 
52
#endif
 
53
#ifdef HAVE_UNISTD_H
39
54
#include <unistd.h>
40
 
#include <sys/mman.h>
 
55
#endif
 
56
#ifdef HAVE_MMAP
 
57
#include <sys/mman.h> // for msync
 
58
#include "base/vdso_support.h"
41
59
#endif
42
60
 
43
61
#include "google/stacktrace.h"
44
62
 
 
63
#if defined(__linux__) && defined(__i386__) && defined(__ELF__) && defined(HAVE_MMAP)
 
64
// Count "push %reg" instructions in VDSO __kernel_vsyscall(),
 
65
// preceeding "syscall" or "sysenter".
 
66
// If __kernel_vsyscall uses frame pointer, answer 0.
 
67
//
 
68
// kMaxBytes tells how many instruction bytes of __kernel_vsyscall
 
69
// to analyze before giving up. Up to kMaxBytes+1 bytes of
 
70
// instructions could be accessed.
 
71
//
 
72
// Here are known __kernel_vsyscall instruction sequences:
 
73
//
 
74
// SYSENTER (linux-2.6.26/arch/x86/vdso/vdso32/sysenter.S).
 
75
// Used on Intel.
 
76
//  0xffffe400 <__kernel_vsyscall+0>:       push   %ecx
 
77
//  0xffffe401 <__kernel_vsyscall+1>:       push   %edx
 
78
//  0xffffe402 <__kernel_vsyscall+2>:       push   %ebp
 
79
//  0xffffe403 <__kernel_vsyscall+3>:       mov    %esp,%ebp
 
80
//  0xffffe405 <__kernel_vsyscall+5>:       sysenter
 
81
//
 
82
// SYSCALL (see linux-2.6.26/arch/x86/vdso/vdso32/syscall.S).
 
83
// Used on AMD.
 
84
//  0xffffe400 <__kernel_vsyscall+0>:       push   %ebp
 
85
//  0xffffe401 <__kernel_vsyscall+1>:       mov    %ecx,%ebp
 
86
//  0xffffe403 <__kernel_vsyscall+3>:       syscall
 
87
//
 
88
// i386 (see linux-2.6.26/arch/x86/vdso/vdso32/int80.S)
 
89
//  0xffffe400 <__kernel_vsyscall+0>:       int $0x80
 
90
//  0xffffe401 <__kernel_vsyscall+1>:       ret
 
91
//
 
92
static const int kMaxBytes = 10;
 
93
 
 
94
// We use assert()s instead of DCHECK()s -- this is too low level
 
95
// for DCHECK().
 
96
 
 
97
static int CountPushInstructions(const unsigned char *const addr) {
 
98
  int result = 0;
 
99
  for (int i = 0; i < kMaxBytes; ++i) {
 
100
    if (addr[i] == 0x89) {
 
101
      // "mov reg,reg"
 
102
      if (addr[i + 1] == 0xE5) {
 
103
        // Found "mov %esp,%ebp".
 
104
        return 0;
 
105
      }
 
106
      ++i;  // Skip register encoding byte.
 
107
    } else if (addr[i] == 0x0F &&
 
108
               (addr[i + 1] == 0x34 || addr[i + 1] == 0x05)) {
 
109
      // Found "sysenter" or "syscall".
 
110
      return result;
 
111
    } else if ((addr[i] & 0xF0) == 0x50) {
 
112
      // Found "push %reg".
 
113
      ++result;
 
114
    } else if (addr[i] == 0xCD && addr[i + 1] == 0x80) {
 
115
      // Found "int $0x80"
 
116
      assert(result == 0);
 
117
      return 0;
 
118
    } else {
 
119
      // Unexpected instruction.
 
120
      assert(0 == "unexpected instruction in __kernel_vsyscall");
 
121
      return 0;
 
122
    }
 
123
  }
 
124
  // Unexpected: didn't find SYSENTER or SYSCALL in
 
125
  // [__kernel_vsyscall, __kernel_vsyscall + kMaxBytes) interval.
 
126
  assert(0 == "did not find SYSENTER or SYSCALL in __kernel_vsyscall");
 
127
  return 0;
 
128
}
 
129
#endif
 
130
 
45
131
// Given a pointer to a stack frame, locate and return the calling
46
132
// stackframe, or return NULL if no stackframe can be found. Perform sanity
47
133
// checks (the strictness of which is controlled by the boolean parameter
48
134
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
49
 
template<bool STRICT_UNWINDING>
50
 
static void **NextStackFrame(void **old_sp) {
 
135
template<bool STRICT_UNWINDING, bool WITH_CONTEXT>
 
136
static void **NextStackFrame(void **old_sp, const void *uc) {
51
137
  void **new_sp = (void **) *old_sp;
52
138
 
 
139
#if defined(__linux__) && defined(__i386__) && defined(HAVE_VDSO_SUPPORT)
 
140
  if (WITH_CONTEXT && uc != NULL) {
 
141
    // How many "push %reg" instructions are there at __kernel_vsyscall?
 
142
    // This is constant for a given kernel and processor, so compute
 
143
    // it only once.
 
144
    static int num_push_instructions = -1;  // Sentinel: not computed yet.
 
145
    // Initialize with sentinel value: __kernel_rt_sigreturn can not possibly
 
146
    // be there.
 
147
    static const unsigned char *kernel_rt_sigreturn_address = NULL;
 
148
    static const unsigned char *kernel_vsyscall_address = NULL;
 
149
    if (num_push_instructions == -1) {
 
150
      base::VDSOSupport vdso;
 
151
      if (vdso.IsPresent()) {
 
152
        base::VDSOSupport::SymbolInfo rt_sigreturn_symbol_info;
 
153
        base::VDSOSupport::SymbolInfo vsyscall_symbol_info;
 
154
        if (!vdso.LookupSymbol("__kernel_rt_sigreturn", "LINUX_2.5",
 
155
                               STT_FUNC, &rt_sigreturn_symbol_info) ||
 
156
            !vdso.LookupSymbol("__kernel_vsyscall", "LINUX_2.5",
 
157
                               STT_FUNC, &vsyscall_symbol_info) ||
 
158
            rt_sigreturn_symbol_info.address == NULL ||
 
159
            vsyscall_symbol_info.address == NULL) {
 
160
          // Unexpected: 32-bit VDSO is present, yet one of the expected
 
161
          // symbols is missing or NULL.
 
162
          assert(0 == "VDSO is present, but doesn't have expected symbols");
 
163
          num_push_instructions = 0;
 
164
        } else {
 
165
          kernel_rt_sigreturn_address =
 
166
              reinterpret_cast<const unsigned char *>(
 
167
                  rt_sigreturn_symbol_info.address);
 
168
          kernel_vsyscall_address =
 
169
              reinterpret_cast<const unsigned char *>(
 
170
                  vsyscall_symbol_info.address);
 
171
          num_push_instructions =
 
172
              CountPushInstructions(kernel_vsyscall_address);
 
173
        }
 
174
      } else {
 
175
        num_push_instructions = 0;
 
176
      }
 
177
    }
 
178
    if (num_push_instructions != 0 && kernel_rt_sigreturn_address != NULL &&
 
179
        old_sp[1] == kernel_rt_sigreturn_address) {
 
180
      const ucontext_t *ucv = static_cast<const ucontext_t *>(uc);
 
181
      // This kernel does not use frame pointer in its VDSO code,
 
182
      // and so %ebp is not suitable for unwinding.
 
183
      const void **const reg_ebp =
 
184
          reinterpret_cast<const void **>(ucv->uc_mcontext.gregs[REG_EBP]);
 
185
      const unsigned char *const reg_eip =
 
186
          reinterpret_cast<unsigned char *>(ucv->uc_mcontext.gregs[REG_EIP]);
 
187
      if (new_sp == reg_ebp &&
 
188
          kernel_vsyscall_address <= reg_eip &&
 
189
          reg_eip - kernel_vsyscall_address < kMaxBytes) {
 
190
        // We "stepped up" to __kernel_vsyscall, but %ebp is not usable.
 
191
        // Restore from 'ucv' instead.
 
192
        void **const reg_esp =
 
193
            reinterpret_cast<void **>(ucv->uc_mcontext.gregs[REG_ESP]);
 
194
        // Check that alleged %esp is not NULL and is reasonably aligned.
 
195
        if (reg_esp &&
 
196
            ((uintptr_t)reg_esp & (sizeof(reg_esp) - 1)) == 0) {
 
197
          // Check that alleged %esp is actually readable. This is to prevent
 
198
          // "double fault" in case we hit the first fault due to e.g. stack
 
199
          // corruption.
 
200
          //
 
201
          // page_size is linker-initalized to avoid async-unsafe locking
 
202
          // that GCC would otherwise insert (__cxa_guard_acquire etc).
 
203
          static int page_size;
 
204
          if (page_size == 0) {
 
205
            // First time through.
 
206
            page_size = getpagesize();
 
207
          }
 
208
          void *const reg_esp_aligned =
 
209
              reinterpret_cast<void *>(
 
210
                  (uintptr_t)(reg_esp + num_push_instructions - 1) &
 
211
                  ~(page_size - 1));
 
212
          if (msync(reg_esp_aligned, page_size, MS_ASYNC) == 0) {
 
213
            // Alleged %esp is readable, use it for further unwinding.
 
214
            new_sp = reinterpret_cast<void **>(
 
215
                reg_esp[num_push_instructions - 1]);
 
216
          }
 
217
        }
 
218
      }
 
219
    }
 
220
  }
 
221
#endif
 
222
 
53
223
  // Check that the transition from frame pointer old_sp to frame
54
224
  // pointer new_sp isn't clearly bogus
55
225
  if (STRICT_UNWINDING) {
73
243
  // last two pages in the address space
74
244
  if ((uintptr_t)new_sp >= 0xffffe000) return NULL;
75
245
#endif
76
 
#if !defined(WIN32)
 
246
#ifdef HAVE_MMAP
77
247
  if (!STRICT_UNWINDING) {
78
248
    // Lax sanity checks cause a crash on AMD-based machines with
79
249
    // VDSO-enabled kernels.
89
259
  return new_sp;
90
260
}
91
261
 
92
 
// If you change this function, also change GetStackFrames below.
 
262
// If you change this function, see NOTE at the top of file.
 
263
// Same as above, but with signal ucontext_t pointer.
 
264
int GetStackTraceWithContext(void** result,
 
265
                             int max_depth,
 
266
                             int skip_count,
 
267
                             const void *uc) {
 
268
  void **sp;
 
269
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
 
270
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
 
271
  // It's always correct on llvm, and the techniques below aren't (in
 
272
  // particular, llvm-gcc will make a copy of pcs, so it's not in sp[2]),
 
273
  // so we also prefer __builtin_frame_address when running under llvm.
 
274
  sp = reinterpret_cast<void**>(__builtin_frame_address(0));
 
275
#elif defined(__i386__)
 
276
  // Stack frame format:
 
277
  //    sp[0]   pointer to previous frame
 
278
  //    sp[1]   caller address
 
279
  //    sp[2]   first argument
 
280
  //    ...
 
281
  // NOTE: This will break under llvm, since result is a copy and not in sp[2]
 
282
  sp = (void **)&result - 2;
 
283
#elif defined(__x86_64__)
 
284
  unsigned long rbp;
 
285
  // Move the value of the register %rbp into the local variable rbp.
 
286
  // We need 'volatile' to prevent this instruction from getting moved
 
287
  // around during optimization to before function prologue is done.
 
288
  // An alternative way to achieve this
 
289
  // would be (before this __asm__ instruction) to call Noop() defined as
 
290
  //   static void Noop() __attribute__ ((noinline));  // prevent inlining
 
291
  //   static void Noop() { asm(""); }  // prevent optimizing-away
 
292
  __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
 
293
  // Arguments are passed in registers on x86-64, so we can't just
 
294
  // offset from &result
 
295
  sp = (void **) rbp;
 
296
#else
 
297
# error Using stacktrace_x86-inl.h on a non x86 architecture!
 
298
#endif
 
299
 
 
300
  int n = 0;
 
301
  while (sp && n < max_depth) {
 
302
    if (*(sp+1) == reinterpret_cast<void *>(0)) {
 
303
      // In 64-bit code, we often see a frame that
 
304
      // points to itself and has a return address of 0.
 
305
      break;
 
306
    }
 
307
    if (skip_count > 0) {
 
308
      skip_count--;
 
309
    } else {
 
310
      result[n++] = *(sp+1);
 
311
    }
 
312
    // Use strict unwinding rules.
 
313
    sp = NextStackFrame<true, true>(sp, uc);
 
314
  }
 
315
  return n;
 
316
}
 
317
 
93
318
int GetStackTrace(void** result, int max_depth, int skip_count) {
94
319
  void **sp;
95
 
#ifdef __i386__
 
320
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
 
321
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
 
322
  // It's always correct on llvm, and the techniques below aren't (in
 
323
  // particular, llvm-gcc will make a copy of pcs, so it's not in sp[2]),
 
324
  // so we also prefer __builtin_frame_address when running under llvm.
 
325
  sp = reinterpret_cast<void**>(__builtin_frame_address(0));
 
326
#elif defined(__i386__)
96
327
  // Stack frame format:
97
328
  //    sp[0]   pointer to previous frame
98
329
  //    sp[1]   caller address
99
330
  //    sp[2]   first argument
100
331
  //    ...
 
332
  // NOTE: This will break under llvm, since result is a copy and not in sp[2]
101
333
  sp = (void **)&result - 2;
102
 
#endif
103
 
 
104
 
#ifdef __x86_64__
105
 
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
 
334
#elif defined(__x86_64__)
106
335
  unsigned long rbp;
107
336
  // Move the value of the register %rbp into the local variable rbp.
108
337
  // We need 'volatile' to prevent this instruction from getting moved
115
344
  // Arguments are passed in registers on x86-64, so we can't just
116
345
  // offset from &result
117
346
  sp = (void **) rbp;
 
347
#else
 
348
# error Using stacktrace_x86-inl.h on a non x86 architecture!
118
349
#endif
119
350
 
120
351
  int n = 0;
121
352
  while (sp && n < max_depth) {
122
 
    if (*(sp+1) == (void *)0) {
 
353
    if (*(sp+1) == reinterpret_cast<void *>(0)) {
123
354
      // In 64-bit code, we often see a frame that
124
355
      // points to itself and has a return address of 0.
125
356
      break;
130
361
      result[n++] = *(sp+1);
131
362
    }
132
363
    // Use strict unwinding rules.
133
 
    sp = NextStackFrame<true>(sp);
 
364
    sp = NextStackFrame<true, false>(sp, NULL);
134
365
  }
135
366
  return n;
136
367
}
137
368
 
138
 
// If you change this function, also change GetStackTrace above:
 
369
// If you change this function, see NOTE at the top of file.
139
370
//
140
371
// This GetStackFrames routine shares a lot of code with GetStackTrace
141
372
// above. This code could have been refactored into a common routine,
164
395
// class, we are in trouble.
165
396
int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
166
397
  void **sp;
167
 
#ifdef __i386__
168
 
  // Stack frame format:
169
 
  //    sp[0]   pointer to previous frame
170
 
  //    sp[1]   caller address
171
 
  //    sp[2]   first argument
172
 
  //    ...
173
 
  sp = (void **)&pcs - 2;
174
 
#endif
175
 
 
176
 
#ifdef __x86_64__
177
 
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
178
 
  unsigned long rbp;
179
 
  // Move the value of the register %rbp into the local variable rbp.
180
 
  // We need 'volatile' to prevent this instruction from getting moved
181
 
  // around during optimization to before function prologue is done.
182
 
  // An alternative way to achieve this
183
 
  // would be (before this __asm__ instruction) to call Noop() defined as
184
 
  //   static void Noop() __attribute__ ((noinline));  // prevent inlining
185
 
  //   static void Noop() { asm(""); }  // prevent optimizing-away
186
 
  __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
187
 
  // Arguments are passed in registers on x86-64, so we can't just
188
 
  // offset from &pcs
189
 
  sp = (void **) rbp;
190
 
#endif
191
 
 
192
 
  int n = 0;
193
 
  while (sp && n < max_depth) {
194
 
    if (*(sp+1) == (void *)0) {
195
 
      // In 64-bit code, we often see a frame that
196
 
      // points to itself and has a return address of 0.
197
 
      break;
198
 
    }
199
 
    // The GetStackFrames routine is called when we are in some
200
 
    // informational context (the failure signal handler for example).
201
 
    // Use the non-strict unwinding rules to produce a stack trace
202
 
    // that is as complete as possible (even if it contains a few bogus
203
 
    // entries in some rare cases).
204
 
    void **next_sp = NextStackFrame<false>(sp);
 
398
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
 
399
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
 
400
  // It's always correct on llvm, and the techniques below aren't (in
 
401
  // particular, llvm-gcc will make a copy of pcs, so it's not in sp[2]),
 
402
  // so we also prefer __builtin_frame_address when running under llvm.
 
403
  sp = reinterpret_cast<void**>(__builtin_frame_address(0));
 
404
#elif defined(__i386__)
 
405
  // Stack frame format:
 
406
  //    sp[0]   pointer to previous frame
 
407
  //    sp[1]   caller address
 
408
  //    sp[2]   first argument
 
409
  //    ...
 
410
  sp = (void **)&pcs - 2;
 
411
#elif defined(__x86_64__)
 
412
  unsigned long rbp;
 
413
  // Move the value of the register %rbp into the local variable rbp.
 
414
  // We need 'volatile' to prevent this instruction from getting moved
 
415
  // around during optimization to before function prologue is done.
 
416
  // An alternative way to achieve this
 
417
  // would be (before this __asm__ instruction) to call Noop() defined as
 
418
  //   static void Noop() __attribute__ ((noinline));  // prevent inlining
 
419
  //   static void Noop() { asm(""); }  // prevent optimizing-away
 
420
  __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
 
421
  // Arguments are passed in registers on x86-64, so we can't just
 
422
  // offset from &result
 
423
  sp = (void **) rbp;
 
424
#else
 
425
# error Using stacktrace_x86-inl.h on a non x86 architecture!
 
426
#endif
 
427
 
 
428
  int n = 0;
 
429
  while (sp && n < max_depth) {
 
430
    if (*(sp+1) == reinterpret_cast<void *>(0)) {
 
431
      // In 64-bit code, we often see a frame that
 
432
      // points to itself and has a return address of 0.
 
433
      break;
 
434
    }
 
435
    // The GetStackFrames routine is called when we are in some
 
436
    // informational context (the failure signal handler for example).
 
437
    // Use the non-strict unwinding rules to produce a stack trace
 
438
    // that is as complete as possible (even if it contains a few bogus
 
439
    // entries in some rare cases).
 
440
    void **next_sp = NextStackFrame<false, false>(sp, NULL);
 
441
    if (skip_count > 0) {
 
442
      skip_count--;
 
443
    } else {
 
444
      pcs[n] = *(sp+1);
 
445
      if (next_sp > sp) {
 
446
        sizes[n] = (uintptr_t)next_sp - (uintptr_t)sp;
 
447
      } else {
 
448
        // A frame-size of 0 is used to indicate unknown frame size.
 
449
        sizes[n] = 0;
 
450
      }
 
451
      n++;
 
452
    }
 
453
    sp = next_sp;
 
454
  }
 
455
  return n;
 
456
}
 
457
 
 
458
// If you change this function, see NOTE at the top of file.
 
459
// Same as above, but with signal ucontext_t pointer.
 
460
int GetStackFramesWithContext(void** pcs,
 
461
                              int* sizes,
 
462
                              int max_depth,
 
463
                              int skip_count,
 
464
                              const void *uc) {
 
465
  void **sp;
 
466
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __llvm__
 
467
  // __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8.
 
468
  // It's always correct on llvm, and the techniques below aren't (in
 
469
  // particular, llvm-gcc will make a copy of pcs, so it's not in sp[2]),
 
470
  // so we also prefer __builtin_frame_address when running under llvm.
 
471
  sp = reinterpret_cast<void**>(__builtin_frame_address(0));
 
472
#elif defined(__i386__)
 
473
  // Stack frame format:
 
474
  //    sp[0]   pointer to previous frame
 
475
  //    sp[1]   caller address
 
476
  //    sp[2]   first argument
 
477
  //    ...
 
478
  // NOTE: This will break under llvm, since result is a copy and not in sp[2]
 
479
  sp = (void **)&pcs - 2;
 
480
#elif defined(__x86_64__)
 
481
  unsigned long rbp;
 
482
  // Move the value of the register %rbp into the local variable rbp.
 
483
  // We need 'volatile' to prevent this instruction from getting moved
 
484
  // around during optimization to before function prologue is done.
 
485
  // An alternative way to achieve this
 
486
  // would be (before this __asm__ instruction) to call Noop() defined as
 
487
  //   static void Noop() __attribute__ ((noinline));  // prevent inlining
 
488
  //   static void Noop() { asm(""); }  // prevent optimizing-away
 
489
  __asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
 
490
  // Arguments are passed in registers on x86-64, so we can't just
 
491
  // offset from &result
 
492
  sp = (void **) rbp;
 
493
#else
 
494
# error Using stacktrace_x86-inl.h on a non x86 architecture!
 
495
#endif
 
496
 
 
497
  int n = 0;
 
498
  while (sp && n < max_depth) {
 
499
    if (*(sp+1) == reinterpret_cast<void *>(0)) {
 
500
      // In 64-bit code, we often see a frame that
 
501
      // points to itself and has a return address of 0.
 
502
      break;
 
503
    }
 
504
    // The GetStackFrames routine is called when we are in some
 
505
    // informational context (the failure signal handler for example).
 
506
    // Use the non-strict unwinding rules to produce a stack trace
 
507
    // that is as complete as possible (even if it contains a few bogus
 
508
    // entries in some rare cases).
 
509
    void **next_sp = NextStackFrame<false, true>(sp, uc);
205
510
    if (skip_count > 0) {
206
511
      skip_count--;
207
512
    } else {