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.

1020 lines
31 KiB

  1. #ifndef _WIN64
  2. /*++
  3. Copyright (c) 1992 Microsoft Corporation
  4. Module Name:
  5. symhelp.c
  6. Abstract:
  7. Symbol Helper for debugging
  8. Author:
  9. Steve Wood (stevewo) 11-Mar-1994
  10. Revision History:
  11. --*/
  12. #define _SYMHELP_SOURCE_
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include <imagehlp.h>
  18. #include <debug.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include "symhelp.h"
  22. //
  23. // Primitives to access symbolic debug information in an image file
  24. //
  25. typedef struct _RTL_SYMBOL_INFORMATION {
  26. ULONG Type;
  27. ULONG SectionNumber;
  28. ULONG Value;
  29. STRING Name;
  30. } RTL_SYMBOL_INFORMATION, *PRTL_SYMBOL_INFORMATION;
  31. NTSTATUS
  32. RtlLookupSymbolByAddress(
  33. IN PVOID ImageBase,
  34. IN PVOID MappedBase OPTIONAL,
  35. IN PVOID Address,
  36. IN ULONG ClosenessLimit,
  37. OUT PRTL_SYMBOL_INFORMATION SymbolInformation,
  38. OUT PRTL_SYMBOL_INFORMATION NextSymbolInformation OPTIONAL
  39. );
  40. typedef struct _PROCESS_DEBUG_INFORMATION {
  41. LIST_ENTRY List;
  42. HANDLE UniqueProcess;
  43. DWORD ImageBase;
  44. DWORD EndOfImage;
  45. PIMAGE_DEBUG_INFORMATION DebugInfo;
  46. UCHAR ImageFilePath[ MAX_PATH ];
  47. } PROCESS_DEBUG_INFORMATION, *PPROCESS_DEBUG_INFORMATION;
  48. PLOAD_SYMBOLS_FILTER_ROUTINE LoadSymbolsFilterRoutine;
  49. RTL_CRITICAL_SECTION LoadedImageDebugInfoListCritSect;
  50. LIST_ENTRY LoadedImageDebugInfoListHead;
  51. LIST_ENTRY LoadedProcessDebugInfoListHead;
  52. LPSTR SymbolSearchPath;
  53. // This variable tracks how many times InitializeImageDebugInformation has been
  54. // called. Certain operations are performed only on the first call (as
  55. // NumInitCalls transitions from -1 to 0).
  56. LONG NumInitCalls = -1;
  57. LPSTR
  58. GetEnvVariable(
  59. IN LPSTR VariableName
  60. )
  61. {
  62. NTSTATUS Status;
  63. STRING Name, Value;
  64. UNICODE_STRING UnicodeName, UnicodeValue;
  65. RtlInitString( &Name, VariableName );
  66. RtlInitUnicodeString( &UnicodeValue, NULL );
  67. Status = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE );
  68. if (!NT_SUCCESS( Status )) {
  69. return NULL;
  70. }
  71. Status = RtlQueryEnvironmentVariable_U( NULL, &UnicodeName, &UnicodeValue );
  72. if (Status != STATUS_BUFFER_TOO_SMALL) {
  73. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  74. return NULL;
  75. }
  76. UnicodeValue.MaximumLength = UnicodeValue.Length + sizeof( UNICODE_NULL );
  77. UnicodeValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, UnicodeValue.MaximumLength );
  78. if (UnicodeValue.Buffer == NULL) {
  79. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  80. return NULL;
  81. }
  82. Status = RtlQueryEnvironmentVariable_U( NULL, &UnicodeName, &UnicodeValue );
  83. if (!NT_SUCCESS( Status )) {
  84. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  85. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  86. return NULL;
  87. }
  88. Status = RtlUnicodeStringToAnsiString( &Value, &UnicodeValue, TRUE );
  89. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  90. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  91. if (!NT_SUCCESS( Status )) {
  92. return NULL;
  93. }
  94. Value.Buffer[ Value.Length ] = '\0';
  95. return Value.Buffer;
  96. }
  97. LPSTR
  98. SetSymbolSearchPath( )
  99. {
  100. ULONG Size, i, Attributes, NumberOfSymbolPaths;
  101. LPSTR s, SymbolPaths[ 4 ];
  102. if (SymbolSearchPath != NULL) {
  103. return SymbolSearchPath;
  104. }
  105. Size = 0;
  106. NumberOfSymbolPaths = 0;
  107. if (s = GetEnvVariable( "_NT_SYMBOL_PATH" )) {
  108. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  109. }
  110. if (s = GetEnvVariable( "_NT_ALT_SYMBOL_PATH" )) {
  111. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  112. }
  113. if (s = GetEnvVariable( "SystemRoot" )) {
  114. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  115. }
  116. SymbolPaths[ NumberOfSymbolPaths++ ] = ".";
  117. Size = 1;
  118. for (i=0; i<NumberOfSymbolPaths; i++) {
  119. Attributes = GetFileAttributesA( SymbolPaths[ i ] );
  120. if ( Attributes != 0xffffffff && (Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  121. Size += 1 + strlen( SymbolPaths[ i ] );
  122. }
  123. else {
  124. SymbolPaths[ i ] = NULL;
  125. }
  126. }
  127. SymbolSearchPath = RtlAllocateHeap( RtlProcessHeap(), 0, Size );
  128. if (SymbolSearchPath == NULL) {
  129. return NULL;
  130. }
  131. *SymbolSearchPath = '\0';
  132. for (i=0; i<NumberOfSymbolPaths; i++) {
  133. if (s = SymbolPaths[ i ]) {
  134. if (*SymbolSearchPath != '\0') {
  135. strcat( SymbolSearchPath, ";" );
  136. }
  137. strcat( SymbolSearchPath, s );
  138. }
  139. }
  140. return SymbolSearchPath;
  141. }
  142. BOOL
  143. InitializeImageDebugInformation(
  144. IN PLOAD_SYMBOLS_FILTER_ROUTINE LoadSymbolsFilter,
  145. IN HANDLE TargetProcess,
  146. IN BOOL NewProcess,
  147. IN BOOL GetKernelSymbols
  148. )
  149. {
  150. PPEB Peb;
  151. NTSTATUS Status;
  152. PROCESS_BASIC_INFORMATION ProcessInformation;
  153. PLDR_DATA_TABLE_ENTRY LdrEntry;
  154. LDR_DATA_TABLE_ENTRY LdrEntryData;
  155. PLIST_ENTRY LdrHead, LdrNext;
  156. PPEB_LDR_DATA Ldr;
  157. UNICODE_STRING UnicodeString;
  158. ANSI_STRING AnsiString;
  159. LPSTR ImageFilePath;
  160. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  161. RTL_PROCESS_MODULES ModuleInfoBuffer;
  162. PRTL_PROCESS_MODULES ModuleInfo;
  163. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo1;
  164. ULONG RequiredLength, ModuleNumber;
  165. // Is this the first call?
  166. if ( InterlockedIncrement ( &NumInitCalls ) == 0 )
  167. {
  168. // Yes
  169. SetSymbolSearchPath();
  170. InitializeListHead( &LoadedImageDebugInfoListHead );
  171. InitializeListHead( &LoadedProcessDebugInfoListHead );
  172. Status = RtlInitializeCriticalSection( &LoadedImageDebugInfoListCritSect );
  173. if (!NT_SUCCESS(Status)) {
  174. return FALSE;
  175. }
  176. }
  177. // The filter routine can be superceded at any time.
  178. LoadSymbolsFilterRoutine = LoadSymbolsFilter;
  179. if (GetKernelSymbols) {
  180. ModuleInfo = &ModuleInfoBuffer;
  181. RequiredLength = sizeof( *ModuleInfo );
  182. Status = NtQuerySystemInformation( SystemModuleInformation,
  183. ModuleInfo,
  184. RequiredLength,
  185. &RequiredLength
  186. );
  187. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  188. ModuleInfo = NULL;
  189. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  190. &ModuleInfo,
  191. 0,
  192. &RequiredLength,
  193. MEM_COMMIT,
  194. PAGE_READWRITE
  195. );
  196. if (NT_SUCCESS( Status )) {
  197. Status = NtQuerySystemInformation( SystemModuleInformation,
  198. ModuleInfo,
  199. RequiredLength,
  200. &RequiredLength
  201. );
  202. if (NT_SUCCESS( Status )) {
  203. ModuleInfo1 = &ModuleInfo->Modules[ 0 ];
  204. for (ModuleNumber=0; ModuleNumber<ModuleInfo->NumberOfModules; ModuleNumber++) {
  205. if ((DWORD)(ModuleInfo1->ImageBase) & 0x80000000) {
  206. if (ImageFilePath = strchr( ModuleInfo1->FullPathName, ':')) {
  207. ImageFilePath -= 1;
  208. }
  209. else {
  210. ImageFilePath = ModuleInfo1->FullPathName +
  211. strlen( ModuleInfo1->FullPathName );
  212. while (ImageFilePath > ModuleInfo1->FullPathName) {
  213. if (ImageFilePath[ -1 ] == '\\') {
  214. break;
  215. }
  216. else {
  217. ImageFilePath -= 1;
  218. }
  219. }
  220. }
  221. AddImageDebugInformation( NULL,
  222. ImageFilePath,
  223. (DWORD)ModuleInfo1->ImageBase,
  224. ModuleInfo1->ImageSize
  225. );
  226. }
  227. ModuleInfo1++;
  228. }
  229. }
  230. NtFreeVirtualMemory( NtCurrentProcess(),
  231. &ModuleInfo,
  232. &RequiredLength,
  233. MEM_RELEASE
  234. );
  235. }
  236. }
  237. }
  238. if (TargetProcess == NULL) {
  239. // Load module information for this process.
  240. TargetProcess = GetCurrentProcess();
  241. }
  242. Status = NtQueryInformationProcess( TargetProcess,
  243. ProcessBasicInformation,
  244. &ProcessInformation,
  245. sizeof( ProcessInformation ),
  246. NULL
  247. );
  248. if (!NT_SUCCESS( Status )) {
  249. return FALSE;
  250. }
  251. Peb = ProcessInformation.PebBaseAddress;
  252. if (NewProcess) {
  253. return TRUE;
  254. }
  255. //
  256. // Ldr = Peb->Ldr
  257. //
  258. Status = NtReadVirtualMemory( TargetProcess,
  259. &Peb->Ldr,
  260. &Ldr,
  261. sizeof( Ldr ),
  262. NULL
  263. );
  264. if (!NT_SUCCESS( Status )) {
  265. return FALSE;
  266. }
  267. LdrHead = &Ldr->InMemoryOrderModuleList;
  268. //
  269. // LdrNext = Head->Flink;
  270. //
  271. Status = NtReadVirtualMemory( TargetProcess,
  272. &LdrHead->Flink,
  273. &LdrNext,
  274. sizeof( LdrNext ),
  275. NULL
  276. );
  277. if (!NT_SUCCESS( Status )) {
  278. return FALSE;
  279. }
  280. while (LdrNext != LdrHead) {
  281. LdrEntry = CONTAINING_RECORD( LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
  282. Status = NtReadVirtualMemory( TargetProcess,
  283. LdrEntry,
  284. &LdrEntryData,
  285. sizeof( LdrEntryData ),
  286. NULL
  287. );
  288. if (!NT_SUCCESS( Status )) {
  289. return FALSE;
  290. }
  291. UnicodeString.Length = LdrEntryData.FullDllName.Length;
  292. UnicodeString.MaximumLength = LdrEntryData.FullDllName.MaximumLength;
  293. UnicodeString.Buffer = RtlAllocateHeap( RtlProcessHeap(),
  294. 0,
  295. UnicodeString.MaximumLength
  296. );
  297. if (!UnicodeString.Buffer) {
  298. return FALSE;
  299. }
  300. Status = NtReadVirtualMemory( TargetProcess,
  301. LdrEntryData.FullDllName.Buffer,
  302. UnicodeString.Buffer,
  303. UnicodeString.MaximumLength,
  304. NULL
  305. );
  306. if (!NT_SUCCESS( Status )) {
  307. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeString.Buffer );
  308. return FALSE;
  309. }
  310. RtlUnicodeStringToAnsiString( &AnsiString,
  311. &UnicodeString,
  312. TRUE
  313. );
  314. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeString.Buffer );
  315. if (ImageFilePath = strchr( AnsiString.Buffer, ':')) {
  316. ImageFilePath -= 1;
  317. }
  318. else {
  319. ImageFilePath = AnsiString.Buffer;
  320. }
  321. AddImageDebugInformation( (HANDLE)ProcessInformation.UniqueProcessId,
  322. ImageFilePath,
  323. (DWORD)LdrEntryData.DllBase,
  324. LdrEntryData.SizeOfImage
  325. );
  326. RtlFreeAnsiString( &AnsiString );
  327. LdrNext = LdrEntryData.InMemoryOrderLinks.Flink;
  328. }
  329. return TRUE;
  330. }
  331. BOOL
  332. AddImageDebugInformation(
  333. IN HANDLE UniqueProcess,
  334. IN LPSTR ImageFilePath,
  335. IN DWORD ImageBase,
  336. IN DWORD ImageSize
  337. )
  338. {
  339. NTSTATUS Status;
  340. PLIST_ENTRY Head, Next;
  341. PIMAGE_DEBUG_INFORMATION DebugInfo;
  342. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  343. HANDLE FileHandle;
  344. UCHAR PathBuffer[ MAX_PATH ];
  345. FileHandle = FindExecutableImage( ImageFilePath, SymbolSearchPath, PathBuffer );
  346. if (FileHandle == NULL) {
  347. if (LoadSymbolsFilterRoutine != NULL) {
  348. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  349. ImageFilePath,
  350. ImageBase,
  351. ImageSize,
  352. LoadSymbolsPathNotFound
  353. );
  354. }
  355. return FALSE;
  356. }
  357. CloseHandle( FileHandle );
  358. if (LoadSymbolsFilterRoutine != NULL) {
  359. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  360. PathBuffer,
  361. ImageBase,
  362. ImageSize,
  363. LoadSymbolsDeferredLoad
  364. );
  365. }
  366. Status = RtlEnterCriticalSection( &LoadedImageDebugInfoListCritSect );
  367. if (!NT_SUCCESS( Status )) {
  368. return FALSE;
  369. }
  370. Head = &LoadedImageDebugInfoListHead;
  371. Next = Head->Flink;
  372. while (Next != Head) {
  373. DebugInfo = CONTAINING_RECORD( Next, IMAGE_DEBUG_INFORMATION, List );
  374. if (DebugInfo->ImageBase == ImageBase &&
  375. !_stricmp( PathBuffer, DebugInfo->ImageFilePath )
  376. ) {
  377. break;
  378. }
  379. Next = Next->Flink;
  380. }
  381. if (Next == Head) {
  382. DebugInfo = NULL;
  383. }
  384. Head = &LoadedProcessDebugInfoListHead;
  385. Next = Head->Flink;
  386. while (Next != Head) {
  387. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  388. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  389. !_stricmp( PathBuffer, ProcessInfo->ImageFilePath )
  390. ) {
  391. return TRUE;
  392. }
  393. Next = Next->Flink;
  394. }
  395. ProcessInfo = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( *ProcessInfo ) );
  396. if (ProcessInfo == NULL) {
  397. return FALSE;
  398. }
  399. ProcessInfo->ImageBase = ImageBase;
  400. ProcessInfo->EndOfImage = ImageBase + ImageSize;
  401. ProcessInfo->UniqueProcess = UniqueProcess;
  402. ProcessInfo->DebugInfo = DebugInfo;
  403. strcpy( ProcessInfo->ImageFilePath, PathBuffer );
  404. InsertTailList( &LoadedProcessDebugInfoListHead, &ProcessInfo->List );
  405. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  406. return TRUE;
  407. }
  408. BOOL
  409. RemoveImageDebugInformation(
  410. IN HANDLE UniqueProcess,
  411. IN LPSTR ImageFilePath,
  412. IN DWORD ImageBase
  413. )
  414. {
  415. PLIST_ENTRY Head, Next;
  416. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  417. Head = &LoadedProcessDebugInfoListHead;
  418. Next = Head->Flink;
  419. while (Next != Head) {
  420. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  421. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  422. (!ARGUMENT_PRESENT( ImageFilePath ) ||
  423. !_stricmp( ImageFilePath, ProcessInfo->ImageFilePath )
  424. )
  425. ) {
  426. if (LoadSymbolsFilterRoutine != NULL) {
  427. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  428. ProcessInfo->ImageFilePath,
  429. ProcessInfo->ImageBase,
  430. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  431. LoadSymbolsUnload
  432. );
  433. }
  434. Next = Next->Blink;
  435. RemoveEntryList( &ProcessInfo->List );
  436. RtlFreeHeap( RtlProcessHeap(), 0, ProcessInfo );
  437. if (ARGUMENT_PRESENT( ImageFilePath )) {
  438. break;
  439. }
  440. }
  441. Next = Next->Flink;
  442. }
  443. return TRUE;
  444. }
  445. PIMAGE_DEBUG_INFORMATION
  446. FindImageDebugInformation(
  447. IN HANDLE UniqueProcess,
  448. IN DWORD Address
  449. )
  450. {
  451. NTSTATUS Status;
  452. PLIST_ENTRY Head, Next;
  453. PIMAGE_DEBUG_INFORMATION DebugInfo;
  454. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  455. Status = RtlEnterCriticalSection( &LoadedImageDebugInfoListCritSect );
  456. if (!NT_SUCCESS( Status )) {
  457. return NULL;
  458. }
  459. if (Address & 0x80000000) {
  460. UniqueProcess = NULL;
  461. }
  462. Head = &LoadedProcessDebugInfoListHead;
  463. Next = Head->Flink;
  464. while (Next != Head) {
  465. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  466. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  467. Address >= ProcessInfo->ImageBase &&
  468. Address < ProcessInfo->EndOfImage
  469. ) {
  470. break;
  471. }
  472. Next = Next->Flink;
  473. }
  474. if (Next == Head) {
  475. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  476. return NULL;
  477. }
  478. DebugInfo = ProcessInfo->DebugInfo;
  479. if (DebugInfo == NULL) {
  480. DebugInfo = MapDebugInformation( NULL, ProcessInfo->ImageFilePath, SymbolSearchPath, ProcessInfo->ImageBase );
  481. if (DebugInfo != NULL) {
  482. DebugInfo->ImageBase = ProcessInfo->ImageBase;
  483. ProcessInfo->DebugInfo = DebugInfo;
  484. if (LoadSymbolsFilterRoutine != NULL) {
  485. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  486. ProcessInfo->ImageFilePath,
  487. ProcessInfo->ImageBase,
  488. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  489. LoadSymbolsLoad
  490. );
  491. }
  492. InsertTailList( &LoadedImageDebugInfoListHead, &DebugInfo->List );
  493. }
  494. else {
  495. if (LoadSymbolsFilterRoutine != NULL) {
  496. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  497. ProcessInfo->ImageFilePath,
  498. ProcessInfo->ImageBase,
  499. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  500. LoadSymbolsUnableToLoad
  501. );
  502. }
  503. }
  504. }
  505. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  506. return DebugInfo;
  507. }
  508. ULONG
  509. GetSymbolicNameForAddress(
  510. IN HANDLE UniqueProcess,
  511. IN ULONG Address,
  512. OUT LPSTR Name,
  513. IN ULONG MaxNameLength
  514. )
  515. {
  516. NTSTATUS Status;
  517. PIMAGE_DEBUG_INFORMATION DebugInfo;
  518. RTL_SYMBOL_INFORMATION SymbolInformation;
  519. ULONG i, ModuleNameLength, Result, Offset;
  520. LPSTR s;
  521. DebugInfo = FindImageDebugInformation( UniqueProcess,
  522. Address
  523. );
  524. if (DebugInfo != NULL) {
  525. if (s = strchr( DebugInfo->ImageFileName, '.' )) {
  526. ModuleNameLength = s - DebugInfo->ImageFileName;
  527. }
  528. else {
  529. ModuleNameLength = strlen( DebugInfo->ImageFileName );
  530. }
  531. // [mikese] RtlLookupSymbolByAddress will fault if there is
  532. // no COFF symbol information.
  533. if ( DebugInfo->CoffSymbols != NULL ) {
  534. Status = RtlLookupSymbolByAddress( (PVOID)DebugInfo->ImageBase,
  535. DebugInfo->CoffSymbols,
  536. (PVOID)Address,
  537. 0x4000,
  538. &SymbolInformation,
  539. NULL
  540. );
  541. }
  542. else {
  543. Status = STATUS_UNSUCCESSFUL;
  544. }
  545. }
  546. else {
  547. ModuleNameLength = 0;
  548. Status = STATUS_UNSUCCESSFUL;
  549. }
  550. if (NT_SUCCESS( Status )) {
  551. s = SymbolInformation.Name.Buffer;
  552. i = 1;
  553. while (SymbolInformation.Name.Length > i &&
  554. isdigit( s[ SymbolInformation.Name.Length - i ] )
  555. ) {
  556. i += 1;
  557. }
  558. if (s[ SymbolInformation.Name.Length - i ] == '@') {
  559. SymbolInformation.Name.Length = (USHORT)(SymbolInformation.Name.Length - i);
  560. }
  561. s = Name;
  562. Result = _snprintf( s, MaxNameLength,
  563. "%.*s!%Z",
  564. ModuleNameLength,
  565. DebugInfo->ImageFileName,
  566. &SymbolInformation.Name
  567. );
  568. Offset = Address - DebugInfo->ImageBase - SymbolInformation.Value;
  569. if (Offset != 0) {
  570. Result += _snprintf( s + Result, MaxNameLength - Result, "+0x%x", Offset );
  571. }
  572. }
  573. else {
  574. if (ModuleNameLength != 0) {
  575. Result = _snprintf( Name, MaxNameLength,
  576. "%.*s!0x%08x",
  577. ModuleNameLength,
  578. DebugInfo->ImageFileName,
  579. Address
  580. );
  581. }
  582. else {
  583. Result = _snprintf( Name, MaxNameLength, "0x%08x", Address );
  584. }
  585. }
  586. return Result;
  587. }
  588. ULONG
  589. TranslateAddress (
  590. IN ULONG Address,
  591. OUT LPSTR Name,
  592. IN ULONG MaxNameLength )
  593. {
  594. PRTL_DEBUG_INFORMATION p;
  595. NTSTATUS Status;
  596. DWORD ProcessId;
  597. ULONG Result = 0;
  598. ULONG Attempts = 0;
  599. // We need to call Initialize once to ensure that GetSymbolicNameForAddress
  600. // does not fault.
  601. if ( NumInitCalls == -1 )
  602. {
  603. InitializeImageDebugInformation( LoadSymbolsFilterRoutine,
  604. NULL, FALSE, FALSE );
  605. }
  606. ProcessId = GetCurrentProcessId();
  607. while ( Result == 0 )
  608. {
  609. Result = GetSymbolicNameForAddress ( (HANDLE)ProcessId, Address,
  610. Name, MaxNameLength );
  611. if ( Result == 0 )
  612. {
  613. if ( ++Attempts < 2 )
  614. {
  615. // Try reintialising, to load any modules we missed on a previous
  616. // occasion (or if we haven't initialised yet).
  617. // I don't need a load-symbols-filter, so just use whatever is
  618. // already there, if any
  619. InitializeImageDebugInformation( LoadSymbolsFilterRoutine,
  620. NULL, FALSE, FALSE );
  621. }
  622. else
  623. {
  624. // Apparently we are unable to do the right thing, so just return
  625. // the address as hex.
  626. Result = _snprintf( Name, MaxNameLength, "0x%08x", Address );
  627. }
  628. }
  629. }
  630. return Result;
  631. }
  632. NTSTATUS
  633. RtlpCaptureSymbolInformation(
  634. IN PIMAGE_SYMBOL SymbolEntry,
  635. IN PCHAR StringTable,
  636. OUT PRTL_SYMBOL_INFORMATION SymbolInformation
  637. );
  638. PIMAGE_COFF_SYMBOLS_HEADER
  639. RtlpGetCoffDebugInfo(
  640. IN PVOID ImageBase,
  641. IN PVOID MappedBase OPTIONAL
  642. );
  643. NTSTATUS
  644. RtlLookupSymbolByAddress(
  645. IN PVOID ImageBase,
  646. IN PVOID MappedBase OPTIONAL,
  647. IN PVOID Address,
  648. IN ULONG ClosenessLimit,
  649. OUT PRTL_SYMBOL_INFORMATION SymbolInformation,
  650. OUT PRTL_SYMBOL_INFORMATION NextSymbolInformation OPTIONAL
  651. )
  652. /*++
  653. Routine Description:
  654. Given a code address, this routine returns the nearest symbol
  655. name and the offset from the symbol to that name. If the
  656. nearest symbol is not within ClosenessLimit of the location,
  657. STATUS_ENTRYPOINT_NOT_FOUND is returned.
  658. Arguments:
  659. ImageBase - Supplies the base address of the image containing
  660. Address
  661. MappedBase - Optional parameter, that if specified means the image
  662. was mapped as a data file and the MappedBase gives the
  663. location it was mapped. If this parameter does not
  664. point to an image file base, then it is assumed that
  665. this is a pointer to the coff debug info.
  666. ClosenessLimit - Specifies the maximum distance that Address can be
  667. from the value of a symbol to be considered
  668. "found". Symbol's whose value is further away then
  669. this are not "found".
  670. SymbolInformation - Points to a structure that is filled in by
  671. this routine if a symbol table entry is found.
  672. NextSymbolInformation - Optional parameter, that if specified, is
  673. filled in with information about these
  674. symbol whose value is the next address above
  675. Address
  676. Return Value:
  677. Status of operation.
  678. --*/
  679. {
  680. NTSTATUS Status;
  681. ULONG AddressOffset, i;
  682. PIMAGE_SYMBOL PreviousSymbolEntry;
  683. PIMAGE_SYMBOL SymbolEntry;
  684. IMAGE_SYMBOL Symbol;
  685. PUCHAR StringTable;
  686. BOOLEAN SymbolFound;
  687. PIMAGE_COFF_SYMBOLS_HEADER DebugInfo;
  688. DebugInfo = RtlpGetCoffDebugInfo( ImageBase, MappedBase );
  689. if (DebugInfo == NULL) {
  690. return STATUS_INVALID_IMAGE_FORMAT;
  691. }
  692. //
  693. // Crack the symbol table.
  694. //
  695. SymbolEntry = (PIMAGE_SYMBOL)
  696. ((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
  697. StringTable = (PUCHAR)
  698. ((ULONG)SymbolEntry + DebugInfo->NumberOfSymbols * (ULONG)IMAGE_SIZEOF_SYMBOL);
  699. //
  700. // Find the "header" symbol (skipping all the section names)
  701. //
  702. for (i = 0; i < DebugInfo->NumberOfSymbols; i++) {
  703. if (!strcmp( &SymbolEntry->N.ShortName[ 0 ], "header" )) {
  704. break;
  705. }
  706. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)SymbolEntry +
  707. IMAGE_SIZEOF_SYMBOL);
  708. }
  709. //
  710. // If no "header" symbol found, just start at the first symbol.
  711. //
  712. if (i >= DebugInfo->NumberOfSymbols) {
  713. SymbolEntry = (PIMAGE_SYMBOL)((ULONG)DebugInfo + DebugInfo->LvaToFirstSymbol);
  714. i = 0;
  715. }
  716. //
  717. // Loop through all symbols in the symbol table. For each symbol,
  718. // if it is within the code section, subtract off the bias and
  719. // see if there are any hits within the profile buffer for
  720. // that symbol.
  721. //
  722. AddressOffset = (ULONG)Address - (ULONG)ImageBase;
  723. SymbolFound = FALSE;
  724. for (; i < DebugInfo->NumberOfSymbols; i++) {
  725. //
  726. // Skip over any Auxilliary entries.
  727. //
  728. try {
  729. while (SymbolEntry->NumberOfAuxSymbols) {
  730. i = i + 1 + SymbolEntry->NumberOfAuxSymbols;
  731. SymbolEntry = (PIMAGE_SYMBOL)
  732. ((ULONG)SymbolEntry + IMAGE_SIZEOF_SYMBOL +
  733. SymbolEntry->NumberOfAuxSymbols * IMAGE_SIZEOF_SYMBOL
  734. );
  735. }
  736. RtlMoveMemory( &Symbol, SymbolEntry, IMAGE_SIZEOF_SYMBOL );
  737. }
  738. except(EXCEPTION_EXECUTE_HANDLER) {
  739. return GetExceptionCode();
  740. }
  741. //
  742. // If this symbol value is less than the value we are looking for.
  743. //
  744. if (Symbol.Value <= AddressOffset) {
  745. //
  746. // Then remember this symbol entry.
  747. //
  748. PreviousSymbolEntry = SymbolEntry;
  749. SymbolFound = TRUE;
  750. }
  751. else {
  752. //
  753. // All done looking if value of symbol is greater than
  754. // what we are looking for, as symbols are in address order
  755. //
  756. break;
  757. }
  758. SymbolEntry = (PIMAGE_SYMBOL)
  759. ((ULONG)SymbolEntry + IMAGE_SIZEOF_SYMBOL);
  760. }
  761. if (!SymbolFound || (AddressOffset - PreviousSymbolEntry->Value) > ClosenessLimit) {
  762. return STATUS_ENTRYPOINT_NOT_FOUND;
  763. }
  764. Status = RtlpCaptureSymbolInformation( PreviousSymbolEntry, StringTable, SymbolInformation );
  765. if (NT_SUCCESS( Status ) && ARGUMENT_PRESENT( NextSymbolInformation )) {
  766. Status = RtlpCaptureSymbolInformation( SymbolEntry, StringTable, NextSymbolInformation );
  767. }
  768. return Status;
  769. }
  770. NTSTATUS
  771. RtlpCaptureSymbolInformation(
  772. IN PIMAGE_SYMBOL SymbolEntry,
  773. IN PCHAR StringTable,
  774. OUT PRTL_SYMBOL_INFORMATION SymbolInformation
  775. )
  776. {
  777. USHORT MaximumLength;
  778. PCHAR s;
  779. SymbolInformation->SectionNumber = SymbolEntry->SectionNumber;
  780. SymbolInformation->Type = SymbolEntry->Type;
  781. SymbolInformation->Value = SymbolEntry->Value;
  782. if (SymbolEntry->N.Name.Short) {
  783. MaximumLength = 8;
  784. s = &SymbolEntry->N.ShortName[ 0 ];
  785. }
  786. else {
  787. MaximumLength = 64;
  788. s = &StringTable[ SymbolEntry->N.Name.Long ];
  789. }
  790. #if i386
  791. if (*s == '_') {
  792. s++;
  793. MaximumLength--;
  794. }
  795. #endif
  796. SymbolInformation->Name.Buffer = s;
  797. SymbolInformation->Name.Length = 0;
  798. while (*s && MaximumLength--) {
  799. SymbolInformation->Name.Length++;
  800. s++;
  801. }
  802. SymbolInformation->Name.MaximumLength = SymbolInformation->Name.Length;
  803. return( STATUS_SUCCESS );
  804. }
  805. PIMAGE_COFF_SYMBOLS_HEADER
  806. RtlpGetCoffDebugInfo(
  807. IN PVOID ImageBase,
  808. IN PVOID MappedBase OPTIONAL
  809. )
  810. {
  811. PIMAGE_COFF_SYMBOLS_HEADER DebugInfo;
  812. PIMAGE_DOS_HEADER DosHeader;
  813. PIMAGE_DEBUG_DIRECTORY DebugDirectory;
  814. ULONG DebugSize;
  815. ULONG NumberOfDebugDirectories;
  816. DosHeader = (PIMAGE_DOS_HEADER)MappedBase;
  817. if ( !DosHeader || DosHeader->e_magic == IMAGE_DOS_SIGNATURE ) {
  818. //
  819. // Locate debug section.
  820. //
  821. DebugDirectory = (PIMAGE_DEBUG_DIRECTORY)
  822. RtlImageDirectoryEntryToData( (PVOID)(MappedBase == NULL ? ImageBase : MappedBase),
  823. (BOOLEAN)(MappedBase == NULL ? TRUE : FALSE),
  824. IMAGE_DIRECTORY_ENTRY_DEBUG,
  825. &DebugSize
  826. );
  827. if (!DebugDirectory ||
  828. (DebugSize < sizeof(IMAGE_DEBUG_DIRECTORY)) ||
  829. ((DebugSize % sizeof(IMAGE_DEBUG_DIRECTORY)) != 0)) {
  830. return NULL;
  831. }
  832. //
  833. // point debug directory at coff debug directory
  834. //
  835. NumberOfDebugDirectories = DebugSize / sizeof(*DebugDirectory);
  836. while ( NumberOfDebugDirectories-- ) {
  837. if ( DebugDirectory->Type == IMAGE_DEBUG_TYPE_COFF ) {
  838. break;
  839. }
  840. DebugDirectory++;
  841. }
  842. if (DebugDirectory->Type != IMAGE_DEBUG_TYPE_COFF ) {
  843. return NULL;
  844. }
  845. if (MappedBase == NULL) {
  846. if (DebugDirectory->AddressOfRawData == 0) {
  847. return(NULL);
  848. }
  849. DebugInfo = (PIMAGE_COFF_SYMBOLS_HEADER)
  850. ((ULONG) ImageBase + DebugDirectory->AddressOfRawData);
  851. } else {
  852. DebugInfo = (PIMAGE_COFF_SYMBOLS_HEADER)
  853. ((ULONG) MappedBase + DebugDirectory->PointerToRawData);
  854. }
  855. } else {
  856. DebugInfo = (PIMAGE_COFF_SYMBOLS_HEADER)MappedBase;
  857. }
  858. return DebugInfo;
  859. }
  860. #endif