sewardj | 267100d | 2005-04-24 12:33:12 +0000 | [diff] [blame] | 1 | |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 2 | /*--------------------------------------------------------------------*/ |
sewardj | 267100d | 2005-04-24 12:33:12 +0000 | [diff] [blame] | 3 | /*--- Take snapshots of client stacks. m_stacktrace.c ---*/ |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 4 | /*--------------------------------------------------------------------*/ |
| 5 | |
| 6 | /* |
| 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
| 9 | |
sewardj | b3a1e4b | 2015-08-21 11:32:26 +0000 | [diff] [blame] | 10 | Copyright (C) 2000-2015 Julian Seward |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 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 | |
njn | c7561b9 | 2005-06-19 01:24:32 +0000 | [diff] [blame] | 31 | #include "pub_core_basics.h" |
sewardj | 4cfea4f | 2006-10-14 19:26:10 +0000 | [diff] [blame] | 32 | #include "pub_core_vki.h" |
njn | c7561b9 | 2005-06-19 01:24:32 +0000 | [diff] [blame] | 33 | #include "pub_core_threadstate.h" |
njn | 6882443 | 2009-02-10 06:48:00 +0000 | [diff] [blame] | 34 | #include "pub_core_debuginfo.h" // XXX: circular dependency |
njn | 24a6efb | 2005-06-20 03:36:51 +0000 | [diff] [blame] | 35 | #include "pub_core_aspacemgr.h" // For VG_(is_addressable)() |
njn | 97405b2 | 2005-06-02 03:39:33 +0000 | [diff] [blame] | 36 | #include "pub_core_libcbase.h" |
njn | 132bfcc | 2005-06-04 19:16:06 +0000 | [diff] [blame] | 37 | #include "pub_core_libcassert.h" |
njn | 36a20fa | 2005-06-03 03:08:39 +0000 | [diff] [blame] | 38 | #include "pub_core_libcprint.h" |
njn | f536bbb | 2005-06-13 04:21:38 +0000 | [diff] [blame] | 39 | #include "pub_core_machine.h" |
njn | 2024234 | 2005-05-16 23:31:24 +0000 | [diff] [blame] | 40 | #include "pub_core_options.h" |
sewardj | 9084de7 | 2008-02-11 11:23:12 +0000 | [diff] [blame] | 41 | #include "pub_core_stacks.h" // VG_(stack_limits) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 42 | #include "pub_core_stacktrace.h" |
rhyskidd | 8695a65 | 2015-06-06 03:57:34 +0000 | [diff] [blame] | 43 | #include "pub_core_syswrap.h" // VG_(is_in_syscall) |
sewardj | 14c7cc5 | 2007-02-25 15:08:24 +0000 | [diff] [blame] | 44 | #include "pub_core_xarray.h" |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 45 | #include "pub_core_clientstate.h" // VG_(client__dl_sysinfo_int80) |
njn | a7598f6 | 2005-06-18 03:27:58 +0000 | [diff] [blame] | 46 | #include "pub_core_trampoline.h" |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 47 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 48 | |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 49 | /*------------------------------------------------------------*/ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 50 | /*--- ---*/ |
| 51 | /*--- BEGIN platform-dependent unwinder worker functions ---*/ |
| 52 | /*--- ---*/ |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 53 | /*------------------------------------------------------------*/ |
| 54 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 55 | /* Take a snapshot of the client's stack, putting up to 'max_n_ips' |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 56 | IPs into 'ips'. In order to be thread-safe, we pass in the |
| 57 | thread's IP SP, FP if that's meaningful, and LR if that's |
| 58 | meaningful. Returns number of IPs put in 'ips'. |
sewardj | dfbaa22 | 2006-01-18 04:25:20 +0000 | [diff] [blame] | 59 | |
| 60 | If you know what the thread ID for this stack is, send that as the |
| 61 | first parameter, else send zero. This helps generate better stack |
| 62 | traces on ppc64-linux and has no effect on other platforms. |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 63 | */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 64 | |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 65 | /* Do frame merging in the _i frames in _ips array of recursive cycles |
| 66 | of up to _nframes. The merge is done during stack unwinding |
| 67 | (i.e. in platform specific unwinders) to collect as many |
| 68 | "interesting" stack traces as possible. */ |
| 69 | #define RECURSIVE_MERGE(_nframes,_ips,_i){ \ |
| 70 | Int dist; \ |
| 71 | for (dist = 1; dist <= _nframes && dist < (Int)_i; dist++) { \ |
| 72 | if (_ips[_i-1] == _ips[_i-1-dist]) { \ |
| 73 | _i = _i - dist; \ |
| 74 | break; \ |
| 75 | } \ |
| 76 | } \ |
| 77 | } |
| 78 | |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 79 | /* Note about calculation of fp_min : fp_min is the lowest address |
| 80 | which can be accessed during unwinding. This is SP - VG_STACK_REDZONE_SZB. |
| 81 | On most platforms, this will be equal to SP (as VG_STACK_REDZONE_SZB |
| 82 | is 0). However, on some platforms (e.g. amd64), there is an accessible |
| 83 | redzone below the SP. Some CFI unwind info are generated, taking this |
| 84 | into account. As an example, the following is a CFI unwind info on |
| 85 | amd64 found for a 'retq' instruction: |
| 86 | [0x400f7e .. 0x400f7e]: let cfa=oldSP+8 in RA=*(cfa+-8) SP=cfa+0 BP=*(cfa+-16) |
| 87 | 0x400f7e: retq |
| 88 | As you can see, the previous BP is found 16 bytes below the cfa, which |
| 89 | is the oldSP+8. So, effectively, the BP is found 8 bytes below the SP. |
| 90 | The fp_min must take this into account, otherwise, VG_(use_CF_info) will |
| 91 | not unwind the BP. */ |
| 92 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 93 | /* ------------------------ x86 ------------------------- */ |
| 94 | |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 95 | #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ |
| 96 | || defined(VGP_x86_solaris) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 97 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 98 | #define N_FP_CF_VERIF 1021 |
| 99 | // prime number so that size of fp_CF_verif is just below 4K or 8K |
| 100 | // Note that this prime nr differs from the one chosen in |
| 101 | // m_debuginfo/debuginfo.c for the cfsi cache : in case we have |
| 102 | // a collision here between two IPs, we expect to not (often) have the |
| 103 | // same collision in the cfsi cache (and vice-versa). |
| 104 | |
| 105 | // unwinding with fp chain is ok: |
| 106 | #define FPUNWIND 0 |
| 107 | // there is no CFI info for this IP: |
| 108 | #define NOINFO 1 |
| 109 | // Unwind with FP is not ok, must use CF unwind: |
| 110 | #define CFUNWIND 2 |
| 111 | |
| 112 | static Addr fp_CF_verif_cache [N_FP_CF_VERIF]; |
| 113 | |
| 114 | /* An unwind done by following the fp chain technique can be incorrect |
| 115 | as not all frames are respecting the standard bp/sp ABI. |
| 116 | The CF information is now generated by default by gcc |
| 117 | (as part of the dwarf info). However, unwinding using CF information |
| 118 | is significantly slower : a slowdown of 20% has been observed |
| 119 | on an helgrind test case. |
| 120 | So, by default, the unwinding will be done using the fp chain. |
| 121 | But before accepting to unwind an IP with fp_chain, the result |
| 122 | of the unwind will be checked with the CF information. |
| 123 | This check can give 3 results: |
| 124 | FPUNWIND (0): there is CF info, and it gives the same result as fp unwind. |
| 125 | => it is assumed that future unwind for this IP can be done |
| 126 | with the fast fp chain, without further CF checking |
| 127 | NOINFO (1): there is no CF info (so, fp unwind is the only do-able thing) |
| 128 | CFUNWIND (2): there is CF info, but unwind result differs. |
| 129 | => it is assumed that future unwind for this IP must be done |
| 130 | with the CF info. |
| 131 | Of course, if each fp unwind implies a check done with a CF unwind, |
| 132 | it would just be slower => we cache the check result in an |
| 133 | array of checked Addr. |
| 134 | The check for an IP will be stored at |
| 135 | fp_CF_verif_cache[IP % N_FP_CF_VERIF] as one of: |
| 136 | IP ^ FPUNWIND |
| 137 | IP ^ NOINFO |
| 138 | IP ^ CFUNWIND |
| 139 | |
| 140 | Note: we can re-use the last (ROUNDDOWN (log (N_FP_CF_VERIF))) bits |
| 141 | to store the check result, as they are guaranteed to be non significant |
| 142 | in the comparison between 2 IPs stored in fp_CF_verif_cache). |
| 143 | In other words, if two IPs are only differing on the last 2 bits, |
| 144 | then they will not land in the same cache bucket. |
| 145 | */ |
| 146 | |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 147 | /* cached result of VG_(FPO_info_present)(). Refreshed each time |
| 148 | the fp_CF_verif_generation is different of the current debuginfo |
| 149 | generation. */ |
| 150 | static Bool FPO_info_present = False; |
| 151 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 152 | static UInt fp_CF_verif_generation = 0; |
| 153 | // Our cache has to be maintained in sync with the CFI cache. |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 154 | // Each time the debuginfo is changed, its generation will be incremented. |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 155 | // We will clear our cache when our saved generation differs from |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 156 | // the debuginfo generation. |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 157 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 158 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 159 | /*OUT*/Addr* ips, UInt max_n_ips, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 160 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 161 | const UnwindStartRegs* startRegs, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 162 | Addr fp_max_orig ) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 163 | { |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 164 | const Bool do_stats = False; // compute and output some stats regularly. |
| 165 | static struct { |
| 166 | UInt nr; // nr of stacktraces computed |
| 167 | UInt nf; // nr of frames computed |
| 168 | UInt Ca; // unwind for which cache indicates CFUnwind must be used. |
| 169 | UInt FF; // unwind for which cache indicates FPUnwind can be used. |
| 170 | UInt Cf; // unwind at end of stack+store CFUNWIND (xip not end of stack). |
| 171 | UInt Fw; // unwind at end of stack+store FPUNWIND |
| 172 | UInt FO; // unwind + store FPUNWIND |
| 173 | UInt CF; // unwind + store CFUNWIND. Details below. |
| 174 | UInt xi; UInt xs; UInt xb; // register(s) which caused a 'store CFUNWIND'. |
| 175 | UInt Ck; // unwind fp invalid+store FPUNWIND |
| 176 | UInt MS; // microsoft unwind |
| 177 | } stats; |
| 178 | |
philippe | c996326 | 2013-03-01 20:37:41 +0000 | [diff] [blame] | 179 | const Bool debug = False; |
| 180 | // = VG_(debugLog_getLevel) () > 3; |
| 181 | // = True; |
| 182 | // = stats.nr >= 123456; |
| 183 | const HChar* unwind_case; // used when debug is True. |
| 184 | // Debugging this function is not straightforward. |
| 185 | // Here is the easiest way I have found: |
| 186 | // 1. Change the above to True. |
| 187 | // 2. Start your program under Valgrind with --tool=none --vgdb-error=0 |
| 188 | // 3. Use GDB/vgdb to put a breakpoint where you want to debug the stacktrace |
| 189 | // 4. Continue till breakpoint is encountered |
| 190 | // 5. From GDB, use 'monitor v.info scheduler' and examine the unwind traces. |
| 191 | // You might have to do twice 'monitor v.info scheduler' to see |
| 192 | // the effect of caching the results of the verification. |
| 193 | // You can also modify the debug dynamically using by using |
| 194 | // 'monitor v.set debuglog 4. |
| 195 | |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 196 | Int i; |
| 197 | Addr fp_max; |
| 198 | UInt n_found = 0; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 199 | const Int cmrf = VG_(clo_merge_recursive_frames); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 200 | |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 201 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 202 | vg_assert(sizeof(Addr) == sizeof(void*)); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 203 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 204 | D3UnwindRegs fpverif_uregs; // result of CF unwind for a check reason. |
philippe | c4feec1 | 2013-01-30 23:53:59 +0000 | [diff] [blame] | 205 | Addr xip_verified = 0; // xip for which we have calculated fpverif_uregs |
| 206 | // 0 assigned to silence false positive -Wuninitialized warning |
sewardj | 522d4d3 | 2013-01-31 10:39:07 +0000 | [diff] [blame] | 207 | // This is a false positive as xip_verified is assigned when |
| 208 | // xip_verif > CFUNWIND and only used if xip_verif > CFUNWIND. |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 209 | |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 210 | D3UnwindRegs uregs; |
| 211 | uregs.xip = (Addr)startRegs->r_pc; |
| 212 | uregs.xsp = (Addr)startRegs->r_sp; |
| 213 | uregs.xbp = startRegs->misc.X86.r_ebp; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 214 | Addr fp_min = uregs.xsp - VG_STACK_REDZONE_SZB; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 215 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 216 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
njn | c0ec8e9 | 2005-12-25 06:34:04 +0000 | [diff] [blame] | 217 | stopping when the trail goes cold, which we guess to be |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 218 | when FP is not a reasonable stack location. */ |
| 219 | |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 220 | // JRS 2002-sep-17: hack, to round up fp_max to the end of the |
| 221 | // current page, at least. Dunno if it helps. |
| 222 | // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again |
sewardj | 45f4e7c | 2005-09-27 19:20:21 +0000 | [diff] [blame] | 223 | fp_max = VG_PGROUNDUP(fp_max_orig); |
sewardj | d0c0ea6 | 2008-03-03 22:20:51 +0000 | [diff] [blame] | 224 | if (fp_max >= sizeof(Addr)) |
| 225 | fp_max -= sizeof(Addr); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 226 | |
| 227 | if (debug) |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 228 | VG_(printf)("max_n_ips=%u fp_min=0x%08lx fp_max_orig=0x08%lx, " |
philippe | 4934554 | 2014-06-14 22:12:37 +0000 | [diff] [blame] | 229 | "fp_max=0x%08lx ip=0x%08lx fp=0x%08lx\n", |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 230 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 231 | uregs.xip, uregs.xbp); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 232 | |
| 233 | /* Assertion broken before main() is reached in pthreaded programs; the |
| 234 | * offending stack traces only have one item. --njn, 2002-aug-16 */ |
| 235 | /* vg_assert(fp_min <= fp_max);*/ |
njn | f76d27a | 2009-05-28 01:53:07 +0000 | [diff] [blame] | 236 | // On Darwin, this kicks in for pthread-related stack traces, so they're |
| 237 | // only 1 entry long which is wrong. |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 238 | # if defined(VGO_linux) |
sewardj | 5bdfbd2 | 2007-12-15 22:13:05 +0000 | [diff] [blame] | 239 | if (fp_min + 512 >= fp_max) { |
| 240 | /* If the stack limits look bogus, don't poke around ... but |
| 241 | don't bomb out either. */ |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 242 | # elif defined(VGO_solaris) |
| 243 | if (fp_max == 0) { |
| 244 | /* VG_(get_StackTrace)() can be called by tools very early when |
| 245 | various tracing options are enabled. Don't proceed further |
| 246 | if the stack limits look bogus. |
| 247 | */ |
| 248 | # endif |
| 249 | # if defined(VGO_linux) || defined(VGO_solaris) |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 250 | if (sps) sps[0] = uregs.xsp; |
| 251 | if (fps) fps[0] = uregs.xbp; |
| 252 | ips[0] = uregs.xip; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 253 | return 1; |
| 254 | } |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 255 | # endif |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 256 | |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 257 | if (UNLIKELY (fp_CF_verif_generation != VG_(debuginfo_generation)())) { |
| 258 | fp_CF_verif_generation = VG_(debuginfo_generation)(); |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 259 | VG_(memset)(&fp_CF_verif_cache, 0, sizeof(fp_CF_verif_cache)); |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 260 | FPO_info_present = VG_(FPO_info_present)(); |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 261 | } |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 262 | |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 263 | |
| 264 | /* Loop unwinding the stack. Note that the IP value we get on |
| 265 | * each pass (whether from CFI info or a stack frame) is a |
| 266 | * return address so is actually after the calling instruction |
| 267 | * in the calling function. |
| 268 | * |
| 269 | * Because of this we subtract one from the IP after each pass |
| 270 | * of the loop so that we find the right CFI block on the next |
| 271 | * pass - otherwise we can find the wrong CFI info if it happens |
| 272 | * to change after the calling instruction and that will mean |
| 273 | * that we will fail to unwind the next step. |
| 274 | * |
| 275 | * This most frequently happens at the end of a function when |
| 276 | * a tail call occurs and we wind up using the CFI info for the |
| 277 | * next function which is completely wrong. |
| 278 | */ |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 279 | if (sps) sps[0] = uregs.xsp; |
| 280 | if (fps) fps[0] = uregs.xbp; |
| 281 | ips[0] = uregs.xip; |
| 282 | i = 1; |
| 283 | if (do_stats) stats.nr++; |
| 284 | |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 285 | while (True) { |
| 286 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 287 | if (i >= max_n_ips) |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 288 | break; |
| 289 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 290 | UWord hash = uregs.xip % N_FP_CF_VERIF; |
| 291 | Addr xip_verif = uregs.xip ^ fp_CF_verif_cache [hash]; |
| 292 | if (debug) |
philippe | dcef54c | 2014-06-14 10:04:51 +0000 | [diff] [blame] | 293 | VG_(printf)(" uregs.xip 0x%08lx xip_verif[0x%08lx]" |
| 294 | " xbp 0x%08lx xsp 0x%08lx\n", |
| 295 | uregs.xip, xip_verif, |
| 296 | uregs.xbp, uregs.xsp); |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 297 | // If xip is in cache, then xip_verif will be <= CFUNWIND. |
| 298 | // Otherwise, if not in cache, xip_verif will be > CFUNWIND. |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 299 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 300 | /* Try to derive a new (ip,sp,fp) triple from the current set. */ |
| 301 | |
| 302 | /* Do we have to do CFI unwinding ? |
| 303 | We do CFI unwinding if one of the following condition holds: |
| 304 | a. fp_CF_verif_cache contains xip but indicates CFUNWIND must |
| 305 | be done (i.e. fp unwind check failed when we did the first |
| 306 | unwind for this IP). |
| 307 | b. fp_CF_verif_cache does not contain xip. |
| 308 | We will try CFI unwinding in fpverif_uregs and compare with |
| 309 | FP unwind result to insert xip in the cache with the correct |
| 310 | indicator. */ |
| 311 | if (UNLIKELY(xip_verif >= CFUNWIND)) { |
| 312 | if (xip_verif == CFUNWIND) { |
| 313 | /* case a : do "real" cfi unwind */ |
| 314 | if ( VG_(use_CF_info)( &uregs, fp_min, fp_max ) ) { |
| 315 | if (debug) unwind_case = "Ca"; |
| 316 | if (do_stats) stats.Ca++; |
| 317 | goto unwind_done; |
| 318 | } |
| 319 | /* ??? cache indicates we have to do CFI unwind (so, we |
| 320 | previously found CFI info, and failed the fp unwind |
| 321 | check). Now, we just failed with CFI. So, once we |
| 322 | succeed, once we fail. No idea what is going on => |
| 323 | cleanup the cache entry and fallover to fp unwind (this |
| 324 | time). */ |
| 325 | fp_CF_verif_cache [hash] = 0; |
| 326 | if (debug) VG_(printf)(" cache reset as CFI ok then nok\n"); |
| 327 | //??? stats |
| 328 | xip_verif = NOINFO; |
| 329 | } else { |
| 330 | /* case b : do "verif" cfi unwind in fpverif_uregs */ |
| 331 | fpverif_uregs = uregs; |
| 332 | xip_verified = uregs.xip; |
| 333 | if ( !VG_(use_CF_info)( &fpverif_uregs, fp_min, fp_max ) ) { |
| 334 | fp_CF_verif_cache [hash] = uregs.xip ^ NOINFO; |
| 335 | if (debug) VG_(printf)(" cache NOINFO fpverif_uregs\n"); |
| 336 | xip_verif = NOINFO; |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | /* On x86, try the old-fashioned method of following the |
| 342 | %ebp-chain. This can be done if the fp_CF_verif_cache for xip |
| 343 | indicate fp unwind is ok. This must be done if the cache indicates |
| 344 | there is no info. This is also done to confirm what to put in the cache |
| 345 | if xip was not in the cache. */ |
| 346 | /* This deals with frames resulting from functions which begin "pushl% |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 347 | ebp ; movl %esp, %ebp" which is the ABI-mandated preamble. */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 348 | if (fp_min <= uregs.xbp && |
sewardj | 418f6b3 | 2015-07-07 14:06:00 +0000 | [diff] [blame] | 349 | uregs.xbp <= fp_max - 1 * sizeof(UWord)/*see comment below*/ && |
| 350 | VG_IS_4_ALIGNED(uregs.xbp)) |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 351 | { |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 352 | /* fp looks sane, so use it. */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 353 | uregs.xip = (((UWord*)uregs.xbp)[1]); |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 354 | // We stop if we hit a zero (the traditional end-of-stack |
| 355 | // marker) or a one -- these correspond to recorded IPs of 0 or -1. |
| 356 | // The latter because r8818 (in this file) changes the meaning of |
| 357 | // entries [1] and above in a stack trace, by subtracting 1 from |
| 358 | // them. Hence stacks that used to end with a zero value now end in |
| 359 | // -1 and so we must detect that too. |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 360 | if (0 == uregs.xip || 1 == uregs.xip) { |
| 361 | if (xip_verif > CFUNWIND) { |
| 362 | // Check if we obtain the same result with fp unwind. |
| 363 | // If same result, then mark xip as fp unwindable |
| 364 | if (uregs.xip == fpverif_uregs.xip) { |
| 365 | fp_CF_verif_cache [hash] = xip_verified ^ FPUNWIND; |
| 366 | if (debug) VG_(printf)(" cache FPUNWIND 0\n"); |
| 367 | unwind_case = "Fw"; |
| 368 | if (do_stats) stats.Fw++; |
| 369 | break; |
| 370 | } else { |
| 371 | fp_CF_verif_cache [hash] = xip_verified ^ CFUNWIND; |
| 372 | uregs = fpverif_uregs; |
| 373 | if (debug) VG_(printf)(" cache CFUNWIND 0\n"); |
| 374 | unwind_case = "Cf"; |
| 375 | if (do_stats) stats.Cf++; |
| 376 | goto unwind_done; |
| 377 | } |
| 378 | } else { |
| 379 | // end of stack => out of the loop. |
| 380 | break; |
| 381 | } |
| 382 | } |
| 383 | |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 384 | uregs.xsp = uregs.xbp + sizeof(Addr) /*saved %ebp*/ |
| 385 | + sizeof(Addr) /*ra*/; |
| 386 | uregs.xbp = (((UWord*)uregs.xbp)[0]); |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 387 | if (xip_verif > CFUNWIND) { |
| 388 | if (uregs.xip == fpverif_uregs.xip |
| 389 | && uregs.xsp == fpverif_uregs.xsp |
| 390 | && uregs.xbp == fpverif_uregs.xbp) { |
| 391 | fp_CF_verif_cache [hash] = xip_verified ^ FPUNWIND; |
| 392 | if (debug) VG_(printf)(" cache FPUNWIND >2\n"); |
| 393 | if (debug) unwind_case = "FO"; |
| 394 | if (do_stats) stats.FO++; |
| 395 | } else { |
| 396 | fp_CF_verif_cache [hash] = xip_verified ^ CFUNWIND; |
| 397 | if (debug) VG_(printf)(" cache CFUNWIND >2\n"); |
| 398 | if (do_stats && uregs.xip != fpverif_uregs.xip) stats.xi++; |
| 399 | if (do_stats && uregs.xsp != fpverif_uregs.xsp) stats.xs++; |
| 400 | if (do_stats && uregs.xbp != fpverif_uregs.xbp) stats.xb++; |
| 401 | uregs = fpverif_uregs; |
| 402 | if (debug) unwind_case = "CF"; |
| 403 | if (do_stats) stats.CF++; |
| 404 | } |
| 405 | } else { |
| 406 | if (debug) unwind_case = "FF"; |
| 407 | if (do_stats) stats.FF++; |
| 408 | } |
| 409 | goto unwind_done; |
| 410 | } else { |
| 411 | // fp unwind has failed. |
| 412 | // If we were checking the validity of the cfi unwinding, |
| 413 | // we mark in the cache that the fp unwind cannot be done, and that |
| 414 | // cfi unwind is desired. |
| 415 | if (xip_verif > CFUNWIND) { |
| 416 | // We know that fpverif_uregs contains valid information, |
| 417 | // as a failed cf unwind would have put NOINFO in xip_verif. |
| 418 | fp_CF_verif_cache [hash] = xip_verified ^ CFUNWIND; |
| 419 | if (debug) VG_(printf)(" cache CFUNWIND as fp failed\n"); |
| 420 | uregs = fpverif_uregs; |
| 421 | if (debug) unwind_case = "Ck"; |
| 422 | if (do_stats) stats.Ck++; |
| 423 | goto unwind_done; |
| 424 | } |
| 425 | // xip_verif is FPUNWIND or NOINFO. |
| 426 | // We failed the cfi unwind and/or the fp unwind. |
| 427 | // => fallback to FPO info. |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 428 | } |
| 429 | |
sewardj | c8259b8 | 2009-04-22 22:42:10 +0000 | [diff] [blame] | 430 | /* And, similarly, try for MSVC FPO unwind info. */ |
philippe | f7bbd79 | 2015-05-26 21:26:39 +0000 | [diff] [blame] | 431 | if (FPO_info_present |
| 432 | && VG_(use_FPO_info)( &uregs.xip, &uregs.xsp, &uregs.xbp, |
| 433 | fp_min, fp_max ) ) { |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 434 | if (debug) unwind_case = "MS"; |
| 435 | if (do_stats) stats.MS++; |
| 436 | goto unwind_done; |
sewardj | c8259b8 | 2009-04-22 22:42:10 +0000 | [diff] [blame] | 437 | } |
| 438 | |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 439 | /* No luck. We have to give up. */ |
| 440 | break; |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 441 | |
| 442 | unwind_done: |
| 443 | /* Add a frame in ips/sps/fps */ |
| 444 | /* fp is %ebp. sp is %esp. ip is %eip. */ |
| 445 | if (0 == uregs.xip || 1 == uregs.xip) break; |
| 446 | if (sps) sps[i] = uregs.xsp; |
| 447 | if (fps) fps[i] = uregs.xbp; |
| 448 | ips[i++] = uregs.xip - 1; |
| 449 | /* -1: refer to calling insn, not the RA */ |
| 450 | if (debug) |
| 451 | VG_(printf)(" ips%s[%d]=0x%08lx\n", unwind_case, i-1, ips[i-1]); |
| 452 | uregs.xip = uregs.xip - 1; |
| 453 | /* as per comment at the head of this loop */ |
| 454 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 455 | } |
| 456 | |
philippe | 20ede3a | 2013-01-30 23:18:11 +0000 | [diff] [blame] | 457 | if (do_stats) stats.nf += i; |
| 458 | if (do_stats && stats.nr % 10000 == 0) { |
| 459 | VG_(printf)("nr %u nf %u " |
| 460 | "Ca %u FF %u " |
| 461 | "Cf %u " |
| 462 | "Fw %u FO %u " |
| 463 | "CF %u (xi %u xs %u xb %u) " |
| 464 | "Ck %u MS %u\n", |
| 465 | stats.nr, stats.nf, |
| 466 | stats.Ca, stats.FF, |
| 467 | stats.Cf, |
| 468 | stats.Fw, stats.FO, |
| 469 | stats.CF, stats.xi, stats.xs, stats.xb, |
| 470 | stats.Ck, stats.MS); |
| 471 | } |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 472 | n_found = i; |
| 473 | return n_found; |
| 474 | } |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 475 | |
sewardj | 522d4d3 | 2013-01-31 10:39:07 +0000 | [diff] [blame] | 476 | #undef N_FP_CF_VERIF |
| 477 | #undef FPUNWIND |
| 478 | #undef NOINFO |
| 479 | #undef CFUNWIND |
| 480 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 481 | #endif |
| 482 | |
| 483 | /* ----------------------- amd64 ------------------------ */ |
| 484 | |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 485 | #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ |
| 486 | || defined(VGP_amd64_solaris) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 487 | |
| 488 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 489 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 490 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 491 | const UnwindStartRegs* startRegs, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 492 | Addr fp_max_orig ) |
| 493 | { |
philippe | 2d207aa | 2015-05-31 15:18:36 +0000 | [diff] [blame] | 494 | const Bool debug = False; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 495 | Int i; |
| 496 | Addr fp_max; |
| 497 | UInt n_found = 0; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 498 | const Int cmrf = VG_(clo_merge_recursive_frames); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 499 | |
| 500 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 501 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 502 | |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 503 | D3UnwindRegs uregs; |
| 504 | uregs.xip = startRegs->r_pc; |
| 505 | uregs.xsp = startRegs->r_sp; |
| 506 | uregs.xbp = startRegs->misc.AMD64.r_rbp; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 507 | Addr fp_min = uregs.xsp - VG_STACK_REDZONE_SZB; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 508 | |
| 509 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
| 510 | stopping when the trail goes cold, which we guess to be |
| 511 | when FP is not a reasonable stack location. */ |
| 512 | |
| 513 | // JRS 2002-sep-17: hack, to round up fp_max to the end of the |
| 514 | // current page, at least. Dunno if it helps. |
| 515 | // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again |
| 516 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 517 | if (fp_max >= sizeof(Addr)) |
| 518 | fp_max -= sizeof(Addr); |
| 519 | |
| 520 | if (debug) |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 521 | VG_(printf)("max_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 522 | "fp_max=0x%lx ip=0x%lx fp=0x%lx\n", |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 523 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 524 | uregs.xip, uregs.xbp); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 525 | |
| 526 | /* Assertion broken before main() is reached in pthreaded programs; the |
| 527 | * offending stack traces only have one item. --njn, 2002-aug-16 */ |
| 528 | /* vg_assert(fp_min <= fp_max);*/ |
| 529 | // On Darwin, this kicks in for pthread-related stack traces, so they're |
| 530 | // only 1 entry long which is wrong. |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 531 | # if defined(VGO_linux) |
sewardj | f252299 | 2010-10-06 22:45:18 +0000 | [diff] [blame] | 532 | if (fp_min + 256 >= fp_max) { |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 533 | /* If the stack limits look bogus, don't poke around ... but |
| 534 | don't bomb out either. */ |
sewardj | 8eb8bab | 2015-07-21 14:44:28 +0000 | [diff] [blame] | 535 | # elif defined(VGO_solaris) |
| 536 | if (fp_max == 0) { |
| 537 | /* VG_(get_StackTrace)() can be called by tools very early when |
| 538 | various tracing options are enabled. Don't proceed further |
| 539 | if the stack limits look bogus. |
| 540 | */ |
| 541 | # endif |
| 542 | # if defined(VGO_linux) || defined(VGO_solaris) |
| 543 | |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 544 | if (sps) sps[0] = uregs.xsp; |
| 545 | if (fps) fps[0] = uregs.xbp; |
| 546 | ips[0] = uregs.xip; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 547 | return 1; |
| 548 | } |
| 549 | # endif |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 550 | |
| 551 | /* fp is %rbp. sp is %rsp. ip is %rip. */ |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 552 | |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 553 | ips[0] = uregs.xip; |
| 554 | if (sps) sps[0] = uregs.xsp; |
| 555 | if (fps) fps[0] = uregs.xbp; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 556 | i = 1; |
philippe | 2d207aa | 2015-05-31 15:18:36 +0000 | [diff] [blame] | 557 | if (debug) |
| 558 | VG_(printf)(" ipsS[%d]=%#08lx rbp %#08lx rsp %#08lx\n", |
| 559 | i-1, ips[i-1], uregs.xbp, uregs.xsp); |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 560 | |
rhyskidd | bc3770e | 2015-03-07 05:22:12 +0000 | [diff] [blame] | 561 | # if defined(VGO_darwin) |
| 562 | if (VG_(is_valid_tid)(tid_if_known) && |
| 563 | VG_(is_in_syscall)(tid_if_known) && |
| 564 | i < max_n_ips) { |
| 565 | /* On Darwin, all the system call stubs have no function |
| 566 | * prolog. So instead of top of the stack being a new |
| 567 | * frame comprising a saved BP and a return address, we |
| 568 | * just have the return address in the caller's frame. |
| 569 | * Adjust for this by recording the return address. |
| 570 | */ |
| 571 | ips[i] = *(Addr *)uregs.xsp - 1; |
| 572 | if (sps) sps[i] = uregs.xsp; |
| 573 | if (fps) fps[i] = uregs.xbp; |
| 574 | i++; |
| 575 | } |
| 576 | # endif |
| 577 | |
tom | ac35f10 | 2005-11-05 00:17:21 +0000 | [diff] [blame] | 578 | /* Loop unwinding the stack. Note that the IP value we get on |
| 579 | * each pass (whether from CFI info or a stack frame) is a |
| 580 | * return address so is actually after the calling instruction |
| 581 | * in the calling function. |
| 582 | * |
| 583 | * Because of this we subtract one from the IP after each pass |
| 584 | * of the loop so that we find the right CFI block on the next |
| 585 | * pass - otherwise we can find the wrong CFI info if it happens |
| 586 | * to change after the calling instruction and that will mean |
| 587 | * that we will fail to unwind the next step. |
| 588 | * |
| 589 | * This most frequently happens at the end of a function when |
| 590 | * a tail call occurs and we wind up using the CFI info for the |
| 591 | * next function which is completely wrong. |
| 592 | */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 593 | while (True) { |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 594 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 595 | if (i >= max_n_ips) |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 596 | break; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 597 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 598 | /* Try to derive a new (ip,sp,fp) triple from the current set. */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 599 | |
| 600 | /* First off, see if there is any CFI info to hand which can |
| 601 | be used. */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 602 | if ( VG_(use_CF_info)( &uregs, fp_min, fp_max ) ) { |
| 603 | if (0 == uregs.xip || 1 == uregs.xip) break; |
| 604 | if (sps) sps[i] = uregs.xsp; |
| 605 | if (fps) fps[i] = uregs.xbp; |
| 606 | ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 607 | if (debug) |
philippe | 2d207aa | 2015-05-31 15:18:36 +0000 | [diff] [blame] | 608 | VG_(printf)(" ipsC[%d]=%#08lx rbp %#08lx rsp %#08lx\n", |
| 609 | i-1, ips[i-1], uregs.xbp, uregs.xsp); |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 610 | uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 611 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 612 | continue; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 613 | } |
sewardj | 3516553 | 2005-04-30 18:47:48 +0000 | [diff] [blame] | 614 | |
sewardj | eadcd86 | 2006-04-04 15:12:44 +0000 | [diff] [blame] | 615 | /* If VG_(use_CF_info) fails, it won't modify ip/sp/fp, so |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 616 | we can safely try the old-fashioned method. */ |
| 617 | /* This bit is supposed to deal with frames resulting from |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 618 | functions which begin "pushq %rbp ; movq %rsp, %rbp". |
| 619 | Unfortunately, since we can't (easily) look at the insns at |
| 620 | the start of the fn, like GDB does, there's no reliable way |
| 621 | to tell. Hence the hack of first trying out CFI, and if that |
| 622 | fails, then use this as a fallback. */ |
sewardj | f98e1c0 | 2008-10-25 16:22:41 +0000 | [diff] [blame] | 623 | /* Note: re "- 1 * sizeof(UWord)", need to take account of the |
| 624 | fact that we are prodding at & ((UWord*)fp)[1] and so need to |
| 625 | adjust the limit check accordingly. Omitting this has been |
| 626 | observed to cause segfaults on rare occasions. */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 627 | if (fp_min <= uregs.xbp && uregs.xbp <= fp_max - 1 * sizeof(UWord)) { |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 628 | /* fp looks sane, so use it. */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 629 | uregs.xip = (((UWord*)uregs.xbp)[1]); |
| 630 | if (0 == uregs.xip || 1 == uregs.xip) break; |
| 631 | uregs.xsp = uregs.xbp + sizeof(Addr) /*saved %rbp*/ |
| 632 | + sizeof(Addr) /*ra*/; |
| 633 | uregs.xbp = (((UWord*)uregs.xbp)[0]); |
| 634 | if (sps) sps[i] = uregs.xsp; |
| 635 | if (fps) fps[i] = uregs.xbp; |
| 636 | ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 637 | if (debug) |
philippe | 30fb2d3 | 2015-05-31 15:26:51 +0000 | [diff] [blame] | 638 | VG_(printf)(" ipsF[%d]=%#08lx rbp %#08lx rsp %#08lx\n", |
| 639 | i-1, ips[i-1], uregs.xbp, uregs.xsp); |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 640 | uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 641 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 642 | continue; |
| 643 | } |
| 644 | |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 645 | /* Last-ditch hack (evidently GDB does something similar). We |
| 646 | are in the middle of nowhere and we have a nonsense value for |
| 647 | the frame pointer. If the stack pointer is still valid, |
| 648 | assume that what it points at is a return address. Yes, |
| 649 | desperate measures. Could do better here: |
| 650 | - check that the supposed return address is in |
| 651 | an executable page |
| 652 | - check that the supposed return address is just after a call insn |
| 653 | - given those two checks, don't just consider *sp as the return |
| 654 | address; instead scan a likely section of stack (eg sp .. sp+256) |
| 655 | and use suitable values found there. |
| 656 | */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 657 | if (fp_min <= uregs.xsp && uregs.xsp < fp_max) { |
| 658 | uregs.xip = ((UWord*)uregs.xsp)[0]; |
| 659 | if (0 == uregs.xip || 1 == uregs.xip) break; |
| 660 | if (sps) sps[i] = uregs.xsp; |
| 661 | if (fps) fps[i] = uregs.xbp; |
| 662 | ips[i++] = uregs.xip == 0 |
sewardj | b1ae15d | 2008-12-12 13:23:03 +0000 | [diff] [blame] | 663 | ? 0 /* sp[0] == 0 ==> stuck at the bottom of a |
| 664 | thread stack */ |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 665 | : uregs.xip - 1; |
| 666 | /* -1: refer to calling insn, not the RA */ |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 667 | if (debug) |
bart | a0b6b2c | 2008-07-07 06:49:24 +0000 | [diff] [blame] | 668 | VG_(printf)(" ipsH[%d]=%#08lx\n", i-1, ips[i-1]); |
sewardj | 9365e3f | 2010-01-01 19:55:17 +0000 | [diff] [blame] | 669 | uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ |
| 670 | uregs.xsp += 8; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 671 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 672 | continue; |
| 673 | } |
| 674 | |
| 675 | /* No luck at all. We have to give up. */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 676 | break; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 677 | } |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 678 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 679 | n_found = i; |
| 680 | return n_found; |
| 681 | } |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 682 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 683 | #endif |
| 684 | |
| 685 | /* -----------------------ppc32/64 ---------------------- */ |
| 686 | |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 687 | #if defined(VGP_ppc32_linux) || defined(VGP_ppc64be_linux) \ |
| 688 | || defined(VGP_ppc64le_linux) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 689 | |
| 690 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 691 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 692 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 693 | const UnwindStartRegs* startRegs, |
sewardj | f5f1e12 | 2010-01-02 13:24:58 +0000 | [diff] [blame] | 694 | Addr fp_max_orig ) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 695 | { |
| 696 | Bool lr_is_first_RA = False; |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 697 | # if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux) |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 698 | Word redir_stack_size = 0; |
| 699 | Word redirs_used = 0; |
| 700 | # endif |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 701 | const Int cmrf = VG_(clo_merge_recursive_frames); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 702 | |
| 703 | Bool debug = False; |
| 704 | Int i; |
| 705 | Addr fp_max; |
| 706 | UInt n_found = 0; |
| 707 | |
| 708 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 709 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 710 | |
sewardj | f5f1e12 | 2010-01-02 13:24:58 +0000 | [diff] [blame] | 711 | Addr ip = (Addr)startRegs->r_pc; |
| 712 | Addr sp = (Addr)startRegs->r_sp; |
| 713 | Addr fp = sp; |
sewardj | 6e9de46 | 2011-06-28 07:25:29 +0000 | [diff] [blame] | 714 | # if defined(VGP_ppc32_linux) |
sewardj | f5f1e12 | 2010-01-02 13:24:58 +0000 | [diff] [blame] | 715 | Addr lr = startRegs->misc.PPC32.r_lr; |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 716 | # elif defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) |
sewardj | f5f1e12 | 2010-01-02 13:24:58 +0000 | [diff] [blame] | 717 | Addr lr = startRegs->misc.PPC64.r_lr; |
| 718 | # endif |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 719 | Addr fp_min = sp - VG_STACK_REDZONE_SZB; |
sewardj | f5f1e12 | 2010-01-02 13:24:58 +0000 | [diff] [blame] | 720 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 721 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
| 722 | stopping when the trail goes cold, which we guess to be |
| 723 | when FP is not a reasonable stack location. */ |
| 724 | |
| 725 | // JRS 2002-sep-17: hack, to round up fp_max to the end of the |
| 726 | // current page, at least. Dunno if it helps. |
| 727 | // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again |
| 728 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 729 | if (fp_max >= sizeof(Addr)) |
| 730 | fp_max -= sizeof(Addr); |
| 731 | |
| 732 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 733 | VG_(printf)("max_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 734 | "fp_max=0x%lx ip=0x%lx fp=0x%lx\n", |
| 735 | max_n_ips, fp_min, fp_max_orig, fp_max, ip, fp); |
| 736 | |
| 737 | /* Assertion broken before main() is reached in pthreaded programs; the |
| 738 | * offending stack traces only have one item. --njn, 2002-aug-16 */ |
| 739 | /* vg_assert(fp_min <= fp_max);*/ |
| 740 | if (fp_min + 512 >= fp_max) { |
| 741 | /* If the stack limits look bogus, don't poke around ... but |
| 742 | don't bomb out either. */ |
| 743 | if (sps) sps[0] = sp; |
| 744 | if (fps) fps[0] = fp; |
| 745 | ips[0] = ip; |
| 746 | return 1; |
| 747 | } |
sewardj | 75ea798 | 2005-11-14 15:18:25 +0000 | [diff] [blame] | 748 | |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 749 | /* fp is %r1. ip is %cia. Note, ppc uses r1 as both the stack and |
| 750 | frame pointers. */ |
| 751 | |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 752 | # if defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 753 | redir_stack_size = VEX_GUEST_PPC64_REDIR_STACK_SIZE; |
| 754 | redirs_used = 0; |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 755 | # endif |
| 756 | |
carll | a6954a4 | 2015-05-06 19:18:28 +0000 | [diff] [blame] | 757 | # if defined(VG_PLAT_USES_PPCTOC) || defined (VGP_ppc64le_linux) |
sewardj | cfb5e2b | 2006-01-19 03:47:30 +0000 | [diff] [blame] | 758 | /* Deal with bogus LR values caused by function |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 759 | interception/wrapping on ppc-TOC platforms; see comment on |
| 760 | similar code a few lines further down. */ |
florian | ddd61ff | 2015-01-04 17:20:45 +0000 | [diff] [blame] | 761 | if (lr == (Addr)&VG_(ppctoc_magic_redirect_return_stub) |
sewardj | cfb5e2b | 2006-01-19 03:47:30 +0000 | [diff] [blame] | 762 | && VG_(is_valid_tid)(tid_if_known)) { |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 763 | Word hsp = VG_(threads)[tid_if_known].arch.vex.guest_REDIR_SP; |
| 764 | redirs_used++; |
| 765 | if (hsp >= 1 && hsp < redir_stack_size) |
sewardj | cfb5e2b | 2006-01-19 03:47:30 +0000 | [diff] [blame] | 766 | lr = VG_(threads)[tid_if_known] |
| 767 | .arch.vex.guest_REDIR_STACK[hsp-1]; |
| 768 | } |
| 769 | # endif |
| 770 | |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 771 | /* We have to determine whether or not LR currently holds this fn |
| 772 | (call it F)'s return address. It might not if F has previously |
| 773 | called some other function, hence overwriting LR with a pointer |
| 774 | to some part of F. Hence if LR and IP point to the same |
| 775 | function then we conclude LR does not hold this function's |
| 776 | return address; instead the LR at entry must have been saved in |
| 777 | the stack by F's prologue and so we must get it from there |
| 778 | instead. Note all this guff only applies to the innermost |
| 779 | frame. */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 780 | lr_is_first_RA = False; |
| 781 | { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 782 | const HChar *buf_lr, *buf_ip; |
sewardj | b1ae15d | 2008-12-12 13:23:03 +0000 | [diff] [blame] | 783 | /* The following conditional looks grossly inefficient and |
| 784 | surely could be majorly improved, with not much effort. */ |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 785 | if (VG_(get_fnname_raw) (lr, &buf_lr)) { |
| 786 | HChar buf_lr_copy[VG_(strlen)(buf_lr) + 1]; |
| 787 | VG_(strcpy)(buf_lr_copy, buf_lr); |
| 788 | if (VG_(get_fnname_raw) (ip, &buf_ip)) |
| 789 | if (VG_(strcmp)(buf_lr_copy, buf_ip)) |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 790 | lr_is_first_RA = True; |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 791 | } |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 792 | } |
| 793 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 794 | if (sps) sps[0] = fp; /* NB. not sp */ |
| 795 | if (fps) fps[0] = fp; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 796 | ips[0] = ip; |
| 797 | i = 1; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 798 | |
sewardj | db2ac81 | 2005-12-23 23:33:51 +0000 | [diff] [blame] | 799 | if (fp_min <= fp && fp < fp_max-VG_WORDSIZE+1) { |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 800 | |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 801 | /* initial FP is sane; keep going */ |
| 802 | fp = (((UWord*)fp)[0]); |
| 803 | |
| 804 | while (True) { |
| 805 | |
sewardj | 6e9de46 | 2011-06-28 07:25:29 +0000 | [diff] [blame] | 806 | /* On ppc64-linux (ppc64-elf, really), the lr save |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 807 | slot is 2 words back from sp, whereas on ppc32-elf(?) it's |
| 808 | only one word back. */ |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 809 | # if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux) |
sewardj | dfbaa22 | 2006-01-18 04:25:20 +0000 | [diff] [blame] | 810 | const Int lr_offset = 2; |
| 811 | # else |
| 812 | const Int lr_offset = 1; |
| 813 | # endif |
sewardj | db2ac81 | 2005-12-23 23:33:51 +0000 | [diff] [blame] | 814 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 815 | if (i >= max_n_ips) |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 816 | break; |
| 817 | |
| 818 | /* Try to derive a new (ip,fp) pair from the current set. */ |
| 819 | |
sewardj | f98e1c0 | 2008-10-25 16:22:41 +0000 | [diff] [blame] | 820 | if (fp_min <= fp && fp <= fp_max - lr_offset * sizeof(UWord)) { |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 821 | /* fp looks sane, so use it. */ |
| 822 | |
| 823 | if (i == 1 && lr_is_first_RA) |
| 824 | ip = lr; |
| 825 | else |
sewardj | db2ac81 | 2005-12-23 23:33:51 +0000 | [diff] [blame] | 826 | ip = (((UWord*)fp)[lr_offset]); |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 827 | |
carll | cae0cc2 | 2014-08-07 23:17:29 +0000 | [diff] [blame] | 828 | # if defined(VG_PLAT_USES_PPCTOC) || defined(VGP_ppc64le_linux) |
sewardj | dfbaa22 | 2006-01-18 04:25:20 +0000 | [diff] [blame] | 829 | /* Nasty hack to do with function replacement/wrapping on |
sewardj | 6e9de46 | 2011-06-28 07:25:29 +0000 | [diff] [blame] | 830 | ppc64-linux. If LR points to our magic return stub, |
| 831 | then we are in a wrapped or intercepted function, in |
| 832 | which LR has been messed with. The original LR will |
| 833 | have been pushed onto the thread's hidden REDIR stack |
| 834 | one down from the top (top element is the saved R2) and |
| 835 | so we should restore the value from there instead. |
| 836 | Since nested redirections can and do happen, we keep |
| 837 | track of the number of nested LRs used by the unwinding |
| 838 | so far with 'redirs_used'. */ |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 839 | if (ip == (Addr)&VG_(ppctoc_magic_redirect_return_stub) |
sewardj | dfbaa22 | 2006-01-18 04:25:20 +0000 | [diff] [blame] | 840 | && VG_(is_valid_tid)(tid_if_known)) { |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 841 | Word hsp = VG_(threads)[tid_if_known] |
| 842 | .arch.vex.guest_REDIR_SP; |
sewardj | 15338c5 | 2006-10-17 01:31:58 +0000 | [diff] [blame] | 843 | hsp -= 2 * redirs_used; |
| 844 | redirs_used ++; |
| 845 | if (hsp >= 1 && hsp < redir_stack_size) |
sewardj | dfbaa22 | 2006-01-18 04:25:20 +0000 | [diff] [blame] | 846 | ip = VG_(threads)[tid_if_known] |
| 847 | .arch.vex.guest_REDIR_STACK[hsp-1]; |
| 848 | } |
| 849 | # endif |
| 850 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 851 | if (0 == ip || 1 == ip) break; |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 852 | if (sps) sps[i] = fp; /* NB. not sp */ |
| 853 | if (fps) fps[i] = fp; |
tom | 8805326 | 2009-11-12 13:19:41 +0000 | [diff] [blame] | 854 | fp = (((UWord*)fp)[0]); |
sewardj | b1ae15d | 2008-12-12 13:23:03 +0000 | [diff] [blame] | 855 | ips[i++] = ip - 1; /* -1: refer to calling insn, not the RA */ |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 856 | if (debug) |
bart | a0b6b2c | 2008-07-07 06:49:24 +0000 | [diff] [blame] | 857 | VG_(printf)(" ipsF[%d]=%#08lx\n", i-1, ips[i-1]); |
sewardj | b1ae15d | 2008-12-12 13:23:03 +0000 | [diff] [blame] | 858 | ip = ip - 1; /* ip is probably dead at this point, but |
| 859 | play safe, a la x86/amd64 above. See |
| 860 | extensive comments above. */ |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 861 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 525e232 | 2005-11-13 02:41:35 +0000 | [diff] [blame] | 862 | continue; |
| 863 | } |
| 864 | |
| 865 | /* No luck there. We have to give up. */ |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 866 | break; |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 867 | } |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 868 | } |
| 869 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 870 | n_found = i; |
| 871 | return n_found; |
| 872 | } |
| 873 | |
| 874 | #endif |
| 875 | |
| 876 | /* ------------------------ arm ------------------------- */ |
| 877 | |
| 878 | #if defined(VGP_arm_linux) |
| 879 | |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 880 | static Bool in_same_fn ( Addr a1, Addr a2 ) |
| 881 | { |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 882 | const HChar *buf_a1, *buf_a2; |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 883 | /* The following conditional looks grossly inefficient and |
| 884 | surely could be majorly improved, with not much effort. */ |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 885 | if (VG_(get_fnname_raw) (a1, &buf_a1)) { |
| 886 | HChar buf_a1_copy[VG_(strlen)(buf_a1) + 1]; |
| 887 | VG_(strcpy)(buf_a1_copy, buf_a1); |
| 888 | if (VG_(get_fnname_raw) (a2, &buf_a2)) |
weidendo | 30e866e | 2014-11-05 19:46:21 +0000 | [diff] [blame] | 889 | if (VG_(strcmp)(buf_a1_copy, buf_a2)) |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 890 | return True; |
florian | 46cc045 | 2014-10-25 19:20:38 +0000 | [diff] [blame] | 891 | } |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 892 | return False; |
| 893 | } |
| 894 | |
| 895 | static Bool in_same_page ( Addr a1, Addr a2 ) { |
| 896 | return (a1 & ~0xFFF) == (a2 & ~0xFFF); |
| 897 | } |
| 898 | |
| 899 | static Addr abs_diff ( Addr a1, Addr a2 ) { |
| 900 | return (Addr)(a1 > a2 ? a1 - a2 : a2 - a1); |
| 901 | } |
| 902 | |
| 903 | static Bool has_XT_perms ( Addr a ) |
| 904 | { |
| 905 | NSegment const* seg = VG_(am_find_nsegment)(a); |
| 906 | return seg && seg->hasX && seg->hasT; |
| 907 | } |
| 908 | |
| 909 | static Bool looks_like_Thumb_call32 ( UShort w0, UShort w1 ) |
| 910 | { |
| 911 | if (0) |
| 912 | VG_(printf)("isT32call %04x %04x\n", (UInt)w0, (UInt)w1); |
| 913 | // BL simm26 |
| 914 | if ((w0 & 0xF800) == 0xF000 && (w1 & 0xC000) == 0xC000) return True; |
| 915 | // BLX simm26 |
| 916 | if ((w0 & 0xF800) == 0xF000 && (w1 & 0xC000) == 0xC000) return True; |
| 917 | return False; |
| 918 | } |
| 919 | |
| 920 | static Bool looks_like_Thumb_call16 ( UShort w0 ) |
| 921 | { |
| 922 | return False; |
| 923 | } |
| 924 | |
| 925 | static Bool looks_like_ARM_call ( UInt a0 ) |
| 926 | { |
| 927 | if (0) |
| 928 | VG_(printf)("isA32call %08x\n", a0); |
| 929 | // Leading E forces unconditional only -- fix |
| 930 | if ((a0 & 0xFF000000) == 0xEB000000) return True; |
| 931 | return False; |
| 932 | } |
| 933 | |
| 934 | static Bool looks_like_RA ( Addr ra ) |
| 935 | { |
| 936 | /* 'ra' is a plausible return address if it points to |
| 937 | an instruction after a call insn. */ |
| 938 | Bool isT = (ra & 1); |
| 939 | if (isT) { |
| 940 | // returning to Thumb code |
| 941 | ra &= ~1; |
| 942 | ra -= 4; |
| 943 | if (has_XT_perms(ra)) { |
| 944 | UShort w0 = *(UShort*)ra; |
| 945 | UShort w1 = in_same_page(ra, ra+2) ? *(UShort*)(ra+2) : 0; |
| 946 | if (looks_like_Thumb_call16(w1) || looks_like_Thumb_call32(w0,w1)) |
| 947 | return True; |
| 948 | } |
| 949 | } else { |
| 950 | // ARM |
| 951 | ra &= ~3; |
| 952 | ra -= 4; |
| 953 | if (has_XT_perms(ra)) { |
| 954 | UInt a0 = *(UInt*)ra; |
| 955 | if (looks_like_ARM_call(a0)) |
| 956 | return True; |
| 957 | } |
| 958 | } |
| 959 | return False; |
| 960 | } |
| 961 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 962 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 963 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 964 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 965 | const UnwindStartRegs* startRegs, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 966 | Addr fp_max_orig ) |
| 967 | { |
| 968 | Bool debug = False; |
| 969 | Int i; |
| 970 | Addr fp_max; |
| 971 | UInt n_found = 0; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 972 | const Int cmrf = VG_(clo_merge_recursive_frames); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 973 | |
| 974 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 975 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 976 | |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 977 | D3UnwindRegs uregs; |
sewardj | fa5ce56 | 2010-09-23 22:05:59 +0000 | [diff] [blame] | 978 | uregs.r15 = startRegs->r_pc & 0xFFFFFFFE; |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 979 | uregs.r14 = startRegs->misc.ARM.r14; |
| 980 | uregs.r13 = startRegs->r_sp; |
| 981 | uregs.r12 = startRegs->misc.ARM.r12; |
| 982 | uregs.r11 = startRegs->misc.ARM.r11; |
sewardj | fa5ce56 | 2010-09-23 22:05:59 +0000 | [diff] [blame] | 983 | uregs.r7 = startRegs->misc.ARM.r7; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 984 | Addr fp_min = uregs.r13 - VG_STACK_REDZONE_SZB; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 985 | |
| 986 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
| 987 | stopping when the trail goes cold, which we guess to be |
| 988 | when FP is not a reasonable stack location. */ |
| 989 | |
| 990 | // JRS 2002-sep-17: hack, to round up fp_max to the end of the |
| 991 | // current page, at least. Dunno if it helps. |
| 992 | // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again |
| 993 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 994 | if (fp_max >= sizeof(Addr)) |
| 995 | fp_max -= sizeof(Addr); |
| 996 | |
| 997 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 998 | VG_(printf)("\nmax_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 999 | "fp_max=0x%lx r15=0x%lx r13=0x%lx\n", |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1000 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 1001 | uregs.r15, uregs.r13); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1002 | |
| 1003 | /* Assertion broken before main() is reached in pthreaded programs; the |
| 1004 | * offending stack traces only have one item. --njn, 2002-aug-16 */ |
| 1005 | /* vg_assert(fp_min <= fp_max);*/ |
| 1006 | // On Darwin, this kicks in for pthread-related stack traces, so they're |
| 1007 | // only 1 entry long which is wrong. |
| 1008 | if (fp_min + 512 >= fp_max) { |
| 1009 | /* If the stack limits look bogus, don't poke around ... but |
| 1010 | don't bomb out either. */ |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1011 | if (sps) sps[0] = uregs.r13; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1012 | if (fps) fps[0] = 0; |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1013 | ips[0] = uregs.r15; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1014 | return 1; |
| 1015 | } |
| 1016 | |
| 1017 | /* */ |
| 1018 | |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1019 | if (sps) sps[0] = uregs.r13; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1020 | if (fps) fps[0] = 0; |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1021 | ips[0] = uregs.r15; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1022 | i = 1; |
| 1023 | |
| 1024 | /* Loop unwinding the stack. */ |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 1025 | Bool do_stack_scan = False; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1026 | |
sewardj | 49984ea | 2013-10-18 13:21:26 +0000 | [diff] [blame] | 1027 | /* First try the Official Way, using Dwarf CFI. */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1028 | while (True) { |
| 1029 | if (debug) { |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1030 | VG_(printf)("i: %d, r15: 0x%lx, r13: 0x%lx\n", |
| 1031 | i, uregs.r15, uregs.r13); |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1032 | } |
| 1033 | |
| 1034 | if (i >= max_n_ips) |
| 1035 | break; |
| 1036 | |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1037 | if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { |
| 1038 | if (sps) sps[i] = uregs.r13; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1039 | if (fps) fps[i] = 0; |
sewardj | fa5ce56 | 2010-09-23 22:05:59 +0000 | [diff] [blame] | 1040 | ips[i++] = (uregs.r15 & 0xFFFFFFFE) - 1; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1041 | if (debug) |
sewardj | 3026f71 | 2010-01-01 18:46:41 +0000 | [diff] [blame] | 1042 | VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n", |
| 1043 | uregs.r15, uregs.r13); |
sewardj | fa5ce56 | 2010-09-23 22:05:59 +0000 | [diff] [blame] | 1044 | uregs.r15 = (uregs.r15 & 0xFFFFFFFE) - 1; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1045 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1046 | continue; |
| 1047 | } |
sewardj | 49984ea | 2013-10-18 13:21:26 +0000 | [diff] [blame] | 1048 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1049 | /* No luck. We have to give up. */ |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 1050 | do_stack_scan = True; |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1051 | break; |
| 1052 | } |
sewardj | acaec5f | 2005-08-19 16:02:59 +0000 | [diff] [blame] | 1053 | |
sewardj | 49984ea | 2013-10-18 13:21:26 +0000 | [diff] [blame] | 1054 | /* Now try Plan B (maybe) -- stack scanning. This often gives |
| 1055 | pretty bad results, so this has to be enabled explicitly by the |
| 1056 | user. */ |
| 1057 | if (do_stack_scan |
| 1058 | && i < max_n_ips && i < (Int)VG_(clo_unw_stack_scan_thresh)) { |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 1059 | Int nByStackScan = 0; |
| 1060 | Addr lr = uregs.r14; |
| 1061 | Addr sp = uregs.r13 & ~3; |
| 1062 | Addr pc = uregs.r15; |
| 1063 | // First see if LR contains |
| 1064 | // something that could be a valid return address. |
| 1065 | if (!in_same_fn(lr, pc) && looks_like_RA(lr)) { |
| 1066 | // take it only if 'cand' isn't obviously a duplicate |
| 1067 | // of the last found IP value |
| 1068 | Addr cand = (lr & 0xFFFFFFFE) - 1; |
| 1069 | if (abs_diff(cand, ips[i-1]) > 1) { |
| 1070 | if (sps) sps[i] = 0; |
| 1071 | if (fps) fps[i] = 0; |
| 1072 | ips[i++] = cand; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1073 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 1074 | nByStackScan++; |
| 1075 | } |
| 1076 | } |
| 1077 | while (in_same_page(sp, uregs.r13)) { |
| 1078 | if (i >= max_n_ips) |
| 1079 | break; |
| 1080 | // we're in the same page; fairly safe to keep going |
| 1081 | UWord w = *(UWord*)(sp & ~0x3); |
| 1082 | if (looks_like_RA(w)) { |
| 1083 | Addr cand = (w & 0xFFFFFFFE) - 1; |
| 1084 | // take it only if 'cand' isn't obviously a duplicate |
| 1085 | // of the last found IP value |
| 1086 | if (abs_diff(cand, ips[i-1]) > 1) { |
| 1087 | if (sps) sps[i] = 0; |
| 1088 | if (fps) fps[i] = 0; |
| 1089 | ips[i++] = cand; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1090 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 49984ea | 2013-10-18 13:21:26 +0000 | [diff] [blame] | 1091 | if (++nByStackScan >= VG_(clo_unw_stack_scan_frames)) break; |
sewardj | e947ce1 | 2012-06-15 16:20:23 +0000 | [diff] [blame] | 1092 | } |
| 1093 | } |
| 1094 | sp += 4; |
| 1095 | } |
| 1096 | } |
| 1097 | |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1098 | n_found = i; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1099 | return n_found; |
| 1100 | } |
| 1101 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1102 | #endif |
| 1103 | |
sewardj | f0c1250 | 2014-01-12 12:54:00 +0000 | [diff] [blame] | 1104 | /* ------------------------ arm64 ------------------------- */ |
| 1105 | |
| 1106 | #if defined(VGP_arm64_linux) |
| 1107 | |
| 1108 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 1109 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 1110 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1111 | const UnwindStartRegs* startRegs, |
sewardj | f0c1250 | 2014-01-12 12:54:00 +0000 | [diff] [blame] | 1112 | Addr fp_max_orig ) |
| 1113 | { |
sewardj | 821283b | 2014-01-13 00:21:09 +0000 | [diff] [blame] | 1114 | Bool debug = False; |
| 1115 | Int i; |
| 1116 | Addr fp_max; |
| 1117 | UInt n_found = 0; |
| 1118 | const Int cmrf = VG_(clo_merge_recursive_frames); |
| 1119 | |
| 1120 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 1121 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 1122 | |
| 1123 | D3UnwindRegs uregs; |
| 1124 | uregs.pc = startRegs->r_pc; |
| 1125 | uregs.sp = startRegs->r_sp; |
| 1126 | uregs.x30 = startRegs->misc.ARM64.x30; |
| 1127 | uregs.x29 = startRegs->misc.ARM64.x29; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 1128 | Addr fp_min = uregs.sp - VG_STACK_REDZONE_SZB; |
sewardj | 821283b | 2014-01-13 00:21:09 +0000 | [diff] [blame] | 1129 | |
| 1130 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
| 1131 | stopping when the trail goes cold, which we guess to be |
| 1132 | when FP is not a reasonable stack location. */ |
| 1133 | |
| 1134 | // JRS 2002-sep-17: hack, to round up fp_max to the end of the |
| 1135 | // current page, at least. Dunno if it helps. |
| 1136 | // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again |
| 1137 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 1138 | if (fp_max >= sizeof(Addr)) |
| 1139 | fp_max -= sizeof(Addr); |
| 1140 | |
| 1141 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 1142 | VG_(printf)("\nmax_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 821283b | 2014-01-13 00:21:09 +0000 | [diff] [blame] | 1143 | "fp_max=0x%lx PC=0x%lx SP=0x%lx\n", |
| 1144 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 1145 | uregs.pc, uregs.sp); |
| 1146 | |
| 1147 | /* Assertion broken before main() is reached in pthreaded programs; the |
| 1148 | * offending stack traces only have one item. --njn, 2002-aug-16 */ |
| 1149 | /* vg_assert(fp_min <= fp_max);*/ |
| 1150 | // On Darwin, this kicks in for pthread-related stack traces, so they're |
| 1151 | // only 1 entry long which is wrong. |
| 1152 | if (fp_min + 512 >= fp_max) { |
| 1153 | /* If the stack limits look bogus, don't poke around ... but |
| 1154 | don't bomb out either. */ |
| 1155 | if (sps) sps[0] = uregs.sp; |
| 1156 | if (fps) fps[0] = uregs.x29; |
| 1157 | ips[0] = uregs.pc; |
| 1158 | return 1; |
| 1159 | } |
| 1160 | |
| 1161 | /* */ |
| 1162 | |
| 1163 | if (sps) sps[0] = uregs.sp; |
| 1164 | if (fps) fps[0] = uregs.x29; |
| 1165 | ips[0] = uregs.pc; |
| 1166 | i = 1; |
| 1167 | |
| 1168 | /* Loop unwinding the stack, using CFI. */ |
| 1169 | while (True) { |
| 1170 | if (debug) { |
| 1171 | VG_(printf)("i: %d, pc: 0x%lx, sp: 0x%lx\n", |
| 1172 | i, uregs.pc, uregs.sp); |
| 1173 | } |
| 1174 | |
| 1175 | if (i >= max_n_ips) |
| 1176 | break; |
| 1177 | |
| 1178 | if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { |
| 1179 | if (sps) sps[i] = uregs.sp; |
| 1180 | if (fps) fps[i] = uregs.x29; |
| 1181 | ips[i++] = uregs.pc - 1; |
| 1182 | if (debug) |
| 1183 | VG_(printf)("USING CFI: pc: 0x%lx, sp: 0x%lx\n", |
| 1184 | uregs.pc, uregs.sp); |
| 1185 | uregs.pc = uregs.pc - 1; |
| 1186 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
| 1187 | continue; |
| 1188 | } |
| 1189 | |
| 1190 | /* No luck. We have to give up. */ |
| 1191 | break; |
| 1192 | } |
| 1193 | |
| 1194 | n_found = i; |
| 1195 | return n_found; |
sewardj | f0c1250 | 2014-01-12 12:54:00 +0000 | [diff] [blame] | 1196 | } |
| 1197 | |
| 1198 | #endif |
| 1199 | |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1200 | /* ------------------------ s390x ------------------------- */ |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1201 | |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1202 | #if defined(VGP_s390x_linux) |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1203 | |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1204 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 1205 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 1206 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1207 | const UnwindStartRegs* startRegs, |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1208 | Addr fp_max_orig ) |
| 1209 | { |
| 1210 | Bool debug = False; |
| 1211 | Int i; |
| 1212 | Addr fp_max; |
| 1213 | UInt n_found = 0; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1214 | const Int cmrf = VG_(clo_merge_recursive_frames); |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1215 | |
| 1216 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 1217 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 1218 | |
| 1219 | D3UnwindRegs uregs; |
| 1220 | uregs.ia = startRegs->r_pc; |
| 1221 | uregs.sp = startRegs->r_sp; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 1222 | Addr fp_min = uregs.sp - VG_STACK_REDZONE_SZB; |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1223 | uregs.fp = startRegs->misc.S390X.r_fp; |
| 1224 | uregs.lr = startRegs->misc.S390X.r_lr; |
| 1225 | |
| 1226 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 1227 | if (fp_max >= sizeof(Addr)) |
| 1228 | fp_max -= sizeof(Addr); |
| 1229 | |
| 1230 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 1231 | VG_(printf)("max_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1232 | "fp_max=0x%lx IA=0x%lx SP=0x%lx FP=0x%lx\n", |
| 1233 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 1234 | uregs.ia, uregs.sp,uregs.fp); |
| 1235 | |
| 1236 | /* The first frame is pretty obvious */ |
| 1237 | ips[0] = uregs.ia; |
| 1238 | if (sps) sps[0] = uregs.sp; |
| 1239 | if (fps) fps[0] = uregs.fp; |
| 1240 | i = 1; |
| 1241 | |
| 1242 | /* for everything else we have to rely on the eh_frame. gcc defaults to |
| 1243 | not create a backchain and all the other tools (like gdb) also have |
| 1244 | to use the CFI. */ |
| 1245 | while (True) { |
| 1246 | if (i >= max_n_ips) |
| 1247 | break; |
| 1248 | |
| 1249 | if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { |
| 1250 | if (sps) sps[i] = uregs.sp; |
| 1251 | if (fps) fps[i] = uregs.fp; |
| 1252 | ips[i++] = uregs.ia - 1; |
| 1253 | uregs.ia = uregs.ia - 1; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1254 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1255 | continue; |
| 1256 | } |
| 1257 | /* A problem on the first frame? Lets assume it was a bad jump. |
| 1258 | We will use the link register and the current stack and frame |
| 1259 | pointers and see if we can use the CFI in the next round. */ |
| 1260 | if (i == 1) { |
| 1261 | if (sps) { |
| 1262 | sps[i] = sps[0]; |
| 1263 | uregs.sp = sps[0]; |
| 1264 | } |
| 1265 | if (fps) { |
| 1266 | fps[i] = fps[0]; |
| 1267 | uregs.fp = fps[0]; |
| 1268 | } |
| 1269 | uregs.ia = uregs.lr - 1; |
| 1270 | ips[i++] = uregs.lr - 1; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1271 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1272 | continue; |
| 1273 | } |
| 1274 | |
| 1275 | /* No luck. We have to give up. */ |
| 1276 | break; |
| 1277 | } |
| 1278 | |
| 1279 | n_found = i; |
| 1280 | return n_found; |
| 1281 | } |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1282 | |
sewardj | b5b8740 | 2011-03-07 16:05:35 +0000 | [diff] [blame] | 1283 | #endif |
| 1284 | |
petarj | 4df0bfc | 2013-02-27 23:17:33 +0000 | [diff] [blame] | 1285 | /* ------------------------ mips 32/64 ------------------------- */ |
| 1286 | #if defined(VGP_mips32_linux) || defined(VGP_mips64_linux) |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1287 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 1288 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 1289 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
florian | 518850b | 2014-10-22 22:25:30 +0000 | [diff] [blame] | 1290 | const UnwindStartRegs* startRegs, |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1291 | Addr fp_max_orig ) |
| 1292 | { |
| 1293 | Bool debug = False; |
| 1294 | Int i; |
| 1295 | Addr fp_max; |
| 1296 | UInt n_found = 0; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1297 | const Int cmrf = VG_(clo_merge_recursive_frames); |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1298 | |
| 1299 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 1300 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 1301 | |
| 1302 | D3UnwindRegs uregs; |
| 1303 | uregs.pc = startRegs->r_pc; |
| 1304 | uregs.sp = startRegs->r_sp; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 1305 | Addr fp_min = uregs.sp - VG_STACK_REDZONE_SZB; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1306 | |
petarj | 4df0bfc | 2013-02-27 23:17:33 +0000 | [diff] [blame] | 1307 | #if defined(VGP_mips32_linux) |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1308 | uregs.fp = startRegs->misc.MIPS32.r30; |
| 1309 | uregs.ra = startRegs->misc.MIPS32.r31; |
petarj | 4df0bfc | 2013-02-27 23:17:33 +0000 | [diff] [blame] | 1310 | #elif defined(VGP_mips64_linux) |
| 1311 | uregs.fp = startRegs->misc.MIPS64.r30; |
| 1312 | uregs.ra = startRegs->misc.MIPS64.r31; |
| 1313 | #endif |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1314 | |
| 1315 | /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], |
| 1316 | stopping when the trail goes cold, which we guess to be |
| 1317 | when FP is not a reasonable stack location. */ |
| 1318 | |
| 1319 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 1320 | if (fp_max >= sizeof(Addr)) |
| 1321 | fp_max -= sizeof(Addr); |
| 1322 | |
| 1323 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 1324 | VG_(printf)("max_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1325 | "fp_max=0x%lx pc=0x%lx sp=0x%lx fp=0x%lx\n", |
| 1326 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 1327 | uregs.pc, uregs.sp, uregs.fp); |
| 1328 | |
| 1329 | if (sps) sps[0] = uregs.sp; |
| 1330 | if (fps) fps[0] = uregs.fp; |
| 1331 | ips[0] = uregs.pc; |
| 1332 | i = 1; |
| 1333 | |
| 1334 | /* Loop unwinding the stack. */ |
| 1335 | |
| 1336 | while (True) { |
| 1337 | if (debug) { |
| 1338 | VG_(printf)("i: %d, pc: 0x%lx, sp: 0x%lx, ra: 0x%lx\n", |
| 1339 | i, uregs.pc, uregs.sp, uregs.ra); |
| 1340 | } |
| 1341 | if (i >= max_n_ips) |
| 1342 | break; |
| 1343 | |
petarj | 9228067 | 2012-09-09 01:56:56 +0000 | [diff] [blame] | 1344 | D3UnwindRegs uregs_copy = uregs; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1345 | if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { |
| 1346 | if (debug) |
| 1347 | VG_(printf)("USING CFI: pc: 0x%lx, sp: 0x%lx, ra: 0x%lx\n", |
| 1348 | uregs.pc, uregs.sp, uregs.ra); |
petarj | 9228067 | 2012-09-09 01:56:56 +0000 | [diff] [blame] | 1349 | if (0 != uregs.pc && 1 != uregs.pc) { |
| 1350 | if (sps) sps[i] = uregs.sp; |
| 1351 | if (fps) fps[i] = uregs.fp; |
| 1352 | ips[i++] = uregs.pc - 4; |
| 1353 | uregs.pc = uregs.pc - 4; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1354 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
petarj | 9228067 | 2012-09-09 01:56:56 +0000 | [diff] [blame] | 1355 | continue; |
| 1356 | } else |
| 1357 | uregs = uregs_copy; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1358 | } |
| 1359 | |
| 1360 | int seen_sp_adjust = 0; |
| 1361 | long frame_offset = 0; |
| 1362 | PtrdiffT offset; |
| 1363 | if (VG_(get_inst_offset_in_function)(uregs.pc, &offset)) { |
| 1364 | Addr start_pc = uregs.pc - offset; |
| 1365 | Addr limit_pc = uregs.pc; |
| 1366 | Addr cur_pc; |
| 1367 | for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += 4) { |
| 1368 | unsigned long inst, high_word, low_word; |
| 1369 | unsigned long * cur_inst; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1370 | /* Fetch the instruction. */ |
| 1371 | cur_inst = (unsigned long *)cur_pc; |
| 1372 | inst = *((UInt *) cur_inst); |
| 1373 | if(debug) |
| 1374 | VG_(printf)("cur_pc: 0x%lx, inst: 0x%lx\n", cur_pc, inst); |
| 1375 | |
| 1376 | /* Save some code by pre-extracting some useful fields. */ |
| 1377 | high_word = (inst >> 16) & 0xffff; |
| 1378 | low_word = inst & 0xffff; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1379 | |
| 1380 | if (high_word == 0x27bd /* addiu $sp,$sp,-i */ |
| 1381 | || high_word == 0x23bd /* addi $sp,$sp,-i */ |
| 1382 | || high_word == 0x67bd) { /* daddiu $sp,$sp,-i */ |
| 1383 | if (low_word & 0x8000) /* negative stack adjustment? */ |
| 1384 | frame_offset += 0x10000 - low_word; |
| 1385 | else |
| 1386 | /* Exit loop if a positive stack adjustment is found, which |
| 1387 | usually means that the stack cleanup code in the function |
| 1388 | epilogue is reached. */ |
| 1389 | break; |
| 1390 | seen_sp_adjust = 1; |
| 1391 | } |
| 1392 | } |
| 1393 | if(debug) |
| 1394 | VG_(printf)("offset: 0x%lx\n", frame_offset); |
| 1395 | } |
| 1396 | if (seen_sp_adjust) { |
| 1397 | if (0 == uregs.pc || 1 == uregs.pc) break; |
| 1398 | if (uregs.pc == uregs.ra - 8) break; |
| 1399 | if (sps) { |
| 1400 | sps[i] = uregs.sp + frame_offset; |
| 1401 | } |
| 1402 | uregs.sp = uregs.sp + frame_offset; |
| 1403 | |
| 1404 | if (fps) { |
| 1405 | fps[i] = fps[0]; |
| 1406 | uregs.fp = fps[0]; |
| 1407 | } |
| 1408 | if (0 == uregs.ra || 1 == uregs.ra) break; |
| 1409 | uregs.pc = uregs.ra - 8; |
| 1410 | ips[i++] = uregs.ra - 8; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1411 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1412 | continue; |
| 1413 | } |
| 1414 | |
| 1415 | if (i == 1) { |
| 1416 | if (sps) { |
| 1417 | sps[i] = sps[0]; |
| 1418 | uregs.sp = sps[0]; |
| 1419 | } |
| 1420 | if (fps) { |
| 1421 | fps[i] = fps[0]; |
| 1422 | uregs.fp = fps[0]; |
| 1423 | } |
| 1424 | if (0 == uregs.ra || 1 == uregs.ra) break; |
| 1425 | uregs.pc = uregs.ra - 8; |
| 1426 | ips[i++] = uregs.ra - 8; |
philippe | 4620765 | 2013-01-20 17:11:58 +0000 | [diff] [blame] | 1427 | if (UNLIKELY(cmrf > 0)) {RECURSIVE_MERGE(cmrf,ips,i);}; |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1428 | continue; |
| 1429 | } |
| 1430 | /* No luck. We have to give up. */ |
| 1431 | break; |
| 1432 | } |
| 1433 | |
| 1434 | n_found = i; |
| 1435 | return n_found; |
| 1436 | } |
| 1437 | |
| 1438 | #endif |
| 1439 | |
sewardj | 112711a | 2015-04-10 12:30:09 +0000 | [diff] [blame] | 1440 | /* ------------------------ tilegx ------------------------- */ |
| 1441 | #if defined(VGP_tilegx_linux) |
| 1442 | UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, |
| 1443 | /*OUT*/Addr* ips, UInt max_n_ips, |
| 1444 | /*OUT*/Addr* sps, /*OUT*/Addr* fps, |
| 1445 | const UnwindStartRegs* startRegs, |
| 1446 | Addr fp_max_orig ) |
| 1447 | { |
| 1448 | Bool debug = False; |
| 1449 | Int i; |
| 1450 | Addr fp_max; |
| 1451 | UInt n_found = 0; |
| 1452 | const Int cmrf = VG_(clo_merge_recursive_frames); |
| 1453 | |
| 1454 | vg_assert(sizeof(Addr) == sizeof(UWord)); |
| 1455 | vg_assert(sizeof(Addr) == sizeof(void*)); |
| 1456 | |
| 1457 | D3UnwindRegs uregs; |
| 1458 | uregs.pc = startRegs->r_pc; |
| 1459 | uregs.sp = startRegs->r_sp; |
philippe | 01c353e | 2015-06-04 19:44:47 +0000 | [diff] [blame] | 1460 | Addr fp_min = uregs.sp - VG_STACK_REDZONE_SZB; |
sewardj | 112711a | 2015-04-10 12:30:09 +0000 | [diff] [blame] | 1461 | |
| 1462 | uregs.fp = startRegs->misc.TILEGX.r52; |
| 1463 | uregs.lr = startRegs->misc.TILEGX.r55; |
| 1464 | |
| 1465 | fp_max = VG_PGROUNDUP(fp_max_orig); |
| 1466 | if (fp_max >= sizeof(Addr)) |
| 1467 | fp_max -= sizeof(Addr); |
| 1468 | |
| 1469 | if (debug) |
florian | a7d291d | 2015-08-08 21:08:31 +0000 | [diff] [blame] | 1470 | VG_(printf)("max_n_ips=%u fp_min=0x%lx fp_max_orig=0x%lx, " |
sewardj | 112711a | 2015-04-10 12:30:09 +0000 | [diff] [blame] | 1471 | "fp_max=0x%lx pc=0x%lx sp=0x%lx fp=0x%lx\n", |
| 1472 | max_n_ips, fp_min, fp_max_orig, fp_max, |
| 1473 | uregs.pc, uregs.sp, uregs.fp); |
| 1474 | |
| 1475 | if (sps) sps[0] = uregs.sp; |
| 1476 | if (fps) fps[0] = uregs.fp; |
| 1477 | ips[0] = uregs.pc; |
| 1478 | i = 1; |
| 1479 | |
| 1480 | /* Loop unwinding the stack. */ |
| 1481 | while (True) { |
| 1482 | if (debug) { |
| 1483 | VG_(printf)("i: %d, pc: 0x%lx, sp: 0x%lx, lr: 0x%lx\n", |
| 1484 | i, uregs.pc, uregs.sp, uregs.lr); |
| 1485 | } |
| 1486 | if (i >= max_n_ips) |
| 1487 | break; |
| 1488 | |
| 1489 | D3UnwindRegs uregs_copy = uregs; |
| 1490 | if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { |
| 1491 | if (debug) |
| 1492 | VG_(printf)("USING CFI: pc: 0x%lx, sp: 0x%lx, fp: 0x%lx, lr: 0x%lx\n", |
| 1493 | uregs.pc, uregs.sp, uregs.fp, uregs.lr); |
| 1494 | if (0 != uregs.pc && 1 != uregs.pc && |
| 1495 | (uregs.pc < fp_min || uregs.pc > fp_max)) { |
| 1496 | if (sps) sps[i] = uregs.sp; |
| 1497 | if (fps) fps[i] = uregs.fp; |
| 1498 | if (uregs.pc != uregs_copy.pc && uregs.sp != uregs_copy.sp) |
| 1499 | ips[i++] = uregs.pc - 8; |
| 1500 | uregs.pc = uregs.pc - 8; |
| 1501 | if (UNLIKELY(cmrf > 0)) { RECURSIVE_MERGE(cmrf,ips,i); }; |
| 1502 | continue; |
| 1503 | } else |
| 1504 | uregs = uregs_copy; |
| 1505 | } |
| 1506 | |
| 1507 | Long frame_offset = 0; |
| 1508 | PtrdiffT offset; |
| 1509 | if (VG_(get_inst_offset_in_function)(uregs.pc, &offset)) { |
| 1510 | Addr start_pc = uregs.pc; |
| 1511 | Addr limit_pc = uregs.pc - offset; |
| 1512 | Addr cur_pc; |
| 1513 | /* Try to find any stack adjustment from current instruction |
| 1514 | bundles downward. */ |
| 1515 | for (cur_pc = start_pc; cur_pc > limit_pc; cur_pc -= 8) { |
| 1516 | ULong inst; |
| 1517 | Long off = 0; |
| 1518 | ULong* cur_inst; |
| 1519 | /* Fetch the instruction. */ |
| 1520 | cur_inst = (ULong *)cur_pc; |
| 1521 | inst = *cur_inst; |
| 1522 | if(debug) |
| 1523 | VG_(printf)("cur_pc: 0x%lx, inst: 0x%lx\n", cur_pc, inst); |
| 1524 | |
| 1525 | if ((inst & 0xC000000000000000ULL) == 0) { |
| 1526 | /* Bundle is X type. */ |
| 1527 | if ((inst & 0xC000000070000fffULL) == |
| 1528 | (0x0000000010000db6ULL)) { |
| 1529 | /* addli at X0 */ |
| 1530 | off = (short)(0xFFFF & (inst >> 12)); |
| 1531 | } else if ((inst & 0xF80007ff80000000ULL) == |
| 1532 | (0x000006db00000000ULL)) { |
| 1533 | /* addli at X1 addli*/ |
| 1534 | off = (short)(0xFFFF & (inst >> 43)); |
| 1535 | } else if ((inst & 0xC00000007FF00FFFULL) == |
| 1536 | (0x0000000040100db6ULL)) { |
| 1537 | /* addi at X0 */ |
| 1538 | off = (char)(0xFF & (inst >> 12)); |
| 1539 | } else if ((inst & 0xFFF807ff80000000ULL) == |
| 1540 | (0x180806db00000000ULL)) { |
| 1541 | /* addi at X1 */ |
| 1542 | off = (char)(0xFF & (inst >> 43)); |
| 1543 | } |
| 1544 | } else { |
| 1545 | /* Bundle is Y type. */ |
| 1546 | if ((inst & 0x0000000078000FFFULL) == |
| 1547 | (0x0000000000000db6ULL)) { |
| 1548 | /* addi at Y0 */ |
| 1549 | off = (char)(0xFF & (inst >> 12)); |
| 1550 | } else if ((inst & 0x3C0007FF80000000ULL) == |
| 1551 | (0x040006db00000000ULL)) { |
| 1552 | /* addi at Y1 */ |
| 1553 | off = (char)(0xFF & (inst >> 43)); |
| 1554 | } |
| 1555 | } |
| 1556 | |
| 1557 | if(debug && off) |
| 1558 | VG_(printf)("offset: -0x%lx\n", -off); |
| 1559 | |
| 1560 | if (off < 0) { |
| 1561 | /* frame offset should be modular of 8 */ |
| 1562 | vg_assert((off & 7) == 0); |
| 1563 | frame_offset += off; |
| 1564 | } else if (off > 0) |
| 1565 | /* Exit loop if a positive stack adjustment is found, which |
| 1566 | usually means that the stack cleanup code in the function |
| 1567 | epilogue is reached. */ |
| 1568 | break; |
| 1569 | } |
| 1570 | } |
| 1571 | |
| 1572 | if (frame_offset < 0) { |
| 1573 | if (0 == uregs.pc || 1 == uregs.pc) break; |
| 1574 | |
| 1575 | /* Subtract the offset from the current stack. */ |
| 1576 | uregs.sp = uregs.sp + (ULong)(-frame_offset); |
| 1577 | |
| 1578 | if (debug) |
| 1579 | VG_(printf)("offset: i: %d, pc: 0x%lx, sp: 0x%lx, lr: 0x%lx\n", |
| 1580 | i, uregs.pc, uregs.sp, uregs.lr); |
| 1581 | |
| 1582 | if (uregs.pc == uregs.lr - 8 || |
| 1583 | uregs.lr - 8 >= fp_min && uregs.lr - 8 <= fp_max) { |
| 1584 | if (debug) |
| 1585 | VG_(printf)("new lr = 0x%lx\n", *(ULong*)uregs.sp); |
| 1586 | uregs.lr = *(ULong*)uregs.sp; |
| 1587 | } |
| 1588 | |
| 1589 | uregs.pc = uregs.lr - 8; |
| 1590 | |
| 1591 | if (uregs.lr != 0) { |
| 1592 | /* Avoid the invalid pc = 0xffff...ff8 */ |
| 1593 | if (sps) |
| 1594 | sps[i] = uregs.sp; |
| 1595 | |
| 1596 | if (fps) |
| 1597 | fps[i] = fps[0]; |
| 1598 | |
| 1599 | ips[i++] = uregs.pc; |
| 1600 | |
| 1601 | if (UNLIKELY(cmrf > 0)) { RECURSIVE_MERGE(cmrf,ips,i); }; |
| 1602 | } |
| 1603 | continue; |
| 1604 | } |
| 1605 | |
| 1606 | /* A special case for the 1st frame. Assume it was a bad jump. |
| 1607 | Use the link register "lr" and current stack and frame to |
| 1608 | try again. */ |
| 1609 | if (i == 1) { |
| 1610 | if (sps) { |
| 1611 | sps[1] = sps[0]; |
| 1612 | uregs.sp = sps[0]; |
| 1613 | } |
| 1614 | if (fps) { |
| 1615 | fps[1] = fps[0]; |
| 1616 | uregs.fp = fps[0]; |
| 1617 | } |
| 1618 | if (0 == uregs.lr || 1 == uregs.lr) |
| 1619 | break; |
| 1620 | |
| 1621 | uregs.pc = uregs.lr - 8; |
| 1622 | ips[i++] = uregs.lr - 8; |
| 1623 | if (UNLIKELY(cmrf > 0)) { RECURSIVE_MERGE(cmrf,ips,i); }; |
| 1624 | continue; |
| 1625 | } |
| 1626 | /* No luck. We have to give up. */ |
| 1627 | break; |
| 1628 | } |
| 1629 | |
| 1630 | if (debug) { |
| 1631 | /* Display the back trace. */ |
| 1632 | Int ii ; |
| 1633 | for ( ii = 0; ii < i; ii++) { |
| 1634 | if (sps) { |
| 1635 | VG_(printf)("%d: pc=%lx ", ii, ips[ii]); |
| 1636 | VG_(printf)("sp=%lx\n", sps[ii]); |
| 1637 | } else { |
| 1638 | VG_(printf)("%d: pc=%lx\n", ii, ips[ii]); |
| 1639 | } |
| 1640 | } |
| 1641 | } |
| 1642 | |
| 1643 | n_found = i; |
| 1644 | return n_found; |
| 1645 | } |
| 1646 | #endif |
sewardj | 5db1540 | 2012-06-07 09:13:21 +0000 | [diff] [blame] | 1647 | |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1648 | /*------------------------------------------------------------*/ |
| 1649 | /*--- ---*/ |
| 1650 | /*--- END platform-dependent unwinder worker functions ---*/ |
| 1651 | /*--- ---*/ |
| 1652 | /*------------------------------------------------------------*/ |
| 1653 | |
| 1654 | /*------------------------------------------------------------*/ |
| 1655 | /*--- Exported functions. ---*/ |
| 1656 | /*------------------------------------------------------------*/ |
| 1657 | |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1658 | UInt VG_(get_StackTrace) ( ThreadId tid, |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1659 | /*OUT*/StackTrace ips, UInt max_n_ips, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1660 | /*OUT*/StackTrace sps, |
| 1661 | /*OUT*/StackTrace fps, |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 1662 | Word first_ip_delta ) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1663 | { |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1664 | /* Get the register values with which to start the unwind. */ |
| 1665 | UnwindStartRegs startRegs; |
| 1666 | VG_(memset)( &startRegs, 0, sizeof(startRegs) ); |
| 1667 | VG_(get_UnwindStartRegs)( &startRegs, tid ); |
| 1668 | |
philippe | 38a74d2 | 2014-08-29 22:53:19 +0000 | [diff] [blame] | 1669 | Addr stack_highest_byte = VG_(threads)[tid].client_stack_highest_byte; |
| 1670 | Addr stack_lowest_byte = 0; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1671 | |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1672 | # if defined(VGP_x86_linux) |
sewardj | a672ea3 | 2006-04-29 18:03:14 +0000 | [diff] [blame] | 1673 | /* Nasty little hack to deal with syscalls - if libc is using its |
| 1674 | _dl_sysinfo_int80 function for syscalls (the TLS version does), |
| 1675 | then ip will always appear to be in that function when doing a |
| 1676 | syscall, not the actual libc function doing the syscall. This |
| 1677 | check sees if IP is within that function, and pops the return |
| 1678 | address off the stack so that ip is placed within the library |
| 1679 | function calling the syscall. This makes stack backtraces much |
| 1680 | more useful. |
| 1681 | |
| 1682 | The function is assumed to look like this (from glibc-2.3.6 sources): |
| 1683 | _dl_sysinfo_int80: |
| 1684 | int $0x80 |
| 1685 | ret |
| 1686 | That is 3 (2+1) bytes long. We could be more thorough and check |
| 1687 | the 3 bytes of the function are as expected, but I can't be |
| 1688 | bothered. |
| 1689 | */ |
| 1690 | if (VG_(client__dl_sysinfo_int80) != 0 /* we know its address */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1691 | && startRegs.r_pc >= VG_(client__dl_sysinfo_int80) |
| 1692 | && startRegs.r_pc < VG_(client__dl_sysinfo_int80)+3 |
| 1693 | && VG_(am_is_valid_for_client)(startRegs.r_pc, sizeof(Addr), |
| 1694 | VKI_PROT_READ)) { |
| 1695 | startRegs.r_pc = (ULong) *(Addr*)(UWord)startRegs.r_sp; |
| 1696 | startRegs.r_sp += (ULong) sizeof(Addr); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1697 | } |
sewardj | b9bce63 | 2005-06-21 01:41:34 +0000 | [diff] [blame] | 1698 | # endif |
| 1699 | |
tom | 690c3c8 | 2008-02-08 15:17:07 +0000 | [diff] [blame] | 1700 | /* See if we can get a better idea of the stack limits */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1701 | VG_(stack_limits)( (Addr)startRegs.r_sp, |
philippe | 38a74d2 | 2014-08-29 22:53:19 +0000 | [diff] [blame] | 1702 | &stack_lowest_byte, &stack_highest_byte ); |
tom | 690c3c8 | 2008-02-08 15:17:07 +0000 | [diff] [blame] | 1703 | |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 1704 | /* Take into account the first_ip_delta. */ |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1705 | startRegs.r_pc += (Long)(Word)first_ip_delta; |
sewardj | 39f3423 | 2007-11-09 23:02:28 +0000 | [diff] [blame] | 1706 | |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1707 | if (0) |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 1708 | VG_(printf)("tid %u: stack_highest=0x%08lx ip=0x%010llx " |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1709 | "sp=0x%010llx\n", |
florian | a5e06c3 | 2015-08-05 21:16:09 +0000 | [diff] [blame] | 1710 | tid, stack_highest_byte, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1711 | startRegs.r_pc, startRegs.r_sp); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1712 | |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1713 | return VG_(get_StackTrace_wrk)(tid, ips, max_n_ips, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1714 | sps, fps, |
sewardj | 59570ff | 2010-01-01 11:59:33 +0000 | [diff] [blame] | 1715 | &startRegs, |
philippe | 38a74d2 | 2014-08-29 22:53:19 +0000 | [diff] [blame] | 1716 | stack_highest_byte); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1717 | } |
| 1718 | |
sewardj | 588adef | 2009-08-15 22:41:51 +0000 | [diff] [blame] | 1719 | static void printIpDesc(UInt n, Addr ip, void* uu_opaque) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1720 | { |
philippe | a0a7393 | 2014-06-15 15:42:20 +0000 | [diff] [blame] | 1721 | InlIPCursor *iipc = VG_(new_IIPC)(ip); |
sewardj | 71bc3cb | 2005-05-19 00:25:45 +0000 | [diff] [blame] | 1722 | |
philippe | a0a7393 | 2014-06-15 15:42:20 +0000 | [diff] [blame] | 1723 | do { |
florian | 770a8d2 | 2014-11-03 22:43:42 +0000 | [diff] [blame] | 1724 | const HChar *buf = VG_(describe_IP)(ip, iipc); |
philippe | a0a7393 | 2014-06-15 15:42:20 +0000 | [diff] [blame] | 1725 | if (VG_(clo_xml)) { |
| 1726 | VG_(printf_xml)(" %s\n", buf); |
| 1727 | } else { |
| 1728 | VG_(message)(Vg_UserMsg, " %s %s\n", |
| 1729 | ( n == 0 ? "at" : "by" ), buf); |
| 1730 | } |
| 1731 | n++; |
| 1732 | // Increase n to show "at" for only one level. |
| 1733 | } while (VG_(next_IIPC)(iipc)); |
| 1734 | VG_(delete_IIPC)(iipc); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1735 | } |
| 1736 | |
| 1737 | /* Print a StackTrace. */ |
| 1738 | void VG_(pp_StackTrace) ( StackTrace ips, UInt n_ips ) |
| 1739 | { |
| 1740 | vg_assert( n_ips > 0 ); |
sewardj | 71bc3cb | 2005-05-19 00:25:45 +0000 | [diff] [blame] | 1741 | |
| 1742 | if (VG_(clo_xml)) |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1743 | VG_(printf_xml)(" <stack>\n"); |
sewardj | 71bc3cb | 2005-05-19 00:25:45 +0000 | [diff] [blame] | 1744 | |
sewardj | 588adef | 2009-08-15 22:41:51 +0000 | [diff] [blame] | 1745 | VG_(apply_StackTrace)( printIpDesc, NULL, ips, n_ips ); |
sewardj | 71bc3cb | 2005-05-19 00:25:45 +0000 | [diff] [blame] | 1746 | |
| 1747 | if (VG_(clo_xml)) |
sewardj | 738856f | 2009-07-15 14:48:32 +0000 | [diff] [blame] | 1748 | VG_(printf_xml)(" </stack>\n"); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1749 | } |
| 1750 | |
| 1751 | /* Get and immediately print a StackTrace. */ |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1752 | void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt max_n_ips ) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1753 | { |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1754 | Addr ips[max_n_ips]; |
| 1755 | UInt n_ips |
| 1756 | = VG_(get_StackTrace)(tid, ips, max_n_ips, |
sewardj | b8b79ad | 2008-03-03 01:35:41 +0000 | [diff] [blame] | 1757 | NULL/*array to dump SP values in*/, |
| 1758 | NULL/*array to dump FP values in*/, |
| 1759 | 0/*first_ip_delta*/); |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1760 | VG_(pp_StackTrace)(ips, n_ips); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1761 | } |
| 1762 | |
sewardj | 588adef | 2009-08-15 22:41:51 +0000 | [diff] [blame] | 1763 | void VG_(apply_StackTrace)( |
| 1764 | void(*action)(UInt n, Addr ip, void* opaque), |
| 1765 | void* opaque, |
| 1766 | StackTrace ips, UInt n_ips |
| 1767 | ) |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1768 | { |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1769 | Bool main_done = False; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1770 | Int i = 0; |
| 1771 | |
| 1772 | vg_assert(n_ips > 0); |
| 1773 | do { |
| 1774 | Addr ip = ips[i]; |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1775 | |
sewardj | 73cf4c6 | 2005-11-17 15:12:34 +0000 | [diff] [blame] | 1776 | // Stop after the first appearance of "main" or one of the other names |
| 1777 | // (the appearance of which is a pretty good sign that we've gone past |
| 1778 | // main without seeing it, for whatever reason) |
njn | 6882443 | 2009-02-10 06:48:00 +0000 | [diff] [blame] | 1779 | if ( ! VG_(clo_show_below_main) ) { |
| 1780 | Vg_FnNameKind kind = VG_(get_fnname_kind_from_IP)(ip); |
| 1781 | if (Vg_FnNameMain == kind || Vg_FnNameBelowMain == kind) { |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1782 | main_done = True; |
njn | 6882443 | 2009-02-10 06:48:00 +0000 | [diff] [blame] | 1783 | } |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1784 | } |
| 1785 | |
| 1786 | // Act on the ip |
sewardj | 588adef | 2009-08-15 22:41:51 +0000 | [diff] [blame] | 1787 | action(i, ip, opaque); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1788 | |
| 1789 | i++; |
njn | 3a4b58f | 2009-05-07 23:08:10 +0000 | [diff] [blame] | 1790 | } while (i < n_ips && !main_done); |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1791 | } |
| 1792 | |
| 1793 | |
| 1794 | /*--------------------------------------------------------------------*/ |
njn | 24a6efb | 2005-06-20 03:36:51 +0000 | [diff] [blame] | 1795 | /*--- end ---*/ |
njn | d01fef7 | 2005-03-25 23:35:48 +0000 | [diff] [blame] | 1796 | /*--------------------------------------------------------------------*/ |