stackwalker_selftest.cc
1 // Copyright 2006 Google LLC 2 // 3 // Redistribution and use in source and binary forms, with or without 4 // modification, are permitted provided that the following conditions are 5 // met: 6 // 7 // * Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above 10 // copyright notice, this list of conditions and the following disclaimer 11 // in the documentation and/or other materials provided with the 12 // distribution. 13 // * Neither the name of Google LLC nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 // stackwalker_selftest.cc: Tests StackwalkerX86 or StackwalkerPPC using the 30 // running process' stack as test data, if running on an x86 or ppc and 31 // compiled with gcc. This test is not enabled in the "make check" suite 32 // by default, because certain optimizations interfere with its proper 33 // operation. To turn it on, configure with --enable-selftest. 34 // 35 // Optimizations that cause problems: 36 // - stack frame reuse. The Recursor function here calls itself with 37 // |return Recursor|. When the caller's frame is reused, it will cause 38 // CountCallerFrames to correctly return the same number of frames 39 // in both the caller and callee. This is considered an unexpected 40 // condition in the test, which expects a callee to have one more 41 // caller frame in the stack than its caller. 42 // - frame pointer omission. Even with a stackwalker that understands 43 // this optimization, the code to harness debug information currently 44 // only exists to retrieve it from minidumps, not the current process. 45 // 46 // This test can also serve as a developmental and debugging aid if 47 // PRINT_STACKS is defined. 48 // 49 // Author: Mark Mentovai 50 51 #ifdef HAVE_CONFIG_H 52 #include <config.h> // Must come first 53 #endif 54 55 #include <assert.h> 56 57 #include "processor/logging.h" 58 59 #if defined(__i386) && !defined(__i386__) 60 #define __i386__ 61 #endif 62 #if defined(__sparc) && !defined(__sparc__) 63 #define __sparc__ 64 #endif 65 66 #if (defined(__SUNPRO_CC) || defined(__GNUC__)) && \ 67 (defined(__i386__) || defined(__ppc__) || defined(__sparc__)) 68 69 70 #include <stdio.h> 71 72 #include "common/scoped_ptr.h" 73 #include "google_breakpad/common/breakpad_types.h" 74 #include "google_breakpad/common/minidump_format.h" 75 #include "google_breakpad/processor/basic_source_line_resolver.h" 76 #include "google_breakpad/processor/call_stack.h" 77 #include "google_breakpad/processor/code_module.h" 78 #include "google_breakpad/processor/memory_region.h" 79 #include "google_breakpad/processor/stack_frame.h" 80 #include "google_breakpad/processor/stack_frame_cpu.h" 81 82 using google_breakpad::BasicSourceLineResolver; 83 using google_breakpad::CallStack; 84 using google_breakpad::CodeModule; 85 using google_breakpad::MemoryRegion; 86 using google_breakpad::scoped_ptr; 87 using google_breakpad::StackFrame; 88 using google_breakpad::StackFramePPC; 89 using google_breakpad::StackFrameX86; 90 using google_breakpad::StackFrameSPARC; 91 92 #if defined(__i386__) 93 #include "processor/stackwalker_x86.h" 94 using google_breakpad::StackwalkerX86; 95 #elif defined(__ppc__) 96 #include "processor/stackwalker_ppc.h" 97 using google_breakpad::StackwalkerPPC; 98 #elif defined(__sparc__) 99 #include "processor/stackwalker_sparc.h" 100 using google_breakpad::StackwalkerSPARC; 101 #endif // __i386__ || __ppc__ || __sparc__ 102 103 #define RECURSION_DEPTH 100 104 105 106 // A simple MemoryRegion subclass that provides direct access to this 107 // process' memory space by pointer. 108 class SelfMemoryRegion : public MemoryRegion { 109 public: 110 virtual uint64_t GetBase() const { return 0; } 111 virtual uint32_t GetSize() const { return 0xffffffff; } 112 113 bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const { 114 return GetMemoryAtAddressInternal(address, value); } 115 bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const { 116 return GetMemoryAtAddressInternal(address, value); } 117 bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const { 118 return GetMemoryAtAddressInternal(address, value); } 119 bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const { 120 return GetMemoryAtAddressInternal(address, value); } 121 void Print() const { 122 assert(false); 123 } 124 125 private: 126 template<typename T> bool GetMemoryAtAddressInternal(uint64_t address, 127 T* value) { 128 // Without knowing what addresses are actually mapped, just assume that 129 // everything low is not mapped. This helps the stackwalker catch the 130 // end of a stack when it tries to dereference a null or low pointer 131 // in an attempt to find the caller frame. Other unmapped accesses will 132 // cause the program to crash, but that would properly be a test failure. 133 if (address < 0x100) 134 return false; 135 136 uint8_t* memory = 0; 137 *value = *reinterpret_cast<const T*>(&memory[address]); 138 return true; 139 } 140 }; 141 142 143 #if defined(__GNUC__) 144 145 146 #if defined(__i386__) 147 148 // GetEBP returns the current value of the %ebp register. Because it's 149 // implemented as a function, %ebp itself contains GetEBP's frame pointer 150 // and not the caller's frame pointer. Dereference %ebp to obtain the 151 // caller's frame pointer, which the compiler-generated preamble stored 152 // on the stack (provided frame pointers are not being omitted.) Because 153 // this function depends on the compiler-generated preamble, inlining is 154 // disabled. 155 static uint32_t GetEBP() __attribute__((noinline)); 156 static uint32_t GetEBP() { 157 uint32_t ebp; 158 __asm__ __volatile__( 159 "movl (%%ebp), %0" 160 : "=a" (ebp) 161 ); 162 return ebp; 163 } 164 165 166 // The caller's %esp is 8 higher than the value of %ebp in this function, 167 // assuming that it's not inlined and that the standard prolog is used. 168 // The CALL instruction places a 4-byte return address on the stack above 169 // the caller's %esp, and this function's prolog will save the caller's %ebp 170 // on the stack as well, for another 4 bytes, before storing %esp in %ebp. 171 static uint32_t GetESP() __attribute__((noinline)); 172 static uint32_t GetESP() { 173 uint32_t ebp; 174 __asm__ __volatile__( 175 "movl %%ebp, %0" 176 : "=a" (ebp) 177 ); 178 return ebp + 8; 179 } 180 181 182 // GetEIP returns the instruction pointer identifying the next instruction 183 // to execute after GetEIP returns. It obtains this information from the 184 // stack, where it was placed by the call instruction that called GetEIP. 185 // This function depends on frame pointers not being omitted. It is possible 186 // to write a pure asm version of this routine that has no compiler-generated 187 // preamble and uses %esp instead of %ebp; that would function in the 188 // absence of frame pointers. However, the simpler approach is used here 189 // because GetEBP and stackwalking necessarily depends on access to frame 190 // pointers. Because this function depends on a call instruction and the 191 // compiler-generated preamble, inlining is disabled. 192 static uint32_t GetEIP() __attribute__((noinline)); 193 static uint32_t GetEIP() { 194 uint32_t eip; 195 __asm__ __volatile__( 196 "movl 4(%%ebp), %0" 197 : "=a" (eip) 198 ); 199 return eip; 200 } 201 202 203 #elif defined(__ppc__) 204 205 206 // GetSP returns the current value of the %r1 register, which by convention, 207 // is the stack pointer on ppc. Because it's implemented as a function, 208 // %r1 itself contains GetSP's own stack pointer and not the caller's stack 209 // pointer. Dereference %r1 to obtain the caller's stack pointer, which the 210 // compiler-generated prolog stored on the stack. Because this function 211 // depends on the compiler-generated prolog, inlining is disabled. 212 static uint32_t GetSP() __attribute__((noinline)); 213 static uint32_t GetSP() { 214 uint32_t sp; 215 __asm__ __volatile__( 216 "lwz %0, 0(r1)" 217 : "=r" (sp) 218 ); 219 return sp; 220 } 221 222 223 // GetPC returns the program counter identifying the next instruction to 224 // execute after GetPC returns. It obtains this information from the 225 // link register, where it was placed by the branch instruction that called 226 // GetPC. Because this function depends on the caller's use of a branch 227 // instruction, inlining is disabled. 228 static uint32_t GetPC() __attribute__((noinline)); 229 static uint32_t GetPC() { 230 uint32_t lr; 231 __asm__ __volatile__( 232 "mflr %0" 233 : "=r" (lr) 234 ); 235 return lr; 236 } 237 238 239 #elif defined(__sparc__) 240 241 242 // GetSP returns the current value of the %sp/%o6/%g_r[14] register, which 243 // by convention, is the stack pointer on sparc. Because it's implemented 244 // as a function, %sp itself contains GetSP's own stack pointer and not 245 // the caller's stack pointer. Dereference to obtain the caller's stack 246 // pointer, which the compiler-generated prolog stored on the stack. 247 // Because this function depends on the compiler-generated prolog, inlining 248 // is disabled. 249 static uint32_t GetSP() __attribute__((noinline)); 250 static uint32_t GetSP() { 251 uint32_t sp; 252 __asm__ __volatile__( 253 "mov %%fp, %0" 254 : "=r" (sp) 255 ); 256 return sp; 257 } 258 259 // GetFP returns the current value of the %fp register. Because it's 260 // implemented as a function, %fp itself contains GetFP's frame pointer 261 // and not the caller's frame pointer. Dereference %fp to obtain the 262 // caller's frame pointer, which the compiler-generated preamble stored 263 // on the stack (provided frame pointers are not being omitted.) Because 264 // this function depends on the compiler-generated preamble, inlining is 265 // disabled. 266 static uint32_t GetFP() __attribute__((noinline)); 267 static uint32_t GetFP() { 268 uint32_t fp; 269 __asm__ __volatile__( 270 "ld [%%fp+56], %0" 271 : "=r" (fp) 272 ); 273 return fp; 274 } 275 276 // GetPC returns the program counter identifying the next instruction to 277 // execute after GetPC returns. It obtains this information from the 278 // link register, where it was placed by the branch instruction that called 279 // GetPC. Because this function depends on the caller's use of a branch 280 // instruction, inlining is disabled. 281 static uint32_t GetPC() __attribute__((noinline)); 282 static uint32_t GetPC() { 283 uint32_t pc; 284 __asm__ __volatile__( 285 "mov %%i7, %0" 286 : "=r" (pc) 287 ); 288 return pc + 8; 289 } 290 291 #endif // __i386__ || __ppc__ || __sparc__ 292 293 #elif defined(__SUNPRO_CC) 294 295 #if defined(__i386__) 296 extern "C" { 297 extern uint32_t GetEIP(); 298 extern uint32_t GetEBP(); 299 extern uint32_t GetESP(); 300 } 301 #elif defined(__sparc__) 302 extern "C" { 303 extern uint32_t GetPC(); 304 extern uint32_t GetFP(); 305 extern uint32_t GetSP(); 306 } 307 #endif // __i386__ || __sparc__ 308 309 #endif // __GNUC__ || __SUNPRO_CC 310 311 // CountCallerFrames returns the number of stack frames beneath the function 312 // that called CountCallerFrames. Because this function's return value 313 // is dependent on the size of the stack beneath it, inlining is disabled, 314 // and any function that calls this should not be inlined either. 315 #if defined(__GNUC__) 316 static unsigned int CountCallerFrames() __attribute__((noinline)); 317 #elif defined(__SUNPRO_CC) 318 static unsigned int CountCallerFrames(); 319 #endif 320 static unsigned int CountCallerFrames() { 321 SelfMemoryRegion memory; 322 BasicSourceLineResolver resolver; 323 324 #if defined(__i386__) 325 MDRawContextX86 context = MDRawContextX86(); 326 context.eip = GetEIP(); 327 context.ebp = GetEBP(); 328 context.esp = GetESP(); 329 330 StackwalkerX86 stackwalker = StackwalkerX86(NULL, &context, &memory, NULL, 331 NULL, &resolver); 332 #elif defined(__ppc__) 333 MDRawContextPPC context = MDRawContextPPC(); 334 context.srr0 = GetPC(); 335 context.gpr[1] = GetSP(); 336 337 StackwalkerPPC stackwalker = StackwalkerPPC(NULL, &context, &memory, NULL, 338 NULL, &resolver); 339 #elif defined(__sparc__) 340 MDRawContextSPARC context = MDRawContextSPARC(); 341 context.pc = GetPC(); 342 context.g_r[14] = GetSP(); 343 context.g_r[30] = GetFP(); 344 345 StackwalkerSPARC stackwalker = StackwalkerSPARC(NULL, &context, &memory, 346 NULL, NULL, &resolver); 347 #endif // __i386__ || __ppc__ || __sparc__ 348 349 CallStack stack; 350 vector<const CodeModule*> modules_without_symbols; 351 stackwalker.Walk(&stack, &modules_without_symbols); 352 353 #ifdef PRINT_STACKS 354 printf("\n"); 355 for (unsigned int frame_index = 0; 356 frame_index < stack.frames()->size(); 357 ++frame_index) { 358 StackFrame *frame = stack.frames()->at(frame_index); 359 printf("frame %-3d instruction = 0x%08" PRIx64, 360 frame_index, frame->instruction); 361 #if defined(__i386__) 362 StackFrameX86 *frame_x86 = reinterpret_cast<StackFrameX86*>(frame); 363 printf(" esp = 0x%08x ebp = 0x%08x\n", 364 frame_x86->context.esp, frame_x86->context.ebp); 365 #elif defined(__ppc__) 366 StackFramePPC *frame_ppc = reinterpret_cast<StackFramePPC*>(frame); 367 printf(" gpr[1] = 0x%08x\n", frame_ppc->context.gpr[1]); 368 #elif defined(__sparc__) 369 StackFrameSPARC *frame_sparc = reinterpret_cast<StackFrameSPARC*>(frame); 370 printf(" sp = 0x%08x fp = 0x%08x\n", 371 frame_sparc->context.g_r[14], frame_sparc->context.g_r[30]); 372 #endif // __i386__ || __ppc__ || __sparc__ 373 } 374 #endif // PRINT_STACKS 375 376 // Subtract 1 because the caller wants the number of frames beneath 377 // itself. Because the caller called us, subract two for our frame and its 378 // frame, which are included in stack.size(). 379 return stack.frames()->size() - 2; 380 } 381 382 383 // Recursor verifies that the number stack frames beneath itself is one more 384 // than the number of stack frames beneath its parent. When depth frames 385 // have been reached, Recursor stops checking and returns success. If the 386 // frame count check fails at any depth, Recursor will stop and return false. 387 // Because this calls CountCallerFrames, inlining is disabled. 388 #if defined(__GNUC__) 389 static bool Recursor(unsigned int depth, unsigned int parent_callers) 390 __attribute__((noinline)); 391 #elif defined(__SUNPRO_CC) 392 static bool Recursor(unsigned int depth, unsigned int parent_callers); 393 #endif 394 static bool Recursor(unsigned int depth, unsigned int parent_callers) { 395 unsigned int callers = CountCallerFrames(); 396 if (callers != parent_callers + 1) 397 return false; 398 399 if (depth) 400 return Recursor(depth - 1, callers); 401 402 // depth == 0 403 return true; 404 } 405 406 407 // Because this calls CountCallerFrames, inlining is disabled - but because 408 // it's main (and nobody calls it other than the entry point), it wouldn't 409 // be inlined anyway. 410 #if defined(__GNUC__) 411 int main(int argc, char** argv) __attribute__((noinline)); 412 #elif defined(__SUNPRO_CC) 413 int main(int argc, char** argv); 414 #endif 415 int main(int argc, char** argv) { 416 BPLOG_INIT(&argc, &argv); 417 418 return Recursor(RECURSION_DEPTH, CountCallerFrames()) ? 0 : 1; 419 } 420 421 422 #else 423 // Not i386 or ppc or sparc? We can only test stacks we know how to walk. 424 425 426 int main(int argc, char** argv) { 427 BPLOG_INIT(&argc, &argv); 428 429 // "make check" interprets an exit status of 77 to mean that the test is 430 // not supported. 431 BPLOG(ERROR) << "Selftest not supported here"; 432 return 77; 433 } 434 435 436 #endif // (__GNUC__ || __SUNPRO_CC) && (__i386__ || __ppc__ || __sparc__)