{"id":96906,"date":"2017-08-30T07:00:00","date_gmt":"2017-08-30T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/?p=96906"},"modified":"2019-03-13T01:16:12","modified_gmt":"2019-03-13T08:16:12","slug":"20170830-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20170830-00\/?p=96906","title":{"rendered":"The Alpha AXP, part 17: Reconstructing a call stack"},"content":{"rendered":"<p>I&#8217;m going to wrap up the formal part of the series by applying the information we&#8217;ve been learning over the past several <del>days<\/del> weeks: We&#8217;re going to reconstruct a broken stack. <\/p>\n<p>Suppose you have a debug session where all the <code>k<\/code> command says is <\/p>\n<pre>\nCallee-SP Return-RA  Call Site\n 0235d380 777b63e4 : contoso!OnSysColorChange+<u>0x60<\/u>\n<\/pre>\n<p>That&#8217;s it. We&#8217;ll have to unwind the stack manually. We need to keep track of the stack pointer depth and watch where the compiler stashed the return address. We can do this by going forward or backward. I&#8217;ll demonstrate both. <\/p>\n<p>Let&#8217;s go backward:<\/p>\n<pre>\nkd&gt; u .-<b>60<\/b>\ncontoso!OnSysColorChange:\n777b6380 : 23deffe0 lda    <u>sp,-20(sp)<\/u>\n777b6384 : b53e0000 stq    s0,0(sp)\n777b6388 : b55e0008 stq    s1,8(sp)\n777b638c : b75e0010 stq    <u>ra,10(sp)<\/u>\n<\/pre>\n<p>From the function prologue, we see that it allocates <code>0x20<\/code> bytes of stack and puts the return address at offset <code>0x10<\/code>. So we can pull the first return address right away: <\/p>\n<pre>\nkd&gt; dd @sp+<b>10<\/b> L1\n0235d390  <u>7773b4e8<\/u>\n<\/pre>\n<p>Since our local stack frame is <code>0x20<\/code> bytes, that means that the caller&#8217;s stack begins at <code>@sp + 20<\/code>. Let&#8217;s look at the caller. <\/p>\n<pre>\nkd&gt; u <b>7773b4e8<\/b>\ncontoso!WndProc+1f58:\n7773b4e8 : a20b0040 ldl    a0,40(s2)\n7773b4ec : 47ef0411 bis    zero,fp,a1\n7773b4f0 : 47ed0412 bis    zero,s4,a2\n7773b4f4 : 47ec0413 bis    zero,s3,a3\n7773b4f8 : e61ff989 beq    a0,0000000077739b20 contoso!WndProc+590\n7773b4fc : d3407858 bsr    ra,0000000077759660 contoso!ForwardMessage\n7773b500 : 47ff0400 bis    zero,zero,v0\n7773b504 : c3e00122 br     zero,<u>000000007773b990<\/u> contoso!WndProc+2400\n<\/pre>\n<p>Referring to the source code reveals that the last two lines are a <code>return 0<\/code>, so that last jump goes to the function epilogue. This time, we&#8217;re debugging forward. <\/p>\n<pre>\nkd&gt; u <b>7773b990<\/b>\ncontoso!WndProc+2400:\n7773b990 : a75e0048 ldq    <u>ra,48(sp)<\/u>\n7773b994 : a57e0020 ldq    s2,20(sp)\n7773b998 : a59e0028 ldq    s3,28(sp)\n7773b99c : a5be0030 ldq    s4,30(sp)\n7773b9a0 : a5de0038 ldq    s5,38(sp)\n7773b9a4 : a53e0010 ldq    s0,10(sp)\n7773b9a8 : a55e0018 ldq    s1,18(sp)\n7773b9ac : a5fe0040 ldq    fp,40(sp)\n7773b9b0 : 63ff0000 trapb\n7773b9b4 : 23de01b0 lda    <u>sp,1b0(sp)<\/u>\n7773b9b8 : 6bfa8001 ret    zero,(ra),1  contoso!OnSysColorChange+60\n<\/pre>\n<p>(The disassembler is &#8220;helpfully&#8221; resolving the <code>(ra)<\/code> to <code>contoso!OnSysColorChange+60<\/code>, based on the current value in the <var>ra<\/var> register. It&#8217;s not correct because the <var>ra<\/var> register will certainly change between the current execution point and the <code>ret<\/code>, but we&#8217;ll give the debugger a nice pat on the head for trying.) <\/p>\n<p>By studying the epilogue, we see that the function keeps its return address at offset <code>0x48<\/code>. Since we already had an adjustment of <code>0x20<\/code> from <code>WndProc<\/code>, the combined offset from <code>@sp<\/code> is <\/p>\n<pre>\nkd&gt; dd @sp+<b>20+48<\/b> L1\n0235d3e8  <u>77c9a028<\/u>\n<\/pre>\n<p>And now we just repeat this procedure until we get the full stack trace or we get bored. <\/p>\n<pre>\nkd&gt; u <b>77c9a028<\/b>\nuser32!CallWindowProcAorW+1d8:\n77c9a028 : b01e0040 stl    v0,40(sp)\n77c9a02c : 43e00000 addl   zero,v0,v0\n77c9a030 : a75e0030 ldq    <u>ra,30(sp)<\/u>\n77c9a034 : a53e0008 ldq    s0,8(sp)\n77c9a038 : a55e0010 ldq    s1,10(sp)\n77c9a03c : a57e0018 ldq    s2,18(sp)\n77c9a040 : a59e0020 ldq    s3,20(sp)\n77c9a044 : a5be0028 ldq    s4,28(sp)\n77c9a048 : 23de0060 lda    <u>sp,60(sp)<\/u>\n77c9a04c : 6bfa8001 ret    zero,(ra),1  contoso!OnSysColorChange+60\nkd&gt; dd @sp+<b>20+1b0+30<\/b> l1\n0235d580  <u>77cb64c0<\/u>\nkd&gt; u <b>77cb64c0<\/b>\nuser32!CallWindowProcW+10:\n77cb64c0 : a75e0000 ldq    <u>ra,0(sp)<\/u>\n77cb64c4 : 23de0010 lda    <u>sp,10(sp)<\/u>\n77cb64c8 : 6bfa8001 ret    zero,(ra),1  contoso!OnSysColorChange+60\nkd&gt; dd @sp+<b>20+1b0+60+0<\/b> l1\n0235d5b0  777a7c04\n<\/pre>\n<p>So we have successfully reconstructed this call stack: <\/p>\n<pre>\ncontoso!OnSysColorChange+0x60\ncontoso!WndProc+1f58\nuser32!CallWindowProcAorW+1d8\nuser32!CallWindowProcW+10\n<\/pre>\n<p>Lather, rinse, repeat. (In this particular case, I needed to go back around 20 stack frames in order to find out why the <code>WM_<\/code><code>SYS&shy;COLOR&shy;CHANGE<\/code> message was coming in at such a strange time.) <\/p>\n<p>That concludes our rather lengthy whirlwind tour of the Alpha AXP processor. Maybe you found it interesting, maybe not, but there you have it. <\/p>\n<p>Next up is the MIPS R4000. But I don&#8217;t do it right now, since you&#8217;re probably all tired of this CPU architecture stuff. I&#8217;ll wait a while and then spring it on you when you least expect it. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Putting the information into practice.<\/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":[25],"class_list":["post-96906","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Putting the information into practice.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96906","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=96906"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/96906\/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=96906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=96906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=96906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}