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.

1315 lines
33 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 NewAlignmentFault;
  168. BOOLEAN EmulateAlignmentFault;
  169. BOOLEAN ExceptionWasForwarded;
  170. BOOLEAN AutoAlignment;
  171. NTSTATUS Status;
  172. PVOID ProgramCounter;
  173. PVOID EffectiveAddress;
  174. #if DBG
  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. );
  565. PALIGNMENT_FAULT_IMAGE
  566. KiFindAlignmentFaultImage(
  567. IN PUCHAR ImageName
  568. );
  569. PLDR_DATA_TABLE_ENTRY
  570. KiFindLoaderDataTableEntry(
  571. IN PLIST_ENTRY ListHead,
  572. IN PVOID ProgramCounter,
  573. IN KPROCESSOR_MODE PreviousMode
  574. );
  575. BOOLEAN
  576. KiIncrementLocationAlignmentFault(
  577. IN PALIGNMENT_FAULT_IMAGE FaultImage,
  578. IN ULONG_PTR OffsetFromBase
  579. );
  580. BOOLEAN
  581. KiGetLdrDataTableInformation(
  582. IN PVOID ProgramCounter,
  583. IN KPROCESSOR_MODE PreviousMode,
  584. IN OUT PULONG ImageNameBufferLength,
  585. OUT PCHAR ImageNameBuffer,
  586. OUT PVOID *ImageBase
  587. )
  588. /*++
  589. Routine Description:
  590. This routine returns the name of the image that contains the supplied
  591. address.
  592. Arguments:
  593. ProgramCounter - Supplies the address for which we would like the
  594. name of the containing image.
  595. PreviousMode - Indicates whether the module is a user or kernel image.
  596. ImageNameBufferLength - Supplies a pointer to a buffer length value. On
  597. entry, this value represents the maximum length of StringBuffer. On
  598. exit, the value is set to the actual number of characters stored.
  599. ImageNameBuffer - Supplies a pointer to the output ANSI string into which
  600. the module name will be placed. This string will not be null
  601. terminated.
  602. ImageBase - Supplies a pointer to a location into which the base address
  603. of the located image is placed.
  604. Return Value:
  605. Returns TRUE if a module was located and its name copied to ImageNameBuffer,
  606. or FALSE otherwise.
  607. --*/
  608. {
  609. PLIST_ENTRY head;
  610. PPEB peb;
  611. PLDR_DATA_TABLE_ENTRY tableEntry;
  612. BOOLEAN status;
  613. //
  614. // Since we may be poking around in user space, be sure to recover
  615. // gracefully from any exceptions thrown.
  616. //
  617. try {
  618. //
  619. // Choose the appropriate module list based on whether the fault
  620. // occured in user- or kernel-space.
  621. //
  622. if (PreviousMode == KernelMode) {
  623. head = &PsLoadedModuleList;
  624. } else {
  625. peb = PsGetCurrentProcess()->Peb;
  626. head = &peb->Ldr->InLoadOrderModuleList;
  627. }
  628. tableEntry = KiFindLoaderDataTableEntry( head,
  629. ProgramCounter,
  630. PreviousMode );
  631. if (tableEntry != NULL) {
  632. //
  633. // The module of interest was located. Copy its name and
  634. // base address to the output paramters.
  635. //
  636. KiCopyLastPathElement( &tableEntry->BaseDllName,
  637. ImageNameBufferLength,
  638. ImageNameBuffer );
  639. *ImageBase = tableEntry->DllBase;
  640. status = TRUE;
  641. } else {
  642. //
  643. // A module containing the supplied program counter could not be
  644. // found.
  645. //
  646. status = FALSE;
  647. }
  648. } except(ExSystemExceptionFilter()) {
  649. status = FALSE;
  650. }
  651. return status;
  652. }
  653. PLDR_DATA_TABLE_ENTRY
  654. KiFindLoaderDataTableEntry(
  655. IN PLIST_ENTRY ListHead,
  656. IN PVOID ProgramCounter,
  657. IN KPROCESSOR_MODE PreviousMode
  658. )
  659. /*++
  660. Routine Description:
  661. This is a support routine for KiGetLdrDataTableInformation. Its purpose is
  662. to search a LDR_DATA_TABLE_ENTRY list, looking for a module that contains
  663. the supplied program counter.
  664. Arguments:
  665. ListHead - Supplies a pointer to the LIST_ENTRY that represents the head of
  666. the LDR_DATA_TABLE_ENTRY list to search.
  667. ProgramCounter - Supplies the code location of the faulting instruction.
  668. Return Value:
  669. Returns a pointer to the matching LDR_DATA_TABLE_ENTRY structure, or NULL
  670. if no match is found.
  671. --*/
  672. {
  673. ULONG nodeNumber;
  674. PLIST_ENTRY next;
  675. PLDR_DATA_TABLE_ENTRY ldrDataTableEntry;
  676. ULONG_PTR imageStart;
  677. ULONG_PTR imageEnd;
  678. //
  679. // Walk the user- or kernel-mode module list. It is up to the caller
  680. // to capture any exceptions as a result of the lists being corrupt.
  681. //
  682. nodeNumber = 0;
  683. next = ListHead;
  684. if (PreviousMode != KernelMode) {
  685. ProbeForReadSmallStructure( next,
  686. sizeof(LIST_ENTRY),
  687. PROBE_ALIGNMENT(LIST_ENTRY) );
  688. }
  689. while (TRUE) {
  690. nodeNumber += 1;
  691. next = next->Flink;
  692. if (next == ListHead || nodeNumber > 10000) {
  693. //
  694. // The end of the module list has been reached, or the
  695. // list has been corrupted with a cycle. Indicate that
  696. // no matching module could be located.
  697. //
  698. ldrDataTableEntry = NULL;
  699. break;
  700. }
  701. ldrDataTableEntry = CONTAINING_RECORD( next,
  702. LDR_DATA_TABLE_ENTRY,
  703. InLoadOrderLinks );
  704. if (PreviousMode != KernelMode) {
  705. ProbeForReadSmallStructure( ldrDataTableEntry,
  706. sizeof(LDR_DATA_TABLE_ENTRY),
  707. PROBE_ALIGNMENT(LDR_DATA_TABLE_ENTRY) );
  708. }
  709. imageStart = (ULONG_PTR)ldrDataTableEntry->DllBase;
  710. if (imageStart > (ULONG_PTR)ProgramCounter) {
  711. //
  712. // The start of this module is past the program counter,
  713. // keep looking.
  714. //
  715. continue;
  716. }
  717. imageEnd = imageStart + ldrDataTableEntry->SizeOfImage;
  718. if (imageEnd > (ULONG_PTR)ProgramCounter) {
  719. //
  720. // Found a match.
  721. //
  722. break;
  723. }
  724. }
  725. return ldrDataTableEntry;
  726. }
  727. VOID
  728. KiCopyLastPathElement(
  729. IN PUNICODE_STRING Source,
  730. IN OUT PULONG StringBufferLen,
  731. OUT PCHAR StringBuffer
  732. )
  733. /*++
  734. Routine Description:
  735. This routine locates the last path element of the path name represented by
  736. Source and copies it to StringBuffer.
  737. Arguments:
  738. Source - Supplies a pointer to the source UNICODE_STRING path.
  739. StringBufferLen - Supplies a pointer to a buffer length value. On entry,
  740. this value represents the maximum length of StringBuffer. On exit, the
  741. value is set to the actual number of characters stored.
  742. StringBuffer - Supplies a pointer to the output string buffer that is to
  743. contain the last path element. This string is not null terminated.
  744. Return Value:
  745. None.
  746. --*/
  747. {
  748. PWCHAR src;
  749. PCHAR dst;
  750. USHORT charCount;
  751. //
  752. // The name of the module containing the specified address is at
  753. // ldrDataTableEntry->BaseDllName. It might contain just the name,
  754. // or it might contain the whole path.
  755. //
  756. // Start at the end of the module path and work back until one
  757. // of the following is encountered:
  758. //
  759. // - ModuleName->MaximumLength characters
  760. // - the beginning of the module path string
  761. // - a path seperator
  762. //
  763. charCount = Source->Length / sizeof(WCHAR);
  764. src = &Source->Buffer[ charCount ];
  765. charCount = 0;
  766. while (TRUE) {
  767. if (charCount >= *StringBufferLen) {
  768. break;
  769. }
  770. if (src == Source->Buffer) {
  771. break;
  772. }
  773. if (*(src-1) == L'\\') {
  774. break;
  775. }
  776. src--;
  777. charCount++;
  778. }
  779. //
  780. // Now copy the characters into the output string. We do our own
  781. // ansi-to-unicode conversion because the NLS routines cannot be
  782. // called at raised IRQL.
  783. //
  784. dst = StringBuffer;
  785. *StringBufferLen = charCount;
  786. while (charCount > 0) {
  787. *dst++ = (CHAR)(*src++);
  788. charCount--;
  789. }
  790. }
  791. BOOLEAN
  792. KiNewGlobalAlignmentFault(
  793. IN PVOID ProgramCounter,
  794. IN KPROCESSOR_MODE PreviousMode,
  795. OUT PALIGNMENT_FAULT_IMAGE *AlignmentFaultImage
  796. )
  797. /*++
  798. Routine Description:
  799. This routine looks for an existing alignment fault in the global
  800. fault database. A new record is created if a match could not be
  801. found. The count is incremented, and a pointer to the associated
  802. image record is returned.
  803. Arguments:
  804. ProgramCounter - Supplies the code location of the faulting instruction.
  805. PreviousMode - Supplies the execution mode at the time of the fault.
  806. AlignmentFaultImage - Supplies a location into which the pointer to the
  807. associated ALIGNMENT_FAULT_IMAGE structure is placed.
  808. Return Value:
  809. TRUE if an existing alignment fault match was not found, FALSE otherwise.
  810. --*/
  811. {
  812. ULONG_PTR imageOffset;
  813. CHAR imageNameBuffer[ MAX_IMAGE_NAME_CHARS + 1 ];
  814. ULONG imageNameBufferLength;
  815. PCHAR imageName;
  816. PALIGNMENT_FAULT_IMAGE alignmentFaultImage;
  817. BOOLEAN newFault;
  818. BOOLEAN foundLdrDataInfo;
  819. PVOID imageBase;
  820. KIRQL oldIrql;
  821. imageNameBufferLength = MAX_IMAGE_NAME_CHARS;
  822. foundLdrDataInfo = KiGetLdrDataTableInformation( ProgramCounter,
  823. PreviousMode,
  824. &imageNameBufferLength,
  825. imageNameBuffer,
  826. &imageBase );
  827. if (foundLdrDataInfo == FALSE) {
  828. //
  829. // Couldn't find an image for this program counter.
  830. //
  831. imageBase = NULL;
  832. imageName = "Unavailable";
  833. } else {
  834. imageNameBuffer[ imageNameBufferLength ] = '\0';
  835. imageName = imageNameBuffer;
  836. }
  837. //
  838. // Acquire the spinlock at synch level so that we can handle exceptions
  839. // from ISRs
  840. //
  841. imageOffset = (ULONG_PTR)ProgramCounter - (ULONG_PTR)imageBase;
  842. oldIrql = KeAcquireSpinLockRaiseToSynch( &KipGlobalAlignmentDatabaseLock );
  843. alignmentFaultImage = KiFindAlignmentFaultImage( imageName );
  844. if (alignmentFaultImage == NULL) {
  845. //
  846. // Image table must be full
  847. //
  848. newFault = FALSE;
  849. } else {
  850. newFault = KiIncrementLocationAlignmentFault( alignmentFaultImage,
  851. imageOffset );
  852. }
  853. KeReleaseSpinLock( &KipGlobalAlignmentDatabaseLock, oldIrql );
  854. *AlignmentFaultImage = alignmentFaultImage;
  855. return newFault;
  856. }
  857. BOOLEAN
  858. KiIncrementLocationAlignmentFault(
  859. IN PALIGNMENT_FAULT_IMAGE FaultImage,
  860. IN ULONG_PTR OffsetFromBase
  861. )
  862. /*++
  863. Routine Description:
  864. This is a support routine for KiNewGlobalAligmentFault. Its purpose is to
  865. find or create an alignment fault record once the appropriate alignment
  866. fault image has been found or created.
  867. Arguments:
  868. FaultImage - Supplies a pointer to the ALIGNMENT_FAULT_IMAGE associated
  869. with this alignment fault.
  870. OffsetFromBase - Supplies the image offset within the image of the faulting
  871. instruction.
  872. Return Value:
  873. TRUE if an existing alignment fault match was not found, FALSE otherwise.
  874. --*/
  875. {
  876. PALIGNMENT_FAULT_LOCATION faultLocation;
  877. //
  878. // Walk the location table, looking for a match.
  879. //
  880. faultLocation = FaultImage->LocationHead;
  881. while (faultLocation != NULL) {
  882. if (faultLocation->OffsetFromBase == OffsetFromBase) {
  883. faultLocation->Count++;
  884. return FALSE;
  885. }
  886. faultLocation = faultLocation->Next;
  887. }
  888. //
  889. // Could not find a match. Build a new alignment fault record.
  890. //
  891. if (KiAlignmentFaultLocationCount >= MAX_FAULT_LOCATIONS) {
  892. //
  893. // Table is full. Indicate that this is not a new alignment fault.
  894. //
  895. return FALSE;
  896. }
  897. faultLocation = &KiAlignmentFaultLocations[ KiAlignmentFaultLocationCount ];
  898. faultLocation->Image = FaultImage;
  899. faultLocation->Next = FaultImage->LocationHead;
  900. faultLocation->OffsetFromBase = OffsetFromBase;
  901. faultLocation->Count = 1;
  902. FaultImage->LocationHead = faultLocation;
  903. FaultImage->Instances += 1;
  904. KiAlignmentFaultLocationCount++;
  905. return TRUE;
  906. }
  907. PALIGNMENT_FAULT_IMAGE
  908. KiFindAlignmentFaultImage(
  909. IN PUCHAR ImageName
  910. )
  911. /*++
  912. Routine Description:
  913. This is a support routine for KiNewGlobalAlignmentFault. Its purpose is to
  914. walk the global ALIGNMENT_FAULT_IMAGE list looking for an image name that
  915. matches ImageName. If none is found, a new image record is created and
  916. inserted into the list.
  917. Arguments:
  918. ImageName - Supplies a pointer to the ANSI image name.
  919. Return Value:
  920. Returns a pointer to the matching ALIGNMENT_FAULT_IMAGE structure.
  921. --*/
  922. {
  923. PALIGNMENT_FAULT_IMAGE faultImage;
  924. PALIGNMENT_FAULT_IMAGE lastImage;
  925. if (ImageName == NULL || *ImageName == '\0') {
  926. //
  927. // No image name was supplied.
  928. //
  929. return NULL;
  930. }
  931. //
  932. // Walk the image table, looking for a match.
  933. //
  934. faultImage = &KiAlignmentFaultImages[ 0 ];
  935. lastImage = &KiAlignmentFaultImages[ KiAlignmentFaultImageCount ];
  936. while (faultImage < lastImage) {
  937. if (strcmp(ImageName, faultImage->Name) == 0) {
  938. //
  939. // Found it.
  940. //
  941. faultImage->Count += 1;
  942. return faultImage;
  943. }
  944. faultImage += 1;
  945. }
  946. //
  947. // Create a new fault image if there's room
  948. //
  949. if (KiAlignmentFaultImageCount >= MAX_FAULT_IMAGES) {
  950. //
  951. // Table is full up.
  952. //
  953. return NULL;
  954. }
  955. KiAlignmentFaultImageCount += 1;
  956. //
  957. // Zero the image record. The records start out zero-initialized, this
  958. // is in case KiAlignmentFaultImageCount was manually reset to zero via
  959. // the debugger.
  960. //
  961. RtlZeroMemory( faultImage, sizeof(ALIGNMENT_FAULT_IMAGE) );
  962. faultImage->Count = 1;
  963. strcpy( faultImage->Name, ImageName );
  964. return faultImage;
  965. }
  966. #endif // DBG