Esempio n. 1
0
        private void DisassembleAndWrite(ClrMethod method, ArchitectureMode architecture, Translator translator, ref ulong methodAddressRef, TextWriter writer)
        {
            writer.WriteLine(method.GetFullSignature());
            var info = FindNonEmptyHotColdInfo(method);

            if (info == null)
            {
                writer.WriteLine("    ; Unable to load method data (not JITted?)");
                return;
            }
            var methodAddress = info.HotStart;

            methodAddressRef = methodAddress;
            using (var disasm = new Disassembler(new IntPtr(unchecked ((long)methodAddress)), (int)info.HotSize, architecture, methodAddress))
            {
                foreach (var instruction in disasm.Disassemble())
                {
                    writer.Write(String.Format("0x{0:X8}`{1:X8}:", (instruction.Offset >> 32) & 0xFFFFFFFF, instruction.Offset & 0xFFFFFFFF));
                    writer.Write("    L");
                    writer.Write((instruction.Offset - methodAddress).ToString("x4"));
                    writer.Write(": ");
                    writer.WriteLine(translator.Translate(instruction));
                }
            }
        }
Esempio n. 2
0
        private HotColdRegions FindNonEmptyHotColdInfo(ClrMethod method)
        {
            // I can't really explain this, but it seems that some methods
            // are present multiple times in the same type -- one compiled
            // and one not compiled. A bug in clrmd?
            if (method.HotColdInfo.HotSize > 0)
            {
                return(method.HotColdInfo);
            }

            if (method.Type == null)
            {
                return(null);
            }

            var methodSignature = method.GetFullSignature();

            foreach (var other in method.Type.Methods)
            {
                if (other.MetadataToken == method.MetadataToken && other.GetFullSignature() == methodSignature && other.HotColdInfo.HotSize > 0)
                {
                    return(other.HotColdInfo);
                }
            }

            return(null);
        }
Esempio n. 3
0
        private void DisassembleAndWrite(ClrMethod method, string message, ArchitectureMode architecture, Translator translator, Reference <ulong> methodAddressRef, TextWriter writer)
        {
            writer.WriteLine(method.GetFullSignature());
            if (message != null)
            {
                writer.Write("    ; ");
                writer.WriteLine(message);
                return;
            }

            var info = FindNonEmptyHotColdInfo(method);

            if (info == null)
            {
                writer.WriteLine("    ; Failed to find HotColdInfo — please report at https://github.com/ashmind/TryRoslyn/issues.");
                return;
            }

            var methodAddress = info.HotStart;

            methodAddressRef.Value = methodAddress;
            using (var disasm = new Disassembler(new IntPtr(unchecked ((long)methodAddress)), (int)info.HotSize, architecture, methodAddress)) {
                foreach (var instruction in disasm.Disassemble())
                {
                    writer.Write("    L");
                    writer.Write((instruction.Offset - methodAddress).ToString("x4"));
                    writer.Write(": ");
                    writer.WriteLine(translator.Translate(instruction));
                }
            }
        }
Esempio n. 4
0
        public void CompleteSignatureIsRetrievedForMethodsWithGenericParameters()
        {
            using DataTarget dt = TestTargets.AppDomains.LoadFullDump();
            ClrRuntime runtime = dt.ClrVersions.Single().CreateRuntime();

            ClrModule module = runtime.GetModule("sharedlibrary.dll");
            ClrType   type   = module.GetTypeByName("Foo");

            ClrMethod genericMethod = type.GetMethod("GenericBar");

            string methodName = genericMethod.GetFullSignature();

            Assert.Equal(')', methodName.Last());
        }
        private string GetCalledMethodFromAssemblyOutput(ClrRuntime runtime, string assemblyString)
        {
            string hexAddressText   = "";
            var    callLocation     = assemblyString.LastIndexOf("call");
            var    qwordPtrLocation = assemblyString.IndexOf("qword ptr");
            var    openBracket      = assemblyString.IndexOf('(');
            var    closeBracket     = assemblyString.IndexOf(')');

            if (openBracket != -1 && closeBracket != -1 && closeBracket > openBracket)
            {
                // 000007fe`979171fb e800261b5e      call    mscorlib_ni+0x499800 (000007fe`f5ac9800)
                hexAddressText = assemblyString.Substring(openBracket, closeBracket - openBracket)
                                 .Replace("(", "")
                                 .Replace(")", "")
                                 .Replace("`", "");
            }
            else if (callLocation != -1 && qwordPtrLocation != -1)
            {
                // TODO have to also deal with:
                // 000007fe`979f666f 41ff13          call    qword ptr [r11] ds:000007fe`978e0050=000007fe978ed260
            }
            else if (callLocation != -1)
            {
                // 000007fe`979e6721 e8e2b5ffff      call    000007fe`979e1d08
                var endOfCallLocation = callLocation + 4;
                hexAddressText = assemblyString.Substring(endOfCallLocation, assemblyString.Length - endOfCallLocation)
                                 .Replace("`", "")
                                 .Trim(' ');
            }

            ulong actualAddress;

            if (ulong.TryParse(hexAddressText, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out actualAddress))
            {
                ClrMethod method = runtime.GetMethodByAddress(actualAddress);
                if (method != null)
                {
                    return($"Call: {method.GetFullSignature()}");
                }
                else
                {
                    return($"Call: {actualAddress:x16} -> No matching method found");
                }
            }

            return($"\"{hexAddressText}\" -> Not a valid hex value");
        }
