debugger enhancement

eric pouech eric.pouech at wanadoo.fr
Sat Aug 4 15:42:25 CDT 2001


upon François' request, this patch extends the bt command to also
display the stack state of another (attached) thread
it also enhances a bit the walk thread command with a better display

A+
-- 
---------------
Eric Pouech (http://perso.wanadoo.fr/eric.pouech/)
"The future will be better tomorrow", Vice President Dan Quayle
-------------- next part --------------
Name: winedbg_bt_tid
ChangeLog: extended bt command to display backtrace of another thread
	enhanced process & thread display with process' name
GenDate: 2001/08/04 20:34:36 UTC
ModifiedFiles: debugger/dbg.y debugger/debugger.h debugger/info.c debugger/stack.c debugger/winedbg.c documentation/debugger.sgml
AddedFiles: 
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/debugger/dbg.y,v
retrieving revision 1.44
diff -u -u -r1.44 dbg.y
--- debugger/dbg.y	2001/07/11 17:33:08	1.44
+++ debugger/dbg.y	2001/08/03 07:44:05
@@ -120,7 +120,8 @@
     | tENABLE tNUM tEOL        	{ DEBUG_EnableBreakpoint( $2, TRUE ); }
     | tDISABLE tNUM tEOL       	{ DEBUG_EnableBreakpoint( $2, FALSE ); }
     | tDELETE tBREAK tNUM tEOL 	{ DEBUG_DelBreakpoint( $3 ); }
-    | tBACKTRACE tEOL	       	{ DEBUG_BackTrace(TRUE); }
+    | tBACKTRACE tEOL	       	{ DEBUG_BackTrace(DEBUG_CurrTid, TRUE); }
+    | tBACKTRACE tNUM tEOL     	{ DEBUG_BackTrace($2, TRUE); }
     | tUP tEOL		       	{ DEBUG_SetFrame( curr_frame + 1 );  }
     | tUP tNUM tEOL	       	{ DEBUG_SetFrame( curr_frame + $2 ); }
     | tDOWN tEOL	       	{ DEBUG_SetFrame( curr_frame - 1 );  }
Index: debugger/debugger.h
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/debugger/debugger.h,v
retrieving revision 1.23
diff -u -u -r1.23 debugger.h
--- debugger/debugger.h	2001/07/23 00:04:00	1.23
+++ debugger/debugger.h	2001/08/04 19:37:40
@@ -191,6 +191,7 @@
 typedef struct tagDBG_PROCESS {
     HANDLE			handle;
     DWORD			pid;
+    const char*			imageName;
     DBG_THREAD*			threads;
     int				num_threads;
     unsigned			continue_on_first_exception;
@@ -434,7 +435,7 @@
 
   /* debugger/stack.c */
 extern void DEBUG_InfoStack(void);
-extern void DEBUG_BackTrace(BOOL noisy);
+extern void DEBUG_BackTrace(DWORD threadID, BOOL noisy);
 extern int  DEBUG_InfoLocals(void);
 extern int  DEBUG_SetFrame(int newframe);
 extern int  DEBUG_GetCurrentFrame(struct name_hash ** name, 
@@ -493,6 +494,8 @@
 extern DBG_INTVAR*	DEBUG_GetIntVar(const char*);
 extern BOOL DEBUG_Attach(DWORD pid, BOOL cofe);
 extern void DEBUG_Run(const char* args);
+extern DBG_PROCESS* 	DEBUG_GetProcess(DWORD pid);
+extern DBG_THREAD* 	DEBUG_GetThread(DBG_PROCESS* p, DWORD tid);
 extern int curr_frame;
 
 /* Choose your allocator! */
Index: debugger/info.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/debugger/info.c,v
retrieving revision 1.19
diff -u -u -r1.19 info.c
--- debugger/info.c	2001/07/23 00:04:00	1.19
+++ debugger/info.c	2001/08/04 19:42:24
@@ -466,23 +466,39 @@
     HANDLE snap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 );
     if (snap != INVALID_HANDLE_VALUE)
     {
-        THREADENTRY32 entry;
-        DWORD current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
-        BOOL ok;
+        THREADENTRY32	entry;
+        DWORD 		current = DEBUG_CurrThread ? DEBUG_CurrThread->tid : 0;
+        BOOL 		ok;
+	DWORD		lastProcessId = 0;
 
-		  entry.dwSize = sizeof(entry);
-		  ok = Thread32First( snap, &entry );
+	entry.dwSize = sizeof(entry);
+	ok = Thread32First( snap, &entry );
 
-        DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n",
-                     "tid", "process", "prio" );
+        DEBUG_Printf(DBG_CHN_MESG, "%-8.8s %-8.8s %s\n", "process", "tid", "prio" );
         while (ok)
         {
             if (entry.th32OwnerProcessID != GetCurrentProcessId())
-                DEBUG_Printf(DBG_CHN_MESG, "%08lx %08lx %4ld%s\n",
-                             entry.th32ThreadID, entry.th32OwnerProcessID,
-                             entry.tpBasePri, (entry.th32ThreadID == current) ? " <==" : "" );
+	    {
+		/* FIXME: this assumes that, in the snapshot, all threads of a same process are
+		 * listed sequentially, which is not specified in the doc (Wine's implementation
+		 * does it)
+		 */
+		if (entry.th32OwnerProcessID != lastProcessId)
+		{
+		    DBG_PROCESS*	p = DEBUG_GetProcess(entry.th32OwnerProcessID);
+
+		    DEBUG_Printf(DBG_CHN_MESG, "%08lx%s %s\n", 
+				 entry.th32OwnerProcessID,  p ? " (D)" : "", p ? p->imageName : "");
+		    lastProcessId = entry.th32OwnerProcessID;
+		}
+                DEBUG_Printf(DBG_CHN_MESG, "\t%08lx %4ld%s\n",
+                             entry.th32ThreadID, entry.tpBasePri, 
+			     (entry.th32ThreadID == current) ? " <==" : "");
+
+	    }
             ok = Thread32Next( snap, &entry );
         }
+
         CloseHandle( snap );
     }
 }
