- fixed breakpoint enabled/disabled state management
[wine] / programs / winedbg / stack.c
1 /*
2  * Debugger stack handling
3  *
4  * Copyright 1995 Alexandre Julliard
5  * Copyright 1996 Eric Youngdale
6  * Copyright 1999 Ove Kåven
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26
27 #include "debugger.h"
28 #include "stackframe.h"
29 #include "winbase.h"
30 #include "wine/debug.h"
31 #include "tlhelp32.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(winedbg);
34
35 static int                      nframe;
36 static IMAGEHLP_STACK_FRAME*    frames = NULL;
37
38 /***********************************************************************
39  *           stack_info
40  *
41  * Dump the top of the stack
42  */
43 void stack_info(void)
44 {
45     ADDRESS             addr;
46
47     /* FIXME: we assume stack grows the same way as on i386 */
48     if (!memory_get_current_stack(&addr))
49         dbg_printf("Bad segment (%d)\n", addr.Segment);
50
51     dbg_printf("Stack dump:\n");
52     switch (addr.Mode)
53     {
54     case AddrModeFlat: /* 32-bit mode */
55     case AddrMode1632: /* 32-bit mode */
56         memory_examine(memory_to_linear_addr(&addr), 24, 'x');
57         break;
58     case AddrModeReal:  /* 16-bit mode */
59     case AddrMode1616:
60         memory_examine(memory_to_linear_addr(&addr), 24, 'w');
61         break;
62     }
63 }
64
65 int stack_set_frame(int newframe)
66 {
67     ADDRESS     addr;
68
69     dbg_curr_frame = newframe;
70     if (dbg_curr_frame >= nframe) dbg_curr_frame = nframe - 1;
71     if (dbg_curr_frame < 0)       dbg_curr_frame = 0;
72
73     addr.Mode = AddrModeFlat;
74     addr.Offset = frames[dbg_curr_frame].InstructionOffset;
75     source_list_from_addr(&addr, 0);
76     return TRUE;
77 }
78
79 int stack_get_frame(SYMBOL_INFO* symbol, IMAGEHLP_STACK_FRAME* ihsf)
80 {
81     /*
82      * If we don't have a valid backtrace, then just return.
83      */
84     if (frames == NULL) return FALSE;
85
86     /*
87      * If we don't know what the current function is, then we also have
88      * nothing to report here.
89      */
90     SymFromAddr(dbg_curr_process->handle, frames[dbg_curr_frame].InstructionOffset,
91                 NULL, symbol);
92     if (ihsf) *ihsf = frames[dbg_curr_frame];
93
94     return TRUE;
95 }
96
97 void stack_backtrace(DWORD tid, BOOL noisy)
98 {
99     STACKFRAME                  sf;
100     CONTEXT                     saved_dbg_context;
101     struct dbg_thread*          thread;
102     unsigned                    nf;
103
104     if (tid == -1)  /* backtrace every thread in every process except the debugger itself, invoking via "bt all" */
105     {
106         THREADENTRY32 entry;
107         HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
108         
109         if (snapshot == INVALID_HANDLE_VALUE)
110         {
111             dbg_printf("unable to create toolhelp snapshot\n");
112             return;
113         }
114         
115         entry.dwSize = sizeof(entry);
116         
117         if (!Thread32First(snapshot, &entry))
118         {
119             CloseHandle(snapshot);
120             return;
121         }
122         
123         do
124         {
125             if (entry.th32OwnerProcessID == GetCurrentProcessId()) continue;
126             if (dbg_curr_process) dbg_detach_debuggee();
127
128             dbg_printf("\n");
129             if (!dbg_attach_debuggee(entry.th32OwnerProcessID, FALSE, TRUE))
130             {
131                 dbg_printf("\nwarning: could not attach to 0x%lx\n", entry.th32OwnerProcessID);
132                 continue;
133             }
134
135             dbg_printf("Backtracing for thread 0x%lx in process 0x%lx (%s):\n", entry.th32ThreadID, dbg_curr_pid, dbg_curr_process->imageName);
136             
137             stack_backtrace(entry.th32ThreadID, TRUE);
138         }
139         while (Thread32Next(snapshot, &entry));
140
141         if (dbg_curr_process) dbg_detach_debuggee();
142         CloseHandle(snapshot);
143         return;
144     }
145
146     if (!dbg_curr_process) 
147     {
148         dbg_printf("You must be attached to a process to run this command.\n");
149         return;
150     }
151     
152     saved_dbg_context = dbg_context; /* as we may modify dbg_context... */
153     if (tid == dbg_curr_tid)
154     {
155         thread = dbg_curr_thread;
156         if (frames) HeapFree(GetProcessHeap(), 0, frames);
157         frames = NULL;
158     }
159     else
160     {
161          thread = dbg_get_thread(dbg_curr_process, tid);
162          if (!thread)
163          {
164               dbg_printf("Unknown thread id (0x%08lx) in current process\n", tid);
165               return;
166          }
167          memset(&dbg_context, 0, sizeof(dbg_context));
168          dbg_context.ContextFlags = CONTEXT_FULL;
169          if (SuspendThread(thread->handle) != -1)
170          {
171              if (!GetThreadContext(thread->handle, &dbg_context))
172              {
173                  dbg_printf("Can't get context for thread 0x%lx in current process\n",
174                             tid);
175                  ResumeThread(thread->handle);
176                  return;
177              }
178          }
179          else
180          {
181              dbg_printf("Can't suspend thread 0x%lx in current process\n", tid);
182              return;
183          }
184     }
185
186     nf = 0;
187     memset(&sf, 0, sizeof(sf));
188     memory_get_current_frame(&sf.AddrFrame);
189     memory_get_current_pc(&sf.AddrPC);
190
191     if (noisy) dbg_printf("Backtrace:\n");
192     while (StackWalk(IMAGE_FILE_MACHINE_I386, dbg_curr_process->handle, 
193                      thread->handle, &sf, &dbg_context, NULL, SymFunctionTableAccess,
194                      SymGetModuleBase, NULL))
195     {
196         if (tid == dbg_curr_tid)
197         {
198             frames = dbg_heap_realloc(frames, 
199                                       (nf + 1) * sizeof(IMAGEHLP_STACK_FRAME));
200
201             frames[nf].InstructionOffset = (unsigned long)memory_to_linear_addr(&sf.AddrPC);
202             frames[nf].FrameOffset = (unsigned long)memory_to_linear_addr(&sf.AddrFrame);
203         }
204         if (noisy)
205         {
206             dbg_printf("%s%d ", 
207                        (tid == dbg_curr_tid && nf == dbg_curr_frame ? "=>" : "  "),
208                        nf + 1);
209             print_addr_and_args(&sf.AddrPC, &sf.AddrFrame);
210             dbg_printf(" (");
211             print_bare_address(&sf.AddrFrame);
212             dbg_printf(")\n");
213         }
214         nf++;
215     }
216
217     dbg_context = saved_dbg_context;
218     if (tid == dbg_curr_tid)
219     {
220         nframe = nf;
221     }
222     else
223     {
224         ResumeThread(thread->handle);
225     }
226 }