{"id":3303,"date":"2013-09-06T07:00:00","date_gmt":"2013-09-06T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/09\/06\/how-to-rescue-a-broken-stack-trace-on-x64-recovering-the-stack-pointer\/"},"modified":"2024-07-31T13:18:04","modified_gmt":"2024-07-31T20:18:04","slug":"20130906-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130906-00\/?p=3303","title":{"rendered":"How to rescue a broken stack trace on x64: Recovering the stack pointer"},"content":{"rendered":"<p>Recovering a broken stack on x64 machines on Windows is trickier because the x64 uses unwind codes for stack walking rather than a frame pointer chain. When you dump the stack, all you&#8217;re going to see is return addresses sprinkled in amongst the stack data.<\/p>\n<p><b>Begin digression<\/b>: According to the x64 ABI, each function must begin with a prologue which sets up the stack frame. It traditionally goes something like this:<\/p>\n<pre>    push rbx ;; save registers\r\n    push rsi ;; save registers\r\n    push rdi ;; save registers\r\n    sub rsp, 0x20 ;; allocate space for local variables and outbound calls\r\n<\/pre>\n<p>Suppose we have functions<\/p>\n<pre>void Top(int a, int b)\r\n{\r\n int toplocal = b + 5;\r\n Middle(a, local);\r\n}\r\n\r\nvoid Middle(int c, int d)\r\n{\r\n Bottom(c+d);\r\n}\r\n\r\nvoid Bottom(int e)\r\n{\r\n int bottomlocal1, bottomlocal2;\r\n ...\r\n}\r\n<\/pre>\n<p>When execution reaches the <code>...<\/code> inside function <code>Bottom<\/code> the stack looks like the following. (I put higher addresses at the top; the stack grows downward. I also assume that the code is compiled with absolutely no optimization.)<\/p>\n<table style=\"font-size: 80%;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td rowspan=\"4\" valign=\"middle\">\u00a0<\/td>\n<td rowspan=\"4\">\u00a0<\/td>\n<td rowspan=\"24\">\u00a0<\/td>\n<td style=\"border-top: solid 1pt currentcolor; border-left: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F8E8<\/code><\/td>\n<td valign=\"baseline\">parameter 4 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8E0<\/code><\/td>\n<td valign=\"baseline\">parameter 3 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8D8<\/code><\/td>\n<td valign=\"baseline\">parameter <code>b<\/code> passed to <code>Top<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8D0<\/code><\/td>\n<td valign=\"baseline\">parameter <code>a<\/code> passed to <code>Top<\/code><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"2\" valign=\"middle\"><code>Top<\/code>&#8216;s stack frame<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td style=\"border-left: solid 1pt currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F8C8<\/code><\/td>\n<td valign=\"baseline\">return address of <code>Top<\/code>&#8216;s caller<\/td>\n<td rowspan=\"6\" valign=\"bottom\">During execution of <code>Top<\/code>,<br \/>\n\u2190<code>rsp = 0040F8A0<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8C0<\/code><\/td>\n<td valign=\"baseline\"><code>toplocal<\/code><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"4\" valign=\"middle\">\u00a0<\/td>\n<td style=\"border-top: solid 1pt currentcolor; border-left: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td style=\"border-left: solid 1pt currentcolor; border-bottom: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F8B8<\/code><\/td>\n<td valign=\"baseline\">parameter 4 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8B0<\/code><\/td>\n<td valign=\"baseline\">parameter 3 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8A8<\/code><\/td>\n<td valign=\"baseline\">parameter <code>d<\/code> passed to <code>Middle<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F8A0<\/code><\/td>\n<td valign=\"baseline\">parameter <code>c<\/code> passed to <code>Middle<\/code><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"2\" valign=\"middle\"><code>Middle<\/code>&#8216;s stack frame<\/td>\n<td style=\"border-left: solid 1pt currentcolor;\" rowspan=\"2\">\u00a0<\/td>\n<td rowspan=\"2\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F898<\/code><\/td>\n<td valign=\"baseline\">return address of <code>Middle<\/code>&#8216;s caller<\/td>\n<td rowspan=\"6\" valign=\"bottom\">During execution of <code>Middle<\/code>,<br \/>\n\u2190<code>rsp = 0040F870<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F890<\/code><\/td>\n<td valign=\"baseline\">padding for alignment<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"4\" valign=\"middle\">\u00a0<\/td>\n<td style=\"border-left: solid 1pt currentcolor; border-bottom: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td style=\"border-top: solid 1pt currentcolor; border-left: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F888<\/code><\/td>\n<td valign=\"baseline\">parameter 4 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F880<\/code><\/td>\n<td valign=\"baseline\">parameter 3 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F878<\/code><\/td>\n<td valign=\"baseline\">parameter 2 (unused)<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F870<\/code><\/td>\n<td valign=\"baseline\">parameter <code>e<\/code> passed to <code>Bottom<\/code><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"4\" valign=\"middle\"><code>Bottom<\/code>&#8216;s stack frame<\/td>\n<td rowspan=\"4\">\u00a0<\/td>\n<td style=\"border-left: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F868<\/code><\/td>\n<td valign=\"baseline\">return address of <code>Bottom<\/code>&#8216;s caller<\/td>\n<td rowspan=\"8\" valign=\"bottom\">During execution of <code>Bottom<\/code>,<br \/>\n\u2190<code>rsp = 0040F830<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F860<\/code><\/td>\n<td valign=\"baseline\">padding for alignment<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F858<\/code><\/td>\n<td valign=\"baseline\"><code>bottomlocal1<\/code><\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F850<\/code><\/td>\n<td valign=\"baseline\"><code>bottomlocal2<\/code><\/td>\n<\/tr>\n<tr>\n<td rowspan=\"4\" valign=\"middle\">\u00a0<\/td>\n<td rowspan=\"4\">\u00a0<\/td>\n<td style=\"border-left: solid 1pt currentcolor; border-bottom: solid 1pt currentcolor;\" rowspan=\"4\">\u00a0<\/td>\n<td valign=\"baseline\"><code>0040F848<\/code><\/td>\n<td valign=\"baseline\">parameter 4<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F840<\/code><\/td>\n<td valign=\"baseline\">parameter 3<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F838<\/code><\/td>\n<td valign=\"baseline\">parameter 2<\/td>\n<\/tr>\n<tr>\n<td valign=\"baseline\"><code>0040F830<\/code><\/td>\n<td valign=\"baseline\">parameter 1<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Of course, once the optimizer kicks in, there will also be saved registers in the stack frame, the unused space will start getting used as scratch variables, and the parameters will almost certainly not be spilled into their home locations. <b>End digression<\/b>.<\/p>\n<p>Consider this crash where we started executing random instructions (data in the code segment) and finally trapped.<\/p>\n<pre>0:000&gt; r\r\nrax=0000000000000000 rbx=0000000000000005 rcx=0000000000000042\r\nrdx=0000000000000010 rsi=00000000000615d4 rdi=00000000043f48e0\r\nrip=0000000000000000 rsp=00000000001ebf68 rbp=00000000043f32d0\r\n r8=00000000001ebfd0  r9=0000000000000000 r10=000000007fff3cae\r\nr11=0000000000000000 r12=0000000000000002 r13=0000000000517050\r\nr14=0000000000000000 r15=00000000043f55c0\r\niopl=0         nv up ei pl nz na pe nc\r\ncs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202\r\nABC!RandomFunction+0x1234:\r\n00000000`ff6ebaad test    byte ptr [rax+rdx*4],ah ds:00000000`00000040=??\r\n0:000&gt; k\r\nChild-SP          RetAddr           Call Site\r\n00000000`001ebf70 00000000`00000004 ABC!RandomFunction+0x1234\r\n00000000`001ebf78 00000000`0000000e 0x4\r\n00000000`001ebf80 00000000`00000000 0xe\r\n<\/pre>\n<p>Not very helpful. Let&#8217;s try to reconstruct the call stack. Here&#8217;s what we have right now:<\/p>\n<pre>001ebf70  00000000`00000004\r\n001ebf78  00000000`0000000e\r\n001ebf80  00000000`00000000\r\n001ebf88  00000000`77ba21bc ntdll!RtlAllocateHeap+0x16c\r\n001ebf90  00000000`00000000\r\n001ebf98  00000000`ff6e1fa1 ABC!operator new[]+0x20\r\n001ebfa0  00000000`00000000\r\n001ebfa8  00000000`ff6e28ae ABC!DoesUserPreferMetricUnits+0x2a\r\n001ebfb0  00000000`000615d4\r\n001ebfb8  00000000`043f48e0\r\n001ebfc0  00000000`00000002\r\n001ebfc8  00000000`00517050\r\n001ebfd0  00000000`00000010\r\n001ebfd8  00000000`00000000\r\n001ebfe0  00000000`00000005\r\n001ebfe8  00000000`ff6e2b9b ABC!CUIController::UpdateTwoLineDisplay+0x156\r\n001ebff0  00000000`00000002\r\n001ebff8  00000000`005170f0\r\n001ec000  00000000`043f55c0\r\n001ec008  00000000`00510000\r\n001ec010  00000000`00000000\r\n001ec018  00000000`00000000\r\n001ec020  00000000`00000002\r\n001ec028  00000000`005170f0\r\n001ec030  00000000`00000000\r\n001ec038  00000000`00000000\r\n001ec040  00000000`00000002\r\n001ec048  00000000`005170f0\r\n001ec050  00000000`005170f8\r\n001ec058  00000000`ff6e2a94 ABC!CUIController::displayEvent+0xea\r\n001ec060  00000000`00750ed0\r\n001ec070  00000000`00517118\r\n001ec078  00000000`043f5aa0\r\n001ec080  00000000`005170f8\r\n001ec088  00000000`ff6e2f70 ABC!CEventRegistry::fire+0x34\r\n001ec090  00000000`00518090\r\n001ec098  00000000`00517118\r\n001ec0a0  00000000`043f5aa0\r\n001ec0a8  00000000`0000000e\r\n001ec0b0  00000000`00000000\r\n001ec0b8  00000000`00000000\r\n001ec0c0  00000000`043f2f00\r\n001ec0c8  00000000`ff6e2eef ABC!CCalculatorState::storeAndFire+0x126\r\n001ec0d0  00000000`043f5aa0\r\n001ec0d8  00000000`00000000\r\n001ec0e0  00000000`001ec180\r\n001ec0e8  00000000`00000000\r\n<\/pre>\n<p>(Note that this dump shows addresses increasing <i>downward<\/i>, whereas the previous diagram had them increasing <i>upward<\/i>. Being able to read stack dumps comfortably in both directions is one of those skills you develop as you gain experience.)<\/p>\n<p>There is no frame pointer chain here to help you see if what you found is a call frame. You just have to use your intuition based on the function names. For example, it sounds perfectly reasonable for <code>operator new[]<\/code> to call <code>Rtl\u00adAllocate\u00adHeap<\/code> (to allocate memory), but <code>DoesUserPreferMetric\u00adUnits<\/code> is probably not going to call <code>operator new[]<\/code>.<\/p>\n<p>Some disassembling around of candidate return addresses suggests that the <code>DoesUserPreferMetric\u00adUnits<\/code> is the one likely to have jumped into space, because it is calling through a function pointer variable, whereas the other candidate return addresses used a direct call (or a call to an import table entry, which is unlikely to be invalid).<\/p>\n<p>How do we reconstruct the stack based on this assumption? You trick the debugger into thinking that execution stopped inside the <code>DoesUserPreferMetric\u00adUnits<\/code> just before or after the fateful jump. It&#8217;s easier to do &#8220;just after&#8221;, since that&#8217;s just the return address. We&#8217;re going to pretend that instead of jumping into space, we jumped to a <code>ret<\/code> instruction.<\/p>\n<p>Since we don&#8217;t know what the junk code did before it finally crashed, the current value of <code>rsp<\/code> is probably not accurate. We&#8217;ll have to think backward to a point in time whose stack pointer we can infer, and then replay the code forward.<\/p>\n<p>From our knowledge of stack frames, we see that the <code>rsp<\/code> register had the value <code>001ebfb0<\/code> during the execution of <code>DoesUserPreferMetric\u00adUnits<\/code> just before it called the bad function pointer. Let&#8217;s temporarily set our <code>rsp<\/code> and <code>rip<\/code> to simulate the return from the function.<\/p>\n<pre>0:000&gt; r rsp=1ebfb0\r\n0:000&gt; r rip=ff6e28ae \r\n0:000&gt; k\r\nChild-SP          RetAddr           Call Site\r\n00000000`001ebfb0 00000000`ff6e2b9b ABC!DoesUserPreferMetricUnits+0x2a\r\n00000000`001ebff0 00000000`ff6e2a94 ABC!CUIController::UpdateDisplay+0x156\r\n00000000`001ec060 00000000`ff6e2f70 ABC!CUIController::displayEvent+0xea\r\n00000000`001ec090 00000000`ff6e2eef ABC!CEventRouter::fire+0x34\r\n00000000`001ec0d0 00000000`ff6e3469 ABC!CEngineState::storeAndFire+0x126\r\n00000000`001ec110 00000000`ff6e4149 ABC!CEngine::SetDisplayText+0x39\r\n00000000`001ec140 00000000`ff6ea48d ABC!CEngine::DisplayResult+0x648\r\n00000000`001ec3c0 00000000`ff6e49c6 ABC!CEngine::ProcessCommandWorker+0xa1a\r\n00000000`001ec530 00000000`ff6e4938 ABC!CEngine::ProcessCommand+0x2a\r\n00000000`001ec560 00000000`ff6e460a ABC!CUIController::ProcessInput+0xaa\r\n00000000`001ec5a0 00000000`ff6e4744 ABC!CContainer::ProcessInputs+0x7a1\r\n00000000`001ec700 00000000`77a6c3c1 ABC!CContainer::WndProc+0xa12\r\n00000000`001ecbe0 00000000`77a6a6d8 USER32!UserCallWinProcCheckWow+0x1ad\r\n00000000`001ecca0 00000000`77a6a85d USER32!SendMessageWorker+0x682\r\n00000000`001ecd30 00000000`ff70c5d8 USER32!SendMessageW+0x5c\r\n00000000`001ecd80 00000000`77a5e53b ABC!CMainDlgFrame::MainDlgProc+0x87\r\n00000000`001ecdc0 00000000`77a5e2f2 USER32!UserCallDlgProcCheckWow+0x1b6\r\n00000000`001ece80 00000000`77a5e222 USER32!DefDlgProcWorker+0xf1\r\n00000000`001ecf00 00000000`77a6c3c1 USER32!DefDlgProcW+0x36\r\n00000000`001ecf40 00000000`77a6a6d8 USER32!UserCallWinProcCheckWow+0x1ad\r\n00000000`001ed000 00000000`77a6a85d USER32!SendMessageWorker+0x682\r\n00000000`001ed090 000007fe`fc890ba3 USER32!SendMessageW+0x5c\r\n00000000`001ed0e0 000007fe`fc8947e2 COMCTL32!Button_ReleaseCapture+0x157\r\n00000000`001ed120 00000000`77a6c3c1 COMCTL32!Button_WndProc+0xcde\r\n00000000`001ed1e0 00000000`77a6c60a USER32!UserCallWinProcCheckWow+0x1ad\r\n00000000`001ed2a0 00000000`ff6e1a76 USER32!DispatchMessageWorker+0x3b5\r\n00000000`001ed320 00000000`ff6fa00f ABC!WinMain+0x1db4\r\n00000000`001efa10 00000000`7794f33d ABC!__mainCRTStartup+0x18e\r\n00000000`001efad0 00000000`77b82ca1 kernel32!BaseThreadInitThunk+0xd\r\n00000000`001efb00 00000000`00000000 ntdll!RtlUserThreadStart+0x1d\r\n0:000&gt; r rsp=001ebf68\r\n0:000&gt; r rip=ff6ebaad\r\n<\/pre>\n<p>After getting what we want, we restore the registers to their original values at the time of the crash so that future investigation won&#8217;t be misled by our editing.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>No threading, just return addresses.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-3303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>No threading, just return addresses.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=3303"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/3303\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=3303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=3303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=3303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}