Example #1
0
        private void InspectAssembly(HtmlWriter writer, Assembly asm)
        {
            using (writer.Tag("small")) {
                DomainLink(writer);
            }
            writer.Inline("h5", asm.Name);

            using (writer.ContainerFluid())
            {
                var namespaces = asm.Namespaces.Where(s => s.Name.Length > 0).ToList();
                if (namespaces.Count > 0)
                {
                    using (writer.ContainerFluid())
                        using (writer.Tag("code"))
                        {
                            writer.Inline("h6", "// namespaces");
                            MakeCodeList(
                                writer,
                                namespaces.OrderBy(n => n.Name),
                                n =>
                            {
                                writer.Write("namespace ");
                                NamespaceLink(writer, n, n.RelativeName);
                            });
                        }
                }

                var unnamed = asm.FindNamespace("");
                if (unnamed != null)
                {
                    using (writer.ContainerFluid())
                        using (writer.Tag("code"))
                        {
                            writer.Inline("h6", "// Root namespace");
                            WriteNamespaceMembers(writer, unnamed);
                        }
                }
            }
        }
        private void LayoutInstanceProperties(HtmlWriter writer, Type type)
        {
            var instanceProperties = type.GetProperties(k_AllInstanceBindings);

            if (instanceProperties.Length == 0)
            {
                return;
            }

            Array.Sort(instanceProperties, (lhs, rhs) => ReflectionHelper.CompareProperties(type, lhs, rhs));
            int split = instanceProperties.Length;

            for (int i = 0; i < instanceProperties.Length; i++)
            {
                if (instanceProperties[i].DeclaringType != type)
                {
                    split = i;
                    break;
                }
            }

            if (split > 0)
            {
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Instance properties");
                    LayoutProperties(writer, ArrayView(instanceProperties, 0, split));
                }
            }

            if (split < instanceProperties.Length)
            {
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Inherited properties");
                    LayoutProperties(writer, ArrayView(instanceProperties, split));
                }
            }
        }
        private void LayoutInstanceMethods(HtmlWriter writer, Type type)
        {
            var instanceMethods = type.GetMethods(k_AllInstanceBindings);

            if (instanceMethods.Length == 0)
            {
                return;
            }

            Array.Sort(instanceMethods, (lhs, rhs) => ReflectionHelper.CompareMethods(type, lhs, rhs));
            int split = instanceMethods.Length;

            for (int i = 0; i < instanceMethods.Length; i++)
            {
                if (instanceMethods[i].DeclaringType != type)
                {
                    split = i;
                    break;
                }
            }

            if (split > 0)
            {
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Instance methods");
                    LayoutMethods(writer, ArrayView(instanceMethods, 0, split).Where(m => !m.IsSpecialName));
                }
            }

            if (split < instanceMethods.Length)
            {
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Inherited methods");
                    LayoutMethods(writer, ArrayView(instanceMethods, split).Where(m => !m.IsSpecialName));
                }
            }
        }
Example #4
0
        private void InspectCtor(HtmlWriter writer, Assembly assembly, Type type, ConstructorInfo ctor)
        {
            LayoutMethodHeader(writer, assembly, type, ctor);
            using (writer.Tag("code"))
                using (writer.Tag("h5"))
                {
                    WriteCtorPrefix(writer, ctor);
                    writer.Write(" ");
                    WriteCtorDeclaration(writer, ctor);
                }

            using (writer.ContainerFluid())
                WriteDissassembly(writer, ctor);
        }
Example #5
0
        private void InspectMethod(HtmlWriter writer, Assembly assembly, Type type, MethodInfo method)
        {
            LayoutMethodHeader(writer, assembly, type, method);
            using (writer.Tag("code"))
                using (writer.Tag("h5"))
                {
                    WriteMethodPrefix(writer, method);
                    writer.Write(" ");
                    WriteMethodReturnType(writer, method);
                    writer.Write(" ");
                    WriteMethodDeclaration(writer, method);
                }

            using (writer.ContainerFluid())
                WriteDissassembly(writer, method);
        }
