private DkmSuccessEvaluationResult(
     DkmInspectionContext inspectionContext,
     DkmStackWalkFrame stackFrame,
     string name,
     string fullName,
     DkmEvaluationResultFlags flags,
     string value,
     string editableValue,
     string type,
     DkmEvaluationResultCategory category,
     DkmEvaluationResultAccessType access,
     DkmEvaluationResultStorageType storageType,
     DkmEvaluationResultTypeModifierFlags typeModifierFlags,
     DkmDataAddress address,
     ReadOnlyCollection<DkmCustomUIVisualizerInfo> customUIVisualizers,
     ReadOnlyCollection<DkmModuleInstance> externalModules,
     DkmDataItem dataItem) :
     base(inspectionContext, stackFrame, name, fullName, flags, type, dataItem)
 {
     this.Value = value;
     this.EditableValue = editableValue;
     this.Category = category;
     this.Access = access;
     this.StorageType = storageType;
     this.TypeModifierFlags = typeModifierFlags;
     this.CustomUIVisualizers = customUIVisualizers;
 }
Esempio n. 2
0
 private DkmSuccessEvaluationResult(
     DkmInspectionContext inspectionContext,
     DkmStackWalkFrame stackFrame,
     string name,
     string fullName,
     DkmEvaluationResultFlags flags,
     string value,
     string editableValue,
     string type,
     DkmEvaluationResultCategory category,
     DkmEvaluationResultAccessType access,
     DkmEvaluationResultStorageType storageType,
     DkmEvaluationResultTypeModifierFlags typeModifierFlags,
     DkmDataAddress address,
     ReadOnlyCollection <DkmCustomUIVisualizerInfo> customUIVisualizers,
     ReadOnlyCollection <DkmModuleInstance> externalModules,
     DkmDataItem dataItem) :
     base(inspectionContext, stackFrame, name, fullName, flags, type, dataItem)
 {
     this.Value               = value;
     this.EditableValue       = editableValue;
     this.Category            = category;
     this.Access              = access;
     this.StorageType         = storageType;
     this.TypeModifierFlags   = typeModifierFlags;
     this.CustomUIVisualizers = customUIVisualizers;
 }
Esempio n. 3
0
        internal static DkmEvaluationResult GetLuaFunctionChildAtIndex(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame, string fullName, LuaClosureData value, int index)
        {
            var process = stackFrame.Process;

            var processData = DebugHelpers.GetOrCreateDataItem <LuaLocalProcessData>(process);

            if (index == 0)
            {
                if (value == null)
                {
                    return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "null", DkmEvaluationResultFlags.Invalid, null));
                }

                var functionData = value.ReadFunction(process);

                if (functionData == null)
                {
                    return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "[internal error: failed to read Proto]", DkmEvaluationResultFlags.Invalid, null));
                }

                string source = functionData.ReadSource(process);

                if (source == null)
                {
                    return(DkmFailedEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", "[internal error: failed to read source]", DkmEvaluationResultFlags.Invalid, null));
                }

                int line = functionData.definitionStartLine_opt;

                DkmEvaluationResultCategory          category      = DkmEvaluationResultCategory.Method;
                DkmEvaluationResultTypeModifierFlags typeModifiers = DkmEvaluationResultTypeModifierFlags.None;
                DkmEvaluationResultAccessType        access        = DkmEvaluationResultAccessType.Public;
                DkmEvaluationResultStorageType       storage       = DkmEvaluationResultStorageType.Global;

                LuaAddressEntityData entityData = new LuaAddressEntityData
                {
                    source = source,
                    line   = line,

                    functionAddress            = 0,
                    functionInstructionPointer = 0,
                };

                var entityDataBytes = entityData.Encode();

                DkmInstructionAddress instructionAddress = DkmCustomInstructionAddress.Create(processData.runtimeInstance, processData.moduleInstance, entityDataBytes, (ulong)((line << 16) + 0), null, null);

                DkmDataAddress dataAddress = DkmDataAddress.Create(processData.runtimeInstance, value.functionAddress, instructionAddress);

                return(DkmSuccessEvaluationResult.Create(inspectionContext, stackFrame, "[function]", $"{fullName}.!function", DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Address, $"{source}:{line}", null, "Proto*", category, access, storage, typeModifiers, dataAddress, null, null, null));
            }

            Debug.Assert(false, "Invalid child index");

            return(null);
        }
        public static DkmSuccessEvaluationResult Create(DkmInspectionContext InspectionContext, DkmStackWalkFrame StackFrame, string Name, string FullName, DkmEvaluationResultFlags Flags, string Value, string EditableValue, string Type, DkmEvaluationResultCategory Category, DkmEvaluationResultAccessType Access, DkmEvaluationResultStorageType StorageType, DkmEvaluationResultTypeModifierFlags TypeModifierFlags, DkmDataAddress Address, ReadOnlyCollection<DkmCustomUIVisualizerInfo> CustomUIVisualizers, ReadOnlyCollection<DkmModuleInstance> ExternalModules, DkmDataItem DataItem)
        {
            DkmSuccessEvaluationResult result = new DkmSuccessEvaluationResult
            {
                InspectionContext = InspectionContext,
                Name = Name,
                FullName = FullName,
                Flags = Flags,
                Value = Value,
                Type = Type,
                Category = Category,
                EditableValue = EditableValue,
                CustomUIVisualizers = CustomUIVisualizers
            };

            if (DataItem != null)
            {
                result.SetDataItem(DkmDataCreationDisposition.CreateNew, DataItem);
            }

            return result;
        }
