blob: 1b6a90c3790158b91d14ec8bed794fc540a94568 [file] [log] [blame]
Alexandre Julliard4cc1b331999-05-23 19:57:42 +00001/*
2 * Win32 debugger functions
3 *
4 * Copyright (C) 1999 Alexandre Julliard
5 */
6
Alexandre Julliard5b971f02000-11-26 22:39:50 +00007#include <stdio.h>
Patrik Stridvall2c684081999-07-31 17:36:48 +00008#include <string.h>
9
Alexandre Julliardff81d782000-03-08 12:01:30 +000010#include "winerror.h"
Alexandre Julliard5b971f02000-11-26 22:39:50 +000011#include "wine/winbase16.h"
Alexandre Julliard37e95032001-07-19 00:39:09 +000012#include "wine/server.h"
Alexandre Julliard5b971f02000-11-26 22:39:50 +000013#include "stackframe.h"
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000014#include "debugtools.h"
15
Alexandre Julliard3e2517c2000-01-20 18:59:03 +000016DEFAULT_DEBUG_CHANNEL(debugstr);
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000017
18
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000019/******************************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +000020 * WaitForDebugEvent (KERNEL32.@)
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000021 *
Andrew Johnston03131aa2000-12-19 23:33:03 +000022 * Waits for a debugging event to occur in a process being debugged before
23 * filling out the debug event structure.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000024 *
Andrew Johnston03131aa2000-12-19 23:33:03 +000025 * RETURNS
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000026 *
Andrew Johnston03131aa2000-12-19 23:33:03 +000027 * Returns true if a debug event occurred and false if the call timed out.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000028 */
Andrew Johnston03131aa2000-12-19 23:33:03 +000029BOOL WINAPI WaitForDebugEvent(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +000030 LPDEBUG_EVENT event, /* [out] Address of structure for event information. */
31 DWORD timeout) /* [in] Number of milliseconds to wait for event. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000032{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000033 BOOL ret;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000034 DWORD res;
35
36 for (;;)
Alexandre Julliard4cc1b331999-05-23 19:57:42 +000037 {
Alexandre Julliarde9936d92001-01-26 00:22:26 +000038 HANDLE wait = 0;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000039 debug_event_t data;
40 SERVER_START_REQ( wait_debug_event )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +000041 {
Alexandre Julliarde9936d92001-01-26 00:22:26 +000042 req->get_handle = (timeout != 0);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000043 wine_server_set_reply( req, &data, sizeof(data) );
44 if (!(ret = !wine_server_call_err( req ))) goto done;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000045
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000046 if (!wine_server_reply_size(reply)) /* timeout */
Alexandre Julliarde9936d92001-01-26 00:22:26 +000047 {
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000048 wait = reply->wait;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000049 ret = FALSE;
50 goto done;
51 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000052 event->dwDebugEventCode = data.code;
53 event->dwProcessId = (DWORD)reply->pid;
54 event->dwThreadId = (DWORD)reply->tid;
55 switch(data.code)
Alexandre Julliarde9936d92001-01-26 00:22:26 +000056 {
57 case EXCEPTION_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000058 event->u.Exception.ExceptionRecord = data.info.exception.record;
59 event->u.Exception.dwFirstChance = data.info.exception.first;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000060 break;
61 case CREATE_THREAD_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000062 event->u.CreateThread.hThread = data.info.create_thread.handle;
63 event->u.CreateThread.lpThreadLocalBase = data.info.create_thread.teb;
64 event->u.CreateThread.lpStartAddress = data.info.create_thread.start;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000065 break;
66 case CREATE_PROCESS_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000067 event->u.CreateProcessInfo.hFile = data.info.create_process.file;
68 event->u.CreateProcessInfo.hProcess = data.info.create_process.process;
69 event->u.CreateProcessInfo.hThread = data.info.create_process.thread;
70 event->u.CreateProcessInfo.lpBaseOfImage = data.info.create_process.base;
71 event->u.CreateProcessInfo.dwDebugInfoFileOffset = data.info.create_process.dbg_offset;
72 event->u.CreateProcessInfo.nDebugInfoSize = data.info.create_process.dbg_size;
73 event->u.CreateProcessInfo.lpThreadLocalBase = data.info.create_process.teb;
74 event->u.CreateProcessInfo.lpStartAddress = data.info.create_process.start;
75 event->u.CreateProcessInfo.lpImageName = data.info.create_process.name;
76 event->u.CreateProcessInfo.fUnicode = data.info.create_process.unicode;
77 if (data.info.create_process.file == -1) event->u.CreateProcessInfo.hFile = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000078 break;
79 case EXIT_THREAD_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000080 event->u.ExitThread.dwExitCode = data.info.exit.exit_code;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000081 break;
82 case EXIT_PROCESS_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000083 event->u.ExitProcess.dwExitCode = data.info.exit.exit_code;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000084 break;
85 case LOAD_DLL_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000086 event->u.LoadDll.hFile = data.info.load_dll.handle;
87 event->u.LoadDll.lpBaseOfDll = data.info.load_dll.base;
88 event->u.LoadDll.dwDebugInfoFileOffset = data.info.load_dll.dbg_offset;
89 event->u.LoadDll.nDebugInfoSize = data.info.load_dll.dbg_size;
90 event->u.LoadDll.lpImageName = data.info.load_dll.name;
91 event->u.LoadDll.fUnicode = data.info.load_dll.unicode;
92 if (data.info.load_dll.handle == -1) event->u.LoadDll.hFile = 0;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000093 break;
94 case UNLOAD_DLL_DEBUG_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000095 event->u.UnloadDll.lpBaseOfDll = data.info.unload_dll.base;
Alexandre Julliarde9936d92001-01-26 00:22:26 +000096 break;
97 case OUTPUT_DEBUG_STRING_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +000098 event->u.DebugString.lpDebugStringData = data.info.output_string.string;
99 event->u.DebugString.fUnicode = data.info.output_string.unicode;
100 event->u.DebugString.nDebugStringLength = data.info.output_string.length;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000101 break;
102 case RIP_EVENT:
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000103 event->u.RipInfo.dwError = data.info.rip_info.error;
104 event->u.RipInfo.dwType = data.info.rip_info.type;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000105 break;
106 }
107 done:
James Juran49c779a2001-11-19 02:24:14 +0000108 /* nothing */ ;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000109 }
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000110 SERVER_END_REQ;
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000111 if (ret) return TRUE;
112 if (!wait) break;
113 res = WaitForSingleObject( wait, timeout );
114 CloseHandle( wait );
115 if (res != STATUS_WAIT_0) break;
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000116 }
Alexandre Julliarde9936d92001-01-26 00:22:26 +0000117 SetLastError( ERROR_SEM_TIMEOUT );
118 return FALSE;
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000119}
120
121
122/**********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000123 * ContinueDebugEvent (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000124 *
125 * Enables a thread that previously produced a debug event to continue.
126 *
127 * RETURNS
128 *
129 * True if the debugger is listed as the processes owner and the process
130 * and thread are valid.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000131 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000132BOOL WINAPI ContinueDebugEvent(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000133 DWORD pid, /* [in] The id of the process to continue. */
134 DWORD tid, /* [in] The id of the thread to continue. */
135 DWORD status) /* [in] The rule to apply to unhandled exeptions. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000136{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000137 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +0000138 SERVER_START_REQ( continue_debug_event )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000139 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000140 req->pid = (void *)pid;
141 req->tid = (void *)tid;
142 req->status = status;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000143 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000144 }
145 SERVER_END_REQ;
146 return ret;
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000147}
148
149
150/**********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000151 * DebugActiveProcess (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000152 *
Eric Pouechfbccb382002-02-27 01:28:30 +0000153 * Attempts to attach the debugger to a process.
Andrew Johnston03131aa2000-12-19 23:33:03 +0000154 *
155 * RETURNS
156 *
157 * True if the debugger was attached to process.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000158 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000159BOOL WINAPI DebugActiveProcess(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000160 DWORD pid) /* [in] The process to be debugged. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000161{
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000162 BOOL ret;
Alexandre Julliard67a74992001-02-27 02:09:16 +0000163 SERVER_START_REQ( debug_process )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000164 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000165 req->pid = (void *)pid;
Eric Pouechfbccb382002-02-27 01:28:30 +0000166 req->attach = 1;
167 ret = !wine_server_call_err( req );
168 }
169 SERVER_END_REQ;
170 return ret;
171}
172
173/**********************************************************************
174 * DebugActiveProcessStop (KERNEL32.@)
175 *
176 * Attempts to detach the debugger from a process.
177 *
178 * RETURNS
179 *
180 * True if the debugger was detached from the process.
181 */
182BOOL WINAPI DebugActiveProcessStop(
183 DWORD pid) /* [in] The process to be detached. */
184{
185 BOOL ret;
186 SERVER_START_REQ( debug_process )
187 {
188 req->pid = (void *)pid;
189 req->attach = 0;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000190 ret = !wine_server_call_err( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000191 }
192 SERVER_END_REQ;
193 return ret;
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000194}
195
196
197/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000198 * OutputDebugStringA (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000199 *
200 * Output by an application of a unicode string to a debugger (if attached)
201 * and program log.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000202 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000203void WINAPI OutputDebugStringA(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000204 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000205{
Alexandre Julliard67a74992001-02-27 02:09:16 +0000206 SERVER_START_REQ( output_debug_string )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000207 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000208 req->string = (void *)str;
209 req->unicode = 0;
210 req->length = strlen(str) + 1;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000211 wine_server_call( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000212 }
213 SERVER_END_REQ;
Andreas Mohrcd132372000-05-23 01:13:07 +0000214 WARN("%s\n", str);
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000215}
216
217
218/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000219 * OutputDebugStringW (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000220 *
221 * Output by an appliccation of a unicode string to a debugger (if attached)
222 * and program log.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000223 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000224void WINAPI OutputDebugStringW(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000225 LPCWSTR str) /* [in] The message to be logged and given to the debugger. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000226{
Alexandre Julliard67a74992001-02-27 02:09:16 +0000227 SERVER_START_REQ( output_debug_string )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000228 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000229 req->string = (void *)str;
230 req->unicode = 1;
231 req->length = (lstrlenW(str) + 1) * sizeof(WCHAR);
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000232 wine_server_call( req );
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000233 }
234 SERVER_END_REQ;
Andreas Mohrcd132372000-05-23 01:13:07 +0000235 WARN("%s\n", debugstr_w(str));
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000236}
237
238
239/***********************************************************************
Patrik Stridvallc01c1932001-06-19 03:36:23 +0000240 * OutputDebugString (KERNEL.115)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000241 *
242 * Output by a 16 bit application of an ascii string to a debugger (if attached)
243 * and program log.
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000244 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000245void WINAPI OutputDebugString16(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000246 LPCSTR str) /* [in] The message to be logged and given to the debugger. */
Alexandre Julliard4cc1b331999-05-23 19:57:42 +0000247{
248 OutputDebugStringA( str );
249}
Alexandre Julliard00641d52000-03-08 16:41:37 +0000250
251
252/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000253 * DebugBreak (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000254 *
255 * Raises an exception so that a debugger (if attached)
256 * can take some action.
Alexandre Julliard00641d52000-03-08 16:41:37 +0000257 */
258void WINAPI DebugBreak(void)
259{
260 DbgBreakPoint();
261}
262
Eric Pouechfbccb382002-02-27 01:28:30 +0000263/***********************************************************************
264 * DebugBreakProcess (KERNEL32.@)
265 *
266 * Raises an exception so that a debugger (if attached)
267 * can take some action. Same as DebugBreak, but applies to any process.
268 */
269BOOL WINAPI DebugBreakProcess(HANDLE hProc)
270{
271#if 0 /* FIXME: not correct */
272 int res;
273 int pid;
274
275 TRACE("(%08lx)\n", (DWORD)hProc);
276
277 SERVER_START_REQ( get_process_info )
278 {
279 req->handle = hProc;
280 res = wine_server_call_err( req );
281 pid = (int)reply->pid;
282 }
283 SERVER_END_REQ;
284 return !res && kill(pid, SIGINT) == 0;
285#endif
286 return FALSE;
287}
288
Alexandre Julliard00641d52000-03-08 16:41:37 +0000289
290/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000291 * DebugBreak (KERNEL.203)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000292 *
293 * Raises an expection in a 16 bit application so that a debugger (if attached)
294 * can take some action.
295 *
296 * BUGS
297 *
298 * Only 386 compatible processors implemented.
Alexandre Julliard00641d52000-03-08 16:41:37 +0000299 */
Andrew Johnston03131aa2000-12-19 23:33:03 +0000300void WINAPI DebugBreak16(
Patrik Stridvallbca4a8d2001-02-12 03:49:57 +0000301 CONTEXT86 *context) /* [in/out] A pointer to the 386 compatible processor state. */
Alexandre Julliard00641d52000-03-08 16:41:37 +0000302{
303#ifdef __i386__
304 EXCEPTION_RECORD rec;
305
306 rec.ExceptionCode = EXCEPTION_BREAKPOINT;
307 rec.ExceptionFlags = 0;
308 rec.ExceptionRecord = NULL;
Alexandre Julliarddfd3d4a2000-11-25 23:56:20 +0000309 rec.ExceptionAddress = (LPVOID)context->Eip;
Alexandre Julliard00641d52000-03-08 16:41:37 +0000310 rec.NumberParameters = 0;
311 NtRaiseException( &rec, context, TRUE );
312#endif /* defined(__i386__) */
313}
314
315
316/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000317 * IsDebuggerPresent (KERNEL32.@)
Andrew Johnston03131aa2000-12-19 23:33:03 +0000318 *
319 * Allows a process to determine if there is a debugger attached.
320 *
321 * RETURNS
322 *
323 * True if there is a debugger attached.
Alexandre Julliard00641d52000-03-08 16:41:37 +0000324 */
325BOOL WINAPI IsDebuggerPresent(void)
326{
327 BOOL ret = FALSE;
Alexandre Julliard67a74992001-02-27 02:09:16 +0000328 SERVER_START_REQ( get_process_info )
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000329 {
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000330 req->handle = GetCurrentProcess();
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000331 if (!wine_server_call_err( req )) ret = reply->debugged;
Alexandre Julliard9c2370b2000-08-30 00:00:48 +0000332 }
333 SERVER_END_REQ;
Alexandre Julliard00641d52000-03-08 16:41:37 +0000334 return ret;
335}
Alexandre Julliard5b971f02000-11-26 22:39:50 +0000336
337
338/***********************************************************************
339 * _DebugOutput (KERNEL.328)
340 */
341void WINAPIV _DebugOutput( void )
342{
343 VA_LIST16 valist;
344 WORD flags;
345 SEGPTR spec;
346 char caller[101];
347
348 /* Decode caller address */
349 if (!GetModuleName16( GetExePtr(CURRENT_STACK16->cs), caller, sizeof(caller) ))
350 sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
351
352 /* Build debug message string */
353 VA_START16( valist );
354 flags = VA_ARG16( valist, WORD );
355 spec = VA_ARG16( valist, SEGPTR );
356 /* FIXME: cannot use wvsnprintf16 from kernel */
Alexandre Julliard982a2232000-12-13 20:20:09 +0000357 /* wvsnprintf16( temp, sizeof(temp), MapSL(spec), valist ); */
Alexandre Julliard5b971f02000-11-26 22:39:50 +0000358
359 /* Output */
Alexandre Julliard982a2232000-12-13 20:20:09 +0000360 FIXME("%s %04x %s\n", caller, flags, debugstr_a(MapSL(spec)) );
Alexandre Julliard5b971f02000-11-26 22:39:50 +0000361}
Eric Pouechfbccb382002-02-27 01:28:30 +0000362
363/***********************************************************************
364 * DebugSetProcessKillOnExit (KERNEL.328)
365 *
366 * Let a debugger decide wether a debuggee will be killed upon debugger
367 * termination
368 */
369BOOL WINAPI DebugSetProcessKillOnExit(BOOL kill)
370{
371 BOOL ret = FALSE;
372
373 SERVER_START_REQ( set_debugger_kill_on_exit )
374 {
375 req->kill_on_exit = kill;
376 ret = !wine_server_call_err( req );
377 }
378 SERVER_END_REQ;
379 return ret;
380}
381