Example #6
0
 void WriteNamespaceMembers(HtmlWriter writer, Namespace ns)
 {
     using (writer.Tag("code"))
     {
         foreach (var group in ns.Types.Where(t => t.DeclaringType == null).GroupBy(t => TypeKinds.Classify(t)).OrderBy(group => group.Key))
         {
             using (writer.ContainerFluid())
             {
                 writer.Inline("h6", "// " + group.Key.KindName());
                 MakeCodeList(
                     writer,
                     group.OrderBy(t => t.Name),
                     t => WriteInlineAttributes(writer, t.GetCustomAttributes(false)),
                     t => WriteShortTypeDeclaration(writer, t)
                     );
             }
         }
     }
 }
        private void LayoutNestedTypes(HtmlWriter writer, Type type)
        {
            var nested = type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic);

            if (nested.Length == 0)
            {
                return;
            }
            using (writer.ContainerFluid())
            {
                writer.Inline("h6", "// Nested types");
                MakeCodeList(
                    writer,
                    nested,
                    t => WriteInlineAttributes(writer, t.GetCustomAttributes(false)),
                    t => WriteTypeDeclaration(writer, t)
                    );
            }
        }
Example #8
0
        void InspectDomain(HtmlWriter writer)
        {
            writer.Inline("h5", AppDomain.CurrentDomain.FriendlyName);
            var assemblies = m_Explorer.Assemblies.ToArray();

            Array.Sort(assemblies, (lhs, rhs) => lhs.FullName.CompareTo(rhs.FullName));
            if (assemblies.Length > 0)
            {
                using (writer.ContainerFluid())
                    using (writer.Tag("code"))
                    {
                        writer.Inline("h6", "// assemblies");
                        MakeCodeList(
                            writer,
                            assemblies,
                            a => AssemblyLink(writer, a),
                            a => writer.Write("    // " + a.FullName)
                            );
                    }
            }
        }
