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. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. symhelp.c
  5. Abstract:
  6. Author:
  7. Steve Wood (stevewo) 11-Mar-1994
  8. Revision History:
  9. --*/
  10. #define _SYMHELP_SOURCE_
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <imagehlp.h>
  16. #include <symhelp.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. //
  20. // Primitives to access symbolic debug information in an image file
  21. //
  22. typedef struct _RTL_SYMBOL_INFORMATION {
  23. ULONG Type;
  24. ULONG SectionNumber;
  25. ULONG Value;
  26. STRING Name;
  27. } RTL_SYMBOL_INFORMATION, *PRTL_SYMBOL_INFORMATION;
  28. NTSTATUS
  29. RtlLookupSymbolByAddress(
  30. IN PVOID ImageBase,
  31. IN PVOID MappedBase OPTIONAL,
  32. IN PVOID Address,
  33. IN ULONG ClosenessLimit,
  34. OUT PRTL_SYMBOL_INFORMATION SymbolInformation,
  35. OUT PRTL_SYMBOL_INFORMATION NextSymbolInformation OPTIONAL
  36. );
  37. typedef struct _PROCESS_DEBUG_INFORMATION {
  38. LIST_ENTRY List;
  39. HANDLE UniqueProcess;
  40. DWORD ImageBase;
  41. DWORD EndOfImage;
  42. PIMAGE_DEBUG_INFORMATION DebugInfo;
  43. UCHAR ImageFilePath[ MAX_PATH ];
  44. } PROCESS_DEBUG_INFORMATION, *PPROCESS_DEBUG_INFORMATION;
  45. PLOAD_SYMBOLS_FILTER_ROUTINE LoadSymbolsFilterRoutine;
  46. RTL_CRITICAL_SECTION LoadedImageDebugInfoListCritSect;
  47. LIST_ENTRY LoadedImageDebugInfoListHead;
  48. LIST_ENTRY LoadedProcessDebugInfoListHead;
  49. LPSTR SymbolSearchPath;
  50. // This variable tracks how many times InitializeImageDebugInformation has been
  51. // called. Certain operations are performed only on the first call (as
  52. // NumInitCalls transitions from -1 to 0).
  53. LONG NumInitCalls = -1;
  54. LPSTR
  55. GetEnvVariable(
  56. IN LPSTR VariableName
  57. )
  58. {
  59. NTSTATUS Status;
  60. STRING Name, Value;
  61. UNICODE_STRING UnicodeName, UnicodeValue;
  62. RtlInitString( &Name, VariableName );
  63. RtlInitUnicodeString( &UnicodeValue, NULL );
  64. Status = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE );
  65. if (!NT_SUCCESS( Status )) {
  66. return NULL;
  67. }
  68. Status = RtlQueryEnvironmentVariable_U( NULL, &UnicodeName, &UnicodeValue );
  69. if (Status != STATUS_BUFFER_TOO_SMALL) {
  70. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  71. return NULL;
  72. }
  73. UnicodeValue.MaximumLength = UnicodeValue.Length + sizeof( UNICODE_NULL );
  74. UnicodeValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, UnicodeValue.MaximumLength );
  75. if (UnicodeValue.Buffer == NULL) {
  76. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  77. return NULL;
  78. }
  79. Status = RtlQueryEnvironmentVariable_U( NULL, &UnicodeName, &UnicodeValue );
  80. if (!NT_SUCCESS( Status )) {
  81. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  82. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  83. return NULL;
  84. }
  85. Status = RtlUnicodeStringToAnsiString( &Value, &UnicodeValue, TRUE );
  86. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  87. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeName.Buffer );
  88. if (!NT_SUCCESS( Status )) {
  89. return NULL;
  90. }
  91. Value.Buffer[ Value.Length ] = '\0';
  92. return Value.Buffer;
  93. }
  94. LPSTR
  95. SetSymbolSearchPath( )
  96. {
  97. ULONG Size, i, Attributes, NumberOfSymbolPaths;
  98. LPSTR s, SymbolPaths[ 4 ];
  99. if (SymbolSearchPath != NULL) {
  100. return SymbolSearchPath;
  101. }
  102. Size = 0;
  103. NumberOfSymbolPaths = 0;
  104. if (s = GetEnvVariable( "_NT_SYMBOL_PATH" )) {
  105. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  106. }
  107. if (s = GetEnvVariable( "_NT_ALT_SYMBOL_PATH" )) {
  108. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  109. }
  110. if (s = GetEnvVariable( "SystemRoot" )) {
  111. SymbolPaths[ NumberOfSymbolPaths++ ] = s;
  112. }
  113. SymbolPaths[ NumberOfSymbolPaths++ ] = ".";
  114. Size = 1;
  115. for (i=0; i<NumberOfSymbolPaths; i++) {
  116. Attributes = GetFileAttributes( SymbolPaths[ i ] );
  117. if ( Attributes != 0xffffffff && (Attributes & FILE_ATTRIBUTE_DIRECTORY)) {
  118. Size += 1 + strlen( SymbolPaths[ i ] );
  119. }
  120. else {
  121. SymbolPaths[ i ] = NULL;
  122. }
  123. }
  124. SymbolSearchPath = RtlAllocateHeap( RtlProcessHeap(), 0, Size );
  125. if (SymbolSearchPath == NULL) {
  126. return NULL;
  127. }
  128. *SymbolSearchPath = '\0';
  129. for (i=0; i<NumberOfSymbolPaths; i++) {
  130. if (s = SymbolPaths[ i ]) {
  131. if (*SymbolSearchPath != '\0') {
  132. strcat( SymbolSearchPath, ";" );
  133. }
  134. strcat( SymbolSearchPath, s );
  135. }
  136. }
  137. return SymbolSearchPath;
  138. }
  139. BOOL
  140. InitializeImageDebugInformation(
  141. IN PLOAD_SYMBOLS_FILTER_ROUTINE LoadSymbolsFilter,
  142. IN HANDLE TargetProcess,
  143. IN BOOL NewProcess,
  144. IN BOOL GetKernelSymbols
  145. )
  146. {
  147. PPEB Peb;
  148. NTSTATUS Status;
  149. PROCESS_BASIC_INFORMATION ProcessInformation;
  150. PLDR_DATA_TABLE_ENTRY LdrEntry;
  151. LDR_DATA_TABLE_ENTRY LdrEntryData;
  152. PLIST_ENTRY LdrHead, LdrNext;
  153. PPEB_LDR_DATA Ldr;
  154. UNICODE_STRING UnicodeString;
  155. ANSI_STRING AnsiString;
  156. LPSTR ImageFilePath;
  157. PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
  158. RTL_PROCESS_MODULES ModuleInfoBuffer;
  159. PRTL_PROCESS_MODULES ModuleInfo;
  160. PRTL_PROCESS_MODULE_INFORMATION ModuleInfo1;
  161. ULONG RequiredLength, ModuleNumber;
  162. // Is this the first call?
  163. if ( InterlockedIncrement ( &NumInitCalls ) == 0 )
  164. {
  165. // Yes
  166. SetSymbolSearchPath();
  167. InitializeListHead( &LoadedImageDebugInfoListHead );
  168. InitializeListHead( &LoadedProcessDebugInfoListHead );
  169. RtlInitializeCriticalSection( &LoadedImageDebugInfoListCritSect );
  170. }
  171. // The filter routine can be superceded at any time.
  172. LoadSymbolsFilterRoutine = LoadSymbolsFilter;
  173. if (GetKernelSymbols) {
  174. ModuleInfo = &ModuleInfoBuffer;
  175. RequiredLength = sizeof( *ModuleInfo );
  176. Status = NtQuerySystemInformation( SystemModuleInformation,
  177. ModuleInfo,
  178. RequiredLength,
  179. &RequiredLength
  180. );
  181. if (Status == STATUS_INFO_LENGTH_MISMATCH) {
  182. ModuleInfo = NULL;
  183. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  184. &ModuleInfo,
  185. 0,
  186. &RequiredLength,
  187. MEM_COMMIT,
  188. PAGE_READWRITE
  189. );
  190. if (NT_SUCCESS( Status )) {
  191. Status = NtQuerySystemInformation( SystemModuleInformation,
  192. ModuleInfo,
  193. RequiredLength,
  194. &RequiredLength
  195. );
  196. if (NT_SUCCESS( Status )) {
  197. ModuleInfo1 = &ModuleInfo->Modules[ 0 ];
  198. for (ModuleNumber=0; ModuleNumber<ModuleInfo->NumberOfModules; ModuleNumber++) {
  199. if ((DWORD)(ModuleInfo1->ImageBase) & 0x80000000) {
  200. if (ImageFilePath = strchr( ModuleInfo1->FullPathName, ':')) {
  201. ImageFilePath -= 1;
  202. }
  203. else {
  204. ImageFilePath = ModuleInfo1->FullPathName +
  205. strlen( ModuleInfo1->FullPathName );
  206. while (ImageFilePath > ModuleInfo1->FullPathName) {
  207. if (ImageFilePath[ -1 ] == '\\') {
  208. break;
  209. }
  210. else {
  211. ImageFilePath -= 1;
  212. }
  213. }
  214. }
  215. AddImageDebugInformation( NULL,
  216. ImageFilePath,
  217. (DWORD)ModuleInfo1->ImageBase,
  218. ModuleInfo1->ImageSize
  219. );
  220. }
  221. ModuleInfo1++;
  222. }
  223. }
  224. NtFreeVirtualMemory( NtCurrentProcess(),
  225. &ModuleInfo,
  226. &RequiredLength,
  227. MEM_RELEASE
  228. );
  229. }
  230. }
  231. }
  232. if (TargetProcess == NULL) {
  233. // Load module information for this process.
  234. TargetProcess = GetCurrentProcess();
  235. }
  236. Status = NtQueryInformationProcess( TargetProcess,
  237. ProcessBasicInformation,
  238. &ProcessInformation,
  239. sizeof( ProcessInformation ),
  240. NULL
  241. );
  242. if (!NT_SUCCESS( Status )) {
  243. return FALSE;
  244. }
  245. Peb = ProcessInformation.PebBaseAddress;
  246. if (NewProcess) {
  247. return TRUE;
  248. }
  249. //
  250. // Ldr = Peb->Ldr
  251. //
  252. Status = NtReadVirtualMemory( TargetProcess,
  253. &Peb->Ldr,
  254. &Ldr,
  255. sizeof( Ldr ),
  256. NULL
  257. );
  258. if (!NT_SUCCESS( Status )) {
  259. return FALSE;
  260. }
  261. LdrHead = &Ldr->InMemoryOrderModuleList;
  262. //
  263. // LdrNext = Head->Flink;
  264. //
  265. Status = NtReadVirtualMemory( TargetProcess,
  266. &LdrHead->Flink,
  267. &LdrNext,
  268. sizeof( LdrNext ),
  269. NULL
  270. );
  271. if (!NT_SUCCESS( Status )) {
  272. return FALSE;
  273. }
  274. while (LdrNext != LdrHead) {
  275. LdrEntry = CONTAINING_RECORD( LdrNext, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
  276. Status = NtReadVirtualMemory( TargetProcess,
  277. LdrEntry,
  278. &LdrEntryData,
  279. sizeof( LdrEntryData ),
  280. NULL
  281. );
  282. if (!NT_SUCCESS( Status )) {
  283. return FALSE;
  284. }
  285. UnicodeString.Length = LdrEntryData.FullDllName.Length;
  286. UnicodeString.MaximumLength = LdrEntryData.FullDllName.MaximumLength;
  287. UnicodeString.Buffer = RtlAllocateHeap( RtlProcessHeap(),
  288. 0,
  289. UnicodeString.MaximumLength
  290. );
  291. if (!UnicodeString.Buffer) {
  292. return FALSE;
  293. }
  294. Status = NtReadVirtualMemory( TargetProcess,
  295. LdrEntryData.FullDllName.Buffer,
  296. UnicodeString.Buffer,
  297. UnicodeString.MaximumLength,
  298. NULL
  299. );
  300. if (!NT_SUCCESS( Status )) {
  301. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeString.Buffer );
  302. return FALSE;
  303. }
  304. RtlUnicodeStringToAnsiString( &AnsiString,
  305. &UnicodeString,
  306. TRUE
  307. );
  308. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeString.Buffer );
  309. if (ImageFilePath = strchr( AnsiString.Buffer, ':')) {
  310. ImageFilePath -= 1;
  311. }
  312. else {
  313. ImageFilePath = AnsiString.Buffer;
  314. }
  315. AddImageDebugInformation( (HANDLE)ProcessInformation.UniqueProcessId,
  316. ImageFilePath,
  317. (DWORD)LdrEntryData.DllBase,
  318. LdrEntryData.SizeOfImage
  319. );
  320. RtlFreeAnsiString( &AnsiString );
  321. LdrNext = LdrEntryData.InMemoryOrderLinks.Flink;
  322. }
  323. return TRUE;
  324. }
  325. BOOL
  326. AddImageDebugInformation(
  327. IN HANDLE UniqueProcess,
  328. IN LPSTR ImageFilePath,
  329. IN DWORD ImageBase,
  330. IN DWORD ImageSize
  331. )
  332. {
  333. NTSTATUS Status;
  334. PLIST_ENTRY Head, Next;
  335. PIMAGE_DEBUG_INFORMATION DebugInfo;
  336. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  337. HANDLE FileHandle;
  338. UCHAR PathBuffer[ MAX_PATH ];
  339. FileHandle = FindExecutableImage( ImageFilePath, SymbolSearchPath, PathBuffer );
  340. if (FileHandle == NULL) {
  341. if (LoadSymbolsFilterRoutine != NULL) {
  342. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  343. ImageFilePath,
  344. ImageBase,
  345. ImageSize,
  346. LoadSymbolsPathNotFound
  347. );
  348. }
  349. return FALSE;
  350. }
  351. CloseHandle( FileHandle );
  352. if (LoadSymbolsFilterRoutine != NULL) {
  353. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  354. PathBuffer,
  355. ImageBase,
  356. ImageSize,
  357. LoadSymbolsDeferredLoad
  358. );
  359. }
  360. Status = RtlEnterCriticalSection( &LoadedImageDebugInfoListCritSect );
  361. if (!NT_SUCCESS( Status )) {
  362. return FALSE;
  363. }
  364. Head = &LoadedImageDebugInfoListHead;
  365. Next = Head->Flink;
  366. while (Next != Head) {
  367. DebugInfo = CONTAINING_RECORD( Next, IMAGE_DEBUG_INFORMATION, List );
  368. if (DebugInfo->ImageBase == ImageBase &&
  369. !_stricmp( PathBuffer, DebugInfo->ImageFilePath )
  370. ) {
  371. break;
  372. }
  373. Next = Next->Flink;
  374. }
  375. if (Next == Head) {
  376. DebugInfo = NULL;
  377. }
  378. Head = &LoadedProcessDebugInfoListHead;
  379. Next = Head->Flink;
  380. while (Next != Head) {
  381. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  382. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  383. !_stricmp( PathBuffer, ProcessInfo->ImageFilePath )
  384. ) {
  385. return TRUE;
  386. }
  387. Next = Next->Flink;
  388. }
  389. ProcessInfo = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof( *ProcessInfo ) );
  390. if (ProcessInfo == NULL) {
  391. return FALSE;
  392. }
  393. ProcessInfo->ImageBase = ImageBase;
  394. ProcessInfo->EndOfImage = ImageBase + ImageSize;
  395. ProcessInfo->UniqueProcess = UniqueProcess;
  396. ProcessInfo->DebugInfo = DebugInfo;
  397. strcpy( ProcessInfo->ImageFilePath, PathBuffer );
  398. InsertTailList( &LoadedProcessDebugInfoListHead, &ProcessInfo->List );
  399. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  400. return TRUE;
  401. }
  402. BOOL
  403. RemoveImageDebugInformation(
  404. IN HANDLE UniqueProcess,
  405. IN LPSTR ImageFilePath,
  406. IN DWORD ImageBase
  407. )
  408. {
  409. PLIST_ENTRY Head, Next;
  410. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  411. Head = &LoadedProcessDebugInfoListHead;
  412. Next = Head->Flink;
  413. while (Next != Head) {
  414. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  415. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  416. (!ARGUMENT_PRESENT( ImageFilePath ) ||
  417. !_stricmp( ImageFilePath, ProcessInfo->ImageFilePath )
  418. )
  419. ) {
  420. if (LoadSymbolsFilterRoutine != NULL) {
  421. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  422. ProcessInfo->ImageFilePath,
  423. ProcessInfo->ImageBase,
  424. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  425. LoadSymbolsUnload
  426. );
  427. }
  428. Next = Next->Blink;
  429. RemoveEntryList( &ProcessInfo->List );
  430. RtlFreeHeap( RtlProcessHeap(), 0, ProcessInfo );
  431. if (ARGUMENT_PRESENT( ImageFilePath )) {
  432. break;
  433. }
  434. }
  435. Next = Next->Flink;
  436. }
  437. return TRUE;
  438. }
  439. PIMAGE_DEBUG_INFORMATION
  440. FindImageDebugInformation(
  441. IN HANDLE UniqueProcess,
  442. IN DWORD Address
  443. )
  444. {
  445. NTSTATUS Status;
  446. PLIST_ENTRY Head, Next;
  447. PIMAGE_DEBUG_INFORMATION DebugInfo;
  448. PPROCESS_DEBUG_INFORMATION ProcessInfo;
  449. Status = RtlEnterCriticalSection( &LoadedImageDebugInfoListCritSect );
  450. if (!NT_SUCCESS( Status )) {
  451. return NULL;
  452. }
  453. if (Address & 0x80000000) {
  454. UniqueProcess = NULL;
  455. }
  456. Head = &LoadedProcessDebugInfoListHead;
  457. Next = Head->Flink;
  458. while (Next != Head) {
  459. ProcessInfo = CONTAINING_RECORD( Next, PROCESS_DEBUG_INFORMATION, List );
  460. if (ProcessInfo->UniqueProcess == UniqueProcess &&
  461. Address >= ProcessInfo->ImageBase &&
  462. Address < ProcessInfo->EndOfImage
  463. ) {
  464. break;
  465. }
  466. Next = Next->Flink;
  467. }
  468. if (Next == Head) {
  469. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  470. return NULL;
  471. }
  472. DebugInfo = ProcessInfo->DebugInfo;
  473. if (DebugInfo == NULL) {
  474. DebugInfo = MapDebugInformation( NULL, ProcessInfo->ImageFilePath, SymbolSearchPath, ProcessInfo->ImageBase );
  475. if (DebugInfo != NULL) {
  476. DebugInfo->ImageBase = ProcessInfo->ImageBase;
  477. ProcessInfo->DebugInfo = DebugInfo;
  478. if (LoadSymbolsFilterRoutine != NULL) {
  479. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  480. ProcessInfo->ImageFilePath,
  481. ProcessInfo->ImageBase,
  482. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  483. LoadSymbolsLoad
  484. );
  485. }
  486. InsertTailList( &LoadedImageDebugInfoListHead, &DebugInfo->List );
  487. }
  488. else {
  489. if (LoadSymbolsFilterRoutine != NULL) {
  490. (*LoadSymbolsFilterRoutine)( UniqueProcess,
  491. ProcessInfo->ImageFilePath,
  492. ProcessInfo->ImageBase,
  493. ProcessInfo->EndOfImage - ProcessInfo->ImageBase,
  494. LoadSymbolsUnableToLoad
  495. );
  496. }
  497. }
  498. }
  499. RtlLeaveCriticalSection( &LoadedImageDebugInfoListCritSect );
  500. return DebugInfo;
  501. }
  502. ULONG
  503. GetSymbolicNameForAddress(
  504. IN HANDLE UniqueProcess,
  505. IN ULONG Address,
  506. OUT LPSTR Name,
  507. IN ULONG MaxNameLength
  508. )
  509. {
  510. NTSTATUS Status;
  511. PIMAGE_DEBUG_INFORMATION DebugInfo;
  512. RTL_SYMBOL_INFORMATION SymbolInformation;
  513. ULONG i, ModuleNameLength, Result, Offset;
  514. LPSTR s;
  515. DebugInfo = FindImageDebugInformation( UniqueProcess,
  516. Address
  517. );
  518. if (DebugInfo != NULL) {
  519. if (s = strchr( DebugInfo->ImageFileName, '.' )) {
  520. ModuleNameLength = s - DebugInfo->ImageFileName;
  521. }
  522. else {
  523. ModuleNameLength = strlen( DebugInfo->ImageFileName );
  524. }
  525. // [mikese] RtlLookupSymbolByAddress will fault if there is
  526. // no COFF symbol information.
  527. if ( DebugInfo->CoffSymbols != NULL ) {
  528. Status = RtlLookupSymbolByAddress( (PVOID)DebugInfo->ImageBase,
  529. DebugInfo->CoffSymbols,
  530. (PVOID)Address,
  531. 0x4000,
  532. &SymbolInformation,
  533. NULL
  534. );
  535. }
  536. else {
  537. Status = STATUS_UNSUCCESSFUL;
  538. }
  539. }
  540. else {
  541. ModuleNameLength = 0;
  542. Status = STATUS_UNSUCCESSFUL;
  543. }
  544. if (NT_SUCCESS( Status )) {
  545. s = SymbolInformation.Name.Buffer;
  546. i = 1;
  547. while (SymbolInformation.Name.Length > i &&
  548. isdigit( s[ SymbolInformation.Name.Length - i ] )
  549. ) {
  550. i += 1;
  551. }
  552. if (s[ SymbolInformation.Name.Length - i ] == '@') {
  553. SymbolInformation.Name.Length = (USHORT)(SymbolInformation.Name.Length - i);
  554. }
  555. s = Name;
  556. Result = _snprintf( s, MaxNameLength,
  557. "%.*s!%Z",
  558. ModuleNameLength,
  559. DebugInfo->ImageFileName,
  560. &SymbolInformation.Name
  561. );
  562. Offset = Address - DebugInfo->ImageBase - SymbolInformation.Value;
  563. if (Offset != 0) {
  564. Result += _snprintf( s + Result, MaxNameLength - Result, "+0x%x", Offset );
  565. }
  566. }
  567. else {
  568. if (ModuleNameLength != 0) {
  569. Result = _snprintf( Name, MaxNameLength,
  570. "%.*s!0x%08x",
  571. ModuleNameLength,
  572. DebugInfo->ImageFileName,
  573. Address
  574. );
  575. }
  576. else {
  577. Result = _snprintf( Name, MaxNameLength, "0x%08x", Address );
  578. }
  579. }
  580. return Result;
  581. }
  582. ULONG
  583. TranslateAddress (
  584. IN DWORD ProcessId,
  585. IN ULONG Address,
  586. OUT LPSTR Name,
  587. IN ULONG MaxNameLength )
  588. {
  589. ULONG Result = 0;
  590. ULONG Attempts = 0;
  591. HANDLE hProc = (HANDLE)NULL;
  592. static DWORD dwLastPid = 0;
  593. //
  594. // Get the debug information for this process.
  595. //
  596. if (dwLastPid != ProcessId)
  597. {
  598. hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
  599. if (hProc)
  600. {
  601. InitializeImageDebugInformation(NULL, hProc, FALSE, FALSE);
  602. dwLastPid = ProcessId;
  603. }
  604. else
  605. // printf("Couldn't get process handle: 0x%08x\n", GetLastError());
  606. Result = 1;
  607. }
  608. while ( Result == 0 )
  609. {
  610. Result = GetSymbolicNameForAddress ( (HANDLE)ProcessId, Address,
  611. Name, MaxNameLength );
  612. if ( Result == 0 )
  613. {
  614. if ( ++Attempts < 2 )
  615. {
  616. // Try reinitialising, to load any modules we missed
  617. // on a previous occasion (or if we haven't initialized yet).
  618. InitializeImageDebugInformation(NULL, hProc, FALSE, FALSE);
  619. }
  620. else
  621. {
  622. // Apparently we are unable to do the right thing, so just
  623. // return the address as hex.
  624. Result = _snprintf( Name, MaxNameLength, "0x%08x", Address );
  625. }
  626. }
  627. }
  628. if (hProc)
  629. CloseHandle(hProc);
  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. }