Esempio n. 5
0
 public static DkmSuccessEvaluationResult Create(
     DkmInspectionContext InspectionContext,
     DkmStackWalkFrame StackFrame,
     string Name,
     string FullName,
     DkmEvaluationResultFlags Flags,
     string Value,
     string EditableValue,
     string Type,
     DkmEvaluationResultCategory Category,
     DkmEvaluationResultAccessType Access,
     DkmEvaluationResultStorageType StorageType,
     DkmEvaluationResultTypeModifierFlags TypeModifierFlags,
     DkmDataAddress Address,
     ReadOnlyCollection <DkmCustomUIVisualizerInfo> CustomUIVisualizers,
     ReadOnlyCollection <DkmModuleInstance> ExternalModules,
     DkmDataItem DataItem
     )
 {
     return(new DkmSuccessEvaluationResult(
                InspectionContext,
                StackFrame,
                Name,
                FullName,
                Flags,
                Value,
                EditableValue,
                Type,
                Category,
                Access,
                StorageType,
                TypeModifierFlags,
                Address,
                CustomUIVisualizers,
                ExternalModules,
                DataItem
                ));
 }
 public static DkmSuccessEvaluationResult Create(
     DkmInspectionContext InspectionContext,
     DkmStackWalkFrame StackFrame,
     string Name,
     string FullName,
     DkmEvaluationResultFlags Flags,
     string Value,
     string EditableValue,
     string Type,
     DkmEvaluationResultCategory Category,
     DkmEvaluationResultAccessType Access,
     DkmEvaluationResultStorageType StorageType,
     DkmEvaluationResultTypeModifierFlags TypeModifierFlags,
     DkmDataAddress Address,
     ReadOnlyCollection<DkmCustomUIVisualizerInfo> CustomUIVisualizers,
     ReadOnlyCollection<DkmModuleInstance> ExternalModules,
     DkmDataItem DataItem)
 {
     return new DkmSuccessEvaluationResult(
         InspectionContext,
         StackFrame,
         Name,
         FullName,
         Flags,
         Value,
         EditableValue,
         Type,
         Category,
         Access,
         StorageType,
         TypeModifierFlags,
         Address,
         CustomUIVisualizers,
         ExternalModules,
         DataItem);
 }
        /// <summary>
        /// Evaluates visual expression and converts it to result visualizer.
        /// </summary>
        private void Evaluate()
        {
            if (VisualizedExpression.TagValue == DkmVisualizedExpression.Tag.RootVisualizedExpression)
            {
                DkmRootVisualizedExpression rootVisualizedExpression = VisualizedExpression as DkmRootVisualizedExpression;
                int    processId  = rootVisualizedExpression.InspectionSession?.Process?.LivePart?.Id ?? 0;
                string moduleName = rootVisualizedExpression.Module?.Name;
                string typeString = rootVisualizedExpression.Type;
                ulong  address    = 0;
                bool   hasAddress = false;

                if (VisualizedExpression.ValueHome.TagValue == DkmExpressionValueHome.Tag.PointerValueHome)
                {
                    address    = (VisualizedExpression.ValueHome as DkmPointerValueHome).Address;
                    hasAddress = true;
                }

                if (string.IsNullOrEmpty(typeString) || string.IsNullOrEmpty(moduleName) || !hasAddress)
                {
                    string displayString = "{...CsDebugScript failure...}";

                    EvaluationResult = DkmSuccessEvaluationResult.Create(
                        VisualizedExpression.InspectionContext,
                        VisualizedExpression.StackFrame,
                        rootVisualizedExpression.Name,
                        rootVisualizedExpression.FullName,
                        DkmEvaluationResultFlags.ReadOnly,
                        displayString,
                        "",
                        rootVisualizedExpression.Type,
                        DkmEvaluationResultCategory.Other,
                        DkmEvaluationResultAccessType.None,
                        DkmEvaluationResultStorageType.None,
                        DkmEvaluationResultTypeModifierFlags.None,
                        null,
                        null,
                        null,
                        null);
                    return;
                }

                string title;

                try
                {
                    Process  process  = Process.All.First(p => p.SystemId == processId);
                    Module   module   = process.ModulesByName[System.IO.Path.GetFileNameWithoutExtension(moduleName)];
                    CodeType codeType = ResolveCodeType(process, module, typeString);

                    Variable         = codeType.IsPointer ? Variable.CreatePointer(codeType, address) : Variable.Create(codeType, address);
                    title            = Variable.ToString();
                    ResultVisualizer = CsDebugScript.UI.ResultVisualizers.ResultVisualizer.Create(Variable, Variable.GetType(), "result", CompletionDataType.Unknown, dummyInteractiveResultVisualizer);
                }
                catch
                {
                    title = "{...CsDebugScript...}";
                }

                DkmDataAddress dkmDataAddress = DkmDataAddress.Create(VisualizedExpression.RuntimeInstance, address, rootVisualizedExpression.StackFrame?.InstructionAddress);

                EvaluationResult = DkmSuccessEvaluationResult.Create(
                    VisualizedExpression.InspectionContext,
                    VisualizedExpression.StackFrame,
                    rootVisualizedExpression.Name,
                    rootVisualizedExpression.FullName,
                    DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable,
                    title,
                    "",
                    rootVisualizedExpression.Type,
                    DkmEvaluationResultCategory.Other,
                    DkmEvaluationResultAccessType.None,
                    DkmEvaluationResultStorageType.None,
                    DkmEvaluationResultTypeModifierFlags.None,
                    dkmDataAddress,
                    VSUIVisualizerService.GetUIVisualizers(ResultVisualizer),
                    null,
                    null);
                return;
            }

            // This should never happen...
            throw new NotImplementedException();
        }
