Example #1
0
        public IEnumerable <StatementInfo> GetStatementLines(DisasmInfo method, int ilOffset)
        {
            var instrs = GetMetadataMethod(method)?.Body?.Instructions;

            if (instrs is null)
            {
                yield break;
            }
            var instr    = GetInstruction(instrs, (uint)ilOffset);
            var seqPoint = instr?.SequencePoint;

            if (seqPoint is null)
            {
                yield break;
            }

            const int HIDDEN = 0xFEEFEE;

            if (seqPoint.StartLine == HIDDEN || seqPoint.EndLine == HIDDEN)
            {
                yield break;
            }

            foreach (var info in sourceDocumentProvider.GetLines(seqPoint.Document.Url, seqPoint.StartLine, seqPoint.StartColumn, seqPoint.EndLine, seqPoint.EndColumn))
            {
                yield return(new StatementInfo(info.line, info.span, info.partial));
            }
        }
Example #2
0
 MethodDef?GetMetadataMethod(DisasmInfo method)
 {
     if (!StringComparer.OrdinalIgnoreCase.Equals(lastModule?.Location, method.ModuleFilename))
     {
         lastModule = metadataProvider.GetModule(method.ModuleFilename);
         lastMethod = null;
     }
     if (lastModule?.PdbState is null)
     {
         return(null);
     }
     if (lastMethod?.MDToken.Raw != method.MethodToken)
     {
         lastMethod = lastModule?.ResolveToken(method.MethodToken) as MethodDef;
     }
     return(lastMethod);
 }
