protected void MethodBegin(MethodInfo aMethod) { new Comment("---------------------------------------------------------"); new Comment("Assembly: " + aMethod.MethodBase.DeclaringType.Assembly.FullName); new Comment("Type: " + aMethod.MethodBase.DeclaringType.ToString()); new Comment("Name: " + aMethod.MethodBase.Name); new Comment("Plugged: " + (aMethod.PlugMethod == null ? "No" : "Yes")); // for now: var shouldIncludeArgAndLocalsComment = true; if (shouldIncludeArgAndLocalsComment) { if (aMethod.MethodAssembler == null && !aMethod.IsInlineAssembler) { // the body of aMethod is getting emitted var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { foreach (var localVariable in xBody.LocalVariables) { new Comment(String.Format("Local {0} at EBP-{1}", localVariable.LocalIndex, ILOp.GetEBPOffsetForLocal(aMethod, localVariable.LocalIndex))); } } var xIdxOffset = 0u; if (!aMethod.MethodBase.IsStatic) { new Comment(String.Format("Argument[0] $this at EBP+{0}, size = {1}", X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), ILOp.Align(ILOp.SizeOfType(aMethod.MethodBase.DeclaringType), 4))); xIdxOffset++; } var xParams = aMethod.MethodBase.GetParameters(); var xParamCount = (ushort)xParams.Length; for (ushort i = 0; i < xParamCount; i++) { var xOffset = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, (ushort)(i + xIdxOffset)); var xSize = X86.IL.Ldarg.SizeOfType(xParams[i].ParameterType); // if last argument is 8 byte long, we need to add 4, so that debugger could read all 8 bytes from this variable in positiv direction new Comment(String.Format("Argument[{3}] {0} at EBP+{1}, size = {2}", xParams[i].Name, xOffset, xSize, (xIdxOffset + i))); } var xMethodInfo = aMethod.MethodBase as SysReflection.MethodInfo; if (xMethodInfo != null) { var xSize = ILOp.Align(ILOp.SizeOfType(xMethodInfo.ReturnType), 4); new Comment(String.Format("Return size: {0}", xSize)); } } } // Issue label that is used for calls etc. string xMethodLabel; if (aMethod.PluggedMethod != null) { xMethodLabel = "PLUG_FOR___" + LabelName.Get(aMethod.PluggedMethod.MethodBase); } else { xMethodLabel = LabelName.Get(aMethod.MethodBase); } new Cosmos.Assembler.Label(xMethodLabel); //Assembler.WriteDebugVideo("Method " + aMethod.UID); // We could use same GUID as MethodLabelStart, but its better to keep GUIDs unique globaly for items // so during debugging they can never be confused as to what they point to. mCurrentMethodGuid = DebugInfo.CreateId(); // We issue a second label for GUID. This is increases label count, but for now we need a master label first. // We issue a GUID label to reduce amount of work and time needed to construct debugging DB. var xLabelGuid = DebugInfo.CreateId(); new Cosmos.Assembler.Label("GUID_" + xLabelGuid.ToString()); mCurrentMethodLabel = "METHOD_" + xLabelGuid.ToString(); Cosmos.Assembler.Label.LastFullLabel = mCurrentMethodLabel; mCurrentMethodLabelEndGuid = DebugInfo.CreateId(); if (aMethod.MethodBase.IsStatic && aMethod.MethodBase is ConstructorInfo) { new Comment("Static constructor. See if it has been called already, return if so."); var xName = DataMember.FilterStringForIncorrectChars("CCTOR_CALLED__" + LabelName.GetFullName(aMethod.MethodBase.DeclaringType)); var xAsmMember = new DataMember(xName, (byte)0); Assembler.DataMembers.Add(xAsmMember); new Compare { DestinationRef = Cosmos.Assembler.ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = ".BeforeQuickReturn" }; new Mov { DestinationRef = Cosmos.Assembler.ElementReference.New(xName), DestinationIsIndirect = true, Size = 8, SourceValue = 1 }; new Jump { DestinationLabel = ".AfterCCTorAlreadyCalledCheck" }; new Cosmos.Assembler.Label(".BeforeQuickReturn"); new Mov { DestinationReg = RegistersEnum.ECX, SourceValue = 0 }; new Return { }; new Cosmos.Assembler.Label(".AfterCCTorAlreadyCalledCheck"); } new Push { DestinationReg = Registers.EBP }; new Mov { DestinationReg = Registers.EBP, SourceReg = Registers.ESP }; if (DebugMode == DebugMode.Source) { // Would be nice to use xMethodSymbols.GetSourceStartEnd but we cant // because its not implemented by the unmanaged code underneath. // // This doesnt seem right to store as a field, but old code had it that way so we // continue using a field for now. mSequences = DebugInfo.GetSequencePoints(aMethod.MethodBase, true); if (mSequences.Length > 0) { DebugInfo.AddDocument(mSequences[0].Document); var xMethod = new Method() { ID = mCurrentMethodGuid, TypeToken = aMethod.MethodBase.DeclaringType.MetadataToken, MethodToken = aMethod.MethodBase.MetadataToken, LabelStartID = xLabelGuid, LabelEndID = mCurrentMethodLabelEndGuid, LabelCall = xMethodLabel, AssemblyFileID = DebugInfo.AssemblyGUIDs[aMethod.MethodBase.DeclaringType.Assembly], DocumentID = DebugInfo.DocumentGUIDs[mSequences[0].Document.ToLower()], // Storing Line + Col as one item makes comparisons MUCH easier, otherwise we have to // check for things like col < start col but line > start line. // // () around << are VERY important.. + has precedence over << LineColStart = ((Int64)mSequences[0].LineStart << 32) + mSequences[0].ColStart, LineColEnd = ((Int64)(mSequences[mSequences.Length - 1].LineEnd) << 32) + mSequences[mSequences.Length - 1].ColEnd }; DebugInfo.AddMethod(xMethod); } } if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null && !aMethod.IsInlineAssembler) { // the body of aMethod is getting emitted var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { var xLocalsOffset = mLocals_Arguments_Infos.Count; aMethod.LocalVariablesSize = 0; foreach (var xLocal in xBody.LocalVariables) { var xInfo = new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = false, INDEXINMETHOD = xLocal.LocalIndex, NAME = "Local" + xLocal.LocalIndex, OFFSET = 0 - (int)ILOp.GetEBPOffsetForLocalForDebugger(aMethod, xLocal.LocalIndex), TYPENAME = xLocal.LocalType.AssemblyQualifiedName }; mLocals_Arguments_Infos.Add(xInfo); var xSize = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4); new Comment(String.Format("Local {0}, Size {1}", xLocal.LocalIndex, xSize)); for (int i = 0; i < xSize / 4; i++) { new Push { DestinationValue = 0 }; } aMethod.LocalVariablesSize += xSize; //new Sub { DestinationReg = Registers.ESP, SourceValue = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4) }; } var xCecilMethod = GetCecilMethodDefinitionForSymbolReading(aMethod.MethodBase); if (xCecilMethod != null && xCecilMethod.Body != null) { // mLocals_Arguments_Infos is one huge list, so ourlatest additions are at the end for (int i = 0; i < xCecilMethod.Body.Variables.Count; i++) { mLocals_Arguments_Infos[xLocalsOffset + i].NAME = xCecilMethod.Body.Variables[i].Name; } for (int i = xLocalsOffset + xCecilMethod.Body.Variables.Count - 1; i >= xLocalsOffset; i--) { if (mLocals_Arguments_Infos[i].NAME.Contains('$')) { mLocals_Arguments_Infos.RemoveAt(i); } } } } // debug info: var xIdxOffset = 0u; if (!aMethod.MethodBase.IsStatic) { mLocals_Arguments_Infos.Add(new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = true, NAME = "this:" + X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), INDEXINMETHOD = 0, OFFSET = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), TYPENAME = aMethod.MethodBase.DeclaringType.AssemblyQualifiedName }); xIdxOffset++; } var xParams = aMethod.MethodBase.GetParameters(); var xParamCount = (ushort)xParams.Length; for (ushort i = 0; i < xParamCount; i++) { var xOffset = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, (ushort)(i + xIdxOffset)); // if last argument is 8 byte long, we need to add 4, so that debugger could read all 8 bytes from this variable in positiv direction xOffset -= (int)Cosmos.IL2CPU.ILOp.Align(ILOp.SizeOfType(xParams[i].ParameterType), 4) - 4; mLocals_Arguments_Infos.Add(new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = true, INDEXINMETHOD = (int)(i + xIdxOffset), NAME = xParams[i].Name, OFFSET = xOffset, TYPENAME = xParams[i].ParameterType.AssemblyQualifiedName }); } } }
protected void MethodBegin(MethodInfo aMethod) { XS.Comment("---------------------------------------------------------"); XS.Comment("Assembly: " + aMethod.MethodBase.DeclaringType.Assembly.FullName); XS.Comment("Type: " + aMethod.MethodBase.DeclaringType.ToString()); XS.Comment("Name: " + aMethod.MethodBase.Name); XS.Comment("Plugged: " + (aMethod.PlugMethod == null ? "No" : "Yes")); // for now: var shouldIncludeArgAndLocalsComment = true; if (shouldIncludeArgAndLocalsComment) { if (aMethod.MethodAssembler == null && !aMethod.IsInlineAssembler) { // the body of aMethod is getting emitted var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { foreach (var localVariable in xBody.LocalVariables) { XS.Comment(String.Format("Local {0} at EBP-{1}", localVariable.LocalIndex, ILOp.GetEBPOffsetForLocal(aMethod, localVariable.LocalIndex))); } } var xIdxOffset = 0u; if (!aMethod.MethodBase.IsStatic) { XS.Comment(String.Format("Argument[0] $this at EBP+{0}, size = {1}", X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), ILOp.Align(ILOp.SizeOfType(aMethod.MethodBase.DeclaringType), 4))); xIdxOffset++; } string x = aMethod.MethodBase.Name; string y = aMethod.MethodBase.DeclaringType.Name; var xParams = aMethod.MethodBase.GetParameters(); var xParamCount = (ushort)xParams.Length; for (ushort i = 0; i < xParamCount; i++) { var xOffset = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, (ushort)(i + xIdxOffset)); var xSize = X86.IL.Ldarg.SizeOfType(xParams[i].ParameterType); // if last argument is 8 byte long, we need to add 4, so that debugger could read all 8 bytes from this variable in positiv direction XS.Comment(String.Format("Argument[{3}] {0} at EBP+{1}, size = {2}", xParams[i].Name, xOffset, xSize, (xIdxOffset + i))); } var xMethodInfo = aMethod.MethodBase as SysReflection.MethodInfo; if (xMethodInfo != null) { var xSize = ILOp.Align(ILOp.SizeOfType(xMethodInfo.ReturnType), 4); XS.Comment(String.Format("Return size: {0}", xSize)); } } } // Issue label that is used for calls etc. string xMethodLabel; if (aMethod.PluggedMethod != null) { xMethodLabel = "PLUG_FOR___" + LabelName.Get(aMethod.PluggedMethod.MethodBase); } else { xMethodLabel = LabelName.Get(aMethod.MethodBase); } XS.Label(xMethodLabel); //Assembler.WriteDebugVideo("Method " + aMethod.UID); // We could use same GUID as MethodLabelStart, but its better to keep GUIDs unique globaly for items // so during debugging they can never be confused as to what they point to. mCurrentMethodGuid = DebugInfo.CreateId(); // We issue a second label for GUID. This is increases label count, but for now we need a master label first. // We issue a GUID label to reduce amount of work and time needed to construct debugging DB. var xLabelGuid = DebugInfo.CreateId(); new Label("GUID_" + xLabelGuid.ToString()); mCurrentMethodLabel = "METHOD_" + xLabelGuid.ToString(); Label.LastFullLabel = mCurrentMethodLabel; if (DebugEnabled && StackCorruptionDetection) { // if StackCorruption detection is active, we're also going to emit a stack overflow detection XS.Set(XSRegisters.EAX, "Before_Kernel_Stack"); XS.Compare(XSRegisters.EAX, XSRegisters.ESP); XS.Jump(ConditionalTestEnum.LessThan, mCurrentMethodLabel + ".StackOverflowCheck_End"); XS.ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value new Call { DestinationLabel = mCurrentMethodLabel + ".StackOverflowCheck_GetAddress" }; XS.Label(mCurrentMethodLabel + ".StackOverflowCheck_GetAddress"); XS.Pop(XSRegisters.EAX); new Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; XS.Call("DebugStub_SendStackOverflowOccurred"); XS.Halt(); XS.Label(mCurrentMethodLabel + ".StackOverflowCheck_End"); } mCurrentMethodLabelEndGuid = DebugInfo.CreateId(); if (aMethod.MethodBase.IsStatic && aMethod.MethodBase is ConstructorInfo) { XS.Comment("Static constructor. See if it has been called already, return if so."); var xName = DataMember.FilterStringForIncorrectChars("CCTOR_CALLED__" + LabelName.GetFullName(aMethod.MethodBase.DeclaringType)); XS.DataMember(xName, 0); XS.Compare(xName, 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.Jump(ConditionalTestEnum.Equal, ".BeforeQuickReturn"); XS.Set(xName, 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.Jump(".AfterCCTorAlreadyCalledCheck"); XS.Label(".BeforeQuickReturn"); XS.Set(XSRegisters.ECX, 0); XS.Return(); XS.Label(".AfterCCTorAlreadyCalledCheck"); } XS.Push(XSRegisters.EBP); XS.Set(XSRegisters.EBP, XSRegisters.ESP); if (DebugMode == DebugMode.Source) { // Would be nice to use xMethodSymbols.GetSourceStartEnd but we cant // because its not implemented by the unmanaged code underneath. // // This doesnt seem right to store as a field, but old code had it that way so we // continue using a field for now. mSequences = DebugInfo.GetSequencePoints(aMethod.MethodBase, true); if (mSequences.Length > 0) { DebugInfo.AddDocument(mSequences[0].Document); var xMethod = new Method(); xMethod.ID = mCurrentMethodGuid; xMethod.TypeToken = aMethod.MethodBase.DeclaringType.MetadataToken; xMethod.MethodToken = aMethod.MethodBase.MetadataToken; xMethod.LabelStartID = xLabelGuid; xMethod.LabelEndID = mCurrentMethodLabelEndGuid; xMethod.LabelCall = xMethodLabel; long xAssemblyFileID; if (DebugInfo.AssemblyGUIDs.TryGetValue(aMethod.MethodBase.DeclaringType.Assembly, out xAssemblyFileID)) { xMethod.AssemblyFileID = xAssemblyFileID; } xMethod.DocumentID = DebugInfo.DocumentGUIDs[mSequences[0].Document.ToLower()]; xMethod.LineColStart = ((Int64)mSequences[0].LineStart << 32) + mSequences[0].ColStart; xMethod.LineColEnd = ((Int64)(mSequences[mSequences.Length - 1].LineEnd) << 32) + mSequences[mSequences.Length - 1].ColEnd; DebugInfo.AddMethod(xMethod); } } if (aMethod.MethodAssembler == null && aMethod.PlugMethod == null && !aMethod.IsInlineAssembler) { // the body of aMethod is getting emitted var xBody = aMethod.MethodBase.GetMethodBody(); if (xBody != null) { var xLocalsOffset = mLocals_Arguments_Infos.Count; aMethod.LocalVariablesSize = 0; foreach (var xLocal in xBody.LocalVariables) { var xInfo = new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = false, INDEXINMETHOD = xLocal.LocalIndex, NAME = "Local" + xLocal.LocalIndex, OFFSET = 0 - (int)ILOp.GetEBPOffsetForLocalForDebugger(aMethod, xLocal.LocalIndex), TYPENAME = xLocal.LocalType.AssemblyQualifiedName }; mLocals_Arguments_Infos.Add(xInfo); var xSize = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4); XS.Comment(String.Format("Local {0}, Size {1}", xLocal.LocalIndex, xSize)); for (int i = 0; i < xSize / 4; i++) { XS.Push(0); } aMethod.LocalVariablesSize += xSize; //new Sub { DestinationReg = Registers.ESP, SourceValue = ILOp.Align(ILOp.SizeOfType(xLocal.LocalType), 4) }; } var xCecilMethod = GetCecilMethodDefinitionForSymbolReading(aMethod.MethodBase); if (xCecilMethod != null && xCecilMethod.Body != null) { // mLocals_Arguments_Infos is one huge list, so ourlatest additions are at the end for (int i = 0; i < xCecilMethod.Body.Variables.Count; i++) { mLocals_Arguments_Infos[xLocalsOffset + i].NAME = xCecilMethod.Body.Variables[i].Name; } for (int i = xLocalsOffset + xCecilMethod.Body.Variables.Count - 1; i >= xLocalsOffset; i--) { if (mLocals_Arguments_Infos[i].NAME.Contains('$')) { mLocals_Arguments_Infos.RemoveAt(i); } } } } // debug info: var xIdxOffset = 0u; if (!aMethod.MethodBase.IsStatic) { mLocals_Arguments_Infos.Add(new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = true, NAME = "this:" + X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), INDEXINMETHOD = 0, OFFSET = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, 0), TYPENAME = aMethod.MethodBase.DeclaringType.AssemblyQualifiedName }); xIdxOffset++; } var xParams = aMethod.MethodBase.GetParameters(); var xParamCount = (ushort)xParams.Length; for (ushort i = 0; i < xParamCount; i++) { var xOffset = X86.IL.Ldarg.GetArgumentDisplacement(aMethod, (ushort)(i + xIdxOffset)); // if last argument is 8 byte long, we need to add 4, so that debugger could read all 8 bytes from this variable in positiv direction xOffset -= (int)ILOp.Align(ILOp.SizeOfType(xParams[i].ParameterType), 4) - 4; mLocals_Arguments_Infos.Add(new LOCAL_ARGUMENT_INFO { METHODLABELNAME = xMethodLabel, IsArgument = true, INDEXINMETHOD = (int)(i + xIdxOffset), NAME = xParams[i].Name, OFFSET = xOffset, TYPENAME = xParams[i].ParameterType.AssemblyQualifiedName }); } } }