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.

1021 lines
31 KiB

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