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.

610 lines
15 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. process.c
  5. Abstract:
  6. This module maintains state about each process/thread created by the application
  7. setup/install program.
  8. Author:
  9. Steve Wood (stevewo) 09-Aug-1994
  10. Revision History:
  11. --*/
  12. #include "instaler.h"
  13. BOOLEAN
  14. AddProcess(
  15. LPDEBUG_EVENT DebugEvent,
  16. PPROCESS_INFO *ReturnedProcess
  17. )
  18. {
  19. NTSTATUS Status;
  20. PPROCESS_INFO Process;
  21. RTL_USER_PROCESS_PARAMETERS ProcessParameters;
  22. PEB Peb;
  23. PWSTR FreeBuffer, s;
  24. Process = AllocMem( sizeof( *Process ) );
  25. if (Process == NULL) {
  26. return FALSE;
  27. }
  28. Process->Id = DebugEvent->dwProcessId;
  29. Process->Handle = DebugEvent->u.CreateProcessInfo.hProcess;
  30. InitializeListHead( &Process->ThreadListHead );
  31. InitializeListHead( &Process->BreakpointListHead );
  32. InitializeListHead( &Process->OpenHandleListHead );
  33. InsertTailList( &ProcessListHead, &Process->Entry );
  34. *ReturnedProcess = Process;
  35. Status = NtQueryInformationProcess( Process->Handle,
  36. ProcessBasicInformation,
  37. &Process->ProcessInformation,
  38. sizeof( Process->ProcessInformation ),
  39. NULL
  40. );
  41. FreeBuffer = NULL;
  42. if (ReadMemory( Process,
  43. Process->ProcessInformation.PebBaseAddress,
  44. &Peb,
  45. sizeof( Peb ),
  46. "PEB"
  47. ) &&
  48. Peb.ProcessParameters != NULL &&
  49. ReadMemory( Process,
  50. Peb.ProcessParameters,
  51. &ProcessParameters,
  52. sizeof( ProcessParameters ),
  53. "ProcessParameters"
  54. ) &&
  55. ProcessParameters.ImagePathName.Length != 0 &&
  56. (FreeBuffer = AllocMem( ProcessParameters.ImagePathName.Length + sizeof( UNICODE_NULL ) )) != NULL &&
  57. ReadMemory( Process,
  58. ProcessParameters.Flags & RTL_USER_PROC_PARAMS_NORMALIZED ?
  59. ProcessParameters.ImagePathName.Buffer :
  60. (PWSTR)((ULONG)(ProcessParameters.ImagePathName.Buffer) + (PCHAR)(Peb.ProcessParameters)),
  61. FreeBuffer,
  62. ProcessParameters.ImagePathName.Length,
  63. "Image File Name"
  64. )
  65. ) {
  66. s = (PWSTR)((PCHAR)FreeBuffer + ProcessParameters.ImagePathName.Length);
  67. while (s > FreeBuffer && s[ -1 ] != OBJ_NAME_PATH_SEPARATOR) {
  68. s--;
  69. }
  70. wcsncpy( Process->ImageFileName,
  71. s,
  72. (sizeof( Process->ImageFileName ) - sizeof( UNICODE_NULL )) / sizeof( WCHAR )
  73. );
  74. }
  75. FreeMem( &FreeBuffer );
  76. return TRUE;
  77. }
  78. BOOLEAN
  79. DeleteProcess(
  80. PPROCESS_INFO Process
  81. )
  82. {
  83. PLIST_ENTRY Next, Head;
  84. PTHREAD_INFO Thread;
  85. PBREAKPOINT_INFO Breakpoint;
  86. POPENHANDLE_INFO p;
  87. RemoveEntryList( &Process->Entry );
  88. Head = &Process->ThreadListHead;
  89. Next = Head->Flink;
  90. while (Next != Head) {
  91. Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
  92. Next = Next->Flink;
  93. DeleteThread( Process, Thread );
  94. }
  95. Head = &Process->BreakpointListHead;
  96. Next = Head->Flink;
  97. while (Next != Head) {
  98. Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
  99. Next = Next->Flink;
  100. DestroyBreakpoint( Breakpoint->Address, Process, NULL );
  101. }
  102. Head = &Process->OpenHandleListHead;
  103. Next = Head->Flink;
  104. while (Next != Head) {
  105. p = CONTAINING_RECORD( Next, OPENHANDLE_INFO, Entry );
  106. Next = Next->Flink;
  107. DeleteOpenHandle( Process, p->Handle, p->Type );
  108. }
  109. FreeMem( &Process );
  110. return TRUE;
  111. }
  112. BOOLEAN
  113. AddThread(
  114. LPDEBUG_EVENT DebugEvent,
  115. PPROCESS_INFO Process,
  116. PTHREAD_INFO *ReturnedThread
  117. )
  118. {
  119. PTHREAD_INFO Thread;
  120. Thread = AllocMem( sizeof( *Thread ) );
  121. if (Thread == NULL) {
  122. return FALSE;
  123. }
  124. Thread->Id = DebugEvent->dwThreadId;
  125. if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
  126. Thread->Handle = DebugEvent->u.CreateProcessInfo.hThread;
  127. Thread->StartAddress = DebugEvent->u.CreateProcessInfo.lpStartAddress;
  128. }
  129. else {
  130. Thread->Handle = DebugEvent->u.CreateThread.hThread;
  131. Thread->StartAddress = DebugEvent->u.CreateThread.lpStartAddress;
  132. }
  133. Thread->SingleStepExpected = FALSE;
  134. InitializeListHead( &Thread->BreakpointListHead );
  135. InsertTailList( &Process->ThreadListHead, &Thread->Entry );
  136. *ReturnedThread = Thread;
  137. return TRUE;
  138. }
  139. BOOLEAN
  140. DeleteThread(
  141. PPROCESS_INFO Process,
  142. PTHREAD_INFO Thread
  143. )
  144. {
  145. PLIST_ENTRY Next, Head;
  146. PBREAKPOINT_INFO Breakpoint;
  147. RemoveEntryList( &Thread->Entry );
  148. Head = &Thread->BreakpointListHead;
  149. Next = Head->Flink;
  150. while (Next != Head) {
  151. Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
  152. Next = Next->Flink;
  153. DestroyBreakpoint( Breakpoint->Address, Process, Thread );
  154. }
  155. FreeMem( &Thread );
  156. return TRUE;
  157. }
  158. PPROCESS_INFO
  159. FindProcessById(
  160. ULONG Id
  161. )
  162. {
  163. PLIST_ENTRY Next, Head;
  164. PPROCESS_INFO Process;
  165. Head = &ProcessListHead;
  166. Next = Head->Flink;
  167. while (Next != Head) {
  168. Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry );
  169. if (Process->Id == Id) {
  170. return Process;
  171. }
  172. Next = Next->Flink;
  173. }
  174. return NULL;
  175. }
  176. BOOLEAN
  177. FindProcessAndThreadForEvent(
  178. LPDEBUG_EVENT DebugEvent,
  179. PPROCESS_INFO *ReturnedProcess,
  180. PTHREAD_INFO *ReturnedThread
  181. )
  182. {
  183. PLIST_ENTRY Next, Head;
  184. PPROCESS_INFO Process;
  185. PTHREAD_INFO Thread;
  186. Head = &ProcessListHead;
  187. Next = Head->Flink;
  188. Process = NULL;
  189. Thread = NULL;
  190. while (Next != Head) {
  191. Process = CONTAINING_RECORD( Next, PROCESS_INFO, Entry );
  192. if (Process->Id == DebugEvent->dwProcessId) {
  193. Head = &Process->ThreadListHead;
  194. Next = Head->Flink;
  195. while (Next != Head) {
  196. Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
  197. if (Thread->Id == DebugEvent->dwThreadId) {
  198. break;
  199. }
  200. Thread = NULL;
  201. Next = Next->Flink;
  202. }
  203. break;
  204. }
  205. Process = NULL;
  206. Next = Next->Flink;
  207. }
  208. *ReturnedProcess = Process;
  209. *ReturnedThread = Thread;
  210. if (DebugEvent->dwDebugEventCode == CREATE_PROCESS_DEBUG_EVENT) {
  211. if (Process != NULL) {
  212. DeclareError( INSTALER_DUPLICATE_PROCESS_ID, 0, DebugEvent->dwProcessId );
  213. return FALSE;
  214. }
  215. }
  216. else
  217. if (DebugEvent->dwDebugEventCode == CREATE_THREAD_DEBUG_EVENT) {
  218. if (Thread != NULL) {
  219. DeclareError( INSTALER_DUPLICATE_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId );
  220. return FALSE;
  221. }
  222. if (Process == NULL) {
  223. DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId );
  224. return FALSE;
  225. }
  226. }
  227. else
  228. if (Process == NULL) {
  229. DeclareError( INSTALER_MISSING_PROCESS_ID, 0, DebugEvent->dwProcessId );
  230. return FALSE;
  231. }
  232. else
  233. if (Thread == NULL) {
  234. DeclareError( INSTALER_MISSING_THREAD_ID, 0, DebugEvent->dwThreadId, DebugEvent->dwProcessId );
  235. return FALSE;
  236. }
  237. return TRUE;
  238. }
  239. VOID
  240. SuspendAllButThisThread(
  241. PPROCESS_INFO Process,
  242. PTHREAD_INFO Thread
  243. )
  244. {
  245. PTHREAD_INFO Thread1;
  246. PLIST_ENTRY Next, Head;
  247. if (Thread != NULL) {
  248. Head = &Process->ThreadListHead;
  249. Next = Head->Flink;
  250. while (Next != Head) {
  251. Thread1 = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
  252. if (Thread1 != Thread) {
  253. NtSuspendThread( Thread1->Handle, NULL );
  254. }
  255. Next = Next->Flink;
  256. }
  257. }
  258. return;
  259. }
  260. VOID
  261. ResumeAllButThisThread(
  262. PPROCESS_INFO Process,
  263. PTHREAD_INFO Thread
  264. )
  265. {
  266. PTHREAD_INFO Thread1;
  267. PLIST_ENTRY Next, Head;
  268. if (Thread != NULL) {
  269. Head = &Process->ThreadListHead;
  270. Next = Head->Flink;
  271. while (Next != Head) {
  272. Thread1 = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
  273. if (Thread1 != Thread) {
  274. NtResumeThread( Thread1->Handle, NULL );
  275. }
  276. Next = Next->Flink;
  277. }
  278. }
  279. return;
  280. }
  281. PBREAKPOINT_INFO
  282. FindBreakpoint(
  283. LPVOID Address,
  284. PPROCESS_INFO Process,
  285. PTHREAD_INFO Thread
  286. )
  287. {
  288. PBREAKPOINT_INFO Breakpoint;
  289. PLIST_ENTRY Next, Head;
  290. if (Thread != NULL) {
  291. Head = &Thread->BreakpointListHead;
  292. Next = Head->Flink;
  293. while (Next != Head) {
  294. Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
  295. if (Breakpoint->Address == Address) {
  296. return Breakpoint;
  297. }
  298. Next = Next->Flink;
  299. }
  300. }
  301. Head = &Process->BreakpointListHead;
  302. Next = Head->Flink;
  303. while (Next != Head) {
  304. Breakpoint = CONTAINING_RECORD( Next, BREAKPOINT_INFO, Entry );
  305. if (Breakpoint->Address == Address) {
  306. return Breakpoint;
  307. }
  308. Next = Next->Flink;
  309. }
  310. return NULL;
  311. }
  312. BOOLEAN
  313. CreateBreakpoint(
  314. LPVOID Address,
  315. PPROCESS_INFO Process,
  316. PTHREAD_INFO Thread,
  317. UCHAR ApiIndex,
  318. PAPI_SAVED_PARAMETERS SavedParameters,
  319. PBREAKPOINT_INFO *ReturnedBreakpoint
  320. )
  321. {
  322. PBREAKPOINT_INFO Breakpoint;
  323. Breakpoint = FindBreakpoint( Address, Process, Thread );
  324. if (ARGUMENT_PRESENT( ReturnedBreakpoint )) {
  325. *ReturnedBreakpoint = Breakpoint;
  326. }
  327. if (Breakpoint != NULL) {
  328. return (Breakpoint->ApiIndex == ApiIndex);
  329. }
  330. Breakpoint = AllocMem( sizeof( *Breakpoint ) );
  331. if (Breakpoint == NULL) {
  332. return FALSE;
  333. }
  334. Breakpoint->Address = Address;
  335. Breakpoint->ApiIndex = ApiIndex;
  336. if (ARGUMENT_PRESENT( SavedParameters )) {
  337. Breakpoint->SavedParameters = *SavedParameters;
  338. Breakpoint->SavedParametersValid = TRUE;
  339. }
  340. else {
  341. Breakpoint->SavedParametersValid = FALSE;
  342. }
  343. if (Thread != NULL) {
  344. InsertTailList( &Thread->BreakpointListHead, &Breakpoint->Entry );
  345. }
  346. else {
  347. InsertTailList( &Process->BreakpointListHead, &Breakpoint->Entry );
  348. }
  349. InstallBreakpoint( Process, Breakpoint );
  350. if (ARGUMENT_PRESENT( ReturnedBreakpoint )) {
  351. *ReturnedBreakpoint = Breakpoint;
  352. }
  353. return TRUE;
  354. }
  355. BOOLEAN
  356. DestroyBreakpoint(
  357. LPVOID Address,
  358. PPROCESS_INFO Process,
  359. PTHREAD_INFO Thread
  360. )
  361. {
  362. PBREAKPOINT_INFO Breakpoint;
  363. Breakpoint = FindBreakpoint( Address, Process, Thread );
  364. if (Breakpoint == NULL) {
  365. return FALSE;
  366. }
  367. RemoveBreakpoint( Process, Breakpoint );
  368. RemoveEntryList( &Breakpoint->Entry );
  369. FreeMem( &Breakpoint );
  370. return TRUE;
  371. }
  372. BOOLEAN
  373. HandleThreadsForSingleStep(
  374. PPROCESS_INFO Process,
  375. PTHREAD_INFO ThreadToSingleStep,
  376. BOOLEAN SuspendThreads
  377. )
  378. {
  379. PLIST_ENTRY Next, Head;
  380. PTHREAD_INFO Thread;
  381. Head = &Process->ThreadListHead;
  382. Next = Head->Flink;
  383. while (Next != Head) {
  384. Thread = CONTAINING_RECORD( Next, THREAD_INFO, Entry );
  385. if (Thread != ThreadToSingleStep) {
  386. if (SuspendThreads) {
  387. if (Thread->BreakpointToStepOver == NULL) {
  388. SuspendThread( Thread->Handle );
  389. }
  390. }
  391. else {
  392. ResumeThread( Thread->Handle );
  393. }
  394. break;
  395. }
  396. Next = Next->Flink;
  397. }
  398. return TRUE;
  399. }
  400. BOOLEAN
  401. ReadMemory(
  402. PPROCESS_INFO Process,
  403. PVOID Address,
  404. PVOID DataRead,
  405. ULONG BytesToRead,
  406. PCHAR Reason
  407. )
  408. {
  409. ULONG BytesRead;
  410. if (!ReadProcessMemory( Process->Handle,
  411. Address,
  412. DataRead,
  413. BytesToRead,
  414. &BytesRead
  415. ) ||
  416. BytesRead != BytesToRead
  417. ) {
  418. DbgEvent( MEMORYERROR, ( "Read memory from %x for %x bytes failed (%u) - '%s'\n",
  419. Address,
  420. BytesToRead,
  421. GetLastError(),
  422. Reason
  423. )
  424. );
  425. return FALSE;
  426. }
  427. else {
  428. return TRUE;
  429. }
  430. }
  431. BOOLEAN
  432. WriteMemory(
  433. PPROCESS_INFO Process,
  434. PVOID Address,
  435. PVOID DataToWrite,
  436. ULONG BytesToWrite,
  437. PCHAR Reason
  438. )
  439. {
  440. ULONG BytesWritten;
  441. ULONG OldProtection;
  442. BOOLEAN Result;
  443. if (WriteProcessMemory( Process->Handle,
  444. Address,
  445. DataToWrite,
  446. BytesToWrite,
  447. &BytesWritten
  448. ) &&
  449. BytesWritten == BytesToWrite
  450. ) {
  451. return TRUE;
  452. }
  453. Result = FALSE;
  454. if (GetLastError() == ERROR_NOACCESS &&
  455. VirtualProtectEx( Process->Handle,
  456. Address,
  457. BytesToWrite,
  458. PAGE_READWRITE,
  459. &OldProtection
  460. )
  461. ) {
  462. if (WriteProcessMemory( Process->Handle,
  463. Address,
  464. DataToWrite,
  465. BytesToWrite,
  466. &BytesWritten
  467. ) &&
  468. BytesWritten == BytesToWrite
  469. ) {
  470. Result = TRUE;
  471. }
  472. VirtualProtectEx( Process->Handle,
  473. Address,
  474. BytesToWrite,
  475. OldProtection,
  476. &OldProtection
  477. );
  478. if (Result) {
  479. return TRUE;
  480. }
  481. }
  482. DbgEvent( MEMORYERROR, ( "Write memory to %x for %x bytes failed (%u) - '%s'\n",
  483. Address,
  484. BytesToWrite,
  485. GetLastError(),
  486. Reason
  487. )
  488. );
  489. return FALSE;
  490. }
  491. PVOID
  492. AllocMem(
  493. ULONG Size
  494. )
  495. {
  496. PVOID p;
  497. p = HeapAlloc( AppHeap, HEAP_ZERO_MEMORY, Size );
  498. if (p == NULL) {
  499. DbgEvent( INTERNALERROR, ( "HeapAlloc( %0x8 ) failed\n", Size ) );
  500. }
  501. return p;
  502. }
  503. VOID
  504. FreeMem(
  505. PVOID *p
  506. )
  507. {
  508. if (*p != NULL) {
  509. HeapFree( AppHeap, 0, *p );
  510. *p = NULL;
  511. }
  512. return;
  513. }