[PATCH 1/4] [WineDbg]: now storing the CONTEXT in each stack frame to enable register access in the non topmost frames

Eric Pouech eric.pouech at orange.fr
Tue Mar 30 14:37:01 CDT 2010




A+
---

 programs/winedbg/debugger.h     |    6 +++-
 programs/winedbg/memory.c       |   11 ++------
 programs/winedbg/stack.c        |   53 +++++++++++++++++++++++++++++++++------
 programs/winedbg/tgt_active.c   |    2 +
 programs/winedbg/tgt_minidump.c |    2 +
 5 files changed, 54 insertions(+), 20 deletions(-)


diff --git a/programs/winedbg/debugger.h b/programs/winedbg/debugger.h
index 373600a..9d9c1b2 100644
--- a/programs/winedbg/debugger.h
+++ b/programs/winedbg/debugger.h
@@ -192,6 +192,8 @@ struct dbg_thread
         DWORD_PTR               linear_pc;
         DWORD_PTR               linear_frame;
         DWORD_PTR               linear_stack;
+        CONTEXT                 context;        /* context we got out of stackwalk for this frame */
+        BOOL                    is_ctx_valid;   /* is the context above valid */
     }*                          frames;
     int                         num_frames;
     int                         curr_frame;
@@ -387,8 +389,8 @@ extern void             stack_info(void);
 extern void             stack_backtrace(DWORD threadID);
 extern BOOL             stack_set_frame(int newframe);
 extern BOOL             stack_get_current_frame(IMAGEHLP_STACK_FRAME* ihsf);
-extern BOOL             stack_get_register_current_frame(unsigned regno, DWORD_PTR** pval);
-extern unsigned         stack_fetch_frames(void);
+extern BOOL             stack_get_register_frame(const struct dbg_internal_var* div, DWORD_PTR** pval);
+extern unsigned         stack_fetch_frames(const CONTEXT* ctx);
 extern BOOL             stack_get_current_symbol(SYMBOL_INFO* sym);
 
   /* symbol.c */
