2 * Win32 debugger functions
4 * Copyright (C) 1999 Alexandre Julliard
11 #include "wine/winbase16.h"
13 #include "stackframe.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(debugstr
);
19 /******************************************************************************
20 * WaitForDebugEvent (KERNEL32.720)
22 * Waits for a debugging event to occur in a process being debugged before
23 * filling out the debug event structure.
27 * Returns true if a debug event occurred and false if the call timed out.
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. */
42 struct wait_debug_event_request
*req
= server_alloc_req( sizeof(*req
), sizeof(*data
) );
44 req
->get_handle
= (timeout
!= 0);
45 if (!(ret
= !server_call( REQ_WAIT_DEBUG_EVENT
))) goto done
;
47 if (!server_data_size(req
)) /* timeout */
53 data
= server_data_ptr(req
);
54 event
->dwDebugEventCode
= data
->code
;
55 event
->dwProcessId
= (DWORD
)req
->pid
;
56 event
->dwThreadId
= (DWORD
)req
->tid
;
59 case EXCEPTION_DEBUG_EVENT
:
60 event
->u
.Exception
.ExceptionRecord
= data
->info
.exception
.record
;
61 event
->u
.Exception
.dwFirstChance
= data
->info
.exception
.first
;
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
;
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;
81 case EXIT_THREAD_DEBUG_EVENT
:
82 event
->u
.ExitThread
.dwExitCode
= data
->info
.exit
.exit_code
;
84 case EXIT_PROCESS_DEBUG_EVENT
:
85 event
->u
.ExitProcess
.dwExitCode
= data
->info
.exit
.exit_code
;
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;
96 case UNLOAD_DLL_DEBUG_EVENT
:
97 event
->u
.UnloadDll
.lpBaseOfDll
= data
->info
.unload_dll
.base
;
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
;
105 event
->u
.RipInfo
.dwError
= data
->info
.rip_info
.error
;
106 event
->u
.RipInfo
.dwType
= data
->info
.rip_info
.type
;
112 if (ret
) return TRUE
;
114 res
= WaitForSingleObject( wait
, timeout
);
116 if (res
!= STATUS_WAIT_0
) break;
118 SetLastError( ERROR_SEM_TIMEOUT
);
123 /**********************************************************************
124 * ContinueDebugEvent (KERNEL32.146)
125 * ContinueDebugEvent (WIN32S16.5)
127 * Enables a thread that previously produced a debug event to continue.
131 * True if the debugger is listed as the processes owner and the process
132 * and thread are valid.
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. */
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
);
153 /**********************************************************************
154 * DebugActiveProcess (KERNEL32.180)
156 * Attempts to attach the dugger to a process.
160 * True if the debugger was attached to process.
162 BOOL WINAPI
DebugActiveProcess(
163 DWORD pid
) /* [in] The process to be debugged. */
168 struct debug_process_request
*req
= server_alloc_req( sizeof(*req
), 0 );
169 req
->pid
= (void *)pid
;
170 ret
= !server_call( REQ_DEBUG_PROCESS
);
177 /***********************************************************************
178 * OutputDebugStringA (KERNEL.115)
179 * OutputDebugStringA (KERNEL32.548)
181 * Output by an application of a unicode string to a debugger (if attached)
184 void WINAPI
OutputDebugStringA(
185 LPCSTR str
) /* [in] The message to be logged and given to the debugger. */
189 struct output_debug_string_request
*req
= server_alloc_req( sizeof(*req
), 0 );
190 req
->string
= (void *)str
;
192 req
->length
= strlen(str
) + 1;
193 server_call_noerr( REQ_OUTPUT_DEBUG_STRING
);
200 /***********************************************************************
201 * OutputDebugStringW (KERNEL32.549)
203 * Output by an appliccation of a unicode string to a debugger (if attached)
206 void WINAPI
OutputDebugStringW(
207 LPCWSTR str
) /* [in] The message to be logged and given to the debugger. */
211 struct output_debug_string_request
*req
= server_alloc_req( sizeof(*req
), 0 );
212 req
->string
= (void *)str
;
214 req
->length
= (lstrlenW(str
) + 1) * sizeof(WCHAR
);
215 server_call_noerr( REQ_OUTPUT_DEBUG_STRING
);
218 WARN("%s\n", debugstr_w(str
));
222 /***********************************************************************
223 * OutputDebugString16 (KERNEL.115)
225 * Output by a 16 bit application of an ascii string to a debugger (if attached)
228 void WINAPI
OutputDebugString16(
229 LPCSTR str
) /* [in] The message to be logged and given to the debugger. */
231 OutputDebugStringA( str
);
235 /***********************************************************************
236 * DebugBreak (KERNEL32.181)
238 * Raises an exception so that a debugger (if attached)
239 * can take some action.
241 void WINAPI
DebugBreak(void)
247 /***********************************************************************
248 * DebugBreak16 (KERNEL.203)
250 * Raises an expection in a 16 bit application so that a debugger (if attached)
251 * can take some action.
255 * Only 386 compatible processors implemented.
257 void WINAPI
DebugBreak16(
258 CONTEXT86
*context
) /* [in/out] A pointer to the 386 compatible processor state. */
261 EXCEPTION_RECORD rec
;
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__) */
273 /***********************************************************************
274 * IsDebuggerPresent (KERNEL32.827)
276 * Allows a process to determine if there is a debugger attached.
280 * True if there is a debugger attached.
282 BOOL WINAPI
IsDebuggerPresent(void)
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
;
296 /***********************************************************************
297 * _DebugOutput (KERNEL.328)
299 void WINAPIV
_DebugOutput( void )
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
);
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 ); */
318 FIXME("%s %04x %s\n", caller
, flags
, debugstr_a(MapSL(spec
)) );