Index: debugger/stack.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/debugger/stack.c,v
retrieving revision 1.25
diff -u -u -r1.25 stack.c
--- debugger/stack.c	2000/10/02 22:17:07	1.25
+++ debugger/stack.c	2001/08/03 08:22:17
@@ -106,7 +106,7 @@
     }
 }
 
-static BOOL DEBUG_Frame16(DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
+static BOOL DEBUG_Frame16(DBG_THREAD* thread, DBG_ADDR *addr, unsigned int *cs, int frameno, int noisy)
 {
     unsigned int	possible_cs = 0;
     FRAME16 		frame;
@@ -128,7 +128,7 @@
         if (((frame.cs&7)==7) && (frame.cs != *cs)) {
 	    LDT_ENTRY	le;
 	 
-	    if (GetThreadSelectorEntry( DEBUG_CurrThread->handle, frame.cs, &le) &&
+	    if (GetThreadSelectorEntry( thread->handle, frame.cs, &le) &&
 		(le.HighWord.Bits.Type & 0x08)) { /* code segment */
 	        /* it is very uncommon to push a code segment cs as
 		 * a parameter, so this should work in most cases */
@@ -174,25 +174,64 @@
  *
  * Display a stack back-trace.
  */
-void DEBUG_BackTrace(BOOL noisy)
+void DEBUG_BackTrace(DWORD tid, BOOL noisy)
 {
 #ifdef __i386
     DBG_ADDR 		addr, sw_addr, code, tmp;
-    unsigned int 	ss = DEBUG_context.SegSs;
-    unsigned int	cs = DEBUG_context.SegCs;
+    unsigned int 	ss, cs;
     int 		frameno = 0, is16, ok;
     DWORD 		next_switch, cur_switch, p;
     STACK16FRAME       	frame16;
     STACK32FRAME       	frame32;
     char		ch;
+    CONTEXT		ctx;
+    DBG_THREAD*		thread;
 
+    int 		copy_nframe = 0;
+    int			copy_curr_frame = 0;
+    struct bt_info* 	copy_frames = NULL;
+    
     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Backtrace:\n" );
 
+    if (tid == DEBUG_CurrTid)
+    {
+	 ctx = DEBUG_context;
+	 thread = DEBUG_CurrThread;
+
+	 if (frames) DBG_free( frames );
+	 /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
+    }
+    else
+    {
+	 thread = DEBUG_GetThread(DEBUG_CurrProcess, tid);
+
+	 if (!thread)
+	 {
+	      DEBUG_Printf( DBG_CHN_MESG, "Unknown thread id (0x%08lx) in current process\n", tid);
+	      return;
+	 }
+	 memset(&ctx, 0, sizeof(ctx));
+	 ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS;
+
+	 if ( SuspendThread( thread->handle ) == -1 ||
+	      !GetThreadContext( thread->handle, &ctx ))
+	 {
+	      DEBUG_Printf( DBG_CHN_MESG, "Can't get context for thread id (0x%08lx) in current process\n", tid);
+	      return;
+	 }
+	 /* need to avoid trashing stack frame for current thread */
+	 copy_nframe = nframe;
+	 copy_frames = frames;
+	 copy_curr_frame = curr_frame;
+	 curr_frame = 0;
+    }
+
     nframe = 0;
-    if (frames) DBG_free( frames );
-    /* frames = (struct bt_info *) DBG_alloc( sizeof(struct bt_info) ); */
     frames = NULL;
 
+    cs = ctx.SegCs;
+    ss = ctx.SegSs;
+
     if (DEBUG_IsSelectorSystem(ss)) ss = 0;
     if (DEBUG_IsSelectorSystem(cs)) cs = 0;
 
@@ -201,16 +240,16 @@
     {
     case MODE_32:
         code.seg = cs;
-        code.off = DEBUG_context.Eip;
+        code.off = ctx.Eip;
         addr.seg = ss;
-	addr.off = DEBUG_context.Ebp;
+	addr.off = ctx.Ebp;
         DEBUG_ForceFrame( &addr, &code, frameno, MODE_32, noisy, NULL );
         if (!(code.seg || code.off)) {
             /* trying to execute a null pointer... yuck...
              * if it was a call to null, the return EIP should be
              * available at SS:ESP, so let's try to retrieve it */
             tmp.seg = ss;
-            tmp.off = DEBUG_context.Esp;
+            tmp.off = ctx.Esp;
             if (DEBUG_READ_MEM((void *)DEBUG_ToLinear(&tmp), &code.off, sizeof(code.off))) {
                 DEBUG_ForceFrame( &addr, &code, ++frameno, MODE_32, noisy, ", null call assumed" );
             }
@@ -220,9 +259,9 @@
     case MODE_16:
     case MODE_VM86:
         code.seg = cs;
-        code.off = LOWORD(DEBUG_context.Eip);
+        code.off = LOWORD(ctx.Eip);
         addr.seg = ss;
-	addr.off = LOWORD(DEBUG_context.Ebp);
+	addr.off = LOWORD(ctx.Ebp);
         DEBUG_ForceFrame( &addr, &code, frameno, MODE_16, noisy, NULL );
         is16 = TRUE;
 	break;
@@ -234,7 +273,7 @@
     /* cur_switch holds address of curr_stack's field in TEB in debuggee 
      * address space 
      */
-    cur_switch = (DWORD)DEBUG_CurrThread->teb + OFFSET_OF(TEB, cur_stack);
+    cur_switch = (DWORD)thread->teb + OFFSET_OF(TEB, cur_stack);
     if (!DEBUG_READ_MEM((void*)cur_switch, &next_switch, sizeof(next_switch))) {
         if (noisy) DEBUG_Printf( DBG_CHN_MESG, "Can't read TEB:cur_stack\n");
 	return;
@@ -342,11 +381,21 @@
 	   }
 	} else {
 	    /* ordinary stack frame */
-	   ok = is16 ? DEBUG_Frame16( &addr, &cs, ++frameno, noisy)
+	   ok = is16 ? DEBUG_Frame16( thread, &addr, &cs, ++frameno, noisy)
 	      : DEBUG_Frame32( &addr, &cs, ++frameno, noisy);
 	}
     }
     if (noisy) DEBUG_Printf( DBG_CHN_MESG, "\n" );
+
+    if (tid != DEBUG_CurrTid)
+    {
+	 ResumeThread( thread->handle );
+	 /* restore stack frame for current thread */
+	 if (frames) DBG_free( frames );
+	 frames = copy_frames;
+	 nframe = copy_nframe;
+	 curr_frame = copy_curr_frame;
+    }
 #endif
 }
 
Index: debugger/winedbg.c
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/debugger/winedbg.c,v
retrieving revision 1.36
diff -u -u -r1.36 winedbg.c
--- debugger/winedbg.c	2001/07/23 00:04:00	1.36
+++ debugger/winedbg.c	2001/08/04 20:13:18
@@ -126,7 +126,7 @@
     return EXCEPTION_EXECUTE_HANDLER;
 }
 
-static	DBG_PROCESS*	DEBUG_GetProcess(DWORD pid)
+DBG_PROCESS*	DEBUG_GetProcess(DWORD pid)
 {
     DBG_PROCESS*	p;
     
@@ -135,13 +135,14 @@
     return p;
 }
 
-static	DBG_PROCESS*	DEBUG_AddProcess(DWORD pid, HANDLE h)
+static	DBG_PROCESS*	DEBUG_AddProcess(DWORD pid, HANDLE h, const char* imageName)
 {
     DBG_PROCESS*	p = DBG_alloc(sizeof(DBG_PROCESS));
     if (!p)
 	return NULL;
     p->handle = h;
     p->pid = pid;
+    p->imageName = imageName ? DBG_strdup(imageName) : NULL;
     p->threads = NULL;
     p->num_threads = 0;
     p->continue_on_first_exception = FALSE;
@@ -177,6 +178,7 @@
     if (p->next) p->next->prev = p->prev;
     if (p == DEBUG_ProcessList) DEBUG_ProcessList = p->next;
     if (p == DEBUG_CurrProcess) DEBUG_CurrProcess = NULL;
+    DBG_free((char*)p->imageName);
     DBG_free(p);
 }
 
@@ -206,7 +208,7 @@
     return FALSE;
 }
 
-static	DBG_THREAD*	DEBUG_GetThread(DBG_PROCESS* p, DWORD tid)
+DBG_THREAD*	DEBUG_GetThread(DBG_PROCESS* p, DWORD tid)
 {
     DBG_THREAD*	t;
     
@@ -273,7 +275,7 @@
 
 BOOL				DEBUG_Attach(DWORD pid, BOOL cofe)
 {
-    if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0))) return FALSE;
+    if (!(DEBUG_CurrProcess = DEBUG_AddProcess(pid, 0, NULL))) return FALSE;
 
     if (!DebugActiveProcess(pid)) {
         DEBUG_Printf(DBG_CHN_MESG, "Can't attach process %lx: error %ld\n", pid, GetLastError());
@@ -338,7 +340,7 @@
 	 * Do a quiet backtrace so that we have an idea of what the situation
 	 * is WRT the source files.
 	 */
-	DEBUG_BackTrace(FALSE);
+	DEBUG_BackTrace(DEBUG_CurrTid, FALSE);
     } else {
 	/* This is a real crash, dump some info */
 	DEBUG_InfoRegisters();
@@ -351,7 +353,7 @@
 	}
 	DEBUG_InfoSegments(DEBUG_context.SegFs >> 3, 1);
 #endif
-	DEBUG_BackTrace(TRUE);
+	DEBUG_BackTrace(DEBUG_CurrTid, TRUE);
     }
 
     if (!is_debug ||
@@ -624,11 +626,11 @@
 	    DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
                                            de->u.CreateProcessInfo.hProcess, 
                                            de->u.CreateProcessInfo.lpImageName);
-	    
+
 	    /* FIXME unicode ? de->u.CreateProcessInfo.fUnicode */
-	    DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create process %s @%08lx (%ld<%ld>)\n", 
+	    DEBUG_Printf(DBG_CHN_TRACE, "%08lx:%08lx: create process '%s'/%p @%08lx (%ld<%ld>)\n", 
 			 de->dwProcessId, de->dwThreadId, 
-			 buffer,
+			 buffer, de->u.CreateProcessInfo.lpImageName,
 			 (unsigned long)(LPVOID)de->u.CreateProcessInfo.lpStartAddress,
 			 de->u.CreateProcessInfo.dwDebugInfoFileOffset,
 			 de->u.CreateProcessInfo.nDebugInfoSize);
@@ -639,9 +641,13 @@
 		    break;
 		}
 		DEBUG_CurrProcess->handle = de->u.CreateProcessInfo.hProcess;
