private void LayoutProperties(HtmlWriter writer, IEnumerable <PropertyInfo> properties) { MakeTable( writer, properties, p => WriteTypeName(writer, p.PropertyType), p => { writer.Write(p.Name); writer.Write(" { "); if (p.CanRead) { var getter = p.GetGetMethod(nonPublic: true); WriteMethodPrefix(writer, getter); writer.Write(" "); FunctionLink(writer, getter, "get"); writer.Write("; "); } if (p.CanWrite) { var setter = p.GetSetMethod(nonPublic: true); WriteMethodPrefix(writer, setter); writer.Write(" "); FunctionLink(writer, setter, "set"); writer.Write(";"); } writer.Write(" } "); }, p => WriteAttributes(writer, p.GetCustomAttributes(true), false) ); }
private void LayoutProperties(HtmlWriter writer, IEnumerable <PropertyInfo> properties) { MakeCodeListWithoutSemicolon( writer, properties, p => WriteInlineAttributes(writer, p.GetCustomAttributes(false)), p => WriteTypeName(writer, p.PropertyType), p => { writer.Write(p.Name); writer.Write(" { "); if (p.CanRead) { var getter = p.GetGetMethod(nonPublic: true); WriteMethodPrefix(writer, getter); writer.Write(" "); MethodLink(writer, getter, "get"); writer.Write("; "); } if (p.CanWrite) { var setter = p.GetSetMethod(nonPublic: true); WriteMethodPrefix(writer, setter); writer.Write(" "); MethodLink(writer, setter, "set"); writer.Write(";"); } writer.Write(" } "); } ); }
private void InspectNamespace(HtmlWriter writer, string assemblyName, string namespaceName) { var asm = _explorer.FindAssembly(assemblyName); if (asm == null) { writer.Write("Unknown assembly name " + assemblyName); return; } var ns = asm.FindNamespace(namespaceName); if (asm == null) { writer.Write("Unknown namespace name " + namespaceName); return; } InspectNamespace(writer, ns); }
private void InspectType(HtmlWriter writer, string assemblyName, string typeName) { var asm = _explorer.FindAssembly(assemblyName); if (asm == null) { writer.Write("Unknown assembly name " + assemblyName); return; } var type = asm.FindType(typeName); if (type == null) { writer.Write("Unknown type name " + typeName + " in " + asm.FullName); return; } InspectType(writer, asm, type); }
private void WriteCallInstruction(HtmlWriter writer, Instruction inst, ref MethodContext context) { // we should be able to find the call targets for R11/relative immediate ulong callTarget = GetBranchTarget(inst, context.R11?.LvalUQWord ?? 0); StartNote(writer, ref context); if (callTarget != 0) { var target = Mono.GetJitInfoAnyDomain((IntPtr)callTarget, out _); if (target.Method != null) { if (target.Method.IsConstructor) { WriteCtorPrefix(writer, target.Method); writer.Write(" "); WriteCtorDeclaration(writer, target.Method as ConstructorInfo); } else if (target.Method != null) { WriteMethodPrefix(writer, target.Method); writer.Write(" "); WriteMethodReturnType(writer, target.Method as MethodInfo); writer.Write(" "); if (target.Method.DeclaringType != null) { TypeLink(writer, target.Method.DeclaringType); writer.Write("."); } WriteMethodDeclaration(writer, target.Method as MethodInfo); } } else { writer.Write("unknown target @ " + callTarget.ToString("X16")); } } else if (context.DebugEnabled) { var r11 = context.R11; ud_type stackFrameRegister = context.HasBasePointer ? ud_type.UD_R_RBP : ud_type.UD_R_RSP; if (r11 != null && r11.Base == stackFrameRegister && r11.Type == ud_type.UD_OP_MEM && r11.Value == context.SinglestepTrampolineOffset) { writer.Write("check for singlestep"); return; } writer.Write("unknown target; native, virtual, or unpatched JIT trampoline"); } else { writer.Write("unknown target; native, virtual, or unpatched JIT trampoline"); } }
private void InspectCtor(HtmlWriter writer, Assembly assembly, Type type, ConstructorInfo ctor) { LayoutMethodHeader(writer, assembly, type, ctor); using (writer.Tag("h2")) { WriteCtorPrefix(writer, ctor); writer.Write(" "); WriteCtorDeclaration(writer, ctor); } WriteDissassembly(writer, ctor); }
private void InspectAssembly(HtmlWriter writer, string assemblyName) { var asm = m_Explorer.FindAssembly(assemblyName); if (asm == null) { writer.Write("Unknown assembly name " + assemblyName); return; } InspectAssembly(writer, asm); }
private void WriteShortTypeDeclaration(HtmlWriter writer, Type type) { if (type.IsEnum) { writer.Write("enum "); } else if (type.IsInterface) { writer.Write("interface "); } else if (type.IsValueType) { writer.Write("struct "); } else if (type.IsClass) { writer.Write("class "); } TypeLink(writer, type, type.Name); }
private void WriteJumpInstruction(HtmlWriter writer, Instruction inst, ulong r11) { ulong callTarget = GetBranchTarget(inst, r11); if (callTarget == 0) { return; } writer.Write(" ; "); writer.AHref("go to target", "#X" + callTarget.ToString("X16")); }
private void WriteMethodReturnType(HtmlWriter writer, MethodInfo m) { if (m.ReturnType.IsByRef) { writer.Write("ref "); WriteTypeName(writer, m.ReturnType.GetElementType()); } else { WriteTypeName(writer, m.ReturnType); } }
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); } }
private void WriteGenericArguments(HtmlWriter writer, Type[] types, TypeExt.NameMode mode = TypeExt.NameMode.Short) { writer.Write("< "); for (int i = 0; i < types.Length; i++) { if (i > 0) { writer.Write(", "); } if (types[i].IsGenericParameter) { var gpa = types[i].GenericParameterAttributes; if ((gpa & GenericParameterAttributes.Covariant) != 0) { writer.Write("out "); } else if ((gpa & GenericParameterAttributes.Contravariant) != 0) { writer.Write("in "); } writer.Write(types[i].Name); } else { TypeLink(writer, types[i], types[i].PrettyName(mode)); } } writer.Write(" >"); }
private void LayoutStaticFields(HtmlWriter writer, IEnumerable <FieldInfo> fields) { MakeTable( writer, fields, f => { writer.Write(f.GetAccessModifier().Pretty()); if (f.IsLiteral) { writer.Write(" const"); } else if (f.IsStatic) { writer.Write(" static"); } else if (f.IsInitOnly) { writer.Write(" readonly"); } }, f => WriteTypeName(writer, f.FieldType), f => writer.Write(f.Name), f => writer.Write(f.GetValue(null).ToString()), f => WriteAttributes(writer, f.GetCustomAttributes(true), false) ); }
private void LayoutFields(HtmlWriter writer, IEnumerable <FieldInfo> fields) { MakeTable( writer, fields, f => { writer.Write(f.GetAccessModifier().Pretty()); if (f.IsLiteral) { writer.Write(" const"); } else if (f.IsStatic) { writer.Write(" static"); } else if (f.IsInitOnly) { writer.Write(" readonly"); } }, f => { if (f.FieldType.IsByRef) { writer.Write("ref "); WriteTypeName(writer, f.FieldType.GetElementType()); } else { WriteTypeName(writer, f.FieldType); } }, f => writer.Write(f.Name), f => WriteAttributes(writer, f.GetCustomAttributes(true), false) ); }
private void WriteMethodDeclaration(HtmlWriter writer, MethodInfo m, bool noLink = false) { if (noLink) { writer.Write(m.Name); } else { MethodLink(writer, m, m.Name); } if (m.IsGenericMethodDefinition) { WriteGenericArguments(writer, m.GetGenericArguments(), TypeExt.NameMode.Short, noLink); } writer.Write("("); var ps = m.GetParameters(); for (int i = 0; i < ps.Length; i++) { if (i > 0) { writer.Write(", "); } WriteParameter(writer, ps[i], noLink); } writer.Write(")"); if (m.IsGenericMethodDefinition) { var args = m.GetGenericArguments(); for (int i = 0; i < args.Length; i++) { WriteGenericConstraints(writer, args[i], noLink); } } }
private void InspectDomain(HtmlWriter writer) { writer.Inline("h2", "Domain: " + AppDomain.CurrentDomain.FriendlyName); var assemblies = _explorer.Assemblies.ToArray(); Array.Sort(assemblies, (lhs, rhs) => lhs.FullName.CompareTo(rhs.FullName)); MakeTable( writer, assemblies, a => AssemblyLink(writer, a), a => writer.Write(a.FullName) ); }
private void LayoutMethodHeader(HtmlWriter writer, Assembly asm, Type type, MethodBase method) { using (writer.Tag("small")) { DomainLink(writer); writer.Write(" | "); AssemblyLink(writer, asm); writer.Write(" | "); NamespaceLink(writer, asm.FindNamespace(type.Namespace), type.Namespace ?? "<root>"); writer.Write(" | "); TypeLink(writer, type); writer.Break(); writer.Break(); } var attr = method.GetCustomAttributes(false); if (attr.Length > 0) { writer.Break(); WriteAttributes(writer, attr); } }
private void WriteParameter(HtmlWriter writer, ParameterInfo p) { var pt = p.ParameterType; if (p.IsIn) { writer.Write("in "); } if (p.IsOut) { writer.Write("out "); } else if (p.ParameterType.IsByRef) { if (!p.IsOut && !p.IsIn) { writer.Write("ref "); } pt = p.ParameterType.GetElementType(); } WriteTypeName(writer, pt); writer.Write(" "); writer.Write(p.Name); }
static void MakeCodeListWithoutSemicolon <T>(HtmlWriter writer, IEnumerable <T> ts, params Action <T>[] inner) { foreach (var t in ts) { bool first = true; foreach (var cell in inner) { if (!first) { writer.Write(" "); } cell(t); first = false; } writer.Break(); } }
private void WriteCtorDeclaration(HtmlWriter writer, ConstructorInfo c, bool noLink = false) { if (noLink) { writer.Write(c.DeclaringType.Name); writer.Write("."); writer.Write(c.Name); } else { TypeLink(writer, c.DeclaringType, c.DeclaringType.Name); writer.Write("."); MethodLink(writer, c, c.Name); } if (c.IsGenericMethodDefinition) { WriteGenericArguments(writer, c.GetGenericArguments(), TypeExt.NameMode.Short, noLink); } writer.Write("("); var ps = c.GetParameters(); for (int i = 0; i < ps.Length; i++) { if (i > 0) { writer.Write(", "); } WriteParameter(writer, ps[i], noLink); } writer.Write(")"); if (c.IsGenericMethodDefinition) { var args = c.GetGenericArguments(); for (int i = 0; i < args.Length; i++) { WriteGenericConstraints(writer, args[i], noLink); } } }
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) ); } } }
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 static void WriteStyle(HtmlWriter writer) { using (writer.Tag("style")) { writer.Write( @"table { font-family: arial, sans-serif; border-collapse: collapse; width: 100%; } td, th { border: 1px solid #dddddd; text-align: left; padding: 8px; } tr:nth-child(even) { background-color: #dddddd; }" ); } }
private void WriteCallInstruction(HtmlWriter writer, Instruction inst, ulong r11) { // we should be able to find the call targets for R11/relative immediate ulong callTarget = GetBranchTarget(inst, r11); writer.Write(" ; "); if (callTarget != 0) { var target = Mono.GetJitInfo((IntPtr)callTarget); if (target.Method != null) { if (target.Method.IsConstructor) { WriteCtorPrefix(writer, target.Method); writer.Write(" "); WriteCtorDeclaration(writer, target.Method as ConstructorInfo); } else if (target.Method != null) { WriteMethodPrefix(writer, target.Method); writer.Write(" "); WriteMethodReturnType(writer, target.Method as MethodInfo); writer.Write(" "); if (target.Method.DeclaringType != null) { TypeLink(writer, target.Method.DeclaringType); writer.Write("."); } WriteMethodDeclaration(writer, target.Method as MethodInfo); } } else { writer.Write("unknown target @ " + callTarget.ToString("X16")); } } else { writer.Write("unsupported call, probably virtual"); } }
private void WriteMethodPrefix(HtmlWriter writer, MethodBase method) { writer.Write(method.GetAccessModifier().Pretty()); if ((method.GetMethodImplementationFlags() & MethodImplAttributes.InternalCall) != 0) { writer.Write(" extern"); } else if (method.IsAbstract) { writer.Write(" abstract"); } else if (method.IsFinal) { writer.Write(" sealed"); } else if (method.IsVirtual) { writer.Write(" virtual"); } else if (method.IsStatic) { writer.Write(" static"); } }
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(); }
void WriteAttributes(HtmlWriter writer, object[] attributes, bool stacked = true) { using (writer.Tag("code")) { if (attributes.Length == 0) { return; } if (!stacked) { writer.Write("["); } for (int i = 0; i < attributes.Length; i++) { if (stacked) { writer.Write("["); } else if (i > 0) { writer.Write(", "); } var type = attributes[i].GetType(); TypeLink(writer, type); var properties = type.GetProperties(k_AllInstanceBindings); if (properties.Length > 0) { bool first = true; for (int j = 0; j < properties.Length; j++) { var prop = properties[j]; if (!prop.CanRead || prop.GetIndexParameters().Length > 0 || prop.Name == "TypeId") { continue; } if (!first) { writer.Write(", "); } else { writer.Write("("); } first = false; writer.Write(prop.Name); writer.Write(" = "); var value = prop.GetValue(attributes[i], null); if (value == null) { writer.Write("null"); } else if (value is string) { writer.Write("\""); writer.Write((value as string)); writer.Write("\""); } else { writer.Write(value.ToString()); } } if (!first) { writer.Write(")"); } } if (stacked) { writer.Write("]"); writer.Break(); } } if (!stacked) { writer.Write("]"); } } }
private void WriteDissassembly(HtmlWriter writer, MethodBase method) { if (method.IsAbstract || method.ContainsGenericParameters) { writer.Write("Cannot display disassembly for generic or abstract methods."); return; } var jitInfo = Mono.GetJitInfo(method); writer.Write("Address: "); writer.Write(jitInfo.CodeStart.ToString("X16")); writer.Break(); writer.Write("Code Size in Bytes: "); writer.Write(jitInfo.CodeSize.ToString()); 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; Instruction lastInstruction = null; ulong r11Register = 0; lock (_disassemblerLock) { foreach (var inst in GetInstructions(jitInfo)) { // abbreviate excessive nopping if (inst.Mnemonic == ud_mnemonic_code.UD_Inop) { nops++; lastInstruction = inst; continue; } if (nops > 0) { if (nops == 1) { writer.Write(lastInstruction.ToString()); } else { writer.Write("nop ("); writer.Write(nops.ToString()); writer.Write(" bytes)"); } nops = 0; writer.Write("\n"); } lastInstruction = inst; using (writer.Tag("span").With("id", "X" + Address(inst).ToString("X16"))) { writer.Write(inst.ToString()); if (inst.Mnemonic == ud_mnemonic_code.UD_Imov) { var op0 = inst.Operands[0]; // call targets on x64 are frequently placed in R11, so let's ensure that we catch that. if (op0.Type == ud_type.UD_OP_REG && op0.Base == ud_type.UD_R_R11) { r11Register = inst.Operands[1].LvalUQWord; } } else if (inst.Mnemonic == ud_mnemonic_code.UD_Icall) { WriteCallInstruction(writer, inst, r11Register); r11Register = 0; } else if (IsJump(inst.Mnemonic)) { WriteJumpInstruction(writer, inst, r11Register); } } writer.Write("\n"); } } } } }
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"); } } } } }
private void WriteCtorPrefix(HtmlWriter writer, MethodBase c) { writer.Write(c.GetAccessModifier().Pretty()); }