| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #include "Python.h"
 | 
					
						
							| 
									
										
										
										
											2023-08-23 18:39:00 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "opcode_ids.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 11:20:24 -07:00
										 |  |  | #include "pycore_bitutils.h"      // _Py_popcount32
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #include "pycore_call.h"
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | #include "pycore_ceval.h"         // _PY_EVAL_EVENTS_BITS
 | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  | #include "pycore_code.h"          // _PyCode_Clear_Executors()
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | #include "pycore_critical_section.h"
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #include "pycore_frame.h"
 | 
					
						
							|  |  |  | #include "pycore_interp.h"
 | 
					
						
							|  |  |  | #include "pycore_long.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-03 11:39:11 +02:00
										 |  |  | #include "pycore_modsupport.h"    // _PyModule_CreateInitialized()
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #include "pycore_namespace.h"
 | 
					
						
							|  |  |  | #include "pycore_object.h"
 | 
					
						
							| 
									
										
										
										
											2023-08-23 18:39:00 +01:00
										 |  |  | #include "pycore_opcode_metadata.h" // IS_VALID_OPCODE, _PyOpcode_Caches
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_UINTPTR_RELEASE
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #include "pycore_pyerrors.h"
 | 
					
						
							| 
									
										
										
										
											2023-07-02 18:37:37 +02:00
										 |  |  | #include "pycore_pystate.h"       // _PyInterpreterState_GET()
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Uncomment this to dump debugging output when assertions fail */ | 
					
						
							|  |  |  | // #define INSTRUMENT_DEBUG 1
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | #if defined(Py_DEBUG) && defined(Py_GIL_DISABLED)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ASSERT_WORLD_STOPPED_OR_LOCKED(obj)                         \
 | 
					
						
							|  |  |  |     if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) {   \ | 
					
						
							|  |  |  |         _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);             \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | #define ASSERT_WORLD_STOPPED() assert(_PyInterpreterState_GET()->stoptheworld.world_stopped);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define ASSERT_WORLD_STOPPED_OR_LOCKED(obj)
 | 
					
						
							|  |  |  | #define ASSERT_WORLD_STOPPED()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef Py_GIL_DISABLED
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LOCK_CODE(code)                                             \
 | 
					
						
							|  |  |  |     assert(!_PyInterpreterState_GET()->stoptheworld.world_stopped); \ | 
					
						
							|  |  |  |     Py_BEGIN_CRITICAL_SECTION(code) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define UNLOCK_CODE()   Py_END_CRITICAL_SECTION()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LOCK_CODE(code)
 | 
					
						
							|  |  |  | #define UNLOCK_CODE()
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 12:06:09 -04:00
										 |  |  | PyObject _PyInstrumentation_DISABLE = _PyObject_HEAD_INIT(&PyBaseObject_Type); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-30 12:06:09 -04:00
										 |  |  | PyObject _PyInstrumentation_MISSING = _PyObject_HEAD_INIT(&PyBaseObject_Type); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static const int8_t EVENT_FOR_OPCODE[256] = { | 
					
						
							|  |  |  |     [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN, | 
					
						
							|  |  |  |     [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, | 
					
						
							|  |  |  |     [CALL] = PY_MONITORING_EVENT_CALL, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, | 
					
						
							| 
									
										
										
										
											2023-09-13 10:25:45 -07:00
										 |  |  |     [CALL_KW] = PY_MONITORING_EVENT_CALL, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL_KW] = PY_MONITORING_EVENT_CALL, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, | 
					
						
							| 
									
										
										
										
											2023-05-16 10:29:00 -06:00
										 |  |  |     [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, | 
					
						
							|  |  |  |     [INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     [RESUME] = -1, | 
					
						
							|  |  |  |     [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, | 
					
						
							|  |  |  |     [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD, | 
					
						
							|  |  |  |     [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, | 
					
						
							|  |  |  |     [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, | 
					
						
							|  |  |  |     [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [FOR_ITER] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH, | 
					
						
							|  |  |  |     [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION, | 
					
						
							|  |  |  |     [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const uint8_t DE_INSTRUMENT[256] = { | 
					
						
							|  |  |  |     [INSTRUMENTED_RESUME] = RESUME, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_CONST] = RETURN_CONST, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL] = CALL, | 
					
						
							| 
									
										
										
										
											2023-09-13 10:25:45 -07:00
										 |  |  |     [INSTRUMENTED_CALL_KW] = CALL_KW, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX, | 
					
						
							|  |  |  |     [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE, | 
					
						
							|  |  |  |     [INSTRUMENTED_FOR_ITER] = FOR_ITER, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_FOR] = END_FOR, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_SEND] = END_SEND, | 
					
						
							| 
									
										
										
										
											2023-05-16 10:29:00 -06:00
										 |  |  |     [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const uint8_t INSTRUMENTED_OPCODES[256] = { | 
					
						
							|  |  |  |     [RETURN_CONST] = INSTRUMENTED_RETURN_CONST, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST, | 
					
						
							|  |  |  |     [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, | 
					
						
							|  |  |  |     [CALL] = INSTRUMENTED_CALL, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, | 
					
						
							| 
									
										
										
										
											2023-09-13 10:25:45 -07:00
										 |  |  |     [CALL_KW] = INSTRUMENTED_CALL_KW, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL_KW] = INSTRUMENTED_CALL_KW, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, | 
					
						
							|  |  |  |     [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, | 
					
						
							|  |  |  |     [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, | 
					
						
							|  |  |  |     [RESUME] = INSTRUMENTED_RESUME, | 
					
						
							|  |  |  |     [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME, | 
					
						
							|  |  |  |     [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD, | 
					
						
							|  |  |  |     [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, | 
					
						
							|  |  |  |     [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD, | 
					
						
							|  |  |  |     [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE, | 
					
						
							|  |  |  |     [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE, | 
					
						
							|  |  |  |     [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE, | 
					
						
							|  |  |  |     [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, | 
					
						
							|  |  |  |     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE, | 
					
						
							|  |  |  |     [END_FOR] = INSTRUMENTED_END_FOR, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR, | 
					
						
							|  |  |  |     [END_SEND] = INSTRUMENTED_END_SEND, | 
					
						
							|  |  |  |     [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND, | 
					
						
							| 
									
										
										
										
											2023-04-13 13:56:09 +01:00
										 |  |  |     [FOR_ITER] = INSTRUMENTED_FOR_ITER, | 
					
						
							|  |  |  |     [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER, | 
					
						
							| 
									
										
										
										
											2023-05-16 10:29:00 -06:00
										 |  |  |     [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, | 
					
						
							|  |  |  |     [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR, | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     [INSTRUMENTED_LINE] = INSTRUMENTED_LINE, | 
					
						
							|  |  |  |     [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  | opcode_has_event(int opcode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return ( | 
					
						
							| 
									
										
										
										
											2023-08-15 16:40:05 +01:00
										 |  |  |         opcode != INSTRUMENTED_LINE && | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |         INSTRUMENTED_OPCODES[opcode] > 0 | 
					
						
							|  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  | is_instrumented(int opcode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(opcode != 0); | 
					
						
							|  |  |  |     assert(opcode != RESERVED); | 
					
						
							|  |  |  |     return opcode >= MIN_INSTRUMENTED_OPCODE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 12:45:03 -05:00
										 |  |  | #ifndef NDEBUG
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | static inline bool | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | monitors_equals(_Py_LocalMonitors a, _Py_LocalMonitors b) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if (a.tools[i] != b.tools[i]) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-04-13 12:45:03 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | static inline _Py_LocalMonitors | 
					
						
							|  |  |  | monitors_sub(_Py_LocalMonitors a, _Py_LocalMonitors b) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors res; | 
					
						
							|  |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         res.tools[i] = a.tools[i] & ~b.tools[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-13 12:45:03 -05:00
										 |  |  | #ifndef NDEBUG
 | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | static inline _Py_LocalMonitors | 
					
						
							|  |  |  | monitors_and(_Py_LocalMonitors a, _Py_LocalMonitors b) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors res; | 
					
						
							|  |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         res.tools[i] = a.tools[i] & b.tools[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-04-13 12:45:03 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | /* The union of the *local* events in a and b.
 | 
					
						
							|  |  |  |  * Global events like RAISE are ignored. | 
					
						
							|  |  |  |  * Used for instrumentation, as only local | 
					
						
							|  |  |  |  * events get instrumented. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline _Py_LocalMonitors | 
					
						
							|  |  |  | local_union(_Py_GlobalMonitors a, _Py_LocalMonitors b) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors res; | 
					
						
							|  |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         res.tools[i] = a.tools[i] | b.tools[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | monitors_are_empty(_Py_LocalMonitors m) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if (m.tools[i]) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline bool | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | multiple_tools(_Py_LocalMonitors *m) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if (_Py_popcount32(m->tools[i]) > 1) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline _PyMonitoringEventSet | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | get_local_events(_Py_LocalMonitors *m, int tool_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _PyMonitoringEventSet result = 0; | 
					
						
							|  |  |  |     for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { | 
					
						
							|  |  |  |         if ((m->tools[e] >> tool_id) & 1) { | 
					
						
							|  |  |  |             result |= (1 << e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline _PyMonitoringEventSet | 
					
						
							|  |  |  | get_events(_Py_GlobalMonitors *m, int tool_id) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     _PyMonitoringEventSet result = 0; | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if ((m->tools[e] >> tool_id) & 1) { | 
					
						
							|  |  |  |             result |= (1 << e); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Line delta.
 | 
					
						
							|  |  |  |  * 8 bit value. | 
					
						
							|  |  |  |  * if line_delta == -128: | 
					
						
							|  |  |  |  *     line = None # represented as -1 | 
					
						
							|  |  |  |  * elif line_delta == -127: | 
					
						
							|  |  |  |  *     line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); | 
					
						
							|  |  |  |  * else: | 
					
						
							|  |  |  |  *     line = first_line  + (offset >> OFFSET_SHIFT) + line_delta; | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NO_LINE -128
 | 
					
						
							|  |  |  | #define COMPUTED_LINE -127
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define OFFSET_SHIFT 4
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int8_t | 
					
						
							|  |  |  | compute_line_delta(PyCodeObject *code, int offset, int line) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (line < 0) { | 
					
						
							|  |  |  |         return NO_LINE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT); | 
					
						
							|  |  |  |     if (delta <= INT8_MAX && delta > COMPUTED_LINE) { | 
					
						
							|  |  |  |         return delta; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return COMPUTED_LINE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | compute_line(PyCodeObject *code, int offset, int8_t line_delta) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (line_delta > COMPUTED_LINE) { | 
					
						
							|  |  |  |         return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (line_delta == NO_LINE) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(line_delta == COMPUTED_LINE); | 
					
						
							|  |  |  |     /* Look it up */ | 
					
						
							|  |  |  |     return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  | int | 
					
						
							|  |  |  | _PyInstruction_GetLength(PyCodeObject *code, int offset) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int opcode = _PyCode_CODE(code)[offset].op.code; | 
					
						
							|  |  |  |     assert(opcode != 0); | 
					
						
							|  |  |  |     assert(opcode != RESERVED); | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         opcode = code->_co_monitoring->lines[offset].original_opcode; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |         opcode = code->_co_monitoring->per_instruction_opcodes[offset]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int deinstrumented = DE_INSTRUMENT[opcode]; | 
					
						
							|  |  |  |     if (deinstrumented) { | 
					
						
							|  |  |  |         opcode = deinstrumented; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         opcode = _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(opcode != 0); | 
					
						
							|  |  |  |     assert(!is_instrumented(opcode)); | 
					
						
							| 
									
										
										
										
											2023-07-25 13:01:02 -07:00
										 |  |  |     if (opcode == ENTER_EXECUTOR) { | 
					
						
							|  |  |  |         int exec_index = _PyCode_CODE(code)[offset].op.arg; | 
					
						
							|  |  |  |         _PyExecutorObject *exec = code->co_executors->executors[exec_index]; | 
					
						
							| 
									
										
										
										
											2023-09-22 14:13:31 -07:00
										 |  |  |         opcode = _PyOpcode_Deopt[exec->vm_data.opcode]; | 
					
						
							| 
									
										
										
										
											2023-07-25 13:01:02 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(opcode != ENTER_EXECUTOR); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(opcode == _PyOpcode_Deopt[opcode]); | 
					
						
							|  |  |  |     return 1 + _PyOpcode_Caches[opcode]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef INSTRUMENT_DEBUG
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (tools == NULL) { | 
					
						
							|  |  |  |         fprintf(out, "tools = NULL"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(out, "tools = %d", tools[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (lines == NULL) { | 
					
						
							|  |  |  |         fprintf(out, ", lines = NULL"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (lines[i].original_opcode == 0) { | 
					
						
							|  |  |  |         fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (line_tools == NULL) { | 
					
						
							|  |  |  |         fprintf(out, ", line_tools = NULL"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(out, ", line_tools = %d", line_tools[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (data->per_instruction_opcodes == NULL) { | 
					
						
							|  |  |  |         fprintf(out, ", per-inst opcode = NULL"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (data->per_instruction_tools == NULL) { | 
					
						
							|  |  |  |         fprintf(out, ", per-inst tools = NULL"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  | dump_global_monitors(const char *prefix, _Py_GlobalMonitors monitors, FILE*out) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     fprintf(out, "%s monitors:\n", prefix); | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     for (int event = 0; event < _PY_MONITORING_UNGROUPED_EVENTS; event++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         fprintf(out, "    Event %d: Tools %x\n", event, monitors.tools[event]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  | static void | 
					
						
							|  |  |  | dump_local_monitors(const char *prefix, _Py_LocalMonitors monitors, FILE*out) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     fprintf(out, "%s monitors:\n", prefix); | 
					
						
							|  |  |  |     for (int event = 0; event < _PY_MONITORING_LOCAL_EVENTS; event++) { | 
					
						
							|  |  |  |         fprintf(out, "    Event %d: Tools %x\n", event, monitors.tools[event]); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* No error checking -- Don't use this for anything but experimental debugging */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | dump_instrumentation_data(PyCodeObject *code, int star, FILE*out) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _PyCoMonitoringData *data = code->_co_monitoring; | 
					
						
							|  |  |  |     fprintf(out, "\n"); | 
					
						
							|  |  |  |     PyObject_Print(code->co_name, out, Py_PRINT_RAW); | 
					
						
							|  |  |  |     fprintf(out, "\n"); | 
					
						
							|  |  |  |     if (data == NULL) { | 
					
						
							|  |  |  |         fprintf(out, "NULL\n"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     dump_global_monitors("Global", _PyInterpreterState_GET()->monitors, out); | 
					
						
							|  |  |  |     dump_local_monitors("Code", data->local_monitors, out); | 
					
						
							|  |  |  |     dump_local_monitors("Active", data->active_monitors, out); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     bool starred = false; | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |     for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |         int opcode = instr->op.code; | 
					
						
							|  |  |  |         if (i == star) { | 
					
						
							|  |  |  |             fprintf(out, "**  "); | 
					
						
							|  |  |  |             starred = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]); | 
					
						
							|  |  |  |         dump_instrumentation_data_tools(code, data->tools, i, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_lines(code, data->lines, i, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_line_tools(code, data->line_tools, i, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_per_instruction(code, data, i, out); | 
					
						
							|  |  |  |         fprintf(out, "\n"); | 
					
						
							|  |  |  |         ; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!starred && star >= 0) { | 
					
						
							|  |  |  |         fprintf(out, "Error offset not at valid instruction offset: %d\n", star); | 
					
						
							|  |  |  |         fprintf(out, "    "); | 
					
						
							|  |  |  |         dump_instrumentation_data_tools(code, data->tools, star, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_lines(code, data->lines, star, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_line_tools(code, data->line_tools, star, out); | 
					
						
							|  |  |  |         dump_instrumentation_data_per_instruction(code, data, star, out); | 
					
						
							|  |  |  |         fprintf(out, "\n"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define CHECK(test) do { \
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); \ | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (!(test)) { \ | 
					
						
							|  |  |  |         dump_instrumentation_data(code, i, stderr); \ | 
					
						
							|  |  |  |     } \ | 
					
						
							|  |  |  |     assert(test); \ | 
					
						
							|  |  |  | } while (0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  | static bool | 
					
						
							|  |  |  | valid_opcode(int opcode) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-14 10:51:50 +01:00
										 |  |  |     if (IS_VALID_OPCODE(opcode) && | 
					
						
							|  |  |  |         opcode != CACHE && | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         opcode != RESERVED && | 
					
						
							| 
									
										
										
										
											2023-08-14 10:51:50 +01:00
										 |  |  |         opcode < 255) | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |        return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | sanity_check_instrumentation(PyCodeObject *code) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyCoMonitoringData *data = code->_co_monitoring; | 
					
						
							|  |  |  |     if (data == NULL) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     _Py_GlobalMonitors global_monitors = _PyInterpreterState_GET()->monitors; | 
					
						
							|  |  |  |     _Py_LocalMonitors active_monitors; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (code->_co_monitoring) { | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |         _Py_LocalMonitors local_monitors = code->_co_monitoring->local_monitors; | 
					
						
							|  |  |  |         active_monitors = local_union(global_monitors, local_monitors); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         _Py_LocalMonitors empty = (_Py_LocalMonitors) { 0 }; | 
					
						
							|  |  |  |         active_monitors = local_union(global_monitors, empty); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     assert(monitors_equals( | 
					
						
							|  |  |  |         code->_co_monitoring->active_monitors, | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |         active_monitors)); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     for (int i = 0; i < code_len;) { | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |         int opcode = instr->op.code; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         int base_opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |         CHECK(valid_opcode(opcode)); | 
					
						
							|  |  |  |         CHECK(valid_opcode(base_opcode)); | 
					
						
							|  |  |  |         if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |             opcode = data->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |             if (!is_instrumented(opcode)) { | 
					
						
							|  |  |  |                 CHECK(_PyOpcode_Deopt[opcode] == opcode); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (data->per_instruction_tools) { | 
					
						
							|  |  |  |                 uint8_t tools = active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; | 
					
						
							|  |  |  |                 CHECK((tools & data->per_instruction_tools[i]) == data->per_instruction_tools[i]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |             CHECK(data->lines); | 
					
						
							|  |  |  |             CHECK(valid_opcode(data->lines[i].original_opcode)); | 
					
						
							|  |  |  |             opcode = data->lines[i].original_opcode; | 
					
						
							|  |  |  |             CHECK(opcode != END_FOR); | 
					
						
							|  |  |  |             CHECK(opcode != RESUME); | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |             CHECK(opcode != RESUME_CHECK); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             CHECK(opcode != INSTRUMENTED_RESUME); | 
					
						
							|  |  |  |             if (!is_instrumented(opcode)) { | 
					
						
							|  |  |  |                 CHECK(_PyOpcode_Deopt[opcode] == opcode); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             CHECK(opcode != INSTRUMENTED_LINE); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |         else if (data->lines) { | 
					
						
							|  |  |  |             /* If original_opcode is INSTRUMENTED_INSTRUCTION
 | 
					
						
							|  |  |  |              * *and* we are executing a INSTRUMENTED_LINE instruction | 
					
						
							|  |  |  |              * that has de-instrumented itself, then we will execute | 
					
						
							|  |  |  |              * an invalid INSTRUMENTED_INSTRUCTION */ | 
					
						
							|  |  |  |             CHECK(data->lines[i].original_opcode != INSTRUMENTED_INSTRUCTION); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |             CHECK(data->per_instruction_opcodes[i] != 0); | 
					
						
							|  |  |  |             opcode = data->per_instruction_opcodes[i]; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         if (is_instrumented(opcode)) { | 
					
						
							|  |  |  |             CHECK(DE_INSTRUMENT[opcode] == base_opcode); | 
					
						
							|  |  |  |             int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]]; | 
					
						
							|  |  |  |             if (event < 0) { | 
					
						
							|  |  |  |                 /* RESUME fixup */ | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |                 event = instr->op.arg ? 1: 0; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |             CHECK(active_monitors.tools[event] != 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (data->lines && base_opcode != END_FOR) { | 
					
						
							|  |  |  |             int line1 = compute_line(code, i, data->lines[i].line_delta); | 
					
						
							|  |  |  |             int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT)); | 
					
						
							|  |  |  |             CHECK(line1 == line2); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         CHECK(valid_opcode(opcode)); | 
					
						
							|  |  |  |         if (data->tools) { | 
					
						
							|  |  |  |             uint8_t local_tools = data->tools[i]; | 
					
						
							|  |  |  |             if (opcode_has_event(base_opcode)) { | 
					
						
							|  |  |  |                 int event = EVENT_FOR_OPCODE[base_opcode]; | 
					
						
							|  |  |  |                 if (event == -1) { | 
					
						
							|  |  |  |                     /* RESUME fixup */ | 
					
						
							|  |  |  |                     event = _PyCode_CODE(code)[i].op.arg; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 CHECK((active_monitors.tools[event] & local_tools) == local_tools); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 CHECK(local_tools == 0xff); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |         i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         assert(i <= code_len); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define CHECK(test) assert(test)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Get the underlying opcode, stripping instrumentation */ | 
					
						
							|  |  |  | int _Py_GetBaseOpcode(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int opcode = _PyCode_CODE(code)[i].op.code; | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         opcode = code->_co_monitoring->lines[i].original_opcode; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |         opcode = code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CHECK(opcode != INSTRUMENTED_INSTRUCTION); | 
					
						
							|  |  |  |     CHECK(opcode != INSTRUMENTED_LINE); | 
					
						
							|  |  |  |     int deinstrumented = DE_INSTRUMENT[opcode]; | 
					
						
							|  |  |  |     if (deinstrumented) { | 
					
						
							|  |  |  |         return deinstrumented; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | de_instrument(PyCodeObject *code, int i, int event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_INSTRUCTION); | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_LINE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |     uint8_t *opcode_ptr = &instr->op.code; | 
					
						
							|  |  |  |     int opcode = *opcode_ptr; | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |     assert(opcode != ENTER_EXECUTOR); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     int deinstrumented = DE_INSTRUMENT[opcode]; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (deinstrumented == 0) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented); | 
					
						
							|  |  |  |     *opcode_ptr = deinstrumented; | 
					
						
							|  |  |  |     if (_PyOpcode_Caches[deinstrumented]) { | 
					
						
							| 
									
										
										
										
											2024-04-04 08:03:27 -07:00
										 |  |  |         instr[1].counter = adaptive_counter_warmup(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | de_instrument_line(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     int opcode = instr->op.code; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (opcode != INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; | 
					
						
							|  |  |  |     int original_opcode = lines->original_opcode; | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     if (original_opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |         lines->original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     CHECK(original_opcode != 0); | 
					
						
							|  |  |  |     CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     instr->op.code = original_opcode; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (_PyOpcode_Caches[original_opcode]) { | 
					
						
							| 
									
										
										
										
											2024-04-04 08:03:27 -07:00
										 |  |  |         instr[1].counter = adaptive_counter_warmup(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     assert(instr->op.code != INSTRUMENTED_LINE); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | de_instrument_per_instruction(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |     uint8_t *opcode_ptr = &instr->op.code; | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     int opcode = *opcode_ptr; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         opcode_ptr = &code->_co_monitoring->lines[i].original_opcode; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opcode != INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int original_opcode = code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |     CHECK(original_opcode != 0); | 
					
						
							|  |  |  |     CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]); | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     *opcode_ptr = original_opcode; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (_PyOpcode_Caches[original_opcode]) { | 
					
						
							| 
									
										
										
										
											2024-04-04 08:03:27 -07:00
										 |  |  |         instr[1].counter = adaptive_counter_warmup(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     assert(*opcode_ptr != INSTRUMENTED_INSTRUCTION); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(instr->op.code != INSTRUMENTED_INSTRUCTION); | 
					
						
							|  |  |  |     /* Keep things clean for sanity check */ | 
					
						
							|  |  |  |     code->_co_monitoring->per_instruction_opcodes[i] = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | instrument(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |     uint8_t *opcode_ptr = &instr->op.code; | 
					
						
							|  |  |  |     int opcode =*opcode_ptr; | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; | 
					
						
							|  |  |  |         opcode_ptr = &lines->original_opcode; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |         opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							| 
									
										
										
										
											2023-09-18 07:30:08 -07:00
										 |  |  |         CHECK(opcode != INSTRUMENTED_INSTRUCTION && opcode != INSTRUMENTED_LINE); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         CHECK(opcode == _PyOpcode_Deopt[opcode]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CHECK(opcode != 0); | 
					
						
							|  |  |  |     if (!is_instrumented(opcode)) { | 
					
						
							|  |  |  |         int deopt = _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  |         int instrumented = INSTRUMENTED_OPCODES[deopt]; | 
					
						
							|  |  |  |         assert(instrumented); | 
					
						
							|  |  |  |         *opcode_ptr = instrumented; | 
					
						
							|  |  |  |         if (_PyOpcode_Caches[deopt]) { | 
					
						
							| 
									
										
										
										
											2024-04-04 08:03:27 -07:00
										 |  |  |             instr[1].counter = adaptive_counter_warmup(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | instrument_line(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code; | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     int opcode = *opcode_ptr; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; | 
					
						
							|  |  |  |     lines->original_opcode = _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  |     CHECK(lines->original_opcode > 0); | 
					
						
							|  |  |  |     *opcode_ptr = INSTRUMENTED_LINE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | instrument_per_instruction(PyCodeObject *code, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |     uint8_t *opcode_ptr = &instr->op.code; | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     int opcode = *opcode_ptr; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (opcode == INSTRUMENTED_LINE) { | 
					
						
							|  |  |  |         _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i]; | 
					
						
							|  |  |  |         opcode_ptr = &lines->original_opcode; | 
					
						
							|  |  |  |         opcode = *opcode_ptr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |         assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     CHECK(opcode != 0); | 
					
						
							|  |  |  |     if (is_instrumented(opcode)) { | 
					
						
							|  |  |  |         code->_co_monitoring->per_instruction_opcodes[i] = opcode; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         assert(opcode != 0); | 
					
						
							|  |  |  |         assert(_PyOpcode_Deopt[opcode] != 0); | 
					
						
							|  |  |  |         assert(_PyOpcode_Deopt[opcode] != RESUME); | 
					
						
							|  |  |  |         code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(code->_co_monitoring->per_instruction_opcodes[i] > 0); | 
					
						
							|  |  |  |     *opcode_ptr = INSTRUMENTED_INSTRUCTION; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | remove_tools(PyCodeObject * code, int offset, int event, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(event != PY_MONITORING_EVENT_LINE); | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_INSTRUCTION); | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |     assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |     assert(opcode_has_event(_Py_GetBaseOpcode(code, offset))); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyCoMonitoringData *monitoring = code->_co_monitoring; | 
					
						
							|  |  |  |     if (monitoring && monitoring->tools) { | 
					
						
							|  |  |  |         monitoring->tools[offset] &= ~tools; | 
					
						
							|  |  |  |         if (monitoring->tools[offset] == 0) { | 
					
						
							|  |  |  |             de_instrument(code, offset, event); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event]; | 
					
						
							|  |  |  |         assert(_Py_popcount32(single_tool) <= 1); | 
					
						
							|  |  |  |         if (((single_tool & tools) == single_tool)) { | 
					
						
							|  |  |  |             de_instrument(code, offset, event); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | tools_is_subset_for_event(PyCodeObject * code, int event, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-02 18:37:37 +02:00
										 |  |  |     int global_tools = _PyInterpreterState_GET()->monitors.tools[event]; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int local_tools = code->_co_monitoring->local_monitors.tools[event]; | 
					
						
							|  |  |  |     return tools == ((global_tools | local_tools) & tools); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | remove_line_tools(PyCodeObject * code, int offset, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(code->_co_monitoring); | 
					
						
							|  |  |  |     if (code->_co_monitoring->line_tools) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset]; | 
					
						
							|  |  |  |         *toolsptr &= ~tools; | 
					
						
							|  |  |  |         if (*toolsptr == 0 ) { | 
					
						
							|  |  |  |             de_instrument_line(code, offset); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE]; | 
					
						
							|  |  |  |         assert(_Py_popcount32(single_tool) <= 1); | 
					
						
							|  |  |  |         if (((single_tool & tools) == single_tool)) { | 
					
						
							|  |  |  |             de_instrument_line(code, offset); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | add_tools(PyCodeObject * code, int offset, int event, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(event != PY_MONITORING_EVENT_LINE); | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_INSTRUCTION); | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |     assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(code->_co_monitoring); | 
					
						
							|  |  |  |     if (code->_co_monitoring && | 
					
						
							|  |  |  |         code->_co_monitoring->tools | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         code->_co_monitoring->tools[offset] |= tools; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         assert(_Py_popcount32(tools) == 1); | 
					
						
							|  |  |  |         assert(tools_is_subset_for_event(code, event, tools)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     instrument(code, offset); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | add_line_tools(PyCodeObject * code, int offset, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools)); | 
					
						
							|  |  |  |     assert(code->_co_monitoring); | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     if (code->_co_monitoring->line_tools) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         code->_co_monitoring->line_tools[offset] |= tools; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         assert(_Py_popcount32(tools) == 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     instrument_line(code, offset); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | add_per_instruction_tools(PyCodeObject * code, int offset, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools)); | 
					
						
							|  |  |  |     assert(code->_co_monitoring); | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     if (code->_co_monitoring->per_instruction_tools) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         code->_co_monitoring->per_instruction_tools[offset] |= tools; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         assert(_Py_popcount32(tools) == 1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     instrument_per_instruction(code, offset); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | remove_per_instruction_tools(PyCodeObject * code, int offset, int tools) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(code->_co_monitoring); | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     if (code->_co_monitoring->per_instruction_tools) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset]; | 
					
						
							|  |  |  |         *toolsptr &= ~tools; | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |         if (*toolsptr == 0) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             de_instrument_per_instruction(code, offset); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         /* Single tool */ | 
					
						
							|  |  |  |         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]; | 
					
						
							|  |  |  |         assert(_Py_popcount32(single_tool) <= 1); | 
					
						
							|  |  |  |         if (((single_tool & tools) == single_tool)) { | 
					
						
							|  |  |  |             de_instrument_per_instruction(code, offset); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Return 1 if DISABLE returned, -1 if error, 0 otherwise */ | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | call_one_instrument( | 
					
						
							|  |  |  |     PyInterpreterState *interp, PyThreadState *tstate, PyObject **args, | 
					
						
							|  |  |  |     Py_ssize_t nargsf, int8_t tool, int event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool && tool < 8); | 
					
						
							|  |  |  |     assert(tstate->tracing == 0); | 
					
						
							|  |  |  |     PyObject *instrument = interp->monitoring_callables[tool][event]; | 
					
						
							|  |  |  |     if (instrument == NULL) { | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |         return 0; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     int old_what = tstate->what_event; | 
					
						
							|  |  |  |     tstate->what_event = event; | 
					
						
							|  |  |  |     tstate->tracing++; | 
					
						
							|  |  |  |     PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL); | 
					
						
							|  |  |  |     tstate->tracing--; | 
					
						
							|  |  |  |     tstate->what_event = old_what; | 
					
						
							|  |  |  |     if (res == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(res); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     return (res == &_PyInstrumentation_DISABLE); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const int8_t MOST_SIGNIFICANT_BITS[16] = { | 
					
						
							|  |  |  |     -1, 0, 1, 1, | 
					
						
							|  |  |  |     2, 2, 2, 2, | 
					
						
							|  |  |  |     3, 3, 3, 3, | 
					
						
							|  |  |  |     3, 3, 3, 3, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  | /* We could use _Py_bit_length here, but that is designed for larger (32/64)
 | 
					
						
							|  |  |  |  * bit ints, and can perform relatively poorly on platforms without the | 
					
						
							|  |  |  |  * necessary intrinsics. */ | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | static inline int most_significant_bit(uint8_t bits) { | 
					
						
							|  |  |  |     assert(bits != 0); | 
					
						
							|  |  |  |     if (bits > 15) { | 
					
						
							|  |  |  |         return MOST_SIGNIFICANT_BITS[bits>>4]+4; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     return MOST_SIGNIFICANT_BITS[bits]; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | static uint32_t | 
					
						
							|  |  |  | global_version(PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-03-04 08:29:39 -08:00
										 |  |  |     uint32_t version = (uint32_t)_Py_atomic_load_uintptr_relaxed( | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |         &interp->ceval.instrumentation_version); | 
					
						
							| 
									
										
										
										
											2024-03-04 08:29:39 -08:00
										 |  |  | #ifdef Py_DEBUG
 | 
					
						
							|  |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							|  |  |  |     uint32_t thread_version = | 
					
						
							|  |  |  |         (uint32_t)(_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & | 
					
						
							|  |  |  |                    ~_PY_EVAL_EVENTS_MASK); | 
					
						
							|  |  |  |     assert(thread_version == version); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     return version; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  | /* Atomically set the given version in the given location, without touching
 | 
					
						
							|  |  |  |    anything in _PY_EVAL_EVENTS_MASK. */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  | set_version_raw(uintptr_t *ptr, uint32_t version) | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     uintptr_t old = _Py_atomic_load_uintptr_relaxed(ptr); | 
					
						
							|  |  |  |     uintptr_t new; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     do { | 
					
						
							|  |  |  |         new = (old & _PY_EVAL_EVENTS_MASK) | version; | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     } while (!_Py_atomic_compare_exchange_uintptr(ptr, &old, new)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | set_global_version(PyThreadState *tstate, uint32_t version) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert((version & _PY_EVAL_EVENTS_MASK) == 0); | 
					
						
							|  |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							|  |  |  |     set_version_raw(&interp->ceval.instrumentation_version, version); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef Py_GIL_DISABLED
 | 
					
						
							|  |  |  |     // Set the version on all threads in free-threaded builds.
 | 
					
						
							|  |  |  |     _PyRuntimeState *runtime = &_PyRuntime; | 
					
						
							|  |  |  |     HEAD_LOCK(runtime); | 
					
						
							|  |  |  |     for (tstate = interp->threads.head; tstate; | 
					
						
							|  |  |  |          tstate = PyThreadState_Next(tstate)) { | 
					
						
							|  |  |  |         set_version_raw(&tstate->eval_breaker, version); | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     HEAD_UNLOCK(runtime); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     // Normal builds take the current version from instrumentation_version when
 | 
					
						
							|  |  |  |     // attaching a thread, so we only have to set the current thread's version.
 | 
					
						
							|  |  |  |     set_version_raw(&tstate->eval_breaker, version); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | static bool | 
					
						
							|  |  |  | is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     return global_version(interp) == code->_co_instrumentation_version; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifndef NDEBUG
 | 
					
						
							|  |  |  | static bool | 
					
						
							|  |  |  | instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors expected = local_union( | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         interp->monitors, | 
					
						
							|  |  |  |         code->_co_monitoring->local_monitors); | 
					
						
							|  |  |  |     return monitors_equals(code->_co_monitoring->active_monitors, expected); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline uint8_t | 
					
						
							| 
									
										
										
										
											2023-06-23 13:18:29 +01:00
										 |  |  | get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i, int event) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     uint8_t tools; | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_LINE); | 
					
						
							|  |  |  |     assert(event != PY_MONITORING_EVENT_INSTRUCTION); | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     if (event >= _PY_MONITORING_UNGROUPED_EVENTS) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         assert(event == PY_MONITORING_EVENT_C_RAISE || | 
					
						
							|  |  |  |                 event == PY_MONITORING_EVENT_C_RETURN); | 
					
						
							|  |  |  |         event = PY_MONITORING_EVENT_CALL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |     if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) { | 
					
						
							| 
									
										
										
										
											2023-06-23 13:18:29 +01:00
										 |  |  |         CHECK(is_version_up_to_date(code, interp)); | 
					
						
							|  |  |  |         CHECK(instrumentation_cross_checks(interp, code)); | 
					
						
							|  |  |  |         if (code->_co_monitoring->tools) { | 
					
						
							|  |  |  |             tools = code->_co_monitoring->tools[i]; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             tools = code->_co_monitoring->active_monitors.tools[event]; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |         tools = interp->monitors.tools[event]; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     return tools; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  | static const char *const event_names [] = { | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_START] = "PY_START", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_RESUME] = "PY_RESUME", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_RETURN] = "PY_RETURN", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_YIELD] = "PY_YIELD", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_CALL] = "CALL", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_LINE] = "LINE", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_JUMP] = "JUMP", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_BRANCH] = "BRANCH", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_RAISE] = "RAISE", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_RERAISE] = "RERAISE", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_EXCEPTION_HANDLED] = "EXCEPTION_HANDLED", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_C_RAISE] = "C_RAISE", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_PY_UNWIND] = "PY_UNWIND", | 
					
						
							|  |  |  |     [PY_MONITORING_EVENT_STOP_ITERATION] = "STOP_ITERATION", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | call_instrumentation_vector( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (tstate->tracing) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(!_PyErr_Occurred(tstate)); | 
					
						
							|  |  |  |     assert(args[0] == NULL); | 
					
						
							| 
									
										
										
										
											2023-06-14 13:46:37 +01:00
										 |  |  |     PyCodeObject *code = _PyFrame_GetCode(frame); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(args[1] == NULL); | 
					
						
							|  |  |  |     args[1] = (PyObject *)code; | 
					
						
							|  |  |  |     int offset = (int)(instr - _PyCode_CODE(code)); | 
					
						
							|  |  |  |     /* Offset visible to user should be the offset in bytes, as that is the
 | 
					
						
							|  |  |  |      * convention for APIs involving code offsets. */ | 
					
						
							|  |  |  |     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |     PyObject *offset_obj = PyLong_FromLong(bytes_offset); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (offset_obj == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(args[2] == NULL); | 
					
						
							|  |  |  |     args[2] = offset_obj; | 
					
						
							| 
									
										
										
										
											2023-06-23 13:18:29 +01:00
										 |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							|  |  |  |     uint8_t tools = get_tools_for_instruction(code, interp, offset, event); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET; | 
					
						
							|  |  |  |     PyObject **callargs = &args[1]; | 
					
						
							|  |  |  |     int err = 0; | 
					
						
							|  |  |  |     while (tools) { | 
					
						
							|  |  |  |         int tool = most_significant_bit(tools); | 
					
						
							|  |  |  |         assert(tool >= 0 && tool < 8); | 
					
						
							|  |  |  |         assert(tools & (1 << tool)); | 
					
						
							|  |  |  |         tools ^= (1 << tool); | 
					
						
							|  |  |  |         int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event); | 
					
						
							|  |  |  |         if (res == 0) { | 
					
						
							|  |  |  |             /* Nothing to do */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (res < 0) { | 
					
						
							|  |  |  |             /* error */ | 
					
						
							|  |  |  |             err = -1; | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* DISABLE */ | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |             if (!PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) { | 
					
						
							|  |  |  |                 PyErr_Format(PyExc_ValueError, | 
					
						
							|  |  |  |                               "Cannot disable %s events. Callback removed.", | 
					
						
							|  |  |  |                              event_names[event]); | 
					
						
							|  |  |  |                 /* Clear tool to prevent infinite loop */ | 
					
						
							|  |  |  |                 Py_CLEAR(interp->monitoring_callables[tool][event]); | 
					
						
							|  |  |  |                 err = -1; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |                 LOCK_CODE(code); | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |                 remove_tools(code, offset, event, 1 << tool); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |                 UNLOCK_CODE(); | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(offset_obj); | 
					
						
							|  |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _Py_call_instrumentation( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *args[3] = { NULL, NULL, NULL }; | 
					
						
							|  |  |  |     return call_instrumentation_vector(tstate, event, frame, instr, 2, args); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _Py_call_instrumentation_arg( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *args[4] = { NULL, NULL, NULL, arg }; | 
					
						
							|  |  |  |     return call_instrumentation_vector(tstate, event, frame, instr, 3, args); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _Py_call_instrumentation_2args( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; | 
					
						
							|  |  |  |     return call_instrumentation_vector(tstate, event, frame, instr, 4, args); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  | _Py_CODEUNIT * | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | _Py_call_instrumentation_jump( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(event == PY_MONITORING_EVENT_JUMP || | 
					
						
							|  |  |  |            event == PY_MONITORING_EVENT_BRANCH); | 
					
						
							| 
									
										
										
										
											2023-10-26 14:43:10 +01:00
										 |  |  |     assert(frame->instr_ptr == instr); | 
					
						
							| 
									
										
										
										
											2023-06-14 13:46:37 +01:00
										 |  |  |     PyCodeObject *code = _PyFrame_GetCode(frame); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int to = (int)(target - _PyCode_CODE(code)); | 
					
						
							|  |  |  |     PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT)); | 
					
						
							|  |  |  |     if (to_obj == NULL) { | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |         return NULL; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     PyObject *args[4] = { NULL, NULL, NULL, to_obj }; | 
					
						
							|  |  |  |     int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args); | 
					
						
							|  |  |  |     Py_DECREF(to_obj); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     if (err) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-10-26 14:43:10 +01:00
										 |  |  |     if (frame->instr_ptr != instr) { | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |         /* The callback has caused a jump (by setting the line number) */ | 
					
						
							| 
									
										
										
										
											2023-10-26 14:43:10 +01:00
										 |  |  |         return frame->instr_ptr; | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     return target; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | call_instrumentation_vector_protected( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(_PyErr_Occurred(tstate)); | 
					
						
							|  |  |  |     PyObject *exc = _PyErr_GetRaisedException(tstate); | 
					
						
							|  |  |  |     int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args); | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |         Py_XDECREF(exc); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         _PyErr_SetRaisedException(tstate, exc); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(_PyErr_Occurred(tstate)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | _Py_call_instrumentation_exc2( | 
					
						
							|  |  |  |     PyThreadState *tstate, int event, | 
					
						
							|  |  |  |     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(_PyErr_Occurred(tstate)); | 
					
						
							|  |  |  |     PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 }; | 
					
						
							|  |  |  |     call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _Py_Instrumentation_GetLine(PyCodeObject *code, int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _PyCoMonitoringData *monitoring = code->_co_monitoring; | 
					
						
							|  |  |  |     assert(monitoring != NULL); | 
					
						
							|  |  |  |     assert(monitoring->lines != NULL); | 
					
						
							|  |  |  |     assert(index >= code->_co_firsttraceable); | 
					
						
							|  |  |  |     assert(index < Py_SIZE(code)); | 
					
						
							|  |  |  |     _PyCoLineInstrumentationData *line_data = &monitoring->lines[index]; | 
					
						
							|  |  |  |     int8_t line_delta = line_data->line_delta; | 
					
						
							|  |  |  |     int line = compute_line(code, index, line_delta); | 
					
						
							|  |  |  |     return line; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  | _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2023-06-14 13:46:37 +01:00
										 |  |  |     PyCodeObject *code = _PyFrame_GetCode(frame); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(is_version_up_to_date(code, tstate->interp)); | 
					
						
							|  |  |  |     assert(instrumentation_cross_checks(tstate->interp, code)); | 
					
						
							|  |  |  |     int i = (int)(instr - _PyCode_CODE(code)); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyCoMonitoringData *monitoring = code->_co_monitoring; | 
					
						
							|  |  |  |     _PyCoLineInstrumentationData *line_data = &monitoring->lines[i]; | 
					
						
							| 
									
										
										
										
											2024-02-29 22:46:33 -08:00
										 |  |  |     if (tstate->tracing) { | 
					
						
							|  |  |  |         goto done; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							|  |  |  |     int8_t line_delta = line_data->line_delta; | 
					
						
							|  |  |  |     int line = compute_line(code, i, line_delta); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     assert(line >= 0); | 
					
						
							| 
									
										
										
										
											2023-10-26 14:43:10 +01:00
										 |  |  |     assert(prev != NULL); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     int prev_index = (int)(prev - _PyCode_CODE(code)); | 
					
						
							|  |  |  |     int prev_line = _Py_Instrumentation_GetLine(code, prev_index); | 
					
						
							|  |  |  |     if (prev_line == line) { | 
					
						
							|  |  |  |         int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; | 
					
						
							|  |  |  |         /* RESUME and INSTRUMENTED_RESUME are needed for the operation of
 | 
					
						
							|  |  |  |          * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     uint8_t tools = code->_co_monitoring->line_tools != NULL ? | 
					
						
							|  |  |  |         code->_co_monitoring->line_tools[i] : | 
					
						
							|  |  |  |         (interp->monitors.tools[PY_MONITORING_EVENT_LINE] | | 
					
						
							|  |  |  |          code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE] | 
					
						
							|  |  |  |         ); | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |     /* Special case sys.settrace to avoid boxing the line number,
 | 
					
						
							|  |  |  |      * only to immediately unbox it. */ | 
					
						
							|  |  |  |     if (tools & (1 << PY_MONITORING_SYS_TRACE_ID)) { | 
					
						
							| 
									
										
										
										
											2024-04-09 01:54:28 -07:00
										 |  |  |         if (tstate->c_tracefunc != NULL) { | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |             PyFrameObject *frame_obj = _PyFrame_GetFrameObject(frame); | 
					
						
							|  |  |  |             if (frame_obj == NULL) { | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (frame_obj->f_trace_lines) { | 
					
						
							|  |  |  |                 /* Need to set tracing and what_event as if using
 | 
					
						
							|  |  |  |                  * the instrumentation call. */ | 
					
						
							|  |  |  |                 int old_what = tstate->what_event; | 
					
						
							|  |  |  |                 tstate->what_event = PY_MONITORING_EVENT_LINE; | 
					
						
							|  |  |  |                 tstate->tracing++; | 
					
						
							|  |  |  |                 /* Call c_tracefunc directly, having set the line number. */ | 
					
						
							|  |  |  |                 Py_INCREF(frame_obj); | 
					
						
							|  |  |  |                 frame_obj->f_lineno = line; | 
					
						
							|  |  |  |                 int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None); | 
					
						
							|  |  |  |                 frame_obj->f_lineno = 0; | 
					
						
							|  |  |  |                 tstate->tracing--; | 
					
						
							|  |  |  |                 tstate->what_event = old_what; | 
					
						
							|  |  |  |                 Py_DECREF(frame_obj); | 
					
						
							|  |  |  |                 if (err) { | 
					
						
							|  |  |  |                     return -1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         tools &= (255 - (1 << PY_MONITORING_SYS_TRACE_ID)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (tools == 0) { | 
					
						
							|  |  |  |         goto done; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *line_obj = PyLong_FromLong(line); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (line_obj == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *args[3] = { NULL, (PyObject *)code, line_obj }; | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |     do { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         int tool = most_significant_bit(tools); | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |         assert(tool >= 0 && tool < PY_MONITORING_SYS_PROFILE_ID); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         assert(tools & (1 << tool)); | 
					
						
							|  |  |  |         tools &= ~(1 << tool); | 
					
						
							|  |  |  |         int res = call_one_instrument(interp, tstate, &args[1], | 
					
						
							|  |  |  |                                       2 | PY_VECTORCALL_ARGUMENTS_OFFSET, | 
					
						
							|  |  |  |                                       tool, PY_MONITORING_EVENT_LINE); | 
					
						
							|  |  |  |         if (res == 0) { | 
					
						
							|  |  |  |             /* Nothing to do */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (res < 0) { | 
					
						
							|  |  |  |             /* error */ | 
					
						
							|  |  |  |             Py_DECREF(line_obj); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* DISABLE  */ | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |             LOCK_CODE(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             remove_line_tools(code, i, 1 << tool); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |             UNLOCK_CODE(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |     } while (tools); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     Py_DECREF(line_obj); | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     uint8_t original_opcode; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | done: | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  |     original_opcode = line_data->original_opcode; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(original_opcode != 0); | 
					
						
							| 
									
										
										
										
											2023-08-15 16:40:05 +01:00
										 |  |  |     assert(original_opcode != INSTRUMENTED_LINE); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(_PyOpcode_Deopt[original_opcode] == original_opcode); | 
					
						
							|  |  |  |     return original_opcode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-06-14 13:46:37 +01:00
										 |  |  |     PyCodeObject *code = _PyFrame_GetCode(frame); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(is_version_up_to_date(code, tstate->interp)); | 
					
						
							|  |  |  |     assert(instrumentation_cross_checks(tstate->interp, code)); | 
					
						
							|  |  |  |     int offset = (int)(instr - _PyCode_CODE(code)); | 
					
						
							|  |  |  |     _PyCoMonitoringData *instrumentation_data = code->_co_monitoring; | 
					
						
							|  |  |  |     assert(instrumentation_data->per_instruction_opcodes); | 
					
						
							|  |  |  |     int next_opcode = instrumentation_data->per_instruction_opcodes[offset]; | 
					
						
							|  |  |  |     if (tstate->tracing) { | 
					
						
							|  |  |  |         return next_opcode; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							|  |  |  |     uint8_t tools = instrumentation_data->per_instruction_tools != NULL ? | 
					
						
							|  |  |  |         instrumentation_data->per_instruction_tools[offset] : | 
					
						
							|  |  |  |         (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] | | 
					
						
							|  |  |  |          code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT); | 
					
						
							| 
									
										
										
										
											2023-08-10 13:35:02 +01:00
										 |  |  |     PyObject *offset_obj = PyLong_FromLong(bytes_offset); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (offset_obj == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *args[3] = { NULL, (PyObject *)code, offset_obj }; | 
					
						
							|  |  |  |     while (tools) { | 
					
						
							|  |  |  |         int tool = most_significant_bit(tools); | 
					
						
							|  |  |  |         assert(tool >= 0 && tool < 8); | 
					
						
							|  |  |  |         assert(tools & (1 << tool)); | 
					
						
							|  |  |  |         tools &= ~(1 << tool); | 
					
						
							|  |  |  |         int res = call_one_instrument(interp, tstate, &args[1], | 
					
						
							|  |  |  |                                       2 | PY_VECTORCALL_ARGUMENTS_OFFSET, | 
					
						
							|  |  |  |                                       tool, PY_MONITORING_EVENT_INSTRUCTION); | 
					
						
							|  |  |  |         if (res == 0) { | 
					
						
							|  |  |  |             /* Nothing to do */ | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (res < 0) { | 
					
						
							|  |  |  |             /* error */ | 
					
						
							|  |  |  |             Py_DECREF(offset_obj); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             /* DISABLE  */ | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |             LOCK_CODE(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             remove_per_instruction_tools(code, offset, 1 << tool); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |             UNLOCK_CODE(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_DECREF(offset_obj); | 
					
						
							|  |  |  |     assert(next_opcode != 0); | 
					
						
							|  |  |  |     return next_opcode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyObject * | 
					
						
							|  |  |  | _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *is = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     PyObject *callback = _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id], | 
					
						
							|  |  |  |                                                  Py_XNewRef(obj)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     return callback; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | initialize_tools(PyCodeObject *code) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     uint8_t* tools = code->_co_monitoring->tools; | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(tools != NULL); | 
					
						
							|  |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     for (int i = 0; i < code_len; i++) { | 
					
						
							|  |  |  |         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |         int opcode = instr->op.code; | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |         assert(opcode != ENTER_EXECUTOR); | 
					
						
							|  |  |  |         if (opcode == INSTRUMENTED_LINE) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             opcode = code->_co_monitoring->lines[i].original_opcode; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-18 07:30:08 -07:00
										 |  |  |         if (opcode == INSTRUMENTED_INSTRUCTION) { | 
					
						
							|  |  |  |             opcode = code->_co_monitoring->per_instruction_opcodes[i]; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         bool instrumented = is_instrumented(opcode); | 
					
						
							|  |  |  |         if (instrumented) { | 
					
						
							|  |  |  |             opcode = DE_INSTRUMENT[opcode]; | 
					
						
							|  |  |  |             assert(opcode != 0); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         opcode = _PyOpcode_Deopt[opcode]; | 
					
						
							|  |  |  |         if (opcode_has_event(opcode)) { | 
					
						
							|  |  |  |             if (instrumented) { | 
					
						
							|  |  |  |                 int8_t event; | 
					
						
							|  |  |  |                 if (opcode == RESUME) { | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |                     event = instr->op.arg != 0; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							|  |  |  |                     event = EVENT_FOR_OPCODE[opcode]; | 
					
						
							|  |  |  |                     assert(event > 0); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 assert(event >= 0); | 
					
						
							| 
									
										
										
										
											2023-07-27 15:27:11 +01:00
										 |  |  |                 assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event)); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |                 tools[i] = code->_co_monitoring->active_monitors.tools[event]; | 
					
						
							|  |  |  |                 CHECK(tools[i] != 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 tools[i] = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #ifdef Py_DEBUG
 | 
					
						
							|  |  |  |         /* Initialize tools for invalid locations to all ones to try to catch errors */ | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             tools[i] = 0xff; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) { | 
					
						
							|  |  |  |             tools[i+j] = 0xff; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |         i += _PyOpcode_Caches[opcode]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NO_LINE -128
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | initialize_lines(PyCodeObject *code) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(line_data != NULL); | 
					
						
							|  |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     PyCodeAddressRange range; | 
					
						
							|  |  |  |     _PyCode_InitAddressRange(code, &range); | 
					
						
							|  |  |  |     for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) { | 
					
						
							|  |  |  |         line_data[i].original_opcode = 0; | 
					
						
							|  |  |  |         line_data[i].line_delta = -127; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int current_line = -1; | 
					
						
							|  |  |  |     for (int i = code->_co_firsttraceable; i < code_len; ) { | 
					
						
							|  |  |  |         int opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |         int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range); | 
					
						
							|  |  |  |         line_data[i].line_delta = compute_line_delta(code, i, line); | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |         int length = _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         switch (opcode) { | 
					
						
							|  |  |  |             case END_ASYNC_FOR: | 
					
						
							|  |  |  |             case END_FOR: | 
					
						
							|  |  |  |             case END_SEND: | 
					
						
							|  |  |  |             case RESUME: | 
					
						
							|  |  |  |                 /* END_FOR cannot start a line, as it is skipped by FOR_ITER
 | 
					
						
							|  |  |  |                  * END_SEND cannot start a line, as it is skipped by SEND | 
					
						
							|  |  |  |                  * RESUME must not be instrumented with INSTRUMENT_LINE */ | 
					
						
							|  |  |  |                 line_data[i].original_opcode = 0; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |                 /* Set original_opcode to the opcode iff the instruction
 | 
					
						
							|  |  |  |                  * starts a line, and thus should be instrumented. | 
					
						
							|  |  |  |                  * This saves having to perform this check every time the | 
					
						
							|  |  |  |                  * we turn instrumentation on or off, and serves as a sanity | 
					
						
							|  |  |  |                  * check when debugging. | 
					
						
							|  |  |  |                  */ | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |                 if (line != current_line && line >= 0) { | 
					
						
							|  |  |  |                     line_data[i].original_opcode = opcode; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							|  |  |  |                     line_data[i].original_opcode = 0; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |                 current_line = line; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |         for (int j = 1; j < length; j++) { | 
					
						
							|  |  |  |             line_data[i+j].original_opcode = 0; | 
					
						
							|  |  |  |             line_data[i+j].line_delta = NO_LINE; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |         i += length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (int i = code->_co_firsttraceable; i < code_len; ) { | 
					
						
							|  |  |  |         int opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |         int oparg = 0; | 
					
						
							|  |  |  |         while (opcode == EXTENDED_ARG) { | 
					
						
							|  |  |  |             oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; | 
					
						
							|  |  |  |             i++; | 
					
						
							|  |  |  |             opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg; | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |         i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |         int target = -1; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         switch (opcode) { | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |             case POP_JUMP_IF_FALSE: | 
					
						
							|  |  |  |             case POP_JUMP_IF_TRUE: | 
					
						
							|  |  |  |             case POP_JUMP_IF_NONE: | 
					
						
							|  |  |  |             case POP_JUMP_IF_NOT_NONE: | 
					
						
							|  |  |  |             case JUMP_FORWARD: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 target = i + oparg; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             case FOR_ITER: | 
					
						
							|  |  |  |             case SEND: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 /* Skip over END_FOR/END_SEND */ | 
					
						
							|  |  |  |                 target = i + oparg + 1; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             case JUMP_BACKWARD: | 
					
						
							|  |  |  |             case JUMP_BACKWARD_NO_INTERRUPT: | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 target = i - oparg; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             default: | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         assert(target >= 0); | 
					
						
							|  |  |  |         if (line_data[target].line_delta != NO_LINE) { | 
					
						
							|  |  |  |             line_data[target].original_opcode = _Py_GetBaseOpcode(code, target); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     /* Scan exception table */ | 
					
						
							|  |  |  |     unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable); | 
					
						
							|  |  |  |     unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable); | 
					
						
							|  |  |  |     unsigned char *scan = start; | 
					
						
							|  |  |  |     while (scan < end) { | 
					
						
							|  |  |  |         int start_offset, size, handler; | 
					
						
							|  |  |  |         scan = parse_varint(scan, &start_offset); | 
					
						
							|  |  |  |         assert(start_offset >= 0 && start_offset < code_len); | 
					
						
							|  |  |  |         scan = parse_varint(scan, &size); | 
					
						
							|  |  |  |         assert(size >= 0 && start_offset+size <= code_len); | 
					
						
							|  |  |  |         scan = parse_varint(scan, &handler); | 
					
						
							|  |  |  |         assert(handler >= 0 && handler < code_len); | 
					
						
							|  |  |  |         int depth_and_lasti; | 
					
						
							|  |  |  |         scan = parse_varint(scan, &depth_and_lasti); | 
					
						
							|  |  |  |         int original_opcode = _Py_GetBaseOpcode(code, handler); | 
					
						
							|  |  |  |         /* Skip if not the start of a line.
 | 
					
						
							|  |  |  |          * END_ASYNC_FOR is a bit special as it marks the end of | 
					
						
							|  |  |  |          * an `async for` loop, which should not generate its own | 
					
						
							|  |  |  |          * line event. */ | 
					
						
							|  |  |  |         if (line_data[handler].line_delta != NO_LINE && | 
					
						
							|  |  |  |             original_opcode != END_ASYNC_FOR) { | 
					
						
							|  |  |  |             line_data[handler].original_opcode = original_opcode; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | initialize_line_tools(PyCodeObject *code, _Py_LocalMonitors *all_events) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     uint8_t *line_tools = code->_co_monitoring->line_tools; | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     assert(line_tools != NULL); | 
					
						
							|  |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     for (int i = 0; i < code_len; i++) { | 
					
						
							|  |  |  |         line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  | static int | 
					
						
							|  |  |  | allocate_instrumentation_data(PyCodeObject *code) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (code->_co_monitoring == NULL) { | 
					
						
							|  |  |  |         code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData)); | 
					
						
							|  |  |  |         if (code->_co_monitoring == NULL) { | 
					
						
							|  |  |  |             PyErr_NoMemory(); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |         code->_co_monitoring->local_monitors = (_Py_LocalMonitors){ 0 }; | 
					
						
							|  |  |  |         code->_co_monitoring->active_monitors = (_Py_LocalMonitors){ 0 }; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         code->_co_monitoring->tools = NULL; | 
					
						
							|  |  |  |         code->_co_monitoring->lines = NULL; | 
					
						
							|  |  |  |         code->_co_monitoring->line_tools = NULL; | 
					
						
							|  |  |  |         code->_co_monitoring->per_instruction_opcodes = NULL; | 
					
						
							|  |  |  |         code->_co_monitoring->per_instruction_tools = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							|  |  |  |     if (allocate_instrumentation_data(code)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors all_events = local_union( | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         interp->monitors, | 
					
						
							|  |  |  |         code->_co_monitoring->local_monitors); | 
					
						
							|  |  |  |     bool multitools = multiple_tools(&all_events); | 
					
						
							|  |  |  |     if (code->_co_monitoring->tools == NULL && multitools) { | 
					
						
							|  |  |  |         code->_co_monitoring->tools = PyMem_Malloc(code_len); | 
					
						
							|  |  |  |         if (code->_co_monitoring->tools == NULL) { | 
					
						
							|  |  |  |             PyErr_NoMemory(); | 
					
						
							|  |  |  |             return -1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         initialize_tools(code); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (all_events.tools[PY_MONITORING_EVENT_LINE]) { | 
					
						
							|  |  |  |         if (code->_co_monitoring->lines == NULL) { | 
					
						
							|  |  |  |             code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); | 
					
						
							|  |  |  |             if (code->_co_monitoring->lines == NULL) { | 
					
						
							|  |  |  |                 PyErr_NoMemory(); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             initialize_lines(code); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (multitools && code->_co_monitoring->line_tools == NULL) { | 
					
						
							|  |  |  |             code->_co_monitoring->line_tools = PyMem_Malloc(code_len); | 
					
						
							|  |  |  |             if (code->_co_monitoring->line_tools == NULL) { | 
					
						
							|  |  |  |                 PyErr_NoMemory(); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             initialize_line_tools(code, &all_events); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) { | 
					
						
							|  |  |  |         if (code->_co_monitoring->per_instruction_opcodes == NULL) { | 
					
						
							|  |  |  |             code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData)); | 
					
						
							|  |  |  |             if (code->_co_monitoring->per_instruction_opcodes == NULL) { | 
					
						
							|  |  |  |                 PyErr_NoMemory(); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ | 
					
						
							|  |  |  |             for (int i = 0; i < code_len; i++) { | 
					
						
							|  |  |  |                 code->_co_monitoring->per_instruction_opcodes[i] = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (multitools && code->_co_monitoring->per_instruction_tools == NULL) { | 
					
						
							|  |  |  |             code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len); | 
					
						
							|  |  |  |             if (code->_co_monitoring->per_instruction_tools == NULL) { | 
					
						
							|  |  |  |                 PyErr_NoMemory(); | 
					
						
							|  |  |  |                 return -1; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */ | 
					
						
							|  |  |  |             for (int i = 0; i < code_len; i++) { | 
					
						
							|  |  |  |                 code->_co_monitoring->per_instruction_tools[i] = 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | static int | 
					
						
							|  |  |  | instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED_OR_LOCKED(code); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (is_version_up_to_date(code, interp)) { | 
					
						
							|  |  |  |         assert( | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |             interp->ceval.instrumentation_version == 0 || | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             instrumentation_cross_checks(interp, code) | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |     if (code->co_executors != NULL) { | 
					
						
							|  |  |  |         _PyCode_Clear_Executors(code); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-26 12:51:47 -05:00
										 |  |  |     _Py_Executors_InvalidateDependency(interp, code, 1); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     int code_len = (int)Py_SIZE(code); | 
					
						
							| 
									
										
										
										
											2024-01-05 09:45:22 +00:00
										 |  |  |     /* Exit early to avoid creating instrumentation
 | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |      * data for potential statically allocated code | 
					
						
							|  |  |  |      * objects. | 
					
						
							|  |  |  |      * See https://github.com/python/cpython/issues/108390 */
 | 
					
						
							| 
									
										
										
										
											2024-01-05 09:45:22 +00:00
										 |  |  |     if (code->co_flags & CO_NO_MONITORING_EVENTS) { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (update_instrumentation_data(code, interp)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors active_events = local_union( | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         interp->monitors, | 
					
						
							|  |  |  |         code->_co_monitoring->local_monitors); | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors new_events; | 
					
						
							|  |  |  |     _Py_LocalMonitors removed_events; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bool restarted = interp->last_restart_version > code->_co_instrumentation_version; | 
					
						
							|  |  |  |     if (restarted) { | 
					
						
							|  |  |  |         removed_events = code->_co_monitoring->active_monitors; | 
					
						
							|  |  |  |         new_events = active_events; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else { | 
					
						
							|  |  |  |         removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events); | 
					
						
							|  |  |  |         new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors); | 
					
						
							|  |  |  |         assert(monitors_are_empty(monitors_and(new_events, removed_events))); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     code->_co_monitoring->active_monitors = active_events; | 
					
						
							|  |  |  |     if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         goto done; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     /* Insert instrumentation */ | 
					
						
							| 
									
										
										
										
											2023-06-22 09:48:19 +01:00
										 |  |  |     for (int i = code->_co_firsttraceable; i < code_len; i+= _PyInstruction_GetLength(code, i)) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i]; | 
					
						
							|  |  |  |         CHECK(instr->op.code != 0); | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |         assert(instr->op.code != ENTER_EXECUTOR); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         int base_opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							| 
									
										
										
										
											2023-09-07 09:53:54 +09:00
										 |  |  |         assert(base_opcode != ENTER_EXECUTOR); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if (opcode_has_event(base_opcode)) { | 
					
						
							|  |  |  |             int8_t event; | 
					
						
							|  |  |  |             if (base_opcode == RESUME) { | 
					
						
							|  |  |  |                 event = instr->op.arg > 0; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 event = EVENT_FOR_OPCODE[base_opcode]; | 
					
						
							|  |  |  |                 assert(event > 0); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             uint8_t removed_tools = removed_events.tools[event]; | 
					
						
							|  |  |  |             if (removed_tools) { | 
					
						
							|  |  |  |                 remove_tools(code, i, event, removed_tools); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             uint8_t new_tools = new_events.tools[event]; | 
					
						
							|  |  |  |             if (new_tools) { | 
					
						
							|  |  |  |                 add_tools(code, i, event, new_tools); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // GH-103845: We need to remove both the line and instruction instrumentation before
 | 
					
						
							|  |  |  |     // adding new ones, otherwise we may remove the newly added instrumentation.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE]; | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |     uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (removed_line_tools) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; | 
					
						
							|  |  |  |         for (int i = code->_co_firsttraceable; i < code_len;) { | 
					
						
							|  |  |  |             if (line_data[i].original_opcode) { | 
					
						
							|  |  |  |                 if (removed_line_tools) { | 
					
						
							|  |  |  |                     remove_line_tools(code, i, removed_line_tools); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |             i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |     if (removed_per_instruction_tools) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         for (int i = code->_co_firsttraceable; i < code_len;) { | 
					
						
							|  |  |  |             int opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |             if (opcode == RESUME || opcode == END_FOR) { | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |                 i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             if (removed_per_instruction_tools) { | 
					
						
							|  |  |  |                 remove_per_instruction_tools(code, i, removed_per_instruction_tools); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |             i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-11 14:37:09 +01:00
										 |  |  | #ifdef INSTRUMENT_DEBUG
 | 
					
						
							|  |  |  |     sanity_check_instrumentation(code); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |     uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE]; | 
					
						
							|  |  |  |     uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (new_line_tools) { | 
					
						
							|  |  |  |         _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines; | 
					
						
							|  |  |  |         for (int i = code->_co_firsttraceable; i < code_len;) { | 
					
						
							|  |  |  |             if (line_data[i].original_opcode) { | 
					
						
							|  |  |  |                 if (new_line_tools) { | 
					
						
							|  |  |  |                     add_line_tools(code, i, new_line_tools); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |             i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (new_per_instruction_tools) { | 
					
						
							|  |  |  |         for (int i = code->_co_firsttraceable; i < code_len;) { | 
					
						
							|  |  |  |             int opcode = _Py_GetBaseOpcode(code, i); | 
					
						
							|  |  |  |             if (opcode == RESUME || opcode == END_FOR) { | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |                 i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-05-03 02:51:47 -07:00
										 |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             if (new_per_instruction_tools) { | 
					
						
							|  |  |  |                 add_per_instruction_tools(code, i, new_per_instruction_tools); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2023-06-02 11:46:18 +01:00
										 |  |  |             i += _PyInstruction_GetLength(code, i); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | done: | 
					
						
							|  |  |  |     FT_ATOMIC_STORE_UINTPTR_RELEASE(code->_co_instrumentation_version, | 
					
						
							|  |  |  |                                     global_version(interp)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #ifdef INSTRUMENT_DEBUG
 | 
					
						
							|  |  |  |     sanity_check_instrumentation(code); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | int | 
					
						
							|  |  |  | _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     int res; | 
					
						
							|  |  |  |     LOCK_CODE(code); | 
					
						
							|  |  |  |     res = instrument_lock_held(code, interp); | 
					
						
							|  |  |  |     UNLOCK_CODE(); | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | #define C_RETURN_EVENTS \
 | 
					
						
							|  |  |  |     ((1 << PY_MONITORING_EVENT_C_RETURN) | \ | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |      (1 << PY_MONITORING_EVENT_C_RAISE)) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define C_CALL_EVENTS \
 | 
					
						
							|  |  |  |     (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | instrument_all_executing_code_objects(PyInterpreterState *interp) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     ASSERT_WORLD_STOPPED(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyRuntimeState *runtime = &_PyRuntime; | 
					
						
							|  |  |  |     HEAD_LOCK(runtime); | 
					
						
							|  |  |  |     PyThreadState* ts = PyInterpreterState_ThreadHead(interp); | 
					
						
							|  |  |  |     HEAD_UNLOCK(runtime); | 
					
						
							|  |  |  |     while (ts) { | 
					
						
							| 
									
										
										
										
											2023-08-17 11:16:03 +01:00
										 |  |  |         _PyInterpreterFrame *frame = ts->current_frame; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         while (frame) { | 
					
						
							|  |  |  |             if (frame->owner != FRAME_OWNED_BY_CSTACK) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |                 if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |                     return -1; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             frame = frame->previous; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         HEAD_LOCK(runtime); | 
					
						
							|  |  |  |         ts = PyThreadState_Next(ts); | 
					
						
							|  |  |  |         HEAD_UNLOCK(runtime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  | set_events(_Py_GlobalMonitors *m, int tool_id, _PyMonitoringEventSet events) | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |         uint8_t *tools = &m->tools[e]; | 
					
						
							|  |  |  |         int active = (events >> e) & 1; | 
					
						
							|  |  |  |         *tools &= ~(1 << tool_id); | 
					
						
							|  |  |  |         *tools |= (active << tool_id); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | set_local_events(_Py_LocalMonitors *m, int tool_id, _PyMonitoringEventSet events) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							|  |  |  |     for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         uint8_t *tools = &m->tools[e]; | 
					
						
							|  |  |  |         int val = (events >> e) & 1; | 
					
						
							|  |  |  |         *tools &= ~(1 << tool_id); | 
					
						
							|  |  |  |         *tools |= (val << tool_id); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | check_tool(PyInterpreterState *interp, int tool_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (tool_id < PY_MONITORING_SYS_PROFILE_ID && | 
					
						
							| 
									
										
										
										
											2023-04-29 05:51:55 +01:00
										 |  |  |         interp->monitoring_tool_names[tool_id] == NULL) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  | /* We share the eval-breaker with flags, so the monitoring
 | 
					
						
							|  |  |  |  * version goes in the top 24 bits */ | 
					
						
							|  |  |  | #define MONITORING_VERSION_INCREMENT (1 << _PY_EVAL_EVENTS_BITS)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | int | 
					
						
							|  |  |  | _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							|  |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     assert(events < (1 << _PY_MONITORING_UNGROUPED_EVENTS)); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (check_tool(interp, tool_id)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     int res; | 
					
						
							|  |  |  |     _PyEval_StopTheWorld(interp); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     uint32_t existing_events = get_events(&interp->monitors, tool_id); | 
					
						
							|  |  |  |     if (existing_events == events) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         res = 0; | 
					
						
							|  |  |  |         goto done; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							|  |  |  |     set_events(&interp->monitors, tool_id, events); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     uint32_t new_version = global_version(interp) + MONITORING_VERSION_INCREMENT; | 
					
						
							|  |  |  |     if (new_version == 0) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_OverflowError, "events set too many times"); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         res = -1; | 
					
						
							|  |  |  |         goto done; | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     set_global_version(tstate, new_version); | 
					
						
							| 
									
										
										
										
											2024-02-26 12:51:47 -05:00
										 |  |  |     _Py_Executors_InvalidateAll(interp, 1); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     res = instrument_all_executing_code_objects(interp); | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  |     _PyEval_StartTheWorld(interp); | 
					
						
							|  |  |  |     return res; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     assert(events < (1 << _PY_MONITORING_LOCAL_EVENTS)); | 
					
						
							|  |  |  |     if (code->_co_firsttraceable >= Py_SIZE(code)) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_SystemError, "cannot instrument shim code object '%U'", code->co_name); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (check_tool(interp, tool_id)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     int res; | 
					
						
							|  |  |  |     LOCK_CODE(code); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (allocate_instrumentation_data(code)) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         res = -1; | 
					
						
							|  |  |  |         goto done; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors; | 
					
						
							|  |  |  |     uint32_t existing_events = get_local_events(local, tool_id); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (existing_events == events) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         res = 0; | 
					
						
							|  |  |  |         goto done; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     set_local_events(local, tool_id, events); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (is_version_up_to_date(code, interp)) { | 
					
						
							|  |  |  |         /* Force instrumentation update */ | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         code->_co_instrumentation_version -= MONITORING_VERSION_INCREMENT; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-26 12:51:47 -05:00
										 |  |  |     _Py_Executors_InvalidateDependency(interp, code, 1); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     res = instrument_lock_held(code, interp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  |     UNLOCK_CODE(); | 
					
						
							|  |  |  |     return res; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-03 09:39:50 -07:00
										 |  |  | int | 
					
						
							|  |  |  | _PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); | 
					
						
							|  |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							|  |  |  |     if (check_tool(interp, tool_id)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (code->_co_monitoring == NULL) { | 
					
						
							|  |  |  |         *events = 0; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors; | 
					
						
							|  |  |  |     *events = get_local_events(local, tool_id); | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | module monitoring | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/ | 
					
						
							|  |  |  | /*[clinic end generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "clinic/instrumentation.c.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | check_valid_tool(int tool_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.use_tool_id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     name: object | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name) | 
					
						
							|  |  |  | /*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!PyUnicode_Check(name)) { | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, "tool name must be a str"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (interp->monitoring_tool_names[tool_id] != NULL) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     interp->monitoring_tool_names[tool_id] = Py_NewRef(name); | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.free_tool_id | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_free_tool_id_impl(PyObject *module, int tool_id) | 
					
						
							|  |  |  | /*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     Py_CLEAR(interp->monitoring_tool_names[tool_id]); | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.get_tool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_get_tool_impl(PyObject *module, int tool_id) | 
					
						
							|  |  |  | /*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic end generated code]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     PyObject *name = interp->monitoring_tool_names[tool_id]; | 
					
						
							|  |  |  |     if (name == NULL) { | 
					
						
							|  |  |  |         Py_RETURN_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return Py_NewRef(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.register_callback | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     event: int | 
					
						
							|  |  |  |     func: object | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_register_callback_impl(PyObject *module, int tool_id, int event, | 
					
						
							|  |  |  |                                   PyObject *func) | 
					
						
							|  |  |  | /*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (_Py_popcount32(event) != 1) { | 
					
						
							|  |  |  |         PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int event_id = _Py_bit_length(event)-1; | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     if (event_id < 0 || event_id >= _PY_MONITORING_EVENTS) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         PyErr_Format(PyExc_ValueError, "invalid event %d", event); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-08-10 12:29:06 +01:00
										 |  |  |     if (PySys_Audit("sys.monitoring.register_callback", "O", func) < 0) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (func == Py_None) { | 
					
						
							|  |  |  |         func = NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     func = _PyMonitoring_RegisterCallback(tool_id, event_id, func); | 
					
						
							|  |  |  |     if (func == NULL) { | 
					
						
							|  |  |  |         Py_RETURN_NONE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return func; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.get_events -> int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | monitoring_get_events_impl(PyObject *module, int tool_id) | 
					
						
							|  |  |  | /*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     _Py_GlobalMonitors *m = &_PyInterpreterState_GET()->monitors; | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     _PyMonitoringEventSet event_set = get_events(m, tool_id); | 
					
						
							|  |  |  |     return event_set; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.set_events | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     event_set: int | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_set_events_impl(PyObject *module, int tool_id, int event_set) | 
					
						
							|  |  |  | /*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     if (event_set < 0 || event_set >= (1 << _PY_MONITORING_EVENTS)) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     event_set &= ~C_RETURN_EVENTS; | 
					
						
							|  |  |  |     if (_PyMonitoring_SetEvents(tool_id, event_set)) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.get_local_events -> int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     code: object | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | monitoring_get_local_events_impl(PyObject *module, int tool_id, | 
					
						
							|  |  |  |                                  PyObject *code) | 
					
						
							|  |  |  | /*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!PyCode_Check(code)) { | 
					
						
							|  |  |  |         PyErr_Format( | 
					
						
							|  |  |  |             PyExc_TypeError, | 
					
						
							|  |  |  |             "code must be a code object" | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     _PyMonitoringEventSet event_set = 0; | 
					
						
							|  |  |  |     _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; | 
					
						
							|  |  |  |     if (data != NULL) { | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |         for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |             if ((data->local_monitors.tools[e] >> tool_id) & 1) { | 
					
						
							|  |  |  |                 event_set |= (1 << e); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return event_set; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.set_local_events | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     tool_id: int | 
					
						
							|  |  |  |     code: object | 
					
						
							|  |  |  |     event_set: int | 
					
						
							|  |  |  |     / | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_set_local_events_impl(PyObject *module, int tool_id, | 
					
						
							|  |  |  |                                  PyObject *code, int event_set) | 
					
						
							|  |  |  | /*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (!PyCode_Check(code)) { | 
					
						
							|  |  |  |         PyErr_Format( | 
					
						
							|  |  |  |             PyExc_TypeError, | 
					
						
							|  |  |  |             "code must be a code object" | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (check_valid_tool(tool_id))  { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     event_set &= ~C_RETURN_EVENTS; | 
					
						
							| 
									
										
										
										
											2023-09-05 08:03:53 +01:00
										 |  |  |     if (event_set < 0 || event_set >= (1 << _PY_MONITORING_LOCAL_EVENTS)) { | 
					
						
							|  |  |  |         PyErr_Format(PyExc_ValueError, "invalid local event set 0x%x", event_set); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring.restart_events | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring_restart_events_impl(PyObject *module) | 
					
						
							|  |  |  | /*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* We want to ensure that:
 | 
					
						
							|  |  |  |      * last restart version > instrumented version for all code objects | 
					
						
							|  |  |  |      * last restart version < current version | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     PyThreadState *tstate = _PyThreadState_GET(); | 
					
						
							|  |  |  |     PyInterpreterState *interp = tstate->interp; | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _PyEval_StopTheWorld(interp); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |     uint32_t restart_version = global_version(interp) + MONITORING_VERSION_INCREMENT; | 
					
						
							|  |  |  |     uint32_t new_version = restart_version + MONITORING_VERSION_INCREMENT; | 
					
						
							|  |  |  |     if (new_version <= MONITORING_VERSION_INCREMENT) { | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |         _PyEval_StartTheWorld(interp); | 
					
						
							| 
									
										
										
										
											2023-10-04 16:09:48 +01:00
										 |  |  |         PyErr_Format(PyExc_OverflowError, "events set too many times"); | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     interp->last_restart_version = restart_version; | 
					
						
							| 
									
										
										
										
											2024-02-20 06:57:48 -08:00
										 |  |  |     set_global_version(tstate, new_version); | 
					
						
							| 
									
										
										
										
											2024-04-19 14:47:42 -07:00
										 |  |  |     int res = instrument_all_executing_code_objects(interp); | 
					
						
							|  |  |  |     _PyEval_StartTheWorld(interp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (res) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Py_RETURN_NONE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | add_power2_constant(PyObject *obj, const char *name, int i) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *val = PyLong_FromLong(1<<i); | 
					
						
							|  |  |  |     if (val == NULL) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int err = PyObject_SetAttrString(obj, name, val); | 
					
						
							|  |  |  |     Py_DECREF(val); | 
					
						
							|  |  |  |     return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*[clinic input]
 | 
					
						
							|  |  |  | monitoring._all_events | 
					
						
							|  |  |  | [clinic start generated code]*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyObject * | 
					
						
							|  |  |  | monitoring__all_events_impl(PyObject *module) | 
					
						
							|  |  |  | /*[clinic end generated code: output=6b7581e2dbb690f6 input=62ee9672c17b7f0e]*/ | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2023-07-02 01:44:07 +02:00
										 |  |  |     PyInterpreterState *interp = _PyInterpreterState_GET(); | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |     PyObject *res = PyDict_New(); | 
					
						
							|  |  |  |     if (res == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         uint8_t tools = interp->monitors.tools[e]; | 
					
						
							|  |  |  |         if (tools == 0) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         PyObject *tools_obj = PyLong_FromLong(tools); | 
					
						
							|  |  |  |         assert(tools_obj != NULL); | 
					
						
							|  |  |  |         int err = PyDict_SetItemString(res, event_names[e], tools_obj); | 
					
						
							|  |  |  |         Py_DECREF(tools_obj); | 
					
						
							|  |  |  |         if (err < 0) { | 
					
						
							|  |  |  |             Py_DECREF(res); | 
					
						
							|  |  |  |             return NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static PyMethodDef methods[] = { | 
					
						
							|  |  |  |     MONITORING_USE_TOOL_ID_METHODDEF | 
					
						
							|  |  |  |     MONITORING_FREE_TOOL_ID_METHODDEF | 
					
						
							|  |  |  |     MONITORING_GET_TOOL_METHODDEF | 
					
						
							|  |  |  |     MONITORING_REGISTER_CALLBACK_METHODDEF | 
					
						
							|  |  |  |     MONITORING_GET_EVENTS_METHODDEF | 
					
						
							|  |  |  |     MONITORING_SET_EVENTS_METHODDEF | 
					
						
							|  |  |  |     MONITORING_GET_LOCAL_EVENTS_METHODDEF | 
					
						
							|  |  |  |     MONITORING_SET_LOCAL_EVENTS_METHODDEF | 
					
						
							|  |  |  |     MONITORING_RESTART_EVENTS_METHODDEF | 
					
						
							|  |  |  |     MONITORING__ALL_EVENTS_METHODDEF | 
					
						
							|  |  |  |     {NULL, NULL}  // sentinel
 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct PyModuleDef monitoring_module = { | 
					
						
							|  |  |  |     PyModuleDef_HEAD_INIT, | 
					
						
							|  |  |  |     .m_name = "sys.monitoring", | 
					
						
							|  |  |  |     .m_size = -1, /* multiple "initialization" just copies the module dict. */ | 
					
						
							|  |  |  |     .m_methods = methods, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PyObject *_Py_CreateMonitoringObject(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION); | 
					
						
							|  |  |  |     if (mod == NULL) { | 
					
						
							|  |  |  |         return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-05-12 12:21:20 +01:00
										 |  |  |     if (PyObject_SetAttrString(mod, "DISABLE", &_PyInstrumentation_DISABLE)) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     PyObject *events = _PyNamespace_New(NULL); | 
					
						
							|  |  |  |     if (events == NULL) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     int err = PyObject_SetAttrString(mod, "events", events); | 
					
						
							|  |  |  |     Py_DECREF(events); | 
					
						
							|  |  |  |     if (err) { | 
					
						
							|  |  |  |         goto error; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-07-22 23:35:27 +02:00
										 |  |  |     for (int i = 0; i < _PY_MONITORING_EVENTS; i++) { | 
					
						
							| 
									
										
										
										
											2023-04-12 12:04:55 +01:00
										 |  |  |         if (add_power2_constant(events, event_names[i], i)) { | 
					
						
							|  |  |  |             goto error; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero()); | 
					
						
							|  |  |  |     if (err) goto error; | 
					
						
							|  |  |  |     PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID); | 
					
						
							|  |  |  |     err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val); | 
					
						
							|  |  |  |     Py_DECREF(val); | 
					
						
							|  |  |  |     if (err) goto error; | 
					
						
							|  |  |  |     val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID); | 
					
						
							|  |  |  |     err = PyObject_SetAttrString(mod, "COVERAGE_ID", val); | 
					
						
							|  |  |  |     Py_DECREF(val); | 
					
						
							|  |  |  |     if (err) goto error; | 
					
						
							|  |  |  |     val = PyLong_FromLong(PY_MONITORING_PROFILER_ID); | 
					
						
							|  |  |  |     err = PyObject_SetAttrString(mod, "PROFILER_ID", val); | 
					
						
							|  |  |  |     Py_DECREF(val); | 
					
						
							|  |  |  |     if (err) goto error; | 
					
						
							|  |  |  |     val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID); | 
					
						
							|  |  |  |     err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val); | 
					
						
							|  |  |  |     Py_DECREF(val); | 
					
						
							|  |  |  |     if (err) goto error; | 
					
						
							|  |  |  |     return mod; | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  |     Py_DECREF(mod); | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } |