Beispiel #1
0
        /// <summary>
        /// Create a DkmEvaluationResult representing a Python object.
        /// </summary>
        /// <param name="cppEval">C++ evaluator to use to provide the [C++ view] node for this object.</param>
        /// <param name="cppTypeName">
        /// C++ struct name corresponding to this object type, for use by [C++ view] node. If not specified, it will be inferred from values of 
        /// various function pointers in <c>ob_type</c>, if possible. <c>PyObject</c> is the ultimate fallback.
        /// </param>
        public DkmEvaluationResult CreatePyObjectEvaluationResult(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame, string parentName, PythonEvaluationResult pyEvalResult, CppExpressionEvaluator cppEval, string cppTypeName = null, bool hasCppView = false, bool isOwned = false) {
            var name = pyEvalResult.Name;
            var valueStore = pyEvalResult.ValueStore as IValueStore<PyObject>;
            if (valueStore == null) {
                Debug.Fail("Non-PyObject PythonEvaluationResult passed to CreateEvaluationResult.");
                throw new ArgumentException();
            }

            var valueObj = valueStore.Read();
            string typeName = valueObj.ob_type.Read().tp_name.Read().ReadUnicode();

            var reprOptions = new ReprOptions(inspectionContext);
            string repr = valueObj.Repr(reprOptions);

            var flags = pyEvalResult.Flags;
            if (DebuggerOptions.ShowCppViewNodes || valueObj.GetDebugChildren(reprOptions).Any()) {
                flags |= DkmEvaluationResultFlags.Expandable;
            }
            if (!(valueStore is IWritableDataProxy)) {
                flags |= DkmEvaluationResultFlags.ReadOnly;
            }
            if (valueObj is IPyBaseStringObject) {
                flags |= DkmEvaluationResultFlags.RawString;
            }

            var boolObj = valueObj as IPyBoolObject;
            if (boolObj != null) {
                flags |= DkmEvaluationResultFlags.Boolean;
                if (boolObj.ToBoolean()) {
                    flags |= DkmEvaluationResultFlags.BooleanTrue;
                }
            }

            string fullName = name;
            if (parentName != null) {
                if (!fullName.StartsWith("[")) {
                    fullName = "." + fullName;
                }
                fullName = parentName + fullName;
            }

            var pyObjEvalResult = new PyObjectEvaluationResult(stackFrame.Process, fullName, valueStore, cppTypeName, hasCppView, isOwned);
            return DkmSuccessEvaluationResult.Create(
                inspectionContext, stackFrame, name, fullName, flags, repr, null, typeName, pyEvalResult.Category,
                pyEvalResult.AccessType, pyEvalResult.StorageType, pyEvalResult.TypeModifierFlags, null, null, null,
                pyObjEvalResult);
        }
