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.

692 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. imagedir.c
  5. Abstract:
  6. The module contains the code to translate an image directory type to
  7. the address of the data for that entry.
  8. Author:
  9. Steve Wood (stevewo) 18-Aug-1989
  10. Environment:
  11. User Mode or Kernel Mode
  12. Revision History:
  13. --*/
  14. #include "ntrtlp.h"
  15. #if defined(NTOS_KERNEL_RUNTIME)
  16. VOID
  17. RtlpTouchMemory(
  18. IN PVOID Address,
  19. IN ULONG Length
  20. );
  21. VOID
  22. RtlpMakeStackTraceDataPresentForImage(
  23. IN PVOID ImageBase
  24. );
  25. #if defined(ALLOC_PRAGMA)
  26. #pragma alloc_text(PAGE,RtlpTouchMemory)
  27. #pragma alloc_text(PAGE,RtlMakeStackTraceDataPresent)
  28. #pragma alloc_text(PAGE,RtlpMakeStackTraceDataPresentForImage)
  29. #endif
  30. #endif
  31. PIMAGE_NT_HEADERS
  32. RtlImageNtHeader (
  33. IN PVOID Base
  34. )
  35. /*++
  36. Routine Description:
  37. This function returns the address of the NT Header.
  38. Arguments:
  39. Base - Supplies the base of the image.
  40. Return Value:
  41. Returns the address of the NT Header.
  42. --*/
  43. {
  44. #if defined (BLDR_KERNEL_RUNTIME) || defined(NTOS_KERNEL_RUNTIME)
  45. PIMAGE_NT_HEADERS NtHeaders = NULL;
  46. if (Base != NULL && Base != (PVOID)-1) {
  47. if (((PIMAGE_DOS_HEADER)Base)->e_magic == IMAGE_DOS_SIGNATURE) {
  48. NtHeaders = (PIMAGE_NT_HEADERS)((PCHAR)Base + ((PIMAGE_DOS_HEADER)Base)->e_lfanew);
  49. #if defined(NTOS_KERNEL_RUNTIME)
  50. if (Base < MM_HIGHEST_USER_ADDRESS) {
  51. if ((PVOID)NtHeaders >= MM_HIGHEST_USER_ADDRESS) {
  52. return NULL;
  53. }
  54. if ((PVOID)((PCHAR)NtHeaders + sizeof (IMAGE_NT_HEADERS)) >= MM_HIGHEST_USER_ADDRESS) {
  55. return NULL;
  56. }
  57. }
  58. #endif
  59. if (NtHeaders->Signature != IMAGE_NT_SIGNATURE) {
  60. NtHeaders = NULL;
  61. }
  62. }
  63. }
  64. return NtHeaders;
  65. #else
  66. return RtlpImageNtHeader( Base );
  67. #endif
  68. }
  69. PIMAGE_SECTION_HEADER
  70. RtlSectionTableFromVirtualAddress (
  71. IN PIMAGE_NT_HEADERS NtHeaders,
  72. IN PVOID Base,
  73. IN ULONG Address
  74. )
  75. /*++
  76. Routine Description:
  77. This function locates a VirtualAddress within the image header
  78. of a file that is mapped as a file and returns a pointer to the
  79. section table entry for that virtual address
  80. Arguments:
  81. NtHeaders - Supplies the pointer to the image or data file.
  82. Base - Supplies the base of the image or data file.
  83. Address - Supplies the virtual address to locate.
  84. Return Value:
  85. NULL - The file does not contain data for the specified directory entry.
  86. NON-NULL - Returns the pointer of the section entry containing the data.
  87. --*/
  88. {
  89. ULONG i;
  90. PIMAGE_SECTION_HEADER NtSection;
  91. NtSection = IMAGE_FIRST_SECTION( NtHeaders );
  92. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) {
  93. if ((ULONG)Address >= NtSection->VirtualAddress &&
  94. (ULONG)Address < NtSection->VirtualAddress + NtSection->SizeOfRawData
  95. ) {
  96. return NtSection;
  97. }
  98. ++NtSection;
  99. }
  100. return NULL;
  101. }
  102. PVOID
  103. RtlAddressInSectionTable (
  104. IN PIMAGE_NT_HEADERS NtHeaders,
  105. IN PVOID Base,
  106. IN ULONG Address
  107. )
  108. /*++
  109. Routine Description:
  110. This function locates a VirtualAddress within the image header
  111. of a file that is mapped as a file and returns the seek address
  112. of the data the Directory describes.
  113. Arguments:
  114. NtHeaders - Supplies the pointer to the image or data file.
  115. Base - Supplies the base of the image or data file.
  116. Address - Supplies the virtual address to locate.
  117. Return Value:
  118. NULL - The file does not contain data for the specified directory entry.
  119. NON-NULL - Returns the address of the raw data the directory describes.
  120. --*/
  121. {
  122. PIMAGE_SECTION_HEADER NtSection;
  123. NtSection = RtlSectionTableFromVirtualAddress( NtHeaders,
  124. Base,
  125. Address
  126. );
  127. if (NtSection != NULL) {
  128. return( ((PCHAR)Base + ((ULONG_PTR)Address - NtSection->VirtualAddress) + NtSection->PointerToRawData) );
  129. }
  130. else {
  131. return( NULL );
  132. }
  133. }
  134. PVOID
  135. RtlpImageDirectoryEntryToData32 (
  136. IN PVOID Base,
  137. IN BOOLEAN MappedAsImage,
  138. IN USHORT DirectoryEntry,
  139. OUT PULONG Size,
  140. PIMAGE_NT_HEADERS32 NtHeaders
  141. )
  142. {
  143. ULONG DirectoryAddress;
  144. if (DirectoryEntry >= NtHeaders->OptionalHeader.NumberOfRvaAndSizes) {
  145. return( NULL );
  146. }
  147. if (!(DirectoryAddress = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].VirtualAddress)) {
  148. return( NULL );
  149. }
  150. #if defined(NTOS_KERNEL_RUNTIME)
  151. if (Base < MM_HIGHEST_USER_ADDRESS) {
  152. if ((PVOID)((PCHAR)Base + DirectoryAddress) >= MM_HIGHEST_USER_ADDRESS) {
  153. return( NULL );
  154. }
  155. }
  156. #endif
  157. *Size = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].Size;
  158. if (MappedAsImage || DirectoryAddress < NtHeaders->OptionalHeader.SizeOfHeaders) {
  159. return( (PVOID)((PCHAR)Base + DirectoryAddress) );
  160. }
  161. return( RtlAddressInSectionTable((PIMAGE_NT_HEADERS)NtHeaders, Base, DirectoryAddress ));
  162. }
  163. PVOID
  164. RtlpImageDirectoryEntryToData64 (
  165. IN PVOID Base,
  166. IN BOOLEAN MappedAsImage,
  167. IN USHORT DirectoryEntry,
  168. OUT PULONG Size,
  169. PIMAGE_NT_HEADERS64 NtHeaders
  170. )
  171. {
  172. ULONG DirectoryAddress;
  173. if (DirectoryEntry >= NtHeaders->OptionalHeader.NumberOfRvaAndSizes) {
  174. return( NULL );
  175. }
  176. if (!(DirectoryAddress = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].VirtualAddress)) {
  177. return( NULL );
  178. }
  179. #if defined(NTOS_KERNEL_RUNTIME)
  180. if (Base < MM_HIGHEST_USER_ADDRESS) {
  181. if ((PVOID)((PCHAR)Base + DirectoryAddress) >= MM_HIGHEST_USER_ADDRESS) {
  182. return( NULL );
  183. }
  184. }
  185. #endif
  186. *Size = NtHeaders->OptionalHeader.DataDirectory[ DirectoryEntry ].Size;
  187. if (MappedAsImage || DirectoryAddress < NtHeaders->OptionalHeader.SizeOfHeaders) {
  188. return( (PVOID)((PCHAR)Base + DirectoryAddress) );
  189. }
  190. return( RtlAddressInSectionTable((PIMAGE_NT_HEADERS)NtHeaders, Base, DirectoryAddress ));
  191. }
  192. PVOID
  193. RtlImageDirectoryEntryToData (
  194. IN PVOID Base,
  195. IN BOOLEAN MappedAsImage,
  196. IN USHORT DirectoryEntry,
  197. OUT PULONG Size
  198. )
  199. /*++
  200. Routine Description:
  201. This function locates a Directory Entry within the image header
  202. and returns either the virtual address or seek address of the
  203. data the Directory describes.
  204. Arguments:
  205. Base - Supplies the base of the image or data file.
  206. MappedAsImage - FALSE if the file is mapped as a data file.
  207. - TRUE if the file is mapped as an image.
  208. DirectoryEntry - Supplies the directory entry to locate.
  209. Size - Return the size of the directory.
  210. Return Value:
  211. NULL - The file does not contain data for the specified directory entry.
  212. NON-NULL - Returns the address of the raw data the directory describes.
  213. --*/
  214. {
  215. PIMAGE_NT_HEADERS NtHeaders;
  216. if (LDR_IS_DATAFILE(Base)) {
  217. Base = LDR_DATAFILE_TO_VIEW(Base);
  218. MappedAsImage = FALSE;
  219. }
  220. NtHeaders = RtlImageNtHeader(Base);
  221. if (!NtHeaders)
  222. return NULL;
  223. if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
  224. return (RtlpImageDirectoryEntryToData32(Base,
  225. MappedAsImage,
  226. DirectoryEntry,
  227. Size,
  228. (PIMAGE_NT_HEADERS32)NtHeaders));
  229. } else if (NtHeaders->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
  230. return (RtlpImageDirectoryEntryToData64(Base,
  231. MappedAsImage,
  232. DirectoryEntry,
  233. Size,
  234. (PIMAGE_NT_HEADERS64)NtHeaders));
  235. } else {
  236. return (NULL);
  237. }
  238. }
  239. #if defined(NTOS_KERNEL_RUNTIME)
  240. VOID
  241. RtlMakeStackTraceDataPresent(
  242. VOID
  243. )
  244. /*++
  245. Routine Description:
  246. This function walks the loaded user-mode images and makes present the
  247. portions of the data necessary to support a kernel-debugger stack
  248. dump of the user-mode stack.
  249. N.B. The necessary pieces are merely touched to be brought in. In a low
  250. memory situation, some of the previously-touched pages may be paged
  251. out in order for the new ones to be brought in. This routine is
  252. not guaranteed to do anything useful, however it does more often than
  253. not.
  254. Arguments:
  255. None.
  256. Return value:
  257. None.
  258. --*/
  259. {
  260. PPEB peb;
  261. PLIST_ENTRY head;
  262. PLIST_ENTRY next;
  263. PVOID imageBase;
  264. ULONG imageCount;
  265. LDR_DATA_TABLE_ENTRY UNALIGNED *ldrDataTableEntry;
  266. RTL_PAGED_CODE();
  267. //
  268. // The image list is in user mode and is not to be trusted. The
  269. // surrounding try/except block will guard against most forms of
  270. // list corruption. imageCount is used to bail in finite time
  271. // in the event of a cyclic image list.
  272. //
  273. imageCount = 0;
  274. try {
  275. peb = NtCurrentPeb();
  276. head = &peb->Ldr->InLoadOrderModuleList;
  277. ProbeForReadSmallStructure( head,
  278. sizeof(LIST_ENTRY),
  279. PROBE_ALIGNMENT(LIST_ENTRY) );
  280. next = head;
  281. while (imageCount < 1000) {
  282. next = next->Flink;
  283. if (next == head) {
  284. break;
  285. }
  286. imageCount += 1;
  287. //
  288. // Locate the base address of the image
  289. //
  290. ldrDataTableEntry = CONTAINING_RECORD(next,
  291. LDR_DATA_TABLE_ENTRY,
  292. InLoadOrderLinks);
  293. ProbeForReadSmallStructure( ldrDataTableEntry,
  294. sizeof(LDR_DATA_TABLE_ENTRY),
  295. PROBE_ALIGNMENT(LDR_DATA_TABLE_ENTRY) );
  296. imageBase = ldrDataTableEntry->DllBase;
  297. ProbeForReadSmallStructure (imageBase, sizeof (IMAGE_DOS_HEADER), sizeof (UCHAR));
  298. //
  299. // Make the stack trace data present for this image. Use a
  300. // seperate try/except block here so that subsequent images
  301. // will be processed in the event of a failure.
  302. //
  303. try {
  304. RtlpMakeStackTraceDataPresentForImage(imageBase);
  305. } except (EXCEPTION_EXECUTE_HANDLER) {
  306. NOTHING;
  307. }
  308. }
  309. } except (EXCEPTION_EXECUTE_HANDLER) {
  310. NOTHING;
  311. }
  312. }
  313. VOID
  314. RtlpMakeStackTraceDataPresentForImage(
  315. IN PVOID ImageBase
  316. )
  317. /*++
  318. Routine Description:
  319. This function attempts to make present the portions of an image necessary
  320. to support a kernel-debugger stack dump of the user-mode stack.
  321. Arguments:
  322. ImageBase - Supplies the VA of the base of the image to process.
  323. Return value:
  324. None.
  325. --*/
  326. {
  327. PVOID directory;
  328. ULONG directorySize;
  329. PIMAGE_RUNTIME_FUNCTION_ENTRY functionEntry;
  330. PIMAGE_RUNTIME_FUNCTION_ENTRY lastFunctionEntry;
  331. PCHAR imageBase;
  332. #if defined(_IA64_)
  333. PUNWIND_INFO unwindInfo;
  334. #endif
  335. RTL_PAGED_CODE();
  336. //
  337. // Make present the IMAGE_DIRECTORY_EXCEPTION section.
  338. //
  339. directory = RtlImageDirectoryEntryToData(ImageBase,
  340. TRUE,
  341. IMAGE_DIRECTORY_ENTRY_EXCEPTION,
  342. &directorySize);
  343. if (directory == NULL) {
  344. return;
  345. }
  346. RtlpTouchMemory(directory, directorySize);
  347. #if defined(_IA64_)
  348. //
  349. // The IMAGE_DIRECTORY_EXCEPTION section is an array of
  350. // IMAGE_RUNTIME_FUNCTION_ENTRY structures. Each function entry
  351. // refers, via UnwindInfoAddress (expressed as an image offset) to
  352. // an UNWIND_INFO structure.
  353. //
  354. // All UNWIND_INFO structures must be made present.
  355. //
  356. functionEntry = (PIMAGE_RUNTIME_FUNCTION_ENTRY)directory;
  357. lastFunctionEntry = functionEntry +
  358. directorySize / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
  359. while (functionEntry < lastFunctionEntry) {
  360. unwindInfo = (PUNWIND_INFO)((PCHAR)ImageBase +
  361. functionEntry->UnwindInfoAddress);
  362. //
  363. // An UNWIND_INFO structure consists of a fixed header plus
  364. // a variable-length portion.
  365. //
  366. RtlpTouchMemory(unwindInfo,
  367. sizeof(UNWIND_INFO) +
  368. unwindInfo->DataLength * sizeof(ULONGLONG));
  369. functionEntry += 1;
  370. }
  371. //
  372. // Make present the IMAGE_DIRECTORY_ENTRY_GLOBALPTR section.
  373. //
  374. directory = RtlImageDirectoryEntryToData(ImageBase,
  375. TRUE,
  376. IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
  377. &directorySize);
  378. if (directory == NULL) {
  379. return;
  380. }
  381. RtlpTouchMemory(directory, directorySize);
  382. #endif // _IA64_
  383. }
  384. VOID
  385. RtlpTouchMemory(
  386. IN PVOID Address,
  387. IN ULONG Length
  388. )
  389. /*++
  390. Routine Description:
  391. This function touches all of the pages within a given region.
  392. Arguments:
  393. Address - Supplies the VA of the start of the image to make present.
  394. Length - Supplies the length, in bytes, of the image to make present.
  395. Return value:
  396. None.
  397. --*/
  398. {
  399. PCHAR regionStart;
  400. PCHAR regionEnd;
  401. RTL_PAGED_CODE();
  402. regionStart = Address;
  403. regionEnd = regionStart + Length;
  404. while (regionStart < regionEnd) {
  405. *(volatile UCHAR *)regionStart;
  406. regionStart = PAGE_ALIGN(regionStart + PAGE_SIZE);
  407. }
  408. }
  409. #endif
  410. #if !defined(NTOS_KERNEL_RUNTIME) && !defined(BLDR_KERNEL_RUNTIME)
  411. PIMAGE_SECTION_HEADER
  412. RtlImageRvaToSection(
  413. IN PIMAGE_NT_HEADERS NtHeaders,
  414. IN PVOID Base,
  415. IN ULONG Rva
  416. )
  417. /*++
  418. Routine Description:
  419. This function locates an RVA within the image header of a file
  420. that is mapped as a file and returns a pointer to the section
  421. table entry for that virtual address
  422. Arguments:
  423. NtHeaders - Supplies the pointer to the image or data file.
  424. Base - Supplies the base of the image or data file. The image
  425. was mapped as a data file.
  426. Rva - Supplies the relative virtual address (RVA) to locate.
  427. Return Value:
  428. NULL - The RVA was not found within any of the sections of the image.
  429. NON-NULL - Returns the pointer to the image section that contains
  430. the RVA
  431. --*/
  432. {
  433. ULONG i;
  434. PIMAGE_SECTION_HEADER NtSection;
  435. NtSection = IMAGE_FIRST_SECTION( NtHeaders );
  436. for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) {
  437. if (Rva >= NtSection->VirtualAddress &&
  438. Rva < NtSection->VirtualAddress + NtSection->SizeOfRawData
  439. ) {
  440. return NtSection;
  441. }
  442. ++NtSection;
  443. }
  444. return NULL;
  445. }
  446. PVOID
  447. RtlImageRvaToVa(
  448. IN PIMAGE_NT_HEADERS NtHeaders,
  449. IN PVOID Base,
  450. IN ULONG Rva,
  451. IN OUT PIMAGE_SECTION_HEADER *LastRvaSection OPTIONAL
  452. )
  453. /*++
  454. Routine Description:
  455. This function locates an RVA within the image header of a file that
  456. is mapped as a file and returns the virtual addrees of the
  457. corresponding byte in the file.
  458. Arguments:
  459. NtHeaders - Supplies the pointer to the image or data file.
  460. Base - Supplies the base of the image or data file. The image
  461. was mapped as a data file.
  462. Rva - Supplies the relative virtual address (RVA) to locate.
  463. LastRvaSection - Optional parameter that if specified, points
  464. to a variable that contains the last section value used for
  465. the specified image to translate and RVA to a VA.
  466. Return Value:
  467. NULL - The file does not contain the specified RVA
  468. NON-NULL - Returns the virtual addrees in the mapped file.
  469. --*/
  470. {
  471. PIMAGE_SECTION_HEADER NtSection;
  472. if (!ARGUMENT_PRESENT( LastRvaSection ) ||
  473. (NtSection = *LastRvaSection) == NULL ||
  474. Rva < NtSection->VirtualAddress ||
  475. Rva >= NtSection->VirtualAddress + NtSection->SizeOfRawData
  476. ) {
  477. NtSection = RtlImageRvaToSection( NtHeaders,
  478. Base,
  479. Rva
  480. );
  481. }
  482. if (NtSection != NULL) {
  483. if (LastRvaSection != NULL) {
  484. *LastRvaSection = NtSection;
  485. }
  486. return (PVOID)((PCHAR)Base +
  487. (Rva - NtSection->VirtualAddress) +
  488. NtSection->PointerToRawData
  489. );
  490. }
  491. else {
  492. return NULL;
  493. }
  494. }
  495. #endif