[PATCH 04/11] [DbgHelp]: when doing a stack backtrace on i386 with dwarf or pdb unwinders, get the PC from the right frame

Eric Pouech eric.pouech at orange.fr
Sun Mar 13 15:30:40 CDT 2011


(and fix winedbg accordingly)

A+
---

 dlls/dbghelp/cpu_i386.c  |  159 +++++++++++++++++++++++-----------------------
 programs/winedbg/stack.c |    5 +
 2 files changed, 81 insertions(+), 83 deletions(-)


diff --git a/dlls/dbghelp/cpu_i386.c b/dlls/dbghelp/cpu_i386.c
index 817033b..03d53b3 100644
--- a/dlls/dbghelp/cpu_i386.c
+++ b/dlls/dbghelp/cpu_i386.c
@@ -87,6 +87,51 @@ static unsigned i386_get_addr(HANDLE hThread, const CONTEXT* ctx,
     return FALSE;
 }
 
+#ifdef __i386__
+/* fetch_next_frame32()
+ *
+ * modify (at least) context.{eip, esp, ebp} using unwind information
+ * either out of debug info (dwarf, pdb), or simple stack unwind
+ */
+static BOOL fetch_next_frame32(struct cpu_stack_walk* csw,
+                               CONTEXT* context, DWORD_PTR curr_pc)
+{
+    DWORD_PTR               xframe;
+    struct pdb_cmd_pair     cpair[4];
+    DWORD                   val32;
+
+    if (dwarf2_virtual_unwind(csw, curr_pc, context, &xframe))
+    {
+        context->Esp = xframe;
+        return TRUE;
+    }
+    cpair[0].name = "$ebp";      cpair[0].pvalue = &context->Ebp;
+    cpair[1].name = "$esp";      cpair[1].pvalue = &context->Esp;
+    cpair[2].name = "$eip";      cpair[2].pvalue = &context->Eip;
+    cpair[3].name = NULL;        cpair[3].pvalue = NULL;
+
+    if (!pdb_virtual_unwind(csw, curr_pc, context, cpair))
+    {
+        /* do a simple unwind using ebp
+         * we assume a "regular" prologue in the function has been used
+         */
+        context->Esp = context->Ebp + 2 * sizeof(DWORD);
+        if (!sw_read_mem(csw, context->Ebp + sizeof(DWORD), &val32, sizeof(DWORD)))
+        {
+            WARN("Cannot read new frame offset %p\n",
+                 (void*)(DWORD_PTR)(context->Ebp + (int)sizeof(DWORD)));
+            return FALSE;
+        }
+        context->Eip = val32;
+        /* "pop up" previous EBP value */
+        if (!sw_read_mem(csw, context->Ebp, &val32, sizeof(DWORD)))
+            return FALSE;
+        context->Ebp = val32;
+    }
+    return TRUE;
+}
+#endif
+
 enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};
 
 /* indexes in Reserved array */
@@ -197,7 +242,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
                     goto done_err;
                 }
                 curr_switch = (DWORD_PTR)frame16.frame32;
-
                 if (!sw_read_mem(csw, curr_switch, &ch, sizeof(ch)))
                     curr_switch = 0xFFFFFFFF;
             }
@@ -212,32 +256,6 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
          * we will get it in the next frame
          */
         memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