Esempio n. 6
0
        private string BuildTimerCallbackMethodName(ClrRuntime runtime, ulong timerCallbackRef, string methodPtrString)
        {
            var heap      = runtime.Heap;
            var methodPtr = GetFieldValue(heap, timerCallbackRef, methodPtrString);

            if (methodPtr != null)
            {
                ClrMethod method = runtime.GetMethodByAddress((ulong)(long)methodPtr);
                if (method != null)
                {
                    // look for "this" to figure out the real callback implementor type
                    string thisTypeName = "?";
                    var    thisPtr      = GetFieldValue(heap, timerCallbackRef, "_target");
                    if ((thisPtr != null) && ((ulong)thisPtr) != 0)
                    {
                        ulong thisRef  = (ulong)thisPtr;
                        var   thisType = heap.GetObjectType(thisRef);
                        if (thisType != null)
                        {
                            thisTypeName = thisType.Name;
                        }
                    }
                    else
                    {
                        thisTypeName = (method.Type != null) ? method.Type.Name : "?";
                    }
                    return(method.GetFullSignature());

                    return(string.Format("{0}.{1}", thisTypeName, method.Name));
                }
                else
                {
                    return("");
                }
            }
            else
            {
                return("");
            }
        }
        private void DisassembleAndWrite(ClrMethod method, Remote.MethodJitStatus status, ArchitectureMode architecture, Translator translator, Reference <ulong> methodAddressRef, TextWriter writer)
        {
            writer.WriteLine(method.GetFullSignature());
            switch (status)
            {
            case Remote.MethodJitStatus.GenericOpenNoAttribute:
                writer.WriteLine("    ; Open generics cannot be JIT-compiled.");
                writer.WriteLine("    ; However you can use attribute SharpLab.Runtime.JitGeneric to specify argument types.");
                writer.WriteLine("    ; Example: [JitGeneric(typeof(int)), JitGeneric(typeof(string))] void M<T>() { ... }.");
                return;
            }

            var info = FindNonEmptyHotColdInfo(method);

            if (info == null)
            {
                if (status == Remote.MethodJitStatus.GenericSuccess)
                {
                    writer.WriteLine("    ; Failed to find HotColdInfo for generic method (reference types?).");
                    writer.WriteLine("    ; If you know a solution, please comment at https://github.com/ashmind/SharpLab/issues/99.");
                    return;
                }
                writer.WriteLine("    ; Failed to find HotColdInfo — please report at https://github.com/ashmind/SharpLab/issues.");
                return;
            }

            var methodAddress = info.HotStart;

            methodAddressRef.Value = methodAddress;
            using (var disasm = new Disassembler(new IntPtr(unchecked ((long)methodAddress)), (int)info.HotSize, architecture, methodAddress)) {
                foreach (var instruction in disasm.Disassemble())
                {
                    writer.Write("    L");
                    writer.Write((instruction.Offset - methodAddress).ToString("x4"));
                    writer.Write(": ");
                    writer.WriteLine(translator.Translate(instruction));
                }
            }
        }
Esempio n. 8
0
        private void DisassembleAndWrite(ClrMethod method, string message, Translator translator, Reference <ulong> methodAddressRef, TextWriter writer)
        {
            writer.WriteLine(method.GetFullSignature());
            if (message != null)
            {
                writer.Write("    ; ");
                writer.WriteLine(message);
                return;
            }

            var methodAddress = method.HotColdInfo.HotStart;

            if (methodAddress == 0)
            {
                writer.WriteLine("    ; Method HotStart is 0, not sure why yet.");
                writer.WriteLine("    ; See https://github.com/ashmind/TryRoslyn/issues/82.");
                return;
            }

            var hotSize = method.HotColdInfo.HotSize;

            if (hotSize == 0)
            {
                writer.WriteLine("    ; Method HotSize is 0, not sure why yet.");
                writer.WriteLine("    ; See https://github.com/ashmind/TryRoslyn/issues/82.");
                return;
            }

            methodAddressRef.Value = methodAddress;
            using (var disasm = new Disassembler(new IntPtr(unchecked ((long)methodAddress)), (int)hotSize, ArchitectureMode.x86_64, methodAddress)) {
                foreach (var instruction in disasm.Disassemble())
                {
                    writer.Write("    L{0:x4}: ", instruction.Offset - methodAddress);
                    writer.WriteLine(translator.Translate(instruction));
                }
            }
        }