Example #9
0
        private void InspectNamespace(HtmlWriter writer, Namespace ns)
        {
            using (writer.Tag("small"))
            {
                DomainLink(writer);
                writer.Write(" | ");
                AssemblyLink(writer, ns.Assembly);
            }

            using (writer.ContainerFluid())
            {
                using (writer.Tag("code"))
                    using (writer.Tag("h5"))
                    {
                        writer.Write("namespace ");
                        NamespaceLink(writer, ns, ns.PrettyName);
                    }

                WriteNamespaceMembers(writer, ns);
            }
        }
        void ExecuteLookup(HtmlWriter writer, HttpListenerRequest request)
        {
            const string addresses = nameof(addresses);

            using (writer.Tag("form", "action", CommandUrl("lookup"), "method", "post"))
                using (writer.ContainerFluid())
                    using (writer.Tag("div", "class", "form-group"))
                    {
                        writer.Inline("h2", "Paste addresses to look up (hex)");
                        writer.Tag("textarea", "class", "form-control", "name", addresses, "rows", "10").Dispose();
                        writer.Break();
                        writer.InlineTag("input", "type", "submit", "value", "Submit");
                    }

            NameValueCollection postValues;

            using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
                postValues = System.Web.HttpUtility.ParseQueryString(reader.ReadToEnd());
            if (postValues[addresses] != null)
            {
                var modules = Process.GetCurrentProcess().Modules;
                string FindModule(long address)
                {
                    for (int i = 0; i < modules.Count; i++)
                    {
                        var  m           = modules[i];
                        long baseAddress = m.BaseAddress.ToInt64();
                        if (baseAddress <= address && address < baseAddress + m.ModuleMemorySize)
                        {
                            return(modules[i].ModuleName);
                        }
                    }
                    return("unknown module");
                }

                using (writer.ContainerFluid())
                {
                    writer.Inline("h4", "Results");
                    var lines = postValues[addresses].Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
                    using (writer.Tag("textarea", "class", "form-control", "rows", "10"))
                    {
                        foreach (var line in lines)
                        {
                            writer.Write(line);
                            writer.Write(", ");
                            int start = line.IndexOf("0x");
                            if (start >= 0)
                            {
                                int end = line.IndexOf(',', start);
                                if (end < 0)
                                {
                                    end = line.Length;
                                }
                                var numberString = line.Substring(start + 2, end - start - 2);
                                if (long.TryParse(numberString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out long address))
                                {
                                    var jitInfo = Mono.GetJitInfo(new IntPtr(address));
                                    if (jitInfo.Method == null)
                                    {
                                        writer.Write("unknown method");
                                    }
                                    else if (jitInfo.Method is MethodInfo m)
                                    {
                                        WriteTypeName(writer, m.DeclaringType, true);
                                        writer.Write(".");
                                        WriteMethodDeclaration(writer, m, true);
                                    }
                                    else if (jitInfo.Method is ConstructorInfo c)
                                    {
                                        WriteCtorDeclaration(writer, c, true);
                                    }
                                    writer.Write(", ");
                                    writer.Write(FindModule(address));
                                }
                                else
                                {
                                    writer.Write("failed to parse " + numberString + ",");
                                }
                            }
                            else
                            {
                                writer.Write("failed to parse,");
                            }


                            writer.Write("\n");
                        }
                    }
                }
            }
        }
        void HandleRequest(HttpListenerContext ctxt)
        {
            // decode command
            string url          = ctxt.Request.RawUrl;
            int    commandStart = url.IndexOf('/', 1) + 1;
            string command      = null;

            if (commandStart != -1)
            {
                int commandEnd = url.IndexOf('?', commandStart);
                if (commandEnd == -1)
                {
                    commandEnd = url.Length;
                }

                command = url.Substring(commandStart, commandEnd - commandStart);
            }

            if (string.IsNullOrEmpty(command))
            {
                command = "inspect";
            }

            using (MemoryStream stream = new MemoryStream())
            {
                var sw = new StreamWriter(stream, new UTF8Encoding(false));
                sw.WriteLine("<!doctype html>");
                var writer = new HtmlWriter(sw);
                using (writer.Tag("html", "lang", "en"))
                {
                    using (writer.Tag("head"))
                    {
                        WriteHeaderContent(sw, "ASM Explorer");
                    }

                    using (writer.Tag("body"))
                        using (writer.ContainerFluid())
                        {
                            switch (command)
                            {
                            case "inspect":
                            {
                                ExecuteInspect(writer, ctxt.Request.QueryString);
                                break;
                            }

                            case "lookup":
                            {
                                ExecuteLookup(writer, ctxt.Request);
                                break;
                            }

                            default:
                            {
                                writer.Write($"Invalid command \"{command}\" in {url}");
                                break;
                            }
                            }
                        }

                    sw.WriteLine();
                }

                sw.Flush();
                ctxt.Response.ContentLength64 = stream.Length;
                stream.Position = 0;
                stream.WriteTo(ctxt.Response.OutputStream);
            }

            ctxt.Response.OutputStream.Close();
        }