Esempio n. 8
0
        internal static string EvaluateValueAtAddress(DkmProcess process, ulong address, uint radix, out string editableValue, ref DkmEvaluationResultFlags flags, out DkmDataAddress dataAddress, out string type, out LuaValueDataBase luaValueData)
        {
            editableValue = null;
            dataAddress   = null;
            type          = "unknown";

            luaValueData = LuaHelpers.ReadValue(process, address);

            if (luaValueData == null)
            {
                return(null);
            }

            return(EvaluateValueAtLuaValue(process, luaValueData, radix, out editableValue, ref flags, out dataAddress, out type));
        }
Esempio n. 9
0
        internal static string EvaluateValueAtLuaValue(DkmProcess process, LuaValueDataBase valueBase, uint radix, out string editableValue, ref DkmEvaluationResultFlags flags, out DkmDataAddress dataAddress, out string type)
        {
            editableValue = null;
            dataAddress   = null;
            type          = "unknown";

            if (valueBase == null)
            {
                return(null);
            }

            if (valueBase as LuaValueDataNil != null)
            {
                type = "nil";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly;
                return("nil");
            }

            if (valueBase as LuaValueDataBool != null)
            {
                var value = valueBase as LuaValueDataBool;

                type = "bool";

                if (value.value)
                {
                    flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.Boolean | DkmEvaluationResultFlags.BooleanTrue;
                    editableValue = $"{value.value}";
                    return("true");
                }
                else
                {
                    flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.Boolean;
                    editableValue = $"{value.value}";
                    return("false");
                }
            }

            if (valueBase as LuaValueDataLightUserData != null)
            {
                var value = valueBase as LuaValueDataLightUserData;

                type = "user_data";

                flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                editableValue = $"{value.value}";
                return($"0x{value.value:x}");
            }

            if (valueBase as LuaValueDataNumber != null)
            {
                var value = valueBase as LuaValueDataNumber;

                if (value.extendedType == LuaHelpers.GetIntegerNumberExtendedType())
                {
                    type = "int";

                    flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                    editableValue = $"{value.value}";

                    if (radix == 16)
                    {
                        return($"0x{(int)value.value:x8}");
                    }

                    return($"{value.value}");
                }
                else
                {
                    type = "double";

                    flags        |= DkmEvaluationResultFlags.IsBuiltInType;
                    editableValue = $"{value.value}";
                    return($"{value.value}");
                }
            }

            if (valueBase as LuaValueDataString != null)
            {
                var value = valueBase as LuaValueDataString;

                type = value.extendedType == LuaExtendedType.ShortString ? "short_string" : "long_string";

                flags        |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.RawString;
                editableValue = $"{value.value}";
                dataAddress   = DkmDataAddress.Create(process.GetNativeRuntimeInstance(), value.targetAddress, null);
                return($"0x{value.targetAddress:x} \"{value.value}\"");
            }

            if (valueBase as LuaValueDataTable != null)
            {
                var value = valueBase as LuaValueDataTable;

                type = "table";

                flags |= DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;

                var arrayElementCount = value.value.GetArrayElementCount(process);
                var nodeElementCount  = value.value.GetNodeElementCount(process);

                if (arrayElementCount != 0 && nodeElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{arrayElementCount} element(s) and {nodeElementCount} key(s)]");
                }

                if (arrayElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{arrayElementCount} element(s)]");
                }

                if (nodeElementCount != 0)
                {
                    return($"0x{value.targetAddress:x} table [{nodeElementCount} key(s)]");
                }

                if (!value.value.HasMetaTable())
                {
                    flags &= ~DkmEvaluationResultFlags.Expandable;

                    return($"0x{value.targetAddress:x} table [empty]");
                }

                return($"0x{value.targetAddress:x} table");
            }

            if (valueBase as LuaValueDataLuaFunction != null)
            {
                var value = valueBase as LuaValueDataLuaFunction;

                type = "lua_function";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataExternalFunction != null)
            {
                var value = valueBase as LuaValueDataExternalFunction;

                type = "c_function";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataExternalClosure != null)
            {
                var value = valueBase as LuaValueDataExternalClosure;

                type = "c_closure";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataUserData != null)
            {
                var value = valueBase as LuaValueDataUserData;

                type = "user_data";

                flags |= DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable;
                return($"0x{value.targetAddress:x}");
            }

            if (valueBase as LuaValueDataThread != null)
            {
                var value = valueBase as LuaValueDataThread;

                type = "thread";

                flags |= DkmEvaluationResultFlags.IsBuiltInType | DkmEvaluationResultFlags.ReadOnly;
                return($"0x{value.targetAddress:x}");
            }

            return(null);
        }