Beispiel #2
0
        private void EvaluateExpressionViaInterpreter(DkmInspectionContext inspectionContext, DkmWorkList workList, DkmLanguageExpression expression, DkmStackWalkFrame stackFrame, DkmCompletionRoutine<DkmEvaluateExpressionAsyncResult> completionRoutine) {
            var thread = stackFrame.Thread;
            var process = thread.Process;

            if (_evalLoopThreadId.Read() != (ulong)thread.SystemPart.Id) {
                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text,
                    "Arbitrary Python expressions can only be evaluated on a thread which is stopped in Python code at a breakpoint or " +
                    "after a step-in or a step-over operation. Only expressions involving global and local variables, object field access, " +
                    "and indexing of built-in collection types with literals can be evaluated in the current context.",
                    DkmEvaluationResultFlags.Invalid, null)));
                return;
            }

            var pythonFrame = PyFrameObject.TryCreate(stackFrame);
            if (pythonFrame == null) {
                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, "Could not obtain a Python frame object for the current frame.",
                    DkmEvaluationResultFlags.Invalid, null)));
                return;
            }

            byte[] input = Encoding.UTF8.GetBytes(expression.Text + "\0");
            if (input.Length > ExpressionEvaluationBufferSize) {
                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, "Expression is too long.",
                    DkmEvaluationResultFlags.Invalid, null)));
                return;
            }

            _evalLoopFrame.Write(pythonFrame.Address);
            process.WriteMemory(_evalLoopInput.Address, input);

            bool timedOut;
            using (_evalCompleteEvent = new AutoResetEvent(false)) {
                thread.BeginFuncEvalExecution(DkmFuncEvalFlags.None);
                timedOut = !_evalCompleteEvent.WaitOne(ExpressionEvaluationTimeout);
                _evalCompleteEvent = null;
            }

            if (timedOut) {
                new RemoteComponent.AbortingEvalExecutionRequest().SendLower(process);

                // We need to stop the process before we can report end of func eval completion
                using (_evalAbortedEvent = new AutoResetEvent(false)) {
                    process.AsyncBreak(false);

                    if (!_evalAbortedEvent.WaitOne(20000)) {
                        // This is a catastrophic error, since we can't report func eval completion unless we can stop the process,
                        // and VS will hang until we do report completion. At this point we can only kill the debuggee so that the
                        // VS at least gets back to a reasonable state.
                        _evalAbortedEvent = null;
                        process.Terminate(1);

                        completionRoutine(DkmEvaluateExpressionAsyncResult.CreateErrorResult(new Exception("Couldn't abort a failed expression evaluation.")));
                        return;
                    }

                    _evalAbortedEvent = null;
                }

                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, "Evaluation timed out.",
                    DkmEvaluationResultFlags.Invalid, null)));
                return;
            }

            ulong objPtr = _evalLoopResult.Read();
            var obj = PyObject.FromAddress(process, objPtr);
            var exc_type = PyObject.FromAddress(process, _evalLoopExcType.Read());
            var exc_value = PyObject.FromAddress(process, _evalLoopExcValue.Read());
            var exc_str = (PyObject.FromAddress(process, _evalLoopExcStr.Read()) as IPyBaseStringObject).ToStringOrNull();
            var sehCode = _evalLoopSEHCode.Read();

            if (obj != null) {
                var cppEval = new CppExpressionEvaluator(inspectionContext, stackFrame);
                var pyEvalResult =  new PythonEvaluationResult(obj, expression.Text) { Flags = DkmEvaluationResultFlags.SideEffect };
                var evalResult = CreatePyObjectEvaluationResult(inspectionContext, stackFrame, null, pyEvalResult, cppEval, null, hasCppView: true, isOwned: true);
                _evalLoopResult.Write(0); // don't let the eval loop decref the object - we will do it ourselves later, when eval result is closed
                completionRoutine(new DkmEvaluateExpressionAsyncResult(evalResult));
            } else if (sehCode != 0) {
                string errorText = string.Format("Structured exception {0:x08} ", sehCode);
                if (Enum.IsDefined(typeof(EXCEPTION_CODE), sehCode)) {
                    errorText += "(" + (EXCEPTION_CODE)sehCode + ") ";
                }
                errorText += "raised while evaluating expression";
                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, errorText,
                    DkmEvaluationResultFlags.Invalid, null)));
            } else if (exc_type != null) {
                string typeName;
                var typeObject = exc_type as PyTypeObject;
                if (typeObject != null) {
                    typeName = typeObject.tp_name.Read().ReadUnicode();
                } else {
                    typeName = "<unknown exception type>";
                }

                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, typeName + " raised while evaluating expression: " + exc_str,
                    DkmEvaluationResultFlags.Invalid, null)));
            } else {
                completionRoutine(new DkmEvaluateExpressionAsyncResult(DkmFailedEvaluationResult.Create(
                    inspectionContext, stackFrame, expression.Text, expression.Text, "Unknown error occurred while evaluating expression.",
                    DkmEvaluationResultFlags.Invalid, null)));
            }
        }
        private DkmEvaluationResult GetPythonView(DkmVisualizedExpression visualizedExpression) {
            var stackFrame = visualizedExpression.StackFrame;
            var process = stackFrame.Process;
            var pythonRuntime = process.GetPythonRuntimeInstance();
            if (pythonRuntime == null) {
                return null;
            }

            var home = visualizedExpression.ValueHome as DkmPointerValueHome;
            if (home == null) {
                Debug.Fail("PythonViewNativeVisualizer given a visualized expression that has a non-DkmPointerValueHome home.");
                return null;
            } else if (home.Address == 0) {
                return null;
            }

            var exprEval = process.GetDataItem<ExpressionEvaluator>();
            if (exprEval == null) {
                Debug.Fail("PythonViewNativeVisualizer failed to obtain an instance of ExpressionEvaluator.");
                return null;
            }

            string cppTypeName = null;
            var childExpr = visualizedExpression as DkmChildVisualizedExpression;
            if (childExpr != null) {
                var evalResult = childExpr.EvaluationResult as DkmSuccessEvaluationResult;
                cppTypeName = evalResult.Type;
            } else {
                object punkTypeSymbol;
                visualizedExpression.GetSymbolInterface(typeof(IDiaSymbol).GUID, out punkTypeSymbol);
                using (ComPtr.Create(punkTypeSymbol)) {
                    var typeSymbol = punkTypeSymbol as IDiaSymbol;
                    if (typeSymbol != null) {
                        cppTypeName = typeSymbol.name;
                    }
                }
            }

            PyObject objRef;
            try {
                objRef = PyObject.FromAddress(process, home.Address);
            } catch {
                return null;
            }

            var pyEvalResult = new PythonEvaluationResult(objRef, "[Python view]")
            {
                Category = DkmEvaluationResultCategory.Property,
                AccessType = DkmEvaluationResultAccessType.Private
            };

            var inspectionContext = visualizedExpression.InspectionContext;
            CppExpressionEvaluator cppEval;
            try {
                cppEval = new CppExpressionEvaluator(inspectionContext, stackFrame);
            } catch {
                return null;
            }

            var pythonContext = DkmInspectionContext.Create(visualizedExpression.InspectionSession, pythonRuntime, stackFrame.Thread,
                inspectionContext.Timeout, inspectionContext.EvaluationFlags, inspectionContext.FuncEvalFlags, inspectionContext.Radix,
                DkmLanguage.Create("Python", new DkmCompilerId(Guids.MicrosoftVendorGuid, Guids.PythonLanguageGuid)), null);
            try {
                return exprEval.CreatePyObjectEvaluationResult(pythonContext, stackFrame, null, pyEvalResult, cppEval, cppTypeName, hasCppView: true);
            } catch {
                return null;
            }
        }