Example #12
0
        private void WriteDissassembly(HtmlWriter writer, MethodBase method)
        {
            if (method.IsAbstract || method.ContainsGenericParameters)
            {
                writer.Write("Cannot display disassembly for generic or abstract methods.");
                return;
            }

            var context = new MethodContext()
            {
                DebugEnabled = MonoDebug.IsEnabled
            };

            var jitInfo = Mono.GetJitInfo(method);

            using (writer.ContainerFluid())
            {
                writer.Write("Address: ");
                writer.Write(jitInfo.CodeStart.ToString("X16"));
                writer.Break();
                writer.Write("Code Size in Bytes: ");
                writer.Write(jitInfo.CodeSize.ToString());
                writer.Break();
                writer.Write("Debug mode: ");
                writer.Write(context.DebugEnabled ? "enabled" : "disabled");
                writer.Break();
            }

            if (jitInfo.CodeSize <= 0)
            {
                return;
            }

            using (writer.Tag("pre"))
            {
                using (writer.Tag("code"))
                {
                    // some special help for calls using R11 and nops
                    int  nops  = 0;
                    bool first = true;
                    lock (_disassemblerLock)
                    {
                        foreach (var inst in GetInstructions(jitInfo))
                        {
                            context.HasLineNote = false;

                            if (first)
                            {
                                context.HasBasePointer =
                                    inst.Mnemonic == ud_mnemonic_code.UD_Ipush &&
                                    inst.Operands[0].Type == ud_type.UD_OP_REG &&
                                    inst.Operands[0].Base == ud_type.UD_R_RBP;
                                first = false;
                            }

                            // abbreviate excessive nopping
                            if (inst.Mnemonic == ud_mnemonic_code.UD_Inop)
                            {
                                nops++;
                                context.LastInstruction = inst;
                                continue;
                            }

                            if (nops > 0)
                            {
                                if (nops == 1)
                                {
                                    writer.Write(context.LastInstruction.ToString());
                                }
                                else
                                {
                                    var str = context.LastInstruction.ToString();
                                    writer.Write(str);
                                    context.LineLength = str.Length;
                                    StartNote(writer, ref context);

                                    writer.Write("repeated nops (");
                                    writer.Write(nops.ToString());
                                    writer.Write(" bytes)");
                                }

                                nops = 0;
                                context.HasLineNote = false;
                                writer.Write("\n");
                            }

                            using (writer.Tag("span", "id", "X" + Address(inst).ToString("X16")))
                            {
                                var str = inst.ToString();
                                context.LineLength = str.Length;
                                writer.Write(str);

                                if (inst.Mnemonic == ud_mnemonic_code.UD_Imov)
                                {
                                    var op0 = inst.Operands[0];
                                    var op1 = inst.Operands[1];

                                    // call targets on x64 are frequently placed in R11, so let's ensure that we catch that.
                                    if (IsR11(op0))
                                    {
                                        context.R11 = op1;
                                    }
                                    if (context.DebugEnabled)
                                    {
                                        if (IsLocalStore(inst) && IsR11(op1) && context.R11 != null && context.R11.Type == ud_type.UD_OP_IMM)
                                        {
                                            if (context.BreakpointTrampolineOffset == 0)
                                            {
                                                context.BreakpointTrampolineOffset = op0.Value;
                                                StartNote(writer, ref context);
                                                writer.Write("write breakpoint trampoline");
                                            }
                                            else if (context.SinglestepTrampolineOffset == 0)
                                            {
                                                context.SinglestepTrampolineOffset = op0.Value;
                                                StartNote(writer, ref context);
                                                writer.Write("write singlestep trampoline");
                                            }
                                        }
                                        else if (IsReadSinglestepTrampoline(inst))
                                        {
                                            StartNote(writer, ref context);
                                            writer.Write("read singlestep trampoline");
                                        }
                                        else if (IsReadBreakpointTrampoline(inst))
                                        {
                                            StartNote(writer, ref context);
                                            writer.Write("read breakpoint trampoline");
                                        }
                                    }
                                }
                                else if (inst.Mnemonic == ud_mnemonic_code.UD_Iadd)
                                {
                                    var op1 = inst.Operands[1];
                                    if (op1.Type == ud_type.UD_OP_IMM)
                                    {
                                        StartNote(writer, ref context);
                                        writer.Write(op1.Value.ToString());
                                    }
                                }
                                else if (inst.Mnemonic == ud_mnemonic_code.UD_Icall)
                                {
                                    WriteCallInstruction(writer, inst, ref context);
                                    context.R11 = null;
                                }
                                else if (IsJump(inst.Mnemonic))
                                {
                                    WriteJumpInstruction(writer, inst, ref context);
                                }
                            }

                            writer.Write("\n");

                            context.LastInstruction = inst;
                        }
                    }
                }
            }

            bool IsR11(Operand op) => op.Type == ud_type.UD_OP_REG && op.Base == ud_type.UD_R_R11;
            bool IsReadSinglestepTrampoline(Instruction inst) => IsLocalLoadOffset(inst, context.SinglestepTrampolineOffset);
            bool IsReadBreakpointTrampoline(Instruction inst) => IsLocalLoadOffset(inst, context.BreakpointTrampolineOffset);
            ud_type StackFrameRegister() => context.HasBasePointer ? ud_type.UD_R_RBP : ud_type.UD_R_RSP;

            bool IsLocalInteraction(Instruction inst, int operand)
            {
                if (inst.Mnemonic != ud_mnemonic_code.UD_Imov)
                {
                    return(false);
                }
                var op = inst.Operands[operand];

                return(op.Type == ud_type.UD_OP_MEM && op.Base == StackFrameRegister());
            }

            bool IsLocalStore(Instruction inst) => IsLocalInteraction(inst, 0);
            bool IsLocalLoad(Instruction inst) => IsLocalInteraction(inst, 1);
            bool IsLocalLoadOffset(Instruction inst, long offset) => IsLocalLoad(inst) && inst.Operands[1].Value == offset;
        }
        private void InspectType(HtmlWriter writer, Assembly assembly, Type type)
        {
            var asm = assembly;
            var ns  = asm.FindNamespace(type.Namespace);

            using (writer.Tag("small"))
            {
                DomainLink(writer);
                writer.Write(" | ");
                AssemblyLink(writer, asm);
                writer.Write(" | ");
                NamespaceLink(writer, ns, type.Namespace ?? "<root>");

                // see whether this is a nested type
                if (type.DeclaringType != null)
                {
                    writer.Write(" | ");
                    TypeLink(writer, type.DeclaringType);
                }
            }

            using (writer.ContainerFluid())
                using (writer.Tag("code"))
                {
                    writer.Write("namespace ");
                    NamespaceLink(writer, ns, string.IsNullOrEmpty(ns.FullName) ? "<root>" : ns.FullName);

                    HtmlWriter.TagHandle outerClass = default;
                    if (type.DeclaringType != null)
                    {
                        outerClass = writer.ContainerFluid();
                        WriteTypeDeclaration(writer, type.DeclaringType);
                    }

                    using (writer.ContainerFluid())
                    {
                        var attr = type.GetCustomAttributes(false);
                        if (attr.Length > 0)
                        {
                            WriteAttributes(writer, attr);
                        }

                        using (writer.Tag("h5"))
                            WriteTypeDeclaration(writer, type);

                        if (type.IsGenericType && type.GenericTypeArguments.Length != 0)
                        {
                            writer.Break();
                            writer.Write("// instance of generic definition ");
                            TypeLink(writer, type.GetGenericTypeDefinition(), type.Name);
                        }

                        if (type.IsClass || type.IsValueType)
                        {
                            InspectClass(writer, type);
                        }
                        else if (type.IsInterface)
                        {
                            InspectInterface(writer, type);
                        }
                        else if (type.IsEnum)
                        {
                            InspectEnum(writer, type);
                        }
                    }
                    outerClass.Dispose();
                }
        }
        private void InspectClass(HtmlWriter writer, Type type)
        {
            var instanceCtors = type.GetConstructors(k_AllInstanceBindings);

            Array.Sort(instanceCtors, (lhs, rhs) => ReflectionHelper.CompareConstructors(type, lhs, rhs));
            if (instanceCtors.Length > 0)
            {
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Constructors");
                    LayoutCtors(writer, instanceCtors);
                }
            }

            var staticCtor = type.GetConstructors(k_AllStaticBindings);

            if (staticCtor.Length > 0)
            {
                Array.Sort(staticCtor, (lhs, rhs) => ReflectionHelper.CompareConstructors(type, lhs, rhs));
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Static constructors");
                    LayoutCtors(writer, staticCtor);
                }
            }

            LayoutInstanceFields(writer, type);

            var staticFields = type.GetFields(k_AllStaticBindings);

            if (staticFields.Length > 0)
            {
                Array.Sort(staticFields, (lhs, rhs) => ReflectionHelper.CompareFields(type, lhs, rhs));
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Static fields");
                    LayoutStaticFields(writer, staticFields);
                }
            }

            LayoutInstanceProperties(writer, type);

            var staticProperties = type.GetProperties(k_AllStaticBindings);

            if (staticProperties.Length > 0)
            {
                Array.Sort(staticProperties, (lhs, rhs) => ReflectionHelper.CompareProperties(type, lhs, rhs));
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "Static properties");
                    LayoutProperties(writer, staticProperties);
                }
            }

            LayoutInstanceMethods(writer, type);

            var staticMethods = type.GetMethods(k_AllStaticBindings);

            if (staticMethods.Length > 0)
            {
                Array.Sort(staticMethods, (lhs, rhs) => ReflectionHelper.CompareMethods(type, lhs, rhs));
                using (writer.ContainerFluid())
                {
                    writer.Inline("h6", "// Static functions");
                    LayoutMethods(writer, staticMethods.Where(m => !m.IsSpecialName));
                }
            }

            LayoutNestedTypes(writer, type);
        }