1 /* 2 * PROJECT: ReactOS NT Layer/System API 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/ntdll/dbg/dbgui.c 5 * PURPOSE: Native Wrappers for the NT Debug Implementation 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES *****************************************************************/ 10 11 #include <ntdll.h> 12 13 #include <ndk/dbgkfuncs.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 18 /* FUNCTIONS *****************************************************************/ 19 20 /* 21 * @implemented 22 */ 23 NTSTATUS 24 NTAPI 25 DbgUiConnectToDbg(VOID) 26 { 27 OBJECT_ATTRIBUTES ObjectAttributes; 28 29 /* Don't connect twice */ 30 if (NtCurrentTeb()->DbgSsReserved[1]) return STATUS_SUCCESS; 31 32 /* Setup the Attributes */ 33 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, 0); 34 35 /* Create the object */ 36 return ZwCreateDebugObject(&NtCurrentTeb()->DbgSsReserved[1], 37 DEBUG_OBJECT_ALL_ACCESS, 38 &ObjectAttributes, 39 DBGK_KILL_PROCESS_ON_EXIT); 40 } 41 42 /* 43 * @implemented 44 */ 45 NTSTATUS 46 NTAPI 47 DbgUiContinue(IN PCLIENT_ID ClientId, 48 IN NTSTATUS ContinueStatus) 49 { 50 /* Tell the kernel object to continue */ 51 return ZwDebugContinue(NtCurrentTeb()->DbgSsReserved[1], 52 ClientId, 53 ContinueStatus); 54 } 55 56 /* 57 * @implemented 58 */ 59 NTSTATUS 60 NTAPI 61 DbgUiConvertStateChangeStructure(IN PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 62 OUT PVOID Win32DebugEvent) 63 { 64 NTSTATUS Status; 65 THREAD_BASIC_INFORMATION ThreadBasicInfo; 66 LPDEBUG_EVENT DebugEvent = Win32DebugEvent; 67 68 /* Write common data */ 69 DebugEvent->dwProcessId = PtrToUlong(WaitStateChange->AppClientId.UniqueProcess); 70 DebugEvent->dwThreadId = PtrToUlong(WaitStateChange->AppClientId.UniqueThread); 71 72 /* Check what kind of even this is */ 73 switch (WaitStateChange->NewState) 74 { 75 /* New thread */ 76 case DbgCreateThreadStateChange: 77 { 78 /* Setup Win32 code */ 79 DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT; 80 81 /* Copy data over */ 82 DebugEvent->u.CreateThread.hThread = 83 WaitStateChange->StateInfo.CreateThread.HandleToThread; 84 DebugEvent->u.CreateThread.lpStartAddress = 85 WaitStateChange->StateInfo.CreateThread.NewThread.StartAddress; 86 87 /* Query the TEB */ 88 Status = NtQueryInformationThread(WaitStateChange->StateInfo. 89 CreateThread.HandleToThread, 90 ThreadBasicInformation, 91 &ThreadBasicInfo, 92 sizeof(ThreadBasicInfo), 93 NULL); 94 if (!NT_SUCCESS(Status)) 95 { 96 /* Failed to get PEB address */ 97 DebugEvent->u.CreateThread.lpThreadLocalBase = NULL; 98 } 99 else 100 { 101 /* Write PEB Address */ 102 DebugEvent->u.CreateThread.lpThreadLocalBase = 103 ThreadBasicInfo.TebBaseAddress; 104 } 105 break; 106 } 107 108 /* New process */ 109 case DbgCreateProcessStateChange: 110 { 111 /* Write Win32 debug code */ 112 DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT; 113 114 /* Copy data over */ 115 DebugEvent->u.CreateProcessInfo.hProcess = 116 WaitStateChange->StateInfo.CreateProcessInfo.HandleToProcess; 117 DebugEvent->u.CreateProcessInfo.hThread = 118 WaitStateChange->StateInfo.CreateProcessInfo.HandleToThread; 119 DebugEvent->u.CreateProcessInfo.hFile = 120 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. 121 FileHandle; 122 DebugEvent->u.CreateProcessInfo.lpBaseOfImage = 123 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. 124 BaseOfImage; 125 DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset = 126 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. 127 DebugInfoFileOffset; 128 DebugEvent->u.CreateProcessInfo.nDebugInfoSize = 129 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. 130 DebugInfoSize; 131 DebugEvent->u.CreateProcessInfo.lpStartAddress = 132 WaitStateChange->StateInfo.CreateProcessInfo.NewProcess. 133 InitialThread.StartAddress; 134 135 /* Query TEB address */ 136 Status = NtQueryInformationThread(WaitStateChange->StateInfo. 137 CreateProcessInfo.HandleToThread, 138 ThreadBasicInformation, 139 &ThreadBasicInfo, 140 sizeof(ThreadBasicInfo), 141 NULL); 142 if (!NT_SUCCESS(Status)) 143 { 144 /* Failed to get PEB address */ 145 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL; 146 } 147 else 148 { 149 /* Write PEB Address */ 150 DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = 151 ThreadBasicInfo.TebBaseAddress; 152 } 153 154 /* Clear image name */ 155 DebugEvent->u.CreateProcessInfo.lpImageName = NULL; 156 DebugEvent->u.CreateProcessInfo.fUnicode = TRUE; 157 break; 158 } 159 160 /* Thread exited */ 161 case DbgExitThreadStateChange: 162 { 163 /* Write the Win32 debug code and the exit status */ 164 DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT; 165 DebugEvent->u.ExitThread.dwExitCode = 166 WaitStateChange->StateInfo.ExitThread.ExitStatus; 167 break; 168 } 169 170 /* Process exited */ 171 case DbgExitProcessStateChange: 172 { 173 /* Write the Win32 debug code and the exit status */ 174 DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT; 175 DebugEvent->u.ExitProcess.dwExitCode = 176 WaitStateChange->StateInfo.ExitProcess.ExitStatus; 177 break; 178 } 179 180 /* Any sort of exception */ 181 case DbgExceptionStateChange: 182 case DbgBreakpointStateChange: 183 case DbgSingleStepStateChange: 184 { 185 /* Check if this was a debug print */ 186 if (WaitStateChange->StateInfo.Exception.ExceptionRecord. 187 ExceptionCode == DBG_PRINTEXCEPTION_C) 188 { 189 /* Set the Win32 code */ 190 DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT; 191 192 /* Copy debug string information */ 193 DebugEvent->u.DebugString.lpDebugStringData = 194 (PVOID)WaitStateChange-> 195 StateInfo.Exception.ExceptionRecord. 196 ExceptionInformation[1]; 197 DebugEvent->u.DebugString.nDebugStringLength = 198 WaitStateChange->StateInfo.Exception.ExceptionRecord. 199 ExceptionInformation[0]; 200 DebugEvent->u.DebugString.fUnicode = FALSE; 201 } 202 else if (WaitStateChange->StateInfo.Exception.ExceptionRecord. 203 ExceptionCode == DBG_RIPEXCEPTION) 204 { 205 /* Set the Win32 code */ 206 DebugEvent->dwDebugEventCode = RIP_EVENT; 207 208 /* Set exception information */ 209 DebugEvent->u.RipInfo.dwType = 210 WaitStateChange->StateInfo.Exception.ExceptionRecord. 211 ExceptionInformation[1]; 212 DebugEvent->u.RipInfo.dwError = 213 WaitStateChange->StateInfo.Exception.ExceptionRecord. 214 ExceptionInformation[0]; 215 } 216 else 217 { 218 /* Otherwise, this is a debug event, copy info over */ 219 DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT; 220 DebugEvent->u.Exception.ExceptionRecord = 221 WaitStateChange->StateInfo.Exception.ExceptionRecord; 222 DebugEvent->u.Exception.dwFirstChance = 223 WaitStateChange->StateInfo.Exception.FirstChance; 224 } 225 break; 226 } 227 228 /* DLL Load */ 229 case DbgLoadDllStateChange: 230 { 231 /* Set the Win32 debug code */ 232 DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT; 233 234 /* Copy the rest of the data */ 235 DebugEvent->u.LoadDll.hFile = 236 WaitStateChange->StateInfo.LoadDll.FileHandle; 237 DebugEvent->u.LoadDll.lpBaseOfDll = 238 WaitStateChange->StateInfo.LoadDll.BaseOfDll; 239 DebugEvent->u.LoadDll.dwDebugInfoFileOffset = 240 WaitStateChange->StateInfo.LoadDll.DebugInfoFileOffset; 241 DebugEvent->u.LoadDll.nDebugInfoSize = 242 WaitStateChange->StateInfo.LoadDll.DebugInfoSize; 243 DebugEvent->u.LoadDll.lpImageName = 244 WaitStateChange->StateInfo.LoadDll.NamePointer; 245 246 /* It's Unicode */ 247 DebugEvent->u.LoadDll.fUnicode = TRUE; 248 break; 249 } 250 251 /* DLL Unload */ 252 case DbgUnloadDllStateChange: 253 { 254 /* Set Win32 code and DLL Base */ 255 DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT; 256 DebugEvent->u.UnloadDll.lpBaseOfDll = 257 WaitStateChange->StateInfo.UnloadDll.BaseAddress; 258 break; 259 } 260 261 /* Anything else, fail */ 262 default: return STATUS_UNSUCCESSFUL; 263 } 264 265 /* Return success */ 266 return STATUS_SUCCESS; 267 } 268 269 /* 270 * @implemented 271 */ 272 NTSTATUS 273 NTAPI 274 DbgUiWaitStateChange(OUT PDBGUI_WAIT_STATE_CHANGE WaitStateChange, 275 IN PLARGE_INTEGER TimeOut OPTIONAL) 276 { 277 /* Tell the kernel to wait */ 278 return NtWaitForDebugEvent(NtCurrentTeb()->DbgSsReserved[1], 279 TRUE, 280 TimeOut, 281 WaitStateChange); 282 } 283 284 /* 285 * @implemented 286 */ 287 VOID 288 NTAPI 289 DbgUiRemoteBreakin(VOID) 290 { 291 /* Make sure a debugger is enabled; if so, breakpoint */ 292 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint(); 293 294 /* Exit the thread */ 295 RtlExitUserThread(STATUS_SUCCESS); 296 } 297 298 /* 299 * @implemented 300 */ 301 NTSTATUS 302 NTAPI 303 DbgUiIssueRemoteBreakin(IN HANDLE Process) 304 { 305 HANDLE hThread; 306 CLIENT_ID ClientId; 307 NTSTATUS Status; 308 309 /* Create the thread that will do the breakin */ 310 Status = RtlCreateUserThread(Process, 311 NULL, 312 FALSE, 313 0, 314 0, 315 PAGE_SIZE, 316 (PVOID)DbgUiRemoteBreakin, 317 NULL, 318 &hThread, 319 &ClientId); 320 321 /* Close the handle on success */ 322 if(NT_SUCCESS(Status)) NtClose(hThread); 323 324 /* Return status */ 325 return Status; 326 } 327 328 /* 329 * @implemented 330 */ 331 HANDLE 332 NTAPI 333 DbgUiGetThreadDebugObject(VOID) 334 { 335 /* Just return the handle from the TEB */ 336 return NtCurrentTeb()->DbgSsReserved[1]; 337 } 338 339 /* 340 * @implemented 341 */ 342 VOID 343 NTAPI 344 DbgUiSetThreadDebugObject(HANDLE DebugObject) 345 { 346 /* Just set the handle in the TEB */ 347 NtCurrentTeb()->DbgSsReserved[1] = DebugObject; 348 } 349 350 /* 351 * @implemented 352 */ 353 NTSTATUS 354 NTAPI 355 DbgUiDebugActiveProcess(IN HANDLE Process) 356 { 357 NTSTATUS Status; 358 359 /* Tell the kernel to start debugging */ 360 Status = NtDebugActiveProcess(Process, NtCurrentTeb()->DbgSsReserved[1]); 361 if (NT_SUCCESS(Status)) 362 { 363 /* Now break-in the process */ 364 Status = DbgUiIssueRemoteBreakin(Process); 365 if (!NT_SUCCESS(Status)) 366 { 367 /* We couldn't break-in, cancel debugging */ 368 DbgUiStopDebugging(Process); 369 } 370 } 371 372 /* Return status */ 373 return Status; 374 } 375 376 /* 377 * @implemented 378 */ 379 NTSTATUS 380 NTAPI 381 DbgUiStopDebugging(IN HANDLE Process) 382 { 383 /* Call the kernel to remove the debug object */ 384 return NtRemoveProcessDebug(Process, NtCurrentTeb()->DbgSsReserved[1]); 385 } 386 387 /* EOF */ 388