diff --git a/programs/winedbg/memory.c b/programs/winedbg/memory.c
index 2b17dab..76a103a 100644
--- a/programs/winedbg/memory.c
+++ b/programs/winedbg/memory.c
@@ -694,16 +694,11 @@ BOOL memory_get_register(DWORD regno, DWORD_PTR** value, char* buffer, int len)
     {
         if (div->val == regno)
         {
-            if (dbg_curr_thread->curr_frame != 0)
+            if (!stack_get_register_frame(div, value))
             {
-                if (!stack_get_register_current_frame(regno, value))
-                {
-                    if (buffer) snprintf(buffer, len, "<register %s not in topmost frame>", div->name);
-                    return FALSE;
-                }
+                if (buffer) snprintf(buffer, len, "<register %s not accessible in this frame>", div->name);
+                return FALSE;
             }
-            else
-                *value = (DWORD_PTR*)((char*)&dbg_context + (DWORD_PTR)div->pval);
 
             if (buffer) lstrcpynA(buffer, div->name, len);
             return TRUE;
diff --git a/programs/winedbg/stack.c b/programs/winedbg/stack.c
index 40e6dae..f5769a8 100644
--- a/programs/winedbg/stack.c
+++ b/programs/winedbg/stack.c
@@ -119,6 +119,35 @@ BOOL stack_get_register_current_frame(unsigned regno, DWORD_PTR** pval)
     return TRUE;
 }
 
+BOOL stack_get_register_frame(const struct dbg_internal_var* div, DWORD_PTR** pval)
+{
+    if (dbg_curr_thread->frames == NULL) return FALSE;
+    if (dbg_curr_thread->frames[dbg_curr_thread->curr_frame].is_ctx_valid)
+        *pval = (DWORD_PTR*)((char*)&dbg_curr_thread->frames[dbg_curr_thread->curr_frame].context +
+                             (DWORD_PTR)div->pval);
+    else
+    {
+        enum be_cpu_addr        kind;
+
+        if (!be_cpu->get_register_info(div->val, &kind)) return FALSE;
+
+        /* reuse some known registers directly out of stackwalk details */
+        switch (kind)
+        {
+        case be_cpu_addr_pc:
+            *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_pc;
+            break;
+        case be_cpu_addr_stack:
+            *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_stack;
+            break;
+        case be_cpu_addr_frame:
+            *pval = &dbg_curr_thread->frames[dbg_curr_thread->curr_frame].linear_frame;
+            break;
+        }
+    }
+    return TRUE;
+}
+
 BOOL stack_set_frame(int newframe)
 {
     ADDRESS64   addr;
@@ -163,14 +192,14 @@ static BOOL CALLBACK stack_read_mem(HANDLE hProc, DWORD64 addr,
  *
  * Do a backtrace on the current thread
  */
-unsigned stack_fetch_frames(void)
+unsigned stack_fetch_frames(const CONTEXT* _ctx)
 {
     STACKFRAME64 sf;
     unsigned     nf = 0;
     /* as native stackwalk can modify the context passed to it, simply copy
      * it to avoid any damage
      */
-    CONTEXT      ctx = dbg_context;
+    CONTEXT      ctx = *_ctx, prevctx = ctx;
 
     HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames);
     dbg_curr_thread->frames = NULL;
@@ -200,6 +229,15 @@ unsigned stack_fetch_frames(void)
         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;
+        /* 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...
+         */
+        dbg_curr_thread->frames[nf].is_ctx_valid =
+            (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;
@@ -317,27 +355,26 @@ static void backtrace_tid(struct dbg_process* pcs, DWORD tid)
         dbg_printf("Unknown thread id (%04x) in process (%04x)\n", tid, pcs->pid);
     else
     {
-        CONTEXT saved_ctx = dbg_context;
+        CONTEXT context;
 
         dbg_curr_tid = dbg_curr_thread->tid;
-        memset(&dbg_context, 0, sizeof(dbg_context));
-        dbg_context.ContextFlags = CONTEXT_FULL;
+        memset(&context, 0, sizeof(context));
+        context.ContextFlags = CONTEXT_FULL;
         if (SuspendThread(dbg_curr_thread->handle) != -1)
         {
-            if (!GetThreadContext(dbg_curr_thread->handle, &dbg_context))
+            if (!GetThreadContext(dbg_curr_thread->handle, &context))
             {
                 dbg_printf("Can't get context for thread %04x in current process\n",
                            tid);
             }
             else
             {
-                stack_fetch_frames();
+                stack_fetch_frames(&context);
                 backtrace();
             }
             ResumeThread(dbg_curr_thread->handle);
         }
         else dbg_printf("Can't suspend thread %04x in current process\n", tid);
-        dbg_context = saved_ctx;
     }
     dbg_curr_thread = thread;
     dbg_curr_tid = thread ? thread->tid : 0;
diff --git a/programs/winedbg/tgt_active.c b/programs/winedbg/tgt_active.c
index cbcc297..c612615 100644
--- a/programs/winedbg/tgt_active.c
+++ b/programs/winedbg/tgt_active.c
@@ -157,7 +157,7 @@ static unsigned dbg_exception_prolog(BOOL is_debug, BOOL first_chance, const EXC
      * Do a quiet backtrace so that we have an idea of what the situation
      * is WRT the source files.
      */
-    stack_fetch_frames();
+    stack_fetch_frames(&dbg_context);
 
     if (is_debug && !is_break && break_should_continue(&addr, rec->ExceptionCode))
 	return FALSE;
diff --git a/programs/winedbg/tgt_minidump.c b/programs/winedbg/tgt_minidump.c
index 7826b78..a4a1af7 100644
--- a/programs/winedbg/tgt_minidump.c
+++ b/programs/winedbg/tgt_minidump.c
@@ -376,7 +376,7 @@ static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data)
             memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva,
                    min(sizeof(dbg_context), mes->ThreadContext.DataSize));
             memory_get_current_pc(&addr);
-            stack_fetch_frames();
+            stack_fetch_frames(&dbg_context);
             be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0);
             stack_info();
             be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);






More information about the wine-patches mailing list