public static Scope ParseSymbol(Codebase owner, string symbol) { return(new Scope { Owner = owner, Name = ExtractScope(symbol), Functions = new List <Function>(), Lines = new List <LineOfCode>(), CalledFrom = new List <Scope>(), CallsTo = new List <Scope>(), Leaks = new List <Backtrace>() }); }
public static SourceFile Create(Codebase owner, Module parentModule, string path) { return(new SourceFile { Owner = owner, FullPath = path, ParentModule = parentModule, Filename = Path.GetFileName(path), Lines = new List <LineOfCode>(), CalledFrom = new List <SourceFile>(), CallsTo = new List <SourceFile>(), Leaks = new List <Backtrace>() }); }
public static LineOfCode Parse(Codebase owner, string line) { line = line.Trim(); var result = new LineOfCode(); result.Owner = owner; result.ID = line; result.CalledFrom = new List <LineOfCode>(); result.CallsTo = new List <LineOfCode>(); result.Leaks = new List <Backtrace>(); var match = Regex.Match(line, "(?<moduleName>.*)\\!(?<symbolName>.*)\\+(?<rest>(.*))?$|(?<moduleName>.*)$"); var moduleName = match.Groups["moduleName"].Value; var symbolName = match.Groups["symbolName"].Value; if (String.IsNullOrEmpty(symbolName)) { symbolName = moduleName; } var rest = match.Groups["rest"].Success ? match.Groups["rest"].Value : ""; result.Module = owner.Modules.FirstOrDefault(x => x.Name == moduleName); result.Scope = owner.GetScope(symbolName); result.Function = owner.GetFunction(symbolName); result.Scope.Lines.Add(result); // Add line to scope result.Function.Lines.AddOrGet(result); // Add line to function result.Module.Scopes.AddOrGet(result.Scope); // Add scope to module result.Module.Functions.AddOrGet(result.Function); // Add function to module result.Module.Lines.AddOrGet(result); // Add line to module match = Regex.Match(rest, ".* \\((?<fileName>.*), (?<lineNum>\\d*)\\)"); if (match.Success) // Is file,line present? { var filename = match.Groups["fileName"].Value; var lineNum = Convert.ToInt32(match.Groups["lineNum"].Value); result.LineNumber = lineNum; result.SourceFile = owner.GetFile(filename, result.Module); result.SourceFile.Lines.AddOrGet(result); // Add line to file result.Module.Files.AddOrGet(result.SourceFile); // Add file to module result.GeneratePreview(filename, lineNum); } return(result); }
public static Module Create(Codebase owner, string name, string symbolsFile) { return(new Module { Name = name, Owner = owner, SymbolsFile = symbolsFile, Scopes = new List <Scope>(), Files = new List <SourceFile>(), Lines = new List <LineOfCode>(), Functions = new List <Function>(), CalledFrom = new List <Module>(), CallsTo = new List <Module>(), Leaks = new List <Backtrace>() }); }
public static Function ParseSymbol(Codebase owner, string symbol) { var match = Regex.Match(symbol, "((.+::)*)(?<functionName>.*)"); var name = match.Groups["functionName"].Value; var scope = owner.GetScope(symbol); var result = new Function { Owner = owner, SymbolName = symbol, Name = name, DeclaringScope = scope, Lines = new List <LineOfCode>(), CalledFrom = new List <Function>(), CallsTo = new List <Function>(), Leaks = new List <Backtrace>() }; scope.Functions.AddOrGet(result); return(result); }
public static Backtrace FromLines(Codebase owner, List <string> lines, int startLine, int endLine) { var header = lines[0]; var subHeader = lines[1]; var headerNumbers = Regex.Matches(header, "(?<number>^-\\s*\\d+)|(?<number>\\d+)( |\\))") // first number must capture negative sign if exists. .Cast <Match>() .Select(x => x.Groups["number"].Value.Replace(" ", "")) .Select(x => Convert.ToInt32(x)) .ToList(); var subHeaderNumberMatches = Regex.Matches(subHeader, "(?<number>^-\\s*\\d+)|(?<number>\\d+)( |\\))"); //var subHeaderNumbers = Regex.Matches(subHeader, "(?<number>^-\\s*\\d+)|(?<number>\\d+)( |\\))") // first number must capture negative sign if exists. var subHeaderNumbers = subHeaderNumberMatches .Cast <Match>() .Select(x => x.Groups["number"].Value.Replace(" ", "")) .Select(x => Convert.ToInt32(x)) .ToList(); var bytesDelta = headerNumbers[0]; var newBytes = headerNumbers[1]; var oldBytes = headerNumbers[2]; var countDelta = subHeaderNumbers[0]; var newCount = subHeaderNumbers[1]; var oldCount = subHeaderNumbers[2]; var result = new Backtrace { TotalLeak = bytesDelta, Count = countDelta, Owner = owner, Lines = new List <LineOfCode>(), StartLine = startLine, EndLine = endLine }; var justLines = lines.Skip(2).Where(x => x.Trim() != string.Empty).ToList(); LineOfCode prevLine = null; foreach (var lineStr in justLines) { var line = owner.GetLine(lineStr); line.Leaks.AddOrGet(result); // Add leak to line's leaks line.Function.Leaks.AddOrGet(result); // Add leak to line's function's leak line.Scope.Leaks.AddOrGet(result); // Add leak to line's scope's leak if (line.SourceFile != null) { line.SourceFile.Leaks.AddOrGet(result); // Add leak to line's file's leaks } line.Module.Leaks.AddOrGet(result); // Add leak to line's module's leaks result.Lines.Add(line); // Add line to leak // Connect and update calls to and called from if (prevLine != null) { line.CallsTo.AddOrGet(prevLine); // Line calls prevLine line.Function.CallsTo.AddOrGet(prevLine.Function); // Line's function calls prevLine's function line.Module.CallsTo.AddOrGet(prevLine.Module); // Line's module calls prevLine's module if (line.SourceFile != null && prevLine.SourceFile != null) { line.SourceFile.CallsTo.AddOrGet(prevLine.SourceFile); // Line's file calls prevLine's file prevLine.SourceFile.CalledFrom.AddOrGet(line.SourceFile); // PrevLine's file is called from line's file } prevLine.CalledFrom.AddOrGet(line); // PrevLine is called from line prevLine.Function.CalledFrom.AddOrGet(line.Function); // PrevLine's function is called from line's function prevLine.Module.CalledFrom.AddOrGet(line.Module); // PrevLine's module is called from line's module } prevLine = line; } return(result); }
public static Codebase Parse(string path, Action <int> onProgress = null) { if (!File.Exists(path)) { throw new Exception("File \"" + path + "\" not found!"); } var lines = File.ReadAllLines(path); if (onProgress != null) { onProgress(10); } var blocksStarts = new List <int>(); // Detect block edges for (int i = 0; i < lines.Length; i++) { var line = lines[i]; // Foreach block start foreach (Match match in Regex.Matches(line, "[+-]( )*\\d+ \\(( )*\\d+ \\-( )*\\d")) { var start = match.Index; if (blocksStarts.Any()) { if (blocksStarts.Last() < i - 1) { blocksStarts.Add(i); } } else { blocksStarts.Add(i); } } } blocksStarts.Add(lines.Count() - 1); if (onProgress != null) { onProgress(20); } var codebase = new Codebase(); codebase.RawData = File.ReadAllText(path); if (onProgress != null) { onProgress(30); } // Detect and parse modules for (int i = 0; i < blocksStarts[0]; i++) { var line = lines[i]; var match = Regex.Match(line, "DBGHELP\\: (?<moduleName>.*) - (?<label>.*)"); if (match.Success) { var symbolsFile = string.Empty; if ("private symbols & lines " == match.Groups["label"].Value) { symbolsFile = lines[i + 1].Trim(); } codebase.Modules.Add(Module.Create(codebase, match.Groups["moduleName"].Value, symbolsFile)); } } // Fake module to match "Alias" entries in stack. codebase.Modules.Add(Module.Create(codebase, "Alias", "")); if (onProgress != null) { onProgress(50); } // Parse the backtraces for (int i = 0; i < blocksStarts.Count() - 1; i++) { var startIndex = blocksStarts[i]; var endIndex = blocksStarts[i + 1]; var blockLines = lines.Skip(startIndex) .Take(endIndex - startIndex) .Where(x => x.Trim(' ', '\t') != string.Empty) .ToList(); if (blockLines.Count() < 4) { continue; } codebase.AddBacktrace(blockLines, blocksStarts[i], blocksStarts[i + 1]); if (onProgress != null) { onProgress((int)(50 + 50 * ((double)blocksStarts[i + 1] / lines.Count()))); } } codebase.Normalize(); return(codebase); }