public static BoolEvaluation TestUClassFlags(string uclass_expr_str, string flags, DkmVisualizedExpression context_expr) { ExpressionManipulator em = ExpressionManipulator.FromExpression(uclass_expr_str); em = em.PtrCast(Typ.UClass).PtrMember(Memb.ClassFlags); var class_flags_expr_str = em.Expression; // @TODO: Could do the flag test on this side by hard coding in the value of RF_Native, but for now // doing it the more robust way, and evaluating the expression in the context of the debugee. return(TestExpressionFlags(class_flags_expr_str, flags, context_expr)); }
// Given an expression which resolves to a pointer of any kind, returns the pointer value as an integer. public static ulong EvaluatePointerAddress(string pointer_expr_str, DkmVisualizedExpression context_expr) { ExpressionManipulator em = ExpressionManipulator.FromExpression(pointer_expr_str); // Cast to void* to avoid unnecessary visualization processing. string address_expr_str = em.PtrCast(Cpp.Void).Expression; var address_eval = (DkmEvaluationResult)DefaultEE.DefaultEval(address_expr_str, context_expr, true); if (address_eval.TagValue == DkmEvaluationResult.Tag.SuccessResult) { var eval = address_eval as DkmSuccessEvaluationResult; return(eval.Address != null ? eval.Address.Value : 0); } return(0); }
// Flags should be in a form that can be inserted into a bit test expression in the // debuggee context (eg. a raw integer, or a combination of RF_*** flags) public static bool TestUObjectFlags(string uobj_expr_str, string flags, DkmVisualizedExpression context_expr) { ExpressionManipulator em = ExpressionManipulator.FromExpression(uobj_expr_str); em = em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjFlags); var obj_flags_expr_str = em.Expression; // @NOTE: Value string is formatted as 'RF_... | RF_... (<integer value>)' // So for now, rather than extracting what we want, just inject the full expression for // the flags member into the below flag test expression. //string obj_flags_str = ((DkmSuccessEvaluationResult)obj_flags_expr.EvaluationResult).Value; // @TODO: Could do the flag test on this side by hard coding in the value of RF_Native, but for now // doing it the more robust way, and evaluating the expression in the context of the debugee. string flag_test_expr_str = String.Format( "({0} & {1}) != 0", obj_flags_expr_str, flags ); return(EvaluateBooleanExpression(flag_test_expr_str, context_expr)); }
public bool DetermineObjectCanHaveProperties() { switch (Config.PropertyDisplayPolicy) { case Config.PropDisplayPolicyType.BlueprintOnly: { // See if the actual class of the object instance is native or not. var uclass_em = obj_em_.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass); var is_native_res = UE4Utility.TestUClassFlags( uclass_em.Expression, ClassFlags.Native, context_expr_ ); return(is_native_res.IsValid && !is_native_res.Value); } case Config.PropDisplayPolicyType.All: return(true); default: return(false); } }
public void EvaluateProperties() { List <DkmEvaluationResult> evals = new List <DkmEvaluationResult>(); // Assume we've been constructed with the fabricated property list expression DkmChildVisualizedExpression proplist_expr = (DkmChildVisualizedExpression)expression_; Debug.Assert(proplist_expr != null); // start could be an expression with the type of any UObject-derived class DkmVisualizedExpression start_expr = proplist_expr.Parent; string base_expression_str = Utility.GetExpressionFullName(start_expr); base_expression_str = Utility.StripExpressionFormatting(base_expression_str); ExpressionManipulator obj_em = null; // @TODO: Deal with non-pointer start expression obj_em = ExpressionManipulator.FromExpression(base_expression_str); // Determine if our base expression is <UObject-type>* or <UObject-type> bool is_pointer = start_expr.GetDataItem <UObjectDataItem>().IsPointer; if (!is_pointer) { obj_em = obj_em.AddressOf(); } var uclass_em = obj_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjClass); if (Config.PropertyDisplayPolicy == Config.PropDisplayPolicyType.BlueprintOnly) { // See if the actual class of the object instance whose properties we want to enumerate // is native or not. var is_native_res = UE4Utility.TestUClassFlags( uclass_em.Expression, ClassFlags.Native, start_expr ); // If the instance class is native, then it can't possibly have any non-native properties, // so bail out now. // @TODO: Even if the class is not native, we should still be able to avoid doing all the work // for enumerating every native property in order to find the non-native ones... // @TODO: How best to deal with failed is_native evaluation? if (is_native_res.IsValid && is_native_res.Value) { return; } } // Get the UStruct part of the UClass, in order to begin iterating properties var ustruct_em = uclass_em.PtrCast(Typ.UStruct); // Now access PropertyLink member, which is the start of the linked list of properties var prop_em = ustruct_em.PtrMember(Memb.FirstProperty); uint idx = 0; while (true) { Debug.Print("UE4PV: Invoking raw eval on UProperty* expression"); var prop_eval = DefaultEE.DefaultEval(prop_em.Expression, start_expr, true) as DkmSuccessEvaluationResult; Debug.Assert(prop_eval != null); if (prop_eval.Address.Value == 0) { // nullptr, end of property list break; } bool should_skip = false; if (!should_skip && Config.PropertyDisplayPolicy == Config.PropDisplayPolicyType.BlueprintOnly) { // Check to see if this property is native or blueprint // We can test this by getting the UProperty's Outer, and checking its object flags for RF_Native. var prop_outer_em = prop_em.PtrCast(Typ.UObjectBase).PtrMember(Memb.ObjOuter); // @NOTE: RF_Native has gone, and checking for RF_MarkAsNative never seems to return true... //var is_native_res = UE4Utility.TestUObjectFlags(prop_outer_em.Expression, ObjFlags.Native, start_expr); // So, access class flags instead. // Note that we make the assumption here that the property's outer is a UClass, which should be safe since // we're starting out with a uobject, so all properties, including inherited ones, should be outered to a uclass. var prop_outer_uclass_em = prop_outer_em.PtrCast(Typ.UClass); var is_native_res = UE4Utility.TestUClassFlags(prop_outer_uclass_em.Expression, ClassFlags.Native, start_expr); // According to UE4 UStruct API docs, property linked list is ordered from most-derived // to base. If so, we should be able to bail out here knowing that having hit a native property, // all following properties must be native too. if (is_native_res.IsValid && is_native_res.Value) { return; } } if (!should_skip) { // @TODO: Here we use the starting expression for the container. // May not work if the root expression was not of pointer type!! var prop_val_eval = GeneratePropertyValueEval( obj_em.Expression, prop_em.Expression, idx, start_expr ); if (prop_val_eval != null && !Config.IsPropertyHidden(prop_val_eval.Name)) { prop_evals_[prop_val_eval.Name] = prop_val_eval; ++idx; } } // Advance to next link prop_em = prop_em.PtrMember(Memb.NextProperty); } }