Esempio n. 9
0
 static DisassembledMethod CreateEmpty(ClrMethod method, string reason)
 => DisassembledMethod.Empty(method.GetFullSignature(), method.NativeCode, reason);
Esempio n. 10
0
        static string TryEnqueueCalledMethod(string textRepresentation, State state, int depth, ClrMethod currentMethod)
        {
            if (!TryGetHexAdress(textRepresentation, out ulong address))
            {
                return(null); // call    qword ptr [rax+20h] // needs further research
            }
            var method = state.Runtime.GetMethodByAddress(address);

            if (method == null) // not managed method
            {
                return(DisassemblerConstants.NotManagedMethod);
            }

            if (method.NativeCode == currentMethod.NativeCode && method.GetFullSignature() == currentMethod.GetFullSignature())
            {
                return(null); // in case of call which is just a jump within the method
            }
            if (!state.HandledMethods.Contains(new MethodId(method.MetadataToken, method.Type.MetadataToken)))
            {
                state.Todo.Enqueue(new MethodInfo(method, depth + 1));
            }

            return(method.GetFullSignature());
        }
Esempio n. 11
0
        private void DisassembleMethod(ClrMethod method)
        {
            var    module   = method.Type.Module;
            string fileName = module.FileName;

            AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName);
            TypeDefinition     type     = assembly.MainModule.GetType(method.Type.Name);

            MethodDefinition methodDef = type.Methods.Single(
                m => m.MetadataToken.ToUInt32() == method.MetadataToken);

            _context.WriteLine("{0}", method.GetFullSignature());

            if (method.ILOffsetMap == null)
            {
                return;
            }

            var mapByOffset = (from map in method.ILOffsetMap
                               where map.ILOffset != -2
                               where map.StartAddress <= map.EndAddress
                               orderby map.ILOffset
                               select map).ToArray();

            if (mapByOffset.Length == 0)
            {
                // The method doesn't have an offset map. Just print the whole thing.
                PrintInstructions(methodDef.Body.Instructions);
            }

            // This is the prologue, looks like it's always there, but it could
            // also be the only thing that's in the method
            DisassembleNative(method.ILOffsetMap.Single(e => e.ILOffset == -2));

            for (int i = 0; i < mapByOffset.Length; ++i)
            {
                var map = mapByOffset[i];
                IEnumerable <Instruction> instructions;
                if (i == mapByOffset.Length - 1)
                {
                    instructions = methodDef.Body.Instructions.Where(
                        instr => instr.Offset >= map.ILOffset);
                }
                else
                {
                    instructions = methodDef.Body.Instructions.Where(
                        instr => instr.Offset >= map.ILOffset &&
                        instr.Offset < mapByOffset[i + 1].ILOffset);
                }

                // The GetSourceInformation method doesn't attempt to load symbols.
                if (!module.IsPdbLoaded)
                {
                    string pdb = module.TryDownloadPdb(null);
                    if (pdb != null)
                    {
                        module.LoadPdb(pdb);
                    }
                }
                var sourceLocation = module.GetSourceInformation(method, map.ILOffset);
                if (sourceLocation != null)
                {
                    _context.WriteLine("{0} {1}-{2}:{3}-{4}", sourceLocation.FilePath,
                                       sourceLocation.LineNumber, sourceLocation.LineNumberEnd,
                                       sourceLocation.ColStart, sourceLocation.ColEnd);
                    for (int line = sourceLocation.LineNumber; line <= sourceLocation.LineNumberEnd; ++line)
                    {
                        _context.WriteLine(ReadSourceLine(sourceLocation.FilePath, line));
                        _context.WriteLine(new string(' ', sourceLocation.ColStart - 1) + new string('^', sourceLocation.ColEnd - sourceLocation.ColStart));
                    }
                }
                PrintInstructions(instructions);
                DisassembleNative(map);
            }

            // TODO We are still not printing the epilogue while sosex does
        }
        private static void TryTranslateAddressToName(Instruction instruction, State state, int depth, ClrMethod currentMethod)
        {
            var runtime = state.Runtime;

            if (!TryGetReferencedAddress(instruction, (uint)runtime.PointerSize, out ulong address))
            {
                return;
            }

            if (state.AddressToNameMapping.ContainsKey(address))
            {
                return;
            }

            var jitHelperFunctionName = runtime.GetJitHelperFunctionName(address);

            if (!string.IsNullOrEmpty(jitHelperFunctionName))
            {
                state.AddressToNameMapping.Add(address, jitHelperFunctionName);
                return;
            }

            var methodTableName = runtime.GetMethodTableName(address);

            if (!string.IsNullOrEmpty(methodTableName))
            {
                state.AddressToNameMapping.Add(address, $"MT_{methodTableName}");
                return;
            }

            var methodDescriptor = runtime.GetMethodByHandle(address);

            if (!(methodDescriptor is null))
            {
                state.AddressToNameMapping.Add(address, $"MD_{methodDescriptor.GetFullSignature()}");
                return;
            }

            var method = runtime.GetMethodByAddress(address);

            if (method is null && (address & ((uint)runtime.PointerSize - 1)) == 0)
            {
                if (runtime.ReadPointer(address, out ulong newAddress) && newAddress > ushort.MaxValue)
                {
                    method = runtime.GetMethodByAddress(newAddress);
                }
            }

            if (method is null)
            {
                return;
            }

            if (method.NativeCode == currentMethod.NativeCode && method.GetFullSignature() == currentMethod.GetFullSignature())
            {
                return; // in case of a call which is just a jump within the method or a recursive call
            }
            if (!state.HandledMethods.Contains(method))
            {
                state.Todo.Enqueue(new MethodInfo(method, depth + 1));
            }

            var methodName = method.GetFullSignature();

            if (!methodName.Any(c => c == '.')) // the method name does not contain namespace and type name
            {
                methodName = $"{method.Type.Name}.{method.GetFullSignature()}";
            }
            state.AddressToNameMapping.Add(address, methodName);
        }
