m_stacktrace.c revision 121d1d082678d9f50ac50f66c93f23122c31739b
1 2/*--------------------------------------------------------------------*/ 3/*--- Take snapshots of client stacks. m_stacktrace.c ---*/ 4/*--------------------------------------------------------------------*/ 5 6/* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2005 Julian Seward 11 jseward@acm.org 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26 02111-1307, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29*/ 30 31#include "pub_core_basics.h" 32#include "pub_core_threadstate.h" 33#include "pub_core_debuginfo.h" 34#include "pub_core_aspacemgr.h" // For VG_(is_addressable)() 35#include "pub_core_libcbase.h" 36#include "pub_core_libcassert.h" 37#include "pub_core_libcprint.h" 38#include "pub_core_machine.h" 39#include "pub_core_options.h" 40#include "pub_core_profile.h" 41#include "pub_core_stacktrace.h" 42#include "pub_core_trampoline.h" 43 44/*------------------------------------------------------------*/ 45/*--- Exported functions. ---*/ 46/*------------------------------------------------------------*/ 47 48/* Take a snapshot of the client's stack, putting the up to 'n_ips' 49 IPs into 'ips'. In order to be thread-safe, we pass in the 50 thread's IP SP, FP if that's meaningful, and LR if that's 51 meaningful. Returns number of IPs put in 'ips'. 52*/ 53UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips, 54 Addr ip, Addr sp, Addr fp, Addr lr, 55 Addr fp_min, Addr fp_max_orig ) 56{ 57#if defined(VGP_ppc32_linux) 58 Bool lr_is_first_RA = False; /* ppc only */ 59#endif 60 Bool debug = False; 61 Int i; 62 Addr fp_max; 63 UInt n_found = 0; 64 65 VGP_PUSHCC(VgpExeContext); 66 67 vg_assert(sizeof(Addr) == sizeof(UWord)); 68 vg_assert(sizeof(Addr) == sizeof(void*)); 69 70 /* Snaffle IPs from the client's stack into ips[0 .. n_ips-1], 71 putting zeroes in when the trail goes cold, which we guess to be 72 when FP is not a reasonable stack location. */ 73 74 for (i = 0; i < n_ips; i++) 75 ips[i] = 0; 76 77 // JRS 2002-sep-17: hack, to round up fp_max to the end of the 78 // current page, at least. Dunno if it helps. 79 // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again 80 fp_max = VG_PGROUNDUP(fp_max_orig); 81 fp_max -= sizeof(Addr); 82 83 if (debug) 84 VG_(printf)("n_ips=%d fp_min=%p fp_max_orig=%p, fp_max=%p ip=%p fp=%p\n", 85 n_ips, fp_min, fp_max_orig, fp_max, ip, fp); 86 87 /* Assertion broken before main() is reached in pthreaded programs; the 88 * offending stack traces only have one item. --njn, 2002-aug-16 */ 89 /* vg_assert(fp_min <= fp_max);*/ 90 91 if (fp_min + VG_(clo_max_stackframe) <= fp_max) { 92 /* If the stack is ridiculously big, don't poke around ... but 93 don't bomb out either. Needed to make John Regehr's 94 user-space threads package work. JRS 20021001 */ 95 ips[0] = ip; 96 VGP_POPCC(VgpExeContext); 97 return 1; 98 } 99 100 /* Otherwise unwind the stack in a platform-specific way. Trying 101 to merge the x86, amd64 and ppc32 logic into a single piece of 102 code is just too confusing. */ 103 104 /*--------------------- x86 and amd64 ---------------------*/ 105 106# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) 107 108 /* fp is %ebp/%rbp. sp is %esp/%rsp. ip is %eip/%rip. */ 109 110 ips[0] = ip; 111 i = 1; 112 113 while (True) { 114 115 if (i >= n_ips) 116 break; 117 118 /* Try to derive a new (ip,sp,fp) triple from the current 119 set. */ 120 121 /* First off, see if there is any CFI info to hand which can 122 be used. */ 123 if ( VG_(use_CFI_info)( &ip, &sp, &fp, fp_min, fp_max ) ) { 124 ips[i++] = ip; 125 if (debug) 126 VG_(printf)(" ipsC[%d]=%08p\n", i-1, ips[i-1]); 127 ip = ip - 1; 128 continue; 129 } 130 131 /* If VG_(use_CFI_info) fails, it won't modify ip/sp/fp, so 132 we can safely try the old-fashioned method. */ 133 /* This bit is supposed to deal with frames resulting from 134 functions which begin "pushl% ebp ; movl %esp, %ebp" (x86) 135 or "pushq %rbp ; movq %rsp, %rbp" (amd64). Unfortunately, 136 since we can't (easily) look at the insns at the start of 137 the fn, like GDB does, there's no reliable way to tell. 138 Hence the hack of first trying out CFI, and if that fails, 139 then use this as a fallback. */ 140 if (fp_min <= fp && fp <= fp_max) { 141 /* fp looks sane, so use it. */ 142 ip = (((UWord*)fp)[1]); 143 sp = fp + sizeof(Addr) /*saved %ebp/%rbp*/ 144 + sizeof(Addr) /*ra*/; 145 fp = (((UWord*)fp)[0]); 146 ips[i++] = ip; 147 if (debug) 148 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]); 149 ip = ip - 1; 150 continue; 151 } 152 153 /* No luck there. We have to give up. */ 154 break; 155 } 156 157 /*--------------------- ppc32 ---------------------*/ 158 159# elif defined(VGP_ppc32_linux) 160 161 /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and 162 frame pointers. */ 163 164 lr_is_first_RA = False; 165 { 166# define M_VG_ERRTXT 1000 167 UChar buf_lr[M_VG_ERRTXT], buf_ip[M_VG_ERRTXT]; 168 if (VG_(get_fnname_nodemangle) (lr, buf_lr, M_VG_ERRTXT)) 169 if (VG_(get_fnname_nodemangle) (ip, buf_ip, M_VG_ERRTXT)) 170 if (VG_(strncmp)(buf_lr, buf_ip, M_VG_ERRTXT)) 171 lr_is_first_RA = True; 172# undef M_VG_ERRTXT 173 } 174 175 ips[0] = ip; 176 i = 1; 177 fp = (((UWord*)fp)[0]); 178 179 while (True) { 180 181 if (i >= n_ips) 182 break; 183 184 /* Try to derive a new (ip,fp) pair from the current set. */ 185 186 if (fp_min <= fp && fp <= fp_max) { 187 /* fp looks sane, so use it. */ 188 189 if (i == 1 && lr_is_first_RA) 190 ip = lr; 191 else 192 ip = (((UWord*)fp)[1]); 193 194 fp = (((UWord*)fp)[0]); 195 ips[i++] = ip; 196 if (debug) 197 VG_(printf)(" ipsF[%d]=%08p\n", i-1, ips[i-1]); 198 continue; 199 } 200 201 /* No luck there. We have to give up. */ 202 break; 203 } 204 205# else 206# error "Unknown platform" 207# endif 208 209 n_found = i; 210 VGP_POPCC(VgpExeContext); 211 return n_found; 212} 213 214UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips ) 215{ 216 /* thread in thread table */ 217 Addr ip = VG_(get_IP)(tid); 218 Addr fp = VG_(get_FP)(tid); 219 Addr sp = VG_(get_SP)(tid); 220 Addr lr = VG_(get_LR)(tid); 221 Addr stack_highest_word = VG_(threads)[tid].client_stack_highest_word; 222 223# if defined(VGP_x86_linux) 224 /* Nasty little hack to deal with sysinfo syscalls - if libc is 225 using the sysinfo page for syscalls (the TLS version does), then 226 ip will always appear to be in that page when doing a syscall, 227 not the actual libc function doing the syscall. This check sees 228 if IP is within the syscall code, and pops the return address 229 off the stack so that ip is placed within the library function 230 calling the syscall. This makes stack backtraces much more 231 useful. */ 232 if (ip >= (Addr)&VG_(trampoline_stuff_start) 233 && ip < (Addr)&VG_(trampoline_stuff_end) 234 && VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) { 235 ip = *(Addr *)sp; 236 sp += sizeof(Addr); 237 } 238# endif 239 240 if (0) 241 VG_(printf)("tid %d: stack_highest=%p ip=%p sp=%p fp=%p\n", 242 tid, stack_highest_word, ip, sp, fp); 243 244 return VG_(get_StackTrace2)(ips, n_ips, ip, sp, fp, lr, sp, stack_highest_word); 245} 246 247static void printIpDesc(UInt n, Addr ip) 248{ 249 #define BUF_LEN 4096 250 251 static UChar buf[BUF_LEN]; 252 253 VG_(describe_IP)(ip, buf, BUF_LEN); 254 255 if (VG_(clo_xml)) { 256 VG_(message)(Vg_UserMsg, " %s", buf); 257 } else { 258 VG_(message)(Vg_UserMsg, " %s %s", ( n == 0 ? "at" : "by" ), buf); 259 } 260} 261 262/* Print a StackTrace. */ 263void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ) 264{ 265 vg_assert( n_ips > 0 ); 266 267 if (VG_(clo_xml)) 268 VG_(message)(Vg_UserMsg, " <stack>"); 269 270 VG_(apply_StackTrace)( printIpDesc, ips, n_ips ); 271 272 if (VG_(clo_xml)) 273 VG_(message)(Vg_UserMsg, " </stack>"); 274} 275 276/* Get and immediately print a StackTrace. */ 277void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt n_ips ) 278{ 279 Addr ips[n_ips]; 280 VG_(get_StackTrace)(tid, ips, n_ips); 281 VG_(pp_StackTrace) ( ips, n_ips); 282} 283 284 285void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip), 286 StackTrace ips, UInt n_ips ) 287{ 288 #define MYBUF_LEN 10 // only needs to be long enough for "main" 289 290 Bool main_done = False; 291 Char mybuf[MYBUF_LEN]; // ok to stack allocate mybuf[] -- it's tiny 292 Int i = 0; 293 294 vg_assert(n_ips > 0); 295 do { 296 Addr ip = ips[i]; 297 if (i > 0) 298 ip -= VG_MIN_INSTR_SZB; // point to calling line 299 300 // Stop after "main"; if main() is recursive, stop after last main(). 301 if ( ! VG_(clo_show_below_main)) { 302 VG_(get_fnname_nodemangle)( ip, mybuf, MYBUF_LEN ); 303 if ( VG_STREQ("main", mybuf) ) 304 main_done = True; 305 else if (main_done) 306 break; 307 } 308 309 // Act on the ip 310 action(i, ip); 311 312 i++; 313 } while (i < n_ips && ips[i] != 0); 314 315 #undef MYBUF_LEN 316} 317 318 319/*--------------------------------------------------------------------*/ 320/*--- end ---*/ 321/*--------------------------------------------------------------------*/ 322