blob: e55a6322e5aab61d1085ace54f076486d18e7622 [file] [log] [blame]
Brian Silverman20350ac2021-11-17 18:19:55 -08001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
Austin Schuh745610d2015-09-06 18:19:50 -07002// Copyright (c) 2005, Google Inc.
3// All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004//
Austin Schuh745610d2015-09-06 18:19:50 -07005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008//
Austin Schuh745610d2015-09-06 18:19:50 -07009// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
Brian Silverman20350ac2021-11-17 18:19:55 -080018//
Austin Schuh745610d2015-09-06 18:19:50 -070019// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include "config_for_unittests.h"
32#ifdef HAVE_EXECINFO_H
33#include <execinfo.h>
34#endif
35#include <stdio.h>
36#include <stdlib.h>
Brian Silverman20350ac2021-11-17 18:19:55 -080037
38// On those architectures we can and should test if backtracing with
39// ucontext and from signal handler works
40#if __GNUC__ && __linux__ && (__x86_64__ || __aarch64__ || __riscv)
41#include <signal.h>
42#define TEST_UCONTEXT_BITS 1
43#endif
44
Austin Schuh745610d2015-09-06 18:19:50 -070045#include "base/commandlineflags.h"
46#include "base/logging.h"
47#include <gperftools/stacktrace.h>
Brian Silverman20350ac2021-11-17 18:19:55 -080048#include "tests/testutil.h"
Austin Schuh745610d2015-09-06 18:19:50 -070049
50namespace {
51
52// Obtain a backtrace, verify that the expected callers are present in the
53// backtrace, and maybe print the backtrace to stdout.
54
55// The sequence of functions whose return addresses we expect to see in the
56// backtrace.
57const int BACKTRACE_STEPS = 6;
58
59struct AddressRange {
60 const void *start, *end;
61};
62
63// Expected function [start,end] range.
64AddressRange expected_range[BACKTRACE_STEPS];
65
66#if __GNUC__
67// Using GCC extension: address of a label can be taken with '&&label'.
68// Start should be a label somewhere before recursive call, end somewhere
69// after it.
70#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
71 do { \
72 (prange)->start = &&start_label; \
73 (prange)->end = &&end_label; \
74 CHECK_LT((prange)->start, (prange)->end); \
75 } while (0)
76// This macro expands into "unmovable" code (opaque to GCC), and that
77// prevents GCC from moving a_label up or down in the code.
78// Without it, there is no code following the 'end' label, and GCC
79// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
80// the recursive call.
81#define DECLARE_ADDRESS_LABEL(a_label) \
82 a_label: do { __asm__ __volatile__(""); } while (0)
83// Gcc 4.4.0 may split function into multiple chunks, and the chunk
84// performing recursive call may end up later in the code then the return
85// instruction (this actually happens with FDO).
86// Adjust function range from __builtin_return_address.
87#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
88 do { \
89 void *ra = __builtin_return_address(0); \
90 CHECK_LT((prange)->start, ra); \
91 if (ra > (prange)->end) { \
92 printf("Adjusting range from %p..%p to %p..%p\n", \
93 (prange)->start, (prange)->end, \
94 (prange)->start, ra); \
95 (prange)->end = ra; \
96 } \
97 } while (0)
98#else
99// Assume the Check* functions below are not longer than 256 bytes.
100#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
101 do { \
102 (prange)->start = reinterpret_cast<const void *>(&fn); \
103 (prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
104 } while (0)
105#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
106#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
107#endif // __GNUC__
108
Brian Silverman20350ac2021-11-17 18:19:55 -0800109
Austin Schuh745610d2015-09-06 18:19:50 -0700110//-----------------------------------------------------------------------//
111
112void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
113{
114 CHECK_GE(ret_addr, range.start);
115 CHECK_LE(ret_addr, range.end);
116}
117
118//-----------------------------------------------------------------------//
119
Brian Silverman20350ac2021-11-17 18:19:55 -0800120#if TEST_UCONTEXT_BITS
121
122struct get_stack_trace_args {
123 int *size_ptr;
124 void **result;
125 int max_depth;
126 uintptr_t where;
127} gst_args;
128
129static
130void SignalHandler(int dummy, siginfo_t *si, void* ucv) {
131 auto uc = static_cast<ucontext_t*>(ucv);
132
133#ifdef __riscv
134 uc->uc_mcontext.__gregs[REG_PC] = gst_args.where;
135#elif __aarch64__
136 uc->uc_mcontext.pc = gst_args.where;
137#else
138 uc->uc_mcontext.gregs[REG_RIP] = gst_args.where;
139#endif
140
141 *gst_args.size_ptr = GetStackTraceWithContext(
142 gst_args.result,
143 gst_args.max_depth,
144 2,
145 uc);
146}
147
148int ATTRIBUTE_NOINLINE CaptureLeafUContext(void **stack, int stack_len) {
149 INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
150 DECLARE_ADDRESS_LABEL(start);
151
152 int size;
153
154 printf("Capturing stack trace from signal's ucontext\n");
155 struct sigaction sa;
156 memset(&sa, 0, sizeof(sa));
157 sa.sa_sigaction = SignalHandler;
158 sa.sa_flags = SA_SIGINFO | SA_RESETHAND;
159 int rv = sigaction(SIGSEGV, &sa, nullptr);
160 CHECK(rv == 0);
161
162 gst_args.size_ptr = &size;
163 gst_args.result = stack;
164 gst_args.max_depth = stack_len;
165 gst_args.where = reinterpret_cast<uintptr_t>(noopt(&&after));
166
167 // now, "write" to null pointer and trigger sigsegv to run signal
168 // handler. It'll then change PC to after, as if we jumped one line
169 // below.
170 *noopt(reinterpret_cast<void**>(0)) = 0;
171 // this is not reached, but gcc gets really odd if we don't actually
172 // use computed goto.
173 static void* jump_target = &&after;
174 goto *noopt(&jump_target);
175
176after:
177 printf("Obtained %d stack frames.\n", size);
178 CHECK_GE(size, 1);
179 CHECK_LE(size, stack_len);
180
181 DECLARE_ADDRESS_LABEL(end);
182
183 return size;
184}
185
186#endif // TEST_UCONTEXT_BITS
187
188int ATTRIBUTE_NOINLINE CaptureLeafPlain(void **stack, int stack_len) {
189 INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
190 DECLARE_ADDRESS_LABEL(start);
191
192 int size = GetStackTrace(stack, stack_len, 0);
193
194 printf("Obtained %d stack frames.\n", size);
195 CHECK_GE(size, 1);
196 CHECK_LE(size, stack_len);
197
198 DECLARE_ADDRESS_LABEL(end);
199
200 return size;
201}
202
Austin Schuh745610d2015-09-06 18:19:50 -0700203void ATTRIBUTE_NOINLINE CheckStackTrace(int);
Brian Silverman20350ac2021-11-17 18:19:55 -0800204
205int (*leaf_capture_fn)(void**, int) = CaptureLeafPlain;
206
207void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(int i) {
208 const int STACK_LEN = 20;
Austin Schuh745610d2015-09-06 18:19:50 -0700209 void *stack[STACK_LEN];
210 int size;
211
212 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
Brian Silverman20350ac2021-11-17 18:19:55 -0800213
214 size = leaf_capture_fn(stack, STACK_LEN);
Austin Schuh745610d2015-09-06 18:19:50 -0700215
216#ifdef HAVE_EXECINFO_H
217 {
218 char **strings = backtrace_symbols(stack, size);
Austin Schuh745610d2015-09-06 18:19:50 -0700219 for (int i = 0; i < size; i++)
220 printf("%s %p\n", strings[i], stack[i]);
221 printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
222 free(strings);
223 }
224#endif
225
Brian Silverman20350ac2021-11-17 18:19:55 -0800226 for (int i = 0, j = 0; i < BACKTRACE_STEPS; i++, j++) {
227 if (i == 1 && j == 1) {
228 // this is expected to be our function for which we don't
229 // establish bounds. So skip.
230 j++;
231 }
Austin Schuh745610d2015-09-06 18:19:50 -0700232 printf("Backtrace %d: expected: %p..%p actual: %p ... ",
Brian Silverman20350ac2021-11-17 18:19:55 -0800233 i, expected_range[i].start, expected_range[i].end, stack[j]);
Austin Schuh745610d2015-09-06 18:19:50 -0700234 fflush(stdout);
Brian Silverman20350ac2021-11-17 18:19:55 -0800235 CheckRetAddrIsInFunction(stack[j], expected_range[i]);
Austin Schuh745610d2015-09-06 18:19:50 -0700236 printf("OK\n");
237 }
Austin Schuh745610d2015-09-06 18:19:50 -0700238}
239
240//-----------------------------------------------------------------------//
241
242/* Dummy functions to make the backtrace more interesting. */
243void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
244 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
245 INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
246 DECLARE_ADDRESS_LABEL(start);
247 for (int j = i; j >= 0; j--)
Brian Silverman20350ac2021-11-17 18:19:55 -0800248 CheckStackTraceLeaf(j);
Austin Schuh745610d2015-09-06 18:19:50 -0700249 DECLARE_ADDRESS_LABEL(end);
250}
251void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
252 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
253 INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
254 DECLARE_ADDRESS_LABEL(start);
255 for (int j = i; j >= 0; j--)
256 CheckStackTrace4(j);
257 DECLARE_ADDRESS_LABEL(end);
258}
259void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
260 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
261 INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
262 DECLARE_ADDRESS_LABEL(start);
263 for (int j = i; j >= 0; j--)
264 CheckStackTrace3(j);
265 DECLARE_ADDRESS_LABEL(end);
266}
267void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
268 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
269 INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
270 DECLARE_ADDRESS_LABEL(start);
271 for (int j = i; j >= 0; j--)
272 CheckStackTrace2(j);
273 DECLARE_ADDRESS_LABEL(end);
274}
275void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
276 INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
277 DECLARE_ADDRESS_LABEL(start);
Brian Silverman20350ac2021-11-17 18:19:55 -0800278 for (int j = i; j >= 0; j--) {
Austin Schuh745610d2015-09-06 18:19:50 -0700279 CheckStackTrace1(j);
Brian Silverman20350ac2021-11-17 18:19:55 -0800280 }
Austin Schuh745610d2015-09-06 18:19:50 -0700281 DECLARE_ADDRESS_LABEL(end);
282}
283
284} // namespace
285//-----------------------------------------------------------------------//
286
287int main(int argc, char ** argv) {
288 CheckStackTrace(0);
289 printf("PASS\n");
Brian Silverman20350ac2021-11-17 18:19:55 -0800290
291#if TEST_UCONTEXT_BITS
292 leaf_capture_fn = CaptureLeafUContext;
293 CheckStackTrace(0);
294 printf("PASS\n");
295#endif // TEST_UCONTEXT_BITS
296
Austin Schuh745610d2015-09-06 18:19:50 -0700297 return 0;
298}