+		if (DEBUG_CurrProcess->imageName == NULL)
+		    DEBUG_CurrProcess->imageName = DBG_strdup(buffer[0] ? buffer : "<Debugged Process>");
+
 	    } else {
 		DEBUG_CurrProcess = DEBUG_AddProcess(de->dwProcessId,
-						     de->u.CreateProcessInfo.hProcess);
+						     de->u.CreateProcessInfo.hProcess,
+						     buffer[0] ? buffer : "<Debugged Process>");
 		if (DEBUG_CurrProcess == NULL) {
 		    DEBUG_Printf(DBG_CHN_ERR, "Unknown process\n");
 		    break;
@@ -665,11 +671,7 @@
 	    DEBUG_InitCurrProcess();
 	    DEBUG_InitCurrThread();
 
-            DEBUG_ProcessGetStringIndirect(buffer, sizeof(buffer), 
-                                           DEBUG_CurrThread->process->handle, 
-                                           de->u.CreateProcessInfo.lpImageName);
-	    DEBUG_LoadModule32(buffer[0] ? buffer : "<Debugged process>",
-                               de->u.CreateProcessInfo.hFile, 
+	    DEBUG_LoadModule32(DEBUG_CurrProcess->imageName, de->u.CreateProcessInfo.hFile, 
 			       (DWORD)de->u.CreateProcessInfo.lpBaseOfImage);
 
             if (buffer[0])  /* we got a process name */
@@ -825,7 +827,7 @@
 	return FALSE;
     }
     DEBUG_CurrPid = info.dwProcessId;
-    if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0))) return FALSE;
+    if (!(DEBUG_CurrProcess = DEBUG_AddProcess(DEBUG_CurrPid, 0, NULL))) return FALSE;
 
     return TRUE;
 }
