Merge pull request #209 from sergiud/cmake-icc-fix
[platform/upstream/glog.git] / src / stacktrace_unittest.cc
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 <stdio.h>
33 #include <stdlib.h>
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 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 void ATTRIBUTE_NOINLINE CheckStackTrace(int);
115 void ATTRIBUTE_NOINLINE CheckStackTraceLeaf(void) {
116   const int STACK_LEN = 10;
117   void *stack[STACK_LEN];
118   int size;
119
120   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
121   INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
122   DECLARE_ADDRESS_LABEL(start);
123   size = GetStackTrace(stack, STACK_LEN, 0);
124   printf("Obtained %d stack frames.\n", size);
125   CHECK_GE(size, 1);
126   CHECK_LE(size, STACK_LEN);
127
128   if (1) {
129 #ifdef HAVE_EXECINFO_H
130     char **strings = backtrace_symbols(stack, size);
131     printf("Obtained %d stack frames.\n", size);
132     for (int i = 0; i < size; i++)
133       printf("%s %p\n", strings[i], stack[i]);
134     printf("CheckStackTrace() addr: %p\n", &CheckStackTrace);
135     free(strings);
136 #endif
137   }
138   for (int i = 0; i < BACKTRACE_STEPS; i++) {
139     printf("Backtrace %d: expected: %p..%p  actual: %p ... ",
140            i, expected_range[i].start, expected_range[i].end, stack[i]);
141     fflush(stdout);
142     CheckRetAddrIsInFunction(stack[i], expected_range[i]);
143     printf("OK\n");
144   }
145   DECLARE_ADDRESS_LABEL(end);
146 }
147
148 //-----------------------------------------------------------------------//
149
150 /* Dummy functions to make the backtrace more interesting. */
151 void ATTRIBUTE_NOINLINE CheckStackTrace4(int i) {
152   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[2]);
153   INIT_ADDRESS_RANGE(CheckStackTrace4, start, end, &expected_range[1]);
154   DECLARE_ADDRESS_LABEL(start);
155   for (int j = i; j >= 0; j--)
156     CheckStackTraceLeaf();
157   DECLARE_ADDRESS_LABEL(end);
158 }
159 void ATTRIBUTE_NOINLINE CheckStackTrace3(int i) {
160   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[3]);
161   INIT_ADDRESS_RANGE(CheckStackTrace3, start, end, &expected_range[2]);
162   DECLARE_ADDRESS_LABEL(start);
163   for (int j = i; j >= 0; j--)
164     CheckStackTrace4(j);
165   DECLARE_ADDRESS_LABEL(end);
166 }
167 void ATTRIBUTE_NOINLINE CheckStackTrace2(int i) {
168   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[4]);
169   INIT_ADDRESS_RANGE(CheckStackTrace2, start, end, &expected_range[3]);
170   DECLARE_ADDRESS_LABEL(start);
171   for (int j = i; j >= 0; j--)
172     CheckStackTrace3(j);
173   DECLARE_ADDRESS_LABEL(end);
174 }
175 void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
176   ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[5]);
177   INIT_ADDRESS_RANGE(CheckStackTrace1, start, end, &expected_range[4]);
178   DECLARE_ADDRESS_LABEL(start);
179   for (int j = i; j >= 0; j--)
180     CheckStackTrace2(j);
181   DECLARE_ADDRESS_LABEL(end);
182 }
183 void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
184   INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
185   DECLARE_ADDRESS_LABEL(start);
186   for (int j = i; j >= 0; j--)
187     CheckStackTrace1(j);
188   DECLARE_ADDRESS_LABEL(end);
189 }
190
191 //-----------------------------------------------------------------------//
192
193 int main(int, char ** argv) {
194   FLAGS_logtostderr = true;
195   InitGoogleLogging(argv[0]);
196
197   CheckStackTrace(0);
198
199   printf("PASS\n");
200   return 0;
201 }
202
203 #else
204 int main() {
205   printf("PASS (no stacktrace support)\n");
206   return 0;
207 }
208 #endif  // HAVE_STACKTRACE