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.

923 lines
28 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Function entry cache.
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000.
  6. //
  7. //----------------------------------------------------------------------------
  8. #include <nt.h>
  9. #include <ntrtl.h>
  10. #include <nturtl.h>
  11. #include <ntimage.h>
  12. #define NOEXTAPI
  13. #include <wdbgexts.h>
  14. #include <ntdbg.h>
  15. #include "private.h"
  16. #include "symbols.h"
  17. #include "globals.h"
  18. #include "fecache.hpp"
  19. //----------------------------------------------------------------------------
  20. //
  21. // FunctionEntryCache.
  22. //
  23. //----------------------------------------------------------------------------
  24. FunctionEntryCache::FunctionEntryCache(ULONG ImageDataSize,
  25. ULONG CacheDataSize,
  26. ULONG Machine)
  27. {
  28. m_ImageDataSize = ImageDataSize;
  29. m_CacheDataSize = CacheDataSize;
  30. m_Machine = Machine;
  31. m_Entries = NULL;
  32. }
  33. FunctionEntryCache::~FunctionEntryCache(void)
  34. {
  35. if (m_Entries != NULL)
  36. {
  37. MemFree(m_Entries);
  38. }
  39. }
  40. BOOL
  41. FunctionEntryCache::Initialize(ULONG MaxEntries, ULONG ReplaceAt)
  42. {
  43. // Already initialized.
  44. if (m_Entries != NULL) {
  45. return TRUE;
  46. }
  47. m_Entries = (FeCacheEntry*)MemAlloc(sizeof(FeCacheEntry) * MaxEntries);
  48. if (m_Entries == NULL) {
  49. return FALSE;
  50. }
  51. m_MaxEntries = MaxEntries;
  52. m_ReplaceAt = ReplaceAt;
  53. m_Used = 0;
  54. m_Next = 0;
  55. return TRUE;
  56. }
  57. FeCacheEntry*
  58. FunctionEntryCache::Find(
  59. HANDLE Process,
  60. ULONG64 CodeOffset,
  61. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  62. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  63. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
  64. )
  65. {
  66. FeCacheEntry* FunctionEntry;
  67. FE_DEBUG(("\nFunctionEntryCache::Find(ControlPc=%.8I64x, Machine=%X)\n",
  68. CodeOffset, m_Machine));
  69. // Look for a static or dynamic function entry.
  70. FunctionEntry = FindDirect( Process, CodeOffset, ReadMemory,
  71. GetModuleBase, GetFunctionEntry );
  72. if (FunctionEntry == NULL) {
  73. return NULL;
  74. }
  75. //
  76. // The capability exists for more than one function entry
  77. // to map to the same function. This permits a function to
  78. // have discontiguous code segments described by separate
  79. // function table entries. If the ending prologue address
  80. // is not within the limits of the begining and ending
  81. // address of the function table entry, then the prologue
  82. // ending address is the address of the primary function
  83. // table entry that accurately describes the ending prologue
  84. // address.
  85. //
  86. FunctionEntry = SearchForPrimaryEntry(FunctionEntry, Process, ReadMemory,
  87. GetModuleBase, GetFunctionEntry);
  88. #if DBG
  89. if (tlsvar(DebugFunctionEntries)) {
  90. if (FunctionEntry == NULL) {
  91. dbPrint("FunctionEntryCache::Find returning NULL\n");
  92. } else {
  93. if (FunctionEntry->Address) {
  94. dbPrint("FunctionEntryCache::Find returning "
  95. "FunctionEntry=%.8I64x %s\n",
  96. FunctionEntry->Address,
  97. FunctionEntry->Description);
  98. } else {
  99. dbPrint("FunctionEntryCache::Find returning "
  100. "FunctionEntry=%.8I64x %s\n",
  101. (ULONG64)(LONG64)(LONG_PTR)FunctionEntry,
  102. FunctionEntry->Description);
  103. }
  104. }
  105. }
  106. #endif
  107. return FunctionEntry;
  108. }
  109. FeCacheEntry*
  110. FunctionEntryCache::FindDirect(
  111. HANDLE Process,
  112. ULONG64 CodeOffset,
  113. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  114. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  115. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
  116. )
  117. {
  118. FeCacheEntry* FunctionEntry;
  119. ULONG64 ModuleBase;
  120. //
  121. // Look for function entry in static function tables.
  122. //
  123. FunctionEntry = FindStatic( Process, CodeOffset, ReadMemory,
  124. GetModuleBase, GetFunctionEntry,
  125. &ModuleBase );
  126. FE_DEBUG((" FindDirect: ControlPc=0x%I64x functionEntry=0x%p\n"
  127. " FindStatic %s\n", CodeOffset, FunctionEntry,
  128. FunctionEntry != NULL ? "succeeded" : "FAILED"));
  129. if (FunctionEntry != NULL) {
  130. return FunctionEntry;
  131. }
  132. //
  133. // If not in static image range and no static function entry
  134. // found use FunctionEntryCallback routine (if present) for
  135. // dynamic function entry or some other source of pdata (e.g.
  136. // saved pdata information for ROM images).
  137. //
  138. PPROCESS_ENTRY ProcessEntry = FindProcessEntry( Process );
  139. if (ProcessEntry == NULL) {
  140. return NULL;
  141. }
  142. PVOID RawEntry;
  143. if (!ModuleBase) {
  144. if (!IsImageMachineType64(m_Machine) &&
  145. ProcessEntry->pFunctionEntryCallback32) {
  146. RawEntry = ProcessEntry->pFunctionEntryCallback32
  147. (Process, (ULONG)CodeOffset,
  148. (PVOID)ProcessEntry->FunctionEntryUserContext);
  149. if (RawEntry) {
  150. IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Ent64;
  151. // This currently only happens for Axp32 so
  152. // upconvert.
  153. ConvertAlphaRf32To64
  154. ((PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY)RawEntry, &Ent64);
  155. FunctionEntry = FillTemporary(Process, &Ent64);
  156. FE_SET_DESC(FunctionEntry, "from FunctionEntryCallback32");
  157. }
  158. } else if (ProcessEntry->pFunctionEntryCallback64) {
  159. RawEntry = ProcessEntry->pFunctionEntryCallback64
  160. (Process, CodeOffset, ProcessEntry->FunctionEntryUserContext);
  161. if (RawEntry != NULL) {
  162. FunctionEntry = FillTemporary(Process, RawEntry);
  163. FE_SET_DESC(FunctionEntry, "from FunctionEntryCallback64");
  164. }
  165. }
  166. if (FunctionEntry != NULL) {
  167. FE_DEBUG((" FindDirect: got dynamic entry\n"));
  168. } else if (GetFunctionEntry != NULL) {
  169. // VC 6 didn't supply a GetModuleBase callback so this code is
  170. // to make stack walking backward compatible.
  171. //
  172. // If we don't have a function by now, use the old-style function
  173. // entry callback and let VC give it to us. Note that MSDN
  174. // documentation indicates that this callback should return
  175. // a 3-field IMAGE_FUNCTION_ENTRY structure, but VC 6 actually
  176. // returns the 5-field IMAGE_RUNTIME_FUNCTION_ENTRY. Since
  177. // the purpose of this hack is to make VC 6 work just go with the
  178. // way VC 6 does it rather than what MSDN says.
  179. RawEntry = GetFunctionEntry(Process, CodeOffset);
  180. if (RawEntry != NULL) {
  181. FunctionEntry = FillTemporary(Process, RawEntry);
  182. FE_SET_DESC(FunctionEntry, "from GetFunctionEntry");
  183. FE_DEBUG((" FindDirect: got user entry\n"));
  184. }
  185. }
  186. } else {
  187. // Nothing has turned up a function entry but we do have a
  188. // module base address. One possibility is that this is the
  189. // kernel debugger and the pdata section is not paged in.
  190. // The last ditch attempt for a function entry will be an
  191. // internal dbghelp call to get the pdata entry from the
  192. // debug info. This is not great because the data in the debug
  193. // section is incomplete and potentially out of date, but in
  194. // most cases it works and makes it possible to get user-mode
  195. // stack traces in the kernel debugger.
  196. PIMGHLP_RVA_FUNCTION_DATA RvaEntry =
  197. GetFunctionEntryFromDebugInfo( ProcessEntry, CodeOffset );
  198. if (RvaEntry != NULL) {
  199. FeCacheData Data;
  200. TranslateRvaDataToRawData(RvaEntry, ModuleBase, &Data);
  201. FunctionEntry = FillTemporary(Process, &Data);
  202. FE_SET_DESC(FunctionEntry, "from GetFunctionEntryFromDebugInfo");
  203. FE_DEBUG((" FindDirect: got debug info entry\n"));
  204. }
  205. }
  206. return FunctionEntry;
  207. }
  208. FeCacheEntry*
  209. FunctionEntryCache::FindStatic(
  210. HANDLE Process,
  211. ULONG64 CodeOffset,
  212. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  213. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  214. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry,
  215. PULONG64 ModuleBase
  216. )
  217. {
  218. ULONG RelCodeOffset;
  219. *ModuleBase = GetModuleBase( Process, CodeOffset );
  220. if (CodeOffset - *ModuleBase > 0xffffffff) {
  221. return NULL;
  222. }
  223. RelCodeOffset = (ULONG)(CodeOffset - *ModuleBase);
  224. FE_DEBUG((" FindStatic: ControlPc=0x%I64x ImageBase=0x%I64x\n"
  225. " biasedControlPc=0x%lx\n",
  226. CodeOffset, *ModuleBase, RelCodeOffset));
  227. FeCacheEntry* FunctionEntry;
  228. ULONG Index;
  229. //
  230. // Check the array of recently fetched function entries
  231. //
  232. FunctionEntry = m_Entries;
  233. for (Index = 0; Index < m_Used; Index++) {
  234. if (FunctionEntry->Process == Process &&
  235. FunctionEntry->ModuleBase == *ModuleBase &&
  236. RelCodeOffset >= FunctionEntry->RelBegin &&
  237. RelCodeOffset < FunctionEntry->RelEnd) {
  238. FE_DEBUG((" FindStatic: cache hit - index=%ld\n", Index));
  239. return FunctionEntry;
  240. }
  241. FunctionEntry++;
  242. }
  243. //
  244. // If an image was found that included the specified code, then locate the
  245. // function table for the image.
  246. //
  247. if (*ModuleBase == 0) {
  248. return NULL;
  249. }
  250. ULONG64 FunctionTable;
  251. ULONG SizeOfFunctionTable;
  252. FunctionTable = FunctionTableBase( Process, ReadMemory, *ModuleBase,
  253. &SizeOfFunctionTable );
  254. if (FunctionTable == NULL) {
  255. return NULL;
  256. }
  257. FE_DEBUG((" FindStatic: functionTable=0x%I64x "
  258. "sizeOfFunctionTable=%ld count:%ld\n",
  259. FunctionTable, SizeOfFunctionTable,
  260. SizeOfFunctionTable / m_ImageDataSize));
  261. LONG High;
  262. LONG Low;
  263. LONG Middle;
  264. //
  265. // If a function table is located, then search the function table
  266. // for a function table entry for the specified code offset.
  267. //
  268. Low = 0;
  269. High = (SizeOfFunctionTable / m_ImageDataSize) - 1;
  270. //
  271. // Perform binary search on the function table for a function table
  272. // entry that subsumes the specified code offset.
  273. //
  274. while (High >= Low) {
  275. //
  276. // Compute next probe index and test entry. If the specified PC
  277. // is greater than of equal to the beginning address and less
  278. // than the ending address of the function table entry, then
  279. // return the address of the function table entry. Otherwise,
  280. // continue the search.
  281. //
  282. Middle = (Low + High) >> 1;
  283. ULONG64 NextFunctionTableEntry = FunctionTable +
  284. Middle * m_ImageDataSize;
  285. //
  286. // Fetch the function entry and bail if there is an error reading it
  287. //
  288. FunctionEntry = ReadImage( Process, NextFunctionTableEntry,
  289. ReadMemory, GetModuleBase );
  290. if (FunctionEntry == NULL) {
  291. FE_DEBUG((" FindStatic: ReadImage "
  292. "functionEntryAddress=0x%I64x FAILED\n",
  293. NextFunctionTableEntry));
  294. return NULL;
  295. }
  296. if (RelCodeOffset < FunctionEntry->RelBegin) {
  297. High = Middle - 1;
  298. } else if (RelCodeOffset >= FunctionEntry->RelEnd) {
  299. Low = Middle + 1;
  300. } else {
  301. return Promote( FunctionEntry );
  302. }
  303. }
  304. return NULL;
  305. }
  306. FeCacheEntry*
  307. FunctionEntryCache::ReadImage(
  308. HANDLE Process,
  309. ULONG64 Address,
  310. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  311. PGET_MODULE_BASE_ROUTINE64 GetModuleBase
  312. )
  313. {
  314. FeCacheEntry* FunctionEntry;
  315. ULONG Index;
  316. // Check the array of recently fetched function entries.
  317. FunctionEntry = m_Entries;
  318. for (Index = 0; Index < m_Used; Index++) {
  319. if (FunctionEntry->Process == Process &&
  320. FunctionEntry->Address == Address ) {
  321. return FunctionEntry;
  322. }
  323. FunctionEntry++;
  324. }
  325. FeCacheData Data;
  326. DWORD Done;
  327. if (!ReadMemory(Process, Address, &Data, m_ImageDataSize, &Done) ||
  328. Done != m_ImageDataSize) {
  329. return NULL;
  330. }
  331. // If not in the cache, replace the entry that m_Next
  332. // points to. m_Next cycles through the last part of the
  333. // table and function entries we want to keep are promoted to the first
  334. // part of the table so they don't get overwritten by new ones being read
  335. // as part of the binary search through function entry tables.
  336. if (m_Used < m_MaxEntries) {
  337. m_Used++;
  338. m_Next = m_Used;
  339. } else {
  340. m_Next++;
  341. if (m_Next >= m_MaxEntries) {
  342. m_Next = m_ReplaceAt + 1;
  343. }
  344. }
  345. FunctionEntry = m_Entries + (m_Next - 1);
  346. FunctionEntry->Data = Data;
  347. FunctionEntry->Address = Address;
  348. FunctionEntry->Process = Process;
  349. FunctionEntry->ModuleBase = GetModuleBase(Process, Address);
  350. FE_SET_DESC(FunctionEntry, "from target process");
  351. // Translate after all other information is filled in so
  352. // the translation routine can use it.
  353. TranslateRawData(FunctionEntry);
  354. return FunctionEntry;
  355. }
  356. void
  357. FunctionEntryCache::InvalidateProcessOrModule(HANDLE Process, ULONG64 Base)
  358. {
  359. FeCacheEntry* FunctionEntry;
  360. ULONG Index;
  361. FunctionEntry = m_Entries;
  362. Index = 0;
  363. while (Index < m_Used) {
  364. if (FunctionEntry->Process == Process &&
  365. (Base == 0 || FunctionEntry->ModuleBase == Base)) {
  366. // Pull the last entry down into this slot
  367. // to keep things packed. There's no need
  368. // to update m_Next as this will open a
  369. // new slot for use and m_Next will be reset
  370. // when it is used.
  371. *FunctionEntry = m_Entries[--m_Used];
  372. } else {
  373. Index++;
  374. FunctionEntry++;
  375. }
  376. }
  377. }
  378. FeCacheEntry*
  379. FunctionEntryCache::Promote(FeCacheEntry* Entry)
  380. {
  381. ULONG Index;
  382. ULONG Move;
  383. Index = (ULONG)(Entry - m_Entries);
  384. // Make sure it's promoted out of the temporary area.
  385. if (Index >= m_ReplaceAt) {
  386. Move = Index - (m_ReplaceAt - 3);
  387. } else {
  388. Move = ( Index >= 3 ) ? 3 : 1;
  389. }
  390. if (Index > Move) {
  391. FeCacheEntry Temp = *Entry;
  392. *Entry = m_Entries[Index - Move];
  393. m_Entries[Index - Move] = Temp;
  394. Index -= Move;
  395. }
  396. return m_Entries + Index;
  397. }
  398. ULONG64
  399. FunctionEntryCache::FunctionTableBase(
  400. HANDLE Process,
  401. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  402. ULONG64 Base,
  403. PULONG Size
  404. )
  405. {
  406. ULONG64 NtHeaders;
  407. ULONG64 ExceptionDirectoryEntryAddress;
  408. IMAGE_DATA_DIRECTORY ExceptionData;
  409. IMAGE_DOS_HEADER DosHeaderData;
  410. DWORD Done;
  411. // Read DOS header to calculate the address of the NT header.
  412. if (!ReadMemory( Process, Base, &DosHeaderData, sizeof(DosHeaderData),
  413. &Done ) ||
  414. Done != sizeof(DosHeaderData)) {
  415. return 0;
  416. }
  417. if (DosHeaderData.e_magic != IMAGE_DOS_SIGNATURE) {
  418. return 0;
  419. }
  420. NtHeaders = Base + DosHeaderData.e_lfanew;
  421. if (IsImageMachineType64(m_Machine)) {
  422. ExceptionDirectoryEntryAddress = NtHeaders +
  423. FIELD_OFFSET(IMAGE_NT_HEADERS64,OptionalHeader) +
  424. FIELD_OFFSET(IMAGE_OPTIONAL_HEADER64,DataDirectory) +
  425. IMAGE_DIRECTORY_ENTRY_EXCEPTION * sizeof(IMAGE_DATA_DIRECTORY);
  426. } else {
  427. ExceptionDirectoryEntryAddress = NtHeaders +
  428. FIELD_OFFSET(IMAGE_NT_HEADERS32,OptionalHeader) +
  429. FIELD_OFFSET(IMAGE_OPTIONAL_HEADER32,DataDirectory) +
  430. IMAGE_DIRECTORY_ENTRY_EXCEPTION * sizeof(IMAGE_DATA_DIRECTORY);
  431. }
  432. // Read NT header to get the image data directory.
  433. if (!ReadMemory( Process, ExceptionDirectoryEntryAddress, &ExceptionData,
  434. sizeof(IMAGE_DATA_DIRECTORY), &Done ) ||
  435. Done != sizeof(IMAGE_DATA_DIRECTORY)) {
  436. return 0;
  437. }
  438. *Size = ExceptionData.Size;
  439. return Base + ExceptionData.VirtualAddress;
  440. }
  441. FeCacheEntry*
  442. FunctionEntryCache::SearchForPrimaryEntry(
  443. FeCacheEntry* CacheEntry,
  444. HANDLE Process,
  445. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  446. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  447. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
  448. )
  449. {
  450. // Assume all entries are primary.
  451. return CacheEntry;
  452. }
  453. //----------------------------------------------------------------------------
  454. //
  455. // Ia64FunctionEntryCache.
  456. //
  457. //----------------------------------------------------------------------------
  458. void
  459. Ia64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
  460. {
  461. Entry->RelBegin = Entry->Data.Ia64.BeginAddress & ~15;
  462. Entry->RelEnd = (Entry->Data.Ia64.EndAddress + 15) & ~15;
  463. }
  464. void
  465. Ia64FunctionEntryCache::TranslateRvaDataToRawData
  466. (PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
  467. FeCacheData* Data)
  468. {
  469. Data->Ia64.BeginAddress = RvaData->rvaBeginAddress;
  470. Data->Ia64.EndAddress = RvaData->rvaEndAddress;
  471. Data->Ia64.UnwindInfoAddress = RvaData->rvaPrologEndAddress;
  472. }
  473. #if DBG
  474. void
  475. ShowRuntimeFunctionIa64(
  476. FeCacheEntry* FunctionEntry,
  477. PSTR Label
  478. )
  479. {
  480. if (!tlsvar(DebugFunctionEntries)) {
  481. return;
  482. }
  483. if ( FunctionEntry ) {
  484. if (FunctionEntry->Address) {
  485. dbPrint(" 0x%I64x: %s\n", FunctionEntry->Address,
  486. Label ? Label : "" );
  487. }
  488. else {
  489. dbPrint(" %s\n", Label ? Label : "" );
  490. }
  491. dbPrint(" BeginAddress = 0x%x\n"
  492. " EndAddress = 0x%x\n"
  493. " UnwindInfoAddress = 0x%x\n",
  494. FunctionEntry->Data.Ia64.BeginAddress,
  495. FunctionEntry->Data.Ia64.EndAddress,
  496. FunctionEntry->Data.Ia64.UnwindInfoAddress );
  497. }
  498. else {
  499. dbPrint(" FunctionEntry NULL: %s\n", Label ? Label : "" );
  500. }
  501. }
  502. #endif // #if DBG
  503. //----------------------------------------------------------------------------
  504. //
  505. // Amd64FunctionEntryCache.
  506. //
  507. //----------------------------------------------------------------------------
  508. void
  509. Amd64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
  510. {
  511. Entry->RelBegin = Entry->Data.Amd64.BeginAddress;
  512. Entry->RelEnd = Entry->Data.Amd64.EndAddress;
  513. }
  514. void
  515. Amd64FunctionEntryCache::TranslateRvaDataToRawData
  516. (PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
  517. FeCacheData* Data)
  518. {
  519. Data->Amd64.BeginAddress = RvaData->rvaBeginAddress;
  520. Data->Amd64.EndAddress = RvaData->rvaEndAddress;
  521. Data->Amd64.UnwindInfoAddress = RvaData->rvaPrologEndAddress;
  522. }
  523. //----------------------------------------------------------------------------
  524. //
  525. // AlphaFunctionEntryCache.
  526. //
  527. //----------------------------------------------------------------------------
  528. void
  529. AlphaFunctionEntryCache::TranslateRvaDataToRawData
  530. (PIMGHLP_RVA_FUNCTION_DATA RvaData, ULONG64 ModuleBase,
  531. FeCacheData* Data)
  532. {
  533. Data->Axp64.BeginAddress = ModuleBase + RvaData->rvaBeginAddress;
  534. Data->Axp64.EndAddress = ModuleBase + RvaData->rvaEndAddress;
  535. Data->Axp64.ExceptionHandler = 0;
  536. Data->Axp64.HandlerData = 0;
  537. Data->Axp64.PrologEndAddress = ModuleBase + RvaData->rvaPrologEndAddress;
  538. }
  539. FeCacheEntry*
  540. AlphaFunctionEntryCache::SearchForPrimaryEntry(
  541. FeCacheEntry* CacheEntry,
  542. HANDLE Process,
  543. PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemory,
  544. PGET_MODULE_BASE_ROUTINE64 GetModuleBase,
  545. PFUNCTION_TABLE_ACCESS_ROUTINE64 GetFunctionEntry
  546. )
  547. {
  548. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY FunctionEntry =
  549. &CacheEntry->Data.Axp64;
  550. if ((ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) <
  551. ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
  552. (ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry) >=
  553. ALPHA_RF_END_ADDRESS(FunctionEntry))) {
  554. FE_ShowRuntimeFunctionAxp64
  555. ((CacheEntry, "SearchForPrimaryEntry: secondary entry"));
  556. // Officially the PrologEndAddress field in secondary function entries
  557. // doesn't have the exception mode bits there have been some versions
  558. // of alpha tools that put them there. Strip them off to be safe.
  559. CacheEntry = ReadImage( Process,
  560. ALPHA_RF_PROLOG_END_ADDRESS(FunctionEntry),
  561. ReadMemory, GetModuleBase );
  562. if (!CacheEntry) {
  563. return NULL;
  564. }
  565. CacheEntry = Promote( CacheEntry );
  566. } else if (ALPHA_RF_IS_FIXED_RETURN(FunctionEntry)) {
  567. ULONG64 FixedReturn = ALPHA_RF_FIXED_RETURN64(FunctionEntry);
  568. FE_ShowRuntimeFunctionAxp64
  569. ((CacheEntry, "SearchForPrimaryEntry: fixed return entry"));
  570. // Recursively call Find to ensure we get a
  571. // primary function entry here.
  572. // Check for incorrectly formed function entry where the fixed
  573. // return points to itself.
  574. if ((FixedReturn < ALPHA_RF_BEGIN_ADDRESS(FunctionEntry)) ||
  575. (FixedReturn >= ALPHA_RF_END_ADDRESS(FunctionEntry))) {
  576. CacheEntry = Find( Process, ALPHA_RF_FIXED_RETURN64(FunctionEntry),
  577. ReadMemory, GetModuleBase, GetFunctionEntry );
  578. }
  579. }
  580. FE_ShowRuntimeFunctionAxp64
  581. ((CacheEntry, "SearchForPrimaryEntry: primary entry"));
  582. return CacheEntry;
  583. }
  584. void
  585. ConvertAlphaRf32To64(
  586. PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY rf32,
  587. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY rf64
  588. )
  589. {
  590. rf64->BeginAddress = (ULONG64)(LONG64)(LONG)rf32->BeginAddress;
  591. rf64->EndAddress = (ULONG64)(LONG64)(LONG)rf32->EndAddress;
  592. rf64->ExceptionHandler = (ULONG64)(LONG64)(LONG)rf32->ExceptionHandler;
  593. rf64->HandlerData = (ULONG64)(LONG64)(LONG)rf32->HandlerData;
  594. rf64->PrologEndAddress = (ULONG64)(LONG64)(LONG)rf32->PrologEndAddress;
  595. }
  596. #if DBG
  597. #define MAXENTRYTYPE 2
  598. const char *EntryTypeName[] = {
  599. "ALPHA_RF_NOT_CONTIGUOUS", // 0
  600. "ALPHA_RF_ALT_ENT_PROLOG", // 1
  601. "ALPHA_RF_NULL_CONTEXT", // 2
  602. "***INVALID***"
  603. };
  604. void
  605. ShowRuntimeFunctionAxp64(
  606. FeCacheEntry* FunctionEntry,
  607. PSTR Label
  608. )
  609. {
  610. BOOL Secondary = FALSE;
  611. BOOL FixedReturn = FALSE;
  612. ULONG EntryType = 0;
  613. ULONG NullCount = 0;
  614. if (tlsvar(DebugFunctionEntries)) {
  615. if (FunctionEntry != NULL && FunctionEntry->Address) {
  616. dbPrint(" %.8I64x: ", FunctionEntry->Address );
  617. } else {
  618. dbPrint(" ");
  619. }
  620. if (Label) {
  621. dbPrint(Label);
  622. }
  623. dbPrint("\n");
  624. if (FunctionEntry) {
  625. PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Axp64 =
  626. &FunctionEntry->Data.Axp64;
  627. if ((ALPHA_RF_PROLOG_END_ADDRESS(Axp64) <
  628. ALPHA_RF_BEGIN_ADDRESS(Axp64)) ||
  629. (ALPHA_RF_PROLOG_END_ADDRESS(Axp64) >
  630. ALPHA_RF_END_ADDRESS(Axp64))) {
  631. Secondary = TRUE;
  632. EntryType = ALPHA_RF_ENTRY_TYPE(Axp64);
  633. if (EntryType > MAXENTRYTYPE) {
  634. EntryType = MAXENTRYTYPE;
  635. }
  636. } else if (ALPHA_RF_IS_FIXED_RETURN(Axp64)) {
  637. FixedReturn = TRUE;
  638. }
  639. NullCount = ALPHA_RF_NULL_CONTEXT_COUNT(Axp64);
  640. dbPrint(" BeginAddress = %16.8I64x\n", Axp64->BeginAddress);
  641. dbPrint(" EndAddress = %16.8I64x", Axp64->EndAddress);
  642. if (NullCount) {
  643. dbPrint(" %d null-context instructions", NullCount);
  644. }
  645. dbPrint("\n");
  646. dbPrint(" ExceptionHandler = %16.8I64x",
  647. Axp64->ExceptionHandler);
  648. if (Axp64->ExceptionHandler != 0) {
  649. if (Secondary) {
  650. ULONG64 AlternateProlog = ALPHA_RF_ALT_PROLOG64(Axp64);
  651. switch( EntryType ) {
  652. case ALPHA_RF_NOT_CONTIGUOUS:
  653. case ALPHA_RF_ALT_ENT_PROLOG:
  654. if ((AlternateProlog >=
  655. ALPHA_RF_BEGIN_ADDRESS(Axp64)) &&
  656. (AlternateProlog <= Axp64->EndAddress)) {
  657. dbPrint(" alternate PrologEndAddress");
  658. }
  659. break;
  660. case ALPHA_RF_NULL_CONTEXT:
  661. dbPrint(" stack adjustment");
  662. }
  663. } else if (FixedReturn) {
  664. dbPrint(" fixed return address");
  665. }
  666. }
  667. dbPrint("\n");
  668. dbPrint(" HandlerData = %16.8I64x", Axp64->HandlerData);
  669. if (Secondary) {
  670. dbPrint(" type %d: %s", EntryType, EntryTypeName[EntryType] );
  671. }
  672. dbPrint("\n");
  673. dbPrint(" PrologEndAddress = %16.8I64x\n",
  674. Axp64->PrologEndAddress );
  675. }
  676. }
  677. }
  678. #endif // #if DBG
  679. //----------------------------------------------------------------------------
  680. //
  681. // Axp32FunctionEntryCache.
  682. //
  683. //----------------------------------------------------------------------------
  684. void
  685. Axp32FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
  686. {
  687. IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY Ent64;
  688. // Convert to 64-bit so that Alpha function entries are
  689. // always stored as 64-bit for code commonality.
  690. ConvertAlphaRf32To64(&Entry->Data.Axp32, &Ent64);
  691. Entry->Data.Axp64 = Ent64;
  692. Entry->RelBegin = (ULONG)
  693. (Entry->Data.Axp64.BeginAddress - Entry->ModuleBase);
  694. Entry->RelEnd = (ULONG)
  695. (Entry->Data.Axp64.EndAddress - Entry->ModuleBase);
  696. }
  697. //----------------------------------------------------------------------------
  698. //
  699. // Axp64FunctionEntryCache.
  700. //
  701. //----------------------------------------------------------------------------
  702. void
  703. Axp64FunctionEntryCache::TranslateRawData(FeCacheEntry* Entry)
  704. {
  705. Entry->RelBegin = (ULONG)
  706. (Entry->Data.Axp64.BeginAddress - Entry->ModuleBase);
  707. Entry->RelEnd = (ULONG)
  708. (Entry->Data.Axp64.EndAddress - Entry->ModuleBase);
  709. }
  710. //----------------------------------------------------------------------------
  711. //
  712. // Functions.
  713. //
  714. //----------------------------------------------------------------------------
  715. FunctionEntryCache*
  716. GetFeCache(ULONG Machine, BOOL Create)
  717. {
  718. FunctionEntryCache* Cache;
  719. switch(Machine) {
  720. case IMAGE_FILE_MACHINE_ALPHA:
  721. if (tlsvar(Axp32FunctionEntries) == NULL && Create) {
  722. tlsvar(Axp32FunctionEntries) = new Axp32FunctionEntryCache;
  723. if (tlsvar(Axp32FunctionEntries) == NULL) {
  724. return NULL;
  725. }
  726. }
  727. Cache = tlsvar(Axp32FunctionEntries);
  728. break;
  729. case IMAGE_FILE_MACHINE_ALPHA64:
  730. if (tlsvar(Axp64FunctionEntries) == NULL && Create) {
  731. tlsvar(Axp64FunctionEntries) = new Axp64FunctionEntryCache;
  732. if (tlsvar(Axp64FunctionEntries) == NULL) {
  733. return NULL;
  734. }
  735. }
  736. Cache = tlsvar(Axp64FunctionEntries);
  737. break;
  738. case IMAGE_FILE_MACHINE_AMD64:
  739. if (tlsvar(Amd64FunctionEntries) == NULL && Create) {
  740. tlsvar(Amd64FunctionEntries) = new Amd64FunctionEntryCache;
  741. if (tlsvar(Amd64FunctionEntries) == NULL) {
  742. return NULL;
  743. }
  744. }
  745. Cache = tlsvar(Amd64FunctionEntries);
  746. break;
  747. case IMAGE_FILE_MACHINE_IA64:
  748. if (tlsvar(Ia64FunctionEntries) == NULL && Create) {
  749. tlsvar(Ia64FunctionEntries) = new Ia64FunctionEntryCache;
  750. if (tlsvar(Ia64FunctionEntries) == NULL) {
  751. return NULL;
  752. }
  753. }
  754. Cache = tlsvar(Ia64FunctionEntries);
  755. break;
  756. default:
  757. return NULL;
  758. }
  759. if (Cache && !Cache->Initialize(60, 40)) {
  760. return NULL;
  761. }
  762. return Cache;
  763. }
  764. void
  765. ClearFeCaches(void)
  766. {
  767. if (tlsvar(Axp32FunctionEntries)) {
  768. delete (Axp32FunctionEntryCache*)tlsvar(Axp32FunctionEntries);
  769. tlsvar(Axp32FunctionEntries) = NULL;
  770. }
  771. if (tlsvar(Axp64FunctionEntries)) {
  772. delete (Axp64FunctionEntryCache*)tlsvar(Axp64FunctionEntries);
  773. tlsvar(Axp64FunctionEntries) = NULL;
  774. }
  775. if (tlsvar(Ia64FunctionEntries)) {
  776. delete (Ia64FunctionEntryCache*)tlsvar(Ia64FunctionEntries);
  777. tlsvar(Ia64FunctionEntries) = NULL;
  778. }
  779. if (tlsvar(Amd64FunctionEntries)) {
  780. delete (Amd64FunctionEntryCache*)tlsvar(Amd64FunctionEntries);
  781. tlsvar(Amd64FunctionEntries) = NULL;
  782. }
  783. }