public override IEnumerable<PythonEvaluationResult> GetDebugChildren(ReprOptions reprOptions) { yield return new PythonEvaluationResult(new ValueStore<long>(ReadElements().Count()), "len()") { Category = DkmEvaluationResultCategory.Method }; var reprBuilder = new ReprBuilder(reprOptions); foreach (var entry in ReadElements()) { reprBuilder.Clear(); reprBuilder.AppendFormat("[{0}]", entry.Key); yield return new PythonEvaluationResult(entry.Value, reprBuilder.ToString()); } }
public override IEnumerable <PythonEvaluationResult> GetDebugChildren(ReprOptions reprOptions) { yield return(new PythonEvaluationResult(new ValueStore <long>(ReadElements().Count()), "len()") { Category = DkmEvaluationResultCategory.Method }); var reprBuilder = new ReprBuilder(reprOptions); foreach (var entry in ReadElements()) { reprBuilder.Clear(); reprBuilder.AppendFormat("[{0}]", entry.Key); yield return(new PythonEvaluationResult(entry.Value, reprBuilder.ToString())); } }
/// <summary> /// Tries to evaluate the given expression by treating it as a chain of member access and indexing operations (e.g. <c>fob[0].oar.baz['abc'].blah</c>), /// and looking up the corresponding members in data model provided by <see cref="GetFrameLocals"/>. /// </summary> /// <param name="vars">List of variables, in the context of which the expression is evaluated.</param> /// <returns> /// <c>true</c> if evaluation was successful, or if it failed and no fallback is possible (e.g. expression is invalid). /// <c>false</c> if evaluation was not successful due to the limitations of this evaluator, and it may be possible to evaluate it correctly by other means. /// </returns> private bool EvaluateExpressionByWalkingObjects(IEnumerable<DkmSuccessEvaluationResult> vars, DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine<DkmEvaluateExpressionAsyncResult> completionRoutine) { var pyrtInfo = stackFrame.Thread.Process.GetPythonRuntimeInfo(); var parserOptions = new ParserOptions { ErrorSink = new StringErrorSink() }; var parser = Parser.CreateParser(new StringReader(expression.Text), pyrtInfo.LanguageVersion, parserOptions); var expr = ((ReturnStatement)parser.ParseTopExpression().Body).Expression; string errorText = parserOptions.ErrorSink.ToString(); if (!string.IsNullOrEmpty(errorText)) { completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create( inspectionContext, stackFrame, expression.Text, expression.Text, errorText, DkmEvaluationResultFlags.Invalid, null))); return true; } // Unroll the AST into a sequence of member access and indexing operations, if possible. var path = new Stack<string>(); var reprBuilder = new ReprBuilder(new ReprOptions(stackFrame.Thread.Process)); while (true) { var memberExpr = expr as MemberExpression; if (memberExpr != null) { path.Push(memberExpr.Name); expr = memberExpr.Target; continue; } var indexingExpr = expr as IndexExpression; if (indexingExpr != null) { var indexExpr = indexingExpr.Index as ConstantExpression; if (indexExpr != null) { reprBuilder.Clear(); reprBuilder.AppendFormat("[{0:PY}]", indexExpr.Value); path.Push(reprBuilder.ToString()); expr = indexingExpr.Target; continue; } } break; } var varExpr = expr as NameExpression; if (varExpr == null) { return false; } path.Push(varExpr.Name); // Walk the path through Locals while (true) { var name = path.Pop(); var evalResult = vars.FirstOrDefault(er => er.Name == name); if (evalResult == null) { return false; } if (path.Count == 0) { // Clone the evaluation result, but use expression text as its name. DkmDataItem dataItem = (DkmDataItem)evalResult.GetDataItem<PyObjectEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<GlobalsEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<CppViewEvaluationResult>() ?? (DkmDataItem)evalResult.GetDataItem<RawEvaluationResult>(); evalResult = DkmSuccessEvaluationResult.Create( evalResult.InspectionContext, evalResult.StackFrame, expression.Text, expression.Text, evalResult.Flags, evalResult.Value, evalResult.EditableValue, evalResult.Type, evalResult.Category, evalResult.Access, evalResult.StorageType, evalResult.TypeModifierFlags, evalResult.Address, evalResult.CustomUIVisualizers, evalResult.ExternalModules, dataItem); completionRoutine(new DkmEvaluateExpressionAsyncResult(evalResult)); return true; } var childWorkList = DkmWorkList.Create(null); evalResult.GetChildren(childWorkList, 0, inspectionContext, getChildrenResult => getChildrenResult.EnumContext.GetItems(childWorkList, 0, int.MaxValue, getItemsResult => vars = getItemsResult.Items.OfType<DkmSuccessEvaluationResult>())); childWorkList.Execute(); } }
public List<DkmEvaluationResult> GetChildren(ExpressionEvaluator exprEval, DkmEvaluationResult result, DkmInspectionContext inspectionContext) { var stackFrame = result.StackFrame; var cppEval = new CppExpressionEvaluator(inspectionContext, stackFrame); var obj = ValueStore.Read(); var evalResults = new List<DkmEvaluationResult>(); var reprOptions = new ReprOptions(inspectionContext); var reprBuilder = new ReprBuilder(reprOptions); if (DebuggerOptions.ShowCppViewNodes && !HasCppView) { if (CppTypeName == null) { // Try to guess the object's C++ type by looking at function pointers in its PyTypeObject. If they are pointing // into a module for which symbols are available, C++ EE should be able to resolve them into something like // "0x1e120d50 {python33_d.dll!list_dealloc(PyListObject *)}". If we are lucky, one of those functions will have // the first argument declared as a strongly typed pointer, rather than PyObject* or void*. CppTypeName = "PyObject"; CppTypeModuleName = null; foreach (string methodField in _methodFields) { var funcPtrEvalResult = cppEval.TryEvaluateObject(null, "PyObject", obj.Address, ".ob_type->" + methodField) as DkmSuccessEvaluationResult; if (funcPtrEvalResult == null || funcPtrEvalResult.Value.IndexOf('{') < 0) { continue; } var match = _cppFirstArgTypeFromFuncPtrRegex.Match(funcPtrEvalResult.Value); string module = match.Groups["module"].Value; string firstArgType = match.Groups["type"].Value; if (firstArgType != "void" && firstArgType != "PyObject" && firstArgType != "_object") { CppTypeName = firstArgType; CppTypeModuleName = module; break; } } } string cppExpr = CppExpressionEvaluator.GetExpressionForObject(CppTypeModuleName, CppTypeName, obj.Address, ",!"); var evalResult = DkmIntermediateEvaluationResult.Create( inspectionContext, stackFrame, "[C++ view]", "{C++}" + cppExpr, cppExpr, CppExpressionEvaluator.CppLanguage, stackFrame.Process.GetNativeRuntimeInstance(), null); evalResults.Add(evalResult); } int i = 0; foreach (var child in obj.GetDebugChildren(reprOptions).Take(MaxDebugChildren)) { if (child.Name == null) { reprBuilder.Clear(); reprBuilder.AppendFormat("[{0:PY}]", i++); child.Name = reprBuilder.ToString(); } DkmEvaluationResult evalResult; if (child.ValueStore is IValueStore<PyObject>) { evalResult = exprEval.CreatePyObjectEvaluationResult(inspectionContext, stackFrame, FullName, child, cppEval); } else { var value = child.ValueStore.Read(); reprBuilder.Clear(); reprBuilder.AppendLiteral(value); string type = null; if (Process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V27) { _typeMapping2x.TryGetValue(value.GetType(), out type); } if (type == null) { _typeMapping.TryGetValue(value.GetType(), out type); } var flags = DkmEvaluationResultFlags.ReadOnly; if (value is string) { flags |= DkmEvaluationResultFlags.RawString; } string childFullName = child.Name; if (FullName != null) { if (childFullName.EndsWith("()")) { // len() childFullName = childFullName.Substring(0, childFullName.Length - 2) + "(" + FullName + ")"; } else { if (!childFullName.StartsWith("[")) { // [0], ['fob'] etc childFullName = "." + childFullName; } childFullName = FullName + childFullName; } } evalResult = DkmSuccessEvaluationResult.Create( inspectionContext, stackFrame, child.Name, childFullName, flags, reprBuilder.ToString(), null, type, child.Category, child.AccessType, child.StorageType, child.TypeModifierFlags, null, null, null, new RawEvaluationResult { Value = value }); } evalResults.Add(evalResult); } return evalResults; }