stacktrace_unittest.cc
Go to the documentation of this file.
1 // Copyright (c) 2004, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "utilities.h"
31 
32 #include <cstdio>
33 #include <cstdlib>
34 #include "config.h"
35 #include "base/commandlineflags.h"
36 #include <glog/logging.h>
37 #include "stacktrace.h"
38 
39 #ifdef HAVE_EXECINFO_H
40 # include <execinfo.h>
41 #endif
42 
43 using namespace GOOGLE_NAMESPACE;
44 
45 #ifdef HAVE_STACKTRACE
46 
47 // Obtain a backtrace, verify that the expected callers are present in the
48 // backtrace, and maybe print the backtrace to stdout.
49 
50 // The sequence of functions whose return addresses we expect to see in the
51 // backtrace.
52 const int BACKTRACE_STEPS = 6;
53 
54 struct AddressRange {
55  const void *start, *end;
56 };
57 
58 // Expected function [start,end] range.
59 AddressRange expected_range[BACKTRACE_STEPS];
60 
61 #if __GNUC__
62 // Using GCC extension: address of a label can be taken with '&&label'.
63 // Start should be a label somewhere before recursive call, end somewhere
64 // after it.
65 #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
66  do { \
67  (prange)->start = &&start_label; \
68  (prange)->end = &&end_label; \
69  CHECK_LT((prange)->start, (prange)->end); \
70  } while (0)
71 // This macro expands into "unmovable" code (opaque to GCC), and that
72 // prevents GCC from moving a_label up or down in the code.
73 // Without it, there is no code following the 'end' label, and GCC
74 // (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
75 // the recursive call.
76 #define DECLARE_ADDRESS_LABEL(a_label) \
77  a_label: do { __asm__ __volatile__(""); } while (0)
78 // Gcc 4.4.0 may split function into multiple chunks, and the chunk
79 // performing recursive call may end up later in the code then the return
80 // instruction (this actually happens with FDO).
81 // Adjust function range from __builtin_return_address.
82 #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
83  do { \
84  void *ra = __builtin_return_address(0); \
85  CHECK_LT((prange)->start, ra); \
86  if (ra > (prange)->end) { \
87  printf("Adjusting range from %p..%p to %p..%p\n", \
88  (prange)->start, (prange)->end, \
89  (prange)->start, ra); \
90  (prange)->end = ra; \
91  } \
92  } while (0)
93 #else
94 // Assume the Check* functions below are not longer than 256 bytes.
95 #define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
96  do { \
97  (prange)->start = reinterpret_cast<const void *>(&fn); \
98  (prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
99  } while (0)
100 #define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
101 #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
102 #endif // __GNUC__
103 
104 //-----------------------------------------------------------------------//
105 
106 static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
107 {
108  CHECK_GE(ret_addr, range.start);
109  CHECK_LE(ret_addr, range.end);
110 }
111 
112 //-----------------------------------------------------------------------//
113 
114 #if defined(__clang__)
115 #pragma clang diagnostic push
116 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
117 #endif
118 
119 void ATTRIBUTE_NOINLINE CheckStackTrace(int);
120 static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
121  const int STACK_LEN = 10;
122  void *stack[STACK_LEN];
123  int size;
124 
125  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
126  INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
127  DECLARE_ADDRESS_LABEL(start);
128  size = GetStackTrace(stack, STACK_LEN, 0);
129  printf("Obtained %d stack frames.\n", size);
130  CHECK_GE(size, 1);
131  CHECK_LE(size, STACK_LEN);
132 
133  if (1) {
134 #ifdef HAVE_EXECINFO_H
135  char **strings = backtrace_symbols(stack, size);
136  printf("Obtained %d stack frames.\n", size);
137  for (int i = 0; i < size; i++) {
138  printf("%s %p\n", strings[i], stack[i]);
139  }
140 
141  union {
142  void (*p1)(int);
143  void* p2;
144  } p = {&CheckStackTrace};
145 
146  printf("CheckStackTrace() addr: %p\n", p.p2);
147  free(strings);
148 #endif
149  }
150  for (int i = 0; i < BACKTRACE_STEPS; i++) {
151  printf("Backtrace %d: expected: %p..%p actual: %p ... ",
152  i, expected_range[i].start, expected_range[i].end, stack[i]);
153  fflush(stdout);
154  CheckRetAddrIsInFunction(stack[i], expected_range[i]);
155  printf("OK\n");
156  }
157  DECLARE_ADDRESS_LABEL(end);
158 }
159 
160 //-----------------------------------------------------------------------//
161 
162 /* Dummy functions to make the backtrace more interesting. */
163 static void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
164  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
165  INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
166  DECLARE_ADDRESS_LABEL(start);
167  for (int j = i; j >= 0; j--) {
168  CheckStackTraceLeaf();
169  }
170  DECLARE_ADDRESS_LABEL(end);
171 }
172 static void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
173  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
174  INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
175  DECLARE_ADDRESS_LABEL(start);
176  for (int j = i; j >= 0; j--) {
177  CheckStackTrace4(j);
178  }
179  DECLARE_ADDRESS_LABEL(end);
180 }
181 static void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
182  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
183  INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
184  DECLARE_ADDRESS_LABEL(start);
185  for (int j = i; j >= 0; j--) {
186  CheckStackTrace3(j);
187  }
188  DECLARE_ADDRESS_LABEL(end);
189 }
190 static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
191  ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
192  INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
193  DECLARE_ADDRESS_LABEL(start);
194  for (int j = i; j >= 0; j--) {
195  CheckStackTrace2(j);
196  }
197  DECLARE_ADDRESS_LABEL(end);
198 }
199 
200 #ifndef __GNUC__
201 // On non-GNU environment, we use the address of `CheckStackTrace` to
202 // guess the address range of this function. This guess is wrong for
203 // non-static function on Windows. This is probably because
204 // `&CheckStackTrace` returns the address of a trampoline like PLT,
205 // not the actual address of `CheckStackTrace`.
206 // See https://github.com/google/glog/issues/421 for the detail.
207 static
208 #endif
209 void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
210  INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
211  DECLARE_ADDRESS_LABEL(start);
212  for (int j = i; j >= 0; j--) {
213  CheckStackTrace1(j);
214  }
215  DECLARE_ADDRESS_LABEL(end);
216 }
217 
218 #if defined(__clang__)
219 #pragma clang diagnostic pop
220 #endif
221 
222 //-----------------------------------------------------------------------//
223 
224 int main(int, char ** argv) {
225  FLAGS_logtostderr = true;
226  InitGoogleLogging(argv[0]);
227 
228  CheckStackTrace(0);
229 
230  printf("PASS\n");
231  return 0;
232 }
233 
234 #else
235 int main() {
236  printf("PASS (no stacktrace support)\n");
237  return 0;
238 }
239 #endif // HAVE_STACKTRACE
CHECK_LE
#define CHECK_LE(a, b)
Definition: check.h:68
end
GLuint GLuint end
Definition: glcorearb.h:2858
strings
GLsizei const GLchar *const * strings
Definition: glcorearb.h:4046
main
int main()
Definition: stacktrace_unittest.cc:235
ATTRIBUTE_NOINLINE
#define ATTRIBUTE_NOINLINE
Definition: utilities.h:142
GetStackTrace
_START_GOOGLE_NAMESPACE_ GLOG_EXPORT int GetStackTrace(void **result, int max_depth, int skip_count)
Definition: stacktrace_generic-inl.h:41
conformance_python.stdout
stdout
Definition: conformance_python.py:50
range
GLenum GLint * range
Definition: glcorearb.h:3963
google::protobuf.internal
Definition: python/google/protobuf/internal/__init__.py:1
start
GLuint start
Definition: glcorearb.h:2858
p
const char * p
Definition: gmock-matchers_test.cc:3863
size
#define size
Definition: glcorearb.h:2944
FLAGS_logtostderr
static int FLAGS_logtostderr
Definition: sdk/include/aditof/log.h:67
commandlineflags.h
utilities.h
void
typedef void(APIENTRY *GLDEBUGPROCARB)(GLenum source
i
int i
Definition: gmock-matchers_test.cc:764
size
GLsizeiptr size
Definition: glcorearb.h:2943
stacktrace.h
InitGoogleLogging
void InitGoogleLogging(const char *argv0)
Definition: logging.cc:2618
CHECK_GE
#define CHECK_GE(a, b)
Definition: check.h:67


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:58