private IList <DebugType> FindTypesInModules(String name) { List <DebugType> result = new List <DebugType>(); List <Module> modules = new List <Module>(process.Modules); foreach (Module module in modules) { MetaDataImport metaData = module.MetaData; foreach (TypeDefProps typeDef in module.MetaData.EnumTypeDefProps()) { uint token = typeDef.Token; if (metaData.GetGenericParamCount(token) == 0) { if (name.Equals(typeDef.Name)) { try { result.Add(DebugType.Create(module, token)); } catch { } } } } } return(result); }
public static DebugType GetDebugType(Type t, List <DebugType> gen_args) { string name; if (t.Assembly == typeof(int).Assembly) { name = "mscorlib.dll"; } else { name = t.Assembly.ManifestModule.ScopeName; } return(DebugType.Create(WorkbenchServiceFactory.DebuggerManager.DebuggedProcess.GetModule(name), (uint)t.MetadataToken, gen_args.ToArray())); }
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) { Value left = ((Value)binaryOperatorExpression.Left.AcceptVisitor(this, null)).GetPermanentReference(); Value right = ((Value)binaryOperatorExpression.Right.AcceptVisitor(this, null)).GetPermanentReference(); if (!left.IsReference && left.Type.FullName != right.Type.FullName) { throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName)); } Value val = Eval.NewObjectNoConstructor(DebugType.Create(context.Process, null, typeof(bool).FullName)); try { switch (binaryOperatorExpression.Op) { case BinaryOperatorType.Equality: val.PrimitiveValue = Equals(right.PrimitiveValue, left.PrimitiveValue); break; case BinaryOperatorType.InEquality: val.PrimitiveValue = !Equals(right.PrimitiveValue, left.PrimitiveValue); break; // case BinaryOperatorType.Add : // val.PrimitiveValue = (right.PrimitiveValue.ToString() + left.PrimitiveValue.ToString()); // break; // case BinaryOperatorType.GreaterThan : // val.PrimitiveValue = (right.PrimitiveValue > left.PrimitiveValue); // break; // case BinaryOperatorType.LessThanOrEqual : // val.PrimitiveValue = (right.PrimitiveValue <= left.PrimitiveValue); // break; // case BinaryOperatorType.GreaterThanOrEqual : // val.PrimitiveValue = (right.PrimitiveValue >= left.PrimitiveValue); // break; default: throw new NotImplementedException("BinaryOperator: " + binaryOperatorExpression.Op); } } catch (NotImplementedException e) { throw e; } catch (System.Exception e2) { throw new GetValueException(e2.Message); } return(val); }
public static DebugType GetDebugType(Type t) { Process p = WorkbenchServiceFactory.DebuggerManager.DebuggedProcess; string name; if (t.Assembly == typeof(int).Assembly) { name = "mscorlib.dll"; } else { name = t.Assembly.ManifestModule.ScopeName; } DebugType dt = DebugType.Create(p.GetModule(name), (uint)t.MetadataToken); return(dt); }
public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { if (primitiveExpression.Value == null) { return(Eval.CreateValue(context.Process, null)); } else if (primitiveExpression.Value is string) { return(Eval.NewString(context.Process, primitiveExpression.Value as string)); } else { Value val = Eval.NewObjectNoConstructor(DebugType.Create(context.Process, null, primitiveExpression.Value.GetType().FullName)); val.PrimitiveValue = primitiveExpression.Value; return(val); } }
public static void Initialize(TestContext ctx) { _ = ctx; // unused using var llvmContext = new Context( ); using var module = llvmContext.CreateBitcodeModule("test", SourceLanguage.C, TestSrcFileName, "unit tests"); var tm = TargetMachine.FromTriple(Triple.HostTriple); module.TargetTriple = tm.Triple; module.Layout = tm.TargetData; var doubleType = new DebugBasicType(llvmContext.DoubleType, module, "double", DiTypeKind.Float); var voidType = DebugType.Create <ITypeRef, DIType>(module.Context.VoidType, null); var printDecl = module.CreateFunction(PrintFuncName, false, voidType, doubleType); var bldr = CreateFunctionAndGetBuilder(module, doubleType, AddFuncName, AddSectionName, 0); bldr.CurrentDebugLocation = new DILocation(llvmContext, 2, 1, bldr.InsertFunction !.DISubProgram !); var result = bldr.FAdd(bldr.InsertFunction.Parameters[0], bldr.InsertFunction.Parameters[1]); _ = bldr.Call(printDecl, result); bldr.Return(result); bldr = CreateFunctionAndGetBuilder(module, doubleType, SubFuncName, SubSectionName, 5); bldr.CurrentDebugLocation = new DILocation(llvmContext, 7, 1, bldr.InsertFunction !.DISubProgram !); result = bldr.FSub(bldr.InsertFunction.Parameters[0], bldr.InsertFunction.Parameters[1]); _ = bldr.Call(printDecl, result); bldr.Return(result); bldr = CreateFunctionAndGetBuilder(module, doubleType, MulFuncName, MulSectionName, 10); bldr.CurrentDebugLocation = new DILocation(llvmContext, 12, 1, bldr.InsertFunction !.DISubProgram !); result = bldr.FMul(bldr.InsertFunction.Parameters[0], bldr.InsertFunction.Parameters[1]); _ = bldr.Call(printDecl, result); bldr.Return(result); bldr = CreateFunctionAndGetBuilder(module, doubleType, DivFuncName, DivSectionName, 15); bldr.CurrentDebugLocation = new DILocation(llvmContext, 17, 1, bldr.InsertFunction !.DISubProgram !); result = bldr.FDiv(bldr.InsertFunction.Parameters[0], bldr.InsertFunction.Parameters[1]); _ = bldr.Call(printDecl, result); bldr.Return(result); Debug.WriteLine(module.WriteToString( )); tm.EmitToFile(module, TestObjFileName, CodeGenFileType.ObjectFile); }
public Value GetPermanentReference() { ICorDebugValue corValue = this.CorValue; if (this.Type.IsClass) { corValue = this.CorObjectValue.CastTo <ICorDebugHeapValue2>().CreateHandle(CorDebugHandleType.HANDLE_STRONG).CastTo <ICorDebugValue>(); } if (this.Type.IsValueType || this.Type.IsPrimitive) { if (!corValue.Is <ICorDebugReferenceValue>()) { // Box the value type if (this.Type.IsPrimitive) { // Get value type for the primive type object o = this.PrimitiveValue; corValue = Eval.NewObjectNoConstructor(DebugType.Create(process, null, this.Type.FullName)).RawCorValue; this.SetPrimitiveValue(o); } else { corValue = Eval.NewObjectNoConstructor(this.Type).RawCorValue; } // Make the reference to box permanent corValue = corValue.CastTo <ICorDebugReferenceValue>().Dereference().CastTo <ICorDebugHeapValue2>().CreateHandle(CorDebugHandleType.HANDLE_STRONG).CastTo <ICorDebugValue>(); // Create new value Value newValue = new Value(process, new IExpirable[] {}, new IMutable[] {}, delegate { return(corValue); }); // Copy the data inside the box newValue.CorGenericValue.RawValue = this.CorGenericValue.RawValue; return(newValue); } else { // Make the reference to box permanent corValue = corValue.CastTo <ICorDebugReferenceValue>().Dereference().CastTo <ICorDebugHeapValue2>().CreateHandle(CorDebugHandleType.HANDLE_STRONG).CastTo <ICorDebugValue>(); } } return(new Value(process, new IExpirable[] {}, new IMutable[] {}, delegate { return corValue; })); }
private static Function DeclareCopyFunc(BitcodeModule module , DIFile diFile , IDebugType <ITypeRef, DIType> voidType , DIDerivedType constFoo , DebugPointerType fooPtr ) { // Since the first parameter is passed by value // using the pointer + alloca + memcopy pattern, the actual // source, and therefore debug, signature is NOT a pointer. // However, that usage would create a signature with two // pointers as the arguments, which doesn't match the source // To get the correct debug info signature this inserts an // explicit DebugType<> that overrides the default behavior // to pair the LLVM pointer type with the original source type. var copySig = module.Context.CreateFunctionType(module.DIBuilder , voidType , DebugType.Create(fooPtr, constFoo) , fooPtr ); var copyFunc = module.CreateFunction(scope: diFile , name: "copy" , linkageName: null , file: diFile , line: 11 , signature: copySig , isLocalToUnit: true , isDefinition: true , scopeLine: 14 , debugFlags: DebugInfoFlags.Prototyped , isOptimized: false ).Linkage(Linkage.Internal) // static function .AddAttributes(FunctionAttributeIndex.Function, AttributeKind.NoUnwind, AttributeKind.NoInline, AttributeKind.OptimizeNone) .AddAttributes(FunctionAttributeIndex.Function, TargetDependentAttributes); TargetDetails.AddABIAttributesForByValueStructure(copyFunc, 0); return(copyFunc); }
/// <summary>Creates a test LLVM module with debug information</summary> /// <param name="args">ignored</param> /// <remarks> /// <code language="c" title="Example code generated" source="test.c" /> /// </remarks> public static void Main(string[] args) { TargetDetails = new CortexM3Details(); string srcPath = args[0]; if (!File.Exists(srcPath)) { Console.Error.WriteLine("Src file not found: '{0}'", srcPath); return; } srcPath = Path.GetFullPath(srcPath); string moduleName = $"test_{TargetDetails.ShortName}.bc"; using (StaticState.InitializeLLVM()) { StaticState.RegisterAll( ); var target = Target.FromTriple(TargetDetails.Triple); using (var context = new Context( )) using (var targetMachine = target.CreateTargetMachine(TargetDetails.Triple, TargetDetails.Cpu, TargetDetails.Features, CodeGenOpt.Aggressive, Reloc.Default, CodeModel.Small)) using (var module = new BitcodeModule(context, moduleName)) { module.SourceFileName = Path.GetFileName(srcPath); TargetDependentAttributes = TargetDetails.BuildTargetDependentFunctionAttributes(context); var targetData = targetMachine.TargetData; module.TargetTriple = targetMachine.Triple; module.Layout = targetMachine.TargetData; // create compile unit and file as the top level scope for everything var cu = module.DIBuilder.CreateCompileUnit(SourceLanguage.C99 , Path.GetFileName(srcPath) , Path.GetDirectoryName(srcPath) , VersionIdentString , false , string.Empty , 0 ); var diFile = module.DIBuilder.CreateFile(srcPath); // Create basic types used in this compilation var i32 = new DebugBasicType(module.Context.Int32Type, module, "int", DiTypeKind.Signed); var f32 = new DebugBasicType(module.Context.FloatType, module, "float", DiTypeKind.Float); var voidType = DebugType.Create(module.Context.VoidType, ( DIType )null); var i32Array_0_32 = i32.CreateArrayType(module, 0, 32); // create the LLVM structure type and body with full debug information #pragma warning disable SA1500 // "Warning SA1500 Braces for multi - line statements must not share line" (simple table format) var fooBody = new[] { new DebugMemberInfo { File = diFile, Line = 3, Name = "a", DebugType = i32, Index = 0 } , new DebugMemberInfo { File = diFile, Line = 4, Name = "b", DebugType = f32, Index = 1 } , new DebugMemberInfo { File = diFile, Line = 5, Name = "c", DebugType = i32Array_0_32, Index = 2 } }; #pragma warning restore var fooType = new DebugStructType(module, "struct.foo", cu, "foo", diFile, 1, DebugInfoFlags.None, fooBody); // add global variables and constants var constArray = ConstantArray.From(i32, 32, module.Context.CreateConstant(3), module.Context.CreateConstant(4)); var barValue = module.Context.CreateNamedConstantStruct(fooType , module.Context.CreateConstant(1) , module.Context.CreateConstant(2.0f) , constArray ); var bar = module.AddGlobal(fooType, false, 0, barValue, "bar"); bar.Alignment = targetData.AbiAlignmentOf(fooType); bar.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(cu, "bar", string.Empty, diFile, 8, fooType.DIType, false, null)); var baz = module.AddGlobal(fooType, false, Linkage.Common, Constant.NullValueFor(fooType), "baz"); baz.Alignment = targetData.AbiAlignmentOf(fooType); baz.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(cu, "baz", string.Empty, diFile, 9, fooType.DIType, false, null)); // add module flags and compiler identifiers... // this can technically occur at any point, though placing it here makes // comparing against clang generated files easier AddModuleFlags(module); // create types for function args var constFoo = module.DIBuilder.CreateQualifiedType(fooType.DIType, QualifiedTypeTag.Const); var fooPtr = new DebugPointerType(fooType, module); // Create the functions // NOTE: The declaration ordering is reversed from that of the sample code file (test.c) // However, this is what Clang ends up doing for some reason so it is // replicated here to aid in comparing the generated LL files. Function doCopyFunc = DeclareDoCopyFunc(module, diFile, voidType); Function copyFunc = DeclareCopyFunc(module, diFile, voidType, constFoo, fooPtr); CreateCopyFunctionBody(module, targetData, copyFunc, diFile, fooType, fooPtr, constFoo); CreateDoCopyFunctionBody(module, targetData, doCopyFunc, fooType, bar, baz, copyFunc); // finalize the debug information // all temporaries must be replaced by now, this resolves any remaining // forward declarations and marks the builder to prevent adding any // nodes that are not completely resolved. module.DIBuilder.Finish( ); // verify the module is still good and print any errors found if (!module.Verify(out string msg)) { Console.Error.WriteLine("ERROR: {0}", msg); } else { // test optimization works, but don't save it as that makes it harder to do a diff with official clang builds {// force a GC to verify callback delegate for diagnostics is still valid, this is for test only and wouldn't // normally be done in production code. GC.Collect(GC.MaxGeneration); var modForOpt = module.Clone( ); // NOTE: // The ordering of passes can matter depending on the pass and passes may be added more than once // the caller has full control of ordering, this is just a sample of effectively randomly picked // passes and not necessarily a reflection of any particular use case. var pm = new ModulePassManager( ) .AddAlwaysInlinerPass( ) .AddAggressiveDCEPass( ) .AddArgumentPromotionPass( ) .AddBasicAliasAnalysisPass( ) .AddBitTrackingDCEPass( ) .AddCFGSimplificationPass( ) .AddConstantMergePass( ) .AddConstantPropagationPass( ) .AddFunctionInliningPass( ) .AddGlobalOptimizerPass( ) .AddInstructionCombiningPass( ); pm.Run(modForOpt); } // Module is good, so generate the output files module.WriteToFile("test.bc"); File.WriteAllText("test.ll", module.WriteToString( )); targetMachine.EmitToFile(module, "test.o", CodeGenFileType.ObjectFile); targetMachine.EmitToFile(module, "test.s", CodeGenFileType.AssemblySource); } } } }
public static void Main(string[] args) { #region CommandlineArguments if (args.Length < 2 || args.Length > 3) { ShowUsage( ); return; } string outputPath = args.Length == 3 ? args[2] : Environment.CurrentDirectory; string srcPath = args[1]; if (!File.Exists(srcPath)) { Console.Error.WriteLine("Src file not found: '{0}'", srcPath); return; } srcPath = Path.GetFullPath(srcPath); #endregion using var libLLVM = InitializeLLVM( ); #region TargetDetailsSelection switch (args[0].ToUpperInvariant( )) { case "M3": TargetDetails = new CortexM3Details(libLLVM); break; case "X64": TargetDetails = new X64Details(libLLVM); break; default: ShowUsage( ); return; } string moduleName = $"test_{TargetDetails.ShortName}.bc"; #endregion #region CreatingModule using var context = new Context( ); using var module = context.CreateBitcodeModule(moduleName, SourceLanguage.C99, srcPath, VersionIdentString); module.SourceFileName = Path.GetFileName(srcPath); module.TargetTriple = TargetDetails.TargetMachine.Triple; module.Layout = TargetDetails.TargetMachine.TargetData; Debug.Assert(!(module.DICompileUnit is null), "Expected module with non-null compile unit"); TargetDependentAttributes = TargetDetails.BuildTargetDependentFunctionAttributes(context); #endregion var diFile = module.DIBuilder.CreateFile(srcPath); #region CreatingBasicTypesWithDebugInfo // Create basic types used in this compilation var i32 = new DebugBasicType(module.Context.Int32Type, module, "int", DiTypeKind.Signed); var f32 = new DebugBasicType(module.Context.FloatType, module, "float", DiTypeKind.Float); var voidType = DebugType.Create <ITypeRef, DIType>(module.Context.VoidType, null); var i32Array_0_32 = i32.CreateArrayType(module, 0, 32); #endregion #region CreatingStructureTypes // create the LLVM structure type and body with full debug information var fooBody = new[] { new DebugMemberInfo(0, "a", diFile, 3, i32), new DebugMemberInfo(1, "b", diFile, 4, f32), new DebugMemberInfo(2, "c", diFile, 5, i32Array_0_32), }; var fooType = new DebugStructType(module, "struct.foo", module.DICompileUnit, "foo", diFile, 1, DebugInfoFlags.None, fooBody); #endregion #region CreatingGlobalsAndMetadata // add global variables and constants var constArray = ConstantArray.From(i32, 32, module.Context.CreateConstant(3), module.Context.CreateConstant(4)); var barValue = module.Context.CreateNamedConstantStruct(fooType , module.Context.CreateConstant(1) , module.Context.CreateConstant(2.0f) , constArray ); var bar = module.AddGlobal(fooType, false, 0, barValue, "bar"); bar.Alignment = module.Layout.AbiAlignmentOf(fooType); bar.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(module.DICompileUnit, "bar", string.Empty, diFile, 8, fooType.DIType, false, null)); var baz = module.AddGlobal(fooType, false, Linkage.Common, Constant.NullValueFor(fooType), "baz"); baz.Alignment = module.Layout.AbiAlignmentOf(fooType); baz.AddDebugInfo(module.DIBuilder.CreateGlobalVariableExpression(module.DICompileUnit, "baz", string.Empty, diFile, 9, fooType.DIType, false, null)); // add module flags and compiler identifiers... // this can technically occur at any point, though placing it here makes // comparing against clang generated files easier AddModuleFlags(module); #endregion #region CreatingQualifiedTypes // create types for function args var constFoo = module.DIBuilder.CreateQualifiedType(fooType.DIType, QualifiedTypeTag.Const); var fooPtr = new DebugPointerType(fooType, module); #endregion // Create the functions // NOTE: The declaration ordering is reversed from that of the sample code file (test.c) // However, this is what Clang ends up doing for some reason so it is // replicated here to aid in comparing the generated LL files. IrFunction doCopyFunc = DeclareDoCopyFunc(module, diFile, voidType); IrFunction copyFunc = DeclareCopyFunc(module, diFile, voidType, constFoo, fooPtr); CreateCopyFunctionBody(module, copyFunc, diFile, fooType, fooPtr, constFoo); CreateDoCopyFunctionBody(module, doCopyFunc, fooType, bar, baz, copyFunc); // finalize the debug information // all temporaries must be replaced by now, this resolves any remaining // forward declarations and marks the builder to prevent adding any // nodes that are not completely resolved. module.DIBuilder.Finish( ); // verify the module is still good and print any errors found if (!module.Verify(out string msg)) { Console.Error.WriteLine("ERROR: {0}", msg); } else { // test optimization works, but don't save it as that makes it harder to do a compare with official clang builds {// force a GC to verify callback delegate for diagnostics is still valid, this is for test only and wouldn't // normally be done in production code. GC.Collect(GC.MaxGeneration); using var modForOpt = module.Clone( ); // NOTE: // The ordering of passes can matter depending on the pass, and passes may be added more than once // the caller has full control of ordering, this is just a sample of effectively randomly picked // passes and not necessarily a reflection of any particular use case. using var pm = new ModulePassManager( ); pm.AddAlwaysInlinerPass( ) .AddAggressiveDCEPass( ) .AddArgumentPromotionPass( ) .AddBasicAliasAnalysisPass( ) .AddBitTrackingDCEPass( ) .AddCFGSimplificationPass( ) .AddConstantMergePass( ) .AddConstantPropagationPass( ) .AddFunctionInliningPass( ) .AddGlobalOptimizerPass( ) .AddInstructionCombiningPass( ) .Run(modForOpt); } // Module is good, so generate the output files module.WriteToFile(Path.Combine(outputPath, "test.bc")); File.WriteAllText(Path.Combine(outputPath, "test.ll"), module.WriteToString( )); TargetDetails.TargetMachine.EmitToFile(module, Path.Combine(outputPath, "test.o"), CodeGenFileType.ObjectFile); TargetDetails.TargetMachine.EmitToFile(module, Path.Combine(outputPath, "test.s"), CodeGenFileType.AssemblySource); Console.WriteLine("Generated test.bc, test.ll, test.o, and test.s"); } }
public static List <AbstractNode> GetDebugInfo(Process process, ICorDebugValue corValue) { List <AbstractNode> items = new List <AbstractNode>(); if (corValue.Is <ICorDebugValue>()) { InfoNode info = new InfoNode("ICorDebugValue", ""); info.AddChild("Address", corValue.Address.ToString("X8")); info.AddChild("Type", ((CorElementType)corValue.Type).ToString()); info.AddChild("Size", corValue.Size.ToString()); items.Add(info); } if (corValue.Is <ICorDebugValue2>()) { InfoNode info = new InfoNode("ICorDebugValue2", ""); ICorDebugValue2 corValue2 = corValue.CastTo <ICorDebugValue2>(); string fullname; try { fullname = DebugType.Create(process, corValue2.ExactType).FullName; } catch (DebuggerException e) { fullname = e.Message; } info.AddChild("ExactType", fullname); items.Add(info); } if (corValue.Is <ICorDebugGenericValue>()) { InfoNode info = new InfoNode("ICorDebugGenericValue", ""); try { byte[] bytes = corValue.CastTo <ICorDebugGenericValue>().RawValue; for (int i = 0; i < bytes.Length; i += 8) { string val = ""; for (int j = i; j < bytes.Length && j < i + 8; j++) { val += bytes[j].ToString("X2") + " "; } info.AddChild("Value" + i.ToString("X2"), val); } } catch (ArgumentException) { info.AddChild("Value", "N/A"); } items.Add(info); } if (corValue.Is <ICorDebugReferenceValue>()) { InfoNode info = new InfoNode("ICorDebugReferenceValue", ""); ICorDebugReferenceValue refValue = corValue.CastTo <ICorDebugReferenceValue>(); info.AddChild("IsNull", (refValue.IsNull != 0).ToString()); if (refValue.IsNull == 0) { info.AddChild("Value", refValue.Value.ToString("X8")); if (refValue.Dereference() != null) { info.AddChild("Dereference", "", GetDebugInfo(process, refValue.Dereference())); } else { info.AddChild("Dereference", "N/A"); } } items.Add(info); } if (corValue.Is <ICorDebugHeapValue>()) { InfoNode info = new InfoNode("ICorDebugHeapValue", ""); items.Add(info); } if (corValue.Is <ICorDebugHeapValue2>()) { InfoNode info = new InfoNode("ICorDebugHeapValue2", ""); items.Add(info); } if (corValue.Is <ICorDebugObjectValue>()) { InfoNode info = new InfoNode("ICorDebugObjectValue", ""); ICorDebugObjectValue objValue = corValue.CastTo <ICorDebugObjectValue>(); info.AddChild("Class", objValue.Class.Token.ToString("X8")); info.AddChild("IsValueClass", (objValue.IsValueClass != 0).ToString()); items.Add(info); } if (corValue.Is <ICorDebugObjectValue2>()) { InfoNode info = new InfoNode("ICorDebugObjectValue2", ""); items.Add(info); } if (corValue.Is <ICorDebugBoxValue>()) { InfoNode info = new InfoNode("ICorDebugBoxValue", ""); ICorDebugBoxValue boxValue = corValue.CastTo <ICorDebugBoxValue>(); info.AddChild("Object", "", GetDebugInfo(process, boxValue.Object.CastTo <ICorDebugValue>())); items.Add(info); } if (corValue.Is <ICorDebugStringValue>()) { InfoNode info = new InfoNode("ICorDebugStringValue", ""); ICorDebugStringValue stringValue = corValue.CastTo <ICorDebugStringValue>(); info.AddChild("Length", stringValue.Length.ToString()); info.AddChild("String", stringValue.String); items.Add(info); } if (corValue.Is <ICorDebugArrayValue>()) { InfoNode info = new InfoNode("ICorDebugArrayValue", ""); info.AddChild("...", "..."); items.Add(info); } if (corValue.Is <ICorDebugHandleValue>()) { InfoNode info = new InfoNode("ICorDebugHandleValue", ""); ICorDebugHandleValue handleValue = corValue.CastTo <ICorDebugHandleValue>(); info.AddChild("HandleType", handleValue.HandleType.ToString()); items.Add(info); } return(items); }