private void MarkBranchTargets(string word, string lineText, TextLocation pos, IDocument document, TextArea text) { if (_branchMarkers.Count > 0) { foreach (var marker in _branchMarkers) { document.MarkerStrategy.RemoveMarker(marker); } _branchMarkers.Clear(); text.Refresh(); } if (word == null) { return; } bool couldBeJump = Regex.IsMatch(word, "^[0-9a-fA-F]{3,4}$"); if (!couldBeJump) { return; } int wordIdx; GetWordAtColumn(lineText, pos.Column, out wordIdx); bool isFirstWord = lineText.IndexOf(word, StringComparison.Ordinal) == wordIdx; bool isJumpInstruction = false; if (!isFirstWord) { var words = GetWordAndPrevious(lineText, pos.Column); isJumpInstruction = words != null && words[0] == MethodDisassembly.JumpMarker; } if (!isFirstWord && !isJumpInstruction) { return; } HashSet <string> exceptionTargetOffsets = new HashSet <string>(); if (isFirstWord) { int offset = int.Parse(word, NumberStyles.HexNumber); foreach (var ex in _methodDef.Body.Exceptions) { if (offset >= ex.TryStart.Offset && offset <= ex.TryEnd.Offset) { foreach (var c in ex.Catches) { exceptionTargetOffsets.Add(MethodDisassembly.FormatOffset(c.Instruction.Offset).Trim()); } if (ex.CatchAll != null) { exceptionTargetOffsets.Add(MethodDisassembly.FormatOffset(ex.CatchAll.Offset).Trim()); } } } } LineSegment mainLine = null; int jumpMarkerLen = MethodDisassembly.JumpMarker.Length; // jump target? foreach (var line in document.LineSegmentCollection) { bool isLineFirstWord = true; string curLine = document.GetText(line); int curOffset = 0; foreach (var curWord in SplitAndKeep(curLine, SplitCharacters)) { if (curWord.Trim() == "") { curOffset += curWord.Length; continue; } // mark all words matching the jump instruction if (curWord == word) { if (isLineFirstWord && mainLine == null) { mainLine = line; } else { // add marker. if (curOffset > 4 && curLine.Substring(curOffset - jumpMarkerLen - 1, jumpMarkerLen) == MethodDisassembly.JumpMarker) { AddBranchMarker(document, line.Offset + curOffset - jumpMarkerLen - 1, curWord.Length + jumpMarkerLen + 1); } else { AddBranchMarker(document, line.Offset + curOffset, curWord.Length); } } } else if (/*isLineFirstWord &&*/ exceptionTargetOffsets.Contains(curWord)) { if (!isLineFirstWord) { AddBranchMarker(document, line.Offset + curOffset, curWord.Length, true); } else { AddBranchMarker(document, line.Offset, line.TotalLength, true); } } curOffset += curWord.Length; isLineFirstWord = false; } } if (mainLine != null && _branchMarkers.Count > 0) { // better would be to mark the whole line, not only the words. AddBranchMarker(document, mainLine.Offset, mainLine.TotalLength); } if (_branchMarkers.Count > 0) { text.Refresh(); } }
public string Format(FormatOptions options) { var nl = Environment.NewLine; var sb = new StringBuilder(); var body = _methodDef.Body; var cfg = new ControlFlowGraph(body); SourceCodePosition lastSource = null; _dissassembly.Format = options; var embedSource = options.HasFlag(FormatOptions.EmbedSourceCode) || options.HasFlag(FormatOptions.EmbedSourcePositions); if (embedSource && _dissassembly.MethodEntry != null) { var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault(); if (pos != null) { sb.Append(" // ----- Source Code: "); sb.Append(pos.Document.Path); sb.Append(nl); } } foreach (var block in cfg) { if (options.HasFlag(FormatOptions.ShowControlFlow)) { sb.AppendFormat(" // ----- Entry [{0}] Exit [{1}]{2}", string.Join(", ", block.EntryBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())), string.Join(", ", block.ExitBlocks.Select(x => _dissassembly.FormatAddress(x.Entry).Trim())), nl); } foreach (var i in block.Instructions) { if (embedSource) { var source = _dissassembly.FindSourceCode(i.Offset, false); if (source != null && lastSource != null && source.Document.Path != lastSource.Document.Path) { // print document name. sb.Append(" // ----- "); sb.Append(source.Document.Path); sb.Append(nl); lastSource = null; } if (source == null && lastSource != null) { sb.AppendLine(" // ----- (no source)"); } else if (source != null && (lastSource == null || !source.Position.EqualExceptOffset(lastSource.Position))) { if (options.HasFlag(FormatOptions.EmbedSourcePositions)) { sb.AppendFormat(" // ----- Position: {0} - {1}{2}", source.Position.Start, source.Position.End, nl); } if (options.HasFlag(FormatOptions.EmbedSourceCode)) { string[] lines = GetSourceCodeLines(source); if (lines != null) { sb.AppendLine(" // " + string.Join(nl + " // ", lines)); } } } lastSource = source; } sb.AppendLine(_dissassembly.FormatInstruction(i)); } } sb.AppendLine(); if (body.Exceptions.Any()) { sb.AppendLine("Exception handlers:"); foreach (var handler in body.Exceptions) { sb.AppendFormat("\t{0} - {1}{2}", _dissassembly.FormatAddress(handler.TryStart), _dissassembly.FormatAddress(handler.TryEnd), nl); foreach (var c in handler.Catches) { sb.AppendFormat("\t\t{0} => {1}{2}", c.Type, _dissassembly.FormatAddress(c.Instruction), nl); } if (handler.CatchAll != null) { sb.AppendFormat("\t\t{0} => {1}{2}", "<any>", _dissassembly.FormatAddress(handler.CatchAll), nl); } } sb.AppendLine(); } if (_mapFile != null) { var typeEntry = _mapFile.GetTypeByNewName(_methodDef.Owner.Fullname); if (typeEntry != null) { var methodEntry = typeEntry.FindDexMethod(_methodDef.Name, _methodDef.Prototype.ToSignature()); if (methodEntry != null) { _registersToVariableNames = new Dictionary <string, string>(); var validParameters = methodEntry.Parameters.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validParameters.Any()) { sb.AppendLine("Parameters:"); foreach (var p in validParameters) { var registerName = _dissassembly.FormatRegister(p.Register); sb.AppendFormat("\t{0} (r{1}) -> {2}{3}", registerName, p.Register, p.Name, nl); if (!string.IsNullOrEmpty(p.Name)) { _registersToVariableNames.Add(registerName, p.Name); } } sb.AppendLine(); } var validVariables = methodEntry.Variables.Where(x => !string.IsNullOrEmpty(x.Name)).ToList(); if (validVariables.Any()) { sb.AppendLine("Variables:"); foreach (var p in validVariables) { var registerName = _dissassembly.FormatRegister(p.Register); sb.AppendFormat("\t{0} -> {1}{2}", registerName, p.Name, nl); if (!string.IsNullOrEmpty(p.Name)) { _registersToVariableNames.Add(registerName, p.Name); } } sb.AppendLine(); } sb.AppendLine("Source code positions:"); Document lastDocument = null; foreach (var row in _mapFile.GetSourceCodePositions(methodEntry)) { if (row.Document != lastDocument) { sb.AppendFormat("\t{0}{1}", row.Document.Path, nl); lastDocument = row.Document; } var pos = row.Position; sb.AppendFormat("\t{0}\t({1},{2}) - ({3},{4}){5}", MethodDisassembly.FormatOffset(pos.MethodOffset), pos.Start.Line, pos.Start.Column, pos.End.Line, pos.End.Column, nl); } } } } return(sb.ToString()); }