Utilize the second parameter (version number) for deb.sh.
[platform/upstream/glog.git] / src / stacktrace_x86_64-inl.h
1 // Copyright 2005 - 2007 Google Inc.
2 // All rights reserved.
3 //
4 // Author: Arun Sharma
5 //
6 // Produce stack trace using libgcc
7
8 extern "C" {
9 #include <stdlib.h> // for NULL
10 #include <unwind.h> // ABI defined unwinder
11 }
12 #include "stacktrace.h"
13
14 _START_GOOGLE_NAMESPACE_
15
16 typedef struct {
17   void **result;
18   int max_depth;
19   int skip_count;
20   int count;
21 } trace_arg_t;
22
23
24 // Workaround for the malloc() in _Unwind_Backtrace() issue.
25 static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context *uc, void *opq) {
26   return _URC_NO_REASON;
27 }
28
29
30 // This code is not considered ready to run until
31 // static initializers run so that we are guaranteed
32 // that any malloc-related initialization is done.
33 static bool ready_to_run = false;
34 class StackTraceInit {
35  public:
36    StackTraceInit() {
37      // Extra call to force initialization
38      _Unwind_Backtrace(nop_backtrace, NULL);
39      ready_to_run = true;
40    }
41 };
42
43 static StackTraceInit module_initializer;  // Force initialization
44
45 static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
46   trace_arg_t *targ = (trace_arg_t *) opq;
47
48   if (targ->skip_count > 0) {
49     targ->skip_count--;
50   } else {
51     targ->result[targ->count++] = (void *) _Unwind_GetIP(uc);
52   }
53
54   if (targ->count == targ->max_depth)
55     return _URC_END_OF_STACK;
56
57   return _URC_NO_REASON;
58 }
59
60 // If you change this function, also change GetStackFrames below.
61 int GetStackTrace(void** result, int max_depth, int skip_count) {
62   if (!ready_to_run)
63     return 0;
64
65   trace_arg_t targ;
66
67   skip_count += 1;         // Do not include the "GetStackTrace" frame
68
69   targ.result = result;
70   targ.max_depth = max_depth;
71   targ.skip_count = skip_count;
72   targ.count = 0;
73
74   _Unwind_Backtrace(GetOneFrame, &targ);
75
76   return targ.count;
77 }
78
79 // If you change this function, also change GetStackTrace above:
80 //
81 // This GetStackFrames routine shares a lot of code with GetStackTrace
82 // above. This code could have been refactored into a common routine,
83 // and then both GetStackTrace/GetStackFrames could call that routine.
84 // There are two problems with that:
85 //
86 // (1) The performance of the refactored-code suffers substantially - the
87 //     refactored needs to be able to record the stack trace when called
88 //     from GetStackTrace, and both the stack trace and stack frame sizes,
89 //     when called from GetStackFrames - this introduces enough new
90 //     conditionals that GetStackTrace performance can degrade by as much
91 //     as 50%.
92 //
93 // (2) Whether the refactored routine gets inlined into GetStackTrace and
94 //     GetStackFrames depends on the compiler, and we can't guarantee the
95 //     behavior either-way, even with "__attribute__ ((always_inline))"
96 //     or "__attribute__ ((noinline))". But we need this guarantee or the
97 //     frame counts may be off by one.
98 //
99 // Both (1) and (2) can be addressed without this code duplication, by
100 // clever use of template functions, and by defining GetStackTrace and
101 // GetStackFrames as macros that expand to these template functions.
102 // However, this approach comes with its own set of problems - namely,
103 // macros and  preprocessor trouble - for example,  if GetStackTrace
104 // and/or GetStackFrames is ever defined as a member functions in some
105 // class, we are in trouble.
106 int GetStackFrames(void** pcs, int* sizes, int max_depth, int skip_count) {
107   if (!ready_to_run)
108     return 0;
109
110   trace_arg_t targ;
111
112   skip_count += 1;         // Do not include the "GetStackFrames" frame
113
114   targ.result = pcs;
115   targ.max_depth = max_depth;
116   targ.skip_count = skip_count;
117   targ.count = 0;
118
119   _Unwind_Backtrace(GetOneFrame, &targ);
120
121   // No implementation for finding out the stack frame sizes yet.
122   memset(sizes, 0, sizeof(*sizes) * targ.count);
123
124   return targ.count;
125 }
126
127 _END_GOOGLE_NAMESPACE_