зеркало из https://github.com/microsoft/PTVS.git
Rollup of all of the mixed mode changes (#8071)
* Support mixed mode for 3.10 (#8050) * Fix 3.10 thread state * Add the other versions elsewhere * Test with native calling python * Fix 3.10 thread state * Add the other versions elsewhere * Test with native calling python * Add commit where _cframe was created * Use an environment variable for python install path * Get 3.11 to work in mixed mode (#8056) * Fix 3.10 thread state * Partially working for 3.11 Locals/Globals not being read correctly. They moved * Basics for 3.11 working * Fix stuff broken in 3.10 by 3.11 changes * Fix tabs * Fix review comments * Support for 312 mixed mode debugging (#8063) * Fix 3.10 thread state * Partially working for 3.11 Locals/Globals not being read correctly. They moved * Basics for 3.11 working * Fix stuff broken in 3.10 by 3.11 changes * Fix tabs * Get python breakpoints working again * Partially working for 3.11 Locals/Globals not being read correctly. They moved * Get python breakpoints working again * Get longs to work using new 3.12 long implementation * Compute dynamic parts of the frame like the f_back and the line number * Update comment * Add support for mixed mode debugging in 3.13 (#8070) * Changes for 3.13 Mixed mode debugging * Fix step out/over * Fix example to not hold file handle
This commit is contained in:
Родитель
1c06c37c64
Коммит
8b1d41a17a
|
@ -1,6 +1,12 @@
|
|||
|
||||
import ctypes
|
||||
|
||||
def returnATuple():
|
||||
return (4, 5)
|
||||
|
||||
def returnADict():
|
||||
return { "4": 5 }
|
||||
|
||||
# Load the DLL
|
||||
mylib = ctypes.CDLL('..\\x64\\Debug\\CppDll.dll')
|
||||
|
||||
|
@ -9,4 +15,9 @@ result = mylib.add(5, 10)
|
|||
|
||||
print(f"Result from C++ DLL: {result}")
|
||||
|
||||
print("After result is printed")
|
||||
print("After result is printed")
|
||||
|
||||
x = returnATuple()
|
||||
y = returnADict()
|
||||
|
||||
print("After tuple")
|
|
@ -11,7 +11,7 @@
|
|||
<OutputPath>.</OutputPath>
|
||||
<Name>PythonApplication</Name>
|
||||
<RootNamespace>PythonApplication</RootNamespace>
|
||||
<InterpreterId>Global|PythonCore|3.9</InterpreterId>
|
||||
<InterpreterId>Global|PythonCore|3.13</InterpreterId>
|
||||
<LaunchProvider>Standard Python launcher</LaunchProvider>
|
||||
<EnableNativeCodeDebugging>True</EnableNativeCodeDebugging>
|
||||
</PropertyGroup>
|
||||
|
@ -34,6 +34,10 @@
|
|||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<InterpreterReference Include="Global|PythonCore|3.10" />
|
||||
<InterpreterReference Include="Global|PythonCore|3.11" />
|
||||
<InterpreterReference Include="Global|PythonCore|3.12" />
|
||||
<InterpreterReference Include="Global|PythonCore|3.13" />
|
||||
<InterpreterReference Include="Global|PythonCore|3.9" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
|
||||
|
|
|
@ -13,12 +13,13 @@ DWORD WINAPI runner(LPVOID lpParam)
|
|||
std::filesystem::path cwd = std::filesystem::current_path();
|
||||
std::filesystem::path startFile = cwd / "runner.py";
|
||||
|
||||
const char * startFileStr = startFile.string().c_str();
|
||||
std::string str = startFile.string();
|
||||
const char * startFileStr = str.c_str();
|
||||
|
||||
PyObject* startObj = Py_BuildValue("s", startFileStr);
|
||||
FILE* file = _Py_fopen_obj(startObj, "rb+");
|
||||
if (file != NULL) {
|
||||
PyRun_SimpleFile(file, startFileStr);
|
||||
PyRun_SimpleFileEx(file, startFileStr, 1);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
|
|
|
@ -104,14 +104,14 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Users\rchiodo\AppData\Local\Programs\Python\Python311\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(LOCALAPPDATA)\Programs\Python\Python313\include;$(LOCALAPPDATA)\Programs\Python\Python312\include;$(LOCALAPPDATA)\Programs\Python\Python311\include;$(LOCALAPPDATA)\Programs\Python\Python310\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>C:\Users\rchiodo\AppData\Local\Programs\Python\Python311\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(LOCALAPPDATA)\Programs\Python\Python313\libs;$(LOCALAPPDATA)\Programs\Python\Python312\libs;$(LOCALAPPDATA)\Programs\Python\Python311\libs;$(LOCALAPPDATA)\Programs\Python\Python310\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
|
@ -122,7 +122,7 @@
|
|||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>C:\Users\rchiodo\AppData\Local\Programs\Python\Python311\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(LOCALAPPDATA)\Programs\Python\Python310\include;$(LOCALAPPDATA)\Programs\Python\Python311\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<LanguageStandard_C>stdc17</LanguageStandard_C>
|
||||
</ClCompile>
|
||||
|
@ -131,7 +131,7 @@
|
|||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>C:\Users\rchiodo\AppData\Local\Programs\Python\Python311\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>$(LOCALAPPDATA)\Programs\Python\Python310\libs;$(LOCALAPPDATA)\Programs\Python\Python311\libs;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -39,7 +39,10 @@ namespace Microsoft.CookiecutterTools.Interpreters {
|
|||
V37 = 0x0307,
|
||||
V38 = 0x0308,
|
||||
V39 = 0x0309,
|
||||
V310 = 0x0310
|
||||
V310 = 0x030a,
|
||||
V311 = 0x030b,
|
||||
V312 = 0x030c,
|
||||
V313 = 0x030d,
|
||||
}
|
||||
|
||||
public static class PythonLanguageVersionExtensions {
|
||||
|
@ -87,6 +90,9 @@ namespace Microsoft.CookiecutterTools.Interpreters {
|
|||
case 8: return PythonLanguageVersion.V38;
|
||||
case 9: return PythonLanguageVersion.V39;
|
||||
case 10: return PythonLanguageVersion.V310;
|
||||
case 11: return PythonLanguageVersion.V311;
|
||||
case 12: return PythonLanguageVersion.V312;
|
||||
case 13: return PythonLanguageVersion.V313;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
PyCodeObject code = pythonFrame.f_code.Read();
|
||||
var loc = new SourceLocation(
|
||||
code.co_filename.Read().ToStringOrNull(),
|
||||
pythonFrame.f_lineno.Read(),
|
||||
pythonFrame.ComputeLineNumber(stackContext.InspectionSession, nativeFrame, stackContext.FormatOptions.EvaluationFlags),
|
||||
code.co_name.Read().ToStringOrNull(),
|
||||
nativeFrame.InstructionAddress as DkmNativeInstructionAddress);
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
private readonly DkmStackWalkFrame _nativeFrame;
|
||||
private readonly DkmInspectionContext _cppInspectionContext;
|
||||
|
||||
public CppExpressionEvaluator(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame) {
|
||||
public CppExpressionEvaluator(DkmInspectionContext inspectionContext, DkmStackWalkFrame stackFrame)
|
||||
: this(inspectionContext.InspectionSession, inspectionContext.Radix, stackFrame) {
|
||||
}
|
||||
public CppExpressionEvaluator(DkmInspectionSession inspectionSession, uint radix, DkmStackWalkFrame stackFrame, DkmEvaluationFlags flags = DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects) {
|
||||
_process = stackFrame.Process;
|
||||
var thread = stackFrame.Thread;
|
||||
|
||||
|
@ -53,16 +56,15 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
DkmStackWalkFrameFlags.None, null, stackFrame.Registers, null);
|
||||
}
|
||||
|
||||
_cppInspectionContext = DkmInspectionContext.Create(inspectionContext.InspectionSession, _process.GetNativeRuntimeInstance(), thread, Timeout,
|
||||
DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects, DkmFuncEvalFlags.None, inspectionContext.Radix, CppLanguage, null);
|
||||
_cppInspectionContext = DkmInspectionContext.Create(inspectionSession, _process.GetNativeRuntimeInstance(), thread, Timeout,
|
||||
flags, DkmFuncEvalFlags.None, radix, CppLanguage, null);
|
||||
}
|
||||
|
||||
public CppExpressionEvaluator(DkmThread thread, ulong frameBase, ulong vframe) {
|
||||
public CppExpressionEvaluator(DkmThread thread, ulong frameBase, ulong vframe, DkmEvaluationFlags flags = DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects) {
|
||||
_process = thread.Process;
|
||||
|
||||
var inspectionSession = DkmInspectionSession.Create(_process, null);
|
||||
_cppInspectionContext = DkmInspectionContext.Create(inspectionSession, _process.GetNativeRuntimeInstance(), thread, Timeout,
|
||||
DkmEvaluationFlags.TreatAsExpression | DkmEvaluationFlags.NoSideEffects, DkmFuncEvalFlags.None, 10, CppLanguage, null);
|
||||
flags, DkmFuncEvalFlags.None, 10, CppLanguage, null);
|
||||
|
||||
const int CV_ALLREG_VFRAME = 0x00007536;
|
||||
var vframeReg = DkmUnwoundRegister.Create(CV_ALLREG_VFRAME, new ReadOnlyCollection<byte>(BitConverter.GetBytes(vframe)));
|
||||
|
@ -79,8 +81,8 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public DkmEvaluationResult TryEvaluate(string expr) {
|
||||
using (var cppExpr = DkmLanguageExpression.Create(CppLanguage, DkmEvaluationFlags.NoSideEffects, expr, null)) {
|
||||
public DkmEvaluationResult TryEvaluate(string expr, DkmEvaluationFlags flags = DkmEvaluationFlags.NoSideEffects) {
|
||||
using (var cppExpr = DkmLanguageExpression.Create(CppLanguage, flags, expr, null)) {
|
||||
DkmEvaluationResult cppEvalResult = null;
|
||||
var cppWorkList = DkmWorkList.Create(null);
|
||||
_cppInspectionContext.EvaluateExpression(cppWorkList, cppExpr, _nativeFrame, (result) => {
|
||||
|
@ -95,8 +97,8 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
return TryEvaluate(GetExpressionForObject(moduleName, typeName, address, tail));
|
||||
}
|
||||
|
||||
public string Evaluate(string expr) {
|
||||
var er = TryEvaluate(expr);
|
||||
public string Evaluate(string expr, DkmEvaluationFlags flags = DkmEvaluationFlags.NoSideEffects) {
|
||||
var er = TryEvaluate(expr, flags);
|
||||
var ser = er as DkmSuccessEvaluationResult;
|
||||
if (ser == null) {
|
||||
throw new CppEvaluationException(er);
|
||||
|
@ -104,9 +106,9 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
return ser.Value;
|
||||
}
|
||||
|
||||
public int EvaluateInt32(string expr) {
|
||||
public int EvaluateInt32(string expr, DkmEvaluationFlags flags = DkmEvaluationFlags.NoSideEffects) {
|
||||
try {
|
||||
return int.Parse(Evaluate("(__int32)(" + expr + ")"));
|
||||
return int.Parse(Evaluate("(__int32)(" + expr + ")", flags));
|
||||
} catch (FormatException) {
|
||||
throw new CppEvaluationException();
|
||||
}
|
||||
|
|
|
@ -107,6 +107,16 @@
|
|||
<Compile Include="Proxies\DataProxy.cs" />
|
||||
<Compile Include="ExpressionEvaluator.cs" />
|
||||
<Compile Include="LocalStackWalkingComponent.cs" />
|
||||
<Compile Include="Proxies\Structs\CFrameProxy.cs" />
|
||||
<Compile Include="Proxies\Structs\ImportState.cs" />
|
||||
<Compile Include="Proxies\Structs\PyCodeObject310.cs" />
|
||||
<Compile Include="Proxies\Structs\PyCodeObject311.cs" />
|
||||
<Compile Include="Proxies\Structs\PyDictObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyDictObject311.cs" />
|
||||
<Compile Include="Proxies\Structs\PyFrameObject310.cs" />
|
||||
<Compile Include="Proxies\Structs\PyFrameObject311.cs" />
|
||||
<Compile Include="Proxies\Structs\PyFunctionObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyInterpreterFrame.cs" />
|
||||
<Compile Include="Proxies\Structs\PyRuntimeState.cs" />
|
||||
<Compile Include="Proxies\Structs\PyEllipsisObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyComplexObject.cs" />
|
||||
|
@ -118,6 +128,9 @@
|
|||
<Compile Include="Proxies\Structs\PyBoolObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PySetObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyCellObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyThreads.cs" />
|
||||
<Compile Include="Proxies\Structs\PyUnicodeObject311.cs" />
|
||||
<Compile Include="Proxies\Structs\PyUnicodeObject312.cs" />
|
||||
<Compile Include="PythonRuntimeInfo.cs" />
|
||||
<Compile Include="StackFrameDataItem.cs" />
|
||||
<Compile Include="ValueStore.cs" />
|
||||
|
@ -138,7 +151,7 @@
|
|||
<Compile Include="Proxies\Structs\PyInterpreterState.cs" />
|
||||
<Compile Include="Proxies\StructProxy.cs" />
|
||||
<Compile Include="Proxies\Structs\PyCodeObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyDictObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyDictObject310.cs" />
|
||||
<Compile Include="Proxies\Structs\PyFrameObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyListObject.cs" />
|
||||
<Compile Include="Proxies\Structs\PyLongObject.cs" />
|
||||
|
|
|
@ -20,6 +20,9 @@ using Microsoft.VisualStudio.Debugger;
|
|||
namespace Microsoft.PythonTools.Debugger.Concord {
|
||||
public static class DebuggerOptions {
|
||||
// These are intentionally not implemented as auto-properties to enable easily changing them at runtime, including when stopped in native code.
|
||||
//
|
||||
// These show up in commands in the debugger watch window if you set the registry value:
|
||||
// Key: HKCU/Software/Microsoft/PythonTools/Debugger - Value: PythonDeveloper: DWORD = 1
|
||||
private static bool _showNativePythonFrames;
|
||||
private static bool _usePythonStepping;
|
||||
private static bool _showCppViewNodes;
|
||||
|
@ -29,7 +32,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
|
||||
public static bool ShowNativePythonFrames {
|
||||
get {
|
||||
return _showNativePythonFrames; // Enable this to show native (C++) frames including our trace helper
|
||||
return _showNativePythonFrames; // Enable this to show native (C++) frames including our trace helper and CPython code
|
||||
}
|
||||
set {
|
||||
_showNativePythonFrames = value;
|
||||
|
@ -39,7 +42,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
|
||||
public static bool UsePythonStepping {
|
||||
get {
|
||||
return _usePythonStepping; // Disable this to step through the TraceHelper dll in the launched VS
|
||||
return _usePythonStepping; // Disable this to step through the TraceHelper dll (or CPython) in the launched VS
|
||||
}
|
||||
set {
|
||||
_usePythonStepping = value;
|
||||
|
|
|
@ -76,9 +76,14 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
_pyrtInfo = process.GetPythonRuntimeInfo();
|
||||
|
||||
LoadInitialPythonModules();
|
||||
string pyCodeFunctionName = (_pyrtInfo.LanguageVersion < PythonLanguageVersion.V38) ? "PyCode_New" : "PyCode_NewWithPosOnlyArgs";
|
||||
LocalComponent.CreateRuntimeDllFunctionBreakpoint(_pyrtInfo.DLLs.Python, pyCodeFunctionName, PythonDllBreakpointHandlers.PyCode_New, enable: true, debugStart: true);
|
||||
LocalComponent.CreateRuntimeDllFunctionBreakpoint(_pyrtInfo.DLLs.Python, "PyCode_NewEmpty", PythonDllBreakpointHandlers.PyCode_NewEmpty, enable: true, debugStart: true);
|
||||
|
||||
if (_pyrtInfo.LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
LocalComponent.CreateRuntimeDllFunctionBreakpoint(_pyrtInfo.DLLs.Python, "PyCode_NewWithPosOnlyArgs", PythonDllBreakpointHandlers.PyCode_New, enable: true, debugStart: true);
|
||||
LocalComponent.CreateRuntimeDllFunctionBreakpoint(_pyrtInfo.DLLs.Python, "PyCode_NewEmpty", PythonDllBreakpointHandlers.PyCode_NewEmpty, enable: true, debugStart: true);
|
||||
} else {
|
||||
// In 3.11, the PyCode_New functions were no longer used. Instead, an internal _PyCode_New function is used to create a code object.
|
||||
LocalComponent.CreateRuntimeDllFunctionBreakpoint(_pyrtInfo.DLLs.Python, "_PyCode_New", PythonDllBreakpointHandlers._PyCode_New, enable: true, debugStart: true);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadInitialPythonModules() {
|
||||
|
@ -160,6 +165,27 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
}.SendLower(process);
|
||||
}
|
||||
|
||||
public static void _PyCode_New(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
|
||||
var process = thread.Process;
|
||||
var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
|
||||
|
||||
var filenamePtr = cppEval.EvaluateUInt64("con->filename");
|
||||
var filenameObj = PyObject.FromAddress(process, filenamePtr) as IPyBaseStringObject;
|
||||
if (filenameObj == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
string filename = filenameObj.ToString();
|
||||
if (process.GetPythonRuntimeInstance().GetModuleInstances().Any(mi => mi.FullName == filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
new RemoteComponent.CreateModuleRequest {
|
||||
ModuleId = Guid.NewGuid(),
|
||||
FileName = filename
|
||||
}.SendLower(process);
|
||||
}
|
||||
|
||||
public static void PyCode_NewEmpty(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
|
||||
var process = thread.Process;
|
||||
var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
|
||||
|
|
|
@ -58,21 +58,24 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies {
|
|||
public static readonly FactoryFunc Factory;
|
||||
|
||||
static FactoryBuilder() {
|
||||
FactoryFunc nonPolymorphicFactory;
|
||||
var ctor = typeof(TProxy).GetConstructor(new[] { typeof(DkmProcess), typeof(ulong) });
|
||||
if (ctor != null) {
|
||||
var processParam = Expression.Parameter(typeof(DkmProcess));
|
||||
var addressParam = Expression.Parameter(typeof(ulong));
|
||||
var polymorphicParam = Expression.Parameter(typeof(bool));
|
||||
nonPolymorphicFactory = Expression.Lambda<FactoryFunc>(
|
||||
Expression.New(ctor, processParam, addressParam),
|
||||
new[] { processParam, addressParam, polymorphicParam })
|
||||
.Compile();
|
||||
} else {
|
||||
nonPolymorphicFactory = (process, address, polymorphic) => {
|
||||
Debug.Fail("IDebuggeeReference-derived type " + typeof(TProxy).Name + " does not have a (DkmProcess, ulong) constructor.");
|
||||
throw new NotSupportedException();
|
||||
};
|
||||
FactoryFunc nonPolymorphicFactory = (process, address, polymorphic) => {
|
||||
Debug.Fail("IDebuggeeReference-derived type " + typeof(TProxy).Name + " does not have a (DkmProcess, ulong) constructor or cannot be instantiated.");
|
||||
throw new NotSupportedException();
|
||||
};
|
||||
var type = typeof(TProxy);
|
||||
|
||||
// Make sure we have a constructor that takes a DkmProcess and a ulong. If we don't, we can't instantiate the type.
|
||||
if (!type.IsAbstract) {
|
||||
var ctor = type.GetConstructor(new[] { typeof(DkmProcess), typeof(ulong) });
|
||||
if (ctor != null) {
|
||||
var processParam = Expression.Parameter(typeof(DkmProcess));
|
||||
var addressParam = Expression.Parameter(typeof(ulong));
|
||||
var polymorphicParam = Expression.Parameter(typeof(bool));
|
||||
nonPolymorphicFactory = Expression.Lambda<FactoryFunc>(
|
||||
Expression.New(ctor, processParam, addressParam),
|
||||
new[] { processParam, addressParam, polymorphicParam })
|
||||
.Compile();
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof(IPyObject).IsAssignableFrom(typeof(TProxy))) {
|
||||
|
|
|
@ -20,6 +20,7 @@ using System.Linq;
|
|||
using Microsoft.Dia;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.VisualStudio.Debugger.Interop;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies {
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||
|
@ -139,11 +140,6 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies {
|
|||
return new { _process, _address }.GetHashCode();
|
||||
}
|
||||
|
||||
protected TProxy GetFieldProxy<TProxy>(StructField<TProxy>? field, bool polymorphic = true)
|
||||
where TProxy : IDataProxy {
|
||||
return field.HasValue ? GetFieldProxy(field.Value) : default(TProxy);
|
||||
}
|
||||
|
||||
protected TProxy GetFieldProxy<TProxy>(StructField<TProxy> field, bool polymorphic = true)
|
||||
where TProxy : IDataProxy {
|
||||
return DataProxy.Create<TProxy>(Process, Address.OffsetBy(field.Offset), polymorphic);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "_cframe", MinVersion = PythonLanguageVersion.V310, MaxVersion = PythonLanguageVersion.V310)]
|
||||
[StructProxy(StructName = "_PyCFrame", MinVersion = PythonLanguageVersion.V311)]
|
||||
internal class CFrameProxy : StructProxy {
|
||||
internal class Fields {
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<Int32Proxy> use_tracing;
|
||||
public StructField<PointerProxy<CFrameProxy>> previous;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PointerProxy<PyInterpreterFrame>> current_frame;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public CFrameProxy(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public Int32Proxy use_tracing {
|
||||
get { return GetFieldProxy(_fields.use_tracing); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyInterpreterFrame> current_frame => GetFieldProxy(_fields.current_frame);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "_import_state", MinVersion = PythonLanguageVersion.V312)]
|
||||
internal class ImportState : StructProxy {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyDictObject>> modules;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public ImportState(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictObject> modules {
|
||||
get { return GetFieldProxy(_fields.modules); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,60 +14,30 @@
|
|||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
internal class PyCodeObject : PyObject {
|
||||
public class Fields {
|
||||
public StructField<Int32Proxy> co_nlocals;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_names;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_varnames;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_freevars;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_cellvars;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_filename;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_name;
|
||||
public StructField<Int32Proxy> co_firstlineno;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
internal abstract class PyCodeObject : PyObject {
|
||||
public PyCodeObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyCodeObject>();
|
||||
}
|
||||
|
||||
public Int32Proxy co_nlocals {
|
||||
get { return GetFieldProxy(_fields.co_nlocals); }
|
||||
}
|
||||
public abstract Int32Proxy co_nlocals { get; }
|
||||
|
||||
public PointerProxy<PyTupleObject> co_names {
|
||||
get { return GetFieldProxy(_fields.co_names); }
|
||||
}
|
||||
public abstract PointerProxy<PyTupleObject> co_names { get; }
|
||||
|
||||
public PointerProxy<PyTupleObject> co_varnames {
|
||||
get { return GetFieldProxy(_fields.co_varnames); }
|
||||
}
|
||||
public abstract IWritableDataProxy<PyTupleObject> co_varnames { get; }
|
||||
|
||||
public PointerProxy<PyTupleObject> co_freevars {
|
||||
get { return GetFieldProxy(_fields.co_freevars); }
|
||||
}
|
||||
public abstract IWritableDataProxy<PyTupleObject> co_freevars { get; }
|
||||
|
||||
public PointerProxy<PyTupleObject> co_cellvars {
|
||||
get { return GetFieldProxy(_fields.co_cellvars); }
|
||||
}
|
||||
public abstract IWritableDataProxy<PyTupleObject> co_cellvars { get; }
|
||||
|
||||
public PointerProxy<IPyBaseStringObject> co_filename {
|
||||
get { return GetFieldProxy(_fields.co_filename); }
|
||||
}
|
||||
public abstract PointerProxy<IPyBaseStringObject> co_filename { get; }
|
||||
|
||||
public PointerProxy<IPyBaseStringObject> co_name {
|
||||
get { return GetFieldProxy(_fields.co_name); }
|
||||
}
|
||||
public abstract PointerProxy<IPyBaseStringObject> co_name { get; }
|
||||
|
||||
public Int32Proxy co_firstlineno {
|
||||
get { return GetFieldProxy(_fields.co_firstlineno); }
|
||||
}
|
||||
public abstract Int32Proxy co_firstlineno { get; }
|
||||
|
||||
public override void Repr(ReprBuilder builder) {
|
||||
string name = co_name.TryRead().ToStringOrNull() ?? "???";
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyCodeObject", MaxVersion = PythonLanguageVersion.V310)]
|
||||
[PyType(MaxVersion = PythonLanguageVersion.V310, VariableName = "PyCode_Type")]
|
||||
internal class PyCodeObject310 : PyCodeObject {
|
||||
public class Fields {
|
||||
public StructField<Int32Proxy> co_nlocals;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_names;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_varnames;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_freevars;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_cellvars;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_filename;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_name;
|
||||
public StructField<Int32Proxy> co_firstlineno;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public override Int32Proxy co_nlocals => GetFieldProxy(_fields.co_nlocals);
|
||||
|
||||
public override PointerProxy<PyTupleObject> co_names => GetFieldProxy(_fields.co_names);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_varnames => GetFieldProxy(_fields.co_varnames);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_freevars => GetFieldProxy(_fields.co_freevars);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_cellvars => GetFieldProxy(_fields.co_cellvars);
|
||||
|
||||
public override PointerProxy<IPyBaseStringObject> co_filename => GetFieldProxy(_fields.co_filename);
|
||||
|
||||
public override PointerProxy<IPyBaseStringObject> co_name => GetFieldProxy(_fields.co_name);
|
||||
|
||||
public override Int32Proxy co_firstlineno => GetFieldProxy(_fields.co_firstlineno);
|
||||
|
||||
public PyCodeObject310(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyCodeObject310>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyCodeObject", MinVersion = PythonLanguageVersion.V311)]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V311, VariableName = "PyCode_Type")]
|
||||
internal class PyCodeObject311 : PyCodeObject {
|
||||
public class Fields {
|
||||
public StructField<Int32Proxy> co_nlocals;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_names;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_filename;
|
||||
public StructField<PointerProxy<IPyBaseStringObject>> co_name;
|
||||
public StructField<Int32Proxy> co_firstlineno;
|
||||
public StructField<PointerProxy<PyTupleObject>> co_localsplusnames;
|
||||
public StructField<PointerProxy<PyBytesObject>> co_localspluskinds;
|
||||
public StructField<ArrayProxy<SByteProxy>> co_code_adaptive;
|
||||
public StructField<Int32Proxy> _co_firsttraceable;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public override Int32Proxy co_nlocals => GetFieldProxy(_fields.co_nlocals);
|
||||
|
||||
public override PointerProxy<PyTupleObject> co_names => GetFieldProxy(_fields.co_names);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_varnames => GetVariableTupleProxy(VariableKind.CO_FAST_LOCAL);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_freevars => GetVariableTupleProxy(VariableKind.CO_FAST_FREE);
|
||||
|
||||
public override IWritableDataProxy<PyTupleObject> co_cellvars => GetVariableTupleProxy(VariableKind.CO_FAST_CELL);
|
||||
|
||||
public override PointerProxy<IPyBaseStringObject> co_filename => GetFieldProxy(_fields.co_filename);
|
||||
|
||||
public override PointerProxy<IPyBaseStringObject> co_name => GetFieldProxy(_fields.co_name);
|
||||
|
||||
public override Int32Proxy co_firstlineno => GetFieldProxy(_fields.co_firstlineno);
|
||||
|
||||
public ArrayProxy<SByteProxy> co_code_adaptive => GetFieldProxy(_fields.co_code_adaptive);
|
||||
|
||||
public Int32Proxy _co_firsttraceable => GetFieldProxy(_fields._co_firsttraceable);
|
||||
|
||||
public PyCodeObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyCodeObject311>();
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum VariableKind {
|
||||
CO_FAST_LOCAL = 0x20,
|
||||
CO_FAST_CELL = 0x40,
|
||||
CO_FAST_FREE = 0x80
|
||||
}
|
||||
|
||||
private IWritableDataProxy<PyTupleObject> GetVariableTupleProxy(VariableKind kind) {
|
||||
return new PyVariableTuplePointerProxy(Process, kind, GetFieldProxy(_fields.co_localsplusnames), GetFieldProxy(_fields.co_localspluskinds));
|
||||
}
|
||||
|
||||
// In 3.11, the co_varnames, co_freevars, and co_cellvars were all removed. In order to not have to change our usage
|
||||
// of them, this class and the PyVariableTuple were created in order to pretend to behave like the original co_varnames etc.
|
||||
internal class PyVariableTuplePointerProxy : IWritableDataProxy<PyTupleObject> {
|
||||
private readonly PyVariableTuple _pseudoTuple;
|
||||
private readonly PointerProxy<PyTupleObject> _realTuple;
|
||||
private readonly DkmProcess _process;
|
||||
|
||||
public PyVariableTuplePointerProxy(DkmProcess process, VariableKind kind, PointerProxy<PyTupleObject> localsplusnames, PointerProxy<PyBytesObject> localspluskinds) {
|
||||
_pseudoTuple = new PyVariableTuple(process, kind, localsplusnames, localspluskinds);
|
||||
_realTuple = localsplusnames;
|
||||
_process = process;
|
||||
}
|
||||
|
||||
public DkmProcess Process => _process;
|
||||
|
||||
public ulong Address => _realTuple.Address;
|
||||
|
||||
public long ObjectSize => _realTuple.ObjectSize;
|
||||
|
||||
public PyTupleObject Read() => _pseudoTuple;
|
||||
|
||||
public void Write(PyTupleObject value) => throw new NotImplementedException();
|
||||
public void Write(object value) => throw new NotImplementedException();
|
||||
object IValueStore.Read() => _pseudoTuple;
|
||||
}
|
||||
|
||||
[PyType(Hidden = true)]
|
||||
internal class PyVariableTuple : PyTupleObject {
|
||||
private readonly VariableKind _kind;
|
||||
private readonly PointerProxy<PyTupleObject> _localsplusnames;
|
||||
private readonly PointerProxy<PyBytesObject> _localspluskinds;
|
||||
private readonly DkmProcess _process;
|
||||
|
||||
public PyVariableTuple(DkmProcess process, VariableKind kind, PointerProxy<PyTupleObject> localsplusnames, PointerProxy<PyBytesObject> localspluskinds)
|
||||
: base(process, localsplusnames.Read().Address) {
|
||||
_kind = kind;
|
||||
_localsplusnames = localsplusnames;
|
||||
_localspluskinds = localspluskinds;
|
||||
_process = process;
|
||||
}
|
||||
|
||||
public override IEnumerable<PointerProxy<PyObject>> ReadElements() {
|
||||
var localsplusnames = new List<PointerProxy<PyObject>>(_localsplusnames.Read().ReadElements());
|
||||
var localspluskinds = _localspluskinds.Read().ToBytes();
|
||||
Debug.Assert(localsplusnames.Count == localspluskinds.Length);
|
||||
for (var i = 0; i < localsplusnames.Count; i++) {
|
||||
var name = localsplusnames[i];
|
||||
var kind = (VariableKind)localspluskinds[i];
|
||||
if ((kind & _kind) == _kind) {
|
||||
yield return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -21,68 +21,12 @@ using Microsoft.VisualStudio.Debugger;
|
|||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyDictObject", MinVersion = PythonLanguageVersion.V39)]
|
||||
[PyType(VariableName = "PyDict_Type", MinVersion = PythonLanguageVersion.V39)]
|
||||
internal class PyDictObject : PyObject {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyDictKeysObject>> ma_keys;
|
||||
public StructField<PointerProxy<ArrayProxy<PointerProxy<PyObject>>>> ma_values;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictObject(DkmProcess process, ulong address)
|
||||
internal abstract class PyDictObject : PyObject {
|
||||
protected PyDictObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyDictObject>();
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictKeysObject> ma_keys {
|
||||
get { return GetFieldProxy(_fields.ma_keys); }
|
||||
}
|
||||
|
||||
public PointerProxy<ArrayProxy<PointerProxy<PyObject>>> ma_values {
|
||||
get { return GetFieldProxy(_fields.ma_values); }
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<PyObject, PointerProxy<PyObject>>> ReadElements() {
|
||||
if (ma_keys.IsNull) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var keys = ma_keys.Read();
|
||||
var size = keys.dk_size.Read();
|
||||
if (size <= 0) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var n = keys.dk_nentries.Read();
|
||||
var dk_entries = keys.dk_entries;
|
||||
var entry = dk_entries[0];
|
||||
|
||||
if (!ma_values.IsNull) {
|
||||
var values = ma_values.Read();
|
||||
var value = values[0];
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var key = entry.me_key;
|
||||
if (!value.IsNull && !key.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
entry = entry.GetAdjacentProxy(1);
|
||||
value = value.GetAdjacentProxy(1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var key = entry.me_key;
|
||||
var value = entry.me_value;
|
||||
if (!key.IsNull && !value.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
entry = entry.GetAdjacentProxy(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract IEnumerable<KeyValuePair<PyObject, PointerProxy<PyObject>>> ReadElements();
|
||||
|
||||
public override void Repr(ReprBuilder builder) {
|
||||
var count = ReadElements().Count();
|
||||
|
@ -114,75 +58,4 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, StructName = "_dictkeysobject")]
|
||||
internal class PyDictKeysObject : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> dk_size;
|
||||
public StructField<SSizeTProxy> dk_nentries;
|
||||
public StructField<ArrayProxy<SByteProxy>> dk_indices;
|
||||
}
|
||||
|
||||
public readonly Fields _fields;
|
||||
|
||||
public SSizeTProxy dk_size {
|
||||
get { return GetFieldProxy(_fields.dk_size); }
|
||||
}
|
||||
|
||||
public SSizeTProxy dk_nentries {
|
||||
get { return GetFieldProxy(_fields.dk_nentries); }
|
||||
}
|
||||
|
||||
public ArrayProxy<PyDictKeyEntry> dk_entries {
|
||||
get {
|
||||
// dk_entries is located after dk_indices, which is
|
||||
// variable length depending on the size of the table.
|
||||
long size = dk_size.Read();
|
||||
long offset = _fields.dk_indices.Offset;
|
||||
if (size <= 0) {
|
||||
return default(ArrayProxy<PyDictKeyEntry>);
|
||||
} else if (size <= 0xFF) {
|
||||
offset += size;
|
||||
} else if (size <= 0xFFFF) {
|
||||
offset += size * 2;
|
||||
} else if (size <= 0xFFFFFFFF) {
|
||||
offset += size * 4;
|
||||
} else {
|
||||
offset += size * 8;
|
||||
}
|
||||
|
||||
return DataProxy.Create<ArrayProxy<PyDictKeyEntry>>(
|
||||
Process,
|
||||
Address.OffsetBy(offset)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public PyDictKeysObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39)]
|
||||
internal class PyDictKeyEntry : StructProxy {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyObject>> me_key;
|
||||
public StructField<PointerProxy<PyObject>> me_value;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictKeyEntry(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_key {
|
||||
get { return GetFieldProxy(_fields.me_key); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_value {
|
||||
get { return GetFieldProxy(_fields.me_value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyDictObject", MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V310 )]
|
||||
[PyType(VariableName = "PyDict_Type", MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V310)]
|
||||
internal class PyDictObject310 : PyDictObject {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyDictKeysObject310>> ma_keys;
|
||||
public StructField<PointerProxy<ArrayProxy<PointerProxy<PyObject>>>> ma_values;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictObject310(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyDictObject310>();
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictKeysObject310> ma_keys {
|
||||
get { return GetFieldProxy(_fields.ma_keys); }
|
||||
}
|
||||
|
||||
public PointerProxy<ArrayProxy<PointerProxy<PyObject>>> ma_values {
|
||||
get { return GetFieldProxy(_fields.ma_values); }
|
||||
}
|
||||
|
||||
public override IEnumerable<KeyValuePair<PyObject, PointerProxy<PyObject>>> ReadElements() {
|
||||
if (ma_keys.IsNull) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var keys = ma_keys.Read();
|
||||
var size = keys.dk_size.Read();
|
||||
if (size <= 0) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var n = keys.dk_nentries.Read();
|
||||
var dk_entries = keys.dk_entries;
|
||||
var entry = dk_entries.First();
|
||||
|
||||
if (!ma_values.IsNull) {
|
||||
var values = ma_values.Read();
|
||||
var value = values[0];
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var key = entry.me_key;
|
||||
if (!value.IsNull && !key.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
entry = entry.GetAdjacentProxy(1);
|
||||
value = value.GetAdjacentProxy(1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var key = entry.me_key;
|
||||
var value = entry.me_value;
|
||||
if (!key.IsNull && !value.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
entry = entry.GetAdjacentProxy(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V310, StructName = "_dictkeysobject")]
|
||||
internal class PyDictKeysObject310 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> dk_size;
|
||||
public StructField<SSizeTProxy> dk_nentries;
|
||||
public StructField<ArrayProxy<SByteProxy>> dk_indices;
|
||||
}
|
||||
|
||||
public readonly Fields _fields;
|
||||
|
||||
public SSizeTProxy dk_size => GetFieldProxy(_fields.dk_size);
|
||||
|
||||
public SSizeTProxy dk_nentries {
|
||||
get { return GetFieldProxy(_fields.dk_nentries); }
|
||||
}
|
||||
|
||||
public IEnumerable<PyDictKeyEntry310> dk_entries {
|
||||
get {
|
||||
// dk_entries is located after dk_indices, which is
|
||||
// variable length depending on the size of the table.
|
||||
long size = dk_size.Read();
|
||||
long offset = _fields.dk_indices.Offset;
|
||||
if (size <= 0) {
|
||||
return default(ArrayProxy<PyDictKeyEntry310>);
|
||||
} else if (size <= 0xFF) {
|
||||
offset += size;
|
||||
} else if (size <= 0xFFFF) {
|
||||
offset += size * 2;
|
||||
} else if (size <= 0xFFFFFFFF) {
|
||||
offset += size * 4;
|
||||
} else {
|
||||
offset += size * 8;
|
||||
}
|
||||
|
||||
return DataProxy.Create<ArrayProxy<PyDictKeyEntry310>>(
|
||||
Process,
|
||||
Address.OffsetBy(offset)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public PyDictKeysObject310(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, StructName = "PyDictKeyEntry")]
|
||||
internal class PyDictKeyEntry310 : StructProxy {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyObject>> me_key;
|
||||
public StructField<PointerProxy<PyObject>> me_value;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictKeyEntry310(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_key {
|
||||
get { return GetFieldProxy(_fields.me_key); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_value {
|
||||
get { return GetFieldProxy(_fields.me_value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyDictObject", MinVersion = PythonLanguageVersion.V311)]
|
||||
[PyType(VariableName = "PyDict_Type", MinVersion = PythonLanguageVersion.V311)]
|
||||
internal class PyDictObject311 : PyDictObject {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyDictKeysObject311>> ma_keys;
|
||||
public StructField<PointerProxy<ArrayProxy<PointerProxy<PyObject>>>> ma_values;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyDictObject311>();
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictKeysObject311> ma_keys {
|
||||
get { return GetFieldProxy(_fields.ma_keys); }
|
||||
}
|
||||
|
||||
public PointerProxy<ArrayProxy<PointerProxy<PyObject>>> ma_values {
|
||||
get { return GetFieldProxy(_fields.ma_values); }
|
||||
}
|
||||
|
||||
public override IEnumerable<KeyValuePair<PyObject, PointerProxy<PyObject>>> ReadElements() {
|
||||
if (ma_keys.IsNull) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var keys = ma_keys.Read();
|
||||
var size = 1 << (int)keys.dk_log2_size.Read();
|
||||
if (size <= 0) {
|
||||
yield break;
|
||||
}
|
||||
|
||||
var n = keys.dk_nentries.Read();
|
||||
if (!ma_values.IsNull) {
|
||||
var values = ma_values.Read();
|
||||
var value = values[0];
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var entry = GetDkEntry(i);
|
||||
var key = entry.me_key;
|
||||
if (!value.IsNull && !key.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
value = value.GetAdjacentProxy(1);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
var entry = GetDkEntry(i);
|
||||
var key = entry.me_key;
|
||||
var value = entry.me_value;
|
||||
if (!key.IsNull && !value.IsNull) {
|
||||
yield return new KeyValuePair<PyObject, PointerProxy<PyObject>>(key.Read(), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IDictKeyEntry GetDkEntry(int position) {
|
||||
var keys = ma_keys.Read();
|
||||
if (keys.dk_kind.Read() == 0) {
|
||||
var entries = keys.dk_general_entries;
|
||||
return entries[position];
|
||||
} else {
|
||||
var entries = keys.dk_unicode_entries;
|
||||
return entries[position];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V311, StructName = "_dictkeysobject")]
|
||||
internal class PyDictKeysObject311 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> dk_log2_size;
|
||||
public StructField<SSizeTProxy> dk_log2_index_bytes;
|
||||
public StructField<SSizeTProxy> dk_nentries;
|
||||
public StructField<ArrayProxy<SByteProxy>> dk_indices;
|
||||
public StructField<ByteProxy> dk_kind;
|
||||
}
|
||||
|
||||
public readonly Fields _fields;
|
||||
|
||||
public SSizeTProxy dk_log2_size => GetFieldProxy(_fields.dk_log2_size);
|
||||
public SSizeTProxy dk_log2_index_bytes => GetFieldProxy(_fields.dk_log2_index_bytes);
|
||||
|
||||
public ByteProxy dk_kind => GetFieldProxy(_fields.dk_kind);
|
||||
|
||||
public SSizeTProxy dk_nentries {
|
||||
get { return GetFieldProxy(_fields.dk_nentries); }
|
||||
}
|
||||
|
||||
public ArrayProxy<PyDictKeyEntry311> dk_general_entries {
|
||||
get {
|
||||
// dk_entries is located after dk_indices, which is
|
||||
// variable length depending on the size of the table.
|
||||
long log_size = dk_log2_index_bytes.Read();
|
||||
long offset = _fields.dk_indices.Offset;
|
||||
offset += 1 << (int)log_size;
|
||||
|
||||
return DataProxy.Create<ArrayProxy<PyDictKeyEntry311>>(
|
||||
Process,
|
||||
Address.OffsetBy(offset)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayProxy<PyDictUnicodeEntry> dk_unicode_entries {
|
||||
get {
|
||||
// dk_entries is located after dk_indices, which is
|
||||
// variable length depending on the size of the table.
|
||||
long log_size = dk_log2_index_bytes.Read();
|
||||
long offset = _fields.dk_indices.Offset;
|
||||
offset += 1 << (int)log_size;
|
||||
|
||||
return DataProxy.Create<ArrayProxy<PyDictUnicodeEntry>>(
|
||||
Process,
|
||||
Address.OffsetBy(offset)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public PyDictKeysObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IDictKeyEntry : IDataProxy<IDictKeyEntry> {
|
||||
public PointerProxy<PyObject> me_key { get; }
|
||||
|
||||
public PointerProxy<PyObject> me_value { get; }
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V311, StructName ="PyDictKeyEntry")]
|
||||
internal class PyDictKeyEntry311 : StructProxy, IDictKeyEntry {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyObject>> me_key;
|
||||
public StructField<PointerProxy<PyObject>> me_value;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictKeyEntry311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_key {
|
||||
get { return GetFieldProxy(_fields.me_key); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_value {
|
||||
get { return GetFieldProxy(_fields.me_value); }
|
||||
}
|
||||
|
||||
public IDictKeyEntry Read() => this;
|
||||
}
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V311)]
|
||||
internal class PyDictUnicodeEntry : StructProxy, IDictKeyEntry {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyObject>> me_key;
|
||||
public StructField<PointerProxy<PyObject>> me_value;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyDictUnicodeEntry(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_key {
|
||||
get { return GetFieldProxy(_fields.me_key); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> me_value {
|
||||
get { return GetFieldProxy(_fields.me_value); }
|
||||
}
|
||||
|
||||
public IDictKeyEntry Read() => this;
|
||||
}
|
||||
}
|
|
@ -14,37 +14,16 @@
|
|||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.PythonTools.Common.Core.OS;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.VisualStudio.Debugger.CallStack;
|
||||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
using static Microsoft.VisualStudio.Threading.SingleThreadedSynchronizationContext;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, StructName = "_frame")]
|
||||
internal class PyFrameObject : PyVarObject {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyFrameObject>> f_back;
|
||||
public StructField<PointerProxy<PyCodeObject>> f_code;
|
||||
public StructField<PointerProxy<PyDictObject>> f_globals;
|
||||
public StructField<PointerProxy<PyDictObject>> f_locals;
|
||||
public StructField<Int32Proxy> f_lineno;
|
||||
public StructField<ArrayProxy<PointerProxy<PyObject>>> f_localsplus;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
internal abstract class PyFrameObject : PyVarObject {
|
||||
public PyFrameObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
var pythonInfo = process.GetPythonRuntimeInfo();
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyFrameObject>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,34 +56,26 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
|
||||
var framePtrAddress = PyFrameObject.GetFramePtrAddress(frame, previousFrameCount);
|
||||
if (framePtrAddress != 0) {
|
||||
return new PyFrameObject(frame.Process, framePtrAddress);
|
||||
var pythonInfo = process.GetPythonRuntimeInfo();
|
||||
if (pythonInfo.LanguageVersion < PythonLanguageVersion.V311) {
|
||||
return new PyFrameObject310(frame.Process, framePtrAddress);
|
||||
}
|
||||
return new PyFrameObject311(frame.Process, framePtrAddress);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PointerProxy<PyFrameObject> f_back {
|
||||
get { return GetFieldProxy(_fields.f_back); }
|
||||
}
|
||||
public abstract PointerProxy<PyFrameObject> f_back { get; }
|
||||
|
||||
public PointerProxy<PyCodeObject> f_code {
|
||||
get { return GetFieldProxy(_fields.f_code); }
|
||||
}
|
||||
public abstract PointerProxy<PyCodeObject> f_code { get; }
|
||||
|
||||
public PointerProxy<PyDictObject> f_globals {
|
||||
get { return GetFieldProxy(_fields.f_globals); }
|
||||
}
|
||||
public abstract PointerProxy<PyDictObject> f_globals { get; }
|
||||
|
||||
public PointerProxy<PyDictObject> f_locals {
|
||||
get { return GetFieldProxy(_fields.f_locals); }
|
||||
}
|
||||
public abstract PointerProxy<PyDictObject> f_locals { get; }
|
||||
|
||||
public Int32Proxy f_lineno {
|
||||
get { return GetFieldProxy(_fields.f_lineno); }
|
||||
}
|
||||
public abstract int ComputeLineNumber(DkmInspectionSession inspectionSession, DkmStackWalkFrame frame, DkmEvaluationFlags flags);
|
||||
|
||||
public ArrayProxy<PointerProxy<PyObject>> f_localsplus {
|
||||
get { return GetFieldProxy(_fields.f_localsplus); }
|
||||
}
|
||||
public abstract ArrayProxy<PointerProxy<PyObject>> f_localsplus { get; }
|
||||
|
||||
private static ulong GetFramePtrAddress(DkmStackWalkFrame frame, int? previousFrameCount) {
|
||||
// Frame address may already be stored in the frame, check the data.
|
||||
|
@ -115,12 +86,12 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
var process = frame.Process;
|
||||
var tid = frame.Thread.SystemPart.Id;
|
||||
PyThreadState tstate = PyThreadState.GetThreadStates(process).FirstOrDefault(ts => ts.thread_id.Read() == tid);
|
||||
PyFrameObject pyFrame = tstate.frame.Read();
|
||||
PyFrameObject pyFrame = tstate.frame.TryRead();
|
||||
if (pyFrame != null) {
|
||||
// This pyFrame should be the topmost frame. We need to go down the callstack
|
||||
// based on the number of previous frames that were already found.
|
||||
var numberBack = previousFrameCount != null ? previousFrameCount.Value : 0;
|
||||
while (numberBack > 0) {
|
||||
while (numberBack > 0 && pyFrame.f_back.Process != null) {
|
||||
pyFrame = pyFrame.f_back.Read();
|
||||
numberBack--;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger.CallStack;
|
||||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "_frame", MaxVersion = PythonLanguageVersion.V310)]
|
||||
[PyType(MaxVersion = PythonLanguageVersion.V310, VariableName = "PyFrame_Type")]
|
||||
internal class PyFrameObject310 : PyFrameObject {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyFrameObject>> f_back;
|
||||
public StructField<PointerProxy<PyCodeObject>> f_code;
|
||||
public StructField<PointerProxy<PyDictObject>> f_globals;
|
||||
public StructField<PointerProxy<PyDictObject>> f_locals;
|
||||
public StructField<PointerProxy<PyObject>> f_trace;
|
||||
public StructField<Int32Proxy> f_lineno;
|
||||
public StructField<ArrayProxy<PointerProxy<PyObject>>> f_localsplus;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public override PointerProxy<PyFrameObject> f_back => GetFieldProxy(_fields.f_back);
|
||||
|
||||
public override PointerProxy<PyCodeObject> f_code => GetFieldProxy(_fields.f_code);
|
||||
|
||||
public override PointerProxy<PyDictObject> f_globals => GetFieldProxy(_fields.f_globals);
|
||||
|
||||
public override PointerProxy<PyDictObject> f_locals => GetFieldProxy(_fields.f_locals);
|
||||
|
||||
public override ArrayProxy<PointerProxy<PyObject>> f_localsplus => GetFieldProxy(_fields.f_localsplus);
|
||||
|
||||
public override int ComputeLineNumber(DkmInspectionSession inspectionSession, DkmStackWalkFrame frame, DkmEvaluationFlags flags) => GetFieldProxy(_fields.f_lineno).Read();
|
||||
|
||||
public PyFrameObject310(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
var pythonInfo = process.GetPythonRuntimeInfo();
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyFrameObject310>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
using Microsoft.VisualStudio.Debugger.CallStack;
|
||||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "_frame", MinVersion = PythonLanguageVersion.V311)]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V311, VariableName = "PyFrame_Type")]
|
||||
internal class PyFrameObject311 : PyFrameObject {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyFrameObject>> f_back;
|
||||
public StructField<PointerProxy<PyInterpreterFrame>> f_frame;
|
||||
public StructField<PointerProxy<PyObject>> f_trace;
|
||||
public StructField<Int32Proxy> f_lineno;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyFrameObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
var pythonInfo = process.GetPythonRuntimeInfo();
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyFrameObject311>();
|
||||
}
|
||||
|
||||
public PointerProxy<PyInterpreterFrame> f_frame {
|
||||
get { return GetFieldProxy(_fields.f_frame); }
|
||||
}
|
||||
|
||||
private PyInterpreterFrame GetFrame() {
|
||||
return f_frame.TryRead();
|
||||
}
|
||||
|
||||
public override PointerProxy<PyFrameObject> f_back {
|
||||
get {
|
||||
// See the code here https://github.com/python/cpython/blob/a0866f4c81ecc057d4521e8e7a02f4e1fff175a1/Objects/frameobject.c#L1491,
|
||||
// f_back can be null when there is actually a frame because it's created lazily.
|
||||
var back = GetFieldProxy(_fields.f_back);
|
||||
if (back.IsNull) {
|
||||
back = GetFrame().FindBackFrame();
|
||||
}
|
||||
return back;
|
||||
}
|
||||
}
|
||||
|
||||
public override PointerProxy<PyCodeObject> f_code => GetFrame().f_code;
|
||||
|
||||
public override PointerProxy<PyDictObject> f_globals => GetFrame().f_globals;
|
||||
|
||||
public override PointerProxy<PyDictObject> f_locals => GetFrame().f_locals;
|
||||
|
||||
public override ArrayProxy<PointerProxy<PyObject>> f_localsplus => GetFrame().f_localsplus;
|
||||
|
||||
public override int ComputeLineNumber(DkmInspectionSession inspectionSession, DkmStackWalkFrame frame, DkmEvaluationFlags flags) {
|
||||
var setLineNumber = GetFieldProxy(_fields.f_lineno).Read();
|
||||
if (setLineNumber == 0 && flags != DkmEvaluationFlags.None) {
|
||||
// We need to use the CppExpressionEvaluator to compute the line number from
|
||||
// our frame object. This function here: https://github.com/python/cpython/blob/46710ca5f263936a2e36fa5d0f140cf9f50b2618/Objects/frameobject.c#L40-L41
|
||||
//
|
||||
// However only do this when stopped at a breakpoint and evaluating the frame. Otherwise we it will fail and cause stepping
|
||||
// to think the frame we eval is where we should stop.
|
||||
var evaluator = new CppExpressionEvaluator(inspectionSession, 10, frame, DkmEvaluationFlags.TreatAsExpression);
|
||||
var funcAddr = Process.GetPythonRuntimeInfo().DLLs.Python.GetFunctionAddress("PyFrame_GetLineNumber");
|
||||
var frameAddr = Address;
|
||||
try {
|
||||
setLineNumber = evaluator.EvaluateInt32(string.Format("((int (*)(void *)){0})({1})", funcAddr, frameAddr), DkmEvaluationFlags.EnableExtendedSideEffects);
|
||||
} catch (CppEvaluationException) {
|
||||
// This means we can't evaluate right now, just leave as zero
|
||||
setLineNumber = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return setLineNumber;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "PyFunctionObject", MinVersion = PythonLanguageVersion.V310)]
|
||||
internal class PyFunctionObject : PyObject {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyObject>> func_globals;
|
||||
public StructField<PointerProxy<PyObject>> func_builtins;
|
||||
public StructField<PointerProxy<PyObject>> func_name;
|
||||
public StructField<PointerProxy<PyObject>> func_qualname;
|
||||
public StructField<PointerProxy<PyObject>> func_code;
|
||||
public StructField<PointerProxy<PyObject>> func_defaults;
|
||||
public StructField<PointerProxy<PyObject>> func_kwdefaults;
|
||||
public StructField<PointerProxy<PyObject>> func_closure;
|
||||
public StructField<PointerProxy<PyObject>> func_doc;
|
||||
public StructField<PointerProxy<PyObject>> func_dict;
|
||||
public StructField<PointerProxy<PyObject>> func_weakreflist;
|
||||
public StructField<PointerProxy<PyObject>> func_module;
|
||||
public StructField<PointerProxy<PyObject>> func_annotations;
|
||||
public StructField<PointerProxy<UInt64Proxy>> vectorcall;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<UInt32Proxy> func_version;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyFunctionObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyFunctionObject>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
// This was added in commit https://github.com/python/cpython/commit/ae0a2b756255629140efcbe57fc2e714f0267aa3
|
||||
[StructProxy(StructName = "_PyInterpreterFrame", MinVersion = PythonLanguageVersion.V311)]
|
||||
internal class PyInterpreterFrame : StructProxy {
|
||||
internal class Fields {
|
||||
public StructField<PointerProxy<PyDictObject>> f_globals;
|
||||
public StructField<PointerProxy<PyDictObject>> f_builtins;
|
||||
public StructField<PointerProxy<PyDictObject>> f_locals;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<PointerProxy<PyCodeObject>> f_code;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V313)]
|
||||
public StructField<PointerProxy<PyCodeObject>> f_executable;
|
||||
public StructField<PointerProxy<PyFrameObject>> frame_obj;
|
||||
public StructField<PointerProxy<PyInterpreterFrame>> previous;
|
||||
public StructField<ArrayProxy<PointerProxy<PyObject>>> localsplus;
|
||||
public StructField<CharProxy> owner;
|
||||
}
|
||||
|
||||
private const int FRAME_OWNED_BY_THREAD = 0;
|
||||
private const int FRAME_OWNED_BY_GENERATOR = 1;
|
||||
private const int FRAME_OWNED_BY_FRAME_OBJECT = 2;
|
||||
private const int FRAME_OWNED_BY_CSTACK = 3;
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyInterpreterFrame(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyCodeObject> f_code {
|
||||
get {
|
||||
// In 3.13, the f_code was renamed to f_executable
|
||||
if (_fields.f_code.Process != null) {
|
||||
return GetFieldProxy(_fields.f_code);
|
||||
}
|
||||
return GetFieldProxy(_fields.f_executable);
|
||||
}
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictObject> f_globals {
|
||||
get { return GetFieldProxy(_fields.f_globals); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictObject> f_locals {
|
||||
get { return GetFieldProxy(_fields.f_locals); }
|
||||
}
|
||||
|
||||
public ArrayProxy<PointerProxy<PyObject>> f_localsplus {
|
||||
get { return GetFieldProxy(_fields.localsplus); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyFrameObject> frame_obj {
|
||||
get { return GetFieldProxy(_fields.frame_obj); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyInterpreterFrame> previous => GetFieldProxy(_fields.previous);
|
||||
|
||||
private bool OwnedByThread() {
|
||||
if (Process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
return true;
|
||||
}
|
||||
var owner = (GetFieldProxy(_fields.owner) as IValueStore).Read();
|
||||
var charOwner = owner.ToString()[0];
|
||||
return (int)charOwner == FRAME_OWNED_BY_THREAD;
|
||||
}
|
||||
|
||||
public PointerProxy<PyFrameObject> FindBackFrame() {
|
||||
// Trace.WriteLine("Searching for back frame ...");
|
||||
var frame = previous.TryRead();
|
||||
while (frame != null && !frame.OwnedByThread()) {
|
||||
frame = frame.previous.TryRead();
|
||||
}
|
||||
|
||||
// Make sure this frame_obj is pointing to this frame. Since the f_back
|
||||
// of a PyFrameObject can be null even if it exists, the PyFrameObject we find
|
||||
// through the list of PyInterpreterFrames may not have been created. We need
|
||||
// to make sure it points to the PyInterpreterFrame we found so that subsequent calls
|
||||
// to get things like its f_locals will work.
|
||||
if (frame != null && !frame.frame_obj.IsNull) {
|
||||
var obj = frame.frame_obj.Read() as PyFrameObject311;
|
||||
obj.f_frame.Write(frame);
|
||||
return frame.frame_obj;
|
||||
}
|
||||
return default(PointerProxy<PyFrameObject>);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
// permissions and limitations under the License.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
|
@ -23,8 +24,14 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
internal class PyInterpreterState : StructProxy {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyInterpreterState>> next;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V310)]
|
||||
public StructField<PointerProxy<PyThreadState>> tstate_head;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PyThreads> threads;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PointerProxy<PyDictObject>> modules;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<ImportState> imports;
|
||||
public StructField<PointerProxy> eval_frame;
|
||||
public StructField<ceval_state> ceval;
|
||||
}
|
||||
|
@ -49,11 +56,23 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
}
|
||||
|
||||
public PointerProxy<PyThreadState> tstate_head {
|
||||
get { return GetFieldProxy(_fields.tstate_head); }
|
||||
get {
|
||||
if (_fields.tstate_head.Process != null) {
|
||||
return GetFieldProxy(_fields.tstate_head);
|
||||
}
|
||||
var threads = GetFieldProxy(_fields.threads);
|
||||
return threads.head;
|
||||
}
|
||||
}
|
||||
|
||||
public PointerProxy<PyDictObject> modules {
|
||||
get { return GetFieldProxy(_fields.modules); }
|
||||
get {
|
||||
if (_fields.modules.Process != null) {
|
||||
return GetFieldProxy(_fields.modules);
|
||||
}
|
||||
var imports = GetFieldProxy(_fields.imports);
|
||||
return imports.modules;
|
||||
}
|
||||
}
|
||||
|
||||
public PointerProxy eval_frame {
|
||||
|
@ -62,29 +81,31 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
|
||||
public ceval_state ceval => GetFieldProxy(_fields.ceval);
|
||||
|
||||
private class InterpHeadHolder : DkmDataItem {
|
||||
public readonly PointerProxy<PyInterpreterState> Proxy;
|
||||
|
||||
public InterpHeadHolder(DkmProcess process) {
|
||||
var pyrtInfo = process.GetPythonRuntimeInfo();
|
||||
Proxy = pyrtInfo.GetRuntimeState()?.interpreters.head
|
||||
?? pyrtInfo.DLLs.Python.GetStaticVariable<PointerProxy<PyInterpreterState>>("interp_head");
|
||||
}
|
||||
}
|
||||
|
||||
public static PointerProxy<PyInterpreterState> interp_head(DkmProcess process) {
|
||||
return process.GetOrCreateDataItem(() => new InterpHeadHolder(process)).Proxy;
|
||||
}
|
||||
|
||||
public static IEnumerable<PyInterpreterState> GetInterpreterStates(DkmProcess process) {
|
||||
for (var interp = interp_head(process).TryRead(); interp != null; interp = interp.next.TryRead()) {
|
||||
yield return interp;
|
||||
var pyrtInfo = process.GetPythonRuntimeInfo();
|
||||
var runtimeState = pyrtInfo.GetRuntimeState();
|
||||
var interpreters = runtimeState.interpreters;
|
||||
var head = interpreters.head.TryRead();
|
||||
while (head != null) {
|
||||
yield return head;
|
||||
head = head.next.TryRead();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PyThreadState> GetThreadStates() {
|
||||
for (var tstate = tstate_head.TryRead(); tstate != null; tstate = tstate.next.TryRead()) {
|
||||
yield return tstate;
|
||||
public IEnumerable<PyThreadState> GetThreadStates(DkmProcess process) {
|
||||
var pyrtInfo = process.GetPythonRuntimeInfo();
|
||||
if (pyrtInfo.LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
for (var tstate = tstate_head.TryRead(); tstate != null; tstate = tstate.next.TryRead()) {
|
||||
yield return tstate;
|
||||
}
|
||||
} else {
|
||||
var threads = GetFieldProxy(_fields.threads);
|
||||
var head = threads.head.TryRead();
|
||||
while (head != null && head.Address != 0) {
|
||||
yield return head;
|
||||
head = head.next.TryRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +113,7 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public class ceval_state : StructProxy {
|
||||
private class Fields {
|
||||
public StructField<Int32Proxy> recursion_limit;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V39)]
|
||||
public StructField<Int32Proxy> tracing_possible;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
internal class PyLongObject : PyVarObject {
|
||||
private class Fields {
|
||||
[FieldProxy(MaxVersion = Common.Parsing.PythonLanguageVersion.V311)]
|
||||
public StructField<ByteProxy> ob_digit; // this is actually either uint16 or uint32, depending on Python bitness
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<_PyLongValue> long_value;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
@ -40,6 +44,16 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
}
|
||||
|
||||
public static PyLongObject Create(DkmProcess process, BigInteger value) {
|
||||
// Use two different methods. PyLongObjects changed in 3.12. Instead of inheritance, we'll use an if statement so
|
||||
// that we don't have to change classes derived from PyLongObject.
|
||||
if (process.GetPythonRuntimeInfo().LanguageVersion < PythonLanguageVersion.V312) {
|
||||
return Create11(process, value);
|
||||
} else {
|
||||
return Create12(process, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static PyLongObject Create11(DkmProcess process, BigInteger value) {
|
||||
var allocator = process.GetDataItem<PyObjectAllocator>();
|
||||
Debug.Assert(allocator != null);
|
||||
|
||||
|
@ -77,12 +91,69 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static PyLongObject Create12(DkmProcess process, BigInteger value) {
|
||||
var allocator = process.GetDataItem<PyObjectAllocator>();
|
||||
Debug.Assert(allocator != null);
|
||||
|
||||
var bitsInDigit = process.Is64Bit() ? 30 : 15;
|
||||
var bytesInDigit = process.Is64Bit() ? 4 : 2;
|
||||
|
||||
var absValue = BigInteger.Abs(value);
|
||||
long numDigits = 0;
|
||||
for (var t = absValue; t != 0;) {
|
||||
++numDigits;
|
||||
t >>= bitsInDigit;
|
||||
}
|
||||
|
||||
var result = allocator.Allocate<PyLongObject>(numDigits * bytesInDigit);
|
||||
|
||||
// Size comes from here:
|
||||
// https://github.com/python/cpython/blob/a0866f4c81ecc057d4521e8e7a02f4e1fff175a1/Objects/longobject.c#L158
|
||||
var fields = StructProxy.GetStructFields<_PyLongValue, _PyLongValue.Fields>(process);
|
||||
long ob_size = numDigits * bytesInDigit + fields.ob_digit.Offset;
|
||||
result.ob_size.Write(ob_size);
|
||||
|
||||
// Digits are stored in the long_value.lv_data field in 3.12
|
||||
result.long_value.WriteTag((ulong)numDigits, value == 0, value < 0);
|
||||
|
||||
// Then we write the data out one digit at a time
|
||||
if (bitsInDigit == 15) {
|
||||
for (var digitPtr = new UInt16Proxy(process, result.ob_digit.Address); absValue != 0; digitPtr = digitPtr.GetAdjacentProxy(1)) {
|
||||
digitPtr.Write((ushort)(absValue % (1 << bitsInDigit)));
|
||||
absValue >>= bitsInDigit;
|
||||
}
|
||||
} else {
|
||||
for (var digitPtr = new UInt32Proxy(process, result.ob_digit.Address); absValue != 0; digitPtr = digitPtr.GetAdjacentProxy(1)) {
|
||||
digitPtr.Write((uint)(absValue % (1 << bitsInDigit)));
|
||||
absValue >>= bitsInDigit;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ByteProxy ob_digit {
|
||||
get { return GetFieldProxy(_fields.ob_digit); }
|
||||
get {
|
||||
if (_fields.ob_digit.Process != null) {
|
||||
return GetFieldProxy(_fields.ob_digit);
|
||||
} else {
|
||||
return GetFieldProxy(_fields.long_value).ob_digit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BigInteger ToBigInteger() {
|
||||
if (Process.GetPythonRuntimeInfo().LanguageVersion < PythonLanguageVersion.V312) {
|
||||
return ToBigInteger11();
|
||||
} else {
|
||||
return ToBigInteger12();
|
||||
}
|
||||
}
|
||||
|
||||
public _PyLongValue long_value => GetFieldProxy(_fields.long_value);
|
||||
|
||||
private BigInteger ToBigInteger11() {
|
||||
var bitsInDigit = Process.Is64Bit() ? 30 : 15;
|
||||
|
||||
long ob_size = this.ob_size.Read();
|
||||
|
@ -112,8 +183,86 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
return ob_size > 0 ? result : -result;
|
||||
}
|
||||
|
||||
public BigInteger ToBigInteger12() {
|
||||
var bitsInDigit = Process.Is64Bit() ? 30 : 15;
|
||||
var long_value = GetFieldProxy(_fields.long_value);
|
||||
long count = long_value.digit_count;
|
||||
|
||||
// Read and parse digits in reverse, starting from the most significant ones.
|
||||
var result = new BigInteger(0);
|
||||
if (bitsInDigit == 15) {
|
||||
var digitPtr = new UInt16Proxy(Process, ob_digit.Address).GetAdjacentProxy(count);
|
||||
for (long i = 0; i != count; ++i) {
|
||||
digitPtr = digitPtr.GetAdjacentProxy(-1);
|
||||
result <<= bitsInDigit;
|
||||
result += digitPtr.Read();
|
||||
}
|
||||
} else {
|
||||
var digitPtr = new UInt32Proxy(Process, ob_digit.Address).GetAdjacentProxy(count);
|
||||
for (long i = 0; i != count; ++i) {
|
||||
digitPtr = digitPtr.GetAdjacentProxy(-1);
|
||||
result <<= bitsInDigit;
|
||||
result += digitPtr.Read();
|
||||
}
|
||||
}
|
||||
|
||||
return long_value.is_negative ? -result : result;
|
||||
}
|
||||
|
||||
public override void Repr(ReprBuilder builder) {
|
||||
builder.AppendLiteral(ToBigInteger());
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V312, StructName = "_PyLongValue")]
|
||||
public class _PyLongValue : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<UInt64Proxy> lv_tag;
|
||||
public StructField<ByteProxy> ob_digit;
|
||||
}
|
||||
|
||||
private const int SIGN_ZERO = 1;
|
||||
private const int SIGN_NEGATIVE = 2;
|
||||
private const int NON_SIZE_BITS = 3;
|
||||
private const int SIGN_MASK = 3;
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public _PyLongValue(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public ByteProxy ob_digit => GetFieldProxy(_fields.ob_digit);
|
||||
|
||||
public UInt64Proxy lv_tag => GetFieldProxy(_fields.lv_tag);
|
||||
|
||||
public void WriteTag(ulong numberDigits, bool isZero, bool isNegative) {
|
||||
ulong lv_tag = numberDigits << NON_SIZE_BITS;
|
||||
if (isZero) {
|
||||
lv_tag |= SIGN_ZERO;
|
||||
} else if (isNegative) {
|
||||
lv_tag |= SIGN_NEGATIVE;
|
||||
}
|
||||
this.lv_tag.Write(lv_tag);
|
||||
}
|
||||
|
||||
public uint digit_count {
|
||||
get {
|
||||
return (uint)(lv_tag.Read() >> NON_SIZE_BITS);
|
||||
}
|
||||
|
||||
set {
|
||||
lv_tag.Write((value << NON_SIZE_BITS) | (lv_tag.Read() & SIGN_MASK));
|
||||
}
|
||||
}
|
||||
|
||||
public bool is_negative {
|
||||
get {
|
||||
return (lv_tag.Read() & SIGN_MASK) == SIGN_NEGATIVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public string VariableName { get; set; }
|
||||
public PythonLanguageVersion MinVersion { get; set; }
|
||||
public PythonLanguageVersion MaxVersion { get; set; }
|
||||
public bool Hidden { get; set; }
|
||||
}
|
||||
|
||||
internal interface IPyObject : IValueStore<PyObject>, IDataProxy<StructProxy> {
|
||||
|
@ -81,6 +82,9 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
if (pyTypeAttr.MaxVersion != PythonLanguageVersion.None && langVer > pyTypeAttr.MaxVersion) {
|
||||
continue;
|
||||
}
|
||||
if (pyTypeAttr.Hidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
typeVarName = pyTypeAttr.VariableName ?? ComputeVariableName(proxyType);
|
||||
break;
|
||||
|
@ -169,7 +173,12 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
} else if (dictoffset < 0) {
|
||||
var varObj = this as PyVarObject;
|
||||
if (varObj == null) {
|
||||
throw new InvalidDataException();
|
||||
// Prior to 3.11 this should have been an error. In 3.11 many objects have negative tp_dictoffset
|
||||
if (Process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
Debug.Fail("Non-var object with negative tp_dictoffset.");
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
long size = ob_type.tp_basicsize.Read();
|
||||
|
|
|
@ -32,6 +32,7 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public StructField<BoolProxy> core_initialized;
|
||||
public StructField<BoolProxy> initialized;
|
||||
public StructField<pyinterpreters> interpreters;
|
||||
public StructField<gilstate_runtime_state> gilstate;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
@ -44,6 +45,7 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public BoolProxy core_initialized => GetFieldProxy(_fields.core_initialized);
|
||||
public BoolProxy initialized => GetFieldProxy(_fields.initialized);
|
||||
public pyinterpreters interpreters => GetFieldProxy(_fields.interpreters);
|
||||
public gilstate_runtime_state gilstate => GetFieldProxy(_fields.gilstate);
|
||||
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, StructName = "pyinterpreters")]
|
||||
|
@ -64,6 +66,22 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public PointerProxy<PyInterpreterState> main => GetFieldProxy(_fields.main);
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V312, StructName = "_gilstate_runtime_state")]
|
||||
public class gilstate_runtime_state : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<Int32Proxy> check_enabled;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public gilstate_runtime_state(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public Int32Proxy check_enabled => GetFieldProxy(_fields.check_enabled);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -24,15 +24,27 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
internal class PyThreadState : StructProxy {
|
||||
private class Fields {
|
||||
public StructField<PointerProxy<PyThreadState>> next;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V310)]
|
||||
public StructField<PointerProxy<PyFrameObject>> frame;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PointerProxy<PyInterpreterState>> interp;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V39)]
|
||||
public StructField<Int32Proxy> use_tracing;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V310, MaxVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<PointerProxy<CFrameProxy>> cframe;
|
||||
public StructField<PointerProxy> c_tracefunc;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PointerProxy<PyObject>> curexc_type;
|
||||
[FieldProxy(MaxVersion = PythonLanguageVersion.V311)]
|
||||
public StructField<PointerProxy<PyObject>> curexc_value;
|
||||
public StructField<PointerProxy<PyObject>> curexc_traceback;
|
||||
public StructField<PyErr_StackItem> exc_state;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<PointerProxy<PyBaseExceptionObject>> current_exception;
|
||||
public StructField<PointerProxy<PyErr_StackItem>> exc_info;
|
||||
public StructField<Int32Proxy> thread_id;
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V312)]
|
||||
public StructField<Int32Proxy> tracing; // Indicates if sys.monitoring is set, not something we set here.
|
||||
[FieldProxy(MinVersion = PythonLanguageVersion.V313)]
|
||||
public StructField<PointerProxy<PyInterpreterFrame>> current_frame;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
@ -54,11 +66,27 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
}
|
||||
|
||||
public PointerProxy<PyFrameObject> frame {
|
||||
get { return GetFieldProxy(_fields.frame); }
|
||||
get {
|
||||
if (_fields.frame.Process != null) {
|
||||
return GetFieldProxy(_fields.frame);
|
||||
}
|
||||
|
||||
// In 3.11, the current frame was moved into the cframe
|
||||
if (_fields.cframe.Process != null) {
|
||||
var cframe = GetFieldProxy(_fields.cframe).Read();
|
||||
var interpFrame311 = cframe.current_frame.TryRead();
|
||||
return interpFrame311.frame_obj;
|
||||
}
|
||||
|
||||
// In 3.13, cframe was removed and the current_frame was just placed
|
||||
// in the thread.
|
||||
var interpFrame = GetFieldProxy(_fields.current_frame).TryRead();
|
||||
return interpFrame.frame_obj;
|
||||
}
|
||||
}
|
||||
|
||||
public Int32Proxy use_tracing {
|
||||
get { return GetFieldProxy(_fields.use_tracing); }
|
||||
public PointerProxy<CFrameProxy> cframe {
|
||||
get { return GetFieldProxy(_fields.cframe); }
|
||||
}
|
||||
|
||||
public PointerProxy c_tracefunc {
|
||||
|
@ -66,33 +94,52 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
}
|
||||
|
||||
public PointerProxy<PyObject> curexc_type {
|
||||
get { return GetFieldProxy(_fields.curexc_type); }
|
||||
get {
|
||||
if (_fields.curexc_type.Process != null) {
|
||||
return GetFieldProxy(_fields.curexc_type);
|
||||
}
|
||||
|
||||
// In 3.12, the current exception was stored by itself instead of separately with the
|
||||
// type and value.
|
||||
var exc = GetFieldProxy(_fields.current_exception).Read();
|
||||
return exc.ob_type.ReinterpretCast<PyObject>();
|
||||
}
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> curexc_value {
|
||||
get { return GetFieldProxy(_fields.curexc_value); }
|
||||
get {
|
||||
if (_fields.curexc_value.Process != null) {
|
||||
return GetFieldProxy(_fields.curexc_value);
|
||||
}
|
||||
|
||||
// In 3.12, the current exception was stored by itself instead of separately with the
|
||||
// type and value.
|
||||
return GetFieldProxy(_fields.current_exception).ReinterpretCast<PyObject>();
|
||||
}
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> curexc_traceback {
|
||||
get { return GetFieldProxy(_fields.curexc_traceback); }
|
||||
}
|
||||
|
||||
public PointerProxy<PyObject> exc_type(PythonLanguageVersion version) =>
|
||||
GetFieldProxy(_fields.exc_state).exc_type;
|
||||
|
||||
public PointerProxy<PyObject> exc_value(PythonLanguageVersion version) =>
|
||||
GetFieldProxy(_fields.exc_state).exc_value;
|
||||
|
||||
public PointerProxy<PyObject> exc_traceback(PythonLanguageVersion version) =>
|
||||
GetFieldProxy(_fields.exc_state).exc_traceback;
|
||||
|
||||
|
||||
public Int32Proxy thread_id {
|
||||
get { return GetFieldProxy(_fields.thread_id); }
|
||||
}
|
||||
|
||||
public static IEnumerable<PyThreadState> GetThreadStates(DkmProcess process) {
|
||||
return PyInterpreterState.GetInterpreterStates(process).SelectMany(interp => interp.GetThreadStates());
|
||||
return PyInterpreterState.GetInterpreterStates(process).SelectMany(interp => interp.GetThreadStates(process));
|
||||
}
|
||||
|
||||
public void RegisterTracing(ulong traceFunc) {
|
||||
// In 3.10, the use_tracing flag sets tracing for the thread.
|
||||
if (_fields.use_tracing.Process != null) {
|
||||
GetFieldProxy(_fields.use_tracing).Write(1);
|
||||
}
|
||||
// In 3.11 the cframe has the use_tracing flag, but must be set to 255.
|
||||
if (_fields.cframe.Process != null && Process.GetPythonRuntimeInfo().LanguageVersion == PythonLanguageVersion.V311) {
|
||||
var frame = cframe.Read();
|
||||
frame.use_tracing.Write(255);
|
||||
}
|
||||
// In 3.12, there's no longer a use_tracing flag. We have to register tracing through an API instead.
|
||||
if (Process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V311) {
|
||||
c_tracefunc.Write(traceFunc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// Python Tools for Visual Studio
|
||||
// Copyright(c) Microsoft Corporation
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the License); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS
|
||||
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
||||
// IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
// MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
//
|
||||
// See the Apache Version 2.0 License for specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(StructName = "pythreads", MinVersion = PythonLanguageVersion.V311)]
|
||||
internal class PyThreads: StructProxy {
|
||||
internal class Fields {
|
||||
public StructField<UInt64Proxy> next_unique_id;
|
||||
public StructField<PointerProxy<PyThreadState>> head;
|
||||
public StructField<Int64Proxy> count;
|
||||
public StructField<UInt64Proxy> stacksize;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyThreads(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public PointerProxy<PyThreadState> head {
|
||||
get { return GetFieldProxy(_fields.head); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,7 +38,7 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
get { return GetFieldProxy(_fields.ob_item); }
|
||||
}
|
||||
|
||||
public IEnumerable<PointerProxy<PyObject>> ReadElements() {
|
||||
public virtual IEnumerable<PointerProxy<PyObject>> ReadElements() {
|
||||
return ob_item.Take(ob_size.Read());
|
||||
}
|
||||
|
||||
|
|
|
@ -23,176 +23,11 @@ using Microsoft.VisualStudio.Debugger;
|
|||
using Microsoft.VisualStudio.Debugger.Evaluation;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, StructName = "PyUnicodeObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V39, VariableName = "PyUnicode_Type")]
|
||||
internal class PyUnicodeObject : PyVarObject, IPyBaseStringObject {
|
||||
private static readonly Encoding _latin1 = Encoding.GetEncoding("Latin1");
|
||||
|
||||
private enum PyUnicode_Kind {
|
||||
PyUnicode_WCHAR_KIND = 0,
|
||||
PyUnicode_1BYTE_KIND = 1,
|
||||
PyUnicode_2BYTE_KIND = 2,
|
||||
PyUnicode_4BYTE_KIND = 4
|
||||
}
|
||||
|
||||
private enum Interned {
|
||||
SSTATE_NOT_INTERNED = 0,
|
||||
SSTATE_INTERNED_MORTAL = 1,
|
||||
SSTATE_INTERNED_IMMORTAL = 2
|
||||
}
|
||||
|
||||
private struct State {
|
||||
private static readonly BitVector32.Section
|
||||
internedSection = BitVector32.CreateSection(2),
|
||||
kindSection = BitVector32.CreateSection(4, internedSection),
|
||||
compactSection = BitVector32.CreateSection(1, kindSection),
|
||||
asciiSection = BitVector32.CreateSection(1, compactSection),
|
||||
readySection = BitVector32.CreateSection(1, asciiSection);
|
||||
|
||||
private BitVector32 _state;
|
||||
|
||||
private State(byte state) {
|
||||
_state = new BitVector32(state);
|
||||
}
|
||||
|
||||
public static explicit operator State(byte state) {
|
||||
return new State(state);
|
||||
}
|
||||
|
||||
public static explicit operator byte(State state) {
|
||||
return (byte)state._state.Data;
|
||||
}
|
||||
|
||||
public Interned interned {
|
||||
get { return (Interned)_state[internedSection]; }
|
||||
set { _state[internedSection] = (int)value; }
|
||||
}
|
||||
|
||||
public PyUnicode_Kind kind {
|
||||
get { return (PyUnicode_Kind)_state[kindSection]; }
|
||||
set { _state[kindSection] = (int)value; }
|
||||
}
|
||||
|
||||
public bool compact {
|
||||
get { return _state[compactSection] != 0; }
|
||||
set { _state[compactSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ascii {
|
||||
get { return _state[asciiSection] != 0; }
|
||||
set { _state[asciiSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ready {
|
||||
get { return _state[readySection] != 0; }
|
||||
set { _state[readySection] = value ? 1 : 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public class Fields {
|
||||
public StructField<PointerProxy> data;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
private readonly PyASCIIObject _asciiObject;
|
||||
private readonly PyCompactUnicodeObject _compactObject;
|
||||
internal abstract class PyUnicodeObject : PyVarObject, IPyBaseStringObject {
|
||||
protected static readonly Encoding _latin1 = Encoding.GetEncoding("Latin1");
|
||||
|
||||
public PyUnicodeObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyUnicodeObject>();
|
||||
|
||||
_asciiObject = new PyASCIIObject(process, address);
|
||||
_compactObject = new PyCompactUnicodeObject(process, address);
|
||||
}
|
||||
|
||||
public static PyUnicodeObject Create(DkmProcess process, string value) {
|
||||
var allocator = process.GetDataItem<PyObjectAllocator>();
|
||||
Debug.Assert(allocator != null);
|
||||
|
||||
var result = allocator.Allocate<PyUnicodeObject>(value.Length * sizeof(char));
|
||||
|
||||
result._asciiObject.hash.Write(-1);
|
||||
result._asciiObject.length.Write(value.Length);
|
||||
result._compactObject.wstr_length.Write(value.Length);
|
||||
|
||||
var state = new State {
|
||||
interned = Interned.SSTATE_NOT_INTERNED,
|
||||
kind = PyUnicode_Kind.PyUnicode_2BYTE_KIND,
|
||||
compact = true,
|
||||
ascii = false,
|
||||
ready = true
|
||||
};
|
||||
result._asciiObject.state.Write((byte)state);
|
||||
|
||||
ulong dataPtr = result.Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject>(process));
|
||||
result._asciiObject.wstr.Write(dataPtr);
|
||||
process.WriteMemory(dataPtr, Encoding.Unicode.GetBytes(value));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString() {
|
||||
byte[] buf;
|
||||
|
||||
State state = (State)_asciiObject.state.Read();
|
||||
if (state.ascii) {
|
||||
state.kind = PyUnicode_Kind.PyUnicode_1BYTE_KIND;
|
||||
}
|
||||
|
||||
if (!state.ready) {
|
||||
ulong wstr = _asciiObject.wstr.Read();
|
||||
if (wstr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
uint wstr_length = checked((uint)_compactObject.wstr_length.Read());
|
||||
if (wstr_length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
buf = new byte[wstr_length * 2];
|
||||
Process.ReadMemory(wstr, DkmReadMemoryFlags.None, buf);
|
||||
return Encoding.Unicode.GetString(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
int length = checked((int)_asciiObject.length.Read());
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
ulong data;
|
||||
if (!state.compact) {
|
||||
data = GetFieldProxy(_fields.data).Read();
|
||||
} else if (state.ascii) {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyASCIIObject>(Process));
|
||||
} else {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject>(Process));
|
||||
}
|
||||
if (data == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
buf = new byte[length * (int)state.kind];
|
||||
Process.ReadMemory(data, DkmReadMemoryFlags.None, buf);
|
||||
Encoding enc;
|
||||
switch (state.kind) {
|
||||
case PyUnicode_Kind.PyUnicode_1BYTE_KIND:
|
||||
enc = _latin1;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_2BYTE_KIND:
|
||||
enc = Encoding.Unicode;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_4BYTE_KIND:
|
||||
enc = Encoding.UTF32;
|
||||
break;
|
||||
default:
|
||||
Debug.Fail("Unsupported PyUnicode_Kind " + state.kind);
|
||||
return null;
|
||||
}
|
||||
|
||||
return enc.GetString(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
public override void Repr(ReprBuilder builder) {
|
||||
|
@ -214,54 +49,15 @@ namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
|||
public static explicit operator string(PyUnicodeObject obj) {
|
||||
return (object)obj == null ? null : obj.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
internal class PyASCIIObject : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> length;
|
||||
public StructField<SSizeTProxy> hash;
|
||||
public StructField<ByteProxy> state;
|
||||
public StructField<PointerProxy> wstr;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyASCIIObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy length {
|
||||
get { return GetFieldProxy(_fields.length); }
|
||||
}
|
||||
|
||||
public SSizeTProxy hash {
|
||||
get { return GetFieldProxy(_fields.hash); }
|
||||
}
|
||||
|
||||
public ByteProxy state {
|
||||
get { return GetFieldProxy(_fields.state); }
|
||||
}
|
||||
|
||||
public PointerProxy wstr {
|
||||
get { return GetFieldProxy(_fields.wstr); }
|
||||
public static PyUnicodeObject Create(DkmProcess process, string value) {
|
||||
if (process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V311) {
|
||||
return PyUnicodeObject311.Create311(process, value);
|
||||
} else {
|
||||
return PyUnicodeObject312.Create312(process, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class PyCompactUnicodeObject : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> wstr_length;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyCompactUnicodeObject(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy wstr_length {
|
||||
get { return GetFieldProxy(_fields.wstr_length); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,232 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V311, StructName = "PyUnicodeObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V311, VariableName = "PyUnicode_Type")]
|
||||
internal class PyUnicodeObject311 : PyUnicodeObject {
|
||||
private enum PyUnicode_Kind {
|
||||
PyUnicode_WCHAR_KIND = 0,
|
||||
PyUnicode_1BYTE_KIND = 1,
|
||||
PyUnicode_2BYTE_KIND = 2,
|
||||
PyUnicode_4BYTE_KIND = 4
|
||||
}
|
||||
|
||||
private enum Interned {
|
||||
SSTATE_NOT_INTERNED = 0,
|
||||
SSTATE_INTERNED_MORTAL = 1,
|
||||
SSTATE_INTERNED_IMMORTAL = 2
|
||||
}
|
||||
|
||||
private struct State {
|
||||
private static readonly BitVector32.Section
|
||||
internedSection = BitVector32.CreateSection(2),
|
||||
kindSection = BitVector32.CreateSection(4, internedSection),
|
||||
compactSection = BitVector32.CreateSection(1, kindSection),
|
||||
asciiSection = BitVector32.CreateSection(1, compactSection),
|
||||
readySection = BitVector32.CreateSection(1, asciiSection);
|
||||
|
||||
private BitVector32 _state;
|
||||
|
||||
private State(byte state) {
|
||||
_state = new BitVector32(state);
|
||||
}
|
||||
|
||||
public static explicit operator State(byte state) {
|
||||
return new State(state);
|
||||
}
|
||||
|
||||
public static explicit operator byte(State state) {
|
||||
return (byte)state._state.Data;
|
||||
}
|
||||
|
||||
public Interned interned {
|
||||
get { return (Interned)_state[internedSection]; }
|
||||
set { _state[internedSection] = (int)value; }
|
||||
}
|
||||
|
||||
public PyUnicode_Kind kind {
|
||||
get { return (PyUnicode_Kind)_state[kindSection]; }
|
||||
set { _state[kindSection] = (int)value; }
|
||||
}
|
||||
|
||||
public bool compact {
|
||||
get { return _state[compactSection] != 0; }
|
||||
set { _state[compactSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ascii {
|
||||
get { return _state[asciiSection] != 0; }
|
||||
set { _state[asciiSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ready {
|
||||
get { return _state[readySection] != 0; }
|
||||
set { _state[readySection] = value ? 1 : 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public class Fields {
|
||||
public StructField<PointerProxy> data;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
private readonly PyASCIIObject311 _asciiObject;
|
||||
private readonly PyCompactUnicodeObject311 _compactObject;
|
||||
|
||||
public PyUnicodeObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyUnicodeObject311>();
|
||||
|
||||
_asciiObject = new PyASCIIObject311(process, address);
|
||||
_compactObject = new PyCompactUnicodeObject311(process, address);
|
||||
}
|
||||
|
||||
public static PyUnicodeObject311 Create311(DkmProcess process, string value) {
|
||||
var allocator = process.GetDataItem<PyObjectAllocator>();
|
||||
Debug.Assert(allocator != null);
|
||||
|
||||
var result = allocator.Allocate<PyUnicodeObject311>(value.Length * sizeof(char));
|
||||
|
||||
result._asciiObject.hash.Write(-1);
|
||||
result._asciiObject.length.Write(value.Length);
|
||||
result._compactObject.wstr_length.Write(value.Length);
|
||||
|
||||
var state = new State {
|
||||
interned = Interned.SSTATE_NOT_INTERNED,
|
||||
kind = PyUnicode_Kind.PyUnicode_2BYTE_KIND,
|
||||
compact = true,
|
||||
ascii = false,
|
||||
ready = true
|
||||
};
|
||||
result._asciiObject.state.Write((byte)state);
|
||||
|
||||
ulong dataPtr = result.Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject311>(process));
|
||||
result._asciiObject.wstr.Write(dataPtr);
|
||||
process.WriteMemory(dataPtr, Encoding.Unicode.GetBytes(value));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
byte[] buf;
|
||||
|
||||
State state = (State)_asciiObject.state.Read();
|
||||
if (state.ascii) {
|
||||
state.kind = PyUnicode_Kind.PyUnicode_1BYTE_KIND;
|
||||
}
|
||||
|
||||
if (!state.ready) {
|
||||
ulong wstr = _asciiObject.wstr.Read();
|
||||
if (wstr == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
uint wstr_length = checked((uint)_compactObject.wstr_length.Read());
|
||||
if (wstr_length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
buf = new byte[wstr_length * 2];
|
||||
Process.ReadMemory(wstr, DkmReadMemoryFlags.None, buf);
|
||||
return Encoding.Unicode.GetString(buf, 0, buf.Length);
|
||||
}
|
||||
|
||||
int length = checked((int)_asciiObject.length.Read());
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
ulong data;
|
||||
if (!state.compact) {
|
||||
data = GetFieldProxy(_fields.data).Read();
|
||||
} else if (state.ascii) {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyASCIIObject311>(Process));
|
||||
} else {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject311>(Process));
|
||||
}
|
||||
if (data == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
buf = new byte[length * (int)state.kind];
|
||||
Process.ReadMemory(data, DkmReadMemoryFlags.None, buf);
|
||||
Encoding enc;
|
||||
switch (state.kind) {
|
||||
case PyUnicode_Kind.PyUnicode_1BYTE_KIND:
|
||||
enc = _latin1;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_2BYTE_KIND:
|
||||
enc = Encoding.Unicode;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_4BYTE_KIND:
|
||||
enc = Encoding.UTF32;
|
||||
break;
|
||||
default:
|
||||
Debug.Fail("Unsupported PyUnicode_Kind " + state.kind);
|
||||
return null;
|
||||
}
|
||||
|
||||
return enc.GetString(buf, 0, buf.Length);
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MaxVersion = PythonLanguageVersion.V311, StructName = "PyASCIIObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V311, VariableName = "PyASCII_Type")]
|
||||
internal class PyASCIIObject311 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> length;
|
||||
public StructField<SSizeTProxy> hash;
|
||||
public StructField<ByteProxy> state;
|
||||
public StructField<PointerProxy> wstr;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyASCIIObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy length {
|
||||
get { return GetFieldProxy(_fields.length); }
|
||||
}
|
||||
|
||||
public SSizeTProxy hash {
|
||||
get { return GetFieldProxy(_fields.hash); }
|
||||
}
|
||||
|
||||
public ByteProxy state {
|
||||
get { return GetFieldProxy(_fields.state); }
|
||||
}
|
||||
|
||||
public PointerProxy wstr => GetFieldProxy(_fields.wstr);
|
||||
}
|
||||
|
||||
[StructProxy(MaxVersion = PythonLanguageVersion.V311, StructName = "PyCompactUnicodeObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V39, MaxVersion = PythonLanguageVersion.V311, VariableName = "PyCompactUnicode_Type")]
|
||||
internal class PyCompactUnicodeObject311 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> wstr_length;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyCompactUnicodeObject311(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy wstr_length {
|
||||
get { return GetFieldProxy(_fields.wstr_length); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PythonTools.Common.Core.OS;
|
||||
using Microsoft.PythonTools.Common.Parsing;
|
||||
using Microsoft.VisualStudio.Debugger;
|
||||
|
||||
namespace Microsoft.PythonTools.Debugger.Concord.Proxies.Structs {
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V312, StructName = "PyUnicodeObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V312, VariableName = "PyUnicode_Type")]
|
||||
internal class PyUnicodeObject312 : PyUnicodeObject {
|
||||
private enum PyUnicode_Kind {
|
||||
PyUnicode_1BYTE_KIND = 1,
|
||||
PyUnicode_2BYTE_KIND = 2,
|
||||
PyUnicode_4BYTE_KIND = 4
|
||||
}
|
||||
|
||||
private enum Interned {
|
||||
SSTATE_NOT_INTERNED = 0,
|
||||
SSTATE_INTERNED_MORTAL = 1,
|
||||
SSTATE_INTERNED_IMMORTAL = 2
|
||||
}
|
||||
|
||||
private struct State {
|
||||
private static readonly BitVector32.Section
|
||||
internedSection = BitVector32.CreateSection(2),
|
||||
kindSection = BitVector32.CreateSection(4, internedSection),
|
||||
compactSection = BitVector32.CreateSection(1, kindSection),
|
||||
asciiSection = BitVector32.CreateSection(1, compactSection),
|
||||
readySection = BitVector32.CreateSection(1, asciiSection);
|
||||
|
||||
private BitVector32 _state;
|
||||
|
||||
private State(byte state) {
|
||||
_state = new BitVector32(state);
|
||||
}
|
||||
|
||||
public static explicit operator State(byte state) {
|
||||
return new State(state);
|
||||
}
|
||||
|
||||
public static explicit operator byte(State state) {
|
||||
return (byte)state._state.Data;
|
||||
}
|
||||
|
||||
public Interned interned {
|
||||
get { return (Interned)_state[internedSection]; }
|
||||
set { _state[internedSection] = (int)value; }
|
||||
}
|
||||
|
||||
public PyUnicode_Kind kind {
|
||||
get { return (PyUnicode_Kind)_state[kindSection]; }
|
||||
set { _state[kindSection] = (int)value; }
|
||||
}
|
||||
|
||||
public bool compact {
|
||||
get { return _state[compactSection] != 0; }
|
||||
set { _state[compactSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ascii {
|
||||
get { return _state[asciiSection] != 0; }
|
||||
set { _state[asciiSection] = value ? 1 : 0; }
|
||||
}
|
||||
|
||||
public bool ready {
|
||||
get { return _state[readySection] != 0; }
|
||||
set { _state[readySection] = value ? 1 : 0; }
|
||||
}
|
||||
}
|
||||
|
||||
public class Fields {
|
||||
public StructField<PointerProxy> data;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
private readonly PyASCIIObject312 _asciiObject;
|
||||
private readonly PyCompactUnicodeObject312 _compactObject;
|
||||
|
||||
public PyUnicodeObject312(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
CheckPyType<PyUnicodeObject312>();
|
||||
|
||||
_asciiObject = new PyASCIIObject312(process, address);
|
||||
_compactObject = new PyCompactUnicodeObject312(process, address);
|
||||
}
|
||||
|
||||
public static PyUnicodeObject312 Create312(DkmProcess process, string value) {
|
||||
var allocator = process.GetDataItem<PyObjectAllocator>();
|
||||
Debug.Assert(allocator != null);
|
||||
|
||||
var result = allocator.Allocate<PyUnicodeObject312>(value.Length * sizeof(char));
|
||||
|
||||
result._asciiObject.hash.Write(-1);
|
||||
result._asciiObject.length.Write(value.Length);
|
||||
result._compactObject.utf8_length.Write(value.Length);
|
||||
var kind = value.Length != Encoding.UTF8.GetByteCount(value) ? PyUnicode_Kind.PyUnicode_2BYTE_KIND : PyUnicode_Kind.PyUnicode_1BYTE_KIND;
|
||||
|
||||
var state = new State {
|
||||
interned = Interned.SSTATE_NOT_INTERNED,
|
||||
kind = kind,
|
||||
compact = true,
|
||||
ascii = false,
|
||||
ready = true
|
||||
};
|
||||
result._asciiObject.state.Write((byte)state);
|
||||
|
||||
ulong dataPtr = result.Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject312>(process));
|
||||
result._compactObject.utf8.Write(dataPtr);
|
||||
process.WriteMemory(dataPtr, Encoding.UTF8.GetBytes(value));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
byte[] buf;
|
||||
|
||||
State state = (State)_asciiObject.state.Read();
|
||||
if (state.ascii) {
|
||||
state.kind = PyUnicode_Kind.PyUnicode_1BYTE_KIND;
|
||||
}
|
||||
|
||||
int length = checked((int)_asciiObject.length.Read());
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
ulong data;
|
||||
if (!state.compact) {
|
||||
data = GetFieldProxy(_fields.data).Read();
|
||||
} else if (state.ascii) {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyASCIIObject312>(Process));
|
||||
} else {
|
||||
data = Address.OffsetBy(StructProxy.SizeOf<PyCompactUnicodeObject312>(Process));
|
||||
}
|
||||
if (data == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
buf = new byte[length * (int)state.kind];
|
||||
Process.ReadMemory(data, DkmReadMemoryFlags.None, buf);
|
||||
Encoding enc;
|
||||
switch (state.kind) {
|
||||
case PyUnicode_Kind.PyUnicode_1BYTE_KIND:
|
||||
enc = _latin1;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_2BYTE_KIND:
|
||||
enc = Encoding.Unicode;
|
||||
break;
|
||||
case PyUnicode_Kind.PyUnicode_4BYTE_KIND:
|
||||
enc = Encoding.UTF32;
|
||||
break;
|
||||
default:
|
||||
Debug.Fail("Unsupported PyUnicode_Kind " + state.kind);
|
||||
return null;
|
||||
}
|
||||
|
||||
return enc.GetString(buf, 0, buf.Length);
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V312, StructName = "PyASCIIObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V312, VariableName = "PyASCII_Type")]
|
||||
internal class PyASCIIObject312 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> length;
|
||||
public StructField<SSizeTProxy> hash;
|
||||
public StructField<ByteProxy> state;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyASCIIObject312(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy length {
|
||||
get { return GetFieldProxy(_fields.length); }
|
||||
}
|
||||
|
||||
public SSizeTProxy hash {
|
||||
get { return GetFieldProxy(_fields.hash); }
|
||||
}
|
||||
|
||||
public ByteProxy state {
|
||||
get { return GetFieldProxy(_fields.state); }
|
||||
}
|
||||
}
|
||||
|
||||
[StructProxy(MinVersion = PythonLanguageVersion.V312, StructName = "PyCompactUnicodeObject")]
|
||||
[PyType(MinVersion = PythonLanguageVersion.V312, VariableName = "PyCompactUnicode_Type")]
|
||||
internal class PyCompactUnicodeObject312 : StructProxy {
|
||||
public class Fields {
|
||||
public StructField<SSizeTProxy> utf8_length;
|
||||
public StructField<PointerProxy> utf8;
|
||||
}
|
||||
|
||||
private readonly Fields _fields;
|
||||
|
||||
public PyCompactUnicodeObject312(DkmProcess process, ulong address)
|
||||
: base(process, address) {
|
||||
InitializeStruct(this, out _fields);
|
||||
}
|
||||
|
||||
public SSizeTProxy utf8_length {
|
||||
get { return GetFieldProxy(_fields.utf8_length); }
|
||||
}
|
||||
|
||||
public PointerProxy utf8 {
|
||||
get { return GetFieldProxy(_fields.utf8); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -76,6 +76,9 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
case "38": return PythonLanguageVersion.V38;
|
||||
case "39": return PythonLanguageVersion.V39;
|
||||
case "310": return PythonLanguageVersion.V310;
|
||||
case "311": return PythonLanguageVersion.V311;
|
||||
case "312": return PythonLanguageVersion.V312;
|
||||
case "313": return PythonLanguageVersion.V313;
|
||||
default: return PythonLanguageVersion.None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,28 +62,48 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
// Layout of this struct must always remain in sync with DebuggerHelper/trace.cpp.
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
private struct PyCodeObject_FieldOffsets {
|
||||
public readonly long co_varnames, co_filename, co_name;
|
||||
public readonly long co_filename, co_name;
|
||||
|
||||
public PyCodeObject_FieldOffsets(DkmProcess process) {
|
||||
var fields = StructProxy.GetStructFields<PyCodeObject, PyCodeObject.Fields>(process);
|
||||
co_varnames = fields.co_varnames.Offset;
|
||||
co_filename = fields.co_filename.Offset;
|
||||
co_name = fields.co_name.Offset;
|
||||
if (process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
var fields = StructProxy.GetStructFields<PyCodeObject310, PyCodeObject310.Fields>(process);
|
||||
co_filename = fields.co_filename.Offset;
|
||||
co_name = fields.co_name.Offset;
|
||||
} else {
|
||||
var fields = StructProxy.GetStructFields<PyCodeObject311, PyCodeObject311.Fields>(process);
|
||||
co_filename = fields.co_filename.Offset;
|
||||
co_name = fields.co_name.Offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Layout of this struct must always remain in sync with DebuggerHelper/trace.cpp.
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
private struct PyFrameObject_FieldOffsets {
|
||||
public readonly long f_back, f_code, f_globals, f_locals, f_lineno;
|
||||
public readonly long f_back, f_code, f_globals, f_locals, f_lineno, f_frame;
|
||||
|
||||
public PyFrameObject_FieldOffsets(DkmProcess process) {
|
||||
var fields = StructProxy.GetStructFields<PyFrameObject, PyFrameObject.Fields>(process);
|
||||
f_back = fields.f_back.Offset;
|
||||
f_code = fields.f_code.Offset;
|
||||
f_globals = fields.f_globals.Offset;
|
||||
f_locals = fields.f_locals.Offset;
|
||||
f_lineno = fields.f_lineno.Offset;
|
||||
// For 310, these are on the _frame struct itself.
|
||||
if (process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V310) {
|
||||
var fields = StructProxy.GetStructFields<PyFrameObject310, PyFrameObject310.Fields>(process);
|
||||
f_back = fields.f_back.Offset;
|
||||
f_code = fields.f_code.Offset;
|
||||
f_globals = fields.f_globals.Offset;
|
||||
f_locals = fields.f_locals.Offset;
|
||||
f_lineno = fields.f_lineno.Offset;
|
||||
f_frame = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// For 311 and higher, they are on the PyInterpreterFrame struct which is pointed to by the _frame struct.
|
||||
var _frameFields = StructProxy.GetStructFields<PyFrameObject311, PyFrameObject311.Fields>(process);
|
||||
var _interpreterFields = StructProxy.GetStructFields<PyInterpreterFrame, PyInterpreterFrame.Fields>(process);
|
||||
f_frame = _frameFields.f_frame.Offset;
|
||||
f_back = _frameFields.f_back.Offset;
|
||||
f_code = _interpreterFields.f_code.Process != null ? _interpreterFields.f_code.Offset : _interpreterFields.f_executable.Offset;
|
||||
f_globals = _interpreterFields.f_globals.Offset;
|
||||
f_locals = _interpreterFields.f_locals.Offset;
|
||||
f_lineno = _frameFields.f_lineno.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,22 +122,43 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 8)]
|
||||
private struct PyUnicodeObject_FieldOffsets {
|
||||
public readonly long sizeof_PyASCIIObject, sizeof_PyCompactUnicodeObject;
|
||||
public readonly long length, state, wstr, wstr_length, data;
|
||||
public readonly long length, state, wstr, wstr_length, utf8, utf8_length, data;
|
||||
|
||||
public PyUnicodeObject_FieldOffsets(DkmProcess process) {
|
||||
sizeof_PyASCIIObject = StructProxy.SizeOf<PyASCIIObject>(process);
|
||||
sizeof_PyCompactUnicodeObject = StructProxy.SizeOf<PyUnicodeObject>(process);
|
||||
if (process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V311) {
|
||||
sizeof_PyASCIIObject = StructProxy.SizeOf<PyASCIIObject311>(process);
|
||||
sizeof_PyCompactUnicodeObject = StructProxy.SizeOf<PyCompactUnicodeObject311>(process);
|
||||
|
||||
var asciiFields = StructProxy.GetStructFields<PyASCIIObject, PyASCIIObject.Fields>(process);
|
||||
length = asciiFields.length.Offset;
|
||||
state = asciiFields.state.Offset;
|
||||
wstr = asciiFields.wstr.Offset;
|
||||
var asciiFields = StructProxy.GetStructFields<PyASCIIObject311, PyASCIIObject311.Fields>(process);
|
||||
length = asciiFields.length.Offset;
|
||||
state = asciiFields.state.Offset;
|
||||
wstr = asciiFields.wstr.Offset;
|
||||
utf8 = 0;
|
||||
utf8_length = 0;
|
||||
|
||||
var compactFields = StructProxy.GetStructFields<PyCompactUnicodeObject, PyCompactUnicodeObject.Fields>(process);
|
||||
wstr_length = compactFields.wstr_length.Offset;
|
||||
var compactFields = StructProxy.GetStructFields<PyCompactUnicodeObject311, PyCompactUnicodeObject311.Fields>(process);
|
||||
wstr_length = compactFields.wstr_length.Offset;
|
||||
|
||||
var unicodeFields = StructProxy.GetStructFields<PyUnicodeObject311, PyUnicodeObject311.Fields>(process);
|
||||
data = unicodeFields.data.Offset;
|
||||
} else {
|
||||
sizeof_PyASCIIObject = StructProxy.SizeOf<PyASCIIObject312>(process);
|
||||
sizeof_PyCompactUnicodeObject = StructProxy.SizeOf<PyCompactUnicodeObject312>(process);
|
||||
|
||||
var asciiFields = StructProxy.GetStructFields<PyASCIIObject312, PyASCIIObject312.Fields>(process);
|
||||
length = asciiFields.length.Offset;
|
||||
state = asciiFields.state.Offset;
|
||||
wstr = 0;
|
||||
|
||||
var compactFields = StructProxy.GetStructFields<PyCompactUnicodeObject312, PyCompactUnicodeObject312.Fields>(process);
|
||||
wstr_length = 0;
|
||||
utf8_length = compactFields.utf8_length.Offset;
|
||||
utf8 = compactFields.utf8.Offset;
|
||||
|
||||
var unicodeFields = StructProxy.GetStructFields<PyUnicodeObject312, PyUnicodeObject312.Fields>(process);
|
||||
data = unicodeFields.data.Offset;
|
||||
}
|
||||
|
||||
var unicodeFields = StructProxy.GetStructFields<PyUnicodeObject, PyUnicodeObject.Fields>(process);
|
||||
data = unicodeFields.data.Offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +190,9 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
|
||||
public Types(DkmProcess process, PythonRuntimeInfo pyrtInfo) {
|
||||
PyBytes_Type = PyObject.GetPyType<PyBytesObject>(process).Address;
|
||||
PyUnicode_Type = PyObject.GetPyType<PyUnicodeObject>(process).Address;
|
||||
PyUnicode_Type = process.GetPythonRuntimeInfo().LanguageVersion <= PythonLanguageVersion.V311 ?
|
||||
PyObject.GetPyType<PyUnicodeObject311>(process).Address :
|
||||
PyObject.GetPyType<PyUnicodeObject312>(process).Address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +206,11 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
public ulong PyErr_Restore;
|
||||
public ulong PyErr_Occurred;
|
||||
public ulong PyObject_Str;
|
||||
public ulong PyEval_SetTraceAllThreads;
|
||||
public ulong PyGILState_Ensure;
|
||||
public ulong PyGILState_Release;
|
||||
public ulong Py_Initialize;
|
||||
public ulong Py_Finalize;
|
||||
|
||||
public FunctionPointers(DkmProcess process, PythonRuntimeInfo pyrtInfo) {
|
||||
Py_DecRef = pyrtInfo.DLLs.Python.GetFunctionAddress("Py_DecRef");
|
||||
|
@ -172,6 +220,13 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
PyErr_Restore = pyrtInfo.DLLs.Python.GetFunctionAddress("PyErr_Restore");
|
||||
PyErr_Occurred = pyrtInfo.DLLs.Python.GetFunctionAddress("PyErr_Occurred");
|
||||
PyObject_Str = pyrtInfo.DLLs.Python.GetFunctionAddress("PyObject_Str");
|
||||
PyEval_SetTraceAllThreads = pyrtInfo.LanguageVersion >= PythonLanguageVersion.V312 ?
|
||||
pyrtInfo.DLLs.Python.GetFunctionAddress("PyEval_SetTraceAllThreads") :
|
||||
0;
|
||||
PyGILState_Ensure = pyrtInfo.DLLs.Python.GetFunctionAddress("PyGILState_Ensure");
|
||||
PyGILState_Release = pyrtInfo.DLLs.Python.GetFunctionAddress("PyGILState_Release");
|
||||
Py_Initialize = pyrtInfo.DLLs.Python.GetFunctionAddress("Py_Initialize");
|
||||
Py_Finalize = pyrtInfo.DLLs.Python.GetFunctionAddress("Py_Finalize");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +235,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
private readonly PythonDllBreakpointHandlers _handlers;
|
||||
private readonly DkmNativeInstructionAddress _traceFunc;
|
||||
private readonly DkmNativeInstructionAddress _evalFrameFunc;
|
||||
private readonly DkmNativeInstructionAddress _pyEval_FrameDefault;
|
||||
private readonly PointerProxy _defaultEvalFrameFunc;
|
||||
private readonly ByteProxy _isTracing;
|
||||
|
||||
|
@ -222,6 +278,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
_process = process;
|
||||
_pyrtInfo = process.GetPythonRuntimeInfo();
|
||||
|
||||
_pyEval_FrameDefault = _pyrtInfo.DLLs.Python.GetExportedFunctionAddress("_PyEval_EvalFrameDefault");
|
||||
_traceFunc = _pyrtInfo.DLLs.DebuggerHelper.GetExportedFunctionAddress("TraceFunc");
|
||||
_evalFrameFunc =
|
||||
_pyrtInfo.DLLs.DebuggerHelper.GetExportedFunctionAddress("EvalFrameFunc");
|
||||
|
@ -243,7 +300,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
if (_pyrtInfo.LanguageVersion >= PythonLanguageVersion.V36) {
|
||||
RegisterJITTracing(interp);
|
||||
}
|
||||
foreach (var tstate in interp.GetThreadStates()) {
|
||||
foreach (var tstate in interp.GetThreadStates(process)) {
|
||||
RegisterTracing(tstate);
|
||||
}
|
||||
}
|
||||
|
@ -251,6 +308,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
_handlers = new PythonDllBreakpointHandlers(this);
|
||||
LocalComponent.CreateRuntimeDllFunctionExitBreakpoints(_pyrtInfo.DLLs.Python, "new_threadstate", _handlers.new_threadstate, enable: true);
|
||||
LocalComponent.CreateRuntimeDllFunctionExitBreakpoints(_pyrtInfo.DLLs.Python, "PyInterpreterState_New", _handlers.PyInterpreterState_New, enable: true);
|
||||
LocalComponent.CreateRuntimeDllFunctionExitBreakpoints(_pyrtInfo.DLLs.Python, "_PyInterpreterState_New", _handlers._PyInterpreterState_New, enable: true);
|
||||
|
||||
foreach (var methodInfo in _handlers.GetType().GetMethods()) {
|
||||
var stepInAttr = (StepInGateAttribute)Attribute.GetCustomAttribute(methodInfo, typeof(StepInGateAttribute));
|
||||
|
@ -269,9 +327,15 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Int32Proxy> GetTracingPossible(PythonRuntimeInfo pyrtInfo, DkmProcess process) =>
|
||||
from interp in PyInterpreterState.GetInterpreterStates(process)
|
||||
private IEnumerable<Int32Proxy> GetTracingPossible(PythonRuntimeInfo pyrtInfo, DkmProcess process) {
|
||||
// On 3.10 and above the tracing_possible is determined on each thread by the cframe object, so we don't need to
|
||||
// check the interpreter state (it's no longer set there).
|
||||
if (pyrtInfo.LanguageVersion > PythonLanguageVersion.V39) {
|
||||
return Enumerable.Empty<Int32Proxy>();
|
||||
}
|
||||
return from interp in PyInterpreterState.GetInterpreterStates(process)
|
||||
select interp.ceval.tracing_possible;
|
||||
}
|
||||
|
||||
private void AddStepInGate(StepInGateHandler handler, DkmNativeModuleInstance module, string funcName, bool hasMultipleExitPoints) {
|
||||
var gate = new StepInGate {
|
||||
|
@ -288,8 +352,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
}
|
||||
|
||||
public unsafe void RegisterTracing(PyThreadState tstate) {
|
||||
tstate.use_tracing.Write(1);
|
||||
tstate.c_tracefunc.Write(_traceFunc.GetPointer());
|
||||
tstate.RegisterTracing(_traceFunc.GetPointer());
|
||||
foreach (var pyTracingPossible in GetTracingPossible(_pyrtInfo, _process)) {
|
||||
pyTracingPossible.Write(pyTracingPossible.Read() + 1);
|
||||
}
|
||||
|
@ -300,9 +363,16 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
Debug.Assert(_pyrtInfo.LanguageVersion >= PythonLanguageVersion.V36);
|
||||
|
||||
var current = istate.eval_frame.Read();
|
||||
if (current != _evalFrameFunc.GetPointer()) {
|
||||
var evalFrameAddr = _evalFrameFunc.GetPointer();
|
||||
|
||||
if (current == 0) {
|
||||
// This means the eval_frame is set to the default. Write
|
||||
// this as our _defaultEvalFrameFunc
|
||||
_defaultEvalFrameFunc.Write(_pyEval_FrameDefault.GetPointer());
|
||||
istate.eval_frame.Write(evalFrameAddr);
|
||||
} else if (current != evalFrameAddr) {
|
||||
_defaultEvalFrameFunc.Write(current);
|
||||
istate.eval_frame.Write(_evalFrameFunc.GetPointer());
|
||||
istate.eval_frame.Write(evalFrameAddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,6 +551,15 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
}
|
||||
}
|
||||
|
||||
public void _PyInterpreterState_New(DkmThread thread, ulong frameBase, ulong vframe, ulong returnAddress) {
|
||||
// The new interpreter should be the 'head' of the list of interpreters
|
||||
// (this function actually returns a status code, not the interpreter state).
|
||||
var head = PyInterpreterState.GetInterpreterStates(thread.Process).First();
|
||||
if (head != null && head.Process != null) {
|
||||
_owner.RegisterJITTracing(head);
|
||||
}
|
||||
}
|
||||
|
||||
// This step-in gate is not marked [StepInGate] because it doesn't live in pythonXX.dll, and so we register it manually.
|
||||
public void _call_function_pointer(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
|
||||
var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
|
||||
|
@ -488,7 +567,7 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
_owner.OnPotentialRuntimeExit(thread, pProc);
|
||||
}
|
||||
|
||||
[StepInGate]
|
||||
[StepInGate(MaxVersion = PythonLanguageVersion.V310)]
|
||||
public void call_function(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
|
||||
var process = thread.Process;
|
||||
var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
|
||||
|
@ -511,6 +590,19 @@ namespace Microsoft.PythonTools.Debugger.Concord {
|
|||
_owner.OnPotentialRuntimeExit(thread, ml_meth);
|
||||
}
|
||||
|
||||
[StepInGate(MinVersion = PythonLanguageVersion.V311)]
|
||||
public void PyObject_Vectorcall(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
|
||||
var process = thread.Process;
|
||||
var cppEval = new CppExpressionEvaluator(thread, frameBase, vframe);
|
||||
ulong func = cppEval.EvaluateUInt64(useRegisters ? "@rdx" : "callable");
|
||||
var obj = PyObject.FromAddress(process, func);
|
||||
ulong ml_meth = cppEval.EvaluateUInt64(
|
||||
"((PyObject*){0})->ob_type == &PyCFunction_Type ? ((PyCFunctionObject*){0})->m_ml->ml_meth : 0",
|
||||
func);
|
||||
|
||||
_owner.OnPotentialRuntimeExit(thread, ml_meth);
|
||||
}
|
||||
|
||||
[StepInGate]
|
||||
public void PyCFunction_Call(DkmThread thread, ulong frameBase, ulong vframe, bool useRegisters) {
|
||||
var process = thread.Process;
|
||||
|
|
|
@ -51,17 +51,17 @@ struct {
|
|||
int64_t ob_size;
|
||||
} PyVarObject;
|
||||
struct {
|
||||
int64_t f_back, f_code, f_globals, f_locals, f_lineno;
|
||||
int64_t f_back, f_code, f_globals, f_locals, f_lineno, f_frame;
|
||||
} PyFrameObject;
|
||||
struct {
|
||||
int64_t co_varnames, co_filename, co_name;
|
||||
int64_t co_filename, co_name;
|
||||
} PyCodeObject;
|
||||
struct {
|
||||
int64_t ob_sval;
|
||||
} PyBytesObject;
|
||||
struct {
|
||||
int64_t PyAsciiObjectData, PyCompactUnicodeObjectData;
|
||||
int64_t length, state, wstr, wstr_length, data;
|
||||
int64_t sizeof_PyAsciiObjectData, sizeof_PyCompactUnicodeObjectData;
|
||||
int64_t length, state, wstr, wstr_length, utf8, utf8_length, data;
|
||||
} PyUnicodeObject;
|
||||
} fieldOffsets;
|
||||
|
||||
|
@ -82,6 +82,11 @@ struct {
|
|||
uint64_t PyErr_Restore;
|
||||
uint64_t PyErr_Occurred;
|
||||
uint64_t PyObject_Str;
|
||||
uint64_t PyEval_SetTraceAllThreads;
|
||||
uint64_t PyGILState_Ensure;
|
||||
uint64_t PyGILState_Release;
|
||||
uint64_t Py_Initialize;
|
||||
uint64_t Py_Finalize;
|
||||
} functionPointers;
|
||||
|
||||
void Py_DecRef(PyObject* a1) {
|
||||
|
@ -112,6 +117,33 @@ PyObject* PyObject_Str(PyObject* o) {
|
|||
return reinterpret_cast<decltype(&PyObject_Str)>(functionPointers.PyObject_Str)(o);
|
||||
}
|
||||
|
||||
/* Py_tracefunc return -1 when raising an exception, or 0 for success. */
|
||||
typedef int (*Py_tracefunc)(void* obj, void* frame, int what, void* arg);
|
||||
|
||||
void
|
||||
PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject* arg) {
|
||||
return reinterpret_cast<decltype(&PyEval_SetTraceAllThreads)>(functionPointers.PyEval_SetTraceAllThreads)(func, arg);
|
||||
}
|
||||
|
||||
typedef
|
||||
enum { PyGILState_LOCKED, PyGILState_UNLOCKED } PyGILState_STATE;
|
||||
|
||||
PyGILState_STATE PyGILState_Ensure() {
|
||||
return reinterpret_cast<decltype(&PyGILState_Ensure)>(functionPointers.PyGILState_Ensure)();
|
||||
}
|
||||
|
||||
void PyGILState_Release(PyGILState_STATE state) {
|
||||
return reinterpret_cast<decltype(&PyGILState_Release)>(functionPointers.PyGILState_Release)(state);
|
||||
}
|
||||
|
||||
void Py_Initialize() {
|
||||
return reinterpret_cast<decltype(&Py_Initialize)>(functionPointers.Py_Initialize)();
|
||||
}
|
||||
|
||||
void Py_Finalize() {
|
||||
return reinterpret_cast<decltype(&Py_Finalize)>(functionPointers.Py_Finalize)();
|
||||
}
|
||||
|
||||
// A string provided by the debugger (e.g. for file names). This is actually a variable-length struct,
|
||||
// with _countof(data) == length + 1 - the extra wchar_t is the null terminator.
|
||||
struct DebuggerString {
|
||||
|
@ -256,7 +288,7 @@ bool StringEquals(const DebuggerString* debuggerString, const void* pyString) {
|
|||
|
||||
state = ReadField<char>(pyString, fieldOffsets.PyUnicodeObject.state);
|
||||
|
||||
if (!ready) {
|
||||
if (!ready && fieldOffsets.PyUnicodeObject.wstr != 0) {
|
||||
auto wstr = ReadField<wchar_t*>(pyString, fieldOffsets.PyUnicodeObject.wstr);
|
||||
if (!wstr) {
|
||||
return false;
|
||||
|
@ -279,9 +311,9 @@ bool StringEquals(const DebuggerString* debuggerString, const void* pyString) {
|
|||
if (!compact) {
|
||||
data = ReadField<void*>(pyString, fieldOffsets.PyUnicodeObject.data);
|
||||
} else if (ascii) {
|
||||
data = reinterpret_cast<const char*>(pyString) + fieldOffsets.PyUnicodeObject.PyAsciiObjectData;
|
||||
data = reinterpret_cast<const char*>(pyString) + fieldOffsets.PyUnicodeObject.sizeof_PyAsciiObjectData;
|
||||
} else {
|
||||
data = reinterpret_cast<const char*>(pyString) + fieldOffsets.PyUnicodeObject.PyCompactUnicodeObjectData;
|
||||
data = reinterpret_cast<const char*>(pyString) + fieldOffsets.PyUnicodeObject.sizeof_PyCompactUnicodeObjectData;
|
||||
}
|
||||
|
||||
if (kind == 2) {
|
||||
|
@ -353,8 +385,20 @@ void EvalLoop(void (*bp)()) {
|
|||
auto frame = reinterpret_cast<PyObject*>(evalLoopFrame);
|
||||
PyFrame_FastToLocals(frame);
|
||||
|
||||
auto f_globals = ReadField<PyObject*>(frame, fieldOffsets.PyFrameObject.f_globals);
|
||||
auto f_locals = ReadField<PyObject*>(frame, fieldOffsets.PyFrameObject.f_locals);
|
||||
PyObject* f_globals = NULL;
|
||||
PyObject* f_locals = NULL;
|
||||
if (fieldOffsets.PyFrameObject.f_frame == 0) {
|
||||
// We're on 3.10 or earlier. f_globals and f_locals is directly off of the frame.
|
||||
f_globals = ReadField<PyObject*>(frame, fieldOffsets.PyFrameObject.f_globals);
|
||||
f_locals = ReadField<PyObject*>(frame, fieldOffsets.PyFrameObject.f_locals);
|
||||
}
|
||||
else {
|
||||
// We're on 3.11 or later. f_frame (PyInterpreterFrame) is off of the frame. It has
|
||||
// the f_globals and f_locals object.
|
||||
void* f_frame = ReadField<void*>(frame, fieldOffsets.PyFrameObject.f_frame);
|
||||
f_globals = ReadField<PyObject*>(f_frame, fieldOffsets.PyFrameObject.f_globals);
|
||||
f_locals = ReadField<PyObject*>(f_frame, fieldOffsets.PyFrameObject.f_locals);
|
||||
}
|
||||
|
||||
PyObject *orig_exc_type, *orig_exc_value, *orig_exc_tb;
|
||||
PyErr_Fetch(&orig_exc_type, &orig_exc_value, &orig_exc_tb);
|
||||
|
@ -425,7 +469,7 @@ static void TraceLine(void* frame) {
|
|||
const auto& bpData = breakpointData[iData];
|
||||
|
||||
int f_lineno = ReadField<int>(frame, fieldOffsets.PyFrameObject.f_lineno);
|
||||
if (f_lineno > bpData.maxLineNumber) {
|
||||
if (f_lineno > bpData.maxLineNumber || f_lineno <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -435,8 +479,19 @@ static void TraceLine(void* frame) {
|
|||
return;
|
||||
}
|
||||
|
||||
void* f_code = ReadField<void*>(frame, fieldOffsets.PyFrameObject.f_code);
|
||||
void* co_filename = ReadField<void*>(f_code, fieldOffsets.PyCodeObject.co_filename);
|
||||
void* co_filename = nullptr;
|
||||
if (fieldOffsets.PyFrameObject.f_frame == 0) {
|
||||
// We're on 3.10 or earlier. f_code is directly off of the frame.
|
||||
void* f_code = ReadField<void*>(frame, fieldOffsets.PyFrameObject.f_code);
|
||||
co_filename = ReadField<void*>(f_code, fieldOffsets.PyCodeObject.co_filename);
|
||||
}
|
||||
else {
|
||||
// We're on 3.11 or later. f_frame (PyInterpreterFrame) is off of the frame. It has
|
||||
// the f_code object.
|
||||
void* f_frame = ReadField<void*>(frame, fieldOffsets.PyFrameObject.f_frame);
|
||||
void* f_code = ReadField<void*>(f_frame, fieldOffsets.PyFrameObject.f_code);
|
||||
co_filename = ReadField<void*>(f_code, fieldOffsets.PyCodeObject.co_filename);
|
||||
}
|
||||
if (co_filename == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
@ -540,19 +595,46 @@ int TraceFunc(void* obj, void* frame, int what, void* arg) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// In Python 3.9 the eval function added the thread state. So
|
||||
// we need a new function def to accomodate that change.
|
||||
typedef void* (*_PyFrameEvalFunction)(void*,void*, int);
|
||||
void* InitialEvalFrameFunc(void* ts, void* f, int throwFlag);
|
||||
|
||||
typedef void* (*_PyFrameEvalFunction)(void*, void*, int);
|
||||
_PyFrameEvalFunction CurrentEvalFrameFunc = InitialEvalFrameFunc;
|
||||
|
||||
__declspec(dllexport)
|
||||
_PyFrameEvalFunction DefaultEvalFrameFunc = nullptr;
|
||||
|
||||
__declspec(dllexport)
|
||||
void* EvalFrameFunc(void* ts, void* f, int throwFlag)
|
||||
// Initial EvalFrameFunc that is used to set the trace function.
|
||||
volatile unsigned long _isTracing = 0;
|
||||
void *InitialEvalFrameFunc(void* ts, void* f, int throwFlag)
|
||||
{
|
||||
// If were in 3.12, we need to set the trace function ourselves.
|
||||
// This is because just writing to the use_tracing flag is no longer enough. Internally CPython
|
||||
// doesn't just trace everything if the flag is set. Instead tracing now uses the sys.monitoring
|
||||
// api under the covers. That's a lot more than just flipping a flag.
|
||||
if (functionPointers.PyEval_SetTraceAllThreads != 0 && ::InterlockedCompareExchange(&_isTracing, 1, 0) == 0) {
|
||||
auto gilState = PyGILState_Ensure();
|
||||
PyEval_SetTraceAllThreads(TraceFunc, nullptr);
|
||||
PyGILState_Release(gilState);
|
||||
}
|
||||
|
||||
// Rewrite the current EvalFrameFunc so we don't bother attempting to register the trace function again.
|
||||
CurrentEvalFrameFunc = DefaultEvalFrameFunc;
|
||||
|
||||
if (DefaultEvalFrameFunc)
|
||||
return (*DefaultEvalFrameFunc)(ts, f, throwFlag);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function that is inserted into the current thread state by the debugger as the function to call
|
||||
// in order to evaluate a frame. This is done so that the debugger can intercept the call
|
||||
__declspec(dllexport)
|
||||
void* EvalFrameFunc(void* ts, void* f, int throwFlag)
|
||||
{
|
||||
return (*CurrentEvalFrameFunc)(ts, f, throwFlag);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ namespace TestUtilities {
|
|||
public static readonly PythonVersion Python38 = GetCPythonVersion(PythonLanguageVersion.V38, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python39 = GetCPythonVersion(PythonLanguageVersion.V39, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python310 = GetCPythonVersion(PythonLanguageVersion.V310, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python311 = GetCPythonVersion(PythonLanguageVersion.V311, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python312 = GetCPythonVersion(PythonLanguageVersion.V312, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python313 = GetCPythonVersion(PythonLanguageVersion.V313, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Python27_x64 = GetCPythonVersion(PythonLanguageVersion.V27, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python35_x64 = GetCPythonVersion(PythonLanguageVersion.V35, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python36_x64 = GetCPythonVersion(PythonLanguageVersion.V36, InterpreterArchitecture.x64);
|
||||
|
@ -53,6 +56,9 @@ namespace TestUtilities {
|
|||
public static readonly PythonVersion Python38_x64 = GetCPythonVersion(PythonLanguageVersion.V38, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python39_x64 = GetCPythonVersion(PythonLanguageVersion.V39, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python310_x64 = GetCPythonVersion(PythonLanguageVersion.V310, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python311_x64 = GetCPythonVersion(PythonLanguageVersion.V311, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python312_x64 = GetCPythonVersion(PythonLanguageVersion.V312, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Python313_x64 = GetCPythonVersion(PythonLanguageVersion.V313, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Anaconda27 = GetAnacondaVersion(PythonLanguageVersion.V27, InterpreterArchitecture.x86);
|
||||
public static readonly PythonVersion Anaconda27_x64 = GetAnacondaVersion(PythonLanguageVersion.V27, InterpreterArchitecture.x64);
|
||||
public static readonly PythonVersion Anaconda36 = GetAnacondaVersion(PythonLanguageVersion.V36, InterpreterArchitecture.x86);
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
"name": "ptvs",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@pylance/pylance": "2024.11.1"
|
||||
"@pylance/pylance": "2024.11.2"
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче