Re-organize the way to produce stacktrace.
[platform/upstream/glog.git] / src / stacktrace_libunwind-inl.h
1 // Copyright 2005 - 2007 Google Inc.
2 // All rights reserved.
3 //
4 // Author: Arun Sharma
5 //
6 // Produce stack trace using libunwind
7
8 #include "utilities.h"
9
10 extern "C" {
11 #define UNW_LOCAL_ONLY
12 #include <libunwind.h>
13 }
14 #include "glog/raw_logging.h"
15 #include "stacktrace.h"
16
17 _START_GOOGLE_NAMESPACE_
18
19 // Sometimes, we can try to get a stack trace from within a stack
20 // trace, because libunwind can call mmap (maybe indirectly via an
21 // internal mmap based memory allocator), and that mmap gets trapped
22 // and causes a stack-trace request.  If were to try to honor that
23 // recursive request, we'd end up with infinite recursion or deadlock.
24 // Luckily, it's safe to gnore those subsequent traces.  In such cases,
25 // we return 0 to indicate the situation.
26 static bool g_now_entering = false;
27
28 // If you change this function, also change GetStackFrames below.
29 int GetStackTrace(void** result, int max_depth, int skip_count) {
30   void *ip;
31   int n = 0;
32   unw_cursor_t cursor;
33   unw_context_t uc;
34
35   if (sync_val_compare_and_swap(&g_now_entering, false, true)) {
36     return 0;
37   }
38
39   unw_getcontext(&uc);
40   RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
41   skip_count++;         // Do not include the "GetStackTrace" frame
42
43   while (n < max_depth) {
44     int ret = unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *) &ip);
45     if (ret < 0)
46       break;
47     if (skip_count > 0) {
48       skip_count--;
49     } else {
50       result[n++] = ip;
51     }
52     ret = unw_step(&cursor);
53     if (ret <= 0)
54       break;
55   }
56
57   g_now_entering = false;
58   return n;
59 }
60
61 _END_GOOGLE_NAMESPACE_