Esempio n. 10
0
        public static DkmSuccessEvaluationResult Create(DkmInspectionContext InspectionContext, DkmStackWalkFrame StackFrame, string Name, string FullName, DkmEvaluationResultFlags Flags, string Value, string EditableValue, string Type, DkmEvaluationResultCategory Category, DkmEvaluationResultAccessType Access, DkmEvaluationResultStorageType StorageType, DkmEvaluationResultTypeModifierFlags TypeModifierFlags, DkmDataAddress Address, ReadOnlyCollection <DkmCustomUIVisualizerInfo> CustomUIVisualizers, ReadOnlyCollection <DkmModuleInstance> ExternalModules, DkmDataItem DataItem)
        {
            DkmSuccessEvaluationResult result = new DkmSuccessEvaluationResult
            {
                InspectionContext = InspectionContext,
                Name                = Name,
                FullName            = FullName,
                Flags               = Flags,
                Value               = Value,
                Type                = Type,
                Category            = Category,
                EditableValue       = EditableValue,
                CustomUIVisualizers = CustomUIVisualizers
            };

            if (DataItem != null)
            {
                result.SetDataItem(DkmDataCreationDisposition.CreateNew, DataItem);
            }

            return(result);
        }
Esempio n. 11
0
        protected void EvaluateExpressionResult()
        {
            // We're going to customize the unexpanded display string, as well as the expanded
            // view (if requested later).

            // @TODO: Really don't understand why, but when we invoke the default eval below, and we get
            // reentrant calls for child member UObjects, they are coming back as root expressions
            // with an empty FullName. This subsequently fails to evaluate if we pass it through to
            // default eval again. Perhaps this is somehow related to breaking the potential infinite
            // recursion of visualizing children in order to visualize the parent, but don't follow how it
            // it supposed to be dealt with.
            if (expression_.TagValue == DkmVisualizedExpression.Tag.RootVisualizedExpression)
            {
                var as_root = expression_ as DkmRootVisualizedExpression;
                if (as_root.FullName.Length == 0)
                {
                    string display_str = "{...}";
                    eval_ = DkmSuccessEvaluationResult.Create(
                        expression_.InspectionContext,
                        expression_.StackFrame,
                        as_root.Name,
                        as_root.Name,
                        DkmEvaluationResultFlags.ReadOnly,
                        display_str,
                        "",
#if !VS2013
                        as_root.Type,
#else
                        "Unknown",
#endif
                        DkmEvaluationResultCategory.Other,
                        DkmEvaluationResultAccessType.None,
                        DkmEvaluationResultStorageType.None,
                        DkmEvaluationResultTypeModifierFlags.None,
                        null,
                        null,
                        null,
                        null
                        );
                    state_ = EvaluationState.MinimalEvaluation;
                    return;
                }
            }
            //

            string custom_display_str             = Resources.UE4PropVis.IDS_DISP_CONDENSED;
            DkmSuccessEvaluationResult proto_eval = null;
            bool   is_pointer;
            bool   is_null;
            string address_str = "";

            // @NOTE: Initially here we were executing the full default evaluation of our expression.
            // Problem is that this will call back into us for all UObject children of the expression,
            // because it needs to generate a visualization for them in order to construct its {member vals...} display string.
            // And then, we just ignore that anyway and display our own...

            // The following attempts to avoid that by casting our expression to void* and then evaluating that.
            // If it fails, we assume we are non-pointer. If it succeeds, we can determine from the result whether we are null or not.

            // @WARNING: This may not be so safe, since we can't determine whether evaluation failed because we tried to cast a non-pointer
            // to void*, or because the passed in expression was not valid in the first place. Believe we should be okay, since we should
            // only be receiving expressions that have already been determined to be suitable for our custom visualizer.

            // Ideally though, we'd be able to get a raw expression evaluation, without any visualization taking place.
            // Seems there must be a way to do this, but looks like it requires using a different API...
            const bool UseVoidCastOptimization = true;

            string default_expr_str = Utility.GetExpressionFullName(expression_);
            if (UseVoidCastOptimization)
            {
                default_expr_str = ExpressionManipulator.FromExpression(default_expr_str).PtrCast(Cpp.Void).Expression;
            }

            DkmEvaluationResult eval = DefaultEE.DefaultEval(default_expr_str, expression_, true);

            if (!UseVoidCastOptimization)
            {
                if (eval.TagValue != DkmEvaluationResult.Tag.SuccessResult)
                {
                    // Genuine failure to evaluate the passed in expression
                    eval_  = eval;
                    state_ = EvaluationState.Failed;
                    return;
                }
                else
                {
                    proto_eval         = (DkmSuccessEvaluationResult)eval;
                    custom_display_str = proto_eval.Value;

                    is_pointer = IsPointer(proto_eval);
                    is_null    = is_pointer && IsPointerNull(proto_eval);
                    // @TODO: need to extract address string
                }
            }
            else
            {
                DkmDataAddress address = null;
                if (eval.TagValue != DkmEvaluationResult.Tag.SuccessResult)
                {
                    // Assume the failure just implies the expression was non-pointer (thereby assuming that it was itself valid!)

                    // @TODO: Could actually fall back onto standard evaluation here, in order to determine for sure
                    // that the original expression is valid. Failure wouldn't be common since most of the time we are
                    // dealing with pointer expressions, so any potential optimization should still be gained.

                    is_pointer = false;
                    is_null    = false;
                }
                else
                {
                    var success = (DkmSuccessEvaluationResult)eval;
                    Debug.Assert(IsPointer(success));
                    is_pointer  = true;
                    is_null     = is_pointer && IsPointerNull(success);
                    address     = success.Address;
                    address_str = success.Value;
                }

                proto_eval = DkmSuccessEvaluationResult.Create(
                    expression_.InspectionContext,
                    expression_.StackFrame,
                    "",
                    "",
                    DkmEvaluationResultFlags.ReadOnly | DkmEvaluationResultFlags.Expandable,
                    "",
                    "",
#if !VS2013
                    Utility.GetExpressionType(expression_),
#else
                    is_pointer ? "UObject *" : "UObject",
#endif
                    DkmEvaluationResultCategory.Other,
                    DkmEvaluationResultAccessType.None,
                    DkmEvaluationResultStorageType.None,
                    DkmEvaluationResultTypeModifierFlags.None,
                    address,
                    null,
                    null,
                    null
                    );
            }

            string obj_expression_str = Utility.GetExpressionFullName(expression_);
            var    obj_em             = ExpressionManipulator.FromExpression(obj_expression_str);

            // Store pointer flags on the expression
            expression_.SetDataItem(
                DkmDataCreationDisposition.CreateAlways,
                new UObjectDataItem(is_pointer, is_null)
                );

            if (!is_pointer)
            {
                // All subsequent manipulations of the expression assume it starts as a pointer to a
                // UObject-derived class, so if our expression is to a dereferenced UObject, just
                // prefix an 'address of' to the expression string.
                obj_em = obj_em.AddressOf();
            }

            // Generate the condensed display string.
            if (is_null)
            {
                if (Config.CustomNullObjectPreview)
                {
                    custom_display_str = "<NULL> UObject";
                }
                else
                {
                    var null_eval = DefaultEE.DefaultEval("(void*)0", expression_, true) as DkmSuccessEvaluationResult;
                    custom_display_str = null_eval.Value + " <NULL>";
                }
            }
            else if (Config.DisplayUObjectPreview)
            {
                // Prefix the address, if this is a pointer expression
                string address_prefix_str = "";
                if (is_pointer)
                {
                    address_prefix_str = address_str + " ";
                }

                // Specialized display for UClass?
                bool uclass_specialized = false;
                if (Config.DisplaySpecializedUClassPreview)
                {
                    var    uclass_em = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass);
                    var    _uclass_fname_expr_str = uclass_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression;
                    string _obj_uclass_name_str   = UE4Utility.GetFNameAsString(_uclass_fname_expr_str, expression_);
                    // @TODO: To simplify and for performance reasons, just hard coding known UClass variants
                    if (_obj_uclass_name_str == "Class" ||
                        _obj_uclass_name_str == "BlueprintGeneratedClass" ||
                        _obj_uclass_name_str == "WidgetBlueprintGeneratedClass")
                    {
                        var    fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression;
                        string obj_name_str   = UE4Utility.GetFNameAsString(fname_expr_str, expression_);

                        var parent_uclass_fname_expr_str = obj_em.PtrCast(Typ.UStruct).PtrMember(Memb.SuperStruct).PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression;
                        // This will return null if lookup failed for any reason.
                        // We'll assume this meant no super class exists (ie. we're dealing with UClass itself)
                        string parent_uclass_name_str = UE4Utility.GetFNameAsString(parent_uclass_fname_expr_str, expression_);
                        if (parent_uclass_name_str == null)
                        {
                            parent_uclass_name_str = "None";
                        }

                        custom_display_str = String.Format(
                            "{0}{{ClassName='{1}', Parent='{2}'}}",
                            address_prefix_str,
                            obj_name_str,
                            parent_uclass_name_str
                            );
                        uclass_specialized = true;
                    }
                }

                if (!uclass_specialized)
                {
                    // For standard UObject condensed display string, show the object FName and its UClass.
                    // @TODO: The evaluations required for this may be a performance issue, since they'll be done for all UObject children of any default visualized
                    // aggregate type, even when it is not expanded (the default behaviour is to create a {...} display list of child member visualizations).
                    var    fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression;
                    string obj_name_str   = UE4Utility.GetFNameAsString(fname_expr_str, expression_);

                    var    uclass_fname_expr_str = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass).PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjName).Expression;
                    string obj_uclass_name_str   = UE4Utility.GetFNameAsString(uclass_fname_expr_str, expression_);

                    custom_display_str = String.Format(
                        "{0}{{Name='{1}', Class='{2}'}}",
                        address_prefix_str,
                        obj_name_str,
                        obj_uclass_name_str
                        );
                }
            }

            eval_ = DkmSuccessEvaluationResult.Create(
                proto_eval.InspectionContext,
                proto_eval.StackFrame,
                // Override the eval name with the original expression name, since it will
                // have inherited the ",!" suffix.
                Utility.GetExpressionName(expression_),
                Utility.GetExpressionFullName(expression_),
                proto_eval.Flags,
                custom_display_str,                //success_eval.Value,
                proto_eval.EditableValue,
                proto_eval.Type,
                proto_eval.Category,
                proto_eval.Access,
                proto_eval.StorageType,
                proto_eval.TypeModifierFlags,
                proto_eval.Address,
                proto_eval.CustomUIVisualizers,
                proto_eval.ExternalModules,
                null
                );
            state_ = EvaluationState.Evaluated;
        }