Leaked source code of windows server 2003
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.

1138 lines
30 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. linesym.c
  5. Abstract:
  6. Source file and line support.
  7. Author:
  8. Drew Bliss (drewb) 07-07-1997
  9. Environment:
  10. User Mode
  11. --*/
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <ntldr.h>
  16. #include "private.h"
  17. #include "symbols.h"
  18. #include "globals.h"
  19. // private version of qsort used to avoid compat problems on NT4 and win2k.
  20. // code is published from base\crts
  21. extern
  22. void __cdecl dbg_qsort(void *, size_t, size_t,
  23. int (__cdecl *) (const void *, const void *));
  24. // #define DBG_LINES
  25. // #define DBG_COFF_LINES
  26. // #define DBG_ADDR_SEARCH
  27. BOOL
  28. diaAddLinesForAllMod(
  29. PMODULE_ENTRY mi
  30. );
  31. #if defined(DBG_LINES) || defined(DBG_COFF_LINES) || defined(DBG_ADDR_SEARCH)
  32. void __cdecl
  33. DbgOut(PCSTR Format, ...)
  34. {
  35. char Buf[512];
  36. va_list Args;
  37. va_start(Args, Format);
  38. _vsnprintf(Buf, sizeof(Buf), Format, Args);
  39. va_end(Args);
  40. OutputDebugStringA(Buf);
  41. }
  42. #endif
  43. BOOL
  44. sci2lline(
  45. PMODULE_ENTRY mi,
  46. PSRCCODEINFO sci,
  47. PIMAGEHLP_LINE64 line64)
  48. {
  49. assert(mi && line64 && sci);
  50. line64->Address = sci->Address;
  51. line64->Key = sci->Key;
  52. line64->LineNumber = sci->LineNumber;
  53. line64->FileName = mi->SrcFile;
  54. strcpy(line64->FileName, sci->FileName); // SECURITY: Don't know size of target buffer.
  55. return true;
  56. }
  57. void sciInit(PSRCCODEINFO sci)
  58. {
  59. ZeroMemory(sci, sizeof(SRCCODEINFO));
  60. sci->SizeOfStruct = sizeof(SRCCODEINFO);
  61. }
  62. int
  63. __cdecl
  64. CompareLineAddresses(
  65. const void *v1,
  66. const void *v2
  67. )
  68. {
  69. PSOURCE_LINE Line1 = (PSOURCE_LINE)v1;
  70. PSOURCE_LINE Line2 = (PSOURCE_LINE)v2;
  71. if (Line1->Addr < Line2->Addr) {
  72. return -1;
  73. } else if (Line1->Addr > Line2->Addr) {
  74. return 1;
  75. } else {
  76. return 0;
  77. }
  78. }
  79. #ifdef DEBUG
  80. void
  81. DumpHintList(
  82. PPROCESS_ENTRY pe
  83. )
  84. {
  85. PSOURCE_HINT sh;
  86. for (sh = pe->SourceHints; sh; sh = sh->next)
  87. dtrace("%s - %s\n", sh->filename, sh->mi->ModuleName);
  88. }
  89. #define Debug_DumpHintList DumpHintList
  90. #else
  91. #define Debug_DumpHintList
  92. #endif
  93. PSOURCE_HINT
  94. FindSourceFileInHintList(
  95. PPROCESS_ENTRY pe,
  96. char *filename
  97. )
  98. {
  99. PSOURCE_HINT sh;
  100. assert(pe && filename && *filename);
  101. for (sh = pe->SourceHints; sh; sh = sh->next) {
  102. if (!strcmp(sh->filename, filename))
  103. return sh;
  104. }
  105. return NULL;
  106. }
  107. BOOL
  108. AddSourceFileToHintList(
  109. PPROCESS_ENTRY pe,
  110. PMODULE_ENTRY mi,
  111. LPSTR filename
  112. )
  113. {
  114. PSOURCE_HINT sh;
  115. PSOURCE_HINT psh;
  116. assert(pe && mi && filename && *filename);
  117. sh = FindSourceFileInHintList(pe,filename);
  118. if (sh) {
  119. sh->mi = mi;
  120. return true;
  121. }
  122. sh = (PSOURCE_HINT)MemAlloc(sizeof(SOURCE_HINT));
  123. if (!sh)
  124. return false;
  125. sh->next = NULL;
  126. sh->filename = (LPSTR)MemAlloc(strlen(filename) + 1);
  127. if (!sh->filename) {
  128. MemFree(sh);
  129. return false;
  130. }
  131. strcpy(sh->filename, filename); // SECURITY: Don't know size of target buffer.
  132. sh->mi = mi;
  133. for (psh = pe->SourceHints; psh; psh = psh->next) {
  134. if (!psh->next)
  135. break;
  136. }
  137. if (psh)
  138. psh->next = sh;
  139. else
  140. pe->SourceHints = sh;
  141. Debug_DumpHintList(pe);
  142. return true;
  143. }
  144. void
  145. RemoveSourceForModuleFromHintList(
  146. PPROCESS_ENTRY pe,
  147. PMODULE_ENTRY mi
  148. )
  149. {
  150. PSOURCE_HINT sh;
  151. PSOURCE_HINT psh;
  152. assert(pe && mi);
  153. psh = pe->SourceHints;
  154. for (sh = pe->SourceHints; sh; sh = sh->next) {
  155. if (sh->mi == mi) {
  156. if (psh == sh)
  157. psh = pe->SourceHints = sh->next;
  158. else
  159. psh->next = sh->next;
  160. MemFree(sh->filename);
  161. MemFree(sh);
  162. sh = psh;
  163. }
  164. psh = sh;
  165. if (!sh)
  166. return;
  167. }
  168. Debug_DumpHintList(pe);
  169. }
  170. void
  171. AddSourceEntry(
  172. PMODULE_ENTRY mi,
  173. PSOURCE_ENTRY Src
  174. )
  175. {
  176. PSOURCE_ENTRY SrcCur;
  177. // Overlap is currently permitted.
  178. #if 0
  179. // Check for overlap between SOURCE_ENTRY address ranges.
  180. for (SrcCur = mi->SourceFiles;
  181. SrcCur != NULL;
  182. SrcCur = SrcCur->Next)
  183. {
  184. if (!(SrcCur->MinAddr > Src->MaxAddr ||
  185. SrcCur->MaxAddr < Src->MinAddr))
  186. {
  187. DbgOut("SOURCE_ENTRY overlap between %08I64X:%08I64X "
  188. "and %08I64X:%08I64X\n",
  189. Src->MinAddr, Src->MaxAddr,
  190. SrcCur->MinAddr, SrcCur->MaxAddr);
  191. }
  192. }
  193. #endif
  194. // Sort line info by address.
  195. dbg_qsort((PVOID)Src->LineInfo, Src->Lines, sizeof(Src->LineInfo[0]),
  196. CompareLineAddresses);
  197. // Link new source information into list, sorted by address
  198. // range covered by information.
  199. for (SrcCur = mi->SourceFiles;
  200. SrcCur != NULL;
  201. SrcCur = SrcCur->Next) {
  202. if (SrcCur->MinAddr > Src->MinAddr) {
  203. break;
  204. }
  205. }
  206. Src->Next = SrcCur;
  207. if (SrcCur == NULL) {
  208. if (mi->SourceFilesTail == NULL) {
  209. mi->SourceFiles = Src;
  210. } else {
  211. mi->SourceFilesTail->Next = Src;
  212. }
  213. Src->Prev = mi->SourceFilesTail;
  214. mi->SourceFilesTail = Src;
  215. } else {
  216. if (SrcCur->Prev == NULL) {
  217. mi->SourceFiles = Src;
  218. } else {
  219. SrcCur->Prev->Next = Src;
  220. }
  221. Src->Prev = SrcCur->Prev;
  222. SrcCur->Prev = Src;
  223. }
  224. #ifdef DBG_LINES
  225. DbgOut("%08I64X %08I64X: %5d lines, '%s'\n",
  226. Src->MinAddr, Src->MaxAddr, Src->Lines, Src->File);
  227. #endif
  228. }
  229. #define IS_SECTION_SYM(Sym) \
  230. ((Sym)->StorageClass == IMAGE_SYM_CLASS_STATIC && \
  231. (Sym)->Type == IMAGE_SYM_TYPE_NULL && \
  232. (Sym)->NumberOfAuxSymbols == 1)
  233. BOOL
  234. AddLinesForCoff(
  235. PMODULE_ENTRY mi,
  236. PIMAGE_SYMBOL allSymbols,
  237. DWORD numberOfSymbols,
  238. PIMAGE_LINENUMBER LineNumbers
  239. )
  240. {
  241. PIMAGE_LINENUMBER *SecLines;
  242. BOOL Ret = false;
  243. PIMAGE_SECTION_HEADER sh;
  244. ULONG i;
  245. PIMAGE_SYMBOL Symbol;
  246. ULONG LowestPointer;
  247. // Allocate some space for per-section data.
  248. SecLines = (PIMAGE_LINENUMBER *)MemAlloc(sizeof(PIMAGE_LINENUMBER)*mi->NumSections);
  249. if (SecLines == NULL) {
  250. return false;
  251. }
  252. //
  253. // Add line number information for file groups if such
  254. // groups exist.
  255. //
  256. // First locate the lowest file offset for linenumbers. This
  257. // is necessary to be able to compute relative linenumber pointers
  258. // in split images because currently the pointers aren't updated
  259. // during stripping.
  260. sh = mi->SectionHdrs;
  261. LowestPointer = 0xffffffff;
  262. for (i = 0; i < mi->NumSections; i++, sh++) {
  263. if (sh->NumberOfLinenumbers > 0 &&
  264. sh->PointerToLinenumbers != 0 &&
  265. sh->PointerToLinenumbers < LowestPointer)
  266. {
  267. LowestPointer = sh->PointerToLinenumbers;
  268. }
  269. }
  270. if (LowestPointer == 0xffffffff) {
  271. goto EH_FreeSecLines;
  272. }
  273. sh = mi->SectionHdrs;
  274. for (i = 0; i < mi->NumSections; i++, sh++) {
  275. if (sh->NumberOfLinenumbers > 0 &&
  276. sh->PointerToLinenumbers != 0)
  277. {
  278. SecLines[i] = (PIMAGE_LINENUMBER)
  279. (sh->PointerToLinenumbers - LowestPointer + (DWORD_PTR)LineNumbers);
  280. #ifdef DBG_COFF_LINES
  281. DbgOut("Section %d: %d lines at %08X\n",
  282. i, sh->NumberOfLinenumbers, SecLines[i]);
  283. #endif
  284. } else {
  285. SecLines[i] = NULL;
  286. }
  287. }
  288. // Look for a file symbol.
  289. Symbol = allSymbols;
  290. for (i = 0; i < numberOfSymbols; i++) {
  291. if (Symbol->StorageClass == IMAGE_SYM_CLASS_FILE) {
  292. break;
  293. }
  294. i += Symbol->NumberOfAuxSymbols;
  295. Symbol += 1+Symbol->NumberOfAuxSymbols;
  296. }
  297. // If no file symbols were found, don't attempt to add line
  298. // number information. Something could be done with the raw
  299. // linenumber info in the image (if it exists) but this probably
  300. // isn't an important enough case to worry about.
  301. while (i < numberOfSymbols) {
  302. ULONG iNextFile, iAfterFile;
  303. ULONG iCur, iSym;
  304. PIMAGE_SYMBOL SymAfterFile, CurSym;
  305. PIMAGE_AUX_SYMBOL AuxSym;
  306. ULONG Lines;
  307. ULONG MinAddr, MaxAddr;
  308. LPSTR FileName;
  309. ULONG FileNameLen;
  310. #ifdef DBG_COFF_LINES
  311. DbgOut("%3X: '%s', %X\n", i, Symbol+1, Symbol->Value);
  312. #endif
  313. // A file symbol's Value is the index of the next file symbol.
  314. // In between the two file symbols there may be static
  315. // section symbols which give line number counts for all
  316. // the line numbers in the file.
  317. // The file chain can be NULL terminated or a circular list,
  318. // in which case this code assumes the end comes when the
  319. // list wraps around.
  320. if (Symbol->Value == 0 || Symbol->Value <= i) {
  321. iNextFile = numberOfSymbols;
  322. } else {
  323. iNextFile = Symbol->Value;
  324. }
  325. // Compute the index of the first symbol after the current file
  326. // symbol.
  327. iAfterFile = i+1+Symbol->NumberOfAuxSymbols;
  328. SymAfterFile = Symbol+1+Symbol->NumberOfAuxSymbols;
  329. // Look for section symbols and count up the number of linenumber
  330. // references, the min address and the max address.
  331. CurSym = SymAfterFile;
  332. iCur = iAfterFile;
  333. Lines = 0;
  334. MinAddr = 0xffffffff;
  335. MaxAddr = 0;
  336. while (iCur < iNextFile) {
  337. DWORD Addr;
  338. if (IS_SECTION_SYM(CurSym) &&
  339. SecLines[CurSym->SectionNumber-1] != NULL)
  340. {
  341. AuxSym = (PIMAGE_AUX_SYMBOL)(CurSym+1);
  342. Lines += AuxSym->Section.NumberOfLinenumbers;
  343. Addr = (ULONG)(CurSym->Value+mi->BaseOfDll);
  344. #ifdef DBG_COFF_LINES
  345. DbgOut(" Range %08X %08X, min %08X max %08X\n",
  346. Addr, Addr+AuxSym->Section.Length-1,
  347. MinAddr, MaxAddr);
  348. #endif
  349. if (Addr < MinAddr) {
  350. MinAddr = Addr;
  351. }
  352. Addr += AuxSym->Section.Length-1;
  353. if (Addr > MaxAddr) {
  354. MaxAddr = Addr;
  355. }
  356. }
  357. iCur += 1+CurSym->NumberOfAuxSymbols;
  358. CurSym += 1+CurSym->NumberOfAuxSymbols;
  359. }
  360. if (Lines > 0) {
  361. PSOURCE_ENTRY Src;
  362. PSOURCE_LINE SrcLine;
  363. ULONG iLine;
  364. // We have a filename and some linenumber information,
  365. // so create a SOURCE_ENTRY and fill it in.
  366. FileName = (LPSTR)(Symbol+1);
  367. FileNameLen = strlen(FileName);
  368. Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+
  369. sizeof(SOURCE_LINE)*Lines+
  370. FileNameLen+1);
  371. if (Src == NULL) {
  372. goto EH_FreeSecLines;
  373. }
  374. Src->ModuleId = 0;
  375. Src->MinAddr = MinAddr;
  376. Src->MaxAddr = MaxAddr;
  377. Src->Lines = Lines;
  378. SrcLine = (PSOURCE_LINE)(Src+1);
  379. Src->LineInfo = SrcLine;
  380. // Now that we've got a place to put linenumber information,
  381. // retraverse the section symbols and grab COFF linenumbers
  382. // from the appropriate sections and format them into
  383. // the generic format.
  384. CurSym = SymAfterFile;
  385. iCur = iAfterFile;
  386. while (iCur < iNextFile) {
  387. if (IS_SECTION_SYM(CurSym) &&
  388. SecLines[CurSym->SectionNumber-1] != NULL) {
  389. PIMAGE_LINENUMBER CoffLine;
  390. AuxSym = (PIMAGE_AUX_SYMBOL)(CurSym+1);
  391. CoffLine = SecLines[CurSym->SectionNumber-1];
  392. #ifdef DBG_COFF_LINES
  393. DbgOut(" %d lines at %08X\n",
  394. AuxSym->Section.NumberOfLinenumbers,
  395. CoffLine);
  396. #endif
  397. for (iLine = 0;
  398. iLine < AuxSym->Section.NumberOfLinenumbers;
  399. iLine++)
  400. {
  401. SrcLine->Addr = CoffLine->Type.VirtualAddress+
  402. mi->BaseOfDll;
  403. SrcLine->Line = CoffLine->Linenumber;
  404. CoffLine++;
  405. SrcLine++;
  406. }
  407. SecLines[CurSym->SectionNumber-1] = CoffLine;
  408. }
  409. iCur += 1+CurSym->NumberOfAuxSymbols;
  410. CurSym += 1+CurSym->NumberOfAuxSymbols;
  411. }
  412. // Stick file name at the very end of the data block so
  413. // it doesn't interfere with alignment.
  414. Src->File = (LPSTR)SrcLine;
  415. memcpy(Src->File, FileName, FileNameLen+1);
  416. AddSourceEntry(mi, Src);
  417. // This routine is successful as long as it adds at least
  418. // one new source entry.
  419. Ret = true;
  420. }
  421. // After the loops above iCur and CurSym refer to the next
  422. // file symbol, so update the loop counters from them.
  423. i = iCur;
  424. Symbol = CurSym;
  425. }
  426. EH_FreeSecLines:
  427. MemFree(SecLines);
  428. return Ret;
  429. }
  430. BOOL
  431. AddLinesForOmfSourceModule(
  432. PMODULE_ENTRY mi,
  433. BYTE *Base,
  434. OMFSourceModule *OmfSrcMod,
  435. PVOID PdbModule
  436. )
  437. {
  438. BOOL Ret;
  439. ULONG iFile;
  440. Ret = false;
  441. for (iFile = 0; iFile < (ULONG)OmfSrcMod->cFile; iFile++) {
  442. OMFSourceFile *OmfSrcFile;
  443. BYTE OmfFileNameLen;
  444. LPSTR OmfFileName;
  445. PULONG OmfAddrRanges;
  446. OMFSourceLine *OmfSrcLine;
  447. ULONG iSeg;
  448. PSOURCE_ENTRY Src;
  449. PSOURCE_ENTRY Seg0Src = NULL;
  450. PSOURCE_LINE SrcLine;
  451. ULONG NameAllocLen;
  452. OmfSrcFile = (OMFSourceFile *)(Base+OmfSrcMod->baseSrcFile[iFile]);
  453. // The baseSrcLn array of offsets is immediately followed by
  454. // SVA pairs which define the address ranges for the segments.
  455. OmfAddrRanges = &OmfSrcFile->baseSrcLn[OmfSrcFile->cSeg];
  456. // The name length and data immediately follows the address
  457. // range information.
  458. OmfFileName = (LPSTR)(OmfAddrRanges+2*OmfSrcFile->cSeg)+1;
  459. OmfFileNameLen = *(BYTE *)(OmfFileName-1);
  460. // The compiler can potentially generate a lot of segments
  461. // per file. The segments within a file have disjoint
  462. // address ranges as long as they are treated as separate
  463. // SOURCE_ENTRYs. If all segments for a particular file get
  464. // combined into one SOURCE_ENTRY it leads to address range overlap
  465. // because of combining non-contiguous segments. Allocating
  466. // a SOURCE_ENTRY per segment isn't that bad, particularly since
  467. // the name information only needs to be allocated in the first
  468. // entry for a file and the rest can share it.
  469. NameAllocLen = OmfFileNameLen+1;
  470. for (iSeg = 0; iSeg < (ULONG)OmfSrcFile->cSeg; iSeg++) {
  471. PULONG Off;
  472. PUSHORT Ln;
  473. ULONG iLine;
  474. PIMAGE_SECTION_HEADER sh;
  475. OmfSrcLine = (OMFSourceLine *)(Base+OmfSrcFile->baseSrcLn[iSeg]);
  476. Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+
  477. sizeof(SOURCE_LINE)*OmfSrcLine->cLnOff+
  478. NameAllocLen);
  479. if (Src == NULL) {
  480. return Ret;
  481. }
  482. Src->ModuleId = (ULONG) (ULONG64) PdbModule;
  483. Src->Lines = OmfSrcLine->cLnOff;
  484. sh = &mi->SectionHdrs[OmfSrcLine->Seg-1];
  485. // Process raw segment limits into current addresses.
  486. Src->MinAddr = mi->BaseOfDll+sh->VirtualAddress+(*OmfAddrRanges++);
  487. Src->MaxAddr = mi->BaseOfDll+sh->VirtualAddress+(*OmfAddrRanges++);
  488. // Retrieve line numbers and offsets from raw data and
  489. // process them into current pointers.
  490. SrcLine = (SOURCE_LINE *)(Src+1);
  491. Src->LineInfo = SrcLine;
  492. Off = (ULONG *)&OmfSrcLine->offset[0];
  493. Ln = (USHORT *)(Off+OmfSrcLine->cLnOff);
  494. for (iLine = 0; iLine < OmfSrcLine->cLnOff; iLine++) {
  495. SrcLine->Line = *Ln++;
  496. SrcLine->Addr = (*Off++)+mi->BaseOfDll+sh->VirtualAddress;
  497. // Line symbol information names the IA64 bundle
  498. // syllables with 0,1,2 whereas the debugger expects
  499. // 0,4,8. Convert.
  500. if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 &&
  501. (SrcLine->Addr & 3)) {
  502. SrcLine->Addr = (SrcLine->Addr & ~3) |
  503. ((SrcLine->Addr & 3) << 2);
  504. }
  505. SrcLine++;
  506. }
  507. if (iSeg == 0) {
  508. // Stick file name at the very end of the data block so
  509. // it doesn't interfere with alignment.
  510. Src->File = (LPSTR)SrcLine;
  511. memcpy(Src->File, OmfFileName, OmfFileNameLen);
  512. Src->File[OmfFileNameLen] = 0;
  513. // Later segments will share this initial name storage
  514. // space so they don't need to alloc their own.
  515. NameAllocLen = 0;
  516. Seg0Src = Src;
  517. } else if (Seg0Src) {
  518. Src->File = Seg0Src->File;
  519. }
  520. AddSourceEntry(mi, Src);
  521. // This routine is successful as long as it adds at least
  522. // one new source entry.
  523. Ret = true;
  524. }
  525. }
  526. return Ret;
  527. }
  528. void
  529. srcline2sci(
  530. PSOURCE_ENTRY Src,
  531. PSOURCE_LINE SrcLine,
  532. PSRCCODEINFO sci
  533. )
  534. {
  535. sci->Key = (PVOID)SrcLine;
  536. sci->LineNumber = SrcLine->Line;
  537. sci->Address = SrcLine->Addr;
  538. CopyStrArray(sci->FileName, Src->File ? Src->File : "");
  539. }
  540. PSOURCE_LINE
  541. FindLineInSource(
  542. PSOURCE_ENTRY Src,
  543. DWORD64 Addr
  544. )
  545. {
  546. int Low, Middle, High;
  547. PSOURCE_LINE SrcLine;
  548. Low = 0;
  549. High = Src->Lines-1;
  550. while (High >= Low) {
  551. Middle = (High <= Low) ? Low : (Low + High) >> 1;
  552. SrcLine = &Src->LineInfo[Middle];
  553. #ifdef DBG_ADDR_SEARCH
  554. DbgOut(" Checking %4d:%x`%08X\n", Middle,
  555. (ULONG)(SrcLine->Addr>>32), (ULONG)SrcLine->Addr);
  556. #endif
  557. if (Addr < SrcLine->Addr) {
  558. High = Middle-1;
  559. }
  560. else if (Middle < (int)Src->Lines-1 &&
  561. Addr >= (SrcLine+1)->Addr) {
  562. Low = Middle+1;
  563. } else {
  564. PSOURCE_LINE HighLine;
  565. // Find the highest source line with this offset.
  566. // Source lines are sorted by offset so the highest
  567. // source line could be before or after this one.
  568. while (SrcLine > Src->LineInfo &&
  569. (SrcLine - 1)->Addr == SrcLine->Addr) {
  570. SrcLine--;
  571. }
  572. HighLine = SrcLine;
  573. while (SrcLine < Src->LineInfo + Src->Lines - 1 &&
  574. (++SrcLine)->Addr == HighLine->Addr) {
  575. if (SrcLine->Line > HighLine->Line) {
  576. HighLine = SrcLine;
  577. }
  578. }
  579. return HighLine;
  580. }
  581. }
  582. return NULL;
  583. }
  584. PSOURCE_ENTRY
  585. FindNextSourceEntryForAddr(
  586. PMODULE_ENTRY mi,
  587. DWORD64 Addr,
  588. PSOURCE_ENTRY SearchFrom
  589. )
  590. {
  591. PSOURCE_ENTRY Src;
  592. Src = SearchFrom != NULL ? SearchFrom->Next : mi->SourceFiles;
  593. while (Src != NULL) {
  594. if (Addr < Src->MinAddr) {
  595. // Source files are kept sorted by increasing address so this
  596. // means that the address will not be found later and
  597. // we can stop checking.
  598. return NULL;
  599. } else if (Addr <= Src->MaxAddr) {
  600. // Found one.
  601. return Src;
  602. }
  603. Src = Src->Next;
  604. }
  605. return NULL;
  606. }
  607. BOOL
  608. GetLineFromAddr(
  609. PPROCESS_ENTRY pe,
  610. PMODULE_ENTRY mi,
  611. DWORD64 Addr,
  612. PDWORD Displacement,
  613. PSRCCODEINFO sci
  614. )
  615. {
  616. PSOURCE_ENTRY Src;
  617. DWORD Bias;
  618. DWORD64 srcAddr;
  619. BOOL rc;
  620. if (mi == NULL)
  621. return false;
  622. rc = false;
  623. if (mi->dia) {
  624. rc = diaGetLineFromAddr(mi, Addr, Displacement, sci);
  625. if (rc)
  626. AddSourceFileToHintList(pe, mi, sci->FileName);
  627. return rc;
  628. }
  629. srcAddr = ConvertOmapToSrc(mi,
  630. Addr,
  631. &Bias,
  632. option(SYMOPT_OMAP_FIND_NEAREST));
  633. if (!srcAddr)
  634. return false;
  635. // We have successfully converted
  636. srcAddr += Bias;
  637. for (;;) {
  638. PSOURCE_ENTRY BestSrc;
  639. PSOURCE_LINE BestSrcLine;
  640. DWORD64 BestDisp;
  641. // Search through all the source entries that contain the given
  642. // address, looking for the line with the smallest displacement.
  643. BestDisp = 0xffffffffffffffff;
  644. BestSrc = NULL;
  645. Src = NULL;
  646. while (Src = FindNextSourceEntryForAddr(mi, srcAddr, Src)) {
  647. PSOURCE_LINE SrcLine;
  648. #ifdef DBG_ADDR_SEARCH
  649. DbgOut("Found '%s' %d lines: %08I64X %08I64X for %08I64X\n",
  650. Src->File, Src->Lines, Src->MinAddr, Src->MaxAddr, Addr);
  651. #endif
  652. // Found a matching source entry, so look up the line
  653. // information.
  654. SrcLine = FindLineInSource(Src, srcAddr);
  655. if (SrcLine != NULL &&
  656. Addr-SrcLine->Addr < BestDisp) {
  657. BestDisp = Addr-SrcLine->Addr;
  658. #ifdef DBG_ADDR_SEARCH
  659. DbgOut(" Best disp %I64X\n", BestDisp);
  660. #endif
  661. BestSrc = Src;
  662. BestSrcLine = SrcLine;
  663. if (BestDisp == 0) {
  664. break;
  665. }
  666. }
  667. }
  668. // Only accept displaced answers if there's no more symbol
  669. // information to load.
  670. if (BestSrc != NULL && BestDisp == 0) {
  671. srcline2sci(BestSrc, BestSrcLine, sci);
  672. *Displacement = (ULONG)BestDisp;
  673. return true;
  674. }
  675. return false;
  676. }
  677. return false;
  678. }
  679. PSOURCE_ENTRY
  680. FindNextSourceEntryForFile(
  681. PMODULE_ENTRY mi,
  682. LPSTR FileStr,
  683. PSOURCE_ENTRY SearchFrom
  684. )
  685. {
  686. PSOURCE_ENTRY Src;
  687. Src = SearchFrom != NULL ? SearchFrom->Next : mi->SourceFiles;
  688. while (Src != NULL)
  689. {
  690. if (SymMatchFileName(Src->File, FileStr, NULL, NULL))
  691. {
  692. return Src;
  693. }
  694. Src = Src->Next;
  695. }
  696. return NULL;
  697. }
  698. PSOURCE_ENTRY
  699. FindPrevSourceEntryForFile(
  700. PMODULE_ENTRY mi,
  701. LPSTR FileStr,
  702. PSOURCE_ENTRY SearchFrom
  703. )
  704. {
  705. PSOURCE_ENTRY Src;
  706. Src = SearchFrom != NULL ? SearchFrom->Prev : mi->SourceFilesTail;
  707. while (Src != NULL)
  708. {
  709. if (SymMatchFileName(Src->File, FileStr, NULL, NULL))
  710. {
  711. return Src;
  712. }
  713. Src = Src->Prev;
  714. }
  715. return NULL;
  716. }
  717. BOOL
  718. GetLineFromName(
  719. PPROCESS_ENTRY pe,
  720. PMODULE_ENTRY mi,
  721. LPSTR FileName,
  722. DWORD LineNumber,
  723. PLONG Displacement,
  724. PSRCCODEINFO sci,
  725. DWORD method
  726. )
  727. {
  728. BOOL rc;
  729. PSOURCE_ENTRY Src;
  730. BOOL AtOrGreater;
  731. ULONG Disp;
  732. ULONG BestDisp;
  733. PSOURCE_ENTRY BestSrc;
  734. PSOURCE_LINE BestSrcLine;
  735. if (!mi)
  736. return false;
  737. // If the high bit of the line number is set
  738. // it means that the caller only wants lines at
  739. // or greater than the given line.
  740. AtOrGreater = (LineNumber & 0x80000000) != 0;
  741. LineNumber &= 0x7fffffff;
  742. if (mi->dia)
  743. {
  744. rc = diaGetLineFromName(mi, FileName, LineNumber, Displacement, sci, method);
  745. if (rc)
  746. AddSourceFileToHintList(pe, mi, FileName);
  747. return rc;
  748. }
  749. //
  750. // Search existing source information for a filename match.
  751. // There can be multiple SOURCE_ENTRYs with the same filename,
  752. // so make sure and search them all for an exact match
  753. // before settling on an approximate match.
  754. //
  755. Src = NULL;
  756. BestDisp = 0x7fffffff;
  757. BestSrcLine = NULL;
  758. while (Src = FindNextSourceEntryForFile(mi, FileName, Src))
  759. {
  760. PSOURCE_LINE SrcLine;
  761. ULONG i;
  762. // Found a matching source entry, so look up the closest
  763. // line. Line number info is sorted by address so the actual
  764. // line numbers can be in any order so we can't optimize
  765. // this linear search.
  766. SrcLine = Src->LineInfo;
  767. for (i = 0; i < Src->Lines; i++)
  768. {
  769. if (LineNumber > SrcLine->Line)
  770. {
  771. if (AtOrGreater)
  772. {
  773. Disp = 0x7fffffff;
  774. }
  775. else
  776. {
  777. Disp = LineNumber-SrcLine->Line;
  778. }
  779. }
  780. else
  781. {
  782. Disp = SrcLine->Line-LineNumber;
  783. }
  784. if (Disp < BestDisp)
  785. {
  786. BestDisp = Disp;
  787. BestSrc = Src;
  788. BestSrcLine = SrcLine;
  789. if (Disp == 0)
  790. {
  791. break;
  792. }
  793. }
  794. SrcLine++;
  795. }
  796. // If we found an exact match we can stop.
  797. if (BestDisp == 0)
  798. {
  799. break;
  800. }
  801. }
  802. // Only accept displaced answers if there's no more symbol
  803. // information to load.
  804. if (BestSrcLine != NULL && (BestDisp == 0))
  805. {
  806. srcline2sci(BestSrc, BestSrcLine, sci);
  807. *Displacement = (LONG)(LineNumber-BestSrcLine->Line);
  808. AddSourceFileToHintList(pe, mi, FileName);
  809. return true;
  810. }
  811. return false;
  812. }
  813. #define LINE_ERROR 0xffffffff
  814. // we need to get rid of this function!
  815. ULONG
  816. GetFileLineOffsets(
  817. PMODULE_ENTRY mi,
  818. LPSTR FileName,
  819. PDWORD64 Buffer,
  820. ULONG BufferLines
  821. )
  822. {
  823. PSOURCE_ENTRY Src;
  824. ULONG HighestLine = 0;
  825. // This routine collects all line information in one pass so
  826. // there's no opportunity for lazy loading. We have to
  827. // force lines to be loaded up front.
  828. if (mi->dia && option(SYMOPT_LOAD_LINES)) {
  829. if (!diaAddLinesForAllMod(mi)) {
  830. return LINE_ERROR;
  831. }
  832. }
  833. Src = NULL;
  834. while (Src = FindNextSourceEntryForFile(mi, FileName, Src)) {
  835. PSOURCE_LINE Line;
  836. ULONG i;
  837. ULONG Num;
  838. Line = Src->LineInfo;
  839. for (i = 0; i < Src->Lines; i++) {
  840. if (Line->Line > HighestLine) {
  841. HighestLine = Line->Line;
  842. }
  843. Num = Line->Line - 1;
  844. if (Num < BufferLines) {
  845. Buffer[Num] = Line->Addr;
  846. }
  847. Line++;
  848. }
  849. }
  850. return HighestLine;
  851. }
  852. ULONG
  853. IMAGEAPI
  854. SymGetFileLineOffsets64(
  855. IN HANDLE hProcess,
  856. IN LPSTR ModuleName,
  857. IN LPSTR FileName,
  858. OUT PDWORD64 Buffer,
  859. IN ULONG BufferLines
  860. )
  861. /*++
  862. Routine Description:
  863. This function locates the given file's line information
  864. and fills the given buffer with offsets for each
  865. line. Buffer[Line - 1] is set to the offset for
  866. Line. Buffer entries for lines that do not have information
  867. are left unchanged.
  868. Arguments:
  869. hProcess - Process handle, must have been previously registered
  870. with SymInitialize.
  871. ModuleName - Module name or NULL.
  872. FileName - File name.
  873. Buffer - Array of offsets to fill.
  874. BufferLines - Number of entries in the Buffer array.
  875. Return Value:
  876. 0 - No information was found.
  877. LINE_ERROR - Failure during operation. Call GetLastError to
  878. discover the cause of the failure.
  879. Otherwise the return value is the highest line number found.
  880. --*/
  881. {
  882. PPROCESS_ENTRY ProcessEntry;
  883. PMODULE_ENTRY mi;
  884. ULONG HighestLine = 0;
  885. PLIST_ENTRY Next;
  886. __try {
  887. ProcessEntry = FindProcessEntry( hProcess );
  888. if (!ProcessEntry) {
  889. SetLastError( ERROR_INVALID_HANDLE );
  890. return LINE_ERROR;
  891. }
  892. if (ModuleName != NULL) {
  893. mi = FindModule(hProcess, ProcessEntry, ModuleName, true);
  894. if (mi != NULL) {
  895. return GetFileLineOffsets(mi, FileName, Buffer, BufferLines);
  896. }
  897. SetLastError( ERROR_MOD_NOT_FOUND );
  898. return LINE_ERROR;
  899. }
  900. Next = ProcessEntry->ModuleList.Flink;
  901. if (Next) {
  902. while (Next != &ProcessEntry->ModuleList) {
  903. mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry );
  904. Next = mi->ListEntry.Flink;
  905. if (!LoadSymbols(hProcess, mi, LS_QUALIFIED | LS_LOAD_LINES)) {
  906. continue;
  907. }
  908. HighestLine = GetFileLineOffsets(mi, FileName, Buffer,
  909. BufferLines);
  910. // This will break on lines found or LINE_ERROR.
  911. if (HighestLine > 0) {
  912. break;
  913. }
  914. }
  915. }
  916. } __except (EXCEPTION_EXECUTE_HANDLER) {
  917. ImagepSetLastErrorFromStatus( GetExceptionCode() );
  918. return LINE_ERROR;
  919. }
  920. return HighestLine;
  921. }