|
|
//----------------------------------------------------------------------------
//
// Source file searching and loading.
//
// Copyright (C) Microsoft Corporation, 1997-2002.
//
//----------------------------------------------------------------------------
#include "ntsdp.hpp"
#define DBG_SRC 0
#define VERBOSE_SRC 0
ULONG g_SrcOptions;
LPSTR g_SrcPath; PSRCFILE g_SrcFiles; PSRCFILE g_CurSrcFile; ULONG g_CurSrcLine;
ULONG g_OciSrcBefore; ULONG g_OciSrcAfter = 1;
ULONG g_LsSrcBefore = 4; ULONG g_LsSrcTotal = 10;
PSRCFILE LoadSrcFile( LPSTR PathComponent, LPSTR FileName, LPSTR RecordFileName ) { PathFile* File; PSRCFILE SrcFile, Realloc; ULONG Avail; ULONG BaseLen, Len, Done; LPSTR Cur, End; ULONG Lines; LPSTR *CurLine, LineStart;
if (OpenPathFile(PathComponent, FileName, g_SymOptions, &File) != S_OK) { return NULL; }
BaseLen = sizeof(SRCFILE) + strlen(RecordFileName) + 1; Len = BaseLen; SrcFile = NULL; for (;;) { if (File->QueryDataAvailable(&Avail) != S_OK) { goto EH_CloseFile; } if (Avail == 0) { if (SrcFile == NULL) { goto EH_CloseFile; } break; }
Realloc = (SRCFILE *)realloc(SrcFile, Len + Avail); if (Realloc == NULL) { goto EH_CloseFile; } SrcFile = Realloc; if (File->Read((LPSTR)SrcFile + Len, Avail, &Done) != S_OK || Done < Avail) { goto EH_CloseFile; }
Len += Avail; } SrcFile->File = (LPSTR)(SrcFile + 1); strcpy(SrcFile->File, RecordFileName); SrcFile->RawText = (LPSTR)SrcFile + BaseLen; Len -= BaseLen;
// Count lines in the source file. Stop before the last character
// to handle the case where there's a newline at the end of the
// file in the same way as where there isn't one.
Lines = 0; Cur = SrcFile->RawText; End = SrcFile->RawText + Len; while (Cur < End - 1) { if (*Cur++ == '\n') { Lines++; } } Lines++;
SrcFile->LineText = (char **)malloc(sizeof(LPSTR) * Lines); if (SrcFile->LineText == NULL) { goto EH_CloseFile; }
SrcFile->Lines = Lines; Cur = SrcFile->RawText; CurLine = SrcFile->LineText; LineStart = Cur; while (Cur < End - 1) { if (*Cur == '\n') { *CurLine++ = LineStart; *Cur = 0; LineStart = Cur+1; } else if (*Cur == '\r') { *Cur = 0; } Cur++; } *CurLine++ = LineStart;
delete File;
SrcFile->Next = g_SrcFiles; g_SrcFiles = SrcFile;
#if VERBOSE_SRC
dprintf("Loaded '%s' '%s' %d lines\n", FileName, RecordFileName, Lines); #endif
return SrcFile;
EH_CloseFile: free(SrcFile); delete File; return NULL; }
void DeleteSrcFile( PSRCFILE SrcFile ) { if (g_CurSrcFile == SrcFile) { g_CurSrcFile = NULL; g_CurSrcLine = 0; }
free(SrcFile->LineText); free(SrcFile); }
BOOL MatchSrcFileName( PSRCFILE SrcFile, LPSTR File ) { LPSTR FileStop, MatchStop;
//
// SRCFILE filenames are saved as the partial path that
// matched a source path component rather than the full path
// of the file as loaded. When matching against potentially full
// path information in debug info it's useful to use the incoming
// string as the filename and the SRCFILE filename as the match
// string. A full match indicates that the partial path matches
// completely and so should be used.
//
// This doesn't work so well for human input where the filename is
// likely to be just a filename with no path. In this case there
// won't be a full match of the match string, nor is just flipping
// the order of strings useful because that would allow submatches
// such as "foo.c" matching "barfoo.c". Instead this code tests
// two conditions:
// 1. Full match string match.
// 2. Full file string match (implies partial match string match)
// and the mismatch character is a path separator.
// This forces filenames to match completely.
//
if (SymMatchFileName(File, SrcFile->File, &FileStop, &MatchStop) || (FileStop < File && IS_PATH_DELIM(*MatchStop))) { #if DBG_SRC
dprintf("'%s' matches '%s'\n", SrcFile->File, File); #endif
return TRUE; } else { #if DBG_SRC
dprintf("'%s' doesn't match '%s'\n", SrcFile->File, File); #endif
return FALSE; } }
BOOL UnloadSrcFile( LPSTR File ) { PSRCFILE SrcFile, Prev;
Prev = NULL; for (SrcFile = g_SrcFiles; SrcFile != NULL; SrcFile = SrcFile->Next) { if (MatchSrcFileName(SrcFile, File)) { break; }
Prev = SrcFile; }
if (SrcFile == NULL) { return FALSE; }
if (Prev != NULL) { Prev->Next = SrcFile->Next; } else { g_SrcFiles = SrcFile->Next; }
DeleteSrcFile(SrcFile); return TRUE; }
void UnloadSrcFiles( void ) { PSRCFILE Cur, Next;
for (Cur = g_SrcFiles; Cur != NULL; Cur = Next) { Next = Cur->Next;
DeleteSrcFile(Cur); }
g_SrcFiles = NULL; }
PSRCFILE FindLoadedSrcFile( LPSTR File ) { PSRCFILE SrcFile;
for (SrcFile = g_SrcFiles; SrcFile != NULL; SrcFile = SrcFile->Next) { if (MatchSrcFileName(SrcFile, File)) { #if DBG_SRC
dprintf("Found loaded file '%s'\n", SrcFile->File); #endif
return SrcFile; } }
return NULL; }
BOOL ConcatPathComponents(LPSTR Path, LPSTR PathEnd, LPSTR* PathOut, LPSTR FilePath, LPSTR Buffer, ULONG BufferSize) { if (PathEnd == NULL) { PathEnd = strchr(Path, ';'); if (PathEnd != NULL) { if (PathOut != NULL) { *PathOut = PathEnd + 1; } } else { PathEnd = Path + strlen(Path); if (PathOut != NULL) { *PathOut = NULL; } } }
if (PathEnd > Path) { ULONG Len = (ULONG)(PathEnd - Path); if (Len + 1 >= BufferSize) { return FALSE; } memcpy(Buffer, Path, Len); PathEnd = Buffer + (Len - 1); BufferSize -= Len - 1;
// Attempt to avoid duplicating separators while forcing separation.
if ((*PathEnd == ':' && *FilePath == ':') || (IS_SLASH(*PathEnd) && IS_SLASH(*FilePath))) { FilePath++; } else if (!IS_PATH_DELIM(*PathEnd) && !IS_PATH_DELIM(*FilePath)) { // We've guaranteed we have space for this character.
*(++PathEnd) = '\\'; BufferSize--; } return CopyString(PathEnd + 1, FilePath, BufferSize); } else { return CopyString(Buffer, FilePath, BufferSize); } }
void EditPathSlashes( LPSTR Path ) { if (!IsUrlPathComponent(Path)) { return; } PSTR Scan = Path; // Flip all backslashes forwards.
while (*Scan) { if (*Scan == '\\') { *Scan = '/'; } Scan++; } }
BOOL SrcFileExists( LPSTR Path, LPSTR PathEnd, LPSTR* PathOut, LPSTR FilePath, LPSTR File ) { char Buffer[MAX_SOURCE_PATH];
if (!ConcatPathComponents(Path, PathEnd, PathOut, FilePath, Buffer, DIMA(Buffer))) { return FALSE; } if (File != NULL) { if (!CatString(Buffer, "\\", DIMA(Buffer)) || !CatString(Buffer, File, DIMA(Buffer))) { return FALSE; } }
EditPathSlashes(Buffer);
#if DBG_SRC
dprintf("Check for existence of '%s'\n", Buffer); #endif
FILE_IO_TYPE IoType; return PathFileExists(Path, Buffer, g_SymOptions, &IoType); }
BOOL FindSrcFileOnPath(ULONG StartElement, LPSTR File, ULONG Flags, PSTR Found, ULONG FoundSize, PSTR* MatchPart, PULONG FoundElement) { LPSTR PathSuff; LPSTR Path; LPSTR PathStart; LPSTR PathSep; LPSTR PathCharPtr; char PathChar; ULONG Elt;
// Find the element of the path to start at.
PathStart = FindPathElement(g_SrcPath, StartElement, &PathSep); if (PathStart == NULL) { goto CheckPlainFile; }
// Split the given filename into a path prefix and a path
// suffix. Initially the path prefix is any path components
// and the path suffix is just the filename. If there
// are path components attempt to match them against the source
// path. Keep backing up the path one component at a time
// until a match is found or the prefix is emptied. At
// that point just do a plain file search along the source path.
PathSuff = File + strlen(File);
for (;;) { while (--PathSuff >= File) { if (IS_SLASH(*PathSuff) || (*PathSuff == ':' && !IS_SLASH(*(PathSuff + 1)))) { break; } } PathSuff++;
// If we've run out of path prefix we're done with this
// part of the search.
if (PathSuff == File) { break; }
char Save; LPSTR BestPathStart; LPSTR BestPathEnd; LPSTR BestFile; ULONG BestElement; LPSTR MatchPath; LPSTR MatchFile;
Save = *(PathSuff - 1); *(PathSuff - 1) = 0;
#if DBG_SRC
dprintf("Check path pre '%s' suff '%s'\n", File, PathSuff); #endif
Path = PathStart; Elt = StartElement; BestPathStart = NULL; BestFile = PathSuff - 2; while (*Path != 0) { PathSep = strchr(Path, ';'); if (PathSep == NULL) { PathSep = Path + strlen(Path); }
PathCharPtr = PathSep; if (!*PathSep) { // Back up off the terminator so that PathSep
// can be advanced the same way for both
// ';' and end-of-string cases.
PathSep--; }
// Trim trailing slashes on path components as
// the file components have them trimmed so
// leaving them would confuse the matching.
if (PathCharPtr > Path && IS_SLASH(PathCharPtr[-1])) { PathCharPtr--; } PathChar = *PathCharPtr; if (PathChar != 0) { *PathCharPtr = 0; } SymMatchFileName(Path, File, &MatchPath, &MatchFile);
#if DBG_SRC
dprintf("Match '%s' against '%s': %d (match '%s')\n", Path, File, MatchFile - File, MatchFile + 1); #endif
*PathCharPtr = PathChar;
if (MatchFile < BestFile && SrcFileExists(Path, MatchPath + 1, NULL, MatchFile + 1, PathSuff)) { BestPathStart = Path; BestPathEnd = MatchPath + 1; BestFile = MatchFile + 1; BestElement = Elt;
// Check for complete match or first-match mode.
if (MatchPath < Path || MatchFile < File || (Flags & DEBUG_FIND_SOURCE_BEST_MATCH) == 0) { break; } }
Path = PathSep + 1; Elt++; }
*(PathSuff - 1) = Save;
if (BestPathStart != NULL) { #if DBG_SRC
dprintf("Found partial file '%.*s' on path '%.*s'\n", PathSuff - BestFile, BestFile, BestPathEnd - BestPathStart, BestPathStart); #endif
// Return the match found.
if (!ConcatPathComponents(BestPathStart, BestPathEnd, NULL, BestFile, Found, FoundSize)) { return FALSE; } EditPathSlashes(Found); *MatchPart = BestFile; *FoundElement = BestElement; #if DBG_SRC
dprintf("Found partial file '%s' at %d\n", Found, *FoundElement); #endif
return TRUE; }
// Skip past separator.
PathSuff--; }
// Traverse all directories in the source path and try them with the
// filename given. Start with the given filename
// to make the most restrictive check. If
// no match is found keep trimming components off and
// checking again.
PathSuff = File; for (;;) { #if DBG_SRC
dprintf("Scan all paths for '%s'\n", PathSuff); #endif
Path = PathStart; Elt = StartElement; while (Path != NULL && *Path != 0) { if (SrcFileExists(Path, NULL, &PathSep, PathSuff, NULL)) { // SrcFileExists leaves PathSep set to the
// path element after the separator so back up
// one when forming the return path.
if (PathSep != NULL) { PathSep--; } #if DBG_SRC
dprintf("Found file suffix '%s' on path '%.*s'\n", PathSuff, PathSep != NULL ? PathSep - Path : strlen(Path), Path); #endif
if (!ConcatPathComponents(Path, PathSep, NULL, PathSuff, Found, FoundSize)) { return FALSE; } EditPathSlashes(Found); *MatchPart = PathSuff; *FoundElement = Elt;
#if DBG_SRC
dprintf("Found file suffix '%s' at %d\n", Found, *FoundElement); #endif
return TRUE; }
Path = PathSep; Elt++; }
// Trim a component from the front of the path suffix.
PathSep = PathSuff; while (*PathSep != 0 && !IS_SLASH(*PathSep) && (*PathSep != ':' || IS_SLASH(*(PathSep + 1)))) { PathSep++; } if (*PathSep == 0) { // Nothing left to trim.
break; }
PathSuff = PathSep + 1; }
CheckPlainFile:
#if DBG_SRC
dprintf("Check plain file '%s'\n", File); #endif
DWORD OldErrMode; DWORD FileAttrs;
if (g_SymOptions & SYMOPT_FAIL_CRITICAL_ERRORS) { OldErrMode = SetErrorMode(SEM_FAILCRITICALERRORS); } FileAttrs = GetFileAttributes(File);
if (g_SymOptions & SYMOPT_FAIL_CRITICAL_ERRORS) { SetErrorMode(OldErrMode); }
if (FileAttrs != -1) { CopyString(Found, File, FoundSize); *MatchPart = File; *FoundElement = -1;
#if DBG_SRC
dprintf("Found plain file '%s' at %d\n", Found, *FoundElement); #endif
return TRUE; } return FALSE; }
PSRCFILE LoadSrcFileOnPath( LPSTR File ) { if (g_SrcPath == NULL) { return LoadSrcFile(NULL, File, File); }
char Found[MAX_SOURCE_PATH]; PSTR MatchPart; ULONG Elt;
if (FindSrcFileOnPath(0, File, DEBUG_FIND_SOURCE_BEST_MATCH, Found, DIMA(Found), &MatchPart, &Elt)) { PSTR PathComponent; PSTR Sep; char SepChar; PSRCFILE SrcFile;
if (Elt != -1) { PathComponent = FindPathElement(g_SrcPath, Elt, &Sep); SepChar = *Sep; } else { // FindSrcFileOnPath found the file directly under
// its name instead of on the path.
PathComponent = NULL; Sep = NULL; } SrcFile = LoadSrcFile(PathComponent, Found, MatchPart);
if (Sep) { *Sep = SepChar; } return SrcFile; } dprintf("No source found for '%s'\n", File);
return NULL; }
PSRCFILE FindSrcFile( LPSTR File ) { PSRCFILE SrcFile;
#if DBG_SRC
dprintf("Find '%s'\n", File); #endif
SrcFile = FindLoadedSrcFile(File); if (SrcFile == NULL) { SrcFile = LoadSrcFileOnPath(File); } return SrcFile; }
void OutputSrcLines( PSRCFILE File, ULONG First, ULONG Last, ULONG Mark ) { ULONG i; LPSTR *Text;
if (First < 1) { First = 1; } if (Last > File->Lines) { Last = File->Lines; }
Text = &File->LineText[First-1]; for (i = First; i <= Last; i++) { if (i == Mark) { dprintf(">"); } else { dprintf(" "); }
dprintf("%5d: %s\n", i, *Text++); } }
BOOL OutputSrcLinesAroundAddr( ULONG64 Offset, ULONG Before, ULONG After ) { IMAGEHLP_LINE64 Line; ULONG Disp; PSRCFILE SrcFile;
if (!GetLineFromAddr(g_Process, Offset, &Line, &Disp)) { return FALSE; }
SrcFile = FindSrcFile(Line.FileName); if (SrcFile == NULL) { return FALSE; }
if (Before >= Line.LineNumber) { Before = Line.LineNumber - 1; } OutputSrcLines(SrcFile, Line.LineNumber - Before, Line.LineNumber + After - 1, Line.LineNumber); return TRUE; }
ULONG GetOffsetFromLine( PSTR FileLine, PULONG64 Offset ) { IMAGEHLP_LINE64 Line; LPSTR Mod; LPSTR File; LPSTR LineStr; LPSTR SlashF, SlashB; ULONG LineNum; ULONG Disp; ULONG OldSym; ULONG NewSym; BOOL AllowDisp; BOOL Ret; ImageInfo* Image = NULL;
if ((g_SymOptions & SYMOPT_LOAD_LINES) == 0) { WarnOut("WARNING: Line information loading disabled\n"); }
OldSym = g_SymOptions; NewSym = g_SymOptions; // Symbol directives can prefix the source expression.
// These can be given by sufficiently knowledgeable users
// but they're primarily a back-channel communication
// mechanism for windbg's source management.
if (*FileLine == '<') { FileLine++; while (*FileLine != '>') { switch(*FileLine) { case 'U': // Restrict the search to just loaded modules.
NewSym |= SYMOPT_NO_UNQUALIFIED_LOADS; break; default: error(SYNTAX); }
FileLine++; }
FileLine++; } // Crack string of the form [module!][file][:line] into its
// components. Note that ! is a valid filename character so
// it's possible for ambiguity to occur between module references
// and filenames. This code assumes that ! is uncommon and
// handles it as a module separator unless there's a : or \ or /
// before it. : can also occur in paths and is filtered
// in a similar manner.
File = strchr(FileLine, '!'); LineStr = strchr(FileLine, ':'); SlashF = strchr(FileLine, '/'); SlashB = strchr(FileLine, '\\');
if (File != NULL && (LineStr != NULL && File > LineStr) || (SlashF != NULL && File > SlashF) || (SlashB != NULL && File > SlashB)) { File = NULL; }
if (File != NULL) { if (File == FileLine) { error(SYNTAX); }
Mod = FileLine; *File++ = 0; } else { Mod = NULL; File = FileLine; }
// If a module was specified check and see if it's
// a module that's currently present as that
// will affect which error code is returned.
if (Mod != NULL) { Image = g_Process->FindImageByName(Mod, 0, INAME_MODULE, FALSE); } // Look for the first colon after path components.
while (LineStr != NULL && (LineStr < File || LineStr < SlashF || LineStr < SlashB)) { LineStr = strchr(LineStr + 1, ':'); }
LineNum = 1; if (LineStr != NULL) { PSTR NumEnd;
// A specific line was given so don't allow a displacement.
AllowDisp = FALSE; *LineStr = 0; LineNum = strtoul(LineStr + 1, &NumEnd, 0);
if (*NumEnd == '+') { // Setting the high bit of the line number
// tells dbghelp to search in at-or-greater mode.
// This may produce displacements so allow them.
LineNum |= 0x80000000; AllowDisp = TRUE; } else if (*NumEnd == '~') { // Find the closest line number.
AllowDisp = TRUE; } else if (*NumEnd && *NumEnd != ' ' && *NumEnd != '\t') { error(SYNTAX); } } else { AllowDisp = TRUE; }
Line.SizeOfStruct = sizeof(Line); Ret = FALSE;
// If this is a pure linenumber reference then we need to fill in
// the line information with a current location before doing
// the line-relative query.
if (*File == 0) { ADDR Pc;
if (Mod != NULL) { goto EH_Ret; }
g_Machine->GetPC(&Pc); if (!GetLineFromAddr(g_Process, Flat(Pc), &Line, &Disp)) { goto EH_Ret; }
File = NULL; }
// Establish any special symbol options requested.
SymSetOptions(NewSym); Ret = SymGetLineFromName64(g_Process->m_SymHandle, Mod, File, LineNum, (PLONG)&Disp, &Line);
SymSetOptions(OldSym);
EH_Ret: if (Mod != NULL) { *(File-1) = '!'; }
if (LineStr != NULL) { *LineStr = ':'; }
// Only return a match if it's exact or no line number was specified.
if (Ret && (Disp == 0 || AllowDisp)) { *Offset = Line.Address; return LINE_FOUND; } else if (Image != NULL) { return LINE_NOT_FOUND_IN_MODULE; } else { return LINE_NOT_FOUND; } }
void ParseSrcOptCmd( CHAR Cmd ) { char Cmd2; DWORD Opt;
Cmd2 = PeekChar(); if (Cmd2 == 'l') { g_CurCmd++; Opt = SRCOPT_LIST_LINE; } else if (Cmd2 == 'o') { g_CurCmd++; Opt = SRCOPT_LIST_SOURCE_ONLY; } else if (Cmd2 == 's') { g_CurCmd++; Opt = SRCOPT_LIST_SOURCE; } else if (Cmd2 == 't') { g_CurCmd++; Opt = SRCOPT_STEP_SOURCE; } else if (Cmd2 == '0') { // Numeric options.
if (*(++g_CurCmd) != 'x') { error(SYNTAX); } else { g_CurCmd++; Opt = (DWORD)HexValue(4); } } else if (Cmd2 == '*') { g_CurCmd++; // All.
Opt = 0xffffffff; } else if (Cmd2 != 0 && Cmd2 != ';') { error(SYNTAX); } else { // No character means display current settings.
Opt = 0; }
ULONG OldSrcOpt = g_SrcOptions; if (Cmd == '+') { g_SrcOptions |= Opt;
if ((SymGetOptions() & SYMOPT_LOAD_LINES) == 0) { WarnOut(" WARNING: Line information loading disabled\n"); } } else { g_SrcOptions &= ~Opt; }
if ((OldSrcOpt ^ g_SrcOptions) & SRCOPT_STEP_SOURCE) { NotifyChangeEngineState(DEBUG_CES_CODE_LEVEL, (g_SrcOptions & SRCOPT_STEP_SOURCE) ? DEBUG_LEVEL_SOURCE : DEBUG_LEVEL_ASSEMBLY, TRUE); } dprintf("Source options are %x:\n", g_SrcOptions); if (g_SrcOptions == 0) { dprintf(" None\n"); } else { if (g_SrcOptions & SRCOPT_STEP_SOURCE) { dprintf(" %2x/t - Step/trace by source line\n", SRCOPT_STEP_SOURCE); } if (g_SrcOptions & SRCOPT_LIST_LINE) { dprintf(" %2x/l - List source line for LN and prompt\n", SRCOPT_LIST_LINE); } if (g_SrcOptions & SRCOPT_LIST_SOURCE) { dprintf(" %2x/s - List source code at prompt\n", SRCOPT_LIST_SOURCE); } if (g_SrcOptions & SRCOPT_LIST_SOURCE_ONLY) { dprintf(" %2x/o - Only show source code at prompt\n", SRCOPT_LIST_SOURCE_ONLY); } } }
void ParseSrcLoadCmd( void ) { LPSTR Semi; PSRCFILE SrcFile; char Cur; BOOL Unload;
// Check for an unload request.
Unload = FALSE; if (*g_CurCmd == '-') { g_CurCmd++; Unload = TRUE; }
while ((Cur = *g_CurCmd) == ' ' || Cur == '\t') { g_CurCmd++; }
if (Cur == 0 || Cur == ';') { error(SYNTAX); }
// Look for a semicolon, otherwise assume the whole command
// line is the file path.
Semi = strchr(g_CurCmd, ';'); if (Semi != NULL) { *Semi = 0; }
if (Unload) { if (UnloadSrcFile(g_CurCmd)) { dprintf("Unloaded '%s'\n", g_CurCmd); } } else { SrcFile = FindSrcFile(g_CurCmd); if (SrcFile == NULL) { dprintf("Unable to load '%s'\n", g_CurCmd); } }
if (Semi != NULL) { *Semi = ';'; g_CurCmd = Semi; } else { g_CurCmd += strlen(g_CurCmd); }
if (!Unload && SrcFile != NULL) { g_CurSrcFile = SrcFile; g_CurSrcLine = 1; } }
void ParseSrcListCmd( CHAR Cmd ) { LONG First, Count; char Cur; ULONG OldBase; ADDR Addr; ULONG Mark;
if (Cmd == '.') { g_CurCmd++;
PDEBUG_SCOPE Scope = GetCurrentScope(); if (Scope->Frame.InstructionOffset) { // List current frame
ADDRFLAT(&Addr, Scope->Frame.InstructionOffset); } else { // List at PC.
if (!IS_CUR_MACHINE_ACCESSIBLE()) { error(BADTHREAD); } g_Machine->GetPC(&Addr); } Cmd = 'a'; } else if (Cmd == 'a') { g_CurCmd++;
// List at address, so get an address.
GetAddrExpression(SEGREG_CODE, &Addr);
// Search for and consume trailing ,
while ((Cur = *g_CurCmd) == ' ' || Cur == '\t') { g_CurCmd++; } if (Cur == ',') { Cur = *++g_CurCmd; if (Cur == 0 || Cur == ';') { error(SYNTAX); } } } else if (Cmd == 'c') { g_CurCmd++;
if (g_CurSrcFile != NULL) { dprintf("Current: %s(%d)\n", g_CurSrcFile->File, g_CurSrcLine); } else { dprintf("No current source file\n"); } return; }
while ((Cur = *g_CurCmd) == ' ' || Cur == '\t') { g_CurCmd++; }
// Force base 10 for linenumbers.
OldBase = g_DefaultRadix; g_DefaultRadix = 10;
if (Cur == 0 || Cur == ';') { First = Cmd == 'a' ? -(LONG)g_LsSrcBefore : g_CurSrcLine; Count = g_LsSrcTotal; } else if (Cur == ',') { First = Cmd == 'a' ? -(LONG)g_LsSrcBefore : g_CurSrcLine; g_CurCmd++; Count = (ULONG)GetExpression(); } else { First = (ULONG)GetExpression(); if (*g_CurCmd == ',') { g_CurCmd++; Count = (ULONG)GetExpression(); } else { Count = g_LsSrcTotal; } }
g_DefaultRadix = OldBase;
if (Count < 1) { error(SYNTAX); }
Mark = 0;
if (Cmd == 'a') { DWORD Disp; IMAGEHLP_LINE64 Line; PSRCFILE SrcFile;
// Listing from the source file that Addr is in.
if (!g_Process) { error(BADPROCESS); } if (!GetLineFromAddr(g_Process, Flat(Addr), &Line, &Disp)) { return; }
SrcFile = FindSrcFile(Line.FileName); if (SrcFile == NULL) { return; }
g_CurSrcFile = SrcFile; g_CurSrcLine = Line.LineNumber; Mark = Line.LineNumber; }
if (g_CurSrcFile == NULL) { dprintf("No current source file\n"); return; }
// Address list commands are always relative,
// as are negative starting positions.
if (Cmd == 'a' || First < 0) { g_CurSrcLine += First; } else { g_CurSrcLine = First; }
OutputSrcLines(g_CurSrcFile, g_CurSrcLine, g_CurSrcLine + Count - 1, Mark);
g_CurSrcLine += Count; }
void ParseOciSrcCmd(void) { BOOL AlsoLs = FALSE; while (PeekChar() == '-' || *g_CurCmd == '/') { g_CurCmd++; switch(*g_CurCmd++) { case 'a': AlsoLs = TRUE; break; default: error(SYNTAX); } }
if (PeekChar() != ';' && *g_CurCmd) { ULONG64 Val1 = GetExpression(); ULONG64 Val2 = 0; if (PeekChar() != ';' && *g_CurCmd) { Val2 = GetExpression(); } else { Val2 = (Val1 + 1) / 2; Val1 -= Val2; }
g_OciSrcBefore = (ULONG)Val1; g_OciSrcAfter = (ULONG)Val2;
if (AlsoLs) { g_LsSrcBefore = g_OciSrcBefore; g_LsSrcTotal = g_OciSrcBefore + g_OciSrcAfter; } }
if ((g_SrcOptions & SRCOPT_LIST_SOURCE) == 0) { WarnOut("WARNING: Source line display is disabled\n"); } dprintf("At the prompt, display %d source lines before and %d after\n", g_OciSrcBefore, g_OciSrcAfter);
if (AlsoLs) { dprintf("For lsa commands, display %d source lines before\n", g_LsSrcBefore); dprintf("For ls and lsa commands, display %d source lines\n", g_LsSrcTotal); } }
void DotLines(PDOT_COMMAND Cmd, DebugClient* Client) { ULONG NewOpts = g_SymOptions ^ SYMOPT_LOAD_LINES; for (;;) { if (PeekChar() == '-' || *g_CurCmd == '/') { g_CurCmd++; switch(*g_CurCmd++) { case 'd': NewOpts &= ~SYMOPT_LOAD_LINES; break; case 'e': NewOpts |= SYMOPT_LOAD_LINES; break; case 't': // Toggle, already done.
break; default: error(SYNTAX); } } else { break; } } SetSymOptions(NewOpts);
if (g_SymOptions & SYMOPT_LOAD_LINES) { dprintf("Line number information will be loaded\n"); } else { dprintf("Line number information will not be loaded\n"); } }
|