Leaked source code of windows server 2003
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.

1329 lines
35 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Copyright (c) 1993, 1994 Digital Equipment Corporation
  4. Module Name:
  5. aligntrk.c
  6. Abstract:
  7. This module implements the code necessary to dispatch exceptions to the
  8. proper mode and invoke the exception dispatcher.
  9. Author:
  10. David N. Cutler (davec) 3-Apr-1990
  11. Environment:
  12. Kernel mode only.
  13. Revision History:
  14. Thomas Van Baak (tvb) 12-May-1992
  15. Adapted for Alpha AXP.
  16. Forrest Foltz (forrestf) 30-Dec-1999
  17. Broke out increasingly complex and common alignment fault handling into
  18. this file.
  19. --*/
  20. #include "ki.h"
  21. //
  22. // EXINFO_EFFECTIVE_ADDRESS: slot number [0...4] for faulting address.
  23. //
  24. #if defined(_IA64_)
  25. #define EXINFO_EFFECTIVE_ADDRESS 1
  26. #else // !_IA64_
  27. #define EXINFO_EFFECTIVE_ADDRESS 2
  28. #endif // !_IA64_
  29. //
  30. // Data misalignment exception (auto alignment fixup) control.
  31. //
  32. // If KiEnableAlignmentFaultExceptions is 0, then no alignment
  33. // exceptions are raised and all misaligned user and kernel mode data
  34. // references are emulated. This is consistent with NT/Alpha version
  35. // 3.1 behavior.
  36. //
  37. // If KiEnableAlignmentFaultExceptions is 1, then the
  38. // current thread automatic alignment fixup enable determines whether
  39. // emulation is attempted in user mode. This is consistent with NT/Mips
  40. // behavior.
  41. //
  42. // If KiEnableAlignmentFaultExceptions is 2, then the behavior depends
  43. // on the execution mode at the time of the fault. Kernel-mode code gets
  44. // type 1 behaivor above (no fixup), user-mode code gets type 0 above
  45. // (fixup).
  46. //
  47. // This last mode is temporary until we flush out the remaining user-mode
  48. // alignment faults, at which point the option will be removed and the
  49. // default value will be set to 1.
  50. //
  51. // N.B. This default value may be reset from the Registry during init.
  52. //
  53. ULONG KiEnableAlignmentFaultExceptions = 1;
  54. #define IsWow64Process() (PsGetCurrentProcess()->Wow64Process != NULL)
  55. #if DBG
  56. //
  57. // Globals to track the number of alignment exception fixups in both user and
  58. // kernel.
  59. //
  60. ULONG KiKernelFixupCount = 0;
  61. ULONG KiUserFixupCount = 0;
  62. //
  63. // Set KiBreakOnAlignmentFault to the desired combination of
  64. // the following flags.
  65. //
  66. #define KE_ALIGNMENT_BREAK_USER 0x01
  67. #define KE_ALIGNMENT_BREAK_KERNEL 0x02
  68. ULONG KiBreakOnAlignmentFault = KE_ALIGNMENT_BREAK_USER;
  69. __inline
  70. BOOLEAN
  71. KI_BREAK_ON_ALIGNMENT_FAULT(
  72. IN KPROCESSOR_MODE PreviousMode
  73. )
  74. /*++
  75. Routine description:
  76. Given that an alignment fault has been encountered, determines whether
  77. a debug break should occur based on the execution mode of the fault and
  78. flags in KiBreakOnAlignmentFault.
  79. Arguments:
  80. PreviousMode - The execution mode at the time of the fault.
  81. Return Value:
  82. TRUE if a debug break should occur, FALSE otherwise.
  83. --*/
  84. {
  85. if ((KiBreakOnAlignmentFault & KE_ALIGNMENT_BREAK_USER) != 0 &&
  86. PreviousMode == UserMode) {
  87. return TRUE;
  88. }
  89. if ((KiBreakOnAlignmentFault & KE_ALIGNMENT_BREAK_KERNEL) != 0 &&
  90. PreviousMode == KernelMode) {
  91. return TRUE;
  92. }
  93. return FALSE;
  94. }
  95. //
  96. // Structures to track alignment fault locations on a global basis. These
  97. // are used in the checked kernel only, as an aid in finding and fixing
  98. // alignment faults in the system.
  99. //
  100. #define MAX_IMAGE_NAME_CHARS 15
  101. typedef struct _ALIGNMENT_FAULT_IMAGE *PALIGNMENT_FAULT_IMAGE;
  102. typedef struct _ALIGNMENT_FAULT_LOCATION *PALIGNMENT_FAULT_LOCATION;
  103. typedef struct _ALIGNMENT_FAULT_IMAGE {
  104. //
  105. // Head of singly-linked list of fault locations associated with this image
  106. //
  107. PALIGNMENT_FAULT_LOCATION LocationHead;
  108. //
  109. // Total number of alignment faults associated with this image.
  110. //
  111. ULONG Count;
  112. //
  113. // Number of unique alignment fault locations found in this image
  114. //
  115. ULONG Instances;
  116. //
  117. // Name of the image
  118. //
  119. CHAR Name[ MAX_IMAGE_NAME_CHARS + 1 ];
  120. } ALIGNMENT_FAULT_IMAGE;
  121. BOOLEAN
  122. KiNewGlobalAlignmentFault(
  123. IN PVOID ProgramCounter,
  124. IN KPROCESSOR_MODE PreviousMode,
  125. OUT PALIGNMENT_FAULT_IMAGE *AlignmentFaultImage
  126. );
  127. #endif
  128. NTSTATUS
  129. KipRecordAlignmentException(
  130. IN PVOID ProgramCounter,
  131. OUT PALIGNMENT_EXCEPTION_RECORD *ExceptionRecord
  132. );
  133. PALIGNMENT_EXCEPTION_RECORD
  134. KipFindAlignmentException(
  135. IN PVOID ProgramCounter
  136. );
  137. PALIGNMENT_EXCEPTION_RECORD
  138. KipAllocateAlignmentExceptionRecord( VOID );
  139. BOOLEAN
  140. KiHandleAlignmentFault(
  141. IN PEXCEPTION_RECORD ExceptionRecord,
  142. IN PKEXCEPTION_FRAME ExceptionFrame,
  143. IN PKTRAP_FRAME TrapFrame,
  144. IN KPROCESSOR_MODE PreviousMode,
  145. IN BOOLEAN FirstChance,
  146. OUT BOOLEAN *ExceptionForwarded
  147. )
  148. /*++
  149. Routine description:
  150. This routine deals with alignment exceptions as appropriate. See comments
  151. at the beginning of this module.
  152. Arguments:
  153. ExceptionRecord - Supplies a pointer to an exception record.
  154. ExceptionFrame - Supplies a pointer to an exception frame.
  155. TrapFrame - Supplies a pointer to a trap frame.
  156. PreviousMode - Supplies the previous processor mode.
  157. FirstChance - Supplies a boolean variable that specifies whether this
  158. is the first (TRUE) or second (FALSE) time that this exception has
  159. been processed.
  160. ExceptionForwarded - On return, indicates whether the exception had
  161. already been forwarded to a user-mode debugger.
  162. Return Value:
  163. TRUE if the alignment exception was handled, FALSE otherwise.
  164. --*/
  165. {
  166. BOOLEAN AlignmentFaultHandled;
  167. BOOLEAN EmulateAlignmentFault;
  168. BOOLEAN ExceptionWasForwarded;
  169. BOOLEAN AutoAlignment;
  170. NTSTATUS Status;
  171. PVOID ProgramCounter;
  172. #if DBG
  173. BOOLEAN NewAlignmentFault;
  174. PVOID EffectiveAddress;
  175. PALIGNMENT_FAULT_IMAGE FaultImage;
  176. #endif
  177. //
  178. // Assume the fault was not handled and that the exception had not
  179. // been forwarded to a user-mode debugger.
  180. //
  181. AlignmentFaultHandled = FALSE;
  182. ExceptionWasForwarded = FALSE;
  183. if (FirstChance != FALSE) {
  184. //
  185. // This is the first chance for handling an exception... we haven't yet
  186. // searched for an exception handler.
  187. //
  188. EmulateAlignmentFault = FALSE;
  189. AutoAlignment = FALSE;
  190. ProgramCounter = (PVOID)ExceptionRecord->ExceptionAddress;
  191. //
  192. // Determine whether autoalignment is enabled for thread. If a DPC or
  193. // an interrupt is being executed, then we are in an arbitrary thread
  194. // context. Per-process and per-thread settings are ignored in this
  195. // case.
  196. //
  197. if (IsWow64Process() != FALSE) {
  198. //
  199. // For now, autoalignment is on (both user and kernel) for Wow64
  200. // processes.
  201. //
  202. AutoAlignment = TRUE;
  203. }
  204. if (PreviousMode == UserMode &&
  205. (KeGetCurrentThread()->AutoAlignment != FALSE ||
  206. KeGetCurrentThread()->ApcState.Process->AutoAlignment != FALSE)) {
  207. //
  208. // The fault occured in user mode, and the thread and/or process
  209. // has autoalignment turned on.
  210. //
  211. #if defined(_IA64_)
  212. //
  213. // On IA64 platform, reset psr.ac bit to disable alignment check
  214. //
  215. TrapFrame->StIPSR &= ~(ULONGLONG)(1ULL << PSR_AC);
  216. #endif // defined(_IA64_)
  217. AutoAlignment = TRUE;
  218. }
  219. if (PreviousMode == UserMode &&
  220. PsGetCurrentProcess()->DebugPort != NULL &&
  221. AutoAlignment == FALSE) {
  222. BOOLEAN DebuggerHandledException;
  223. PALIGNMENT_EXCEPTION_RECORD AlignmentExceptionRecord;
  224. //
  225. // The alignment exception is in user mode, there is a debugger
  226. // attached, and autoalignment is not enabled for this thread.
  227. //
  228. // Determine whether this exception has already been observed
  229. // and, if so, whether we should break into the debugger.
  230. //
  231. Status = KipRecordAlignmentException( ProgramCounter,
  232. &AlignmentExceptionRecord );
  233. if (!NT_SUCCESS(Status)) {
  234. AlignmentExceptionRecord = NULL;
  235. }
  236. if (AlignmentExceptionRecord != NULL &&
  237. AlignmentExceptionRecord->AutoFixup != FALSE) {
  238. //
  239. // The alignment exception record for this location
  240. // indicates that an automatic fixup should be applied
  241. // without notifying the debugger. This is because
  242. // the user entered 'gh' at the debug prompt the last
  243. // time we reported this fault.
  244. //
  245. EmulateAlignmentFault = TRUE;
  246. } else {
  247. //
  248. // Forward the exception to the debugger.
  249. //
  250. ExceptionWasForwarded = TRUE;
  251. DebuggerHandledException =
  252. DbgkForwardException( ExceptionRecord, TRUE, FALSE );
  253. if (DebuggerHandledException != FALSE) {
  254. //
  255. // The user continued with "gh", so fix up this and all
  256. // subsequent alignment exceptions at this address.
  257. //
  258. EmulateAlignmentFault = TRUE;
  259. if (AlignmentExceptionRecord != NULL) {
  260. AlignmentExceptionRecord->AutoFixup = TRUE;
  261. }
  262. }
  263. }
  264. } else if ((KiEnableAlignmentFaultExceptions == 0) ||
  265. (AutoAlignment != FALSE) ||
  266. (PreviousMode == UserMode &&
  267. KiEnableAlignmentFaultExceptions == 2)) {
  268. //
  269. // Emulate the alignment if:
  270. //
  271. // KiEnableAlignmentFaultExceptions is 0, OR
  272. // this thread has enabled alignment fixups, OR
  273. // the current process is a WOW64 process, OR
  274. // KiEnableAlignmentFaultExceptions is 2 and the fault occured
  275. // in usermode
  276. //
  277. EmulateAlignmentFault = TRUE;
  278. } else {
  279. //
  280. // We are not fixing up the alignment fault.
  281. //
  282. #if defined(_IA64_)
  283. //
  284. // On IA64 platform, set psr.ac bit to enable h/w alignment check
  285. //
  286. TrapFrame->StIPSR |= (1ULL << PSR_AC);
  287. #endif // defined(_IA64_)
  288. }
  289. #if DBG
  290. //
  291. // Count alignment faults by mode.
  292. //
  293. if (PreviousMode == KernelMode) {
  294. KiKernelFixupCount += 1;
  295. } else {
  296. KiUserFixupCount += 1;
  297. }
  298. EffectiveAddress =
  299. (PVOID)ExceptionRecord->ExceptionInformation[EXINFO_EFFECTIVE_ADDRESS];
  300. NewAlignmentFault = KiNewGlobalAlignmentFault( ProgramCounter,
  301. PreviousMode,
  302. &FaultImage );
  303. if (NewAlignmentFault != FALSE) {
  304. //
  305. // Attempt to determine and display the name of the offending
  306. // image.
  307. //
  308. DbgPrint("KE: %s Fixup: %.16s [%.16s], Pc=%.16p, Addr=%.16p ... Total=%ld %s\n",
  309. (PreviousMode == KernelMode) ? "Kernel" : "User",
  310. &PsGetCurrentProcess()->ImageFileName[0],
  311. FaultImage->Name,
  312. ProgramCounter,
  313. EffectiveAddress,
  314. (PreviousMode == KernelMode) ? KiKernelFixupCount : KiUserFixupCount,
  315. IsWow64Process() ? "(Wow64)" : "");
  316. if (AutoAlignment == FALSE &&
  317. KI_BREAK_ON_ALIGNMENT_FAULT( PreviousMode ) != FALSE &&
  318. ExceptionWasForwarded == FALSE) {
  319. if (EmulateAlignmentFault == FALSE) {
  320. DbgPrint("KE: Misaligned access WILL NOT be emulated\n");
  321. }
  322. //
  323. // This alignment fault would not normally have been fixed up,
  324. // and KiBreakOnAlignmentFault flags indicate that we should
  325. // break into the kernel debugger.
  326. //
  327. // Also, we know that we have not broken into a user-mode
  328. // debugger as a result of this fault.
  329. //
  330. if (PreviousMode != KernelMode) {
  331. RtlMakeStackTraceDataPresent();
  332. }
  333. DbgBreakPoint();
  334. }
  335. }
  336. #endif
  337. //
  338. // Emulate the reference according to the decisions made above.
  339. //
  340. if (EmulateAlignmentFault != FALSE) {
  341. if (KiEmulateReference(ExceptionRecord,
  342. ExceptionFrame,
  343. TrapFrame) != FALSE) {
  344. KeGetCurrentPrcb()->KeAlignmentFixupCount += 1;
  345. AlignmentFaultHandled = TRUE;
  346. }
  347. }
  348. }
  349. *ExceptionForwarded = ExceptionWasForwarded;
  350. return AlignmentFaultHandled;
  351. }
  352. NTSTATUS
  353. KipRecordAlignmentException(
  354. IN PVOID ProgramCounter,
  355. OUT PALIGNMENT_EXCEPTION_RECORD *ExceptionRecord
  356. )
  357. /*++
  358. Routine Description:
  359. This routine searches for an existing ALIGNMENT_EXCEPTION_RECORD on the
  360. per-process list of alignment exceptions. If a match is not found, then
  361. a new record is created.
  362. Arguments:
  363. ProgramCounter - Supplies the address of the faulting instruction.
  364. ExceptionRecord - Supplies a pointer into which is placed the address
  365. of the matching alignment exception record.
  366. Return Value:
  367. STATUS_SUCCESS if the operation was successful, or an appropriate error
  368. code otherwise.
  369. --*/
  370. {
  371. PALIGNMENT_EXCEPTION_RECORD exceptionRecord;
  372. NTSTATUS status;
  373. //
  374. // Lock the alignment exception database
  375. //
  376. KeEnterCriticalRegion();
  377. ExAcquireResourceExclusive( &PsLoadedModuleResource, TRUE );
  378. exceptionRecord = KipFindAlignmentException( ProgramCounter );
  379. if (exceptionRecord == NULL) {
  380. //
  381. // New exception. Allocate a new record.
  382. //
  383. exceptionRecord = KipAllocateAlignmentExceptionRecord();
  384. if (exceptionRecord == NULL) {
  385. status = STATUS_INSUFFICIENT_RESOURCES;
  386. goto exitUnlock;
  387. }
  388. exceptionRecord->ProgramCounter = ProgramCounter;
  389. }
  390. exceptionRecord->Count += 1;
  391. *ExceptionRecord = exceptionRecord;
  392. status = STATUS_SUCCESS;
  393. exitUnlock:
  394. ExReleaseResourceLite( &PsLoadedModuleResource );
  395. KeLeaveCriticalRegion();
  396. return status;
  397. }
  398. PALIGNMENT_EXCEPTION_RECORD
  399. KipAllocateAlignmentExceptionRecord(
  400. VOID
  401. )
  402. /*++
  403. Routine Description:
  404. This is a support routine for KipRecordAlignmentException(). Its purpose
  405. is to locate an available alignment exception record in the per-process
  406. alignment exception list. If none is found, a new alignment exception
  407. table will be allocated and linked into the per-process list.
  408. Arguments:
  409. None.
  410. Return Value:
  411. A pointer to the new alignment exception record if successful, or NULL
  412. otherwise.
  413. --*/
  414. {
  415. PKTHREAD thread;
  416. PKPROCESS process;
  417. PALIGNMENT_EXCEPTION_RECORD exceptionRecord;
  418. PALIGNMENT_EXCEPTION_TABLE exceptionTable;
  419. ULONG exceptionTableCount;
  420. //
  421. // Free exception records have a NULL program counter.
  422. //
  423. exceptionRecord = KipFindAlignmentException( NULL );
  424. if (exceptionRecord == NULL) {
  425. thread = KeGetCurrentThread();
  426. process = thread->ApcState.Process;
  427. //
  428. // Ensure that we haven't exceeded the maximum number of alignment
  429. // exception tables for this process. We could keep a count but we
  430. // do not care about performance here... this code only executes when
  431. // the process is running under a debugger and we're likely about
  432. // to break in.
  433. //
  434. exceptionTableCount = 0;
  435. exceptionTable = process->AlignmentExceptionTable;
  436. while (exceptionTable != NULL) {
  437. exceptionTableCount += 1;
  438. exceptionTable = exceptionTable->Next;
  439. }
  440. if (exceptionTableCount == MAXIMUM_ALIGNMENT_TABLES) {
  441. return NULL;
  442. }
  443. //
  444. // Allocate a new exception table and insert it at the
  445. // head of the per-process list.
  446. //
  447. exceptionTable = ExAllocatePoolWithTag( PagedPool,
  448. sizeof(ALIGNMENT_EXCEPTION_TABLE),
  449. 'tpcX' );
  450. if (exceptionTable == NULL) {
  451. return NULL;
  452. }
  453. RtlZeroMemory( exceptionTable, sizeof(ALIGNMENT_EXCEPTION_TABLE) );
  454. exceptionTable->Next = process->AlignmentExceptionTable;
  455. process->AlignmentExceptionTable = exceptionTable;
  456. //
  457. // Allocate the first record in the array
  458. //
  459. exceptionRecord = &exceptionTable->RecordArray[0];
  460. }
  461. return exceptionRecord;
  462. }
  463. PALIGNMENT_EXCEPTION_RECORD
  464. KipFindAlignmentException(
  465. IN PVOID ProgramCounter
  466. )
  467. /*++
  468. Routine Description:
  469. This routine searches the alignment exception tables associated with
  470. the current process for an alignment exception record that matches
  471. the supplied program counter.
  472. Arguments:
  473. ProgramCounter - Supplies the address of the faulting instruction.
  474. Return Value:
  475. A pointer to the matching alignment exception record, or NULL if none
  476. was found.
  477. --*/
  478. {
  479. PKTHREAD thread;
  480. PKPROCESS process;
  481. PALIGNMENT_EXCEPTION_RECORD exceptionRecord;
  482. PALIGNMENT_EXCEPTION_RECORD lastExceptionRecord;
  483. PALIGNMENT_EXCEPTION_TABLE exceptionTable;
  484. thread = KeGetCurrentThread();
  485. process = thread->ApcState.Process;
  486. //
  487. // Walk the singly-linked list of exception tables dangling
  488. // off of the process.
  489. //
  490. exceptionTable = process->AlignmentExceptionTable;
  491. while (exceptionTable != NULL) {
  492. //
  493. // Scan this table looking for a match.
  494. //
  495. exceptionRecord = exceptionTable->RecordArray;
  496. lastExceptionRecord =
  497. &exceptionTable->RecordArray[ ALIGNMENT_RECORDS_PER_TABLE ];
  498. while (exceptionRecord < lastExceptionRecord) {
  499. if (exceptionRecord->ProgramCounter == ProgramCounter) {
  500. //
  501. // Found it.
  502. //
  503. return exceptionRecord;
  504. }
  505. exceptionRecord++;
  506. }
  507. if (ProgramCounter == NULL) {
  508. //
  509. // Caller was looking for a free exception record. If one exists
  510. // it will be in the first table, which was just examined.
  511. //
  512. break;
  513. }
  514. //
  515. // Go look in the next exception table.
  516. //
  517. exceptionTable = exceptionTable->Next;
  518. }
  519. return NULL;
  520. }
  521. #if DBG
  522. //
  523. // The following routines are used to maintain a global database of alignment
  524. // faults that were found in the system. Alignment faults are stored according
  525. // to the name of the image and the offset within that image. In this way an
  526. // existing alignment fault record will be found if it occurs in the same image
  527. // loaded at a different base address in a new process.
  528. //
  529. typedef struct _ALIGNMENT_FAULT_LOCATION {
  530. //
  531. // Pointer to fault image associated with this location
  532. //
  533. PALIGNMENT_FAULT_IMAGE Image;
  534. //
  535. // Linkage for singly-linked list of fault locations associated with the
  536. // same image.
  537. //
  538. PALIGNMENT_FAULT_LOCATION Next;
  539. //
  540. // Offset of the PC address within the image.
  541. //
  542. ULONG_PTR OffsetFromBase;
  543. //
  544. // Number of alignment faults taken at this location.
  545. //
  546. ULONG Count;
  547. } ALIGNMENT_FAULT_LOCATION;
  548. //
  549. // The maximum number of individual alignment fault locations that will be
  550. // tracked.
  551. //
  552. #define MAX_FAULT_LOCATIONS 2048
  553. #define MAX_FAULT_IMAGES 128
  554. ALIGNMENT_FAULT_LOCATION KiAlignmentFaultLocations[ MAX_FAULT_LOCATIONS ];
  555. ULONG KiAlignmentFaultLocationCount = 0;
  556. ALIGNMENT_FAULT_IMAGE KiAlignmentFaultImages[ MAX_FAULT_IMAGES ];
  557. ULONG KiAlignmentFaultImageCount = 0;
  558. KSPIN_LOCK KipGlobalAlignmentDatabaseLock;
  559. VOID
  560. KiCopyLastPathElement(
  561. IN PUNICODE_STRING Source,
  562. IN OUT PULONG StringBufferLen,
  563. OUT PCHAR StringBuffer,
  564. IN KPROCESSOR_MODE PreviousMode
  565. );
  566. PALIGNMENT_FAULT_IMAGE
  567. KiFindAlignmentFaultImage(
  568. IN PCHAR ImageName
  569. );
  570. PLDR_DATA_TABLE_ENTRY
  571. KiFindLoaderDataTableEntry(
  572. IN PLIST_ENTRY ListHead,
  573. IN PVOID ProgramCounter,
  574. IN KPROCESSOR_MODE PreviousMode
  575. );
  576. BOOLEAN
  577. KiIncrementLocationAlignmentFault(
  578. IN PALIGNMENT_FAULT_IMAGE FaultImage,
  579. IN ULONG_PTR OffsetFromBase
  580. );
  581. BOOLEAN
  582. KiGetLdrDataTableInformation(
  583. IN PVOID ProgramCounter,
  584. IN KPROCESSOR_MODE PreviousMode,
  585. IN OUT PULONG ImageNameBufferLength,
  586. OUT PCHAR ImageNameBuffer,
  587. OUT PVOID *ImageBase
  588. )
  589. /*++
  590. Routine Description:
  591. This routine returns the name of the image that contains the supplied
  592. address.
  593. Arguments:
  594. ProgramCounter - Supplies the address for which we would like the
  595. name of the containing image.
  596. PreviousMode - Indicates whether the module is a user or kernel image.
  597. ImageNameBufferLength - Supplies a pointer to a buffer length value. On
  598. entry, this value represents the maximum length of StringBuffer. On
  599. exit, the value is set to the actual number of characters stored.
  600. ImageNameBuffer - Supplies a pointer to the output ANSI string into which
  601. the module name will be placed. This string will not be null
  602. terminated.
  603. ImageBase - Supplies a pointer to a location into which the base address
  604. of the located image is placed.
  605. Return Value:
  606. Returns TRUE if a module was located and its name copied to ImageNameBuffer,
  607. or FALSE otherwise.
  608. --*/
  609. {
  610. PLIST_ENTRY head;
  611. PPEB peb;
  612. PLDR_DATA_TABLE_ENTRY tableEntry;
  613. BOOLEAN status;
  614. //
  615. // Since we may be poking around in user space, be sure to recover
  616. // gracefully from any exceptions thrown.
  617. //
  618. try {
  619. //
  620. // Choose the appropriate module list based on whether the fault
  621. // occured in user- or kernel-space.
  622. //
  623. if (PreviousMode == KernelMode) {
  624. head = &PsLoadedModuleList;
  625. } else {
  626. peb = PsGetCurrentProcess()->Peb;
  627. head = &peb->Ldr->InLoadOrderModuleList;
  628. }
  629. tableEntry = KiFindLoaderDataTableEntry( head,
  630. ProgramCounter,
  631. PreviousMode );
  632. if (tableEntry != NULL) {
  633. //
  634. // The module of interest was located. Copy its name and
  635. // base address to the output paramters.
  636. //
  637. KiCopyLastPathElement( &tableEntry->BaseDllName,
  638. ImageNameBufferLength,
  639. ImageNameBuffer,
  640. PreviousMode );
  641. *ImageBase = tableEntry->DllBase;
  642. status = TRUE;
  643. } else {
  644. //
  645. // A module containing the supplied program counter could not be
  646. // found.
  647. //
  648. status = FALSE;
  649. }
  650. } except(ExSystemExceptionFilter()) {
  651. status = FALSE;
  652. }
  653. return status;
  654. }
  655. PLDR_DATA_TABLE_ENTRY
  656. KiFindLoaderDataTableEntry(
  657. IN PLIST_ENTRY ListHead,
  658. IN PVOID ProgramCounter,
  659. IN KPROCESSOR_MODE PreviousMode
  660. )
  661. /*++
  662. Routine Description:
  663. This is a support routine for KiGetLdrDataTableInformation. Its purpose is
  664. to search a LDR_DATA_TABLE_ENTRY list, looking for a module that contains
  665. the supplied program counter.
  666. Arguments:
  667. ListHead - Supplies a pointer to the LIST_ENTRY that represents the head of
  668. the LDR_DATA_TABLE_ENTRY list to search.
  669. ProgramCounter - Supplies the code location of the faulting instruction.
  670. Return Value:
  671. Returns a pointer to the matching LDR_DATA_TABLE_ENTRY structure, or NULL
  672. if no match is found.
  673. --*/
  674. {
  675. ULONG nodeNumber;
  676. PLIST_ENTRY next;
  677. PLDR_DATA_TABLE_ENTRY ldrDataTableEntry;
  678. ULONG_PTR imageStart;
  679. ULONG_PTR imageEnd;
  680. //
  681. // Walk the user- or kernel-mode module list. It is up to the caller
  682. // to capture any exceptions as a result of the lists being corrupt.
  683. //
  684. nodeNumber = 0;
  685. next = ListHead;
  686. if (PreviousMode != KernelMode) {
  687. ProbeForReadSmallStructure( next,
  688. sizeof(LIST_ENTRY),
  689. PROBE_ALIGNMENT(LIST_ENTRY) );
  690. }
  691. while (TRUE) {
  692. nodeNumber += 1;
  693. next = next->Flink;
  694. if (next == ListHead || nodeNumber > 10000) {
  695. //
  696. // The end of the module list has been reached, or the
  697. // list has been corrupted with a cycle. Indicate that
  698. // no matching module could be located.
  699. //
  700. ldrDataTableEntry = NULL;
  701. break;
  702. }
  703. ldrDataTableEntry = CONTAINING_RECORD( next,
  704. LDR_DATA_TABLE_ENTRY,
  705. InLoadOrderLinks );
  706. if (PreviousMode != KernelMode) {
  707. ProbeForReadSmallStructure( ldrDataTableEntry,
  708. sizeof(LDR_DATA_TABLE_ENTRY),
  709. PROBE_ALIGNMENT(LDR_DATA_TABLE_ENTRY) );
  710. }
  711. imageStart = (ULONG_PTR)ldrDataTableEntry->DllBase;
  712. if (imageStart > (ULONG_PTR)ProgramCounter) {
  713. //
  714. // The start of this module is past the program counter,
  715. // keep looking.
  716. //
  717. continue;
  718. }
  719. imageEnd = imageStart + ldrDataTableEntry->SizeOfImage;
  720. if (imageEnd > (ULONG_PTR)ProgramCounter) {
  721. //
  722. // Found a match.
  723. //
  724. break;
  725. }
  726. }
  727. return ldrDataTableEntry;
  728. }
  729. VOID
  730. KiCopyLastPathElement(
  731. IN PUNICODE_STRING Source,
  732. IN OUT PULONG StringBufferLen,
  733. OUT PCHAR StringBuffer,
  734. IN KPROCESSOR_MODE PreviousMode
  735. )
  736. /*++
  737. Routine Description:
  738. This routine locates the last path element of the path name represented by
  739. Source and copies it to StringBuffer.
  740. Arguments:
  741. Source - Supplies a pointer to the source UNICODE_STRING path.
  742. StringBufferLen - Supplies a pointer to a buffer length value. On entry,
  743. this value represents the maximum length of StringBuffer. On exit, the
  744. value is set to the actual number of characters stored.
  745. StringBuffer - Supplies a pointer to the output string buffer that is to
  746. contain the last path element. This string is not null terminated.
  747. PreviousMode - Previous mode of the caller for use in probing
  748. Return Value:
  749. None.
  750. --*/
  751. {
  752. PWCHAR src, srcBase;
  753. PCHAR dst;
  754. USHORT charCount;
  755. ULONG srcBaseLength;
  756. //
  757. // The name of the module containing the specified address is at
  758. // ldrDataTableEntry->BaseDllName. It might contain just the name,
  759. // or it might contain the whole path.
  760. //
  761. // Start at the end of the module path and work back until one
  762. // of the following is encountered:
  763. //
  764. // - ModuleName->MaximumLength characters
  765. // - the beginning of the module path string
  766. // - a path seperator
  767. //
  768. srcBase = Source->Buffer;
  769. srcBaseLength = Source->Length;
  770. if (PreviousMode != KernelMode) {
  771. ProbeForRead (srcBase, srcBaseLength, sizeof (WCHAR));
  772. }
  773. charCount = (USHORT)(srcBaseLength / sizeof(WCHAR));
  774. src = &srcBase[ charCount ];
  775. charCount = 0;
  776. while (TRUE) {
  777. if (charCount >= *StringBufferLen) {
  778. break;
  779. }
  780. if (src == srcBase) {
  781. break;
  782. }
  783. if (*(src-1) == L'\\') {
  784. break;
  785. }
  786. src--;
  787. charCount++;
  788. }
  789. //
  790. // Now copy the characters into the output string. We do our own
  791. // ansi-to-unicode conversion because the NLS routines cannot be
  792. // called at raised IRQL.
  793. //
  794. dst = StringBuffer;
  795. *StringBufferLen = charCount;
  796. while (charCount > 0) {
  797. *dst++ = (CHAR)(*src++);
  798. charCount--;
  799. }
  800. }
  801. BOOLEAN
  802. KiNewGlobalAlignmentFault(
  803. IN PVOID ProgramCounter,
  804. IN KPROCESSOR_MODE PreviousMode,
  805. OUT PALIGNMENT_FAULT_IMAGE *AlignmentFaultImage
  806. )
  807. /*++
  808. Routine Description:
  809. This routine looks for an existing alignment fault in the global
  810. fault database. A new record is created if a match could not be
  811. found. The count is incremented, and a pointer to the associated
  812. image record is returned.
  813. Arguments:
  814. ProgramCounter - Supplies the code location of the faulting instruction.
  815. PreviousMode - Supplies the execution mode at the time of the fault.
  816. AlignmentFaultImage - Supplies a location into which the pointer to the
  817. associated ALIGNMENT_FAULT_IMAGE structure is placed.
  818. Return Value:
  819. TRUE if an existing alignment fault match was not found, FALSE otherwise.
  820. --*/
  821. {
  822. ULONG_PTR imageOffset;
  823. CHAR imageNameBuffer[ MAX_IMAGE_NAME_CHARS + 1 ];
  824. ULONG imageNameBufferLength;
  825. PCHAR imageName;
  826. PALIGNMENT_FAULT_IMAGE alignmentFaultImage;
  827. BOOLEAN newFault;
  828. BOOLEAN foundLdrDataInfo;
  829. PVOID imageBase;
  830. KIRQL oldIrql;
  831. imageNameBufferLength = MAX_IMAGE_NAME_CHARS;
  832. foundLdrDataInfo = KiGetLdrDataTableInformation( ProgramCounter,
  833. PreviousMode,
  834. &imageNameBufferLength,
  835. imageNameBuffer,
  836. &imageBase );
  837. if (foundLdrDataInfo == FALSE) {
  838. //
  839. // Couldn't find an image for this program counter.
  840. //
  841. imageBase = NULL;
  842. imageName = "Unavailable";
  843. } else {
  844. imageNameBuffer[ imageNameBufferLength ] = '\0';
  845. imageName = imageNameBuffer;
  846. }
  847. //
  848. // Acquire the spinlock at synch level so that we can handle exceptions
  849. // from ISRs
  850. //
  851. imageOffset = (ULONG_PTR)ProgramCounter - (ULONG_PTR)imageBase;
  852. oldIrql = KeAcquireSpinLockRaiseToSynch( &KipGlobalAlignmentDatabaseLock );
  853. alignmentFaultImage = KiFindAlignmentFaultImage( imageName );
  854. if (alignmentFaultImage == NULL) {
  855. //
  856. // Image table must be full
  857. //
  858. newFault = FALSE;
  859. } else {
  860. newFault = KiIncrementLocationAlignmentFault( alignmentFaultImage,
  861. imageOffset );
  862. }
  863. KeReleaseSpinLock( &KipGlobalAlignmentDatabaseLock, oldIrql );
  864. *AlignmentFaultImage = alignmentFaultImage;
  865. return newFault;
  866. }
  867. BOOLEAN
  868. KiIncrementLocationAlignmentFault(
  869. IN PALIGNMENT_FAULT_IMAGE FaultImage,
  870. IN ULONG_PTR OffsetFromBase
  871. )
  872. /*++
  873. Routine Description:
  874. This is a support routine for KiNewGlobalAligmentFault. Its purpose is to
  875. find or create an alignment fault record once the appropriate alignment
  876. fault image has been found or created.
  877. Arguments:
  878. FaultImage - Supplies a pointer to the ALIGNMENT_FAULT_IMAGE associated
  879. with this alignment fault.
  880. OffsetFromBase - Supplies the image offset within the image of the faulting
  881. instruction.
  882. Return Value:
  883. TRUE if an existing alignment fault match was not found, FALSE otherwise.
  884. --*/
  885. {
  886. PALIGNMENT_FAULT_LOCATION faultLocation;
  887. //
  888. // Walk the location table, looking for a match.
  889. //
  890. faultLocation = FaultImage->LocationHead;
  891. while (faultLocation != NULL) {
  892. if (faultLocation->OffsetFromBase == OffsetFromBase) {
  893. faultLocation->Count++;
  894. return FALSE;
  895. }
  896. faultLocation = faultLocation->Next;
  897. }
  898. //
  899. // Could not find a match. Build a new alignment fault record.
  900. //
  901. if (KiAlignmentFaultLocationCount >= MAX_FAULT_LOCATIONS) {
  902. //
  903. // Table is full. Indicate that this is not a new alignment fault.
  904. //
  905. return FALSE;
  906. }
  907. faultLocation = &KiAlignmentFaultLocations[ KiAlignmentFaultLocationCount ];
  908. faultLocation->Image = FaultImage;
  909. faultLocation->Next = FaultImage->LocationHead;
  910. faultLocation->OffsetFromBase = OffsetFromBase;
  911. faultLocation->Count = 1;
  912. FaultImage->LocationHead = faultLocation;
  913. FaultImage->Instances += 1;
  914. KiAlignmentFaultLocationCount++;
  915. return TRUE;
  916. }
  917. PALIGNMENT_FAULT_IMAGE
  918. KiFindAlignmentFaultImage(
  919. IN PCHAR ImageName
  920. )
  921. /*++
  922. Routine Description:
  923. This is a support routine for KiNewGlobalAlignmentFault. Its purpose is to
  924. walk the global ALIGNMENT_FAULT_IMAGE list looking for an image name that
  925. matches ImageName. If none is found, a new image record is created and
  926. inserted into the list.
  927. Arguments:
  928. ImageName - Supplies a pointer to the ANSI image name.
  929. Return Value:
  930. Returns a pointer to the matching ALIGNMENT_FAULT_IMAGE structure.
  931. --*/
  932. {
  933. PALIGNMENT_FAULT_IMAGE faultImage;
  934. PALIGNMENT_FAULT_IMAGE lastImage;
  935. if (ImageName == NULL || *ImageName == '\0') {
  936. //
  937. // No image name was supplied.
  938. //
  939. return NULL;
  940. }
  941. //
  942. // Walk the image table, looking for a match.
  943. //
  944. faultImage = &KiAlignmentFaultImages[ 0 ];
  945. lastImage = &KiAlignmentFaultImages[ KiAlignmentFaultImageCount ];
  946. while (faultImage < lastImage) {
  947. if (strcmp(ImageName, faultImage->Name) == 0) {
  948. //
  949. // Found it.
  950. //
  951. faultImage->Count += 1;
  952. return faultImage;
  953. }
  954. faultImage += 1;
  955. }
  956. //
  957. // Create a new fault image if there's room
  958. //
  959. if (KiAlignmentFaultImageCount >= MAX_FAULT_IMAGES) {
  960. //
  961. // Table is full up.
  962. //
  963. return NULL;
  964. }
  965. KiAlignmentFaultImageCount += 1;
  966. //
  967. // Zero the image record. The records start out zero-initialized, this
  968. // is in case KiAlignmentFaultImageCount was manually reset to zero via
  969. // the debugger.
  970. //
  971. RtlZeroMemory( faultImage, sizeof(ALIGNMENT_FAULT_IMAGE) );
  972. faultImage->Count = 1;
  973. strcpy( faultImage->Name, ImageName );
  974. return faultImage;
  975. }
  976. #endif // DBG