1 // 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 40 namespace { 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. 47 const int BACKTRACE_STEPS = 6; 48 49 struct AddressRange { 50 const void *start, *end; 51 }; 52 53 // Expected function [start,end] range. 54 AddressRange 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 101 void 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 109 void ATTRIBUTE_NOINLINE CheckStackTrace(int); 110 void 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. */ 147 void 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 } 155 void 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 } 163 void 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 } 171 void 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 } 179 void 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 190 int main(int argc, char ** argv) { 191 CheckStackTrace(0); 192 printf("PASS\n"); 193 return 0; 194 } 195