public int Read(uint dwInstructions, enum_DISASSEMBLY_STREAM_FIELDS dwFields, out uint pdwInstructionsRead, DisassemblyData[] prgDisassembly) { pdwInstructionsRead = 0; if (_method == null) { return(HResults.E_DISASM_NOTAVAILABLE); } var method = _method.Method; var insCount = method.Body.Instructions.Count; bool wantsDocumentUrl = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL) != 0; bool wantsPosition = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION) != 0; bool wantsByteOffset = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET) != 0; bool wantsFlags = (dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS) != 0; for (pdwInstructionsRead = 0; pdwInstructionsRead < dwInstructions; ++pdwInstructionsRead, ++_instructionPointer) { int ip = _instructionPointer; if (ip >= insCount) { break; } var insd = new DisassemblyData(); var ins = method.Body.Instructions[ip]; if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS) != 0) { insd.bstrAddress = _method.FormatAddress(ins); insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_ADDRESS; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID) != 0) { insd.uCodeLocationId = (ulong)ins.Offset; insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_CODELOCATIONID; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE) != 0) { insd.bstrOpcode = _method.FormatOpCode(ins); insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPCODE; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS) != 0) { insd.bstrOperands = _method.FormatOperands(ins); insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS; } if (wantsDocumentUrl || wantsPosition || wantsByteOffset || wantsFlags) { var source = _method.FindSourceCode(ins.Offset); var hasSource = source != null && !source.IsSpecial; bool isSameDocAsPrevious, isSameDocPos; if (hasSource) { isSameDocAsPrevious = _prevSource != null && !_prevSource.IsSpecial && _prevSource.Document.Path == source.Document.Path; isSameDocPos = _prevSource != null && !_prevSource.IsSpecial && isSameDocAsPrevious && source.Position.CompareTo(_prevSource.Position) == 0; } else { isSameDocAsPrevious = (source == null && _prevSource == null) || (source != null && _prevSource != null && _prevSource.IsSpecial); isSameDocPos = isSameDocAsPrevious; } if (wantsDocumentUrl && (!isSameDocAsPrevious || _justSeeked)) { if (hasSource) { insd.bstrDocumentUrl = "file://" + source.Document.Path; insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_DOCUMENTURL; } // how do I clear the document? } int byteOffset = 0; if ((wantsByteOffset || wantsPosition) && hasSource) { if (isSameDocPos) { byteOffset = ins.Offset - _prevSourceInstructionOffset; } else { byteOffset = 0; _prevSourceInstructionOffset = ins.Offset; } } if (wantsPosition && hasSource && !isSameDocPos) { var pos = source.Position; insd.posBeg.dwLine = (uint)(pos.Start.Line - 1); insd.posBeg.dwColumn = (uint)(pos.Start.Column - 1); insd.posEnd.dwLine = (uint)(pos.End.Line - 1); insd.posEnd.dwColumn = (uint)(pos.End.Column - 1); if (insd.posEnd.dwLine - insd.posBeg.dwLine > 3) // never show more than 3 lines. { insd.posEnd.dwLine = insd.posBeg.dwLine + 3; } // Is this just me? I have no idea why my VS throws an exception when using this. //insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_POSITION; } if (wantsByteOffset && hasSource) { insd.dwByteOffset = (uint)byteOffset; insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_BYTEOFFSET; } if (wantsFlags) { if (!isSameDocAsPrevious) { insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_DOCUMENTCHANGE; } if (hasSource) { insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_HASSOURCE; } //if (_loc.Location.Index == (ulong)ins.Offset) // insd.dwFlags |= enum_DISASSEMBLY_FLAGS.DF_INSTRUCTION_ACTIVE; insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_FLAGS; } if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0) { if (!hasSource && !isSameDocPos) { insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS; insd.bstrSymbol = "(generated instructions)"; } else if (hasSource && !isSameDocPos) { // workaround to show something at least if ((dwFields & enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS) != 0) { insd.dwFields |= enum_DISASSEMBLY_STREAM_FIELDS.DSF_OPERANDS_SYMBOLS; insd.bstrSymbol = "File Position: " + source.Position.Start + " - " + source.Position.End; } } } _justSeeked = false; _prevSource = source; } prgDisassembly[pdwInstructionsRead] = insd; } return(pdwInstructionsRead == 0 || _instructionPointer >= insCount ? VSConstants.S_FALSE : VSConstants.S_OK); }
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()); }