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.

721 lines
17 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dbgkproc.c
  5. Abstract:
  6. This module implements process control primitives for the
  7. Dbg component of NT
  8. Author:
  9. Mark Lucovsky (markl) 19-Jan-1990
  10. Revision History:
  11. --*/
  12. #include "dbgkp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, DbgkpSuspendProcess)
  15. #pragma alloc_text(PAGE, DbgkpResumeProcess)
  16. #pragma alloc_text(PAGE, DbgkpSectionToFileHandle)
  17. #pragma alloc_text(PAGE, DbgkCreateThread)
  18. #pragma alloc_text(PAGE, DbgkExitThread)
  19. #pragma alloc_text(PAGE, DbgkExitProcess)
  20. #pragma alloc_text(PAGE, DbgkMapViewOfSection)
  21. #pragma alloc_text(PAGE, DbgkUnMapViewOfSection)
  22. #endif
  23. BOOLEAN
  24. DbgkpSuspendProcess (
  25. VOID
  26. )
  27. /*++
  28. Routine Description:
  29. This function causes all threads in the calling process except for
  30. the calling thread to suspend.
  31. Arguments:
  32. CreateDeleteLockHeld - Supplies a flag that specifies whether or not
  33. the caller is holding the process create delete lock. If the
  34. caller holds the lock, than this function will not aquire the
  35. lock before suspending the process.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. PAGED_CODE();
  41. //
  42. // Freeze the execution of all threads in the current process, but
  43. // the calling thread. If we are in the process of being deleted don't do this.
  44. //
  45. if ((PsGetCurrentProcess()->Flags&PS_PROCESS_FLAGS_PROCESS_DELETE) == 0) {
  46. KeFreezeAllThreads();
  47. return TRUE;
  48. }
  49. return FALSE;
  50. }
  51. VOID
  52. DbgkpResumeProcess (
  53. VOID
  54. )
  55. /*++
  56. Routine Description:
  57. This function causes all threads in the calling process except for
  58. the calling thread to resume.
  59. Arguments:
  60. CreateDeleteLockHeld - Supplies a flag that specifies whether or not
  61. the caller is holding the process create delete lock. If the
  62. caller holds the lock, than this function will not aquire the
  63. lock before suspending the process.
  64. Return Value:
  65. None.
  66. --*/
  67. {
  68. PAGED_CODE();
  69. //
  70. // Thaw the execution of all threads in the current process, but
  71. // the calling thread.
  72. //
  73. KeThawAllThreads();
  74. return;
  75. }
  76. HANDLE
  77. DbgkpSectionToFileHandle(
  78. IN PVOID SectionObject
  79. )
  80. /*++
  81. Routine Description:
  82. This function Opens a handle to the file associated with the processes
  83. section. The file is opened such that it can be dupped all the way to
  84. the UI where the UI can either map the file or read the file to get
  85. the debug info.
  86. Arguments:
  87. SectionHandle - Supplies a handle to the section whose associated file
  88. is to be opened.
  89. Return Value:
  90. NULL - The file could not be opened.
  91. NON-NULL - Returns a handle to the file associated with the specified
  92. section.
  93. --*/
  94. {
  95. NTSTATUS Status;
  96. ANSI_STRING FileName;
  97. UNICODE_STRING UnicodeFileName;
  98. OBJECT_ATTRIBUTES Obja;
  99. IO_STATUS_BLOCK IoStatusBlock;
  100. HANDLE Handle;
  101. PAGED_CODE();
  102. Status = MmGetFileNameForSection(SectionObject, (PSTRING)&FileName);
  103. if ( !NT_SUCCESS(Status) ) {
  104. return NULL;
  105. }
  106. Status = RtlAnsiStringToUnicodeString(&UnicodeFileName,&FileName,TRUE);
  107. ExFreePool(FileName.Buffer);
  108. if ( !NT_SUCCESS(Status) ) {
  109. return NULL;
  110. }
  111. InitializeObjectAttributes(
  112. &Obja,
  113. &UnicodeFileName,
  114. OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE,
  115. NULL,
  116. NULL
  117. );
  118. Status = ZwOpenFile(
  119. &Handle,
  120. (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
  121. &Obja,
  122. &IoStatusBlock,
  123. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  124. FILE_SYNCHRONOUS_IO_NONALERT
  125. );
  126. RtlFreeUnicodeString(&UnicodeFileName);
  127. if ( !NT_SUCCESS(Status) ) {
  128. return NULL;
  129. }
  130. else {
  131. return Handle;
  132. }
  133. }
  134. VOID
  135. DbgkCreateThread(
  136. PVOID StartAddress
  137. )
  138. /*++
  139. Routine Description:
  140. This function is called when a new thread begins to execute. If the
  141. thread has an associated DebugPort, then a message is sent thru the
  142. port.
  143. If this thread is the first thread in the process, then this event
  144. is translated into a CreateProcessInfo message.
  145. If a message is sent, then while the thread is awaiting a reply,
  146. all other threads in the process are suspended.
  147. Arguments:
  148. StartAddress - Supplies the start address for the thread that is
  149. starting.
  150. Return Value:
  151. None.
  152. --*/
  153. {
  154. PVOID Port;
  155. DBGKM_APIMSG m;
  156. PDBGKM_CREATE_THREAD CreateThreadArgs;
  157. PDBGKM_CREATE_PROCESS CreateProcessArgs;
  158. PETHREAD Thread;
  159. PEPROCESS Process;
  160. PDBGKM_LOAD_DLL LoadDllArgs;
  161. NTSTATUS Status;
  162. OBJECT_ATTRIBUTES Obja;
  163. IO_STATUS_BLOCK IoStatusBlock;
  164. PIMAGE_NT_HEADERS NtHeaders;
  165. PTEB Teb;
  166. PAGED_CODE();
  167. Thread = PsGetCurrentThread ();
  168. Process = PsGetCurrentProcessByThread (Thread);
  169. if (PsImageNotifyEnabled && !Process->Pcb.UserTime) {
  170. IMAGE_INFO ImageInfo;
  171. PIMAGE_NT_HEADERS NtHeaders;
  172. ANSI_STRING FileName;
  173. UNICODE_STRING UnicodeFileName;
  174. PUNICODE_STRING pUnicodeFileName;
  175. //
  176. // notification of main .exe
  177. //
  178. ImageInfo.Properties = 0;
  179. ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
  180. ImageInfo.ImageBase = Process->SectionBaseAddress;
  181. ImageInfo.ImageSize = 0;
  182. try {
  183. NtHeaders = RtlImageNtHeader (Process->SectionBaseAddress);
  184. if (NtHeaders) {
  185. ImageInfo.ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
  186. }
  187. } except (EXCEPTION_EXECUTE_HANDLER) {
  188. ImageInfo.ImageSize = 0;
  189. }
  190. ImageInfo.ImageSelector = 0;
  191. ImageInfo.ImageSectionNumber = 0;
  192. pUnicodeFileName = NULL;
  193. Status = MmGetFileNameForSection (Process->SectionObject, (PSTRING)&FileName);
  194. if (NT_SUCCESS (Status)) {
  195. Status = RtlAnsiStringToUnicodeString (&UnicodeFileName, &FileName,TRUE);
  196. ExFreePool (FileName.Buffer);
  197. if (NT_SUCCESS (Status)) {
  198. pUnicodeFileName = &UnicodeFileName;
  199. }
  200. }
  201. PsCallImageNotifyRoutines (pUnicodeFileName,
  202. Process->UniqueProcessId,
  203. &ImageInfo);
  204. if (pUnicodeFileName != NULL) {
  205. RtlFreeUnicodeString (pUnicodeFileName);
  206. }
  207. //
  208. // and of ntdll.dll
  209. //
  210. ImageInfo.Properties = 0;
  211. ImageInfo.ImageAddressingMode = IMAGE_ADDRESSING_MODE_32BIT;
  212. ImageInfo.ImageBase = PsSystemDllBase;
  213. ImageInfo.ImageSize = 0;
  214. try {
  215. NtHeaders = RtlImageNtHeader (PsSystemDllBase);
  216. if ( NtHeaders ) {
  217. ImageInfo.ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
  218. }
  219. } except(EXCEPTION_EXECUTE_HANDLER) {
  220. ImageInfo.ImageSize = 0;
  221. }
  222. ImageInfo.ImageSelector = 0;
  223. ImageInfo.ImageSectionNumber = 0;
  224. RtlInitUnicodeString (&UnicodeFileName,
  225. L"\\SystemRoot\\System32\\ntdll.dll");
  226. PsCallImageNotifyRoutines (&UnicodeFileName,
  227. Process->UniqueProcessId,
  228. &ImageInfo);
  229. }
  230. Port = Process->DebugPort;
  231. if (Port == NULL) {
  232. return;
  233. }
  234. //
  235. // If we are doing a debug attach, then the create process has
  236. // already occured. If this is the case, then the process has
  237. // accumulated some time, so set reported to true
  238. //
  239. if (Process->Pcb.UserTime) {
  240. PS_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_CREATE_REPORTED);
  241. }
  242. if ((PS_TEST_SET_BITS (&Process->Flags, PS_PROCESS_FLAGS_CREATE_REPORTED)&PS_PROCESS_FLAGS_CREATE_REPORTED) == 0) {
  243. //
  244. // This is a create process
  245. //
  246. CreateThreadArgs = &m.u.CreateProcessInfo.InitialThread;
  247. CreateThreadArgs->SubSystemKey = 0;
  248. CreateProcessArgs = &m.u.CreateProcessInfo;
  249. CreateProcessArgs->SubSystemKey = 0;
  250. CreateProcessArgs->FileHandle = DbgkpSectionToFileHandle(
  251. Process->SectionObject
  252. );
  253. CreateProcessArgs->BaseOfImage = Process->SectionBaseAddress;
  254. CreateThreadArgs->StartAddress = NULL;
  255. CreateProcessArgs->DebugInfoFileOffset = 0;
  256. CreateProcessArgs->DebugInfoSize = 0;
  257. try {
  258. NtHeaders = RtlImageNtHeader(Process->SectionBaseAddress);
  259. if ( NtHeaders ) {
  260. CreateThreadArgs->StartAddress = (PVOID)(
  261. NtHeaders->OptionalHeader.ImageBase +
  262. NtHeaders->OptionalHeader.AddressOfEntryPoint);
  263. CreateProcessArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  264. CreateProcessArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  265. }
  266. } except (EXCEPTION_EXECUTE_HANDLER) {
  267. CreateThreadArgs->StartAddress = NULL;
  268. CreateProcessArgs->DebugInfoFileOffset = 0;
  269. CreateProcessArgs->DebugInfoSize = 0;
  270. }
  271. DBGKM_FORMAT_API_MSG(m,DbgKmCreateProcessApi,sizeof(*CreateProcessArgs));
  272. DbgkpSendApiMessage(&m,FALSE);
  273. if (CreateProcessArgs->FileHandle != NULL) {
  274. ObCloseHandle(CreateProcessArgs->FileHandle, KernelMode);
  275. }
  276. LoadDllArgs = &m.u.LoadDll;
  277. LoadDllArgs->BaseOfDll = PsSystemDllBase;
  278. LoadDllArgs->DebugInfoFileOffset = 0;
  279. LoadDllArgs->DebugInfoSize = 0;
  280. Teb = NULL;
  281. try {
  282. NtHeaders = RtlImageNtHeader(PsSystemDllBase);
  283. if ( NtHeaders ) {
  284. LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  285. LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  286. }
  287. //
  288. // Normaly the ntdll loaded fills in this pointer for the debug API's. We fake it here
  289. // as ntdll isn't loaded yet and it can't load itself.
  290. //
  291. Teb = Thread->Tcb.Teb;
  292. if (Teb != NULL) {
  293. Teb->NtTib.ArbitraryUserPointer = Teb->StaticUnicodeBuffer;
  294. wcsncpy (Teb->StaticUnicodeBuffer,
  295. L"ntdll.dll",
  296. sizeof (Teb->StaticUnicodeBuffer) / sizeof (Teb->StaticUnicodeBuffer[0]));
  297. }
  298. } except (EXCEPTION_EXECUTE_HANDLER) {
  299. LoadDllArgs->DebugInfoFileOffset = 0;
  300. LoadDllArgs->DebugInfoSize = 0;
  301. }
  302. //
  303. // Send load dll section for NT dll !
  304. //
  305. InitializeObjectAttributes(
  306. &Obja,
  307. (PUNICODE_STRING)&PsNtDllPathName,
  308. OBJ_CASE_INSENSITIVE | OBJ_FORCE_ACCESS_CHECK | OBJ_KERNEL_HANDLE,
  309. NULL,
  310. NULL
  311. );
  312. Status = ZwOpenFile(
  313. &LoadDllArgs->FileHandle,
  314. (ACCESS_MASK)(GENERIC_READ | SYNCHRONIZE),
  315. &Obja,
  316. &IoStatusBlock,
  317. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  318. FILE_SYNCHRONOUS_IO_NONALERT
  319. );
  320. if (!NT_SUCCESS (Status)) {
  321. LoadDllArgs->FileHandle = NULL;
  322. }
  323. DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
  324. DbgkpSendApiMessage(&m,TRUE);
  325. if (LoadDllArgs->FileHandle != NULL) {
  326. ObCloseHandle(LoadDllArgs->FileHandle, KernelMode);
  327. }
  328. if (Teb != NULL) {
  329. try {
  330. Teb->NtTib.ArbitraryUserPointer = NULL;
  331. } except(EXCEPTION_EXECUTE_HANDLER) {
  332. }
  333. }
  334. } else {
  335. CreateThreadArgs = &m.u.CreateThread;
  336. CreateThreadArgs->SubSystemKey = 0;
  337. CreateThreadArgs->StartAddress = StartAddress;
  338. DBGKM_FORMAT_API_MSG (m,DbgKmCreateThreadApi,sizeof(*CreateThreadArgs));
  339. DbgkpSendApiMessage (&m,TRUE);
  340. }
  341. }
  342. VOID
  343. DbgkExitThread(
  344. NTSTATUS ExitStatus
  345. )
  346. /*++
  347. Routine Description:
  348. This function is called when a new thread terminates. At this
  349. point, the thread will no longer execute in user-mode. No other
  350. exit processing has occured.
  351. If a message is sent, then while the thread is awaiting a reply,
  352. all other threads in the process are suspended.
  353. Arguments:
  354. ExitStatus - Supplies the ExitStatus of the exiting thread.
  355. Return Value:
  356. None.
  357. --*/
  358. {
  359. PVOID Port;
  360. DBGKM_APIMSG m;
  361. PDBGKM_EXIT_THREAD args;
  362. PEPROCESS Process;
  363. BOOLEAN Frozen;
  364. PAGED_CODE();
  365. Process = PsGetCurrentProcess();
  366. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
  367. Port = NULL;
  368. } else {
  369. Port = Process->DebugPort;
  370. }
  371. if ( !Port ) {
  372. return;
  373. }
  374. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) {
  375. return;
  376. }
  377. args = &m.u.ExitThread;
  378. args->ExitStatus = ExitStatus;
  379. DBGKM_FORMAT_API_MSG(m,DbgKmExitThreadApi,sizeof(*args));
  380. Frozen = DbgkpSuspendProcess();
  381. DbgkpSendApiMessage(&m,FALSE);
  382. if (Frozen) {
  383. DbgkpResumeProcess();
  384. }
  385. }
  386. VOID
  387. DbgkExitProcess(
  388. NTSTATUS ExitStatus
  389. )
  390. /*++
  391. Routine Description:
  392. This function is called when a process terminates. The address
  393. space of the process is still intact, but no threads exist in
  394. the process.
  395. Arguments:
  396. ExitStatus - Supplies the ExitStatus of the exiting process.
  397. Return Value:
  398. None.
  399. --*/
  400. {
  401. PVOID Port;
  402. DBGKM_APIMSG m;
  403. PDBGKM_EXIT_PROCESS args;
  404. PEPROCESS Process;
  405. PAGED_CODE();
  406. Process = PsGetCurrentProcess();
  407. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
  408. Port = NULL;
  409. } else {
  410. Port = Process->DebugPort;
  411. }
  412. if ( !Port ) {
  413. return;
  414. }
  415. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_DEADTHREAD) {
  416. return;
  417. }
  418. //
  419. // this ensures that other timed lockers of the process will bail
  420. // since this call is done while holding the process lock, and lock duration
  421. // is controlled by debugger
  422. //
  423. KeQuerySystemTime(&PsGetCurrentProcess()->ExitTime);
  424. args = &m.u.ExitProcess;
  425. args->ExitStatus = ExitStatus;
  426. DBGKM_FORMAT_API_MSG(m,DbgKmExitProcessApi,sizeof(*args));
  427. DbgkpSendApiMessage(&m,FALSE);
  428. }
  429. VOID
  430. DbgkMapViewOfSection(
  431. IN PVOID SectionObject,
  432. IN PVOID BaseAddress,
  433. IN ULONG SectionOffset,
  434. IN ULONG_PTR ViewSize
  435. )
  436. /*++
  437. Routine Description:
  438. This function is called when the current process successfully
  439. maps a view of an image section. If the process has an associated
  440. debug port, then a load dll message is sent.
  441. Arguments:
  442. SectionObject - Supplies a pointer to the section mapped by the
  443. process.
  444. BaseAddress - Supplies the base address of where the section is
  445. mapped in the current process address space.
  446. SectionOffset - Supplies the offset in the section where the
  447. processes mapped view begins.
  448. ViewSize - Supplies the size of the mapped view.
  449. Return Value:
  450. None.
  451. --*/
  452. {
  453. PVOID Port;
  454. DBGKM_APIMSG m;
  455. PDBGKM_LOAD_DLL LoadDllArgs;
  456. PEPROCESS Process;
  457. PIMAGE_NT_HEADERS NtHeaders;
  458. PAGED_CODE();
  459. UNREFERENCED_PARAMETER (SectionOffset);
  460. UNREFERENCED_PARAMETER (ViewSize);
  461. if ( KeGetPreviousMode() == KernelMode ) {
  462. return;
  463. }
  464. Process = PsGetCurrentProcess();
  465. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
  466. Port = NULL;
  467. } else {
  468. Port = Process->DebugPort;
  469. }
  470. if ( !Port ) {
  471. return;
  472. }
  473. LoadDllArgs = &m.u.LoadDll;
  474. LoadDllArgs->FileHandle = DbgkpSectionToFileHandle(SectionObject);
  475. LoadDllArgs->BaseOfDll = BaseAddress;
  476. LoadDllArgs->DebugInfoFileOffset = 0;
  477. LoadDllArgs->DebugInfoSize = 0;
  478. try {
  479. NtHeaders = RtlImageNtHeader(BaseAddress);
  480. if ( NtHeaders ) {
  481. LoadDllArgs->DebugInfoFileOffset = NtHeaders->FileHeader.PointerToSymbolTable;
  482. LoadDllArgs->DebugInfoSize = NtHeaders->FileHeader.NumberOfSymbols;
  483. }
  484. }
  485. except(EXCEPTION_EXECUTE_HANDLER) {
  486. LoadDllArgs->DebugInfoFileOffset = 0;
  487. LoadDllArgs->DebugInfoSize = 0;
  488. }
  489. DBGKM_FORMAT_API_MSG(m,DbgKmLoadDllApi,sizeof(*LoadDllArgs));
  490. DbgkpSendApiMessage(&m,TRUE);
  491. if (LoadDllArgs->FileHandle != NULL) {
  492. ObCloseHandle(LoadDllArgs->FileHandle, KernelMode);
  493. }
  494. }
  495. VOID
  496. DbgkUnMapViewOfSection(
  497. IN PVOID BaseAddress
  498. )
  499. /*++
  500. Routine Description:
  501. This function is called when the current process successfully
  502. un maps a view of an image section. If the process has an associated
  503. debug port, then an "unmap view of section" message is sent.
  504. Arguments:
  505. BaseAddress - Supplies the base address of the section being
  506. unmapped.
  507. Return Value:
  508. None.
  509. --*/
  510. {
  511. PVOID Port;
  512. DBGKM_APIMSG m;
  513. PDBGKM_UNLOAD_DLL UnloadDllArgs;
  514. PEPROCESS Process;
  515. PAGED_CODE();
  516. Process = PsGetCurrentProcess();
  517. if ( KeGetPreviousMode() == KernelMode ) {
  518. return;
  519. }
  520. if (PsGetCurrentThread()->CrossThreadFlags&PS_CROSS_THREAD_FLAGS_HIDEFROMDBG) {
  521. Port = NULL;
  522. } else {
  523. Port = Process->DebugPort;
  524. }
  525. if ( !Port ) {
  526. return;
  527. }
  528. UnloadDllArgs = &m.u.UnloadDll;
  529. UnloadDllArgs->BaseAddress = BaseAddress;
  530. DBGKM_FORMAT_API_MSG(m,DbgKmUnloadDllApi,sizeof(*UnloadDllArgs));
  531. DbgkpSendApiMessage(&m,TRUE);
  532. }