DLR - 为啥我的堆栈跟踪中没有显示调试信息?
Posted
技术标签:
【中文标题】DLR - 为啥我的堆栈跟踪中没有显示调试信息?【英文标题】:DLR - Why isn't debug information showing up in my stacktrace?DLR - 为什么我的堆栈跟踪中没有显示调试信息? 【发布时间】:2013-03-13 15:50:45 【问题描述】:首先,我已经阅读了Making a CLR/.NET Language Debuggable,但我仍然无法实现这一点。
我编写了一种玩具语言,它通过生成 Linq 表达式,然后调用 LambdaExpression#CompileToMethod 来工作。这些表达式中的大多数都附加了调试信息,如下所示:
//SmithExpression#InsertDebugInfo
Expression InsertDebugInfo(Expression expression, DebugInfo debugInfo)
var column = 1;
var debugExpr = Expression.DebugInfo(debugInfo.SymbolDocumentInfo
,Info.LineNumber, column, Info.LineNumber, column + 1);
return Expression.Block(debugExpr, expression);
DebugInfo 如下所示:
public class DebugInfo
/* arbitrary value from http://www.famkruithof.net/uuid/uuidgen */
public static Guid SmithGuid = new Guid("83c65910-8376-11e2-9e96-0800200c9a66");
public readonly SymbolDocumentInfo SymbolDocumentInfo;
public readonly DebugInfoGenerator DebugPdbGenerator;
public DebugInfo(String name)
SymbolDocumentInfo = Expression.SymbolDocument(name, SmithGuid);
DebugPdbGenerator = DebugInfoGenerator.CreatePdbGenerator();
整个事情是这样编译的(你可以忽略关于init的部分):
public static Action CompileSmithExpression(SmithExpression sexpression
,DebugInfo debugInfo, Parameter moduleParameter, Expando module)
AssemblyName assemblyName =
new AssemblyName(
"RuntimeHelpers.CompileToSmithExpression helper assembly"
);
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.RunAndSave
);
ModuleBuilder moduleBuilder = assemblyBuilder
.DefineDynamicModule(assemblyName.Name, "onlyModule.dll");
var debugAttributes =
DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations;
ConstructorInfo constructor =
typeof(DebuggableAttribute)
.GetConstructor(new Type[]
typeof(DebuggableAttribute.DebuggingModes)
);
var cab = new CustomAttributeBuilder(constructor, new object[] debugAttributes );
assemblyBuilder.SetCustomAttribute(cab);
moduleBuilder.SetCustomAttribute(cab);
TypeBuilder typeBuilder =
moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
//inits generates expressions that set 'constant' fields to their values.
//the call also adds the 'constant' fields to the typeBuilder.
//Must call ToArray() to make it run.
var inits = FieldInits(sexpression, typeBuilder).ToArray();
var ex = sexpression.ToExpression(debugInfo);
var fullDlrExpression = Expression.Block(inits.Append(ex));
var parameters = new ParameterExpression[] moduleParameter.DlrParameter ;
var lambda = Expression.Lambda(fullDlrExpression, parameters);
/* Method will take the module as a parameter. */
MethodBuilder meth = typeBuilder.DefineMethod(
"MyMethod",
MethodAttributes.Public | MethodAttributes.Static,
typeof(void),
new Type[] typeof(Expando) );
lambda.CompileToMethod(meth, debugInfo.DebugPdbGenerator);
Type madeType = typeBuilder.CreateType();
return () => madeType.GetMethod("MyMethod").Invoke(null, new Object[] module );
运行代码给出了我想要的异常,但不包括表达式所具有的调试信息。我希望它说“
Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.MissingMemberException: Can't invoke member error of [] []
at (wrapper dynamic-method) object.CallSite.Target (System.Runtime.CompilerServices.Closure,System.Runtime.CompilerServices.CallSite,Smith.Expando) <IL 0x0004f, 0x00127>
at System.Dynamic.UpdateDelegates.UpdateAndExecute1<Smith.Expando, object> (System.Runtime.CompilerServices.CallSite,Smith.Expando) <0x0040b>
at MyDynamicType.MyMethod (Smith.Expando) <IL 0x002bc, 0x00aaa>
at (wrapper managed-to-native) System.Reflection.MonoMethod.InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) <IL 0x00016, 0x00067>
etc...
我最好的猜测是调试信息确实在那里,但我必须做更多的工作才能让堆栈跟踪显示它。有什么想法吗?
【问题讨论】:
肯定更多的工作,没有什么简单的。 dlr.codeplex.com/discussions/80850 "IronRuby 通过在编译时提供 DebugInfoGenerator 来维护 IL 偏移到行号的映射。"这正是我想要做的,并且每个表达式都已经用 DebugInfoExpression 进行了标记。如果有办法从 IL 位置到离它最近的 DebugInfoExpression 行号,那么我可以进行堆栈跟踪。 【参考方案1】:您的异常是嵌套异常。要打印堆栈跟踪,请查看 InnerException。
catch (Exception ex)
while (ex != null)
Debug.Print(ex.ToString());
ex = ex.InnerException();
【讨论】:
以上是关于DLR - 为啥我的堆栈跟踪中没有显示调试信息?的主要内容,如果未能解决你的问题,请参考以下文章
为啥默认配置的spring webflux中没有异常堆栈跟踪?