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 * Contributor: Fabio Zadrozny
14 *
15 * Based on PyDebugAttach.cpp from PVTS. Windows only.
16 * Initially we did an attach completely based on shellcode which got the
17 * GIL called PyRun_SimpleString with the needed code and was done with it
18 * (so, none of this code was needed).
19 * Now, newer version of Python don't initialize threading by default, so,
20 * most of this code is done only to overcome this limitation (and as a plus,
21 * if there's no code running, we also pause the threads to make our code run).
22 *
23 * On Linux the approach is still the simpler one (using gdb), so, on newer
24 * versions of Python it may not work unless the user has some code running
25 * and threads are initialized.
26 * I.e.:
27 *
28 * The user may have to add the code below in the start of its script for
29 * a successful attach (if he doesn't already use threads).
30 *
31 * from threading import Thread
32 * Thread(target=str).start()
33 *
34 * -- this is the workaround for the fact that we can't get the gil
35 * if there aren't any threads (PyGILState_Ensure gives an error).
36 * ***************************************************************************/
37
38
39 // Access to std::cout and std::endl
40 #include <iostream>
41
42 // DECLDIR will perform an export for us
43 #define DLL_EXPORT
44
45 #include "attach.h"
46 #include "stdafx.h"
47 #include "python.h"
48
49 #pragma comment(lib, "kernel32.lib")
50 #pragma comment(lib, "user32.lib")
51 #pragma comment(lib, "advapi32.lib")
52 #pragma comment(lib, "psapi.lib")
53
54 // _Always_ is not defined for all versions, so make it a no-op if missing.
55 #ifndef _Always_
56 #define _Always_(x) x
57 #endif
58
59 using namespace std;
60
61 typedef int (Py_IsInitialized)();
62 typedef void (PyEval_Lock)(); // Acquire/Release lock
63 typedef void (PyThreadState_API)(PyThreadState *); // Acquire/Release lock
64 typedef PyInterpreterState* (PyInterpreterState_Head)();
65 typedef PyThreadState* (PyInterpreterState_ThreadHead)(PyInterpreterState* interp);
66 typedef PyThreadState* (PyThreadState_Next)(PyThreadState *tstate);
67 typedef PyThreadState* (PyThreadState_Swap)(PyThreadState *tstate);
68 typedef int (PyRun_SimpleString)(const char *command);
69 typedef PyObject* (PyDict_New)();
70 typedef PyObject* (PyModule_New)(const char *name);
71 typedef PyObject* (PyModule_GetDict)(PyObject *module);
72 typedef PyObject* (Py_CompileString)(const char *str, const char *filename, int start);
73 typedef PyObject* (PyEval_EvalCode)(PyObject *co, PyObject *globals, PyObject *locals);
74 typedef PyObject* (PyDict_GetItemString)(PyObject *p, const char *key);
75 typedef PyObject* (PyObject_CallFunctionObjArgs)(PyObject *callable, ...); // call w/ varargs, last arg should be NULL
76 typedef void (PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
77 typedef PyObject* (PyEval_GetBuiltins)();
78 typedef int (PyDict_SetItemString)(PyObject *dp, const char *key, PyObject *item);
79 typedef int (PyEval_ThreadsInitialized)();
80 typedef void (Py_AddPendingCall)(int (*func)(void *), void*);
81 typedef PyObject* (PyInt_FromLong)(long);
82 typedef PyObject* (PyString_FromString)(const char* s);
83 typedef void PyEval_SetTrace(Py_tracefunc func, PyObject *obj);
84 typedef void (PyErr_Restore)(PyObject *type, PyObject *value, PyObject *traceback);
85 typedef void (PyErr_Fetch)(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
86 typedef PyObject* (PyErr_Occurred)();
87 typedef PyObject* (PyErr_Print)();
88 typedef PyObject* (PyImport_ImportModule) (const char *name);
89 typedef PyObject* (PyObject_GetAttrString)(PyObject *o, const char *attr_name);
90 typedef PyObject* (PyObject_HasAttrString)(PyObject *o, const char *attr_name);
91 typedef PyObject* (PyObject_SetAttrString)(PyObject *o, const char *attr_name, PyObject* value);
92 typedef PyObject* (PyBool_FromLong)(long v);
93 typedef enum { PyGILState_LOCKED, PyGILState_UNLOCKED } PyGILState_STATE;
94 typedef PyGILState_STATE(PyGILState_Ensure)();
95 typedef void (PyGILState_Release)(PyGILState_STATE);
96 typedef unsigned long (_PyEval_GetSwitchInterval)(void);
97 typedef void (_PyEval_SetSwitchInterval)(unsigned long microseconds);
98 typedef void* (PyThread_get_key_value)(int);
99 typedef int (PyThread_set_key_value)(int, void*);
100 typedef void (PyThread_delete_key_value)(int);
101 typedef PyGILState_STATE PyGILState_EnsureFunc(void);
102 typedef void PyGILState_ReleaseFunc(PyGILState_STATE);
103 typedef PyObject* PyInt_FromSize_t(size_t ival);
104 typedef PyThreadState *PyThreadState_NewFunc(PyInterpreterState *interp);
105
106 class PyObjectHolder;
107 PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object);
108 void DecRef(PyObject* object, bool isDebug);
109 void IncRef(PyObject* object, bool isDebug);
110
111 #define MAX_INTERPRETERS 10
112
113 // Helper class so we can use RAII for freeing python objects when they go out of scope
114 class PyObjectHolder {
115 private:
116 PyObject* _object;
117 public:
118 bool _isDebug;
119
PyObjectHolder(bool isDebug)120 PyObjectHolder(bool isDebug) {
121 _object = nullptr;
122 _isDebug = isDebug;
123 }
124
PyObjectHolder(bool isDebug,PyObject * object)125 PyObjectHolder(bool isDebug, PyObject *object) {
126 _object = object;
127 _isDebug = isDebug;
128 };
129
PyObjectHolder(bool isDebug,PyObject * object,bool addRef)130 PyObjectHolder(bool isDebug, PyObject *object, bool addRef) {
131 _object = object;
132 _isDebug = isDebug;
133 if (_object != nullptr && addRef) {
134 GetPyObjectPointerNoDebugInfo(_isDebug, _object)->ob_refcnt++;
135 }
136 };
137
ToPython()138 PyObject* ToPython() {
139 return _object;
140 }
141
~PyObjectHolder()142 ~PyObjectHolder() {
143 DecRef(_object, _isDebug);
144 }
145
operator *()146 PyObject* operator* () {
147 return GetPyObjectPointerNoDebugInfo(_isDebug, _object);
148 }
149 };
150
151 class InterpreterInfo {
152 public:
InterpreterInfo(HMODULE module,bool debug)153 InterpreterInfo(HMODULE module, bool debug) :
154 Interpreter(module),
155 CurrentThread(nullptr),
156 NewThreadFunction(nullptr),
157 PyGILState_Ensure(nullptr),
158 Version(PythonVersion_Unknown),
159 Call(nullptr),
160 IsDebug(debug),
161 SetTrace(nullptr),
162 PyThreadState_New(nullptr),
163 ThreadState_Swap(nullptr) {
164 }
165
~InterpreterInfo()166 ~InterpreterInfo() {
167 if (NewThreadFunction != nullptr) {
168 delete NewThreadFunction;
169 }
170 }
171
172 PyObjectHolder* NewThreadFunction;
173 PyThreadState** CurrentThread;
174
175 HMODULE Interpreter;
176 PyGILState_EnsureFunc* PyGILState_Ensure;
177 PyEval_SetTrace* SetTrace;
178 PyThreadState_NewFunc* PyThreadState_New;
179 PyThreadState_Swap* ThreadState_Swap;
180
GetVersion()181 PythonVersion GetVersion() {
182 if (Version == PythonVersion_Unknown) {
183 Version = ::GetPythonVersion(Interpreter);
184 }
185 return Version;
186 }
187
GetCall()188 PyObject_CallFunctionObjArgs* GetCall() {
189 if (Call == nullptr) {
190 Call = (PyObject_CallFunctionObjArgs*)GetProcAddress(Interpreter, "PyObject_CallFunctionObjArgs");
191 }
192
193 return Call;
194 }
195
EnsureSetTrace()196 bool EnsureSetTrace() {
197 if (SetTrace == nullptr) {
198 auto setTrace = (PyEval_SetTrace*)(void*)GetProcAddress(Interpreter, "PyEval_SetTrace");
199 SetTrace = setTrace;
200 }
201 return SetTrace != nullptr;
202 }
203
EnsureThreadStateSwap()204 bool EnsureThreadStateSwap() {
205 if (ThreadState_Swap == nullptr) {
206 auto swap = (PyThreadState_Swap*)(void*)GetProcAddress(Interpreter, "PyThreadState_Swap");
207 ThreadState_Swap = swap;
208 }
209 return ThreadState_Swap != nullptr;
210 }
211
EnsureCurrentThread()212 bool EnsureCurrentThread() {
213 if (CurrentThread == nullptr) {
214 auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(
215 Interpreter, "_PyThreadState_Current");
216 CurrentThread = curPythonThread;
217 }
218
219 return CurrentThread != nullptr;
220 }
221
222 private:
223 PythonVersion Version;
224 PyObject_CallFunctionObjArgs* Call;
225 bool IsDebug;
226 };
227
228 DWORD _interpreterCount = 0;
229 InterpreterInfo* _interpreterInfo[MAX_INTERPRETERS];
230
PatchIAT(PIMAGE_DOS_HEADER dosHeader,PVOID replacingFunc,LPSTR exportingDll,LPVOID newFunction)231 void PatchIAT(PIMAGE_DOS_HEADER dosHeader, PVOID replacingFunc, LPSTR exportingDll, LPVOID newFunction) {
232 if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
233 return;
234 }
235
236 auto ntHeader = (IMAGE_NT_HEADERS*)(((BYTE*)dosHeader) + dosHeader->e_lfanew);
237 if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
238 return;
239 }
240
241 auto importAddr = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
242 if (importAddr == 0) {
243 return;
244 }
245
246 auto import = (PIMAGE_IMPORT_DESCRIPTOR)(importAddr + ((BYTE*)dosHeader));
247
248 while (import->Name) {
249 char* name = (char*)(import->Name + ((BYTE*)dosHeader));
250 if (_stricmp(name, exportingDll) == 0) {
251 auto thunkData = (PIMAGE_THUNK_DATA)((import->FirstThunk) + ((BYTE*)dosHeader));
252
253 while (thunkData->u1.Function) {
254 PVOID funcAddr = (char*)(thunkData->u1.Function);
255
256 if (funcAddr == replacingFunc) {
257 DWORD flOldProtect;
258 if (VirtualProtect(&thunkData->u1, sizeof(SIZE_T), PAGE_READWRITE, &flOldProtect)) {
259 thunkData->u1.Function = (SIZE_T)newFunction;
260 VirtualProtect(&thunkData->u1, sizeof(SIZE_T), flOldProtect, &flOldProtect);
261 }
262 }
263 thunkData++;
264 }
265 }
266
267 import++;
268 }
269 }
270
271 typedef BOOL WINAPI EnumProcessModulesFunc(
272 __in HANDLE hProcess,
273 __out HMODULE *lphModule,
274 __in DWORD cb,
275 __out LPDWORD lpcbNeeded
276 );
277
278 typedef __kernel_entry NTSTATUS NTAPI
279 NtQueryInformationProcessFunc(
280 IN HANDLE ProcessHandle,
281 IN PROCESSINFOCLASS ProcessInformationClass,
282 OUT PVOID ProcessInformation,
283 IN ULONG ProcessInformationLength,
284 OUT PULONG ReturnLength OPTIONAL
285 );
286
287
288 // A helper version of EnumProcessModules. On Win7 uses the real EnumProcessModules which
289 // lives in kernel32, and so is safe to use in DLLMain. Pre-Win7 we use NtQueryInformationProcess
290 // (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx) and walk the
291 // LDR_DATA_TABLE_ENTRY data structures http://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx
292 // which have changed in Windows 7, and may change more in the future, so we can't use them there.
__success(return)293 __success(return) BOOL EnumProcessModulesHelper(
294 __in HANDLE hProcess,
295 __out HMODULE *lphModule,
296 __in DWORD cb,
297 _Always_(__out) LPDWORD lpcbNeeded
298 ) {
299 if (lpcbNeeded == nullptr) {
300 return FALSE;
301 }
302 *lpcbNeeded = 0;
303
304 auto kernel32 = GetModuleHandle(L"kernel32.dll");
305 if (kernel32 == nullptr) {
306 return FALSE;
307 }
308
309 auto enumProc = (EnumProcessModulesFunc*)GetProcAddress(kernel32, "K32EnumProcessModules");
310 if (enumProc == nullptr) {
311 // Fallback to pre-Win7 method
312 PROCESS_BASIC_INFORMATION basicInfo;
313 auto ntdll = GetModuleHandle(L"ntdll.dll");
314 if (ntdll == nullptr) {
315 return FALSE;
316 }
317
318 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
319 NtQueryInformationProcessFunc* queryInfo = (NtQueryInformationProcessFunc*)GetProcAddress(ntdll, "NtQueryInformationProcess");
320 if (queryInfo == nullptr) {
321 return FALSE;
322 }
323
324 auto result = queryInfo(
325 GetCurrentProcess(),
326 ProcessBasicInformation,
327 &basicInfo,
328 sizeof(PROCESS_BASIC_INFORMATION),
329 NULL
330 );
331
332 if (FAILED(result)) {
333 return FALSE;
334 }
335
336 // http://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx
337 PEB* peb = basicInfo.PebBaseAddress;
338 auto start = (LDR_DATA_TABLE_ENTRY*)(peb->Ldr->InMemoryOrderModuleList.Flink);
339
340 auto cur = start;
341 *lpcbNeeded = 0;
342
343 do {
344 if ((*lpcbNeeded + sizeof(SIZE_T)) <= cb) {
345 PVOID *curLink = (PVOID*)cur;
346 curLink -= 2;
347 LDR_DATA_TABLE_ENTRY* curTable = (LDR_DATA_TABLE_ENTRY*)curLink;
348 if (curTable->DllBase == nullptr) {
349 break;
350 }
351 lphModule[(*lpcbNeeded) / sizeof(SIZE_T)] = (HMODULE)curTable->DllBase;
352 }
353
354 (*lpcbNeeded) += sizeof(SIZE_T);
355 cur = (LDR_DATA_TABLE_ENTRY*)((LIST_ENTRY*)cur)->Flink;
356 } while (cur != start && cur != 0);
357
358 return *lpcbNeeded <= cb;
359 }
360
361 return enumProc(hProcess, lphModule, cb, lpcbNeeded);
362 }
363
364 // This function will work with Win7 and later versions of the OS and is safe to call under
365 // the loader lock (all APIs used are in kernel32).
PatchFunction(LPSTR exportingDll,PVOID replacingFunc,LPVOID newFunction)366 BOOL PatchFunction(LPSTR exportingDll, PVOID replacingFunc, LPVOID newFunction) {
367 HANDLE hProcess = GetCurrentProcess();
368 DWORD modSize = sizeof(HMODULE) * 1024;
369 HMODULE* hMods = (HMODULE*)_malloca(modSize);
370 DWORD modsNeeded = 0;
371 if (hMods == nullptr) {
372 modsNeeded = 0;
373 return FALSE;
374 }
375
376 while (!EnumProcessModulesHelper(hProcess, hMods, modSize, &modsNeeded)) {
377 // try again w/ more space...
378 _freea(hMods);
379 hMods = (HMODULE*)_malloca(modsNeeded);
380 if (hMods == nullptr) {
381 modsNeeded = 0;
382 break;
383 }
384 modSize = modsNeeded;
385 }
386
387 for (DWORD tmp = 0; tmp < modsNeeded / sizeof(HMODULE); tmp++) {
388 PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hMods[tmp];
389
390 PatchIAT(dosHeader, replacingFunc, exportingDll, newFunction);
391 }
392
393 return TRUE;
394 }
395
GetCurrentModuleFilename()396 wstring GetCurrentModuleFilename() {
397 HMODULE hModule = NULL;
398 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)GetCurrentModuleFilename, &hModule) != 0) {
399 wchar_t filename[MAX_PATH];
400 GetModuleFileName(hModule, filename, MAX_PATH);
401 return filename;
402 }
403 return wstring();
404 }
405
406 struct AttachInfo {
407 PyEval_Lock* InitThreads;
408 HANDLE Event;
409 };
410
411 HANDLE g_initedEvent;
AttachCallback(void * initThreads)412 int AttachCallback(void *initThreads) {
413 // initialize us for threading, this will acquire the GIL if not already created, and is a nop if the GIL is created.
414 // This leaves us in the proper state when we return back to the runtime whether the GIL was created or not before
415 // we were called.
416 ((PyEval_Lock*)initThreads)();
417 SetEvent(g_initedEvent);
418 return 0;
419 }
420
ReadCodeFromFile(wchar_t * filePath)421 char* ReadCodeFromFile(wchar_t* filePath) {
422 ifstream filestr;
423 filestr.open(filePath, ios::binary);
424 if (filestr.fail()) {
425 return nullptr;
426 }
427
428 // get length of file:
429 filestr.seekg(0, ios::end);
430 auto length = filestr.tellg();
431 filestr.seekg(0, ios::beg);
432
433 int len = (int)length;
434 char* buffer = new char[len + 1];
435 filestr.read(buffer, len);
436 buffer[len] = 0;
437
438 // remove carriage returns, copy zero byte
439 for (int read = 0, write = 0; read <= len; read++) {
440 if (buffer[read] == '\r') {
441 continue;
442 } else if (write != read) {
443 buffer[write] = buffer[read];
444 }
445 write++;
446 }
447
448 return buffer;
449 }
450
451 // create a custom heap for our unordered map. This is necessary because if we suspend a thread while in a heap function
452 // then we could deadlock here. We need to be VERY careful about what we do while the threads are suspended.
453 static HANDLE g_heap = 0;
454
455 template<typename T>
456 class PrivateHeapAllocator {
457 public:
458 typedef size_t size_type;
459 typedef ptrdiff_t difference_type;
460 typedef T* pointer;
461 typedef const T* const_pointer;
462 typedef T& reference;
463 typedef const T& const_reference;
464 typedef T value_type;
465
466 template<class U>
467 struct rebind {
468 typedef PrivateHeapAllocator<U> other;
469 };
470
PrivateHeapAllocator()471 explicit PrivateHeapAllocator() {}
472
PrivateHeapAllocator(PrivateHeapAllocator const &)473 PrivateHeapAllocator(PrivateHeapAllocator const&) {}
474
~PrivateHeapAllocator()475 ~PrivateHeapAllocator() {}
476
477 template<typename U>
PrivateHeapAllocator(PrivateHeapAllocator<U> const &)478 PrivateHeapAllocator(PrivateHeapAllocator<U> const&) {}
479
allocate(size_type size,allocator<void>::const_pointer hint=0)480 pointer allocate(size_type size, allocator<void>::const_pointer hint = 0) {
481 if (g_heap == nullptr) {
482 g_heap = HeapCreate(0, 0, 0);
483 }
484 auto mem = HeapAlloc(g_heap, 0, size * sizeof(T));
485 return static_cast<pointer>(mem);
486 }
487
deallocate(pointer p,size_type n)488 void deallocate(pointer p, size_type n) {
489 HeapFree(g_heap, 0, p);
490 }
491
max_size() const492 size_type max_size() const {
493 return (std::numeric_limits<size_type>::max)() / sizeof(T);
494 }
495
construct(pointer p,const T & t)496 void construct(pointer p, const T& t) {
497 new(p) T(t);
498 }
499
destroy(pointer p)500 void destroy(pointer p) {
501 p->~T();
502 }
503 };
504
505 typedef unordered_map<DWORD, HANDLE, std::hash<DWORD>, std::equal_to<DWORD>, PrivateHeapAllocator<pair<DWORD, HANDLE>>> ThreadMap;
506
ResumeThreads(ThreadMap & suspendedThreads)507 void ResumeThreads(ThreadMap &suspendedThreads) {
508 for (auto start = suspendedThreads.begin(); start != suspendedThreads.end(); start++) {
509 ResumeThread((*start).second);
510 CloseHandle((*start).second);
511 }
512 suspendedThreads.clear();
513 }
514
515 // Suspends all threads ensuring that they are not currently in a call to Py_AddPendingCall.
SuspendThreads(ThreadMap & suspendedThreads,Py_AddPendingCall * addPendingCall,PyEval_ThreadsInitialized * threadsInited)516 void SuspendThreads(ThreadMap &suspendedThreads, Py_AddPendingCall* addPendingCall, PyEval_ThreadsInitialized* threadsInited) {
517 DWORD curThreadId = GetCurrentThreadId();
518 DWORD curProcess = GetCurrentProcessId();
519 // suspend all the threads in the process so we can do things safely...
520 bool suspended;
521
522 do {
523 suspended = false;
524 HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
525 if (h != INVALID_HANDLE_VALUE) {
526
527 THREADENTRY32 te;
528 te.dwSize = sizeof(te);
529 if (Thread32First(h, &te)) {
530 do {
531 if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID) && te.th32OwnerProcessID == curProcess) {
532
533
534 if (te.th32ThreadID != curThreadId && suspendedThreads.find(te.th32ThreadID) == suspendedThreads.end()) {
535 auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
536 if (hThread != nullptr) {
537 SuspendThread(hThread);
538
539 bool addingPendingCall = false;
540
541 CONTEXT context;
542 memset(&context, 0x00, sizeof(CONTEXT));
543 context.ContextFlags = CONTEXT_ALL;
544 GetThreadContext(hThread, &context);
545
546 #if defined(_X86_)
547 if(context.Eip >= *((DWORD*)addPendingCall) && context.Eip <= (*((DWORD*)addPendingCall)) + 0x100) {
548 addingPendingCall = true;
549 }
550 #elif defined(_AMD64_)
551 if (context.Rip >= *((DWORD64*)addPendingCall) && context.Rip <= *((DWORD64*)addPendingCall + 0x100)) {
552 addingPendingCall = true;
553 }
554 #endif
555
556 if (addingPendingCall) {
557 // we appear to be adding a pending call via this thread - wait for this to finish so we can add our own pending call...
558 ResumeThread(hThread);
559 SwitchToThread(); // yield to the resumed thread if it's on our CPU...
560 CloseHandle(hThread);
561 } else {
562 suspendedThreads[te.th32ThreadID] = hThread;
563 }
564 suspended = true;
565 }
566 }
567 }
568
569 te.dwSize = sizeof(te);
570 } while (Thread32Next(h, &te) && !threadsInited());
571 }
572 CloseHandle(h);
573 }
574 } while (suspended && !threadsInited());
575 }
576
GetPyObjectPointerNoDebugInfo(bool isDebug,PyObject * object)577 PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object) {
578 if (object != nullptr && isDebug) {
579 // debug builds have 2 extra pointers at the front that we don't care about
580 return (PyObject*)((size_t*)object + 2);
581 }
582 return object;
583 }
584
DecRef(PyObject * object,bool isDebug)585 void DecRef(PyObject* object, bool isDebug) {
586 auto noDebug = GetPyObjectPointerNoDebugInfo(isDebug, object);
587
588 if (noDebug != nullptr && --noDebug->ob_refcnt == 0) {
589 ((PyTypeObject*)GetPyObjectPointerNoDebugInfo(isDebug, noDebug->ob_type))->tp_dealloc(object);
590 }
591 }
592
IncRef(PyObject * object)593 void IncRef(PyObject* object) {
594 object->ob_refcnt++;
595 }
596
597
598 // Ensures handles are closed when they go out of scope
599 class HandleHolder {
600 HANDLE _handle;
601 public:
HandleHolder(HANDLE handle)602 HandleHolder(HANDLE handle) : _handle(handle) {
603 }
604
~HandleHolder()605 ~HandleHolder() {
606 CloseHandle(_handle);
607 }
608 };
609
GetPythonThreadId(PythonVersion version,PyThreadState * curThread)610 long GetPythonThreadId(PythonVersion version, PyThreadState* curThread) {
611 long threadId = 0;
612 if (PyThreadState_25_27::IsFor(version)) {
613 threadId = ((PyThreadState_25_27*)curThread)->thread_id;
614 } else if (PyThreadState_30_33::IsFor(version)) {
615 threadId = ((PyThreadState_30_33*)curThread)->thread_id;
616 } else if (PyThreadState_34_36::IsFor(version)) {
617 threadId = ((PyThreadState_34_36*)curThread)->thread_id;
618 }
619 return threadId;
620 }
621
622 // holder to ensure we release the GIL even in error conditions
623 class GilHolder {
624 PyGILState_STATE _gilState;
625 PyGILState_Release* _release;
626 public:
GilHolder(PyGILState_Ensure * acquire,PyGILState_Release * release)627 GilHolder(PyGILState_Ensure* acquire, PyGILState_Release* release) {
628 _gilState = acquire();
629 _release = release;
630 }
631
~GilHolder()632 ~GilHolder() {
633 _release(_gilState);
634 }
635 };
636
LoadAndEvaluateCode(wchar_t * filePath,const char * fileName,bool isDebug,PyObject * globalsDict,Py_CompileString * pyCompileString,PyDict_SetItemString * dictSetItem,PyEval_EvalCode * pyEvalCode,PyString_FromString * strFromString,PyEval_GetBuiltins * getBuiltins,PyErr_Print pyErrPrint)637 bool LoadAndEvaluateCode(
638 wchar_t* filePath, const char* fileName, bool isDebug, PyObject* globalsDict,
639 Py_CompileString* pyCompileString, PyDict_SetItemString* dictSetItem,
640 PyEval_EvalCode* pyEvalCode, PyString_FromString* strFromString, PyEval_GetBuiltins* getBuiltins,
641 PyErr_Print pyErrPrint
642 ) {
643 auto debuggerCode = ReadCodeFromFile(filePath);
644 if (debuggerCode == nullptr) {
645 return false;
646 }
647
648 auto code = PyObjectHolder(isDebug, pyCompileString(debuggerCode, fileName, 257 /*Py_file_input*/));
649 delete[] debuggerCode;
650
651 if (*code == nullptr) {
652 return false;
653 }
654
655 dictSetItem(globalsDict, "__builtins__", getBuiltins());
656 auto size = WideCharToMultiByte(CP_UTF8, 0, filePath, (DWORD)wcslen(filePath), NULL, 0, NULL, NULL);
657 char* filenameBuffer = new char[size];
658 if (WideCharToMultiByte(CP_UTF8, 0, filePath, (DWORD)wcslen(filePath), filenameBuffer, size, NULL, NULL) != 0) {
659 filenameBuffer[size] = 0;
660 dictSetItem(globalsDict, "__file__", strFromString(filenameBuffer));
661 }
662
663 auto evalResult = PyObjectHolder(isDebug, pyEvalCode(code.ToPython(), globalsDict, globalsDict));
664 #if !NDEBUG
665 if (*evalResult == nullptr) {
666 pyErrPrint();
667 }
668 #endif
669
670 return true;
671 }
672
673 // Checks to see if the specified module is likely a Python interpreter.
IsPythonModule(HMODULE module,bool & isDebug)674 bool IsPythonModule(HMODULE module, bool &isDebug) {
675 wchar_t mod_name[MAX_PATH];
676 isDebug = false;
677 if (GetModuleBaseName(GetCurrentProcess(), module, mod_name, MAX_PATH)) {
678 if (_wcsnicmp(mod_name, L"python", 6) == 0) {
679 if (wcslen(mod_name) >= 10 && _wcsnicmp(mod_name + 8, L"_d", 2) == 0) {
680 isDebug = true;
681 }
682 return true;
683 }
684 }
685 return false;
686 }
687
688 extern "C"
689 {
690
691 /**
692 * The returned value signals the error that happened!
693 *
694 * Return codes:
695 * 0 = all OK.
696 * 1 = Py_IsInitialized not found
697 * 2 = Py_IsInitialized returned false
698 * 3 = Missing Python API
699 * 4 = Interpreter not initialized
700 * 5 = Python version unknown
701 * 6 = Connect timeout
702 **/
DoAttach(HMODULE module,bool isDebug,const char * command,bool showDebugInfo)703 int DoAttach(HMODULE module, bool isDebug, const char *command, bool showDebugInfo )
704 {
705 auto isInit = (Py_IsInitialized*)GetProcAddress(module, "Py_IsInitialized");
706
707 if (isInit == nullptr) {
708 if(showDebugInfo){
709 std::cout << "Py_IsInitialized not found. " << std::endl << std::flush;
710 }
711 return 1;
712 }
713 if (!isInit()) {
714 if(showDebugInfo){
715 std::cout << "Py_IsInitialized returned false. " << std::endl << std::flush;
716 }
717 return 2;
718 }
719
720 auto version = GetPythonVersion(module);
721
722 // found initialized Python runtime, gather and check the APIs we need for a successful attach...
723 auto addPendingCall = (Py_AddPendingCall*)GetProcAddress(module, "Py_AddPendingCall");
724 auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(module, "_PyThreadState_Current");
725 auto interpHead = (PyInterpreterState_Head*)GetProcAddress(module, "PyInterpreterState_Head");
726 auto gilEnsure = (PyGILState_Ensure*)GetProcAddress(module, "PyGILState_Ensure");
727 auto gilRelease = (PyGILState_Release*)GetProcAddress(module, "PyGILState_Release");
728 auto threadHead = (PyInterpreterState_ThreadHead*)GetProcAddress(module, "PyInterpreterState_ThreadHead");
729 auto initThreads = (PyEval_Lock*)GetProcAddress(module, "PyEval_InitThreads");
730 auto acquireLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_AcquireLock");
731 auto releaseLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_ReleaseLock");
732 auto threadsInited = (PyEval_ThreadsInitialized*)GetProcAddress(module, "PyEval_ThreadsInitialized");
733 auto threadNext = (PyThreadState_Next*)GetProcAddress(module, "PyThreadState_Next");
734 auto threadSwap = (PyThreadState_Swap*)GetProcAddress(module, "PyThreadState_Swap");
735 auto pyDictNew = (PyDict_New*)GetProcAddress(module, "PyDict_New");
736 auto pyModuleNew = (PyModule_New*)GetProcAddress(module, "PyModule_New");
737 auto pyModuleGetDict = (PyModule_GetDict*)GetProcAddress(module, "PyModule_GetDict");
738 auto pyCompileString = (Py_CompileString*)GetProcAddress(module, "Py_CompileString");
739 auto pyEvalCode = (PyEval_EvalCode*)GetProcAddress(module, "PyEval_EvalCode");
740 auto getDictItem = (PyDict_GetItemString*)GetProcAddress(module, "PyDict_GetItemString");
741 auto call = (PyObject_CallFunctionObjArgs*)GetProcAddress(module, "PyObject_CallFunctionObjArgs");
742 auto getBuiltins = (PyEval_GetBuiltins*)GetProcAddress(module, "PyEval_GetBuiltins");
743 auto dictSetItem = (PyDict_SetItemString*)GetProcAddress(module, "PyDict_SetItemString");
744 PyInt_FromLong* intFromLong;
745 PyString_FromString* strFromString;
746 PyInt_FromSize_t* intFromSizeT;
747 if (version >= PythonVersion_30) {
748 intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyLong_FromLong");
749 intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyLong_FromSize_t");
750 if (version >= PythonVersion_33) {
751 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicode_FromString");
752 } else {
753 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicodeUCS2_FromString");
754 }
755 } else {
756 intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyInt_FromLong");
757 strFromString = (PyString_FromString*)GetProcAddress(module, "PyString_FromString");
758 intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyInt_FromSize_t");
759 }
760 auto intervalCheck = (int*)GetProcAddress(module, "_Py_CheckInterval");
761 auto errOccurred = (PyErr_Occurred*)GetProcAddress(module, "PyErr_Occurred");
762 auto pyErrFetch = (PyErr_Fetch*)GetProcAddress(module, "PyErr_Fetch");
763 auto pyErrRestore = (PyErr_Restore*)GetProcAddress(module, "PyErr_Restore");
764 auto pyErrPrint = (PyErr_Print*)GetProcAddress(module, "PyErr_Print");
765 auto pyImportMod = (PyImport_ImportModule*) GetProcAddress(module, "PyImport_ImportModule");
766 auto pyGetAttr = (PyObject_GetAttrString*)GetProcAddress(module, "PyObject_GetAttrString");
767 auto pySetAttr = (PyObject_SetAttrString*)GetProcAddress(module, "PyObject_SetAttrString");
768 auto pyNone = (PyObject*)GetProcAddress(module, "_Py_NoneStruct");
769 auto getSwitchInterval = (_PyEval_GetSwitchInterval*)GetProcAddress(module, "_PyEval_GetSwitchInterval");
770 auto setSwitchInterval = (_PyEval_SetSwitchInterval*)GetProcAddress(module, "_PyEval_SetSwitchInterval");
771 auto boolFromLong = (PyBool_FromLong*)GetProcAddress(module, "PyBool_FromLong");
772 auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
773 auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
774 auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
775 auto pyGilStateEnsure = (PyGILState_EnsureFunc*)GetProcAddress(module, "PyGILState_Ensure");
776 auto pyGilStateRelease = (PyGILState_ReleaseFunc*)GetProcAddress(module, "PyGILState_Release");
777 auto PyCFrame_Type = (PyTypeObject*)GetProcAddress(module, "PyCFrame_Type");
778 auto pyRun_SimpleString = (PyRun_SimpleString*)GetProcAddress(module, "PyRun_SimpleString");
779
780 if (addPendingCall == nullptr || curPythonThread == nullptr || interpHead == nullptr || gilEnsure == nullptr || gilRelease == nullptr || threadHead == nullptr ||
781 initThreads == nullptr || releaseLock == nullptr || threadsInited == nullptr || threadNext == nullptr || threadSwap == nullptr ||
782 pyDictNew == nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
783 getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
784 errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
785 getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr || releaseLock == nullptr ||
786 pyGilStateEnsure == nullptr || pyGilStateRelease == nullptr || pyRun_SimpleString == nullptr) {
787 // we're missing some APIs, we cannot attach.
788 if(showDebugInfo){
789 std::cout << "Error, missing Python API!! " << std::endl << std::flush;
790 }
791 return 3;
792 }
793
794 auto head = interpHead();
795 if (head == nullptr) {
796 // this interpreter is loaded but not initialized.
797 if(showDebugInfo){
798 std::cout << "Interpreter not initialized! " << std::endl << std::flush;
799 }
800 return 4;
801 }
802
803 bool threadSafeAddPendingCall = false;
804
805 // check that we're a supported version
806 if (version == PythonVersion_Unknown) {
807 if(showDebugInfo){
808 std::cout << "Python version unknown! " << std::endl << std::flush;
809 }
810 return 5;
811 } else if (version >= PythonVersion_27 && version != PythonVersion_30) {
812 threadSafeAddPendingCall = true;
813 }
814
815
816
817
818
819
820 if (!threadsInited()) {
821 int saveIntervalCheck;
822 unsigned long saveLongIntervalCheck;
823 if (intervalCheck != nullptr) {
824 // not available on 3.2
825 saveIntervalCheck = *intervalCheck;
826 *intervalCheck = -1; // lower the interval check so pending calls are processed faster
827 } else if (getSwitchInterval != nullptr && setSwitchInterval != nullptr) {
828 saveLongIntervalCheck = getSwitchInterval();
829 setSwitchInterval(0);
830 }
831
832 //
833 // Multiple thread support has not been initialized in the interpreter. We need multi threading support
834 // to block any actively running threads and setup the debugger attach state.
835 //
836 // We need to initialize multiple threading support but we need to do so safely. One option is to call
837 // Py_AddPendingCall and have our callback then initialize multi threading. This is completely safe on 2.7
838 // and up. Unfortunately that doesn't work if we're not actively running code on the main thread (blocked on a lock
839 // 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
840 // interpreters.
841 //
842 // Another option is to make sure no code is running - if there is no active thread then we can safely call
843 // PyEval_InitThreads and we're in business. But to know this is safe we need to first suspend all the other
844 // threads in the process and then inspect if any code is running.
845 //
846 // Finally if code is running after we've suspended the threads then we can go ahead and do Py_AddPendingCall
847 // on down-level interpreters as long as we're sure no one else is making a call to Py_AddPendingCall at the same
848 // time.
849 //
850 // Therefore our strategy becomes: Make the Py_AddPendingCall on interpreters where it's thread safe. Then suspend
851 // all threads - if a threads IP is in Py_AddPendingCall resume and try again. Once we've got all of the threads
852 // stopped and not in Py_AddPendingCall (which calls no functions its self, you can see this and it's size in the
853 // debugger) then see if we have a current thread. If not go ahead and initialize multiple threading (it's now safe,
854 // no Python code is running). Otherwise add the pending call and repeat. If at any point during this process
855 // threading becomes initialized (due to our pending call or the Python code creating a new thread) then we're done
856 // and we just resume all of the presently suspended threads.
857
858 ThreadMap suspendedThreads;
859
860 g_initedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
861 HandleHolder holder(g_initedEvent);
862
863 bool addedPendingCall = false;
864 if (addPendingCall != nullptr && threadSafeAddPendingCall) {
865 // we're on a thread safe Python version, go ahead and pend our call to initialize threading.
866 addPendingCall(&AttachCallback, initThreads);
867 addedPendingCall = true;
868 }
869
870 #define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur))
871 const DWORD ticksPerSecond = 1000;
872
873 DWORD startTickCount = GetTickCount();
874 do {
875 SuspendThreads(suspendedThreads, addPendingCall, threadsInited);
876
877 if (!threadsInited()) {
878 if (*curPythonThread == nullptr) {
879 // no threads are currently running, it is safe to initialize multi threading.
880 PyGILState_STATE gilState;
881 if (version >= PythonVersion_34) {
882 // in 3.4 due to http://bugs.python.org/issue20891,
883 // we need to create our thread state manually
884 // before we can call PyGILState_Ensure() before we
885 // can call PyEval_InitThreads().
886
887 // Don't require this function unless we need it.
888 auto threadNew = (PyThreadState_NewFunc*)GetProcAddress(module, "PyThreadState_New");
889 if (threadNew != nullptr) {
890 threadNew(head);
891 }
892 }
893
894 if (version >= PythonVersion_32) {
895 // in 3.2 due to the new GIL and later we can't call Py_InitThreads
896 // without a thread being initialized.
897 // So we use PyGilState_Ensure here to first
898 // initialize the current thread, and then we use
899 // Py_InitThreads to bring up multi-threading.
900 // Some context here: http://bugs.python.org/issue11329
901 // http://pytools.codeplex.com/workitem/834
902 gilState = pyGilStateEnsure();
903 }
904 initThreads();
905
906 if (version >= PythonVersion_32) {
907 // we will release the GIL here
908 pyGilStateRelease(gilState);
909 } else {
910 releaseLock();
911 }
912 } else if (!addedPendingCall) {
913 // someone holds the GIL but no one is actively adding any pending calls. We can pend our call
914 // and initialize threads.
915 addPendingCall(&AttachCallback, initThreads);
916 addedPendingCall = true;
917 }
918 }
919 ResumeThreads(suspendedThreads);
920 } while (!threadsInited() &&
921 (TICKS_DIFF(startTickCount, GetTickCount())) < (ticksPerSecond * 20) &&
922 !addedPendingCall);
923
924 if (!threadsInited()) {
925 if (addedPendingCall) {
926 // we've added our call to initialize multi-threading, we can now wait
927 // until Python code actually starts running.
928 if(showDebugInfo){
929 std::cout << "Waiting for threads to be initialized! " << std::endl << std::flush;
930 }
931
932 ::WaitForSingleObject(g_initedEvent, INFINITE);
933 } else {
934 if(showDebugInfo){
935 std::cout << "Connect timeout! " << std::endl << std::flush;
936 }
937 return 6;
938 }
939 } else {
940 if(showDebugInfo){
941 std::cout << "Threads initialized! " << std::endl << std::flush;
942 }
943 }
944
945 if (intervalCheck != nullptr) {
946 *intervalCheck = saveIntervalCheck;
947 } else if (setSwitchInterval != nullptr) {
948 setSwitchInterval(saveLongIntervalCheck);
949 }
950 } else {
951 if(showDebugInfo){
952 std::cout << "Threads already initialized! " << std::endl << std::flush;
953 }
954 }
955
956 if (g_heap != nullptr) {
957 HeapDestroy(g_heap);
958 g_heap = nullptr;
959 }
960
961
962 GilHolder gilLock(gilEnsure, gilRelease); // acquire and hold the GIL until done...
963
964 pyRun_SimpleString(command);
965 return 0;
966
967 }
968
969
970
971
SetSysTraceFunc(HMODULE module,bool isDebug,bool showDebugInfo)972 int SetSysTraceFunc(HMODULE module, bool isDebug, bool showDebugInfo)
973 {
974
975 if(showDebugInfo){
976 std::cout << "SetSysTraceFunc started. " << std::endl << std::flush;
977 }
978 auto isInit = (Py_IsInitialized*)GetProcAddress(module, "Py_IsInitialized");
979
980 if (isInit == nullptr) {
981 if(showDebugInfo){
982 std::cout << "Py_IsInitialized not found. " << std::endl << std::flush;
983 }
984 return 1;
985 }
986 if (!isInit()) {
987 if(showDebugInfo){
988 std::cout << "Py_IsInitialized returned false. " << std::endl << std::flush;
989 }
990 return 2;
991 }
992
993 auto version = GetPythonVersion(module);
994
995 // found initialized Python runtime, gather and check the APIs we need for a successful attach...
996 auto addPendingCall = (Py_AddPendingCall*)GetProcAddress(module, "Py_AddPendingCall");
997 auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(module, "_PyThreadState_Current");
998 auto interpHead = (PyInterpreterState_Head*)GetProcAddress(module, "PyInterpreterState_Head");
999 auto gilEnsure = (PyGILState_Ensure*)GetProcAddress(module, "PyGILState_Ensure");
1000 auto gilRelease = (PyGILState_Release*)GetProcAddress(module, "PyGILState_Release");
1001 auto threadHead = (PyInterpreterState_ThreadHead*)GetProcAddress(module, "PyInterpreterState_ThreadHead");
1002 auto initThreads = (PyEval_Lock*)GetProcAddress(module, "PyEval_InitThreads");
1003 auto acquireLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_AcquireLock");
1004 auto releaseLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_ReleaseLock");
1005 auto threadsInited = (PyEval_ThreadsInitialized*)GetProcAddress(module, "PyEval_ThreadsInitialized");
1006 auto threadNext = (PyThreadState_Next*)GetProcAddress(module, "PyThreadState_Next");
1007 auto threadSwap = (PyThreadState_Swap*)GetProcAddress(module, "PyThreadState_Swap");
1008 auto pyDictNew = (PyDict_New*)GetProcAddress(module, "PyDict_New");
1009 auto pyModuleNew = (PyModule_New*)GetProcAddress(module, "PyModule_New");
1010 auto pyModuleGetDict = (PyModule_GetDict*)GetProcAddress(module, "PyModule_GetDict");
1011 auto pyCompileString = (Py_CompileString*)GetProcAddress(module, "Py_CompileString");
1012 auto pyEvalCode = (PyEval_EvalCode*)GetProcAddress(module, "PyEval_EvalCode");
1013 auto getDictItem = (PyDict_GetItemString*)GetProcAddress(module, "PyDict_GetItemString");
1014 auto call = (PyObject_CallFunctionObjArgs*)GetProcAddress(module, "PyObject_CallFunctionObjArgs");
1015 auto getBuiltins = (PyEval_GetBuiltins*)GetProcAddress(module, "PyEval_GetBuiltins");
1016 auto dictSetItem = (PyDict_SetItemString*)GetProcAddress(module, "PyDict_SetItemString");
1017 PyInt_FromLong* intFromLong;
1018 PyString_FromString* strFromString;
1019 PyInt_FromSize_t* intFromSizeT;
1020 if (version >= PythonVersion_30) {
1021 intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyLong_FromLong");
1022 intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyLong_FromSize_t");
1023 if (version >= PythonVersion_33) {
1024 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicode_FromString");
1025 } else {
1026 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicodeUCS2_FromString");
1027 }
1028 } else {
1029 intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyInt_FromLong");
1030 strFromString = (PyString_FromString*)GetProcAddress(module, "PyString_FromString");
1031 intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyInt_FromSize_t");
1032 }
1033 auto intervalCheck = (int*)GetProcAddress(module, "_Py_CheckInterval");
1034 auto errOccurred = (PyErr_Occurred*)GetProcAddress(module, "PyErr_Occurred");
1035 auto pyErrFetch = (PyErr_Fetch*)GetProcAddress(module, "PyErr_Fetch");
1036 auto pyErrRestore = (PyErr_Restore*)GetProcAddress(module, "PyErr_Restore");
1037 auto pyErrPrint = (PyErr_Print*)GetProcAddress(module, "PyErr_Print");
1038 auto pyImportMod = (PyImport_ImportModule*) GetProcAddress(module, "PyImport_ImportModule");
1039 auto pyGetAttr = (PyObject_GetAttrString*)GetProcAddress(module, "PyObject_GetAttrString");
1040 auto pySetAttr = (PyObject_SetAttrString*)GetProcAddress(module, "PyObject_SetAttrString");
1041 auto pyHasAttr = (PyObject_HasAttrString*)GetProcAddress(module, "PyObject_HasAttrString");
1042 auto pyNone = (PyObject*)GetProcAddress(module, "_Py_NoneStruct");
1043 auto getSwitchInterval = (_PyEval_GetSwitchInterval*)GetProcAddress(module, "_PyEval_GetSwitchInterval");
1044 auto setSwitchInterval = (_PyEval_SetSwitchInterval*)GetProcAddress(module, "_PyEval_SetSwitchInterval");
1045 auto boolFromLong = (PyBool_FromLong*)GetProcAddress(module, "PyBool_FromLong");
1046 auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
1047 auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
1048 auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
1049 auto pyGilStateEnsure = (PyGILState_EnsureFunc*)GetProcAddress(module, "PyGILState_Ensure");
1050 auto pyGilStateRelease = (PyGILState_ReleaseFunc*)GetProcAddress(module, "PyGILState_Release");
1051 auto PyCFrame_Type = (PyTypeObject*)GetProcAddress(module, "PyCFrame_Type");
1052 auto pyRun_SimpleString = (PyRun_SimpleString*)GetProcAddress(module, "PyRun_SimpleString");
1053
1054 if (addPendingCall == nullptr || curPythonThread == nullptr || interpHead == nullptr || gilEnsure == nullptr || gilRelease == nullptr || threadHead == nullptr ||
1055 initThreads == nullptr || releaseLock == nullptr || threadsInited == nullptr || threadNext == nullptr || threadSwap == nullptr ||
1056 pyDictNew == nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
1057 getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
1058 errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
1059 getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr || releaseLock == nullptr ||
1060 pyGilStateEnsure == nullptr || pyGilStateRelease == nullptr || pyRun_SimpleString == nullptr) {
1061 // we're missing some APIs, we cannot attach.
1062 if(showDebugInfo){
1063 std::cout << "Error, missing Python API!! " << std::endl << std::flush;
1064 }
1065 return 3;
1066 }
1067
1068 auto head = interpHead();
1069 if (head == nullptr) {
1070 // this interpreter is loaded but not initialized.
1071 if(showDebugInfo){
1072 std::cout << "Interpreter not initialized! " << std::endl << std::flush;
1073 }
1074 return 4;
1075 }
1076
1077 GilHolder gilLock(gilEnsure, gilRelease); // acquire and hold the GIL until done...
1078
1079 auto pyTrue = boolFromLong(1);
1080 auto pyFalse = boolFromLong(0);
1081
1082
1083 auto pydevdTracingMod = PyObjectHolder(isDebug, pyImportMod("pydevd_tracing"));
1084 if (*pydevdTracingMod == nullptr) {
1085 if(showDebugInfo){
1086 std::cout << "pydevd_tracing module null! " << std::endl << std::flush;
1087 }
1088 return 7;
1089 }
1090
1091 if(!pyHasAttr(pydevdTracingMod.ToPython(), "_original_settrace")){
1092 if(showDebugInfo){
1093 std::cout << "pydevd_tracing module has no _original_settrace! " << std::endl << std::flush;
1094 }
1095 return 8;
1096 }
1097
1098 auto settrace = PyObjectHolder(isDebug, pyGetAttr(pydevdTracingMod.ToPython(), "_original_settrace"));
1099 if (*settrace == nullptr) {
1100 if(showDebugInfo){
1101 std::cout << "pydevd_tracing._original_settrace null! " << std::endl << std::flush;
1102 }
1103 return 9;
1104 }
1105
1106 auto pydevdMod = PyObjectHolder(isDebug, pyImportMod("pydevd"));
1107 if (*pydevdMod == nullptr) {
1108 if(showDebugInfo){
1109 std::cout << "pydevd module null! " << std::endl << std::flush;
1110 }
1111 return 10;
1112 }
1113
1114 auto getGlobalDebugger = PyObjectHolder(isDebug, pyGetAttr(pydevdMod.ToPython(), "GetGlobalDebugger"));
1115 if (*getGlobalDebugger == nullptr) {
1116 if(showDebugInfo){
1117 std::cout << "pydevd.GetGlobalDebugger null! " << std::endl << std::flush;
1118 }
1119 return 11;
1120 }
1121
1122 auto globalDbg = PyObjectHolder(isDebug, call(getGlobalDebugger.ToPython(), NULL));
1123 if (*globalDbg == nullptr) {
1124 if(showDebugInfo){
1125 std::cout << "pydevd.GetGlobalDebugger() returned null! " << std::endl << std::flush;
1126 }
1127 return 12;
1128 }
1129
1130 if(!pyHasAttr(globalDbg.ToPython(), "trace_dispatch")){
1131 if(showDebugInfo){
1132 std::cout << "pydevd.GetGlobalDebugger() has no attribute trace_dispatch! " << std::endl << std::flush;
1133 }
1134 return 13;
1135 }
1136
1137 auto traceFunc = PyObjectHolder(isDebug, pyGetAttr(globalDbg.ToPython(), "trace_dispatch"));
1138 if (*traceFunc == nullptr) {
1139 if(showDebugInfo){
1140 std::cout << "pydevd.GetGlobalDebugger().trace_dispatch returned null! " << std::endl << std::flush;
1141 }
1142 return 14;
1143 }
1144
1145
1146
1147 // we need to walk the thread list each time after we've initialized a thread so that we are always
1148 // dealing w/ a valid thread list (threads can exit when we run code and therefore the current thread
1149 // could be corrupt). We also don't care about newly created threads as our start_new_thread wrapper
1150 // will handle those. So we collect the initial set of threads first here so that we don't keep iterating
1151 // if the program is spawning large numbers of threads.
1152 unordered_set<PyThreadState*> initialThreads;
1153 for (auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
1154 initialThreads.insert(curThread);
1155 }
1156
1157 int retVal = 0;
1158 unordered_set<PyThreadState*> seenThreads;
1159 {
1160 // find what index is holding onto the thread state...
1161 auto curPyThread = *curPythonThread;
1162 int threadStateIndex = -1;
1163 for (int i = 0; i < 100000; i++) {
1164 void* value = getThreadTls(i);
1165 if (value == curPyThread) {
1166 threadStateIndex = i;
1167 break;
1168 }
1169 }
1170
1171 bool foundThread;
1172 int processedThreads = 0;
1173 do {
1174 foundThread = false;
1175 for (auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
1176 if (initialThreads.find(curThread) == initialThreads.end() ||
1177 seenThreads.insert(curThread).second == false) {
1178 continue;
1179 }
1180 foundThread = true;
1181 processedThreads++;
1182
1183 long threadId = GetPythonThreadId(version, curThread);
1184 // skip this thread - it doesn't really have any Python code on it...
1185 if (threadId != GetCurrentThreadId()) {
1186 // create new debugger Thread object on our injected thread
1187 auto pyThreadId = PyObjectHolder(isDebug, intFromLong(threadId));
1188 PyFrameObject* frame;
1189 // update all of the frames so they have our trace func
1190 if (PyThreadState_25_27::IsFor(version)) {
1191 frame = ((PyThreadState_25_27*)curThread)->frame;
1192 } else if (PyThreadState_30_33::IsFor(version)) {
1193 frame = ((PyThreadState_30_33*)curThread)->frame;
1194 } else if (PyThreadState_34_36::IsFor(version)) {
1195 frame = ((PyThreadState_34_36*)curThread)->frame;
1196 }else{
1197 if(showDebugInfo){
1198 std::cout << "Python version not handled! " << version << std::endl << std::flush;
1199 }
1200 retVal = 15;
1201 break;
1202 }
1203
1204 // switch to our new thread so we can call sys.settrace on it...
1205 // all of the work here needs to be minimal - in particular we shouldn't
1206 // ever evaluate user defined code as we could end up switching to this
1207 // thread on the main thread and corrupting state.
1208 auto prevThreadState = getThreadTls(threadStateIndex);
1209 delThreadTls(threadStateIndex);
1210 setThreadTls(threadStateIndex, curThread);
1211 auto prevThread = threadSwap(curThread);
1212
1213 // save and restore the error in case something funky happens...
1214 auto errOccured = errOccurred();
1215 PyObject *type, *value, *traceback;
1216 if (errOccured) {
1217 pyErrFetch(&type, &value, &traceback);
1218 }
1219
1220 if(showDebugInfo){
1221 std::cout << "setting trace for thread: " << threadId << std::endl << std::flush;
1222 }
1223
1224 DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
1225
1226 if (errOccured) {
1227 pyErrRestore(type, value, traceback);
1228 }
1229
1230 // update all of the frames so they have our trace func
1231 auto curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, frame);
1232 while (curFrame != nullptr) {
1233 // Special case for CFrame objects
1234 // Stackless CFrame does not have a trace function
1235 // This will just prevent a crash on attach.
1236 if (((PyObject*)curFrame)->ob_type != PyCFrame_Type) {
1237 DecRef(curFrame->f_trace, isDebug);
1238 IncRef(*traceFunc);
1239 curFrame->f_trace = traceFunc.ToPython();
1240 }
1241 curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, curFrame->f_back);
1242 }
1243
1244 delThreadTls(threadStateIndex);
1245 setThreadTls(threadStateIndex, prevThread);
1246 threadSwap(prevThread);
1247 }
1248 break;
1249 }
1250 } while (foundThread);
1251 }
1252
1253
1254
1255 return retVal;
1256
1257 }
1258
1259
1260
1261 /**
1262 * Return codes:
1263 *
1264 * -2 = could not allocate memory
1265 * -3 = could not allocate memory to enumerate processes
1266 *
1267 * 0 = all OK.
1268 * 1 = Py_IsInitialized not found
1269 * 2 = Py_IsInitialized returned false
1270 * 3 = Missing Python API
1271 * 4 = Interpreter not initialized
1272 * 5 = Python version unknown
1273 * 6 = Connect timeout
1274 *
1275 * result[0] should have the same result from the return function
1276 * result[0] is also used to set the startup info (on whether to show debug info
1277 * and if the debugger tracing should be set).
1278 **/
AttachAndRunPythonCode(const char * command,int * result)1279 DECLDIR int AttachAndRunPythonCode(const char *command, int *result )
1280 {
1281
1282 int SHOW_DEBUG_INFO = 1;
1283 int CONNECT_DEBUGGER = 2;
1284
1285 bool showDebugInfo = (result[0] & SHOW_DEBUG_INFO) != 0;
1286
1287 if(showDebugInfo){
1288 std::cout << "AttachAndRunPythonCode started (showing debug info). " << std::endl << std::flush;
1289 }
1290
1291 bool connectDebuggerTracing = (result[0] & CONNECT_DEBUGGER) != 0;
1292 if(showDebugInfo){
1293 std::cout << "connectDebuggerTracing: " << connectDebuggerTracing << std::endl << std::flush;
1294 }
1295
1296 HANDLE hProcess = GetCurrentProcess();
1297 DWORD modSize = sizeof(HMODULE) * 1024;
1298 HMODULE* hMods = (HMODULE*)_malloca(modSize);
1299 if (hMods == nullptr) {
1300 result[0] = -2;
1301 return result[0];
1302 }
1303
1304 DWORD modsNeeded;
1305 while (!EnumProcessModules(hProcess, hMods, modSize, &modsNeeded)) {
1306 // try again w/ more space...
1307 _freea(hMods);
1308 hMods = (HMODULE*)_malloca(modsNeeded);
1309 if (hMods == nullptr) {
1310 result[0] = -3;
1311 return result[0];
1312 }
1313 modSize = modsNeeded;
1314 }
1315 int attached = -1;
1316 {
1317 bool pythonFound = false;
1318 for (size_t i = 0; i < modsNeeded / sizeof(HMODULE); i++) {
1319 bool isDebug;
1320 if (IsPythonModule(hMods[i], isDebug)) {
1321 pythonFound = true;
1322 int temp = DoAttach(hMods[i], isDebug, command, showDebugInfo);
1323 if (temp == 0) {
1324 // we've successfully attached the debugger
1325 attached = 0;
1326 if(connectDebuggerTracing){
1327 if(showDebugInfo){
1328 std::cout << "SetSysTraceFunc " << std::endl << std::flush;
1329 }
1330 attached = SetSysTraceFunc(hMods[i], isDebug, showDebugInfo);
1331 }
1332 break;
1333 }else{
1334 if(temp > attached){
1335 //I.e.: the higher the value the more significant it is.
1336 attached = temp;
1337 }
1338 }
1339 }
1340 }
1341 }
1342
1343 if(showDebugInfo){
1344 std::cout << "Result: " << attached << std::endl << std::flush;
1345 }
1346 result[0] = attached;
1347 return result[0];
1348 }
1349
1350
1351
1352
1353
1354 /**
1355 *
1356 *
1357 *
1358 *
1359 *
1360 **/
AttachDebuggerTracing(bool showDebugInfo)1361 DECLDIR int AttachDebuggerTracing(bool showDebugInfo)
1362 {
1363 HANDLE hProcess = GetCurrentProcess();
1364 DWORD modSize = sizeof(HMODULE) * 1024;
1365 HMODULE* hMods = (HMODULE*)_malloca(modSize);
1366 if (hMods == nullptr) {
1367 if(showDebugInfo){
1368 std::cout << "hmods not allocated! " << std::endl << std::flush;
1369 }
1370 return -2;
1371 }
1372
1373 DWORD modsNeeded;
1374 while (!EnumProcessModules(hProcess, hMods, modSize, &modsNeeded)) {
1375 // try again w/ more space...
1376 _freea(hMods);
1377 hMods = (HMODULE*)_malloca(modsNeeded);
1378 if (hMods == nullptr) {
1379 if(showDebugInfo){
1380 std::cout << "hmods not allocated (2)! " << std::endl << std::flush;
1381 }
1382 return -3;
1383 }
1384 modSize = modsNeeded;
1385 }
1386 int attached = -1;
1387 {
1388 bool pythonFound = false;
1389 for (size_t i = 0; i < modsNeeded / sizeof(HMODULE); i++) {
1390 bool isDebug;
1391 if (IsPythonModule(hMods[i], isDebug)) {
1392 pythonFound = true;
1393 if(showDebugInfo){
1394 std::cout << "setting sys trace! " << std::endl << std::flush;
1395 }
1396 int temp = SetSysTraceFunc(hMods[i], isDebug, showDebugInfo);
1397 if (temp == 0) {
1398 // we've successfully attached the debugger
1399 attached = 0;
1400 break;
1401 }else{
1402 if(temp > attached){
1403 //I.e.: the higher the value the more significant it is.
1404 attached = temp;
1405 }
1406 }
1407 }
1408 }
1409 }
1410
1411
1412 return attached;
1413 }
1414
1415 }