Example #3
0
        public void Disassemble(Formatter formatter, TextWriter output, DisasmInfo method)
        {
            formatterOutput.writer = output;
            targets.Clear();
            sortedTargets.Clear();

            bool upperCaseHex = formatter.Options.UpperCaseHex;

            output.Write(commentPrefix);
            output.WriteLine("================================================================================");
            output.Write(commentPrefix);
            output.WriteLine(method.MethodFullName);
            uint codeSize = 0;

            foreach (var info in method.Code)
            {
                codeSize += (uint)info.Code.Length;
            }
            var codeSizeHexText = codeSize.ToString(upperCaseHex ? "X" : "x");

            output.WriteLine($"{commentPrefix}{codeSize} (0x{codeSizeHexText}) bytes");

            void Add(ulong address, TargetKind kind)
            {
                if (!targets.TryGetValue(address, out var addrInfo))
                {
                    targets[address] = new AddressInfo(kind);
                }
                else if (addrInfo.Kind < kind)
                {
                    addrInfo.Kind = kind;
                }
            }

            if (method.Instructions.Count > 0)
            {
                Add(method.Instructions[0].IP, TargetKind.Unknown);
            }
            foreach (ref var instr in method.Instructions)
            {
                switch (instr.FlowControl)
                {
                case FlowControl.Next:
                case FlowControl.Interrupt:
                    break;

                case FlowControl.UnconditionalBranch:
                    Add(instr.NextIP, TargetKind.Unknown);
                    if (instr.Op0Kind == OpKind.NearBranch16 || instr.Op0Kind == OpKind.NearBranch32 || instr.Op0Kind == OpKind.NearBranch64)
                    {
                        Add(instr.NearBranchTarget, TargetKind.Branch);
                    }
                    break;

                case FlowControl.ConditionalBranch:
                case FlowControl.XbeginXabortXend:
                    if (instr.Op0Kind == OpKind.NearBranch16 || instr.Op0Kind == OpKind.NearBranch32 || instr.Op0Kind == OpKind.NearBranch64)
                    {
                        Add(instr.NearBranchTarget, TargetKind.Branch);
                    }
                    break;

                case FlowControl.Call:
                    if (instr.Op0Kind == OpKind.NearBranch16 || instr.Op0Kind == OpKind.NearBranch32 || instr.Op0Kind == OpKind.NearBranch64)
                    {
                        Add(instr.NearBranchTarget, TargetKind.Call);
                    }
                    break;

                case FlowControl.IndirectBranch:
                    Add(instr.NextIP, TargetKind.Unknown);
                    // Unknown target
                    break;

                case FlowControl.IndirectCall:
                    // Unknown target
                    break;

                case FlowControl.Return:
                case FlowControl.Exception:
                    Add(instr.NextIP, TargetKind.Unknown);
                    break;

                default:
                    Debug.Fail($"Unknown flow control: {instr.FlowControl}");
                    break;
                }

                var baseReg = instr.MemoryBase;
                if (baseReg == Register.RIP || baseReg == Register.EIP)
                {
                    int opCount = instr.OpCount;
                    for (int i = 0; i < opCount; i++)
                    {
                        if (instr.GetOpKind(i) == OpKind.Memory)
                        {
                            if (method.Contains(instr.IPRelativeMemoryAddress))
                            {
                                Add(instr.IPRelativeMemoryAddress, TargetKind.Branch);
                            }
                            break;
                        }
                    }
                }
                else if (instr.MemoryDisplSize >= 2)
                {
                    ulong displ;
                    switch (instr.MemoryDisplSize)
                    {
                    case 2:
                    case 4: displ = instr.MemoryDisplacement; break;

                    case 8: displ = (ulong)(int)instr.MemoryDisplacement; break;

                    default:
                        Debug.Fail($"Unknown mem displ size: {instr.MemoryDisplSize}");
                        goto case 8;
                    }
                    if (method.Contains(displ))
                    {
                        Add(displ, TargetKind.Branch);
                    }
                }
            }
            foreach (var map in method.ILMap)
            {
                if (targets.TryGetValue(map.nativeStartAddress, out var info))
                {
                    if (info.Kind < TargetKind.BlockStart && info.Kind != TargetKind.Unknown)
                    {
                        info.Kind = TargetKind.BlockStart;
                    }
                }
                else
                {
                    targets.Add(map.nativeStartAddress, info = new AddressInfo(TargetKind.Unknown));
                }
                if (info.ILOffset < 0)
                {
                    info.ILOffset = map.ilOffset;
                }
            }

            int labelIndex = 0, methodIndex = 0;

            string GetLabel(int index) => LABEL_PREFIX + index.ToString();
            string GetFunc(int index) => FUNC_PREFIX + index.ToString();

            foreach (var kv in targets)
            {
                if (method.Contains(kv.Key))
                {
                    sortedTargets.Add(kv);
                }
            }
            sortedTargets.Sort((a, b) => a.Key.CompareTo(b.Key));
            foreach (var kv in sortedTargets)
            {
                var address = kv.Key;
                var info    = kv.Value;

                switch (info.Kind)
                {
                case TargetKind.Unknown:
                    info.Name = null;
                    break;

                case TargetKind.Data:
                    info.Name = GetLabel(labelIndex++);
                    break;

                case TargetKind.BlockStart:
                case TargetKind.Branch:
                    info.Name = GetLabel(labelIndex++);
                    break;

                case TargetKind.Call:
                    info.Name = GetFunc(methodIndex++);
                    break;

                default:
                    throw new InvalidOperationException();
                }
            }

            foreach (ref var instr in method.Instructions)
            {
                ulong ip = instr.IP;
                if (targets.TryGetValue(ip, out var lblInfo))
                {
                    output.WriteLine();
                    if (!(lblInfo.Name is null))
                    {
                        output.Write(lblInfo.Name);
                        output.Write(':');
                        output.WriteLine();
                    }
                    if (lblInfo.ILOffset >= 0)
                    {
                        if (ShowSourceCode)
                        {
                            foreach (var info in sourceCodeProvider.GetStatementLines(method, lblInfo.ILOffset))
                            {
                                output.Write(commentPrefix);
                                var line   = info.Line;
                                int column = commentPrefix.Length;
                                WriteWithTabs(output, line, 0, line.Length, '\0', ref column);
                                output.WriteLine();
                                if (info.Partial)
                                {
                                    output.Write(commentPrefix);
                                    column = commentPrefix.Length;
                                    WriteWithTabs(output, line, 0, info.Span.Start, ' ', ref column);
                                    output.WriteLine(new string('^', info.Span.Length));
                                }
                            }
                        }
                    }
                }

                if (ShowAddresses)
                {
                    var address = FormatAddress(bitness, ip, upperCaseHex);
                    output.Write(address);
                    output.Write(" ");
                }
                else
                {
                    output.Write(formatter.Options.TabSize > 0 ? "\t\t" : "        ");
                }

                if (ShowHexBytes)
                {
                    if (!method.TryGetCode(ip, out var nativeCode))
                    {
                        throw new InvalidOperationException();
                    }
                    var codeBytes = nativeCode.Code;
                    int index     = (int)(ip - nativeCode.IP);
                    int instrLen  = instr.ByteLength;
                    for (int i = 0; i < instrLen; i++)
                    {
                        byte b = codeBytes[index + i];
                        output.Write(b.ToString(upperCaseHex ? "X2" : "x2"));
                    }
                    int missingBytes = HEXBYTES_COLUMN_BYTE_LENGTH - instrLen;
                    for (int i = 0; i < missingBytes; i++)
                    {
                        output.Write("  ");
                    }
                    output.Write(" ");
                }

                formatter.Format(instr, formatterOutput);
                output.WriteLine();
            }
        }