PageRenderTime 61ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/Servicing/1.1/Release/Product/Python/PyDebugAttach/PyDebugAttach.cpp

#
C++ | 920 lines | 684 code | 125 blank | 111 comment | 229 complexity | 3b63ce55af7665998fd4302614b11c75 MD5 | raw file
Possible License(s): Apache-2.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. * ***************************************************************************/
  14. // PyDebugAttach.cpp : Defines the exported functions for the DLL application.
  15. //
  16. #include "stdafx.h"
  17. #include "PyDebugAttach.h"
  18. #include <Windows.h>
  19. #include <Psapi.h>
  20. #include <TlHelp32.h>
  21. #include <hash_map>
  22. #include <string>
  23. #include <fstream>
  24. #include <hash_set>
  25. #include <WinSock.h>
  26. #include "..\VsPyProf\python.h"
  27. #include <strsafe.h>
  28. using namespace std;
  29. typedef int (Py_IsInitialized) ();
  30. typedef void (PyEval_Lock) (); // Acquire/Release lock
  31. typedef void (PyThreadState_API) (PyThreadState *); // Acquire/Release lock
  32. typedef PyInterpreterState* (PyInterpreterState_Head)();
  33. typedef PyThreadState* (PyInterpreterState_ThreadHead)(PyInterpreterState* interp);
  34. typedef PyThreadState* (PyThreadState_Next)(PyThreadState *tstate);
  35. typedef PyThreadState* (PyThreadState_Swap)(PyThreadState *tstate);
  36. typedef int (PyRun_SimpleString)(const char *command);
  37. typedef PyObject* (PyDict_New)();
  38. typedef PyObject* (Py_CompileString)(const char *str, const char *filename, int start);
  39. typedef int (PyEval_EvalCode)(PyObject *co, PyObject *globals, PyObject *locals);
  40. typedef PyObject* (PyDict_GetItemString)(PyObject *p, const char *key);
  41. typedef PyObject* (PyObject_CallFunctionObjArgs)(PyObject *callable, ...); // call w/ varargs, last arg should be NULL
  42. typedef void (PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
  43. typedef PyObject* (PyEval_GetBuiltins)();
  44. typedef int (PyDict_SetItemString)(PyObject *dp, const char *key, PyObject *item);
  45. typedef int (PyEval_ThreadsInitialized)();
  46. typedef void (Py_AddPendingCall)(int (*func)(void *), void*);
  47. typedef const char* (GetVersionFunc) ();
  48. typedef PyObject* (PyInt_FromLong)(long);
  49. typedef PyObject* (PyString_FromString)(const char* s);
  50. typedef void PyEval_SetTrace(Py_tracefunc func, PyObject *obj);
  51. typedef void (PyErr_Restore)(PyObject *type, PyObject *value, PyObject *traceback);
  52. typedef void (PyErr_Fetch)(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
  53. typedef PyObject* (PyErr_Occurred)();
  54. typedef PyObject* (PyImport_ImportModule)(const char *name);
  55. typedef PyObject* (PyObject_GetAttrString)(PyObject *o, const char *attr_name);
  56. typedef PyObject* (PyObject_SetAttrString)(PyObject *o, const char *attr_name, PyObject* value);
  57. typedef PyObject* (PyBool_FromLong)(long v);
  58. typedef enum {PyGILState_LOCKED, PyGILState_UNLOCKED} PyGILState_STATE;
  59. typedef PyGILState_STATE (PyGILState_Ensure)();
  60. typedef void (PyGILState_Release)(PyGILState_STATE);
  61. typedef unsigned long (_PyEval_GetSwitchInterval)(void);
  62. typedef void (_PyEval_SetSwitchInterval)(unsigned long microseconds);
  63. typedef void* (PyThread_get_key_value)(int);
  64. typedef int (PyThread_set_key_value)(int, void*);
  65. typedef void (PyThread_delete_key_value)(int);
  66. wstring GetCurrentModuleFilename()
  67. {
  68. HMODULE hModule = NULL;
  69. if(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,(LPCTSTR)GetCurrentModuleFilename, &hModule)!=0)
  70. {
  71. wchar_t filename[MAX_PATH];
  72. GetModuleFileName(hModule, filename, MAX_PATH);
  73. return filename;
  74. }
  75. return wstring();
  76. }
  77. struct AttachInfo {
  78. PyEval_Lock* InitThreads;
  79. HANDLE Event;
  80. };
  81. HANDLE g_initedEvent;
  82. int AttachCallback(void *initThreads) {
  83. // initialize us for threading, this will acquire the GIL if not already created, and is a nop if the GIL is created.
  84. // This leaves us in the proper state when we return back to the runtime whether the GIL was created or not before
  85. // we were called.
  86. ((PyEval_Lock*)initThreads)();
  87. SetEvent(g_initedEvent);
  88. return 0;
  89. }
  90. char* ReadDebuggerCode(wchar_t* newName) {
  91. ifstream filestr;
  92. filestr.open(newName, ios::binary);
  93. if(filestr.fail()) {
  94. return nullptr;
  95. }
  96. // get length of file:
  97. filestr.seekg (0, ios::end);
  98. auto length = filestr.tellg();
  99. filestr.seekg (0, ios::beg);
  100. int len = (int)length;
  101. char* buffer = new char[len + 1];
  102. filestr.read(buffer, len);
  103. buffer[len] = 0;
  104. // remove carriage returns, copy zero byte
  105. for(int read = 0, write=0; read<=len; read++) {
  106. if(buffer[read] == '\r') {
  107. continue;
  108. }else if (write != read) {
  109. buffer[write] = buffer[read];
  110. }
  111. write++;
  112. }
  113. return buffer;
  114. }
  115. // create a custom heap for our hash map. This is necessary because if we suspend a thread while in a heap function
  116. // then we could deadlock here. We need to be VERY careful about what we do while the threads are suspended.
  117. class PrivateHeap {
  118. public:
  119. HANDLE heap;
  120. PrivateHeap() {
  121. heap = HeapCreate(0, 0, 0);
  122. }
  123. };
  124. template <typename T> class PrivateHeapAllocator {
  125. public:
  126. typedef size_t size_type;
  127. typedef ptrdiff_t difference_type;
  128. typedef T* pointer;
  129. typedef const T* const_pointer;
  130. typedef T& reference;
  131. typedef const T& const_reference;
  132. typedef T value_type;
  133. template <class U> struct rebind { typedef allocator<U>
  134. other; };
  135. PrivateHeapAllocator() {
  136. }
  137. pointer allocate(size_type size, allocator<void>::const_pointer hint = 0) {
  138. HeapAlloc(_heap.heap, 0, size);
  139. }
  140. void deallocate(pointer p, size_type n) {
  141. HeapFree(_heap.heap, 0, p);
  142. }
  143. private:
  144. static PrivateHeap _heap;
  145. };
  146. typedef hash_map<DWORD, HANDLE, stdext::hash_compare<DWORD, std::less<DWORD> >, PrivateHeapAllocator<pair<DWORD, HANDLE> > > MyHashMap;
  147. void ResumeThreads(MyHashMap &suspendedThreads) {
  148. for(auto start = suspendedThreads.begin(); start != suspendedThreads.end(); start++) {
  149. ResumeThread((*start).second);
  150. CloseHandle((*start).second);
  151. }
  152. suspendedThreads.clear();
  153. }
  154. // Suspends all threads ensuring that they are not currently in a call to Py_AddPendingCall.
  155. void SuspendThreads(MyHashMap &suspendedThreads, Py_AddPendingCall* addPendingCall, PyEval_ThreadsInitialized* threadsInited) {
  156. DWORD curThreadId = GetCurrentThreadId();
  157. DWORD curProcess = GetCurrentProcessId();
  158. // suspend all the threads in the process so we can do things safely...
  159. bool suspended;
  160. do {
  161. suspended = false;
  162. HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  163. if (h != INVALID_HANDLE_VALUE) {
  164. THREADENTRY32 te;
  165. te.dwSize = sizeof(te);
  166. if (Thread32First(h, &te)) {
  167. do {
  168. if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID) && te.th32OwnerProcessID == curProcess) {
  169. if(te.th32ThreadID != curThreadId && suspendedThreads.find(te.th32ThreadID) == suspendedThreads.end()) {
  170. auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
  171. if(hThread != nullptr) {
  172. SuspendThread(hThread);
  173. bool addingPendingCall = false;
  174. #if defined(_X86_)
  175. CONTEXT context;
  176. GetThreadContext(hThread, &context);
  177. if(context.Eip >= *((DWORD*)addPendingCall) && context.Eip <= (*((DWORD*)addPendingCall)) + 0x100) {
  178. addingPendingCall = true;
  179. }
  180. #elif defined(_AMD64_)
  181. CONTEXT context;
  182. GetThreadContext(hThread, &context);
  183. if(context.Rip >= *((DWORD64*)addPendingCall) && context.Rip <= *((DWORD64*)addPendingCall + 0x100)) {
  184. addingPendingCall = true;
  185. }
  186. #endif
  187. if (addingPendingCall) {
  188. // we appear to be adding a pending call via this thread - wait for this to finish so we can add our own pending call...
  189. ResumeThread(hThread);
  190. SwitchToThread(); // yield to the resumed thread if it's on our CPU...
  191. CloseHandle(hThread);
  192. } else {
  193. suspendedThreads[te.th32ThreadID] = hThread;
  194. }
  195. suspended = true;
  196. }
  197. }
  198. }
  199. te.dwSize = sizeof(te);
  200. } while (Thread32Next(h, &te) && !threadsInited());
  201. }
  202. CloseHandle(h);
  203. }
  204. } while(suspended && !threadsInited());
  205. }
  206. PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object) {
  207. if(object != nullptr && isDebug) {
  208. // debug builds have 2 extra pointers at the front that we don't care about
  209. return (PyObject*)((size_t*)object+2);
  210. }
  211. return object;
  212. }
  213. void DecRef(PyObject* object, bool isDebug) {
  214. auto noDebug = GetPyObjectPointerNoDebugInfo(isDebug, object);
  215. if(noDebug != nullptr && --noDebug->ob_refcnt == 0) {
  216. ((PyTypeObject*)GetPyObjectPointerNoDebugInfo(isDebug, noDebug->ob_type))->tp_dealloc(object);
  217. }
  218. }
  219. void IncRef(PyObject* object) {
  220. object->ob_refcnt++;
  221. }
  222. // Helper class so we can use RAII for freeing python objects when they go out of scope
  223. class PyObjectHolder {
  224. private:
  225. PyObject* _object;
  226. bool _isDebug;
  227. public:
  228. PyObjectHolder(bool isDebug) {
  229. _object = nullptr;
  230. _isDebug = isDebug;
  231. }
  232. PyObjectHolder(bool isDebug, PyObject *object) {
  233. _object = object;
  234. _isDebug = isDebug;
  235. };
  236. PyObjectHolder(bool isDebug, PyObject *object, bool addRef) {
  237. _object = object;
  238. _isDebug = isDebug;
  239. if(_object != nullptr && addRef) {
  240. GetPyObjectPointerNoDebugInfo(_isDebug, _object)->ob_refcnt++;
  241. }
  242. };
  243. PyObject* ToPython() {
  244. return _object;
  245. }
  246. ~PyObjectHolder() {
  247. DecRef(_object, _isDebug);
  248. }
  249. PyObject* operator* () {
  250. return GetPyObjectPointerNoDebugInfo(_isDebug, _object);
  251. }
  252. };
  253. // Structure for our shared memory communication, aligned to be identical on 64-bit and 32-bit
  254. struct MemoryBuffer {
  255. int PortNumber; // offset 0-4
  256. __declspec(align(8)) HANDLE AttachStartingEvent; // offset 8 - 16
  257. __declspec(align(8)) HANDLE AttachDoneEvent; // offset 16 - 24
  258. __declspec(align(8)) int ErrorNumber; // offset 24-28
  259. int VersionNumber; // offset 28-32
  260. char DebugId[1]; // null terminated string
  261. };
  262. class ConnectionInfo {
  263. public:
  264. HANDLE FileMapping;
  265. MemoryBuffer *Buffer;
  266. bool Succeeded;
  267. ConnectionInfo() : Succeeded(false) {
  268. }
  269. ConnectionInfo(MemoryBuffer *memoryBuffer, HANDLE fileMapping) :
  270. Succeeded(true), Buffer(memoryBuffer), FileMapping(fileMapping) {
  271. }
  272. // Reports an error while we're initially setting up the attach. These errors can all be
  273. // reported quickly and are reported across the shared memory buffer.
  274. void ReportError(int errorNum) {
  275. Buffer->ErrorNumber = errorNum;
  276. }
  277. // Reports an error after we've started the attach via our socket. These are errors which
  278. // may take a while to get to because the GIL is held and we cannot continue with the attach.
  279. // Because the UI for attach is gone by the time we report this error it gets reported
  280. // in the debug output pane.
  281. // These errors should also be extremely rare - for example a broken PTVS install, or a broken
  282. // Python interpreter. We'd much rather give the user a message box error earlier than the
  283. // error logged in the output window which they might miss.
  284. void ReportErrorAfterAttachDone(DWORD errorNum) {
  285. WSADATA data;
  286. if(!WSAStartup(MAKEWORD(2,0), &data)) {
  287. auto sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  288. if(sock != INVALID_SOCKET) {
  289. sockaddr_in serveraddr = { 0 };
  290. serveraddr.sin_family = AF_INET;
  291. serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  292. serveraddr.sin_port = htons(Buffer->PortNumber);
  293. // connect to our DebugConnectionListener and report the error.
  294. if(connect(sock, (sockaddr*)&serveraddr, sizeof(sockaddr_in)) == 0) {
  295. // send our debug ID as an ASCII string.
  296. send(sock, "A", 1, 0);
  297. DWORD len = strlen(Buffer->DebugId);
  298. send(sock, (const char*)&len, sizeof(DWORD), 0);
  299. send(sock, Buffer->DebugId, len, 0);
  300. // send our error number
  301. send(sock, (const char*)&errorNum, sizeof(errorNum), 0);
  302. }
  303. }
  304. }
  305. }
  306. void SetVersion(int major, int minor) {
  307. // must be kept in sync with PythonLanguageVersion.cs
  308. Buffer->VersionNumber = (major << 8) | minor;
  309. }
  310. ~ConnectionInfo() {
  311. if(Succeeded) {
  312. CloseHandle(Buffer->AttachStartingEvent);
  313. auto attachDoneEvent = Buffer->AttachDoneEvent;
  314. UnmapViewOfFile(Buffer);
  315. CloseHandle(FileMapping);
  316. // we may set this multiple times, but that doesn't matter...
  317. SetEvent(attachDoneEvent);
  318. CloseHandle(attachDoneEvent);
  319. }
  320. }
  321. };
  322. ConnectionInfo GetConnectionInfo() {
  323. HANDLE hMapFile;
  324. char* pBuf;
  325. wchar_t fullMappingName[1024];
  326. _snwprintf_s(fullMappingName, _countof(fullMappingName), L"PythonDebuggerMemory%d", GetCurrentProcessId());
  327. hMapFile = OpenFileMapping(
  328. FILE_MAP_ALL_ACCESS, // read/write access
  329. FALSE, // do not inherit the name
  330. fullMappingName); // name of mapping object
  331. if (hMapFile == NULL) {
  332. return ConnectionInfo();
  333. }
  334. pBuf = (char*) MapViewOfFile(hMapFile, // handle to map object
  335. FILE_MAP_ALL_ACCESS, // read/write permission
  336. 0,
  337. 0,
  338. 1024);
  339. if (pBuf == NULL) {
  340. CloseHandle(hMapFile);
  341. return ConnectionInfo();
  342. }
  343. return ConnectionInfo((MemoryBuffer*)pBuf, hMapFile);
  344. }
  345. // Error messages - ust be kept in sync w/ PythonAttach.cs
  346. enum ConnErrorMessages {
  347. ConnError_None,
  348. ConnError_InterpreterNotInitialized,
  349. ConnError_UnknownVersion,
  350. ConnError_LoadDebuggerFailed,
  351. ConnError_LoadDebuggerBadDebugger,
  352. ConnError_PythonNotFound,
  353. ConnError_TimeOut,
  354. ConnError_CannotOpenProcess,
  355. ConnError_OutOfMemory,
  356. ConnError_CannotInjectThread,
  357. ConnError_SysNotFound,
  358. ConnError_SysSetTraceNotFound,
  359. ConnError_SysGetTraceNotFound,
  360. ConnError_PyDebugAttachNotFound
  361. };
  362. // Ensures handles are closed when they go out of scope
  363. class HandleHolder {
  364. HANDLE _handle;
  365. public:
  366. HandleHolder(HANDLE handle) : _handle(handle) {
  367. }
  368. ~HandleHolder() {
  369. CloseHandle(_handle);
  370. }
  371. };
  372. long GetPythonThreadId(const char* version, PyThreadState* curThread) {
  373. long threadId;
  374. if(version[0] == '3') {
  375. threadId = curThread->_30_31.thread_id;
  376. }else if(version[0] == '2' && version[2] == '4') {
  377. threadId = curThread->_24.thread_id;
  378. }else{
  379. threadId = curThread->_25_27.thread_id;
  380. }
  381. return threadId;
  382. }
  383. // holder to ensure we release the GIL even in error conditions
  384. class GilHolder {
  385. PyGILState_STATE _gilState;
  386. PyGILState_Release* _release;
  387. public:
  388. GilHolder(PyGILState_Ensure* acquire, PyGILState_Release* release) {
  389. _gilState = acquire();
  390. _release = release;
  391. }
  392. ~GilHolder() {
  393. _release(_gilState);
  394. }
  395. };
  396. bool DoAttach(HMODULE module, ConnectionInfo& connInfo, bool isDebug) {
  397. // Python DLL?
  398. auto isInit = (Py_IsInitialized*)GetProcAddress(module, "Py_IsInitialized");
  399. auto getVersion = (GetVersionFunc*)GetProcAddress(module, "Py_GetVersion");
  400. if(getVersion != nullptr && isInit != nullptr && isInit()) {
  401. auto version = getVersion();
  402. // found initialized Python runtime, gather and check the APIs we need for a successful attach...
  403. auto addPendingCall = (Py_AddPendingCall*)GetProcAddress(module, "Py_AddPendingCall");
  404. auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(module, "_PyThreadState_Current");
  405. auto interpHeap = (PyInterpreterState_Head*)GetProcAddress(module, "PyInterpreterState_Head");
  406. auto gilEnsure = (PyGILState_Ensure*)GetProcAddress(module, "PyGILState_Ensure");
  407. auto gilRelease = (PyGILState_Release*)GetProcAddress(module, "PyGILState_Release");
  408. auto threadHead = (PyInterpreterState_ThreadHead*)GetProcAddress(module, "PyInterpreterState_ThreadHead");
  409. auto initThreads = (PyEval_Lock*)GetProcAddress(module, "PyEval_InitThreads");
  410. auto acquireLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_AcquireLock");
  411. auto releaseLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_ReleaseLock");
  412. auto threadsInited = (PyEval_ThreadsInitialized*)GetProcAddress(module, "PyEval_ThreadsInitialized");
  413. auto threadNext = (PyThreadState_Next*)GetProcAddress(module, "PyThreadState_Next");
  414. auto threadSwap = (PyThreadState_Swap*)GetProcAddress(module, "PyThreadState_Swap");
  415. auto pyDictNew = (PyDict_New*)GetProcAddress(module, "PyDict_New");
  416. auto pyCompileString = (Py_CompileString*)GetProcAddress(module, "Py_CompileString");
  417. auto pyEvalCode = (PyEval_EvalCode*)GetProcAddress(module, "PyEval_EvalCode");
  418. auto getDictItem = (PyDict_GetItemString*)GetProcAddress(module, "PyDict_GetItemString");
  419. auto call = (PyObject_CallFunctionObjArgs*)GetProcAddress(module, "PyObject_CallFunctionObjArgs");
  420. auto getBuiltins = (PyEval_GetBuiltins*)GetProcAddress(module, "PyEval_GetBuiltins");
  421. auto dictSetItem = (PyDict_SetItemString*)GetProcAddress(module, "PyDict_SetItemString");
  422. PyInt_FromLong* intFromLong;
  423. PyString_FromString* strFromString;
  424. if(strlen(version) > 0 && version[0] == '3') {
  425. intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyLong_FromLong");
  426. strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicodeUCS2_FromString");
  427. }else{
  428. intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyInt_FromLong");
  429. strFromString = (PyString_FromString*)GetProcAddress(module, "PyString_FromString");
  430. }
  431. auto intervalCheck = (int*)GetProcAddress(module, "_Py_CheckInterval");
  432. auto errOccurred = (PyErr_Occurred*)GetProcAddress(module, "PyErr_Occurred");
  433. auto pyErrFetch = (PyErr_Fetch*)GetProcAddress(module, "PyErr_Fetch");
  434. auto pyErrRestore = (PyErr_Restore*)GetProcAddress(module, "PyErr_Restore");
  435. auto pyImportMod = (PyImport_ImportModule*)GetProcAddress(module, "PyImport_ImportModule");
  436. auto pyGetAttr = (PyObject_GetAttrString*)GetProcAddress(module, "PyObject_GetAttrString");
  437. auto pySetAttr = (PyObject_SetAttrString*)GetProcAddress(module, "PyObject_SetAttrString");
  438. auto pyNone = (PyObject*)GetProcAddress(module, "_Py_NoneStruct");
  439. auto getSwitchInterval = (_PyEval_GetSwitchInterval*)GetProcAddress(module, "_PyEval_GetSwitchInterval");
  440. auto setSwitchInterval = (_PyEval_SetSwitchInterval*)GetProcAddress(module, "_PyEval_SetSwitchInterval");
  441. auto boolFromLong = (PyBool_FromLong*)GetProcAddress(module, "PyBool_FromLong");
  442. auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
  443. auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
  444. auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
  445. if (addPendingCall== nullptr || curPythonThread == nullptr || interpHeap == nullptr || gilEnsure == nullptr || gilRelease== nullptr || threadHead==nullptr ||
  446. initThreads==nullptr || getVersion == nullptr || releaseLock== nullptr || threadsInited== nullptr || threadNext==nullptr || threadSwap==nullptr ||
  447. pyDictNew==nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
  448. getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
  449. errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
  450. getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr || releaseLock == nullptr) {
  451. // we're missing some APIs, we cannot attach.
  452. connInfo.ReportError(ConnError_PythonNotFound);
  453. return false;
  454. }
  455. auto head = interpHeap();
  456. if(head == nullptr) {
  457. // this interpreter is loaded butt not initialized.
  458. connInfo.ReportError(ConnError_InterpreterNotInitialized);
  459. return false;
  460. }
  461. bool threadSafeAddPendingCall = false;
  462. // check that we're a supported version
  463. if (strlen(version) < 3 || // not enough version info
  464. (version[0] != '2' && version[0] != '3') || // not v2 or v3
  465. (version[0] == '2' && (version[2] < '4' || version[2] > '7')) || // not v2.4 - v2.7
  466. (version[0] == '3' && (version[2] < '0' || version[2] > '2')) // not v3.0 - 3.2
  467. ) {
  468. connInfo.ReportError(ConnError_UnknownVersion);
  469. return false;
  470. } else if(version[0] == '3' || (version[0] == '2' && version[2] >= '7')) {
  471. threadSafeAddPendingCall = true;
  472. }
  473. connInfo.SetVersion(version[0] - '0', version[2] - '0');
  474. // we know everything we need for VS to continue the attach.
  475. connInfo.ReportError(ConnError_None);
  476. SetEvent(connInfo.Buffer->AttachStartingEvent);
  477. if(!threadsInited()) {
  478. int saveIntervalCheck;
  479. unsigned long saveLongIntervalCheck;
  480. if (intervalCheck != nullptr) { // not available on 3.2
  481. saveIntervalCheck = *intervalCheck;
  482. *intervalCheck = -1; // lower the interval check so pending calls are processed faster
  483. } else if(getSwitchInterval != nullptr && setSwitchInterval != nullptr) {
  484. saveLongIntervalCheck = getSwitchInterval();
  485. setSwitchInterval(0);
  486. }
  487. //
  488. // Multiple thread support has not been initialized in the interpreter. We need multi threading support
  489. // to block any actively running threads and setup the debugger attach state.
  490. //
  491. // We need to initialize multiple threading support but we need to do so safely. One option is to call
  492. // Py_AddPendingCall and have our callback then initialize multi threading. This is completely safe on 2.7
  493. // and up. Unfortunately that doesn't work if we're not actively running code on the main thread (blocked on a lock
  494. // or reading input). It's also not thread safe pre-2.7 so we need to make sure it's safe to call on down-level
  495. // interpreters.
  496. //
  497. // Another option is to make sure no code is running - if there is no active thread then we can safely call
  498. // PyEval_InitThreads and we're in business. But to know this is safe we need to first suspend all the other
  499. // threads in the process and then inspect if any code is running.
  500. //
  501. // Finally if code is running after we've suspended the threads then we can go ahead and do Py_AddPendingCall
  502. // on down-level interpreters as long as we're sure no one else is making a call to Py_AddPendingCall at the same
  503. // time.
  504. //
  505. // Therefore our strategy becomes: Make the Py_AddPendingCall on interpreters where it's thread safe. Then suspend
  506. // all threads - if a threads IP is in Py_AddPendingCall resume and try again. Once we've got all of the threads
  507. // stopped and not in Py_AddPendingCall (which calls no functions its self, you can see this and it's size in the
  508. // debugger) then see if we have a current thread. If not go ahead and initialize multiple threading (it's now safe,
  509. // no Python code is running). Otherwise add the pending call and repeat. If at any point during this process
  510. // threading becomes initialized (due to our pending call or the Python code creating a new thread) then we're done
  511. // and we just resume all of the presently suspended threads.
  512. MyHashMap suspendedThreads;
  513. bool addedPendingCall = false;
  514. g_initedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  515. HandleHolder holder(g_initedEvent);
  516. if(addPendingCall != nullptr && threadSafeAddPendingCall) {
  517. // we're on a thread safe Python version, go ahead and pend our call to initialize threading.
  518. addPendingCall(&AttachCallback, initThreads);
  519. addedPendingCall = true;
  520. }
  521. #define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur))
  522. const DWORD ticksPerSecond = 1000;
  523. DWORD startTickCount = GetTickCount();
  524. do {
  525. SuspendThreads(suspendedThreads, addPendingCall, threadsInited);
  526. if (!threadsInited()) {
  527. if(*curPythonThread == nullptr) {
  528. // no threads are currently running, it is safe to initialize multi threading.
  529. initThreads();
  530. releaseLock();
  531. }else if(!addedPendingCall) {
  532. // someone holds the GIL but no one is actively adding any pending calls. We can pend our call
  533. // and initialize threads.
  534. addPendingCall(&AttachCallback, initThreads);
  535. addedPendingCall = true;
  536. }
  537. }
  538. ResumeThreads(suspendedThreads);
  539. }while(!threadsInited() &&
  540. (TICKS_DIFF(startTickCount, GetTickCount())) < (ticksPerSecond * 20) &&
  541. !addedPendingCall);
  542. if(!threadsInited()) {
  543. if(addedPendingCall) {
  544. // we've added our call to initialize multi-threading, we can now wait
  545. // until Python code actually starts running.
  546. SetEvent(connInfo.Buffer->AttachDoneEvent);
  547. ::WaitForSingleObject(g_initedEvent, INFINITE);
  548. }else{
  549. connInfo.ReportError(ConnError_TimeOut);
  550. return false;
  551. }
  552. }else{
  553. SetEvent(connInfo.Buffer->AttachDoneEvent);
  554. }
  555. if (intervalCheck != nullptr) {
  556. *intervalCheck = saveIntervalCheck;
  557. } else if(setSwitchInterval != nullptr) {
  558. setSwitchInterval(saveLongIntervalCheck);
  559. }
  560. }else{
  561. SetEvent(connInfo.Buffer->AttachDoneEvent);
  562. }
  563. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  564. // go ahead and bring in the debugger module and initialize all threads in the process...
  565. GilHolder gilLock(gilEnsure, gilRelease); // acquire and hold the GIL until done...
  566. auto filename = GetCurrentModuleFilename();
  567. if(filename.length() == 0) {
  568. return nullptr;
  569. }
  570. wchar_t drive[_MAX_DRIVE], dir[_MAX_DIR], file[_MAX_FNAME], ext[_MAX_EXT];
  571. _wsplitpath_s(filename.c_str(), drive, _MAX_DRIVE, dir, _MAX_DIR, file, _MAX_FNAME, ext, _MAX_EXT);
  572. wchar_t newName[MAX_PATH];
  573. #if defined(_AMD64_)
  574. _wmakepath_s(newName, drive, dir, L"..\\visualstudio_py_debugger", L".py");
  575. #else
  576. _wmakepath_s(newName, drive, dir, L"visualstudio_py_debugger", L".py");
  577. #endif
  578. // run the debugger code...
  579. auto debuggerCode = ReadDebuggerCode(newName);
  580. if(debuggerCode == nullptr) {
  581. connInfo.ReportErrorAfterAttachDone(ConnError_LoadDebuggerFailed);
  582. return false;
  583. }
  584. auto code = PyObjectHolder(isDebug, pyCompileString(debuggerCode, "visualstudio_py_debugger.py", 257 /*Py_file_input*/));
  585. delete [] debuggerCode;
  586. if(*code == nullptr) {
  587. connInfo.ReportErrorAfterAttachDone(ConnError_LoadDebuggerFailed);
  588. return false;
  589. }
  590. // create a globals/locals dict for evaluating the code...
  591. auto globalsDict = PyObjectHolder(isDebug, pyDictNew());
  592. dictSetItem(globalsDict.ToPython(), "__builtins__", getBuiltins());
  593. int size = WideCharToMultiByte(CP_UTF8, 0, newName, wcslen(newName), NULL, 0, NULL, NULL);
  594. char* filenameBuffer = new char[size];
  595. if(WideCharToMultiByte(CP_UTF8, 0, newName, wcslen(newName), filenameBuffer, size, NULL, NULL) != 0) {
  596. filenameBuffer[size] = 0;
  597. dictSetItem (globalsDict.ToPython(), "__file__", strFromString(filenameBuffer));
  598. }
  599. pyEvalCode(code.ToPython(), globalsDict.ToPython(), globalsDict.ToPython());
  600. // now initialize debugger process wide state
  601. auto attach_process = PyObjectHolder(isDebug, getDictItem(globalsDict.ToPython(), "attach_process"), true);
  602. auto new_thread = PyObjectHolder(isDebug, getDictItem(globalsDict.ToPython(), "new_thread"), true);
  603. if (*attach_process == nullptr || *new_thread == nullptr) {
  604. connInfo.ReportErrorAfterAttachDone(ConnError_LoadDebuggerBadDebugger);
  605. return false;
  606. }
  607. auto pyPortNum = PyObjectHolder(isDebug, intFromLong(connInfo.Buffer->PortNumber));
  608. auto debugId = PyObjectHolder(isDebug, strFromString(connInfo.Buffer->DebugId));
  609. DecRef(call(attach_process.ToPython(), pyPortNum.ToPython(), debugId.ToPython(), NULL), isDebug);
  610. auto sysMod = PyObjectHolder(isDebug, pyImportMod("sys"));
  611. if(*sysMod == nullptr) {
  612. connInfo.ReportErrorAfterAttachDone(ConnError_SysNotFound);
  613. return false;
  614. }
  615. auto settrace = PyObjectHolder(isDebug, pyGetAttr(sysMod.ToPython(), "settrace"));
  616. if(*settrace == nullptr) {
  617. connInfo.ReportErrorAfterAttachDone(ConnError_SysSetTraceNotFound);
  618. return false;
  619. }
  620. auto gettrace = PyObjectHolder(isDebug, pyGetAttr(sysMod.ToPython(), "gettrace"));
  621. // we need to walk the thread list each time after we've initialized a thread so that we are always
  622. // dealing w/ a valid thread list (threads can exit when we run code and therefore the current thread
  623. // could be corrupt). We also don't care about newly created threads as our start_new_thread wrapper
  624. // will handle those. So we collect the initial set of threads first here so that we don't keep iterating
  625. // if the program is spawning large numbers of threads.
  626. hash_set<PyThreadState*> initialThreads;
  627. for(auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
  628. initialThreads.insert(curThread);
  629. }
  630. auto pyTrue = boolFromLong(1);
  631. auto pyFalse = boolFromLong(0);
  632. hash_set<PyThreadState*> seenThreads;
  633. {
  634. // Python 3.2's GIL has changed and we need it to be less aggressive in the face of heavy contention
  635. // so that we can successfully attach. So we prevent it from switching us out here.
  636. unsigned long saveLongIntervalCheck;
  637. if(getSwitchInterval != nullptr && setSwitchInterval != nullptr) {
  638. saveLongIntervalCheck = getSwitchInterval();
  639. setSwitchInterval(INFINITE);
  640. }
  641. // find what index is holding onto the thread state...
  642. auto curThread = *curPythonThread;
  643. int threadStateIndex = -1;
  644. for(int i = 0; i < 100000; i++) {
  645. void* value = getThreadTls(i);
  646. if(value == curThread) {
  647. threadStateIndex = i;
  648. break;
  649. }
  650. }
  651. bool foundThread;
  652. int processedThreads = 0;
  653. do {
  654. foundThread = false;
  655. for(auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
  656. if(initialThreads.find(curThread) == initialThreads.end() ||
  657. seenThreads.insert(curThread).second == false) {
  658. continue;
  659. }
  660. foundThread = true;
  661. processedThreads++;
  662. long threadId = GetPythonThreadId(version, curThread);
  663. // skip this thread - it doesn't really have any Python code on it...
  664. if(threadId != GetCurrentThreadId()) {
  665. // create new debugger Thread object on our injected thread
  666. auto pyThreadId = PyObjectHolder(isDebug, intFromLong(threadId));
  667. PyFrameObject* frame;
  668. // update all of the frames so they have our trace func
  669. if(version[0] == '3') {
  670. frame = curThread->_30_31.frame;
  671. }else if(version[0] == '2' && version[2] == '4') {
  672. frame = curThread->_24.frame;
  673. }else{
  674. frame = curThread->_25_27.frame;
  675. }
  676. auto threadObj = PyObjectHolder(isDebug, call(new_thread.ToPython(), pyThreadId.ToPython(), pyTrue, frame, NULL));
  677. if(threadObj.ToPython() == pyNone || *threadObj == nullptr) {
  678. break;
  679. }
  680. // switch to our new thread so we can call sys.settrace on it...
  681. // all of the work here needs to be minimal - in particular we shouldn't
  682. // ever evaluate user defined code as we could end up switching to this
  683. // thread on the main thread and corrupting state.
  684. auto prevThreadState = getThreadTls(threadStateIndex);
  685. delThreadTls(threadStateIndex);
  686. setThreadTls(threadStateIndex, curThread);
  687. auto prevThread = threadSwap(curThread);
  688. // save and restore the error in case something funky happens...
  689. auto errOccured = errOccurred();
  690. PyObject *type, *value, *traceback;
  691. if(errOccured) {
  692. pyErrFetch(&type, &value, &traceback);
  693. }
  694. auto traceFunc = PyObjectHolder(isDebug, pyGetAttr(threadObj.ToPython(), "trace_func"));
  695. if(*gettrace == NULL) {
  696. DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
  697. }else{
  698. auto existingTraceFunc = PyObjectHolder(isDebug, call(gettrace.ToPython(), NULL));
  699. DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
  700. if (existingTraceFunc.ToPython() != pyNone) {
  701. pySetAttr(threadObj.ToPython(), "prev_trace_func", existingTraceFunc.ToPython());
  702. }
  703. }
  704. if(errOccured) {
  705. pyErrRestore(type, value, traceback);
  706. }
  707. // update all of the frames so they have our trace func
  708. auto curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, frame);
  709. while(curFrame != nullptr) {
  710. DecRef(curFrame->f_trace, isDebug);
  711. IncRef(*traceFunc);
  712. curFrame->f_trace = traceFunc.ToPython();
  713. curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, curFrame->f_back);
  714. }
  715. delThreadTls(threadStateIndex);
  716. setThreadTls(threadStateIndex, prevThread);
  717. threadSwap(prevThread);
  718. }
  719. break;
  720. }
  721. }while(foundThread);
  722. if(getSwitchInterval != nullptr && setSwitchInterval != nullptr) {
  723. setSwitchInterval(saveLongIntervalCheck);
  724. }
  725. }
  726. return true;
  727. }
  728. connInfo.ReportError(ConnError_PythonNotFound);
  729. return false;
  730. }
  731. DWORD __stdcall AttachWorker(LPVOID arg) {
  732. HANDLE hProcess = GetCurrentProcess();
  733. size_t modSize = sizeof(HMODULE) * 1024;
  734. HMODULE* hMods = (HMODULE*)_malloca(modSize);
  735. if(hMods == nullptr) {
  736. return 0;
  737. }
  738. DWORD modsNeeded;
  739. while(!EnumProcessModules(hProcess, hMods, modSize, &modsNeeded)) {
  740. // try again w/ more space...
  741. _freea(hMods);
  742. hMods = (HMODULE*)_malloca(modsNeeded);
  743. if(hMods == nullptr) {
  744. return 0;
  745. }
  746. modSize = modsNeeded;
  747. }
  748. {
  749. // scoped to clean connection info before we unload
  750. auto connInfo = GetConnectionInfo();
  751. bool attached = false, pythonFound = false;
  752. if(connInfo.Succeeded) {
  753. for(size_t i = 0; i<modsNeeded/sizeof(HMODULE); i++) {
  754. wchar_t mod_name[MAX_PATH];
  755. if(GetModuleBaseName(hProcess, hMods[i], mod_name, MAX_PATH)) {
  756. if(_wcsnicmp(mod_name, L"python", 6) == 0) {
  757. bool isDebug = false;
  758. if(wcslen(mod_name) >= 10 && _wcsnicmp(mod_name + 8, L"_d", 2) == 0) {
  759. isDebug = true;
  760. }
  761. pythonFound = true;
  762. if(DoAttach(hMods[i], connInfo, isDebug)) {
  763. // we've successfully attached the debugger
  764. attached = true;
  765. break;
  766. }
  767. }
  768. }
  769. }
  770. }
  771. if(!attached) {
  772. if(connInfo.Buffer->ErrorNumber == 0) {
  773. if(pythonFound) {
  774. connInfo.ReportError(ConnError_PythonNotFound);
  775. }else{
  776. connInfo.ReportError(ConnError_InterpreterNotInitialized);
  777. }
  778. }
  779. SetEvent(connInfo.Buffer->AttachStartingEvent);
  780. }
  781. }
  782. HMODULE hModule = NULL;
  783. if(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,(LPCTSTR)GetCurrentModuleFilename, &hModule)!=0) {
  784. // unload ourselves and exit...
  785. FreeLibraryAndExitThread(hModule, 0);
  786. }
  787. return 0;
  788. }
  789. void Attach() {
  790. // create a new thread to run the attach code on so we're not running in DLLMain
  791. // Note we do no synchronization with other threads at all, and we don't care that
  792. // thread detach will be called w/o an attach, so this is safe.
  793. DWORD threadId;
  794. CreateThread(NULL, 0, &AttachWorker, NULL, 0, &threadId);
  795. }