Esempio n. 13
0
        private void DisassembleMethod(ClrMethod method)
        {
            var    module   = method.Type.Module;
            string fileName = module.FileName;

            AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName);
            TypeDefinition     type     = assembly.MainModule.GetType(method.Type.Name);

            MethodDefinition methodDef = type.Methods.Single(
                m => m.MetadataToken.ToUInt32() == method.MetadataToken);

            _context.WriteLine("{0}", method.GetFullSignature());

            if (method.ILOffsetMap == null)
            {
                return;
            }

            var mapByOffset = (from map in method.ILOffsetMap
                               where map.ILOffset >= 0 // prolog is -2, epilog -3
                               where map.StartAddress <= map.EndAddress
                               orderby map.ILOffset
                               select map).ToArray();

            if (mapByOffset.Length == 0)
            {
                // The method doesn't have an offset map. Just print the whole thing.
                PrintInstructions(methodDef.Body.Instructions);
            }

            // This is the prologue, looks like it's always there, but it could
            // also be the only thing that's in the method
            var prologue = method.ILOffsetMap[0];

            if (prologue.ILOffset == -2) // -2 is a magic number for prologue
            {
                DisassembleNative(prologue);
            }

            for (int i = 0; i < mapByOffset.Length; ++i)
            {
                var map = mapByOffset[i];
                IEnumerable <Instruction> instructions;
                if (i == mapByOffset.Length - 1)
                {
                    instructions = methodDef.Body.Instructions.Where(
                        instr => instr.Offset >= map.ILOffset);
                }
                else
                {
                    instructions = methodDef.Body.Instructions.Where(
                        instr => instr.Offset >= map.ILOffset &&
                        instr.Offset < mapByOffset[i + 1].ILOffset);
                }

                var sourceLocation = method.GetSourceLocation(map.ILOffset);
                if (sourceLocation != null)
                {
                    _context.WriteLine("{0} {1}-{2}:{3}-{4}", sourceLocation.FilePath,
                                       sourceLocation.LineNumber, sourceLocation.LineNumberEnd,
                                       sourceLocation.ColStart, sourceLocation.ColEnd);
                    for (int line = sourceLocation.LineNumber; line <= sourceLocation.LineNumberEnd; ++line)
                    {
                        var sourceLine = ReadSourceLine(sourceLocation.FilePath, line);

                        if (sourceLine != null)
                        {
                            _context.WriteLine(sourceLine);
                            _context.WriteLine(new string(' ', sourceLocation.ColStart - 1) + new string('^', sourceLocation.ColEnd - sourceLocation.ColStart));
                        }
                    }
                }
                PrintInstructions(instructions);
                DisassembleNative(map);
            }

            var epilogue = method.ILOffsetMap[method.ILOffsetMap.Length - 1];

            if (epilogue.ILOffset == -3) // -3 is a magic number for epilog
            {
                DisassembleNative(epilogue);
            }
        }