@@ -859,7 +861,7 @@
     DEBUG_InitTypes();
     DEBUG_InitCVDataTypes();    
 
-    /* Initialize internal vars (types must be initialized before) */
+    /* Initialize internal vars (types must have been initialized before) */
     if (!DEBUG_IntVarsRW(TRUE)) return -1;
 
     /* keep it as a guiexe for now, so that Wine won't touch the Unix stdin, 
@@ -881,8 +883,6 @@
 
 	if ((pid = atoi(argv[1])) != 0 && (hEvent = (HANDLE)atoi(argv[2])) != 0) {
 	    if (!DEBUG_Attach(pid, TRUE)) {
-		DEBUG_Printf(DBG_CHN_ERR, "Can't attach process %ld: %ld\n", 
-			     DEBUG_CurrPid, GetLastError());
 		/* don't care about result */
 		SetEvent(hEvent);
 		goto leave;
@@ -920,10 +920,11 @@
     }
 
     retv = DEBUG_MainLoop();
- leave:
+
     /* saves modified variables */
     DEBUG_IntVarsRW(FALSE);
 
+ leave:
     return retv;
 
  oom_leave:
Index: documentation/debugger.sgml
===================================================================
RCS file: /usr/share/cvs/cvsroot/wine/wine/documentation/debugger.sgml,v
retrieving revision 1.5
diff -u -u -r1.5 debugger.sgml
--- documentation/debugger.sgml	2001/05/03 18:32:07	1.5
+++ documentation/debugger.sgml	2001/08/03 08:29:13
@@ -1349,11 +1349,14 @@
 
         <screen>
 bt		print calling stack of current thread
+bt N		print calling stack of thread of ID N (note: this
+                doesn't change the position of the current frame as
+		manipulated by the up & dn commands)
 up		goes up one frame in current thread's stack
 up N		goes up N frames in current thread's stack
 dn		goes down one frame in current thread's stack
 dn N		goes down N frames in current thread's stack
-frame N		set N as the current frame
+frame N		set N as the current frame for current thread's stack
 info local	prints information on local variables for current
 		function 
         </screen>


More information about the wine-patches mailing list