blob: 3c9f73531eff664f3a342aa2d1b5dc2685e361e8 [file] [log] [blame]
Austin Schuh745610d2015-09-06 18:19:50 -07001// Copyright (c) 2005, 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 "config_for_unittests.h"
31#ifdef HAVE_EXECINFO_H
32#include <execinfo.h>
33#endif
34#include <stdio.h>
35#include <stdlib.h>
36#include "base/commandlineflags.h"
37#include "base/logging.h"
38#include <gperftools/stacktrace.h>
39
40namespace {
41
42// Obtain a backtrace, verify that the expected callers are present in the
43// backtrace, and maybe print the backtrace to stdout.
44
45// The sequence of functions whose return addresses we expect to see in the
46// backtrace.
47const int BACKTRACE_STEPS = 6;
48
49struct AddressRange {
50 const void *start, *end;
51};
52
53// Expected function [start,end] range.
54AddressRange expected_range[BACKTRACE_STEPS];
55
56#if __GNUC__
57// Using GCC extension: address of a label can be taken with '&&label'.
58// Start should be a label somewhere before recursive call, end somewhere
59// after it.
60#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
61 do { \
62 (prange)->start = &&start_label; \
63 (prange)->end = &&end_label; \
64 CHECK_LT((prange)->start, (prange)->end); \
65 } while (0)
66// This macro expands into "unmovable" code (opaque to GCC), and that
67// prevents GCC from moving a_label up or down in the code.
68// Without it, there is no code following the 'end' label, and GCC
69// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
70// the recursive call.
71#define DECLARE_ADDRESS_LABEL(a_label) \
72 a_label: do { __asm__ __volatile__(""); } while (0)
73// Gcc 4.4.0 may split function into multiple chunks, and the chunk
74// performing recursive call may end up later in the code then the return
75// instruction (this actually happens with FDO).
76// Adjust function range from __builtin_return_address.
77#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
78 do { \
79 void *ra = __builtin_return_address(0); \
80 CHECK_LT((prange)->start, ra); \
81 if (ra > (prange)->end) { \
82 printf("Adjusting range from %p..%p to %p..%p\n", \
83 (prange)->start, (prange)->end, \
84 (prange)->start, ra); \
85 (prange)->end = ra; \
86 } \
87 } while (0)
88#else
89// Assume the Check* functions below are not longer than 256 bytes.
90#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
91 do { \
92 (prange)->start = reinterpret_cast<const void *>(&fn); \
93 (prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
94 } while (0)
95#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
96#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
97#endif // __GNUC__
98
99//-----------------------------------------------------------------------//
100
101void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
102{
103 CHECK_GE(ret_addr, range.start);
104 CHECK_LE(ret_addr, range.end);
105}
106
107//-----------------------------------------------------------------------//
108
109void ATTRIBUTE_NOINLINE CheckStackTrace(int);
110void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
111 const int STACK_LEN = 10;
112 void *stack[STACK_LEN];
113 int size;
114
115 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
116 INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
117 DECLARE_ADDRESS_LABEL(start);
118 size = GetStackTrace(stack, STACK_LEN, 0);
119 printf("Obtained %d stack frames.\n", size);
120 CHECK_GE(size, 1);
121 CHECK_LE(size, STACK_LEN);
122
123#ifdef HAVE_EXECINFO_H
124 {
125 char **strings = backtrace_symbols(stack, size);
126 printf("Obtained %d stack frames.\n", size);
127 for (int i = 0; i < size; i++)
128 printf("%s %p\n", strings[i], stack[i]);
129 printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
130 free(strings);
131 }
132#endif
133
134 for (int i = 0; i < BACKTRACE_STEPS; i++) {
135 printf("Backtrace %d: expected: %p..%p actual: %p ... ",
136 i, expected_range[i].start, expected_range[i].end, stack[i]);
137 fflush(stdout);
138 CheckRetAddrIsInFunction(stack[i], expected_range[i]);
139 printf("OK\n");
140 }
141 DECLARE_ADDRESS_LABEL(end);
142}
143
144//-----------------------------------------------------------------------//
145
146/* Dummy functions to make the backtrace more interesting. */
147void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
148 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
149 INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
150 DECLARE_ADDRESS_LABEL(start);
151 for (int j = i; j >= 0; j--)
152 CheckStackTraceLeaf();
153 DECLARE_ADDRESS_LABEL(end);
154}
155void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
156 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
157 INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
158 DECLARE_ADDRESS_LABEL(start);
159 for (int j = i; j >= 0; j--)
160 CheckStackTrace4(j);
161 DECLARE_ADDRESS_LABEL(end);
162}
163void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
164 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
165 INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
166 DECLARE_ADDRESS_LABEL(start);
167 for (int j = i; j >= 0; j--)
168 CheckStackTrace3(j);
169 DECLARE_ADDRESS_LABEL(end);
170}
171void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
172 ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
173 INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
174 DECLARE_ADDRESS_LABEL(start);
175 for (int j = i; j >= 0; j--)
176 CheckStackTrace2(j);
177 DECLARE_ADDRESS_LABEL(end);
178}
179void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
180 INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
181 DECLARE_ADDRESS_LABEL(start);
182 for (int j = i; j >= 0; j--)
183 CheckStackTrace1(j);
184 DECLARE_ADDRESS_LABEL(end);
185}
186
187} // namespace
188//-----------------------------------------------------------------------//
189
190int main(int argc, char ** argv) {
191 CheckStackTrace(0);
192 printf("PASS\n");
193 return 0;
194}