Reverse the order for deleting the items in resetcontent to correctly
[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     DWORD64     disp;
82     /*
83      * If we don't have a valid backtrace, then just return.
84      */
85     if (frames == NULL) return FALSE;
86
87     /*
88      * If we don't know what the current function is, then we also have
89      * nothing to report here.
90      */
91     if (!SymFromAddr(dbg_curr_process->handle, frames[dbg_curr_frame].InstructionOffset,
92                      &disp, symbol))
93         return FALSE;
94     if (ihsf) *ihsf = frames[dbg_curr_frame];
95
96     return TRUE;
97 }
98
99 void stack_backtrace(DWORD tid, BOOL noisy)
100 {
101     STACKFRAME                  sf;
102     CONTEXT                     saved_dbg_context;
103     struct dbg_thread*          thread;
104     unsigned                    nf;
105
106     if (tid == -1)  /* backtrace every thread in every process except the debugger itself, invoking via "bt all" */
107     {
108         THREADENTRY32 entry;
109         HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
110         
111         if (snapshot == INVALID_HANDLE_VALUE)
112         {
113             dbg_printf("unable to create toolhelp snapshot\n");
114             return;
115         }
116         
117         entry.dwSize = sizeof(entry);
118         
119         if (!Thread32First(snapshot, &entry))
120         {
121             CloseHandle(snapshot);
122             return;
123         }
124         
125         do
126         {
127             if (entry.th32OwnerProcessID == GetCurrentProcessId()) continue;
128             if (dbg_curr_process) dbg_detach_debuggee();
129
130             dbg_printf("\n");
131             if (!dbg_attach_debuggee(entry.th32OwnerProcessID, FALSE, TRUE))
132             {
133                 dbg_printf("\nwarning: could not attach to 0x%lx\n", entry.th32OwnerProcessID);
134                 continue;
135             }
136
137             dbg_printf("Backtracing for thread 0x%lx in process 0x%lx (%s):\n", entry.th32ThreadID, dbg_curr_pid, dbg_curr_process->imageName);
138             
139             stack_backtrace(entry.th32ThreadID, TRUE);
140         }
141         while (Thread32Next(snapshot, &entry));
142
143         if (dbg_curr_process) dbg_detach_debuggee();
144         CloseHandle(snapshot);
145         return;
146     }
147
148     if (!dbg_curr_process) 
149     {
150         dbg_printf("You must be attached to a process to run this command.\n");
151         return;
152     }
153     
154     saved_dbg_context = dbg_context; /* as we may modify dbg_context... */
155     if (tid == dbg_curr_tid)
156     {
157         thread = dbg_curr_thread;
158         HeapFree(GetProcessHeap(), 0, frames);
159         frames = NULL;
160     }
161     else
162     {
163          thread = dbg_get_thread(dbg_curr_process, tid);
164          if (!thread)
165          {
166               dbg_printf("Unknown thread id (0x%08lx) in current process\n", tid);
167               return;
168          }
169          memset(&dbg_context, 0, sizeof(dbg_context));
170          dbg_context.ContextFlags = CONTEXT_FULL;
171          if (SuspendThread(thread->handle) != -1)
172          {
173              if (!GetThreadContext(thread->handle, &dbg_context))
174              {
175                  dbg_printf("Can't get context for thread 0x%lx in current process\n",
176                             tid);
177                  ResumeThread(thread->handle);
178                  return;
179              }
180          }
181          else
182          {
183              dbg_printf("Can't suspend thread 0x%lx in current process\n", tid);
184              return;
185          }
186     }
187
188     nf = 0;
189     memset(&sf, 0, sizeof(sf));
190     memory_get_current_frame(&sf.AddrFrame);
191     memory_get_current_pc(&sf.AddrPC);
192
193     /* don't confuse StackWalk by passing in inconsistent addresses */
194     if ((sf.AddrPC.Mode == AddrModeFlat) && (sf.AddrFrame.Mode != AddrModeFlat))
195     {
196         sf.AddrFrame.Offset = (DWORD)memory_to_linear_addr(&sf.AddrFrame);
197         sf.AddrFrame.Mode = AddrModeFlat;
198     }
199
200     if (noisy) dbg_printf("Backtrace:\n");
201     while (StackWalk(IMAGE_FILE_MACHINE_I386, dbg_curr_process->handle, 
202                      thread->handle, &sf, &dbg_context, NULL, SymFunctionTableAccess,
203                      SymGetModuleBase, NULL))
204     {
205         if (tid == dbg_curr_tid)
206         {
207             frames = dbg_heap_realloc(frames, 
208                                       (nf + 1) * sizeof(IMAGEHLP_STACK_FRAME));
209
210             frames[nf].InstructionOffset = (unsigned long)memory_to_linear_addr(&sf.AddrPC);
211             frames[nf].FrameOffset = (unsigned long)memory_to_linear_addr(&sf.AddrFrame);
212         }
213         if (noisy)
214         {
215             dbg_printf("%s%d ", 
216                        (tid == dbg_curr_tid && nf == dbg_curr_frame ? "=>" : "  "),
217                        nf + 1);
218             print_addr_and_args(&sf.AddrPC, &sf.AddrFrame);
219             dbg_printf(" (");
220             print_bare_address(&sf.AddrFrame);
221             dbg_printf(")\n");
222         }
223         nf++;
224         /* we've probably gotten ourselves into an infinite loop so bail */
225         if (nf > 200)
226             break;
227     }
228
229     dbg_context = saved_dbg_context;
230     if (tid == dbg_curr_tid)
231     {
232         nframe = nf;
233     }
234     else
235     {
236         ResumeThread(thread->handle);
237     }
238 }