public Task <RegisterNames> GetRegisterNamesAsync() { if (registerNames != null) { return(registerNames.AsTask()); } return(Task.Factory.StartNew(() => { var loc = GetDocumentLocationAsync().Await(DalvikProcess.VmTimeout); MethodDisassembly methodDiss = thread.Manager.Process.DisassemblyProvider.GetFromLocation(loc); registerNames = new RegisterNames(methodDiss == null ? null : methodDiss.Method.Body, HasMethodParametersInLastRegisters); return registerNames; })); }
//private DalvikStackFrame GetUnwindStackFrame(DalvikThread thread, DebugCodeContext context) //{ // foreach (var stackFrame in thread.GetCallStack()) // { // bool isSameMethodEarlierOrSame = stackFrame.Location.IsSameMethod(context.Location) // && stackFrame.Location.Index >= context.Location.Index; // if (isSameMethodEarlierOrSame) // return stackFrame; // } // return null; //} /// <summary> /// Finds the next location with source starting from <paramref name="idx"/>. /// Will return null if no source is found. Will follow a single goto. /// Will return null if multiple gotos or if any other jump instruction is /// encountered. /// </summary> private int?FindNextLocationWithSource(MethodDisassembly disassembly, int idx) { var instructions = disassembly.Method.Body.Instructions; var ins = instructions[idx]; // find the next instruction with source code. var loc = disassembly.FindNextSourceCode(ins.Offset); if (loc == null) { return(null); } int gotos = 0; for (; (ins = instructions[idx]).Offset < loc.Position.MethodOffset; ++idx) { // While working as expected, the following code as no effect on // foreach statements, since the target of the goto is a "IsSpecial" // branch instruction back to the very same goto. if (ins.OpCode == OpCodes.Goto || ins.OpCode == OpCodes.Goto_16 || ins.OpCode == OpCodes.Goto_32) { // follow a single goto. this is typically encountered // at the beginning of the loop of foreach statements. if (gotos++ > 0) { return(null); } ins = (Instruction)ins.Operand; loc = disassembly.FindNextSourceCode(ins.Offset); if (loc == null) { return(null); } idx = instructions.IndexOf(ins) - 1; continue; } if (ins.OpCode.IsJump()) { return(null); } } return(idx); }
public MethodBodyDisassemblyFormatter(MethodDefinition methodDef, MapFileLookup mapFile) { _methodDef = methodDef; _mapFile = mapFile; TypeEntry typeEntry = null; MethodEntry methodEntry = null; if (mapFile != null) { typeEntry = mapFile.GetTypeByNewName(methodDef.Owner.Fullname); if (typeEntry != null) { methodEntry = typeEntry.FindDexMethod(methodDef.Name, methodDef.Prototype.ToSignature()); } } _dissassembly = new MethodDisassembly(methodDef, mapFile, typeEntry, methodEntry); _sourceDocument = new Lazy <string[]>(() => { if (_dissassembly.MethodEntry == null) { return(null); } var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault(); if (pos == null) { return(null); } try { return(File.ReadAllLines(pos.Document.Path)); } catch (Exception) { return(null); } }); }
/// <summary> /// Get all local registers for this frame. /// </summary> /// <returns></returns> public Task <List <DalvikStackFrameValue> > GetRegistersAsync(bool parametersOnly = false, Jdwp.Tag type = Jdwp.Tag.Int, params int[] indizes) { if (parametersOnly && parameters != null) { return(parameters.AsTask()); } if (!parametersOnly && registers != null && indizes.Length == 0) { return(registers.AsTask()); } return(Task.Factory.StartNew(() => { var ret = new List <DalvikStackFrameValue>(); var loc = GetDocumentLocationAsync().Await(DalvikProcess.VmTimeout); List <Register> regDefs; MethodDisassembly methodDiss = thread.Manager.Process.DisassemblyProvider.GetFromLocation(loc); registerNames = registerNames ?? new RegisterNames(methodDiss == null ? null : methodDiss.Method.Body, HasMethodParametersInLastRegisters); if (indizes.Length == 0) { if (methodDiss == null) { return ret; } var body = methodDiss.Method.Body; regDefs = (parametersOnly ? body.Registers.Where(r => registerNames.IsParameter(r)) : body.Registers) .Where(p => indizes.Length == 0 || indizes.Contains(p.Index)) .OrderBy(p => p.Index) .ToList(); } else { regDefs = indizes.Select(i => new Register(i)).ToList(); } var requests = regDefs.Select(reg => new SlotRequest(reg.Index, type)).ToList(); var regValues = Debugger.StackFrame.GetValuesAsync(thread.Id, Id, requests.ToArray()) .Await(DalvikProcess.VmTimeout); var process = thread.Manager.Process; for (int i = 0; i < regDefs.Count && i < regValues.Count; ++i) { var reg = regDefs[i]; int numRegs = methodDiss == null ? int.MaxValue : methodDiss.Method.Body.Instructions.Count; bool isParam = registerNames.IsParameter(reg); string regName = registerNames.GetName(reg); var valInfo = new VariableInfo(0, regName, null, null, numRegs, reg.Index); DalvikStackFrameValue val = new DalvikStackFrameValue(regValues[i], valInfo, isParam, process); ret.Add(val); } if (indizes.Length > 0) { return ret; } if (parametersOnly) { parameters = parameters ?? ret; } else { registers = registers ?? ret; } return ret; })); }
public DebugDisassemblyStream(DebugProgram program, DebugCodeContext documentContext) { _loc = documentContext.DocumentContext.DocumentLocation; _method = program.DisassemblyProvider.GetFromLocation(_loc); }
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()); }