-#ifdef __i386__
-        if (curr_mode == stm_32bit)
-        {
-            DWORD_PTR           xframe;
-            struct pdb_cmd_pair cpair[4];
-            CONTEXT             newctx = *context;
-
-            if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, &newctx, &xframe))
-            {
-                frame->AddrReturn.Mode = AddrModeFlat;
-                frame->AddrReturn.Offset = newctx.Eip;
-                goto done_pep;
-            }
-            cpair[0].name = "$ebp";      cpair[0].pvalue = &newctx.Ebp;
-            cpair[1].name = "$esp";      cpair[1].pvalue = &newctx.Esp;
-            cpair[2].name = "$eip";      cpair[2].pvalue = &newctx.Eip;
-            cpair[3].name = NULL;        cpair[3].pvalue = NULL;
-
-            if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, &newctx, cpair))
-            {
-                frame->AddrReturn.Mode = AddrModeFlat;
-                frame->AddrReturn.Offset = newctx.Eip;
-                goto done_pep;
-            }
-        }
-#endif
     }
     else
     {
@@ -352,9 +370,9 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
         }
         else
         {
-            frame->AddrPC = frame->AddrReturn;
             if (curr_mode == stm_16bit)
             {
+                frame->AddrPC = frame->AddrReturn;
                 frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
                 /* "pop up" previous BP value */
                 if (!sw_read_mem(csw, sw_xlat_addr(csw, &frame->AddrFrame),
@@ -365,36 +383,17 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
             else
             {
 #ifdef __i386__
-                DWORD_PTR               xframe;
-                struct pdb_cmd_pair     cpair[4];
-
-                if (dwarf2_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, &xframe))
-                {
-                    frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
-                    frame->AddrStack.Offset = context->Esp = xframe;
-                    frame->AddrFrame.Offset = context->Ebp;
-                    frame->AddrReturn.Offset = context->Eip;
-                    goto done_pep;
-                }
-                cpair[0].name = "$ebp"; cpair[0].pvalue = &context->Ebp;
-                cpair[1].name = "$esp"; cpair[1].pvalue = &context->Esp;
-                cpair[2].name = "$eip"; cpair[2].pvalue = &context->Eip;
-                cpair[3].name = NULL;   cpair[3].pvalue = NULL;
+                if (!fetch_next_frame32(csw, context, sw_xlat_addr(csw, &frame->AddrPC) - deltapc))
+                    goto done_err;
 
-                if (pdb_virtual_unwind(csw, frame->AddrPC.Offset - deltapc, context, cpair))
-                {
-                    frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrReturn.Mode = AddrModeFlat;
-                    frame->AddrStack.Offset = context->Esp;
-                    frame->AddrFrame.Offset = context->Ebp;
-                    frame->AddrReturn.Offset = context->Eip;
-                    goto done_pep;
-                }
+                frame->AddrStack.Mode = frame->AddrFrame.Mode = frame->AddrPC.Mode = AddrModeFlat;
+                frame->AddrStack.Offset = context->Esp;
+                frame->AddrFrame.Offset = context->Ebp;
+                if (frame->AddrReturn.Offset != context->Eip)
+                    FIXME("new PC=%s different from Eip=%x\n",
+                          wine_dbgstr_longlong(frame->AddrReturn.Offset), context->Eip);
+                frame->AddrPC.Offset = context->Eip;
 #endif
-                frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
-                /* "pop up" previous EBP value */
-                if (!sw_read_mem(csw, frame->AddrFrame.Offset, &val32, sizeof(DWORD)))
-                    goto done_err;
-                frame->AddrFrame.Offset = val32;
             }
         }
     }
@@ -441,40 +440,40 @@ static BOOL i386_stack_walk(struct cpu_stack_walk* csw, LPSTACKFRAME64 frame, CO
             sw_read_mem(csw, p + (2 + i) * sizeof(WORD), &val16, sizeof(val16));
             frame->Params[i] = val16;
         }
+#ifdef __i386__
+        if (context)
+        {
+#define SET(field, seg, reg) \
+            switch (frame->field.Mode) \
+            { \
+            case AddrModeFlat: context->reg = frame->field.Offset; break; \
+            case AddrMode1616: context->seg = frame->field.Segment; context->reg = frame->field.Offset; break; \
+            default: assert(0); \
+            }
+            SET(AddrStack,  SegSs, Esp);
+            SET(AddrFrame,  SegSs, Ebp);
+            SET(AddrReturn, SegCs, Eip);
+#undef SET
+        }
+#endif
     }
     else
     {
-        unsigned int     i;
-        if (!sw_read_mem(csw, frame->AddrFrame.Offset + sizeof(DWORD), &val32, sizeof(DWORD)))
-        {
-            WARN("Cannot read new frame offset %p\n",
-                 (void*)(DWORD_PTR)(frame->AddrFrame.Offset + (int)sizeof(DWORD)));
+        unsigned int    i;
+#ifdef __i386__
+        CONTEXT         newctx = *context;
+
+        if (!fetch_next_frame32(csw, &newctx, frame->AddrPC.Offset - deltapc))
             goto done_err;
-        }
-        frame->AddrReturn.Offset = val32;
+        frame->AddrReturn.Mode = AddrModeFlat;
+        frame->AddrReturn.Offset = newctx.Eip;
+#endif
         for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
         {
             sw_read_mem(csw, frame->AddrFrame.Offset + (2 + i) * sizeof(DWORD), &val32, sizeof(val32));
             frame->Params[i] = val32;
         }
     }
-#ifdef __i386__
-    if (context)
-    {
-#define SET(field, seg, reg) \
-        switch (frame->field.Mode) \
-        { \
-        case AddrModeFlat: context->reg = frame->field.Offset; break; \
-        case AddrMode1616: context->seg = frame->field.Segment; context->reg = frame->field.Offset; break; \
-        default: assert(0); \
-        }
-        SET(AddrStack,  SegSs, Esp);
-        SET(AddrFrame,  SegSs, Ebp);
-        SET(AddrReturn, SegCs, Eip);
-#undef SET
-    }
-done_pep:
-#endif
 
     frame->Far = TRUE;
     frame->Virtual = TRUE;
diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c
index 57eca5c..a291c61 100644
--- a/programs/winedbg/stack.c
+++ b/programs/winedbg/stack.c
@@ -214,7 +214,7 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
     /* as native stackwalk can modify the context passed to it, simply copy
      * it to avoid any damage
      */
-    CONTEXT      ctx = *_ctx, prevctx = ctx;
+    CONTEXT      ctx = *_ctx;
 
     HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames);
     dbg_curr_thread->frames = NULL;
@@ -244,7 +244,7 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
         dbg_curr_thread->frames[nf].linear_frame = (DWORD_PTR)memory_to_linear_addr(&sf.AddrFrame);
         dbg_curr_thread->frames[nf].addr_stack   = sf.AddrStack;
         dbg_curr_thread->frames[nf].linear_stack = (DWORD_PTR)memory_to_linear_addr(&sf.AddrStack);
-        dbg_curr_thread->frames[nf].context      = prevctx;
+        dbg_curr_thread->frames[nf].context      = ctx;
         /* FIXME: can this heuristic be improved: we declare first context always valid, and next ones
          * if it has been modified by the call to StackWalk...
          */
@@ -252,7 +252,6 @@ unsigned stack_fetch_frames(const CONTEXT* _ctx)
             (nf == 0 ||
              (dbg_curr_thread->frames[nf - 1].is_ctx_valid &&
               memcmp(&dbg_curr_thread->frames[nf - 1].context, &ctx, sizeof(ctx))));
-        prevctx = ctx;
         nf++;
         /* we've probably gotten ourselves into an infinite loop so bail */
         if (nf > 200) break;




More information about the wine-patches mailing list