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