Beispiel #1
0
        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);
        }
Beispiel #2
0
        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()));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
 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);
     }
 }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        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; }));
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        /// <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);
                            }
                        }
            }
        }
Beispiel #10
0
        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");
            }
        }
Beispiel #11
0
        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);
        }