internal static void SetupInliningAttributes( IRContext context, Method method, DisassembledMethod disassembledMethod) { // Check whether we are allowed to inline this method if (context.HasFlags(ContextFlags.NoInlining) || !method.HasImplementation) { return; } if (method.HasSource) { var source = method.Source; if ((source.MethodImplementationFlags & MethodImplAttributes.NoInlining) == MethodImplAttributes.NoInlining) { return; } if ((source.MethodImplementationFlags & MethodImplAttributes.AggressiveInlining) == MethodImplAttributes.AggressiveInlining || source.Module.Name == Context.FullAssemblyModuleName) { method.AddFlags(MethodFlags.Inline); } } // Evaluate a simple inlining heuristic if (context.HasFlags(ContextFlags.AggressiveInlining) || disassembledMethod.Instructions.Length <= MaxNumILInstructionsToInline) { method.AddFlags(MethodFlags.Inline); } }
public JavaDebugDisassemblyStream(JavaDebugCodeContext executionContext) { Contract.Requires <ArgumentNullException>(executionContext != null, "executionContext"); _executionContext = executionContext; _bytecode = _executionContext.Location.GetMethod().GetBytecodes(); _disassembledMethod = BytecodeDisassembler.Disassemble(_bytecode); var constantPool = executionContext.Location.GetDeclaringType().GetConstantPool(); var exceptionTable = executionContext.Location.GetMethod().GetExceptionTable(); _evaluationStackDepths = BytecodeDisassembler.GetEvaluationStackDepths(_disassembledMethod, constantPool, exceptionTable); }
public void CallInsideMethodCanBePrettifiedToo() { var method = new DisassembledMethod { Maps = new[] { new Map { Instructions = new Diagnosers.Code[] { new Asm { TextRepresentation = "00007ffe`2f9bd341 e828000000 call 00007ffe`2f9bd36e" }, new Asm { TextRepresentation = "00007ffe`2f9bd346 90 nop" }, new Asm { TextRepresentation = "00007ffe`2f9bd36c 5d pop rbp" }, new Asm { TextRepresentation = "00007ffe`2f9bd36d c3 ret" }, new Asm { TextRepresentation = "00007ffe`2f9bd36e 55 push rbp" } } } }, Name = "Test" }; var expectedOutput = new[] { "call M00_L00", "nop", "pop rbp", "ret", "M00_L00", "push rbp" }; var prettyOutput = DisassemblyPrettifier.Prettify(method, "M00"); for (int i = 0; i < expectedOutput.Length; i++) { Assert.Equal(expectedOutput[i], prettyOutput[i].TextRepresentation); } }
private void Disassemble(CompilationContext compilationContext) { Debug.Assert(compilationContext != null, "Invalid compilation context"); if (DisassembledMethod != null) { return; } DisassembledMethod = DisassembledMethod.Disassemble( MethodBase, compilationContext.NotSupportedILInstructionHandler, compilationContext.CurrentSequencePointEnumerator); if (DisassembledMethod.Method.GetMethodBody().ExceptionHandlingClauses.Count > 0) { throw compilationContext.GetNotSupportedException( ErrorMessages.CustomExceptionSemantics, MethodBase.Name); } }
public JavaDebugDisassemblyStream(JavaDebugCodeContext executionContext) { Contract.Requires <ArgumentNullException>(executionContext != null, "executionContext"); _executionContext = executionContext; _bytecode = _executionContext.Location.GetMethod().GetBytecodes(); _disassembledMethod = BytecodeDisassembler.Disassemble(_bytecode); var constantPool = executionContext.Location.GetDeclaringType().GetConstantPool(); ReadOnlyCollection <ExceptionTableEntry> exceptionTable; try { exceptionTable = executionContext.Location.GetMethod().GetExceptionTable(); } catch (DebuggerException) { exceptionTable = new ReadOnlyCollection <ExceptionTableEntry>(new ExceptionTableEntry[0]); } _evaluationStackDepths = BytecodeDisassembler.GetEvaluationStackDepths(_disassembledMethod, constantPool, exceptionTable); }
private static int GetInstructionAtOffset(DisassembledMethod disassembledMethod, long codeIndex) { return(disassembledMethod.Instructions.FindIndex(i => i.Offset == codeIndex)); }
private bool TryGetAssociatedTree(out IParseTree associatedTree, out IList <IToken> tokens) { try { string sourcePath = _location.GetSourcePath(); if (!File.Exists(sourcePath)) { associatedTree = null; tokens = null; return(false); } string text = File.ReadAllText(sourcePath); AntlrInputStream input = new AntlrInputStream(text); JavaLexer lexer = new JavaLexer(new JavaUnicodeStreamV4(input)); CommonTokenStream tokenStream = new CommonTokenStream(lexer); JavaParser parser = new JavaParser(tokenStream); parser.Interpreter.PredictionMode = PredictionMode.Sll; parser.BuildParseTree = true; JavaParser.CompilationUnitContext result = parser.compilationUnit(); associatedTree = null; tokens = tokenStream.GetTokens(); AssociatedTreeListener listener = new AssociatedTreeListener(_location, tokens); ParseTreeWalker.Default.Walk(listener, result); List <IParseTree> potentialTrees = listener.AssociatedTree; if (potentialTrees.Count == 1) { associatedTree = potentialTrees[0]; } else if (potentialTrees.Count > 1) { byte[] bytecode = _location.GetMethod().GetBytecodes(); DisassembledMethod disassembledMethod = BytecodeDisassembler.Disassemble(bytecode); var constantPool = _location.GetDeclaringType().GetConstantPool(); var exceptionTable = _location.GetMethod().GetExceptionTable(); ImmutableList <int?> evaluationStackDepths = BytecodeDisassembler.GetEvaluationStackDepths(disassembledMethod, constantPool, exceptionTable); ReadOnlyCollection <ILocation> locations = _location.GetMethod().GetLineLocations(); // find all bytecode offsets with evaluation stack depth 0 on the current line List <int> relevantOffsets = new List <int>(); for (int i = 0; i < locations.Count; i++) { if (locations[i].GetLineNumber() != _location.GetLineNumber()) { continue; } long offsetLimit = i < locations.Count - 1 ? locations[i + 1].GetCodeIndex() : bytecode.Length; // start with the instruction for this bytecode offset for (int j = GetInstructionAtOffset(disassembledMethod, locations[i].GetCodeIndex()); j >= 0 && j < disassembledMethod.Instructions.Count && disassembledMethod.Instructions[j].Offset < offsetLimit; j++) { if (evaluationStackDepths[j] == 0) { // ignore unconditional branches if (disassembledMethod.Instructions[j].OpCode.FlowControl == JavaFlowControl.Branch) { continue; } relevantOffsets.Add(disassembledMethod.Instructions[j].Offset); } } } if (relevantOffsets.Count == potentialTrees.Count) { // heuristic: assume they appear in the same order as the source code on this line int treeIndex = relevantOffsets.IndexOf((int)_location.GetCodeIndex()); if (treeIndex >= 0) { associatedTree = potentialTrees[treeIndex]; } } } if (associatedTree == null) { tokens = null; return(false); } return(true); } catch (Exception e) { if (ErrorHandler.IsCriticalException(e)) { throw; } associatedTree = null; tokens = null; return(false); } }
public void SimpleMethodCanBePrettified() { var method = new DisassembledMethod { Maps = new [] { new Map { Instructions = new Diagnosers.Code[] { new Asm { TextRepresentation = "00007ff7`ffbfd2da 33ff xor edi,edi" }, new Asm { TextRepresentation = "00007ff7`ffbfd2dc 48b9e04be659f87f0000 mov rcx,offset System_Private_CoreLib+0x8f4be0 (00007ff8`59e64be0)" }, new Asm { TextRepresentation = "00007ff7`ffbfd2e6 e80570ae5f call coreclr!MetaDataGetDispenser+0x72810 (00007ff8`5f6e42f0)", Comment = "not managed method" }, new Asm { TextRepresentation = "00007ff7`ffbfd2eb 488bd8 mov rbx,rax" }, new Asm { TextRepresentation = "00007ff7`ffbfd2ee 8b4e08 mov ecx,dword ptr [rsi+8]" }, new Asm { TextRepresentation = "00007ff7`ffbfd2f1 894b08 mov dword ptr [rbx+8],ecx" }, new Asm { TextRepresentation = "00007ff7`ffbfd2f4 48b9e04be659f87f0000 mov rcx,offset System_Private_CoreLib+0x8f4be0 (00007ff8`59e64be0)" }, new Asm { TextRepresentation = "00007ff7`ffbfd2fe e8ed6fae5f call coreclr!MetaDataGetDispenser+0x72810 (00007ff8`5f6e42f0)", Comment = "not managed method" }, new Asm { TextRepresentation = "00007ff7`ffbfd303 488bd0 mov rdx,rax" }, new Asm { TextRepresentation = "00007ff7`ffbfd306 c742080c000000 mov dword ptr [rdx+8],0Ch" }, new Asm { TextRepresentation = "00007ff7`ffbfd30d 488bcb mov rcx,rbx" }, new Asm { TextRepresentation = "00007ff7`ffbfd310 e84ba1ee59 call System_Private_CoreLib+0x577460 (00007ff8`59ae7460)", Comment = "HasFlag" }, new Asm { TextRepresentation = "00007ff7`ffbfd315 88460c mov byte ptr [rsi+0Ch],al" }, new Asm { TextRepresentation = "00007ff7`ffbfd318 ffc7 inc edi" }, new Asm { TextRepresentation = "00007ff7`ffbfd31a 81ffe8030000 cmp edi,3E8h" }, new Asm { TextRepresentation = "00007ff7`ffbfd320 7cba jl 00007ff7`ffbfd2dc" }, new Asm { TextRepresentation = "00007ff7`ffbfd322 4883c420 add rsp,20h" } } } }, Name = "Test" }; var expectedOutput = new string[] { "xor edi,edi", "T_L00", "mov rcx,offset System_Private_CoreLib+0x8f4be0", "call coreclr!MetaDataGetDispenser+0x72810", "mov rbx,rax", "mov ecx,dword ptr [rsi+8]", "mov dword ptr [rbx+8],ecx", "mov rcx,offset System_Private_CoreLib+0x8f4be0", "call coreclr!MetaDataGetDispenser+0x72810", "mov rdx,rax", "mov dword ptr [rdx+8],0Ch", "mov rcx,rbx", "call HasFlag", "mov byte ptr [rsi+0Ch],al", "inc edi", "cmp edi,3E8h", "jl T_L00", "add rsp,20h" }; var prettyOutput = DisassemblyPrettifier.Prettify(method, "T"); for (int i = 0; i < expectedOutput.Length; i++) { Assert.Equal(expectedOutput[i], prettyOutput[i].TextRepresentation); } }
public void MethodWithFewJumpsCanBePrettified() { var method = new DisassembledMethod { Maps = new[] { new Map { Instructions = new Diagnosers.Code[] { new Asm { TextRepresentation = "00007ffd`a6304a70 8b4108 mov eax,dword ptr [rcx+8]" }, new Asm { TextRepresentation = "00007ffd`a6304a73 48894c2410 mov qword ptr [rsp+10h],rcx" }, new Asm { TextRepresentation = "00007ffd`a6304a78 4885c9 test rcx,rcx" }, new Asm { TextRepresentation = "00007ffd`a6304a7b 7404 je 00007ffd`a6304a81" }, new Asm { TextRepresentation = "00007ffd`a6304a7d 4883c10c add rcx,0Ch" }, new Asm { TextRepresentation = "00007ffd`a6304a81 4889542408 mov qword ptr [rsp+8],rdx" }, new Asm { TextRepresentation = "00007ffd`a6304a86 4885d2 test rdx,rdx" }, new Asm { TextRepresentation = "00007ffd`a6304a89 7404 je 00007ffd`a6304a8f" }, new Asm { TextRepresentation = "00007ffd`a6304a8b 4883c20c add rdx,0Ch" }, new Asm { TextRepresentation = "00007ffd`a6304a8f 85c0 test eax,eax" }, new Asm { TextRepresentation = "00007ffd`a6304a91 741b je 00007ffd`a6304aae" }, new Asm { TextRepresentation = "00007ffd`a6304a93 440fb701 movzx r8d,word ptr [rcx]" }, new Asm { TextRepresentation = "00007ffd`a6304a97 440fb70a movzx r9d,word ptr [rdx]" }, new Asm { TextRepresentation = "00007ffd`a6304a9b 453bc1 cmp r8d,r9d" }, new Asm { TextRepresentation = "00007ffd`a6304a9e 7518 jne 00007ffd`a6304ab8" }, new Asm { TextRepresentation = "00007ffd`a6304aa0 4883c102 add rcx,2" }, new Asm { TextRepresentation = "00007ffd`a6304aa4 4883c202 add rdx,2" }, new Asm { TextRepresentation = "00007ffd`a6304aa8 ffc8 dec eax" }, new Asm { TextRepresentation = "00007ffd`a6304aaa 85c0 test eax,eax" }, new Asm { TextRepresentation = "00007ffd`a6304aac 75e5 jne 00007ffd`a6304a93" }, new Asm { TextRepresentation = "00007ffd`a6304aae b801000000 mov eax,1" }, new Asm { TextRepresentation = "00007ffd`a6304ab3 4883c418 add rsp,18h" }, new Asm { TextRepresentation = "00007ffd`a6304ab7 c3 ret" }, new Asm { TextRepresentation = "00007ffd`a6304ab8 33c0 xor eax,eax" } } } }, Name = "Test" }; var expectedOutput = new[] { "mov eax,dword ptr [rcx+8]", "mov qword ptr [rsp+10h],rcx", "test rcx,rcx", "je M00_L00", "add rcx,0Ch", "M00_L00", "mov qword ptr [rsp+8],rdx", "test rdx,rdx", "je M00_L01", "add rdx,0Ch", "M00_L01", "test eax,eax", "je M00_L03", "M00_L02", "movzx r8d,word ptr [rcx]", "movzx r9d,word ptr [rdx]", "cmp r8d,r9d", "jne M00_L04", "add rcx,2", "add rdx,2", "dec eax", "test eax,eax", "jne M00_L02", "M00_L03", "mov eax,1", "add rsp,18h", "ret", "M00_L04", "xor eax,eax" }; var prettyOutput = DisassemblyPrettifier.Prettify(method, "M00"); for (int i = 0; i < expectedOutput.Length; i++) { Assert.Equal(expectedOutput[i], prettyOutput[i].TextRepresentation); } }
/// <summary> /// Checks the given method for compatibility. /// </summary> /// <param name="unit">The current compilation unit.</param> /// <param name="method">The method to test for compatiblity.</param> /// <param name="entryPoint">The entry point.</param> private static void CheckMethod( CompileUnit unit, MethodBase method, EntryPoint entryPoint) { var body = method.GetMethodBody(); if (body == null) { return; } var compilationContext = unit.CompilationContext; compilationContext.EnterMethod(method); if (body.ExceptionHandlingClauses.Count > 0) { throw compilationContext.GetNotSupportedException( ErrorMessages.CustomExceptionSemantics, method.Name); } var disassembledMethod = DisassembledMethod.Disassemble( method, compilationContext.NotSupportedILInstructionHandler); foreach (var instruction in disassembledMethod.Instructions) { switch (instruction.InstructionType) { case ILInstructionType.Ldsfld: CodeGenerator.VerifyStaticFieldLoad( compilationContext, unit.Flags, instruction.GetArgumentAs <FieldInfo>()); break; case ILInstructionType.Stsfld: CodeGenerator.VerifyStaticFieldStore( compilationContext, unit.Flags, instruction.GetArgumentAs <FieldInfo>()); break; case ILInstructionType.Box: case ILInstructionType.Unbox: case ILInstructionType.Calli: throw compilationContext.GetNotSupportedException( ErrorMessages.NotSupportedInstruction, method.Name, instruction.InstructionType); case ILInstructionType.Callvirt: var virtualTarget = instruction.GetArgumentAs <MethodInfo>(); var constrainedType = instruction.HasFlags(ILInstructionFlags.Constrained) ? instruction.FlagsContext.Argument as Type : null; CheckCall( unit, CodeGenerator.ResolveVirtualCallTarget( compilationContext, virtualTarget, constrainedType), entryPoint); break; case ILInstructionType.Call: case ILInstructionType.Newobj: CheckCall( unit, instruction.GetArgumentAs <MethodBase>(), entryPoint); break; } } compilationContext.LeaveMethod(method); }
internal static IReadOnlyList <Element> Prettify(DisassembledMethod method, DisassemblyResult disassemblyResult, DisassemblyDiagnoserConfig config, string labelPrefix) { var asmInstructions = method.Maps.SelectMany(map => map.SourceCodes.OfType <Asm>()).ToArray(); // first of all, we search of referenced addresses (jump|calls) var referencedAddresses = new HashSet <ulong>(); foreach (var asm in asmInstructions) { if (ClrMdV2Disassembler.TryGetReferencedAddress(asm.Instruction, disassemblyResult.PointerSize, out ulong referencedAddress)) { referencedAddresses.Add(referencedAddress); } } // for every IP that is referenced, we emit a uinque label var addressesToLabels = new Dictionary <ulong, string>(); int currentLabelIndex = 0; foreach (var instruction in asmInstructions) { if (referencedAddresses.Contains(instruction.InstructionPointer) && !addressesToLabels.ContainsKey(instruction.InstructionPointer)) { addressesToLabels.Add(instruction.InstructionPointer, $"{labelPrefix}_L{currentLabelIndex++:00}"); } } var formatterWithLabelsSymbols = config.GetFormatterWithSymbolSolver(addressesToLabels); var formatterWithGlobalSymbols = config.GetFormatterWithSymbolSolver(disassemblyResult.AddressToNameMapping); var prettified = new List <Element>(); foreach (var map in method.Maps) { foreach (var instruction in map.SourceCodes) { if (instruction is Sharp sharp) { prettified.Add(new Element(sharp.Text, sharp)); } else if (instruction is MonoCode mono) { prettified.Add(new Element(mono.Text, mono)); } else if (instruction is Asm asm) { // this IP is referenced by some jump|call, so we add a label if (addressesToLabels.TryGetValue(asm.InstructionPointer, out string label)) { prettified.Add(new Label(label)); } if (ClrMdV2Disassembler.TryGetReferencedAddress(asm.Instruction, disassemblyResult.PointerSize, out ulong referencedAddress)) { // jump or a call within same method if (addressesToLabels.TryGetValue(referencedAddress, out string translated)) { prettified.Add(new Reference(InstructionFormatter.Format(asm.Instruction, formatterWithLabelsSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), translated, asm)); continue; } // call to a known method if (disassemblyResult.AddressToNameMapping.ContainsKey(referencedAddress)) { prettified.Add(new Element(InstructionFormatter.Format(asm.Instruction, formatterWithGlobalSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), asm)); continue; } } prettified.Add(new Element(InstructionFormatter.Format(asm.Instruction, formatterWithGlobalSymbols, config.PrintInstructionAddresses, disassemblyResult.PointerSize), asm)); } } } return(prettified); }
public StepEventFilter(EventKind internalEventKind, RequestId requestId, SuspendPolicy suspendPolicy, IEnumerable <EventRequestModifier> modifiers, ThreadId thread, JvmtiEnvironment environment, JniEnvironment nativeEnvironment, StepSize size, StepDepth depth) : base(internalEventKind, requestId, suspendPolicy, modifiers, thread) { if (size == StepSize.Statement && JavaVM.DisableStatementStepping) { size = StepSize.Line; } _size = size; _depth = depth; // gather reference information for the thread using (var threadHandle = environment.VirtualMachine.GetLocalReferenceForThread(nativeEnvironment, thread)) { if (threadHandle.IsAlive) { jvmtiError error = environment.GetFrameLocation(threadHandle.Value, 0, out _lastMethod, out _lastLocation); if (error == jvmtiError.None) { error = environment.GetFrameCount(threadHandle.Value, out _stackDepth); } if (error == jvmtiError.None) { _hasMethodInfo = true; } UpdateLastLine(environment); if (error == jvmtiError.None && size == StepSize.Statement && (depth == StepDepth.Over || depth == StepDepth.Into)) { byte[] bytecode; JvmtiErrorHandler.ThrowOnFailure(environment.GetBytecodes(_lastMethod, out bytecode)); _disassembledMethod = BytecodeDisassembler.Disassemble(bytecode); TaggedReferenceTypeId declaringClass; JvmtiErrorHandler.ThrowOnFailure(environment.GetMethodDeclaringClass(nativeEnvironment, _lastMethod, out declaringClass)); using (var classHandle = environment.VirtualMachine.GetLocalReferenceForClass(nativeEnvironment, declaringClass.TypeId)) { int constantPoolCount; byte[] data; JvmtiErrorHandler.ThrowOnFailure(environment.GetConstantPool(classHandle.Value, out constantPoolCount, out data)); List <ConstantPoolEntry> entryList = new List <ConstantPoolEntry>(); int currentPosition = 0; for (int i = 0; i < constantPoolCount - 1; i++) { entryList.Add(ConstantPoolEntry.FromBytes(data, ref currentPosition)); switch (entryList.Last().Type) { case ConstantType.Double: case ConstantType.Long: // these entries take 2 slots entryList.Add(ConstantPoolEntry.Reserved); i++; break; default: break; } } _constantPool = entryList.AsReadOnly(); string classSignature; string classGenericSignature; JvmtiErrorHandler.ThrowOnFailure(environment.GetClassSignature(classHandle.Value, out classSignature, out classGenericSignature)); string methodName; string methodSignature; string methodGenericSignature; JvmtiErrorHandler.ThrowOnFailure(environment.GetMethodName(_lastMethod, out methodName, out methodSignature, out methodGenericSignature)); jobject classLoader; JvmtiErrorHandler.ThrowOnFailure(environment.GetClassLoader(classHandle.Value, out classLoader)); long classLoaderTag; JvmtiErrorHandler.ThrowOnFailure(environment.TagClassLoader(classLoader, out classLoaderTag)); ReadOnlyCollection <ExceptionTableEntry> exceptionTable; JvmtiErrorHandler.ThrowOnFailure(environment.VirtualMachine.GetExceptionTable(classLoaderTag, classSignature, methodName, methodSignature, out exceptionTable)); _evaluationStackDepths = BytecodeDisassembler.GetEvaluationStackDepths(_disassembledMethod, _constantPool, exceptionTable); } } } } }