|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
linesym.c
Abstract:
Source file and line support.
Author:
Drew Bliss (drewb) 07-07-1997
Environment:
User Mode
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntldr.h>
#include "private.h"
#include "symbols.h"
#include "globals.h"
// private version of qsort used to avoid compat problems on NT4 and win2k.
// code is published from base\crts
extern void __cdecl dbg_qsort(void *, size_t, size_t, int (__cdecl *) (const void *, const void *));
// #define DBG_LINES
// #define DBG_COFF_LINES
// #define DBG_ADDR_SEARCH
BOOL diaAddLinesForAllMod( PMODULE_ENTRY mi );
#if defined(DBG_LINES) || defined(DBG_COFF_LINES) || defined(DBG_ADDR_SEARCH)
void __cdecl DbgOut(PCSTR Format, ...) { char Buf[512]; va_list Args;
va_start(Args, Format); _vsnprintf(Buf, sizeof(Buf), Format, Args); va_end(Args); OutputDebugStringA(Buf); } #endif
BOOL sci2lline( PMODULE_ENTRY mi, PSRCCODEINFO sci, PIMAGEHLP_LINE64 line64) { assert(mi && line64 && sci);
line64->Address = sci->Address; line64->Key = sci->Key; line64->LineNumber = sci->LineNumber; line64->FileName = mi->SrcFile; strcpy(line64->FileName, sci->FileName); // SECURITY: Don't know size of target buffer.
return true; }
void sciInit(PSRCCODEINFO sci) { ZeroMemory(sci, sizeof(SRCCODEINFO)); sci->SizeOfStruct = sizeof(SRCCODEINFO); }
int __cdecl CompareLineAddresses( const void *v1, const void *v2 ) { PSOURCE_LINE Line1 = (PSOURCE_LINE)v1; PSOURCE_LINE Line2 = (PSOURCE_LINE)v2;
if (Line1->Addr < Line2->Addr) { return -1; } else if (Line1->Addr > Line2->Addr) { return 1; } else { return 0; } }
#ifdef DEBUG
void DumpHintList( PPROCESS_ENTRY pe ) { PSOURCE_HINT sh;
for (sh = pe->SourceHints; sh; sh = sh->next) dtrace("%s - %s\n", sh->filename, sh->mi->ModuleName); } #define Debug_DumpHintList DumpHintList
#else
#define Debug_DumpHintList
#endif
PSOURCE_HINT FindSourceFileInHintList( PPROCESS_ENTRY pe, char *filename ) { PSOURCE_HINT sh;
assert(pe && filename && *filename);
for (sh = pe->SourceHints; sh; sh = sh->next) { if (!strcmp(sh->filename, filename)) return sh; }
return NULL; }
BOOL AddSourceFileToHintList( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR filename ) { PSOURCE_HINT sh; PSOURCE_HINT psh;
assert(pe && mi && filename && *filename);
sh = FindSourceFileInHintList(pe,filename); if (sh) { sh->mi = mi; return true; }
sh = (PSOURCE_HINT)MemAlloc(sizeof(SOURCE_HINT)); if (!sh) return false;
sh->next = NULL; sh->filename = (LPSTR)MemAlloc(strlen(filename) + 1); if (!sh->filename) { MemFree(sh); return false; } strcpy(sh->filename, filename); // SECURITY: Don't know size of target buffer.
sh->mi = mi;
for (psh = pe->SourceHints; psh; psh = psh->next) { if (!psh->next) break; }
if (psh) psh->next = sh; else pe->SourceHints = sh;
Debug_DumpHintList(pe);
return true; }
void RemoveSourceForModuleFromHintList( PPROCESS_ENTRY pe, PMODULE_ENTRY mi ) { PSOURCE_HINT sh; PSOURCE_HINT psh;
assert(pe && mi);
psh = pe->SourceHints; for (sh = pe->SourceHints; sh; sh = sh->next) { if (sh->mi == mi) { if (psh == sh) psh = pe->SourceHints = sh->next; else psh->next = sh->next; MemFree(sh->filename); MemFree(sh); sh = psh; } psh = sh; if (!sh) return; }
Debug_DumpHintList(pe); }
void AddSourceEntry( PMODULE_ENTRY mi, PSOURCE_ENTRY Src ) { PSOURCE_ENTRY SrcCur;
// Overlap is currently permitted.
#if 0
// Check for overlap between SOURCE_ENTRY address ranges.
for (SrcCur = mi->SourceFiles; SrcCur != NULL; SrcCur = SrcCur->Next) { if (!(SrcCur->MinAddr > Src->MaxAddr || SrcCur->MaxAddr < Src->MinAddr)) { DbgOut("SOURCE_ENTRY overlap between %08I64X:%08I64X " "and %08I64X:%08I64X\n", Src->MinAddr, Src->MaxAddr, SrcCur->MinAddr, SrcCur->MaxAddr); } } #endif
// Sort line info by address.
dbg_qsort((PVOID)Src->LineInfo, Src->Lines, sizeof(Src->LineInfo[0]), CompareLineAddresses);
// Link new source information into list, sorted by address
// range covered by information.
for (SrcCur = mi->SourceFiles; SrcCur != NULL; SrcCur = SrcCur->Next) { if (SrcCur->MinAddr > Src->MinAddr) { break; } }
Src->Next = SrcCur; if (SrcCur == NULL) { if (mi->SourceFilesTail == NULL) { mi->SourceFiles = Src; } else { mi->SourceFilesTail->Next = Src; } Src->Prev = mi->SourceFilesTail; mi->SourceFilesTail = Src; } else { if (SrcCur->Prev == NULL) { mi->SourceFiles = Src; } else { SrcCur->Prev->Next = Src; } Src->Prev = SrcCur->Prev; SrcCur->Prev = Src; }
#ifdef DBG_LINES
DbgOut("%08I64X %08I64X: %5d lines, '%s'\n", Src->MinAddr, Src->MaxAddr, Src->Lines, Src->File); #endif
}
#define IS_SECTION_SYM(Sym) \
((Sym)->StorageClass == IMAGE_SYM_CLASS_STATIC && \ (Sym)->Type == IMAGE_SYM_TYPE_NULL && \ (Sym)->NumberOfAuxSymbols == 1)
BOOL AddLinesForCoff( PMODULE_ENTRY mi, PIMAGE_SYMBOL allSymbols, DWORD numberOfSymbols, PIMAGE_LINENUMBER LineNumbers ) { PIMAGE_LINENUMBER *SecLines; BOOL Ret = false; PIMAGE_SECTION_HEADER sh; ULONG i; PIMAGE_SYMBOL Symbol; ULONG LowestPointer;
// Allocate some space for per-section data.
SecLines = (PIMAGE_LINENUMBER *)MemAlloc(sizeof(PIMAGE_LINENUMBER)*mi->NumSections); if (SecLines == NULL) { return false; }
//
// Add line number information for file groups if such
// groups exist.
//
// First locate the lowest file offset for linenumbers. This
// is necessary to be able to compute relative linenumber pointers
// in split images because currently the pointers aren't updated
// during stripping.
sh = mi->SectionHdrs; LowestPointer = 0xffffffff; for (i = 0; i < mi->NumSections; i++, sh++) { if (sh->NumberOfLinenumbers > 0 && sh->PointerToLinenumbers != 0 && sh->PointerToLinenumbers < LowestPointer) { LowestPointer = sh->PointerToLinenumbers; } }
if (LowestPointer == 0xffffffff) { goto EH_FreeSecLines; }
sh = mi->SectionHdrs; for (i = 0; i < mi->NumSections; i++, sh++) { if (sh->NumberOfLinenumbers > 0 && sh->PointerToLinenumbers != 0) { SecLines[i] = (PIMAGE_LINENUMBER) (sh->PointerToLinenumbers - LowestPointer + (DWORD_PTR)LineNumbers);
#ifdef DBG_COFF_LINES
DbgOut("Section %d: %d lines at %08X\n", i, sh->NumberOfLinenumbers, SecLines[i]); #endif
} else { SecLines[i] = NULL; } }
// Look for a file symbol.
Symbol = allSymbols; for (i = 0; i < numberOfSymbols; i++) { if (Symbol->StorageClass == IMAGE_SYM_CLASS_FILE) { break; }
i += Symbol->NumberOfAuxSymbols; Symbol += 1+Symbol->NumberOfAuxSymbols; }
// If no file symbols were found, don't attempt to add line
// number information. Something could be done with the raw
// linenumber info in the image (if it exists) but this probably
// isn't an important enough case to worry about.
while (i < numberOfSymbols) { ULONG iNextFile, iAfterFile; ULONG iCur, iSym; PIMAGE_SYMBOL SymAfterFile, CurSym; PIMAGE_AUX_SYMBOL AuxSym; ULONG Lines; ULONG MinAddr, MaxAddr; LPSTR FileName; ULONG FileNameLen;
#ifdef DBG_COFF_LINES
DbgOut("%3X: '%s', %X\n", i, Symbol+1, Symbol->Value); #endif
// A file symbol's Value is the index of the next file symbol.
// In between the two file symbols there may be static
// section symbols which give line number counts for all
// the line numbers in the file.
// The file chain can be NULL terminated or a circular list,
// in which case this code assumes the end comes when the
// list wraps around.
if (Symbol->Value == 0 || Symbol->Value <= i) { iNextFile = numberOfSymbols; } else { iNextFile = Symbol->Value; }
// Compute the index of the first symbol after the current file
// symbol.
iAfterFile = i+1+Symbol->NumberOfAuxSymbols; SymAfterFile = Symbol+1+Symbol->NumberOfAuxSymbols;
// Look for section symbols and count up the number of linenumber
// references, the min address and the max address.
CurSym = SymAfterFile; iCur = iAfterFile; Lines = 0; MinAddr = 0xffffffff; MaxAddr = 0; while (iCur < iNextFile) { DWORD Addr;
if (IS_SECTION_SYM(CurSym) && SecLines[CurSym->SectionNumber-1] != NULL) { AuxSym = (PIMAGE_AUX_SYMBOL)(CurSym+1);
Lines += AuxSym->Section.NumberOfLinenumbers;
Addr = (ULONG)(CurSym->Value+mi->BaseOfDll);
#ifdef DBG_COFF_LINES
DbgOut(" Range %08X %08X, min %08X max %08X\n", Addr, Addr+AuxSym->Section.Length-1, MinAddr, MaxAddr); #endif
if (Addr < MinAddr) { MinAddr = Addr; } Addr += AuxSym->Section.Length-1; if (Addr > MaxAddr) { MaxAddr = Addr; } }
iCur += 1+CurSym->NumberOfAuxSymbols; CurSym += 1+CurSym->NumberOfAuxSymbols; }
if (Lines > 0) { PSOURCE_ENTRY Src; PSOURCE_LINE SrcLine; ULONG iLine;
// We have a filename and some linenumber information,
// so create a SOURCE_ENTRY and fill it in.
FileName = (LPSTR)(Symbol+1); FileNameLen = strlen(FileName);
Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+ sizeof(SOURCE_LINE)*Lines+ FileNameLen+1); if (Src == NULL) { goto EH_FreeSecLines; }
Src->ModuleId = 0; Src->MinAddr = MinAddr; Src->MaxAddr = MaxAddr; Src->Lines = Lines;
SrcLine = (PSOURCE_LINE)(Src+1); Src->LineInfo = SrcLine;
// Now that we've got a place to put linenumber information,
// retraverse the section symbols and grab COFF linenumbers
// from the appropriate sections and format them into
// the generic format.
CurSym = SymAfterFile; iCur = iAfterFile; while (iCur < iNextFile) { if (IS_SECTION_SYM(CurSym) && SecLines[CurSym->SectionNumber-1] != NULL) { PIMAGE_LINENUMBER CoffLine;
AuxSym = (PIMAGE_AUX_SYMBOL)(CurSym+1); CoffLine = SecLines[CurSym->SectionNumber-1];
#ifdef DBG_COFF_LINES
DbgOut(" %d lines at %08X\n", AuxSym->Section.NumberOfLinenumbers, CoffLine); #endif
for (iLine = 0; iLine < AuxSym->Section.NumberOfLinenumbers; iLine++) { SrcLine->Addr = CoffLine->Type.VirtualAddress+ mi->BaseOfDll; SrcLine->Line = CoffLine->Linenumber; CoffLine++; SrcLine++; }
SecLines[CurSym->SectionNumber-1] = CoffLine; }
iCur += 1+CurSym->NumberOfAuxSymbols; CurSym += 1+CurSym->NumberOfAuxSymbols; }
// Stick file name at the very end of the data block so
// it doesn't interfere with alignment.
Src->File = (LPSTR)SrcLine; memcpy(Src->File, FileName, FileNameLen+1);
AddSourceEntry(mi, Src);
// This routine is successful as long as it adds at least
// one new source entry.
Ret = true; }
// After the loops above iCur and CurSym refer to the next
// file symbol, so update the loop counters from them.
i = iCur; Symbol = CurSym; }
EH_FreeSecLines: MemFree(SecLines);
return Ret; }
BOOL AddLinesForOmfSourceModule( PMODULE_ENTRY mi, BYTE *Base, OMFSourceModule *OmfSrcMod, PVOID PdbModule ) { BOOL Ret; ULONG iFile;
Ret = false;
for (iFile = 0; iFile < (ULONG)OmfSrcMod->cFile; iFile++) { OMFSourceFile *OmfSrcFile; BYTE OmfFileNameLen; LPSTR OmfFileName; PULONG OmfAddrRanges; OMFSourceLine *OmfSrcLine; ULONG iSeg; PSOURCE_ENTRY Src; PSOURCE_ENTRY Seg0Src = NULL; PSOURCE_LINE SrcLine; ULONG NameAllocLen;
OmfSrcFile = (OMFSourceFile *)(Base+OmfSrcMod->baseSrcFile[iFile]);
// The baseSrcLn array of offsets is immediately followed by
// SVA pairs which define the address ranges for the segments.
OmfAddrRanges = &OmfSrcFile->baseSrcLn[OmfSrcFile->cSeg];
// The name length and data immediately follows the address
// range information.
OmfFileName = (LPSTR)(OmfAddrRanges+2*OmfSrcFile->cSeg)+1; OmfFileNameLen = *(BYTE *)(OmfFileName-1);
// The compiler can potentially generate a lot of segments
// per file. The segments within a file have disjoint
// address ranges as long as they are treated as separate
// SOURCE_ENTRYs. If all segments for a particular file get
// combined into one SOURCE_ENTRY it leads to address range overlap
// because of combining non-contiguous segments. Allocating
// a SOURCE_ENTRY per segment isn't that bad, particularly since
// the name information only needs to be allocated in the first
// entry for a file and the rest can share it.
NameAllocLen = OmfFileNameLen+1;
for (iSeg = 0; iSeg < (ULONG)OmfSrcFile->cSeg; iSeg++) { PULONG Off; PUSHORT Ln; ULONG iLine; PIMAGE_SECTION_HEADER sh;
OmfSrcLine = (OMFSourceLine *)(Base+OmfSrcFile->baseSrcLn[iSeg]);
Src = (PSOURCE_ENTRY)MemAlloc(sizeof(SOURCE_ENTRY)+ sizeof(SOURCE_LINE)*OmfSrcLine->cLnOff+ NameAllocLen); if (Src == NULL) { return Ret; }
Src->ModuleId = (ULONG) (ULONG64) PdbModule; Src->Lines = OmfSrcLine->cLnOff;
sh = &mi->SectionHdrs[OmfSrcLine->Seg-1];
// Process raw segment limits into current addresses.
Src->MinAddr = mi->BaseOfDll+sh->VirtualAddress+(*OmfAddrRanges++); Src->MaxAddr = mi->BaseOfDll+sh->VirtualAddress+(*OmfAddrRanges++);
// Retrieve line numbers and offsets from raw data and
// process them into current pointers.
SrcLine = (SOURCE_LINE *)(Src+1); Src->LineInfo = SrcLine;
Off = (ULONG *)&OmfSrcLine->offset[0]; Ln = (USHORT *)(Off+OmfSrcLine->cLnOff);
for (iLine = 0; iLine < OmfSrcLine->cLnOff; iLine++) { SrcLine->Line = *Ln++; SrcLine->Addr = (*Off++)+mi->BaseOfDll+sh->VirtualAddress;
// Line symbol information names the IA64 bundle
// syllables with 0,1,2 whereas the debugger expects
// 0,4,8. Convert.
if (mi->MachineType == IMAGE_FILE_MACHINE_IA64 && (SrcLine->Addr & 3)) { SrcLine->Addr = (SrcLine->Addr & ~3) | ((SrcLine->Addr & 3) << 2); }
SrcLine++; }
if (iSeg == 0) { // Stick file name at the very end of the data block so
// it doesn't interfere with alignment.
Src->File = (LPSTR)SrcLine; memcpy(Src->File, OmfFileName, OmfFileNameLen); Src->File[OmfFileNameLen] = 0;
// Later segments will share this initial name storage
// space so they don't need to alloc their own.
NameAllocLen = 0; Seg0Src = Src; } else if (Seg0Src) { Src->File = Seg0Src->File; }
AddSourceEntry(mi, Src);
// This routine is successful as long as it adds at least
// one new source entry.
Ret = true; } }
return Ret; }
void srcline2sci( PSOURCE_ENTRY Src, PSOURCE_LINE SrcLine, PSRCCODEINFO sci ) { sci->Key = (PVOID)SrcLine; sci->LineNumber = SrcLine->Line; sci->Address = SrcLine->Addr; CopyStrArray(sci->FileName, Src->File ? Src->File : ""); }
PSOURCE_LINE FindLineInSource( PSOURCE_ENTRY Src, DWORD64 Addr ) { int Low, Middle, High; PSOURCE_LINE SrcLine;
Low = 0; High = Src->Lines-1;
while (High >= Low) { Middle = (High <= Low) ? Low : (Low + High) >> 1; SrcLine = &Src->LineInfo[Middle];
#ifdef DBG_ADDR_SEARCH
DbgOut(" Checking %4d:%x`%08X\n", Middle, (ULONG)(SrcLine->Addr>>32), (ULONG)SrcLine->Addr); #endif
if (Addr < SrcLine->Addr) { High = Middle-1; } else if (Middle < (int)Src->Lines-1 && Addr >= (SrcLine+1)->Addr) { Low = Middle+1; } else { PSOURCE_LINE HighLine;
// Find the highest source line with this offset.
// Source lines are sorted by offset so the highest
// source line could be before or after this one.
while (SrcLine > Src->LineInfo && (SrcLine - 1)->Addr == SrcLine->Addr) { SrcLine--; } HighLine = SrcLine; while (SrcLine < Src->LineInfo + Src->Lines - 1 && (++SrcLine)->Addr == HighLine->Addr) { if (SrcLine->Line > HighLine->Line) { HighLine = SrcLine; } } return HighLine; } }
return NULL; }
PSOURCE_ENTRY FindNextSourceEntryForAddr( PMODULE_ENTRY mi, DWORD64 Addr, PSOURCE_ENTRY SearchFrom ) { PSOURCE_ENTRY Src;
Src = SearchFrom != NULL ? SearchFrom->Next : mi->SourceFiles; while (Src != NULL) { if (Addr < Src->MinAddr) { // Source files are kept sorted by increasing address so this
// means that the address will not be found later and
// we can stop checking.
return NULL; } else if (Addr <= Src->MaxAddr) { // Found one.
return Src; } Src = Src->Next; }
return NULL; }
BOOL GetLineFromAddr( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, DWORD64 Addr, PDWORD Displacement, PSRCCODEINFO sci ) { PSOURCE_ENTRY Src; DWORD Bias; DWORD64 srcAddr; BOOL rc;
if (mi == NULL) return false;
rc = false;
if (mi->dia) { rc = diaGetLineFromAddr(mi, Addr, Displacement, sci); if (rc) AddSourceFileToHintList(pe, mi, sci->FileName); return rc; }
srcAddr = ConvertOmapToSrc(mi, Addr, &Bias, option(SYMOPT_OMAP_FIND_NEAREST));
if (!srcAddr) return false;
// We have successfully converted
srcAddr += Bias;
for (;;) { PSOURCE_ENTRY BestSrc; PSOURCE_LINE BestSrcLine; DWORD64 BestDisp;
// Search through all the source entries that contain the given
// address, looking for the line with the smallest displacement.
BestDisp = 0xffffffffffffffff; BestSrc = NULL; Src = NULL; while (Src = FindNextSourceEntryForAddr(mi, srcAddr, Src)) { PSOURCE_LINE SrcLine;
#ifdef DBG_ADDR_SEARCH
DbgOut("Found '%s' %d lines: %08I64X %08I64X for %08I64X\n", Src->File, Src->Lines, Src->MinAddr, Src->MaxAddr, Addr); #endif
// Found a matching source entry, so look up the line
// information.
SrcLine = FindLineInSource(Src, srcAddr); if (SrcLine != NULL && Addr-SrcLine->Addr < BestDisp) { BestDisp = Addr-SrcLine->Addr;
#ifdef DBG_ADDR_SEARCH
DbgOut(" Best disp %I64X\n", BestDisp); #endif
BestSrc = Src; BestSrcLine = SrcLine; if (BestDisp == 0) { break; } } }
// Only accept displaced answers if there's no more symbol
// information to load.
if (BestSrc != NULL && BestDisp == 0) { srcline2sci(BestSrc, BestSrcLine, sci); *Displacement = (ULONG)BestDisp; return true; }
return false; }
return false; }
PSOURCE_ENTRY FindNextSourceEntryForFile( PMODULE_ENTRY mi, LPSTR FileStr, PSOURCE_ENTRY SearchFrom ) { PSOURCE_ENTRY Src;
Src = SearchFrom != NULL ? SearchFrom->Next : mi->SourceFiles; while (Src != NULL) { if (SymMatchFileName(Src->File, FileStr, NULL, NULL)) { return Src; }
Src = Src->Next; }
return NULL; }
PSOURCE_ENTRY FindPrevSourceEntryForFile( PMODULE_ENTRY mi, LPSTR FileStr, PSOURCE_ENTRY SearchFrom ) { PSOURCE_ENTRY Src;
Src = SearchFrom != NULL ? SearchFrom->Prev : mi->SourceFilesTail; while (Src != NULL) { if (SymMatchFileName(Src->File, FileStr, NULL, NULL)) { return Src; }
Src = Src->Prev; }
return NULL; }
BOOL GetLineFromName( PPROCESS_ENTRY pe, PMODULE_ENTRY mi, LPSTR FileName, DWORD LineNumber, PLONG Displacement, PSRCCODEINFO sci, DWORD method ) { BOOL rc; PSOURCE_ENTRY Src; BOOL AtOrGreater;
ULONG Disp; ULONG BestDisp; PSOURCE_ENTRY BestSrc; PSOURCE_LINE BestSrcLine;
if (!mi) return false;
// If the high bit of the line number is set
// it means that the caller only wants lines at
// or greater than the given line.
AtOrGreater = (LineNumber & 0x80000000) != 0; LineNumber &= 0x7fffffff;
if (mi->dia) { rc = diaGetLineFromName(mi, FileName, LineNumber, Displacement, sci, method); if (rc) AddSourceFileToHintList(pe, mi, FileName); return rc; }
//
// Search existing source information for a filename match.
// There can be multiple SOURCE_ENTRYs with the same filename,
// so make sure and search them all for an exact match
// before settling on an approximate match.
//
Src = NULL; BestDisp = 0x7fffffff; BestSrcLine = NULL; while (Src = FindNextSourceEntryForFile(mi, FileName, Src)) { PSOURCE_LINE SrcLine; ULONG i;
// Found a matching source entry, so look up the closest
// line. Line number info is sorted by address so the actual
// line numbers can be in any order so we can't optimize
// this linear search.
SrcLine = Src->LineInfo; for (i = 0; i < Src->Lines; i++) { if (LineNumber > SrcLine->Line) { if (AtOrGreater) { Disp = 0x7fffffff; } else { Disp = LineNumber-SrcLine->Line; } } else { Disp = SrcLine->Line-LineNumber; }
if (Disp < BestDisp) { BestDisp = Disp; BestSrc = Src; BestSrcLine = SrcLine; if (Disp == 0) { break; } }
SrcLine++; }
// If we found an exact match we can stop.
if (BestDisp == 0) { break; } }
// Only accept displaced answers if there's no more symbol
// information to load.
if (BestSrcLine != NULL && (BestDisp == 0)) { srcline2sci(BestSrc, BestSrcLine, sci); *Displacement = (LONG)(LineNumber-BestSrcLine->Line); AddSourceFileToHintList(pe, mi, FileName); return true; }
return false; }
#define LINE_ERROR 0xffffffff
// we need to get rid of this function!
ULONG GetFileLineOffsets( PMODULE_ENTRY mi, LPSTR FileName, PDWORD64 Buffer, ULONG BufferLines ) { PSOURCE_ENTRY Src; ULONG HighestLine = 0;
// This routine collects all line information in one pass so
// there's no opportunity for lazy loading. We have to
// force lines to be loaded up front.
if (mi->dia && option(SYMOPT_LOAD_LINES)) { if (!diaAddLinesForAllMod(mi)) { return LINE_ERROR; } }
Src = NULL; while (Src = FindNextSourceEntryForFile(mi, FileName, Src)) { PSOURCE_LINE Line; ULONG i; ULONG Num;
Line = Src->LineInfo; for (i = 0; i < Src->Lines; i++) { if (Line->Line > HighestLine) { HighestLine = Line->Line; }
Num = Line->Line - 1; if (Num < BufferLines) { Buffer[Num] = Line->Addr; }
Line++; } }
return HighestLine; }
ULONG IMAGEAPI SymGetFileLineOffsets64( IN HANDLE hProcess, IN LPSTR ModuleName, IN LPSTR FileName, OUT PDWORD64 Buffer, IN ULONG BufferLines )
/*++
Routine Description:
This function locates the given file's line information and fills the given buffer with offsets for each line. Buffer[Line - 1] is set to the offset for Line. Buffer entries for lines that do not have information are left unchanged.
Arguments:
hProcess - Process handle, must have been previously registered with SymInitialize.
ModuleName - Module name or NULL.
FileName - File name.
Buffer - Array of offsets to fill.
BufferLines - Number of entries in the Buffer array.
Return Value:
0 - No information was found.
LINE_ERROR - Failure during operation. Call GetLastError to discover the cause of the failure.
Otherwise the return value is the highest line number found.
--*/
{ PPROCESS_ENTRY ProcessEntry; PMODULE_ENTRY mi; ULONG HighestLine = 0; PLIST_ENTRY Next;
__try { ProcessEntry = FindProcessEntry( hProcess ); if (!ProcessEntry) { SetLastError( ERROR_INVALID_HANDLE ); return LINE_ERROR; }
if (ModuleName != NULL) {
mi = FindModule(hProcess, ProcessEntry, ModuleName, true); if (mi != NULL) { return GetFileLineOffsets(mi, FileName, Buffer, BufferLines); }
SetLastError( ERROR_MOD_NOT_FOUND ); return LINE_ERROR; }
Next = ProcessEntry->ModuleList.Flink; if (Next) { while (Next != &ProcessEntry->ModuleList) {
mi = CONTAINING_RECORD( Next, MODULE_ENTRY, ListEntry ); Next = mi->ListEntry.Flink;
if (!LoadSymbols(hProcess, mi, LS_QUALIFIED | LS_LOAD_LINES)) { continue; }
HighestLine = GetFileLineOffsets(mi, FileName, Buffer, BufferLines); // This will break on lines found or LINE_ERROR.
if (HighestLine > 0) { break; } } }
} __except (EXCEPTION_EXECUTE_HANDLER) {
ImagepSetLastErrorFromStatus( GetExceptionCode() ); return LINE_ERROR;
}
return HighestLine; }
|