Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

522 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dlluistb.c
  5. Abstract:
  6. Debug Subsystem DbgUi API Stubs
  7. Author:
  8. Mark Lucovsky (markl) 23-Jan-1990
  9. Revision History:
  10. Neill Clift 27-Apr-2000 - Rehashed to call new kernel API's for process debugging
  11. --*/
  12. #include "dbgdllp.h"
  13. #include "windows.h"
  14. #define DbgUiDebugObjectHandle (NtCurrentTeb()->DbgSsReserved[1])
  15. NTSTATUS
  16. DbgUiConnectToDbg( VOID )
  17. /*++
  18. Routine Description:
  19. This routine makes a connection between the caller and the DbgUi
  20. port in the Dbg subsystem. In addition to returning a handle to a
  21. port object, a handle to a state change semaphore is returned. This
  22. semaphore is used in DbgUiWaitStateChange APIs.
  23. Arguments:
  24. None.
  25. Return Value:
  26. TBD.
  27. --*/
  28. {
  29. NTSTATUS st;
  30. OBJECT_ATTRIBUTES oa;
  31. //
  32. // if app is already connected, don't reconnect
  33. //
  34. st = STATUS_SUCCESS;
  35. if ( !DbgUiDebugObjectHandle ) {
  36. InitializeObjectAttributes (&oa, NULL, 0, NULL, NULL);
  37. st = NtCreateDebugObject (&DbgUiDebugObjectHandle,
  38. DEBUG_ALL_ACCESS,
  39. &oa,
  40. DEBUG_KILL_ON_CLOSE);
  41. }
  42. return st;
  43. }
  44. HANDLE
  45. DbgUiGetThreadDebugObject (
  46. )
  47. /*++
  48. Routine Description:
  49. This function returns the current threads debug port handle if it has one.
  50. Arguments:
  51. None
  52. Return Value:
  53. HANDLE - Debug port handle;
  54. --*/
  55. {
  56. return DbgUiDebugObjectHandle;
  57. }
  58. VOID
  59. DbgUiSetThreadDebugObject (
  60. IN HANDLE DebugObject
  61. )
  62. /*++
  63. Routine Description:
  64. This function sets the current thread's debug port handle.
  65. Any previous value is simply overwritten; there is no
  66. automatic close of a previous handle.
  67. Arguments:
  68. DebugObject - Debug object handle to set.
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. DbgUiDebugObjectHandle = DebugObject;
  74. }
  75. NTSTATUS
  76. DbgUiWaitStateChange (
  77. OUT PDBGUI_WAIT_STATE_CHANGE StateChange,
  78. IN PLARGE_INTEGER Timeout OPTIONAL
  79. )
  80. /*++
  81. Routine Description:
  82. This function causes the calling user interface to wait for a
  83. state change to occur in one of it's application threads. The
  84. wait is ALERTABLE.
  85. Arguments:
  86. StateChange - Supplies the address of state change record that
  87. will contain the state change information.
  88. Return Value:
  89. TBD
  90. --*/
  91. {
  92. NTSTATUS st;
  93. //
  94. // Wait for a StateChange to occur
  95. //
  96. st = NtWaitForDebugEvent (DbgUiDebugObjectHandle,
  97. TRUE,
  98. Timeout,
  99. StateChange);
  100. return st;
  101. }
  102. NTSTATUS
  103. DbgUiContinue (
  104. IN PCLIENT_ID AppClientId,
  105. IN NTSTATUS ContinueStatus
  106. )
  107. /*++
  108. Routine Description:
  109. This function continues an application thread whose state change was
  110. previously reported through DbgUiWaitStateChange.
  111. Arguments:
  112. AppClientId - Supplies the address of the ClientId of the
  113. application thread being continued. This must be an application
  114. thread that previously notified the caller through
  115. DbgUiWaitStateChange but has not yet been continued.
  116. ContinueStatus - Supplies the continuation status to the thread
  117. being continued. valid values for this are:
  118. DBG_EXCEPTION_HANDLED
  119. DBG_EXCEPTION_NOT_HANDLED
  120. DBG_TERMINATE_THREAD
  121. DBG_TERMINATE_PROCESS
  122. DBG_CONTINUE
  123. Return Value:
  124. STATUS_SUCCESS - Successful call to DbgUiContinue
  125. STATUS_INVALID_CID - An invalid ClientId was specified for the
  126. AppClientId, or the specified Application was not waiting
  127. for a continue.
  128. STATUS_INVALID_PARAMETER - An invalid continue status was specified.
  129. --*/
  130. {
  131. NTSTATUS st;
  132. st = NtDebugContinue (DbgUiDebugObjectHandle,
  133. AppClientId,
  134. ContinueStatus);
  135. return st;
  136. }
  137. NTSTATUS
  138. DbgUiStopDebugging (
  139. IN HANDLE Process
  140. )
  141. /*++
  142. Routine Description:
  143. This function stops debugging the specified process
  144. Arguments:
  145. Process - Process handle of process being debugged
  146. Return Value:
  147. NTSTATUS - Status of call
  148. --*/
  149. {
  150. NTSTATUS st;
  151. st = NtRemoveProcessDebug (Process,
  152. DbgUiDebugObjectHandle);
  153. return st;
  154. }
  155. VOID
  156. DbgUiRemoteBreakin (
  157. IN PVOID Context
  158. )
  159. /*++
  160. Routine Description:
  161. This function starts debugging the target process
  162. Arguments:
  163. Context - Thread context
  164. Return Value:
  165. None
  166. --*/
  167. {
  168. //
  169. // We need to cover the case here where the caller detaches the debugger
  170. // (or the debugger fails and the port is removed by
  171. // the kernel). In this case by the time we execute the debugger may be
  172. // gone. Test first that the debugger is present and if it
  173. // is call the breakpoint routine in a try/except block so if it goes
  174. // away now we unwind and just exit this thread.
  175. //
  176. if ((NtCurrentPeb()->BeingDebugged) ||
  177. (USER_SHARED_DATA->KdDebuggerEnabled & 0x00000002)) {
  178. try {
  179. DbgBreakPoint();
  180. } except (EXCEPTION_EXECUTE_HANDLER) {
  181. }
  182. }
  183. RtlExitUserThread (STATUS_SUCCESS);
  184. }
  185. NTSTATUS
  186. DbgUiIssueRemoteBreakin (
  187. IN HANDLE Process
  188. )
  189. /*++
  190. Routine Description:
  191. This function creates a remote thread int he target process to break in
  192. Arguments:
  193. Process - Process to debug
  194. Return Value:
  195. NTSTATUS - Status of call
  196. --*/
  197. {
  198. NTSTATUS Status, Status1;
  199. HANDLE Thread;
  200. CLIENT_ID ClientId;
  201. Status = RtlCreateUserThread (Process,
  202. NULL,
  203. FALSE,
  204. 0,
  205. 0,
  206. 0,
  207. (PUSER_THREAD_START_ROUTINE) DbgUiRemoteBreakin,
  208. NULL,
  209. &Thread,
  210. &ClientId);
  211. if (NT_SUCCESS (Status)) {
  212. Status1 = NtClose (Thread);
  213. ASSERT (NT_SUCCESS (Status1));
  214. }
  215. return Status;
  216. }
  217. NTSTATUS
  218. DbgUiDebugActiveProcess (
  219. IN HANDLE Process
  220. )
  221. /*++
  222. Routine Description:
  223. This function starts debugging the target process
  224. Arguments:
  225. dwProcessId - Process ID of process being debugged
  226. Return Value:
  227. NTSTATUS - Status of call
  228. --*/
  229. {
  230. NTSTATUS Status, Status1;
  231. Status = NtDebugActiveProcess (Process,
  232. DbgUiDebugObjectHandle);
  233. if (NT_SUCCESS (Status)) {
  234. Status = DbgUiIssueRemoteBreakin (Process);
  235. if (!NT_SUCCESS (Status)) {
  236. Status1 = DbgUiStopDebugging (Process);
  237. }
  238. }
  239. return Status;
  240. }
  241. NTSTATUS
  242. DbgUiConvertStateChangeStructure (
  243. IN PDBGUI_WAIT_STATE_CHANGE StateChange,
  244. OUT LPDEBUG_EVENT DebugEvent)
  245. /*++
  246. Routine Description:
  247. This function converts the internal state change record to the win32 structure.
  248. Arguments:
  249. StateChange - Native debugger event structure
  250. DebugEvent - Win32 structure
  251. Return Value:
  252. NTSTATUS - Status of call
  253. --*/
  254. {
  255. NTSTATUS Status;
  256. HANDLE hThread;
  257. THREAD_BASIC_INFORMATION ThreadBasicInfo;
  258. OBJECT_ATTRIBUTES Obja;
  259. DebugEvent->dwProcessId = HandleToUlong (StateChange->AppClientId.UniqueProcess);
  260. DebugEvent->dwThreadId = HandleToUlong (StateChange->AppClientId.UniqueThread);
  261. switch (StateChange->NewState) {
  262. case DbgCreateThreadStateChange :
  263. DebugEvent->dwDebugEventCode = CREATE_THREAD_DEBUG_EVENT;
  264. DebugEvent->u.CreateThread.hThread =
  265. StateChange->StateInfo.CreateThread.HandleToThread;
  266. DebugEvent->u.CreateThread.lpStartAddress =
  267. (LPTHREAD_START_ROUTINE)StateChange->StateInfo.CreateThread.NewThread.StartAddress;
  268. Status = NtQueryInformationThread (StateChange->StateInfo.CreateThread.HandleToThread,
  269. ThreadBasicInformation,
  270. &ThreadBasicInfo,
  271. sizeof (ThreadBasicInfo),
  272. NULL);
  273. if (!NT_SUCCESS (Status)) {
  274. DebugEvent->u.CreateThread.lpThreadLocalBase = NULL;
  275. } else {
  276. DebugEvent->u.CreateThread.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress;
  277. }
  278. break;
  279. case DbgCreateProcessStateChange :
  280. DebugEvent->dwDebugEventCode = CREATE_PROCESS_DEBUG_EVENT;
  281. DebugEvent->u.CreateProcessInfo.hProcess =
  282. StateChange->StateInfo.CreateProcessInfo.HandleToProcess;
  283. DebugEvent->u.CreateProcessInfo.hThread =
  284. StateChange->StateInfo.CreateProcessInfo.HandleToThread;
  285. DebugEvent->u.CreateProcessInfo.hFile =
  286. StateChange->StateInfo.CreateProcessInfo.NewProcess.FileHandle;
  287. DebugEvent->u.CreateProcessInfo.lpBaseOfImage =
  288. StateChange->StateInfo.CreateProcessInfo.NewProcess.BaseOfImage;
  289. DebugEvent->u.CreateProcessInfo.dwDebugInfoFileOffset =
  290. StateChange->StateInfo.CreateProcessInfo.NewProcess.DebugInfoFileOffset;
  291. DebugEvent->u.CreateProcessInfo.nDebugInfoSize =
  292. StateChange->StateInfo.CreateProcessInfo.NewProcess.DebugInfoSize;
  293. DebugEvent->u.CreateProcessInfo.lpStartAddress =
  294. (LPTHREAD_START_ROUTINE)StateChange->StateInfo.CreateProcessInfo.NewProcess.InitialThread.StartAddress;
  295. Status = NtQueryInformationThread (StateChange->StateInfo.CreateProcessInfo.HandleToThread,
  296. ThreadBasicInformation,
  297. &ThreadBasicInfo,
  298. sizeof (ThreadBasicInfo),
  299. NULL);
  300. if (!NT_SUCCESS (Status)) {
  301. DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = NULL;
  302. } else {
  303. DebugEvent->u.CreateProcessInfo.lpThreadLocalBase = ThreadBasicInfo.TebBaseAddress;
  304. }
  305. DebugEvent->u.CreateProcessInfo.lpImageName = NULL;
  306. DebugEvent->u.CreateProcessInfo.fUnicode = 1;
  307. break;
  308. case DbgExitThreadStateChange :
  309. DebugEvent->dwDebugEventCode = EXIT_THREAD_DEBUG_EVENT;
  310. DebugEvent->u.ExitThread.dwExitCode = (DWORD)StateChange->StateInfo.ExitThread.ExitStatus;
  311. break;
  312. case DbgExitProcessStateChange :
  313. DebugEvent->dwDebugEventCode = EXIT_PROCESS_DEBUG_EVENT;
  314. DebugEvent->u.ExitProcess.dwExitCode = (DWORD)StateChange->StateInfo.ExitProcess.ExitStatus;
  315. break;
  316. case DbgExceptionStateChange :
  317. case DbgBreakpointStateChange :
  318. case DbgSingleStepStateChange :
  319. if (StateChange->StateInfo.Exception.ExceptionRecord.ExceptionCode == DBG_PRINTEXCEPTION_C) {
  320. DebugEvent->dwDebugEventCode = OUTPUT_DEBUG_STRING_EVENT;
  321. DebugEvent->u.DebugString.lpDebugStringData =
  322. (PVOID)StateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[1];
  323. DebugEvent->u.DebugString.nDebugStringLength =
  324. (WORD)StateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[0];
  325. DebugEvent->u.DebugString.fUnicode = (WORD)0;
  326. } else if (StateChange->StateInfo.Exception.ExceptionRecord.ExceptionCode == DBG_RIPEXCEPTION) {
  327. DebugEvent->dwDebugEventCode = RIP_EVENT;
  328. DebugEvent->u.RipInfo.dwType =
  329. (DWORD)StateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[1];
  330. DebugEvent->u.RipInfo.dwError =
  331. (DWORD)StateChange->StateInfo.Exception.ExceptionRecord.ExceptionInformation[0];
  332. } else {
  333. DebugEvent->dwDebugEventCode = EXCEPTION_DEBUG_EVENT;
  334. DebugEvent->u.Exception.ExceptionRecord =
  335. StateChange->StateInfo.Exception.ExceptionRecord;
  336. DebugEvent->u.Exception.dwFirstChance =
  337. StateChange->StateInfo.Exception.FirstChance;
  338. }
  339. break;
  340. case DbgLoadDllStateChange :
  341. DebugEvent->dwDebugEventCode = LOAD_DLL_DEBUG_EVENT;
  342. DebugEvent->u.LoadDll.lpBaseOfDll =
  343. StateChange->StateInfo.LoadDll.BaseOfDll;
  344. DebugEvent->u.LoadDll.hFile =
  345. StateChange->StateInfo.LoadDll.FileHandle;
  346. DebugEvent->u.LoadDll.dwDebugInfoFileOffset =
  347. StateChange->StateInfo.LoadDll.DebugInfoFileOffset;
  348. DebugEvent->u.LoadDll.nDebugInfoSize =
  349. StateChange->StateInfo.LoadDll.DebugInfoSize;
  350. //
  351. // pick up the image name
  352. //
  353. InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL);
  354. Status = NtOpenThread (&hThread,
  355. THREAD_QUERY_INFORMATION,
  356. &Obja,
  357. &StateChange->AppClientId);
  358. if (NT_SUCCESS (Status)) {
  359. Status = NtQueryInformationThread (hThread,
  360. ThreadBasicInformation,
  361. &ThreadBasicInfo,
  362. sizeof (ThreadBasicInfo),
  363. NULL);
  364. NtClose (hThread);
  365. }
  366. if (NT_SUCCESS (Status)) {
  367. DebugEvent->u.LoadDll.lpImageName = &ThreadBasicInfo.TebBaseAddress->NtTib.ArbitraryUserPointer;
  368. } else {
  369. DebugEvent->u.LoadDll.lpImageName = NULL;
  370. }
  371. DebugEvent->u.LoadDll.fUnicode = 1;
  372. break;
  373. case DbgUnloadDllStateChange :
  374. DebugEvent->dwDebugEventCode = UNLOAD_DLL_DEBUG_EVENT;
  375. DebugEvent->u.UnloadDll.lpBaseOfDll =
  376. StateChange->StateInfo.UnloadDll.BaseAddress;
  377. break;
  378. default:
  379. return STATUS_UNSUCCESSFUL;
  380. }
  381. return STATUS_SUCCESS;
  382. }