Documentation update.
[wine] / dlls / kernel / debugger.c
1 /*
2  * Win32 debugger functions
3  *
4  * Copyright (C) 1999 Alexandre Julliard
5  */
6
7 #include <stdio.h>
8 #include <string.h>
9
10 #include "winerror.h"
11 #include "wine/winbase16.h"
12 #include "server.h"
13 #include "stackframe.h"
14 #include "debugtools.h"
15
16 DEFAULT_DEBUG_CHANNEL(debugstr);
17
18
19 /******************************************************************************
20  *           WaitForDebugEvent   (KERNEL32.720)
21  *
22  *  Waits for a debugging event to occur in a process being debugged before
23  *  filling out the debug event structure.
24  *
25  * RETURNS
26  *
27  *  Returns true if a debug event occurred and false if the call timed out.
28  */
29 BOOL WINAPI WaitForDebugEvent(
30          LPDEBUG_EVENT event, /* Address of structure for event information. */
31          DWORD timeout /* Number of milliseconds to wait for event. */)
32 {
33     BOOL ret;
34     SERVER_START_REQ
35     {
36         debug_event_t *data;
37         struct wait_debug_event_request *req = server_alloc_req( sizeof(*req), sizeof(*data) );
38
39         req->timeout = timeout;
40         if (!(ret = !server_call( REQ_WAIT_DEBUG_EVENT ))) goto done;
41
42         if (!server_data_size(req))  /* timeout */
43         {
44             SetLastError( ERROR_SEM_TIMEOUT );
45             ret = FALSE;
46             goto done;
47         }
48         data = server_data_ptr(req);
49         event->dwDebugEventCode = data->code;
50         event->dwProcessId      = (DWORD)req->pid;
51         event->dwThreadId       = (DWORD)req->tid;
52         switch(data->code)
53         {
54         case EXCEPTION_DEBUG_EVENT:
55             event->u.Exception.ExceptionRecord = data->info.exception.record;
56             event->u.Exception.dwFirstChance   = data->info.exception.first;
57             break;
58         case CREATE_THREAD_DEBUG_EVENT:
59             event->u.CreateThread.hThread           = data->info.create_thread.handle;
60             event->u.CreateThread.lpThreadLocalBase = data->info.create_thread.teb;
61             event->u.CreateThread.lpStartAddress    = data->info.create_thread.start;
62             break;
63         case CREATE_PROCESS_DEBUG_EVENT:
64             event->u.CreateProcessInfo.hFile                 = data->info.create_process.file;
65             event->u.CreateProcessInfo.hProcess              = data->info.create_process.process;
66             event->u.CreateProcessInfo.hThread               = data->info.create_process.thread;
67             event->u.CreateProcessInfo.lpBaseOfImage         = data->info.create_process.base;
68             event->u.CreateProcessInfo.dwDebugInfoFileOffset = data->info.create_process.dbg_offset;
69             event->u.CreateProcessInfo.nDebugInfoSize        = data->info.create_process.dbg_size;
70             event->u.CreateProcessInfo.lpThreadLocalBase     = data->info.create_process.teb;
71             event->u.CreateProcessInfo.lpStartAddress        = data->info.create_process.start;
72             event->u.CreateProcessInfo.lpImageName           = data->info.create_process.name;
73             event->u.CreateProcessInfo.fUnicode              = data->info.create_process.unicode;
74             if (data->info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0;
75             break;
76         case EXIT_THREAD_DEBUG_EVENT:
77             event->u.ExitThread.dwExitCode = data->info.exit.exit_code;
78             break;
79         case EXIT_PROCESS_DEBUG_EVENT:
80             event->u.ExitProcess.dwExitCode = data->info.exit.exit_code;
81             break;
82         case LOAD_DLL_DEBUG_EVENT:
83             event->u.LoadDll.hFile                 = data->info.load_dll.handle;
84             event->u.LoadDll.lpBaseOfDll           = data->info.load_dll.base;
85             event->u.LoadDll.dwDebugInfoFileOffset = data->info.load_dll.dbg_offset;
86             event->u.LoadDll.nDebugInfoSize        = data->info.load_dll.dbg_size;
87             event->u.LoadDll.lpImageName           = data->info.load_dll.name;
88             event->u.LoadDll.fUnicode              = data->info.load_dll.unicode;
89             if (data->info.load_dll.handle == -1) event->u.LoadDll.hFile = 0;
90             break;
91         case UNLOAD_DLL_DEBUG_EVENT:
92             event->u.UnloadDll.lpBaseOfDll = data->info.unload_dll.base;
93             break;
94         case OUTPUT_DEBUG_STRING_EVENT:
95             event->u.DebugString.lpDebugStringData  = data->info.output_string.string;
96             event->u.DebugString.fUnicode           = data->info.output_string.unicode;
97             event->u.DebugString.nDebugStringLength = data->info.output_string.length;
98             break;
99         case RIP_EVENT:
100             event->u.RipInfo.dwError = data->info.rip_info.error;
101             event->u.RipInfo.dwType  = data->info.rip_info.type;
102             break;
103         default:
104             server_protocol_error( "WaitForDebugEvent: bad code %d\n", data->code );
105         }
106     done:
107     }
108     SERVER_END_REQ;
109     return ret;
110 }
111
112
113 /**********************************************************************
114  *           ContinueDebugEvent   (KERNEL32.146)
115  *
116  *  Enables a thread that previously produced a debug event to continue.
117  *
118  * RETURNS
119  *
120  *  True if the debugger is listed as the processes owner and the process
121  *  and thread are valid.
122  */
123 BOOL WINAPI ContinueDebugEvent(
124         DWORD pid, /* The id of the process to continue. */
125         DWORD tid, /* The id of the thread to continue. */
126         DWORD status /* The rule to apply to unhandled exeptions. */)
127 {
128     BOOL ret;
129     SERVER_START_REQ
130     {
131         struct continue_debug_event_request *req = server_alloc_req( sizeof(*req), 0 );
132         req->pid    = (void *)pid;
133         req->tid    = (void *)tid;
134         req->status = status;
135         ret = !server_call( REQ_CONTINUE_DEBUG_EVENT );
136     }
137     SERVER_END_REQ;
138     return ret;
139 }
140
141
142 /**********************************************************************
143  *           DebugActiveProcess   (KERNEL32.180)
144  *
145  *  Attempts to attach the dugger to a process.
146  *
147  * RETURNS
148  *
149  *  True if the debugger was attached to process.
150  */
151 BOOL WINAPI DebugActiveProcess(
152         DWORD pid /* The process to be debugged. */)
153 {
154     BOOL ret;
155     SERVER_START_REQ
156     {
157         struct debug_process_request *req = server_alloc_req( sizeof(*req), 0 );
158         req->pid = (void *)pid;
159         ret = !server_call( REQ_DEBUG_PROCESS );
160     }
161     SERVER_END_REQ;
162     return ret;
163 }
164
165
166 /***********************************************************************
167  *           OutputDebugStringA   (KERNEL32.548)
168  *
169  *  Output by an application of a unicode string to a debugger (if attached)
170  *  and program log.
171  */
172 void WINAPI OutputDebugStringA(
173         LPCSTR str /* The message to be logged and given to the debugger. */)
174 {
175     SERVER_START_REQ
176     {
177         struct output_debug_string_request *req = server_alloc_req( sizeof(*req), 0 );
178         req->string  = (void *)str;
179         req->unicode = 0;
180         req->length  = strlen(str) + 1;
181         server_call_noerr( REQ_OUTPUT_DEBUG_STRING );
182     }
183     SERVER_END_REQ;
184     WARN("%s\n", str);
185 }
186
187
188 /***********************************************************************
189  *           OutputDebugStringW   (KERNEL32.549)
190  *
191  *  Output by an appliccation of a unicode string to a debugger (if attached)
192  *  and program log.
193  */
194 void WINAPI OutputDebugStringW(
195         LPCWSTR str /* The message to be logged and given to the debugger. */)
196 {
197     SERVER_START_REQ
198     {
199         struct output_debug_string_request *req = server_alloc_req( sizeof(*req), 0 );
200         req->string  = (void *)str;
201         req->unicode = 1;
202         req->length  = (lstrlenW(str) + 1) * sizeof(WCHAR);
203         server_call_noerr( REQ_OUTPUT_DEBUG_STRING );
204     }
205     SERVER_END_REQ;
206     WARN("%s\n", debugstr_w(str));
207 }
208
209
210 /***********************************************************************
211  *           OutputDebugString16   (KERNEL.115)
212  *
213  *  Output by a 16 bit application of an ascii string to a debugger (if attached)
214  *  and program log.
215  */
216 void WINAPI OutputDebugString16(
217         LPCSTR str /* The message to be logged and given to the debugger.*/)
218 {
219     OutputDebugStringA( str );
220 }
221
222
223 /***********************************************************************
224  *           DebugBreak   (KERNEL32.181)
225  *
226  *  Raises an exception so that a debugger (if attached)
227  *  can take some action.
228  */
229 void WINAPI DebugBreak(void)
230 {
231     DbgBreakPoint();
232 }
233
234
235 /***********************************************************************
236  *           DebugBreak16   (KERNEL.203)
237  *
238  *  Raises an expection in a 16 bit application so that a debugger (if attached)
239  *  can take some action.
240  *
241  * BUGS
242  *
243  *  Only 386 compatible processors implemented.
244  */
245 void WINAPI DebugBreak16(
246         CONTEXT86 *context /* A pointer to the 386 compatible processor state. */)
247 {
248 #ifdef __i386__
249     EXCEPTION_RECORD rec;
250
251     rec.ExceptionCode    = EXCEPTION_BREAKPOINT;
252     rec.ExceptionFlags   = 0;
253     rec.ExceptionRecord  = NULL;
254     rec.ExceptionAddress = (LPVOID)context->Eip;
255     rec.NumberParameters = 0;
256     NtRaiseException( &rec, context, TRUE );
257 #endif  /* defined(__i386__) */
258 }
259
260
261 /***********************************************************************
262  *           IsDebuggerPresent   (KERNEL32)
263  *
264  *  Allows a process to determine if there is a debugger attached.
265  *
266  * RETURNS
267  *
268  *  True if there is a debugger attached.
269  */
270 BOOL WINAPI IsDebuggerPresent(void)
271 {
272     BOOL ret = FALSE;
273     SERVER_START_REQ
274     {
275         struct get_process_info_request *req = server_alloc_req( sizeof(*req), 0 );
276         req->handle = GetCurrentProcess();
277         if (!server_call( REQ_GET_PROCESS_INFO )) ret = req->debugged;
278     }
279     SERVER_END_REQ;
280     return ret;
281 }
282
283
284 /***********************************************************************
285  *           _DebugOutput                    (KERNEL.328)
286  */
287 void WINAPIV _DebugOutput( void )
288 {
289     VA_LIST16 valist;
290     WORD flags;
291     SEGPTR spec;
292     char caller[101];
293
294     /* Decode caller address */
295     if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
296         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
297
298     /* Build debug message string */
299     VA_START16( valist );
300     flags = VA_ARG16( valist, WORD );
301     spec  = VA_ARG16( valist, SEGPTR );
302     /* FIXME: cannot use wvsnprintf16 from kernel */
303     /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
304
305     /* Output */
306     FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
307 }