• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "Python.h"
2 
3 #include "opcode_ids.h"
4 
5 #include "pycore_bitutils.h"      // _Py_popcount32
6 #include "pycore_call.h"
7 #include "pycore_ceval.h"         // _PY_EVAL_EVENTS_BITS
8 #include "pycore_code.h"          // _PyCode_Clear_Executors()
9 #include "pycore_critical_section.h"
10 #include "pycore_frame.h"
11 #include "pycore_interp.h"
12 #include "pycore_long.h"
13 #include "pycore_modsupport.h"    // _PyModule_CreateInitialized()
14 #include "pycore_namespace.h"
15 #include "pycore_object.h"
16 #include "pycore_opcode_metadata.h" // IS_VALID_OPCODE, _PyOpcode_Caches
17 #include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_UINTPTR_RELEASE
18 #include "pycore_pyerrors.h"
19 #include "pycore_pystate.h"       // _PyInterpreterState_GET()
20 
21 /* Uncomment this to dump debugging output when assertions fail */
22 // #define INSTRUMENT_DEBUG 1
23 
24 #if defined(Py_DEBUG) && defined(Py_GIL_DISABLED)
25 
26 #define ASSERT_WORLD_STOPPED_OR_LOCKED(obj)                         \
27     if (!_PyInterpreterState_GET()->stoptheworld.world_stopped) {   \
28         _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(obj);             \
29     }
30 #define ASSERT_WORLD_STOPPED() assert(_PyInterpreterState_GET()->stoptheworld.world_stopped);
31 
32 #else
33 
34 #define ASSERT_WORLD_STOPPED_OR_LOCKED(obj)
35 #define ASSERT_WORLD_STOPPED()
36 
37 #endif
38 
39 #ifdef Py_GIL_DISABLED
40 
41 #define LOCK_CODE(code)                                             \
42     assert(!_PyInterpreterState_GET()->stoptheworld.world_stopped); \
43     Py_BEGIN_CRITICAL_SECTION(code)
44 
45 #define UNLOCK_CODE()   Py_END_CRITICAL_SECTION()
46 
47 #else
48 
49 #define LOCK_CODE(code)
50 #define UNLOCK_CODE()
51 
52 #endif
53 
54 PyObject _PyInstrumentation_DISABLE = _PyObject_HEAD_INIT(&PyBaseObject_Type);
55 
56 PyObject _PyInstrumentation_MISSING = _PyObject_HEAD_INIT(&PyBaseObject_Type);
57 
58 static const int8_t EVENT_FOR_OPCODE[256] = {
59     [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN,
60     [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN,
61     [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN,
62     [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN,
63     [CALL] = PY_MONITORING_EVENT_CALL,
64     [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL,
65     [CALL_KW] = PY_MONITORING_EVENT_CALL,
66     [INSTRUMENTED_CALL_KW] = PY_MONITORING_EVENT_CALL,
67     [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
68     [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
69     [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL,
70     [INSTRUMENTED_LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL,
71     [RESUME] = -1,
72     [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
73     [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
74     [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP,
75     [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP,
76     [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH,
77     [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH,
78     [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH,
79     [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH,
80     [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP,
81     [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP,
82     [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH,
83     [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH,
84     [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH,
85     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH,
86     [FOR_ITER] = PY_MONITORING_EVENT_BRANCH,
87     [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH,
88     [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION,
89     [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION,
90     [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION,
91     [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION,
92 };
93 
94 static const uint8_t DE_INSTRUMENT[256] = {
95     [INSTRUMENTED_RESUME] = RESUME,
96     [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE,
97     [INSTRUMENTED_RETURN_CONST] = RETURN_CONST,
98     [INSTRUMENTED_CALL] = CALL,
99     [INSTRUMENTED_CALL_KW] = CALL_KW,
100     [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX,
101     [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE,
102     [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD,
103     [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD,
104     [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE,
105     [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE,
106     [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE,
107     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE,
108     [INSTRUMENTED_FOR_ITER] = FOR_ITER,
109     [INSTRUMENTED_END_FOR] = END_FOR,
110     [INSTRUMENTED_END_SEND] = END_SEND,
111     [INSTRUMENTED_LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
112 };
113 
114 static const uint8_t INSTRUMENTED_OPCODES[256] = {
115     [RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
116     [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
117     [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
118     [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
119     [CALL] = INSTRUMENTED_CALL,
120     [INSTRUMENTED_CALL] = INSTRUMENTED_CALL,
121     [CALL_KW] = INSTRUMENTED_CALL_KW,
122     [INSTRUMENTED_CALL_KW] = INSTRUMENTED_CALL_KW,
123     [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
124     [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
125     [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
126     [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
127     [RESUME] = INSTRUMENTED_RESUME,
128     [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME,
129     [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
130     [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
131     [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
132     [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
133     [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
134     [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
135     [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
136     [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
137     [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
138     [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
139     [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
140     [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
141     [END_FOR] = INSTRUMENTED_END_FOR,
142     [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR,
143     [END_SEND] = INSTRUMENTED_END_SEND,
144     [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
145     [FOR_ITER] = INSTRUMENTED_FOR_ITER,
146     [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
147     [LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
148     [INSTRUMENTED_LOAD_SUPER_ATTR] = INSTRUMENTED_LOAD_SUPER_ATTR,
149 
150     [INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
151     [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
152 };
153 
154 static inline bool
opcode_has_event(int opcode)155 opcode_has_event(int opcode)
156 {
157     return (
158         opcode != INSTRUMENTED_LINE &&
159         INSTRUMENTED_OPCODES[opcode] > 0
160     );
161 }
162 
163 static inline bool
is_instrumented(int opcode)164 is_instrumented(int opcode)
165 {
166     assert(opcode != 0);
167     assert(opcode != RESERVED);
168     return opcode >= MIN_INSTRUMENTED_OPCODE;
169 }
170 
171 #ifndef NDEBUG
172 static inline bool
monitors_equals(_Py_LocalMonitors a,_Py_LocalMonitors b)173 monitors_equals(_Py_LocalMonitors a, _Py_LocalMonitors b)
174 {
175     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
176         if (a.tools[i] != b.tools[i]) {
177             return false;
178         }
179     }
180     return true;
181 }
182 #endif
183 
184 static inline _Py_LocalMonitors
monitors_sub(_Py_LocalMonitors a,_Py_LocalMonitors b)185 monitors_sub(_Py_LocalMonitors a, _Py_LocalMonitors b)
186 {
187     _Py_LocalMonitors res;
188     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
189         res.tools[i] = a.tools[i] & ~b.tools[i];
190     }
191     return res;
192 }
193 
194 #ifndef NDEBUG
195 static inline _Py_LocalMonitors
monitors_and(_Py_LocalMonitors a,_Py_LocalMonitors b)196 monitors_and(_Py_LocalMonitors a, _Py_LocalMonitors b)
197 {
198     _Py_LocalMonitors res;
199     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
200         res.tools[i] = a.tools[i] & b.tools[i];
201     }
202     return res;
203 }
204 #endif
205 
206 /* The union of the *local* events in a and b.
207  * Global events like RAISE are ignored.
208  * Used for instrumentation, as only local
209  * events get instrumented.
210  */
211 static inline _Py_LocalMonitors
local_union(_Py_GlobalMonitors a,_Py_LocalMonitors b)212 local_union(_Py_GlobalMonitors a, _Py_LocalMonitors b)
213 {
214     _Py_LocalMonitors res;
215     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
216         res.tools[i] = a.tools[i] | b.tools[i];
217     }
218     return res;
219 }
220 
221 static inline bool
monitors_are_empty(_Py_LocalMonitors m)222 monitors_are_empty(_Py_LocalMonitors m)
223 {
224     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
225         if (m.tools[i]) {
226             return false;
227         }
228     }
229     return true;
230 }
231 
232 static inline bool
multiple_tools(_Py_LocalMonitors * m)233 multiple_tools(_Py_LocalMonitors *m)
234 {
235     for (int i = 0; i < _PY_MONITORING_LOCAL_EVENTS; i++) {
236         if (_Py_popcount32(m->tools[i]) > 1) {
237             return true;
238         }
239     }
240     return false;
241 }
242 
243 static inline _PyMonitoringEventSet
get_local_events(_Py_LocalMonitors * m,int tool_id)244 get_local_events(_Py_LocalMonitors *m, int tool_id)
245 {
246     _PyMonitoringEventSet result = 0;
247     for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) {
248         if ((m->tools[e] >> tool_id) & 1) {
249             result |= (1 << e);
250         }
251     }
252     return result;
253 }
254 
255 static inline _PyMonitoringEventSet
get_events(_Py_GlobalMonitors * m,int tool_id)256 get_events(_Py_GlobalMonitors *m, int tool_id)
257 {
258     _PyMonitoringEventSet result = 0;
259     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) {
260         if ((m->tools[e] >> tool_id) & 1) {
261             result |= (1 << e);
262         }
263     }
264     return result;
265 }
266 
267 /* Line delta.
268  * 8 bit value.
269  * if line_delta == -128:
270  *     line = None # represented as -1
271  * elif line_delta == -127 or line_delta == -126:
272  *     line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
273  * else:
274  *     line = first_line  + (offset >> OFFSET_SHIFT) + line_delta;
275  */
276 
277 #define NO_LINE -128
278 #define COMPUTED_LINE_LINENO_CHANGE -127
279 #define COMPUTED_LINE -126
280 
281 #define OFFSET_SHIFT 4
282 
283 static int8_t
compute_line_delta(PyCodeObject * code,int offset,int line)284 compute_line_delta(PyCodeObject *code, int offset, int line)
285 {
286     if (line < 0) {
287         return NO_LINE;
288     }
289     int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT);
290     if (delta <= INT8_MAX && delta > COMPUTED_LINE) {
291         return delta;
292     }
293     return COMPUTED_LINE;
294 }
295 
296 static int
compute_line(PyCodeObject * code,int offset,int8_t line_delta)297 compute_line(PyCodeObject *code, int offset, int8_t line_delta)
298 {
299     if (line_delta > COMPUTED_LINE) {
300         return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta;
301     }
302     if (line_delta == NO_LINE) {
303 
304         return -1;
305     }
306     assert(line_delta == COMPUTED_LINE || line_delta == COMPUTED_LINE_LINENO_CHANGE);
307     /* Look it up */
308     return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
309 }
310 
311 int
_PyInstruction_GetLength(PyCodeObject * code,int offset)312 _PyInstruction_GetLength(PyCodeObject *code, int offset)
313 {
314     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
315 
316     int opcode = _PyCode_CODE(code)[offset].op.code;
317     assert(opcode != 0);
318     assert(opcode != RESERVED);
319     if (opcode == INSTRUMENTED_LINE) {
320         opcode = code->_co_monitoring->lines[offset].original_opcode;
321     }
322     if (opcode == INSTRUMENTED_INSTRUCTION) {
323         opcode = code->_co_monitoring->per_instruction_opcodes[offset];
324     }
325     int deinstrumented = DE_INSTRUMENT[opcode];
326     if (deinstrumented) {
327         opcode = deinstrumented;
328     }
329     else {
330         opcode = _PyOpcode_Deopt[opcode];
331     }
332     assert(opcode != 0);
333     assert(!is_instrumented(opcode));
334     if (opcode == ENTER_EXECUTOR) {
335         int exec_index = _PyCode_CODE(code)[offset].op.arg;
336         _PyExecutorObject *exec = code->co_executors->executors[exec_index];
337         opcode = _PyOpcode_Deopt[exec->vm_data.opcode];
338 
339     }
340     assert(opcode != ENTER_EXECUTOR);
341     assert(opcode == _PyOpcode_Deopt[opcode]);
342     return 1 + _PyOpcode_Caches[opcode];
343 }
344 
345 #ifdef INSTRUMENT_DEBUG
346 
347 static void
dump_instrumentation_data_tools(PyCodeObject * code,uint8_t * tools,int i,FILE * out)348 dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out)
349 {
350     if (tools == NULL) {
351         fprintf(out, "tools = NULL");
352     }
353     else {
354         fprintf(out, "tools = %d", tools[i]);
355     }
356 }
357 
358 static void
dump_instrumentation_data_lines(PyCodeObject * code,_PyCoLineInstrumentationData * lines,int i,FILE * out)359 dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out)
360 {
361     if (lines == NULL) {
362         fprintf(out, ", lines = NULL");
363     }
364     else if (lines[i].original_opcode == 0) {
365         fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta);
366     }
367     else {
368         fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta);
369     }
370 }
371 
372 static void
dump_instrumentation_data_line_tools(PyCodeObject * code,uint8_t * line_tools,int i,FILE * out)373 dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out)
374 {
375     if (line_tools == NULL) {
376         fprintf(out, ", line_tools = NULL");
377     }
378     else {
379         fprintf(out, ", line_tools = %d", line_tools[i]);
380     }
381 }
382 
383 static void
dump_instrumentation_data_per_instruction(PyCodeObject * code,_PyCoMonitoringData * data,int i,FILE * out)384 dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out)
385 {
386     if (data->per_instruction_opcodes == NULL) {
387         fprintf(out, ", per-inst opcode = NULL");
388     }
389     else {
390         fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]);
391     }
392     if (data->per_instruction_tools == NULL) {
393         fprintf(out, ", per-inst tools = NULL");
394     }
395     else {
396         fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]);
397     }
398 }
399 
400 static void
dump_global_monitors(const char * prefix,_Py_GlobalMonitors monitors,FILE * out)401 dump_global_monitors(const char *prefix, _Py_GlobalMonitors monitors, FILE*out)
402 {
403     fprintf(out, "%s monitors:\n", prefix);
404     for (int event = 0; event < _PY_MONITORING_UNGROUPED_EVENTS; event++) {
405         fprintf(out, "    Event %d: Tools %x\n", event, monitors.tools[event]);
406     }
407 }
408 
409 static void
dump_local_monitors(const char * prefix,_Py_LocalMonitors monitors,FILE * out)410 dump_local_monitors(const char *prefix, _Py_LocalMonitors monitors, FILE*out)
411 {
412     fprintf(out, "%s monitors:\n", prefix);
413     for (int event = 0; event < _PY_MONITORING_LOCAL_EVENTS; event++) {
414         fprintf(out, "    Event %d: Tools %x\n", event, monitors.tools[event]);
415     }
416 }
417 
418 /* No error checking -- Don't use this for anything but experimental debugging */
419 static void
dump_instrumentation_data(PyCodeObject * code,int star,FILE * out)420 dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
421 {
422     _PyCoMonitoringData *data = code->_co_monitoring;
423     fprintf(out, "\n");
424     PyObject_Print(code->co_name, out, Py_PRINT_RAW);
425     fprintf(out, "\n");
426     if (data == NULL) {
427         fprintf(out, "NULL\n");
428         return;
429     }
430     dump_global_monitors("Global", _PyInterpreterState_GET()->monitors, out);
431     dump_local_monitors("Code", data->local_monitors, out);
432     dump_local_monitors("Active", data->active_monitors, out);
433     int code_len = (int)Py_SIZE(code);
434     bool starred = false;
435     for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) {
436         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
437         int opcode = instr->op.code;
438         if (i == star) {
439             fprintf(out, "**  ");
440             starred = true;
441         }
442         fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]);
443         dump_instrumentation_data_tools(code, data->tools, i, out);
444         dump_instrumentation_data_lines(code, data->lines, i, out);
445         dump_instrumentation_data_line_tools(code, data->line_tools, i, out);
446         dump_instrumentation_data_per_instruction(code, data, i, out);
447         fprintf(out, "\n");
448         ;
449     }
450     if (!starred && star >= 0) {
451         fprintf(out, "Error offset not at valid instruction offset: %d\n", star);
452         fprintf(out, "    ");
453         dump_instrumentation_data_tools(code, data->tools, star, out);
454         dump_instrumentation_data_lines(code, data->lines, star, out);
455         dump_instrumentation_data_line_tools(code, data->line_tools, star, out);
456         dump_instrumentation_data_per_instruction(code, data, star, out);
457         fprintf(out, "\n");
458     }
459 }
460 
461 #define CHECK(test) do { \
462     if (!(test)) { \
463         dump_instrumentation_data(code, i, stderr); \
464     } \
465     assert(test); \
466 } while (0)
467 
468 static bool
valid_opcode(int opcode)469 valid_opcode(int opcode)
470 {
471     if (opcode == INSTRUMENTED_LINE) {
472         return true;
473     }
474     if (IS_VALID_OPCODE(opcode) &&
475         opcode != CACHE &&
476         opcode != RESERVED &&
477         opcode < 255)
478     {
479        return true;
480     }
481     return false;
482 }
483 
484 static void
sanity_check_instrumentation(PyCodeObject * code)485 sanity_check_instrumentation(PyCodeObject *code)
486 {
487     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
488 
489     _PyCoMonitoringData *data = code->_co_monitoring;
490     if (data == NULL) {
491         return;
492     }
493     _Py_GlobalMonitors global_monitors = _PyInterpreterState_GET()->monitors;
494     _Py_LocalMonitors active_monitors;
495     if (code->_co_monitoring) {
496         _Py_LocalMonitors local_monitors = code->_co_monitoring->local_monitors;
497         active_monitors = local_union(global_monitors, local_monitors);
498     }
499     else {
500         _Py_LocalMonitors empty = (_Py_LocalMonitors) { 0 };
501         active_monitors = local_union(global_monitors, empty);
502     }
503     assert(monitors_equals(
504         code->_co_monitoring->active_monitors,
505         active_monitors));
506     int code_len = (int)Py_SIZE(code);
507     for (int i = 0; i < code_len;) {
508         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
509         int opcode = instr->op.code;
510         int base_opcode = _Py_GetBaseOpcode(code, i);
511         CHECK(valid_opcode(opcode));
512         CHECK(valid_opcode(base_opcode));
513         if (opcode == INSTRUMENTED_INSTRUCTION) {
514             opcode = data->per_instruction_opcodes[i];
515             if (!is_instrumented(opcode)) {
516                 CHECK(_PyOpcode_Deopt[opcode] == opcode);
517             }
518         }
519         if (opcode == INSTRUMENTED_LINE) {
520             CHECK(data->lines);
521             CHECK(valid_opcode(data->lines[i].original_opcode));
522             opcode = data->lines[i].original_opcode;
523             CHECK(opcode != END_FOR);
524             CHECK(opcode != RESUME);
525             CHECK(opcode != RESUME_CHECK);
526             CHECK(opcode != INSTRUMENTED_RESUME);
527             if (!is_instrumented(opcode)) {
528                 CHECK(_PyOpcode_Deopt[opcode] == opcode);
529             }
530             CHECK(opcode != INSTRUMENTED_LINE);
531         }
532         else if (data->lines) {
533             /* If original_opcode is INSTRUMENTED_INSTRUCTION
534              * *and* we are executing a INSTRUMENTED_LINE instruction
535              * that has de-instrumented itself, then we will execute
536              * an invalid INSTRUMENTED_INSTRUCTION */
537             CHECK(data->lines[i].original_opcode != INSTRUMENTED_INSTRUCTION);
538         }
539         if (opcode == INSTRUMENTED_INSTRUCTION) {
540             CHECK(data->per_instruction_opcodes[i] != 0);
541             opcode = data->per_instruction_opcodes[i];
542         }
543         if (is_instrumented(opcode)) {
544             CHECK(DE_INSTRUMENT[opcode] == base_opcode);
545             int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]];
546             if (event < 0) {
547                 /* RESUME fixup */
548                 event = instr->op.arg ? 1: 0;
549             }
550             CHECK(active_monitors.tools[event] != 0);
551         }
552         if (data->lines && base_opcode != END_FOR) {
553             int line1 = compute_line(code, i, data->lines[i].line_delta);
554             int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT));
555             CHECK(line1 == line2);
556         }
557         CHECK(valid_opcode(opcode));
558         if (data->tools) {
559             uint8_t local_tools = data->tools[i];
560             if (opcode_has_event(base_opcode)) {
561                 int event = EVENT_FOR_OPCODE[base_opcode];
562                 if (event == -1) {
563                     /* RESUME fixup */
564                     event = _PyCode_CODE(code)[i].op.arg;
565                 }
566                 CHECK((active_monitors.tools[event] & local_tools) == local_tools);
567             }
568             else {
569                 CHECK(local_tools == 0xff);
570             }
571         }
572         i += _PyInstruction_GetLength(code, i);
573         assert(i <= code_len);
574     }
575 }
576 #else
577 
578 #define CHECK(test) assert(test)
579 
580 #endif
581 
582 /* Get the underlying opcode, stripping instrumentation */
_Py_GetBaseOpcode(PyCodeObject * code,int i)583 int _Py_GetBaseOpcode(PyCodeObject *code, int i)
584 {
585     int opcode = _PyCode_CODE(code)[i].op.code;
586     if (opcode == INSTRUMENTED_LINE) {
587         opcode = code->_co_monitoring->lines[i].original_opcode;
588     }
589     if (opcode == INSTRUMENTED_INSTRUCTION) {
590         opcode = code->_co_monitoring->per_instruction_opcodes[i];
591     }
592     CHECK(opcode != INSTRUMENTED_INSTRUCTION);
593     CHECK(opcode != INSTRUMENTED_LINE);
594     int deinstrumented = DE_INSTRUMENT[opcode];
595     if (deinstrumented) {
596         return deinstrumented;
597     }
598     return _PyOpcode_Deopt[opcode];
599 }
600 
601 static void
de_instrument(PyCodeObject * code,int i,int event)602 de_instrument(PyCodeObject *code, int i, int event)
603 {
604     assert(event != PY_MONITORING_EVENT_INSTRUCTION);
605     assert(event != PY_MONITORING_EVENT_LINE);
606 
607     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
608     uint8_t *opcode_ptr = &instr->op.code;
609     int opcode = *opcode_ptr;
610     assert(opcode != ENTER_EXECUTOR);
611     if (opcode == INSTRUMENTED_LINE) {
612         opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
613         opcode = *opcode_ptr;
614     }
615     if (opcode == INSTRUMENTED_INSTRUCTION) {
616         opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i];
617         opcode = *opcode_ptr;
618     }
619     int deinstrumented = DE_INSTRUMENT[opcode];
620     if (deinstrumented == 0) {
621         return;
622     }
623     CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented);
624     FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, deinstrumented);
625     if (_PyOpcode_Caches[deinstrumented]) {
626         FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter,
627                                        adaptive_counter_warmup().as_counter);
628     }
629 }
630 
631 static void
de_instrument_line(PyCodeObject * code,int i)632 de_instrument_line(PyCodeObject *code, int i)
633 {
634     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
635     int opcode = instr->op.code;
636     if (opcode != INSTRUMENTED_LINE) {
637         return;
638     }
639     _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
640     int original_opcode = lines->original_opcode;
641     if (original_opcode == INSTRUMENTED_INSTRUCTION) {
642         lines->original_opcode = code->_co_monitoring->per_instruction_opcodes[i];
643     }
644     CHECK(original_opcode != 0);
645     CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
646     instr->op.code = original_opcode;
647     if (_PyOpcode_Caches[original_opcode]) {
648         instr[1].counter = adaptive_counter_warmup();
649     }
650     assert(instr->op.code != INSTRUMENTED_LINE);
651 }
652 
653 static void
de_instrument_per_instruction(PyCodeObject * code,int i)654 de_instrument_per_instruction(PyCodeObject *code, int i)
655 {
656     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
657     uint8_t *opcode_ptr = &instr->op.code;
658     int opcode = *opcode_ptr;
659     if (opcode == INSTRUMENTED_LINE) {
660         opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
661         opcode = *opcode_ptr;
662     }
663     if (opcode != INSTRUMENTED_INSTRUCTION) {
664         return;
665     }
666     int original_opcode = code->_co_monitoring->per_instruction_opcodes[i];
667     CHECK(original_opcode != 0);
668     CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
669     *opcode_ptr = original_opcode;
670     if (_PyOpcode_Caches[original_opcode]) {
671         instr[1].counter = adaptive_counter_warmup();
672     }
673     assert(*opcode_ptr != INSTRUMENTED_INSTRUCTION);
674     assert(instr->op.code != INSTRUMENTED_INSTRUCTION);
675 }
676 
677 
678 static void
instrument(PyCodeObject * code,int i)679 instrument(PyCodeObject *code, int i)
680 {
681     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
682     uint8_t *opcode_ptr = &instr->op.code;
683     int opcode =*opcode_ptr;
684     if (opcode == INSTRUMENTED_LINE) {
685         _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
686         opcode_ptr = &lines->original_opcode;
687         opcode = *opcode_ptr;
688     }
689     if (opcode == INSTRUMENTED_INSTRUCTION) {
690         opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i];
691         opcode = *opcode_ptr;
692         CHECK(opcode != INSTRUMENTED_INSTRUCTION && opcode != INSTRUMENTED_LINE);
693         CHECK(opcode == _PyOpcode_Deopt[opcode]);
694     }
695     CHECK(opcode != 0);
696     if (!is_instrumented(opcode)) {
697         int deopt = _PyOpcode_Deopt[opcode];
698         int instrumented = INSTRUMENTED_OPCODES[deopt];
699         assert(instrumented);
700         FT_ATOMIC_STORE_UINT8_RELAXED(*opcode_ptr, instrumented);
701         if (_PyOpcode_Caches[deopt]) {
702           FT_ATOMIC_STORE_UINT16_RELAXED(instr[1].counter.as_counter,
703                                          adaptive_counter_warmup().as_counter);
704             instr[1].counter = adaptive_counter_warmup();
705         }
706     }
707 }
708 
709 static void
instrument_line(PyCodeObject * code,int i)710 instrument_line(PyCodeObject *code, int i)
711 {
712     uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code;
713     int opcode = *opcode_ptr;
714     if (opcode == INSTRUMENTED_LINE) {
715         return;
716     }
717     _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
718     lines->original_opcode = _PyOpcode_Deopt[opcode];
719     CHECK(lines->original_opcode > 0);
720     *opcode_ptr = INSTRUMENTED_LINE;
721 }
722 
723 static void
instrument_per_instruction(PyCodeObject * code,int i)724 instrument_per_instruction(PyCodeObject *code, int i)
725 {
726     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
727     uint8_t *opcode_ptr = &instr->op.code;
728     int opcode = *opcode_ptr;
729     if (opcode == INSTRUMENTED_LINE) {
730         _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
731         opcode_ptr = &lines->original_opcode;
732         opcode = *opcode_ptr;
733     }
734     if (opcode == INSTRUMENTED_INSTRUCTION) {
735         assert(code->_co_monitoring->per_instruction_opcodes[i] > 0);
736         return;
737     }
738     CHECK(opcode != 0);
739     if (is_instrumented(opcode)) {
740         code->_co_monitoring->per_instruction_opcodes[i] = opcode;
741     }
742     else {
743         assert(opcode != 0);
744         assert(_PyOpcode_Deopt[opcode] != 0);
745         assert(_PyOpcode_Deopt[opcode] != RESUME);
746         code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode];
747     }
748     assert(code->_co_monitoring->per_instruction_opcodes[i] > 0);
749     *opcode_ptr = INSTRUMENTED_INSTRUCTION;
750 }
751 
752 static void
remove_tools(PyCodeObject * code,int offset,int event,int tools)753 remove_tools(PyCodeObject * code, int offset, int event, int tools)
754 {
755     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
756     assert(event != PY_MONITORING_EVENT_LINE);
757     assert(event != PY_MONITORING_EVENT_INSTRUCTION);
758     assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event));
759     assert(opcode_has_event(_Py_GetBaseOpcode(code, offset)));
760     _PyCoMonitoringData *monitoring = code->_co_monitoring;
761     if (monitoring && monitoring->tools) {
762         monitoring->tools[offset] &= ~tools;
763         if (monitoring->tools[offset] == 0) {
764             de_instrument(code, offset, event);
765         }
766     }
767     else {
768         /* Single tool */
769         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event];
770         assert(_Py_popcount32(single_tool) <= 1);
771         if (((single_tool & tools) == single_tool)) {
772             de_instrument(code, offset, event);
773         }
774     }
775 }
776 
777 #ifndef NDEBUG
778 static bool
tools_is_subset_for_event(PyCodeObject * code,int event,int tools)779 tools_is_subset_for_event(PyCodeObject * code, int event, int tools)
780 {
781     int global_tools = _PyInterpreterState_GET()->monitors.tools[event];
782     int local_tools = code->_co_monitoring->local_monitors.tools[event];
783     return tools == ((global_tools | local_tools) & tools);
784 }
785 #endif
786 
787 static void
remove_line_tools(PyCodeObject * code,int offset,int tools)788 remove_line_tools(PyCodeObject * code, int offset, int tools)
789 {
790     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
791 
792     assert(code->_co_monitoring);
793     if (code->_co_monitoring->line_tools)
794     {
795         uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset];
796         *toolsptr &= ~tools;
797         if (*toolsptr == 0 ) {
798             de_instrument_line(code, offset);
799         }
800     }
801     else {
802         /* Single tool */
803         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE];
804         assert(_Py_popcount32(single_tool) <= 1);
805         if (((single_tool & tools) == single_tool)) {
806             de_instrument_line(code, offset);
807         }
808     }
809 }
810 
811 static void
add_tools(PyCodeObject * code,int offset,int event,int tools)812 add_tools(PyCodeObject * code, int offset, int event, int tools)
813 {
814     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
815     assert(event != PY_MONITORING_EVENT_LINE);
816     assert(event != PY_MONITORING_EVENT_INSTRUCTION);
817     assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event));
818     assert(code->_co_monitoring);
819     if (code->_co_monitoring &&
820         code->_co_monitoring->tools
821     ) {
822         code->_co_monitoring->tools[offset] |= tools;
823     }
824     else {
825         /* Single tool */
826         assert(_Py_popcount32(tools) == 1);
827         assert(tools_is_subset_for_event(code, event, tools));
828     }
829     instrument(code, offset);
830 }
831 
832 static void
add_line_tools(PyCodeObject * code,int offset,int tools)833 add_line_tools(PyCodeObject * code, int offset, int tools)
834 {
835     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
836 
837     assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools));
838     assert(code->_co_monitoring);
839     if (code->_co_monitoring->line_tools) {
840         code->_co_monitoring->line_tools[offset] |= tools;
841     }
842     else {
843         /* Single tool */
844         assert(_Py_popcount32(tools) == 1);
845     }
846     instrument_line(code, offset);
847 }
848 
849 
850 static void
add_per_instruction_tools(PyCodeObject * code,int offset,int tools)851 add_per_instruction_tools(PyCodeObject * code, int offset, int tools)
852 {
853     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
854 
855     assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools));
856     assert(code->_co_monitoring);
857     if (code->_co_monitoring->per_instruction_tools) {
858         code->_co_monitoring->per_instruction_tools[offset] |= tools;
859     }
860     else {
861         /* Single tool */
862         assert(_Py_popcount32(tools) == 1);
863     }
864     instrument_per_instruction(code, offset);
865 }
866 
867 
868 static void
remove_per_instruction_tools(PyCodeObject * code,int offset,int tools)869 remove_per_instruction_tools(PyCodeObject * code, int offset, int tools)
870 {
871     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
872 
873     assert(code->_co_monitoring);
874     if (code->_co_monitoring->per_instruction_tools) {
875         uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset];
876         *toolsptr &= ~tools;
877         if (*toolsptr == 0) {
878             de_instrument_per_instruction(code, offset);
879         }
880     }
881     else {
882         /* Single tool */
883         uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION];
884         assert(_Py_popcount32(single_tool) <= 1);
885         if (((single_tool & tools) == single_tool)) {
886             de_instrument_per_instruction(code, offset);
887         }
888     }
889 }
890 
891 
892 /* Return 1 if DISABLE returned, -1 if error, 0 otherwise */
893 static int
call_one_instrument(PyInterpreterState * interp,PyThreadState * tstate,PyObject ** args,size_t nargsf,int8_t tool,int event)894 call_one_instrument(
895     PyInterpreterState *interp, PyThreadState *tstate, PyObject **args,
896     size_t nargsf, int8_t tool, int event)
897 {
898     assert(0 <= tool && tool < 8);
899     assert(tstate->tracing == 0);
900     PyObject *instrument = interp->monitoring_callables[tool][event];
901     if (instrument == NULL) {
902         return 0;
903     }
904     int old_what = tstate->what_event;
905     tstate->what_event = event;
906     tstate->tracing++;
907     PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL);
908     tstate->tracing--;
909     tstate->what_event = old_what;
910     if (res == NULL) {
911         return -1;
912     }
913     Py_DECREF(res);
914     return (res == &_PyInstrumentation_DISABLE);
915 }
916 
917 static const int8_t MOST_SIGNIFICANT_BITS[16] = {
918     -1, 0, 1, 1,
919     2, 2, 2, 2,
920     3, 3, 3, 3,
921     3, 3, 3, 3,
922 };
923 
924 /* We could use _Py_bit_length here, but that is designed for larger (32/64)
925  * bit ints, and can perform relatively poorly on platforms without the
926  * necessary intrinsics. */
most_significant_bit(uint8_t bits)927 static inline int most_significant_bit(uint8_t bits) {
928     assert(bits != 0);
929     if (bits > 15) {
930         return MOST_SIGNIFICANT_BITS[bits>>4]+4;
931     }
932     return MOST_SIGNIFICANT_BITS[bits];
933 }
934 
935 static uint32_t
global_version(PyInterpreterState * interp)936 global_version(PyInterpreterState *interp)
937 {
938     uint32_t version = (uint32_t)_Py_atomic_load_uintptr_relaxed(
939         &interp->ceval.instrumentation_version);
940 #ifdef Py_DEBUG
941     PyThreadState *tstate = _PyThreadState_GET();
942     uint32_t thread_version =
943         (uint32_t)(_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) &
944                    ~_PY_EVAL_EVENTS_MASK);
945     assert(thread_version == version);
946 #endif
947     return version;
948 }
949 
950 /* Atomically set the given version in the given location, without touching
951    anything in _PY_EVAL_EVENTS_MASK. */
952 static void
set_version_raw(uintptr_t * ptr,uint32_t version)953 set_version_raw(uintptr_t *ptr, uint32_t version)
954 {
955     uintptr_t old = _Py_atomic_load_uintptr_relaxed(ptr);
956     uintptr_t new;
957     do {
958         new = (old & _PY_EVAL_EVENTS_MASK) | version;
959     } while (!_Py_atomic_compare_exchange_uintptr(ptr, &old, new));
960 }
961 
962 static void
set_global_version(PyThreadState * tstate,uint32_t version)963 set_global_version(PyThreadState *tstate, uint32_t version)
964 {
965     assert((version & _PY_EVAL_EVENTS_MASK) == 0);
966     PyInterpreterState *interp = tstate->interp;
967     set_version_raw(&interp->ceval.instrumentation_version, version);
968 
969 #ifdef Py_GIL_DISABLED
970     // Set the version on all threads in free-threaded builds.
971     _PyRuntimeState *runtime = &_PyRuntime;
972     HEAD_LOCK(runtime);
973     for (tstate = interp->threads.head; tstate;
974          tstate = PyThreadState_Next(tstate)) {
975         set_version_raw(&tstate->eval_breaker, version);
976     };
977     HEAD_UNLOCK(runtime);
978 #else
979     // Normal builds take the current version from instrumentation_version when
980     // attaching a thread, so we only have to set the current thread's version.
981     set_version_raw(&tstate->eval_breaker, version);
982 #endif
983 }
984 
985 static bool
is_version_up_to_date(PyCodeObject * code,PyInterpreterState * interp)986 is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp)
987 {
988     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
989     return global_version(interp) == code->_co_instrumentation_version;
990 }
991 
992 #ifndef NDEBUG
993 static bool
instrumentation_cross_checks(PyInterpreterState * interp,PyCodeObject * code)994 instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code)
995 {
996     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
997     _Py_LocalMonitors expected = local_union(
998         interp->monitors,
999         code->_co_monitoring->local_monitors);
1000     return monitors_equals(code->_co_monitoring->active_monitors, expected);
1001 }
1002 
1003 static int
debug_check_sanity(PyInterpreterState * interp,PyCodeObject * code)1004 debug_check_sanity(PyInterpreterState *interp, PyCodeObject *code)
1005 {
1006     int res;
1007     LOCK_CODE(code);
1008     res = is_version_up_to_date(code, interp) &&
1009           instrumentation_cross_checks(interp, code);
1010     UNLOCK_CODE();
1011     return res;
1012 }
1013 
1014 #endif
1015 
1016 static inline uint8_t
get_tools_for_instruction(PyCodeObject * code,PyInterpreterState * interp,int i,int event)1017 get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i, int event)
1018 {
1019     uint8_t tools;
1020     assert(event != PY_MONITORING_EVENT_LINE);
1021     assert(event != PY_MONITORING_EVENT_INSTRUCTION);
1022     if (event >= _PY_MONITORING_UNGROUPED_EVENTS) {
1023         assert(event == PY_MONITORING_EVENT_C_RAISE ||
1024                 event == PY_MONITORING_EVENT_C_RETURN);
1025         event = PY_MONITORING_EVENT_CALL;
1026     }
1027     if (PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) {
1028         CHECK(debug_check_sanity(interp, code));
1029         if (code->_co_monitoring->tools) {
1030             tools = code->_co_monitoring->tools[i];
1031         }
1032         else {
1033             tools = code->_co_monitoring->active_monitors.tools[event];
1034         }
1035     }
1036     else {
1037         tools = interp->monitors.tools[event];
1038     }
1039     return tools;
1040 }
1041 
1042 static const char *const event_names [] = {
1043     [PY_MONITORING_EVENT_PY_START] = "PY_START",
1044     [PY_MONITORING_EVENT_PY_RESUME] = "PY_RESUME",
1045     [PY_MONITORING_EVENT_PY_RETURN] = "PY_RETURN",
1046     [PY_MONITORING_EVENT_PY_YIELD] = "PY_YIELD",
1047     [PY_MONITORING_EVENT_CALL] = "CALL",
1048     [PY_MONITORING_EVENT_LINE] = "LINE",
1049     [PY_MONITORING_EVENT_INSTRUCTION] = "INSTRUCTION",
1050     [PY_MONITORING_EVENT_JUMP] = "JUMP",
1051     [PY_MONITORING_EVENT_BRANCH] = "BRANCH",
1052     [PY_MONITORING_EVENT_C_RETURN] = "C_RETURN",
1053     [PY_MONITORING_EVENT_PY_THROW] = "PY_THROW",
1054     [PY_MONITORING_EVENT_RAISE] = "RAISE",
1055     [PY_MONITORING_EVENT_RERAISE] = "RERAISE",
1056     [PY_MONITORING_EVENT_EXCEPTION_HANDLED] = "EXCEPTION_HANDLED",
1057     [PY_MONITORING_EVENT_C_RAISE] = "C_RAISE",
1058     [PY_MONITORING_EVENT_PY_UNWIND] = "PY_UNWIND",
1059     [PY_MONITORING_EVENT_STOP_ITERATION] = "STOP_ITERATION",
1060 };
1061 
1062 static int
call_instrumentation_vector(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,Py_ssize_t nargs,PyObject * args[])1063 call_instrumentation_vector(
1064     PyThreadState *tstate, int event,
1065     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[])
1066 {
1067     if (tstate->tracing) {
1068         return 0;
1069     }
1070     assert(!_PyErr_Occurred(tstate));
1071     assert(args[0] == NULL);
1072     PyCodeObject *code = _PyFrame_GetCode(frame);
1073     assert(args[1] == NULL);
1074     args[1] = (PyObject *)code;
1075     int offset = (int)(instr - _PyCode_CODE(code));
1076     /* Offset visible to user should be the offset in bytes, as that is the
1077      * convention for APIs involving code offsets. */
1078     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
1079     PyObject *offset_obj = PyLong_FromLong(bytes_offset);
1080     if (offset_obj == NULL) {
1081         return -1;
1082     }
1083     assert(args[2] == NULL);
1084     args[2] = offset_obj;
1085     PyInterpreterState *interp = tstate->interp;
1086     uint8_t tools = get_tools_for_instruction(code, interp, offset, event);
1087     size_t nargsf = (size_t) nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
1088     PyObject **callargs = &args[1];
1089     int err = 0;
1090     while (tools) {
1091         int tool = most_significant_bit(tools);
1092         assert(tool >= 0 && tool < 8);
1093         assert(tools & (1 << tool));
1094         tools ^= (1 << tool);
1095         int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event);
1096         if (res == 0) {
1097             /* Nothing to do */
1098         }
1099         else if (res < 0) {
1100             /* error */
1101             err = -1;
1102             break;
1103         }
1104         else {
1105             /* DISABLE */
1106             if (!PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) {
1107                 PyErr_Format(PyExc_ValueError,
1108                               "Cannot disable %s events. Callback removed.",
1109                              event_names[event]);
1110                 /* Clear tool to prevent infinite loop */
1111                 Py_CLEAR(interp->monitoring_callables[tool][event]);
1112                 err = -1;
1113                 break;
1114             }
1115             else {
1116                 LOCK_CODE(code);
1117                 remove_tools(code, offset, event, 1 << tool);
1118                 UNLOCK_CODE();
1119             }
1120         }
1121     }
1122     Py_DECREF(offset_obj);
1123     return err;
1124 }
1125 
1126 int
_Py_call_instrumentation(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr)1127 _Py_call_instrumentation(
1128     PyThreadState *tstate, int event,
1129     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr)
1130 {
1131     PyObject *args[3] = { NULL, NULL, NULL };
1132     return call_instrumentation_vector(tstate, event, frame, instr, 2, args);
1133 }
1134 
1135 int
_Py_call_instrumentation_arg(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,PyObject * arg)1136 _Py_call_instrumentation_arg(
1137     PyThreadState *tstate, int event,
1138     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg)
1139 {
1140     PyObject *args[4] = { NULL, NULL, NULL, arg };
1141     return call_instrumentation_vector(tstate, event, frame, instr, 3, args);
1142 }
1143 
1144 int
_Py_call_instrumentation_2args(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,PyObject * arg0,PyObject * arg1)1145 _Py_call_instrumentation_2args(
1146     PyThreadState *tstate, int event,
1147     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1)
1148 {
1149     PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 };
1150     return call_instrumentation_vector(tstate, event, frame, instr, 4, args);
1151 }
1152 
1153 _Py_CODEUNIT *
_Py_call_instrumentation_jump(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,_Py_CODEUNIT * target)1154 _Py_call_instrumentation_jump(
1155     PyThreadState *tstate, int event,
1156     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target)
1157 {
1158     assert(event == PY_MONITORING_EVENT_JUMP ||
1159            event == PY_MONITORING_EVENT_BRANCH);
1160     assert(frame->instr_ptr == instr);
1161     PyCodeObject *code = _PyFrame_GetCode(frame);
1162     int to = (int)(target - _PyCode_CODE(code));
1163     PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT));
1164     if (to_obj == NULL) {
1165         return NULL;
1166     }
1167     PyObject *args[4] = { NULL, NULL, NULL, to_obj };
1168     int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args);
1169     Py_DECREF(to_obj);
1170     if (err) {
1171         return NULL;
1172     }
1173     if (frame->instr_ptr != instr) {
1174         /* The callback has caused a jump (by setting the line number) */
1175         return frame->instr_ptr;
1176     }
1177     return target;
1178 }
1179 
1180 static void
call_instrumentation_vector_protected(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,Py_ssize_t nargs,PyObject * args[])1181 call_instrumentation_vector_protected(
1182     PyThreadState *tstate, int event,
1183     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[])
1184 {
1185     assert(_PyErr_Occurred(tstate));
1186     PyObject *exc = _PyErr_GetRaisedException(tstate);
1187     int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args);
1188     if (err) {
1189         Py_XDECREF(exc);
1190     }
1191     else {
1192         _PyErr_SetRaisedException(tstate, exc);
1193     }
1194     assert(_PyErr_Occurred(tstate));
1195 }
1196 
1197 void
_Py_call_instrumentation_exc2(PyThreadState * tstate,int event,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,PyObject * arg0,PyObject * arg1)1198 _Py_call_instrumentation_exc2(
1199     PyThreadState *tstate, int event,
1200     _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1)
1201 {
1202     assert(_PyErr_Occurred(tstate));
1203     PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 };
1204     call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args);
1205 }
1206 
1207 
1208 int
_Py_Instrumentation_GetLine(PyCodeObject * code,int index)1209 _Py_Instrumentation_GetLine(PyCodeObject *code, int index)
1210 {
1211     _PyCoMonitoringData *monitoring = code->_co_monitoring;
1212     assert(monitoring != NULL);
1213     assert(monitoring->lines != NULL);
1214     assert(index >= code->_co_firsttraceable);
1215     assert(index < Py_SIZE(code));
1216     _PyCoLineInstrumentationData *line_data = &monitoring->lines[index];
1217     int8_t line_delta = line_data->line_delta;
1218     int line = compute_line(code, index, line_delta);
1219     return line;
1220 }
1221 
1222 int
_Py_call_instrumentation_line(PyThreadState * tstate,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr,_Py_CODEUNIT * prev)1223 _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev)
1224 {
1225     PyCodeObject *code = _PyFrame_GetCode(frame);
1226     assert(tstate->tracing == 0);
1227     assert(debug_check_sanity(tstate->interp, code));
1228     int i = (int)(instr - _PyCode_CODE(code));
1229 
1230     _PyCoMonitoringData *monitoring = code->_co_monitoring;
1231     _PyCoLineInstrumentationData *line_data = &monitoring->lines[i];
1232     PyInterpreterState *interp = tstate->interp;
1233     int8_t line_delta = line_data->line_delta;
1234     int line = 0;
1235 
1236     if (line_delta == COMPUTED_LINE_LINENO_CHANGE) {
1237         // We know the line number must have changed, don't need to calculate
1238         // the line number for now because we might not need it.
1239         line = -1;
1240     } else {
1241         line = compute_line(code, i, line_delta);
1242         assert(line >= 0);
1243         assert(prev != NULL);
1244         int prev_index = (int)(prev - _PyCode_CODE(code));
1245         int prev_line = _Py_Instrumentation_GetLine(code, prev_index);
1246         if (prev_line == line) {
1247             int prev_opcode = _PyCode_CODE(code)[prev_index].op.code;
1248             /* RESUME and INSTRUMENTED_RESUME are needed for the operation of
1249              * instrumentation, so must never be hidden by an INSTRUMENTED_LINE.
1250              */
1251             if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) {
1252                 goto done;
1253             }
1254         }
1255     }
1256 
1257     uint8_t tools = code->_co_monitoring->line_tools != NULL ?
1258         code->_co_monitoring->line_tools[i] :
1259         (interp->monitors.tools[PY_MONITORING_EVENT_LINE] |
1260          code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE]
1261         );
1262     /* Special case sys.settrace to avoid boxing the line number,
1263      * only to immediately unbox it. */
1264     if (tools & (1 << PY_MONITORING_SYS_TRACE_ID)) {
1265         if (tstate->c_tracefunc != NULL) {
1266             PyFrameObject *frame_obj = _PyFrame_GetFrameObject(frame);
1267             if (frame_obj == NULL) {
1268                 return -1;
1269             }
1270             if (frame_obj->f_trace_lines) {
1271                 /* Need to set tracing and what_event as if using
1272                  * the instrumentation call. */
1273                 int old_what = tstate->what_event;
1274                 tstate->what_event = PY_MONITORING_EVENT_LINE;
1275                 tstate->tracing++;
1276                 /* Call c_tracefunc directly, having set the line number. */
1277                 Py_INCREF(frame_obj);
1278                 if (line == -1 && line_delta > COMPUTED_LINE) {
1279                     /* Only assign f_lineno if it's easy to calculate, otherwise
1280                      * do lazy calculation by setting the f_lineno to 0.
1281                      */
1282                     line = compute_line(code, i, line_delta);
1283                 }
1284                 frame_obj->f_lineno = line;
1285                 int err = tstate->c_tracefunc(tstate->c_traceobj, frame_obj, PyTrace_LINE, Py_None);
1286                 frame_obj->f_lineno = 0;
1287                 tstate->tracing--;
1288                 tstate->what_event = old_what;
1289                 Py_DECREF(frame_obj);
1290                 if (err) {
1291                     return -1;
1292                 }
1293             }
1294         }
1295         tools &= (255 - (1 << PY_MONITORING_SYS_TRACE_ID));
1296     }
1297     if (tools == 0) {
1298         goto done;
1299     }
1300 
1301     if (line == -1) {
1302         /* Need to calculate the line number now for monitoring events */
1303         line = compute_line(code, i, line_delta);
1304     }
1305     PyObject *line_obj = PyLong_FromLong(line);
1306     if (line_obj == NULL) {
1307         return -1;
1308     }
1309     PyObject *args[3] = { NULL, (PyObject *)code, line_obj };
1310     do {
1311         int tool = most_significant_bit(tools);
1312         assert(tool >= 0 && tool < PY_MONITORING_SYS_PROFILE_ID);
1313         assert(tools & (1 << tool));
1314         tools &= ~(1 << tool);
1315         int res = call_one_instrument(interp, tstate, &args[1],
1316                                       2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
1317                                       tool, PY_MONITORING_EVENT_LINE);
1318         if (res == 0) {
1319             /* Nothing to do */
1320         }
1321         else if (res < 0) {
1322             /* error */
1323             Py_DECREF(line_obj);
1324             return -1;
1325         }
1326         else {
1327             /* DISABLE  */
1328             LOCK_CODE(code);
1329             remove_line_tools(code, i, 1 << tool);
1330             UNLOCK_CODE();
1331         }
1332     } while (tools);
1333     Py_DECREF(line_obj);
1334     uint8_t original_opcode;
1335 done:
1336     original_opcode = line_data->original_opcode;
1337     assert(original_opcode != 0);
1338     assert(original_opcode != INSTRUMENTED_LINE);
1339     assert(_PyOpcode_Deopt[original_opcode] == original_opcode);
1340     return original_opcode;
1341 }
1342 
1343 int
_Py_call_instrumentation_instruction(PyThreadState * tstate,_PyInterpreterFrame * frame,_Py_CODEUNIT * instr)1344 _Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr)
1345 {
1346     PyCodeObject *code = _PyFrame_GetCode(frame);
1347     int offset = (int)(instr - _PyCode_CODE(code));
1348     _PyCoMonitoringData *instrumentation_data = code->_co_monitoring;
1349     assert(instrumentation_data->per_instruction_opcodes);
1350     int next_opcode = instrumentation_data->per_instruction_opcodes[offset];
1351     if (tstate->tracing) {
1352         return next_opcode;
1353     }
1354     assert(debug_check_sanity(tstate->interp, code));
1355     PyInterpreterState *interp = tstate->interp;
1356     uint8_t tools = instrumentation_data->per_instruction_tools != NULL ?
1357         instrumentation_data->per_instruction_tools[offset] :
1358         (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] |
1359          code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION]
1360         );
1361     int bytes_offset = offset * (int)sizeof(_Py_CODEUNIT);
1362     PyObject *offset_obj = PyLong_FromLong(bytes_offset);
1363     if (offset_obj == NULL) {
1364         return -1;
1365     }
1366     PyObject *args[3] = { NULL, (PyObject *)code, offset_obj };
1367     while (tools) {
1368         int tool = most_significant_bit(tools);
1369         assert(tool >= 0 && tool < 8);
1370         assert(tools & (1 << tool));
1371         tools &= ~(1 << tool);
1372         int res = call_one_instrument(interp, tstate, &args[1],
1373                                       2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
1374                                       tool, PY_MONITORING_EVENT_INSTRUCTION);
1375         if (res == 0) {
1376             /* Nothing to do */
1377         }
1378         else if (res < 0) {
1379             /* error */
1380             Py_DECREF(offset_obj);
1381             return -1;
1382         }
1383         else {
1384             /* DISABLE  */
1385             LOCK_CODE(code);
1386             remove_per_instruction_tools(code, offset, 1 << tool);
1387             UNLOCK_CODE();
1388         }
1389     }
1390     Py_DECREF(offset_obj);
1391     assert(next_opcode != 0);
1392     return next_opcode;
1393 }
1394 
1395 
1396 PyObject *
_PyMonitoring_RegisterCallback(int tool_id,int event_id,PyObject * obj)1397 _PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj)
1398 {
1399     PyInterpreterState *is = _PyInterpreterState_GET();
1400     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
1401     assert(0 <= event_id && event_id < _PY_MONITORING_EVENTS);
1402     PyObject *callback = _Py_atomic_exchange_ptr(&is->monitoring_callables[tool_id][event_id],
1403                                                  Py_XNewRef(obj));
1404 
1405     return callback;
1406 }
1407 
1408 static void
initialize_tools(PyCodeObject * code)1409 initialize_tools(PyCodeObject *code)
1410 {
1411     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1412     uint8_t* tools = code->_co_monitoring->tools;
1413 
1414     assert(tools != NULL);
1415     int code_len = (int)Py_SIZE(code);
1416     for (int i = 0; i < code_len; i++) {
1417         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
1418         int opcode = instr->op.code;
1419         assert(opcode != ENTER_EXECUTOR);
1420         if (opcode == INSTRUMENTED_LINE) {
1421             opcode = code->_co_monitoring->lines[i].original_opcode;
1422         }
1423         if (opcode == INSTRUMENTED_INSTRUCTION) {
1424             opcode = code->_co_monitoring->per_instruction_opcodes[i];
1425         }
1426         bool instrumented = is_instrumented(opcode);
1427         if (instrumented) {
1428             opcode = DE_INSTRUMENT[opcode];
1429             assert(opcode != 0);
1430         }
1431         opcode = _PyOpcode_Deopt[opcode];
1432         if (opcode_has_event(opcode)) {
1433             if (instrumented) {
1434                 int8_t event;
1435                 if (opcode == RESUME) {
1436                     event = instr->op.arg != 0;
1437                 }
1438                 else {
1439                     event = EVENT_FOR_OPCODE[opcode];
1440                     assert(event > 0);
1441                 }
1442                 assert(event >= 0);
1443                 assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event));
1444                 tools[i] = code->_co_monitoring->active_monitors.tools[event];
1445                 CHECK(tools[i] != 0);
1446             }
1447             else {
1448                 tools[i] = 0;
1449             }
1450         }
1451 #ifdef Py_DEBUG
1452         /* Initialize tools for invalid locations to all ones to try to catch errors */
1453         else {
1454             tools[i] = 0xff;
1455         }
1456         for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) {
1457             tools[i+j] = 0xff;
1458         }
1459 #endif
1460         i += _PyOpcode_Caches[opcode];
1461     }
1462 }
1463 
1464 #define NO_LINE -128
1465 
1466 static void
initialize_lines(PyCodeObject * code)1467 initialize_lines(PyCodeObject *code)
1468 {
1469     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1470     _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
1471 
1472     assert(line_data != NULL);
1473     int code_len = (int)Py_SIZE(code);
1474     PyCodeAddressRange range;
1475     _PyCode_InitAddressRange(code, &range);
1476     for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) {
1477         line_data[i].original_opcode = 0;
1478         line_data[i].line_delta = -127;
1479     }
1480     int current_line = -1;
1481     for (int i = code->_co_firsttraceable; i < code_len; ) {
1482         int opcode = _Py_GetBaseOpcode(code, i);
1483         int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range);
1484         line_data[i].line_delta = compute_line_delta(code, i, line);
1485         int length = _PyInstruction_GetLength(code, i);
1486         switch (opcode) {
1487             case END_ASYNC_FOR:
1488             case END_FOR:
1489             case END_SEND:
1490             case RESUME:
1491                 /* END_FOR cannot start a line, as it is skipped by FOR_ITER
1492                  * END_SEND cannot start a line, as it is skipped by SEND
1493                  * RESUME must not be instrumented with INSTRUMENT_LINE */
1494                 line_data[i].original_opcode = 0;
1495                 break;
1496             default:
1497                 /* Set original_opcode to the opcode iff the instruction
1498                  * starts a line, and thus should be instrumented.
1499                  * This saves having to perform this check every time the
1500                  * we turn instrumentation on or off, and serves as a sanity
1501                  * check when debugging.
1502                  */
1503                 if (line != current_line && line >= 0) {
1504                     line_data[i].original_opcode = opcode;
1505                     if (line_data[i].line_delta == COMPUTED_LINE) {
1506                         /* Label this line as a line with a line number change
1507                          * which could help the monitoring callback to quickly
1508                          * identify the line number change.
1509                          */
1510                         line_data[i].line_delta = COMPUTED_LINE_LINENO_CHANGE;
1511                     }
1512                 }
1513                 else {
1514                     line_data[i].original_opcode = 0;
1515                 }
1516                 current_line = line;
1517         }
1518         for (int j = 1; j < length; j++) {
1519             line_data[i+j].original_opcode = 0;
1520             line_data[i+j].line_delta = NO_LINE;
1521         }
1522         i += length;
1523     }
1524     for (int i = code->_co_firsttraceable; i < code_len; ) {
1525         int opcode = _Py_GetBaseOpcode(code, i);
1526         int oparg = 0;
1527         while (opcode == EXTENDED_ARG) {
1528             oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg;
1529             i++;
1530             opcode = _Py_GetBaseOpcode(code, i);
1531         }
1532         oparg = (oparg << 8) | _PyCode_CODE(code)[i].op.arg;
1533         i += _PyInstruction_GetLength(code, i);
1534         int target = -1;
1535         switch (opcode) {
1536             case POP_JUMP_IF_FALSE:
1537             case POP_JUMP_IF_TRUE:
1538             case POP_JUMP_IF_NONE:
1539             case POP_JUMP_IF_NOT_NONE:
1540             case JUMP_FORWARD:
1541             {
1542                 target = i + oparg;
1543                 break;
1544             }
1545             case FOR_ITER:
1546             case SEND:
1547             {
1548                 /* Skip over END_FOR/END_SEND */
1549                 target = i + oparg + 1;
1550                 break;
1551             }
1552             case JUMP_BACKWARD:
1553             case JUMP_BACKWARD_NO_INTERRUPT:
1554             {
1555                 target = i - oparg;
1556                 break;
1557             }
1558             default:
1559                 continue;
1560         }
1561         assert(target >= 0);
1562         if (line_data[target].line_delta != NO_LINE) {
1563             line_data[target].original_opcode = _Py_GetBaseOpcode(code, target);
1564             if (line_data[target].line_delta == COMPUTED_LINE_LINENO_CHANGE) {
1565                 // If the line is a jump target, we are not sure if the line
1566                 // number changes, so we set it to COMPUTED_LINE.
1567                 line_data[target].line_delta = COMPUTED_LINE;
1568             }
1569         }
1570     }
1571     /* Scan exception table */
1572     unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code->co_exceptiontable);
1573     unsigned char *end = start + PyBytes_GET_SIZE(code->co_exceptiontable);
1574     unsigned char *scan = start;
1575     while (scan < end) {
1576         int start_offset, size, handler;
1577         scan = parse_varint(scan, &start_offset);
1578         assert(start_offset >= 0 && start_offset < code_len);
1579         scan = parse_varint(scan, &size);
1580         assert(size >= 0 && start_offset+size <= code_len);
1581         scan = parse_varint(scan, &handler);
1582         assert(handler >= 0 && handler < code_len);
1583         int depth_and_lasti;
1584         scan = parse_varint(scan, &depth_and_lasti);
1585         int original_opcode = _Py_GetBaseOpcode(code, handler);
1586         /* Skip if not the start of a line.
1587          * END_ASYNC_FOR is a bit special as it marks the end of
1588          * an `async for` loop, which should not generate its own
1589          * line event. */
1590         if (line_data[handler].line_delta != NO_LINE &&
1591             original_opcode != END_ASYNC_FOR) {
1592             line_data[handler].original_opcode = original_opcode;
1593         }
1594     }
1595 }
1596 
1597 static void
initialize_line_tools(PyCodeObject * code,_Py_LocalMonitors * all_events)1598 initialize_line_tools(PyCodeObject *code, _Py_LocalMonitors *all_events)
1599 {
1600     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1601     uint8_t *line_tools = code->_co_monitoring->line_tools;
1602 
1603     assert(line_tools != NULL);
1604     int code_len = (int)Py_SIZE(code);
1605     for (int i = 0; i < code_len; i++) {
1606         line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE];
1607     }
1608 }
1609 
1610 static int
allocate_instrumentation_data(PyCodeObject * code)1611 allocate_instrumentation_data(PyCodeObject *code)
1612 {
1613     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1614 
1615     if (code->_co_monitoring == NULL) {
1616         code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData));
1617         if (code->_co_monitoring == NULL) {
1618             PyErr_NoMemory();
1619             return -1;
1620         }
1621         code->_co_monitoring->local_monitors = (_Py_LocalMonitors){ 0 };
1622         code->_co_monitoring->active_monitors = (_Py_LocalMonitors){ 0 };
1623         code->_co_monitoring->tools = NULL;
1624         code->_co_monitoring->lines = NULL;
1625         code->_co_monitoring->line_tools = NULL;
1626         code->_co_monitoring->per_instruction_opcodes = NULL;
1627         code->_co_monitoring->per_instruction_tools = NULL;
1628     }
1629     return 0;
1630 }
1631 
1632 static int
update_instrumentation_data(PyCodeObject * code,PyInterpreterState * interp)1633 update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
1634 {
1635     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1636 
1637     int code_len = (int)Py_SIZE(code);
1638     if (allocate_instrumentation_data(code)) {
1639         return -1;
1640     }
1641     _Py_LocalMonitors all_events = local_union(
1642         interp->monitors,
1643         code->_co_monitoring->local_monitors);
1644     bool multitools = multiple_tools(&all_events);
1645     if (code->_co_monitoring->tools == NULL && multitools) {
1646         code->_co_monitoring->tools = PyMem_Malloc(code_len);
1647         if (code->_co_monitoring->tools == NULL) {
1648             PyErr_NoMemory();
1649             return -1;
1650         }
1651         initialize_tools(code);
1652     }
1653     if (all_events.tools[PY_MONITORING_EVENT_LINE]) {
1654         if (code->_co_monitoring->lines == NULL) {
1655             code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData));
1656             if (code->_co_monitoring->lines == NULL) {
1657                 PyErr_NoMemory();
1658                 return -1;
1659             }
1660             initialize_lines(code);
1661         }
1662         if (multitools && code->_co_monitoring->line_tools == NULL) {
1663             code->_co_monitoring->line_tools = PyMem_Malloc(code_len);
1664             if (code->_co_monitoring->line_tools == NULL) {
1665                 PyErr_NoMemory();
1666                 return -1;
1667             }
1668             initialize_line_tools(code, &all_events);
1669         }
1670     }
1671     if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) {
1672         if (code->_co_monitoring->per_instruction_opcodes == NULL) {
1673             code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData));
1674             if (code->_co_monitoring->per_instruction_opcodes == NULL) {
1675                 PyErr_NoMemory();
1676                 return -1;
1677             }
1678             // Initialize all of the instructions so if local events change while another thread is executing
1679             // we know what the original opcode was.
1680             for (int i = 0; i < code_len; i++) {
1681                 int opcode = _PyCode_CODE(code)[i].op.code;
1682                 code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode];
1683             }
1684         }
1685         if (multitools && code->_co_monitoring->per_instruction_tools == NULL) {
1686             code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len);
1687             if (code->_co_monitoring->per_instruction_tools == NULL) {
1688                 PyErr_NoMemory();
1689                 return -1;
1690             }
1691             for (int i = 0; i < code_len; i++) {
1692                 code->_co_monitoring->per_instruction_tools[i] = 0;
1693             }
1694         }
1695     }
1696     return 0;
1697 }
1698 
1699 static int
force_instrument_lock_held(PyCodeObject * code,PyInterpreterState * interp)1700 force_instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1701 {
1702     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1703 
1704 #ifdef _Py_TIER2
1705     if (code->co_executors != NULL) {
1706         _PyCode_Clear_Executors(code);
1707     }
1708     _Py_Executors_InvalidateDependency(interp, code, 1);
1709 #endif
1710     int code_len = (int)Py_SIZE(code);
1711     /* Exit early to avoid creating instrumentation
1712      * data for potential statically allocated code
1713      * objects.
1714      * See https://github.com/python/cpython/issues/108390 */
1715     if (code->co_flags & CO_NO_MONITORING_EVENTS) {
1716         return 0;
1717     }
1718     if (update_instrumentation_data(code, interp)) {
1719         return -1;
1720     }
1721     _Py_LocalMonitors active_events = local_union(
1722         interp->monitors,
1723         code->_co_monitoring->local_monitors);
1724     _Py_LocalMonitors new_events;
1725     _Py_LocalMonitors removed_events;
1726 
1727     bool restarted = interp->last_restart_version > code->_co_instrumentation_version;
1728     if (restarted) {
1729         removed_events = code->_co_monitoring->active_monitors;
1730         new_events = active_events;
1731     }
1732     else {
1733         removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events);
1734         new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors);
1735         assert(monitors_are_empty(monitors_and(new_events, removed_events)));
1736     }
1737     code->_co_monitoring->active_monitors = active_events;
1738     if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) {
1739         goto done;
1740     }
1741     /* Insert instrumentation */
1742     for (int i = code->_co_firsttraceable; i < code_len; i+= _PyInstruction_GetLength(code, i)) {
1743         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
1744         CHECK(instr->op.code != 0);
1745         assert(instr->op.code != ENTER_EXECUTOR);
1746         int base_opcode = _Py_GetBaseOpcode(code, i);
1747         assert(base_opcode != ENTER_EXECUTOR);
1748         if (opcode_has_event(base_opcode)) {
1749             int8_t event;
1750             if (base_opcode == RESUME) {
1751                 event = instr->op.arg > 0;
1752             }
1753             else {
1754                 event = EVENT_FOR_OPCODE[base_opcode];
1755                 assert(event > 0);
1756             }
1757             uint8_t removed_tools = removed_events.tools[event];
1758             if (removed_tools) {
1759                 remove_tools(code, i, event, removed_tools);
1760             }
1761             uint8_t new_tools = new_events.tools[event];
1762             if (new_tools) {
1763                 add_tools(code, i, event, new_tools);
1764             }
1765         }
1766     }
1767 
1768     // GH-103845: We need to remove both the line and instruction instrumentation before
1769     // adding new ones, otherwise we may remove the newly added instrumentation.
1770     uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE];
1771     uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1772 
1773     if (removed_line_tools) {
1774         _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
1775         for (int i = code->_co_firsttraceable; i < code_len;) {
1776             if (line_data[i].original_opcode) {
1777                 remove_line_tools(code, i, removed_line_tools);
1778             }
1779             i += _PyInstruction_GetLength(code, i);
1780         }
1781     }
1782     if (removed_per_instruction_tools) {
1783         for (int i = code->_co_firsttraceable; i < code_len;) {
1784             int opcode = _Py_GetBaseOpcode(code, i);
1785             if (opcode == RESUME || opcode == END_FOR) {
1786                 i += _PyInstruction_GetLength(code, i);
1787                 continue;
1788             }
1789             remove_per_instruction_tools(code, i, removed_per_instruction_tools);
1790             i += _PyInstruction_GetLength(code, i);
1791         }
1792     }
1793 #ifdef INSTRUMENT_DEBUG
1794     sanity_check_instrumentation(code);
1795 #endif
1796 
1797     uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];
1798     uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
1799 
1800     if (new_line_tools) {
1801         _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
1802         for (int i = code->_co_firsttraceable; i < code_len;) {
1803             if (line_data[i].original_opcode) {
1804                 add_line_tools(code, i, new_line_tools);
1805             }
1806             i += _PyInstruction_GetLength(code, i);
1807         }
1808     }
1809     if (new_per_instruction_tools) {
1810         for (int i = code->_co_firsttraceable; i < code_len;) {
1811             int opcode = _Py_GetBaseOpcode(code, i);
1812             if (opcode == RESUME || opcode == END_FOR) {
1813                 i += _PyInstruction_GetLength(code, i);
1814                 continue;
1815             }
1816             add_per_instruction_tools(code, i, new_per_instruction_tools);
1817             i += _PyInstruction_GetLength(code, i);
1818         }
1819     }
1820 
1821 done:
1822     FT_ATOMIC_STORE_UINTPTR_RELEASE(code->_co_instrumentation_version,
1823                                     global_version(interp));
1824 
1825 #ifdef INSTRUMENT_DEBUG
1826     sanity_check_instrumentation(code);
1827 #endif
1828     return 0;
1829 }
1830 
1831 static int
instrument_lock_held(PyCodeObject * code,PyInterpreterState * interp)1832 instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1833 {
1834     ASSERT_WORLD_STOPPED_OR_LOCKED(code);
1835 
1836     if (is_version_up_to_date(code, interp)) {
1837         assert(
1838             interp->ceval.instrumentation_version == 0 ||
1839             instrumentation_cross_checks(interp, code)
1840         );
1841         return 0;
1842     }
1843 
1844     return force_instrument_lock_held(code, interp);
1845 }
1846 
1847 int
_Py_Instrument(PyCodeObject * code,PyInterpreterState * interp)1848 _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
1849 {
1850     int res;
1851     LOCK_CODE(code);
1852     res = instrument_lock_held(code, interp);
1853     UNLOCK_CODE();
1854     return res;
1855 }
1856 
1857 #define C_RETURN_EVENTS \
1858     ((1 << PY_MONITORING_EVENT_C_RETURN) | \
1859      (1 << PY_MONITORING_EVENT_C_RAISE))
1860 
1861 #define C_CALL_EVENTS \
1862     (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL))
1863 
1864 
1865 static int
instrument_all_executing_code_objects(PyInterpreterState * interp)1866 instrument_all_executing_code_objects(PyInterpreterState *interp) {
1867     ASSERT_WORLD_STOPPED();
1868 
1869     _PyRuntimeState *runtime = &_PyRuntime;
1870     HEAD_LOCK(runtime);
1871     PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
1872     HEAD_UNLOCK(runtime);
1873     while (ts) {
1874         _PyInterpreterFrame *frame = ts->current_frame;
1875         while (frame) {
1876             if (frame->owner != FRAME_OWNED_BY_CSTACK) {
1877                 if (instrument_lock_held(_PyFrame_GetCode(frame), interp)) {
1878                     return -1;
1879                 }
1880             }
1881             frame = frame->previous;
1882         }
1883         HEAD_LOCK(runtime);
1884         ts = PyThreadState_Next(ts);
1885         HEAD_UNLOCK(runtime);
1886     }
1887     return 0;
1888 }
1889 
1890 static void
set_events(_Py_GlobalMonitors * m,int tool_id,_PyMonitoringEventSet events)1891 set_events(_Py_GlobalMonitors *m, int tool_id, _PyMonitoringEventSet events)
1892 {
1893     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
1894     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) {
1895         uint8_t *tools = &m->tools[e];
1896         int active = (events >> e) & 1;
1897         *tools &= ~(1 << tool_id);
1898         *tools |= (active << tool_id);
1899     }
1900 }
1901 
1902 static void
set_local_events(_Py_LocalMonitors * m,int tool_id,_PyMonitoringEventSet events)1903 set_local_events(_Py_LocalMonitors *m, int tool_id, _PyMonitoringEventSet events)
1904 {
1905     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
1906     for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) {
1907         uint8_t *tools = &m->tools[e];
1908         int val = (events >> e) & 1;
1909         *tools &= ~(1 << tool_id);
1910         *tools |= (val << tool_id);
1911     }
1912 }
1913 
1914 static int
check_tool(PyInterpreterState * interp,int tool_id)1915 check_tool(PyInterpreterState *interp, int tool_id)
1916 {
1917     if (tool_id < PY_MONITORING_SYS_PROFILE_ID &&
1918         interp->monitoring_tool_names[tool_id] == NULL)
1919     {
1920         PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id);
1921         return -1;
1922     }
1923     return 0;
1924 }
1925 
1926 /* We share the eval-breaker with flags, so the monitoring
1927  * version goes in the top 24 bits */
1928 #define MONITORING_VERSION_INCREMENT (1 << _PY_EVAL_EVENTS_BITS)
1929 
1930 int
_PyMonitoring_SetEvents(int tool_id,_PyMonitoringEventSet events)1931 _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
1932 {
1933     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
1934     PyThreadState *tstate = _PyThreadState_GET();
1935     PyInterpreterState *interp = tstate->interp;
1936     assert(events < (1 << _PY_MONITORING_UNGROUPED_EVENTS));
1937     if (check_tool(interp, tool_id)) {
1938         return -1;
1939     }
1940 
1941     int res;
1942     _PyEval_StopTheWorld(interp);
1943     uint32_t existing_events = get_events(&interp->monitors, tool_id);
1944     if (existing_events == events) {
1945         res = 0;
1946         goto done;
1947     }
1948     set_events(&interp->monitors, tool_id, events);
1949     uint32_t new_version = global_version(interp) + MONITORING_VERSION_INCREMENT;
1950     if (new_version == 0) {
1951         PyErr_Format(PyExc_OverflowError, "events set too many times");
1952         res = -1;
1953         goto done;
1954     }
1955     set_global_version(tstate, new_version);
1956 #ifdef _Py_TIER2
1957     _Py_Executors_InvalidateAll(interp, 1);
1958 #endif
1959     res = instrument_all_executing_code_objects(interp);
1960 done:
1961     _PyEval_StartTheWorld(interp);
1962     return res;
1963 }
1964 
1965 int
_PyMonitoring_SetLocalEvents(PyCodeObject * code,int tool_id,_PyMonitoringEventSet events)1966 _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events)
1967 {
1968     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
1969     PyInterpreterState *interp = _PyInterpreterState_GET();
1970     assert(events < (1 << _PY_MONITORING_LOCAL_EVENTS));
1971     if (code->_co_firsttraceable >= Py_SIZE(code)) {
1972         PyErr_Format(PyExc_SystemError, "cannot instrument shim code object '%U'", code->co_name);
1973         return -1;
1974     }
1975     if (check_tool(interp, tool_id)) {
1976         return -1;
1977     }
1978 
1979     int res;
1980     _PyEval_StopTheWorld(interp);
1981     if (allocate_instrumentation_data(code)) {
1982         res = -1;
1983         goto done;
1984     }
1985 
1986     _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors;
1987     uint32_t existing_events = get_local_events(local, tool_id);
1988     if (existing_events == events) {
1989         res = 0;
1990         goto done;
1991     }
1992     set_local_events(local, tool_id, events);
1993 
1994     res = force_instrument_lock_held(code, interp);
1995 
1996 done:
1997     _PyEval_StartTheWorld(interp);
1998     return res;
1999 }
2000 
2001 int
_PyMonitoring_GetLocalEvents(PyCodeObject * code,int tool_id,_PyMonitoringEventSet * events)2002 _PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events)
2003 {
2004     assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
2005     PyInterpreterState *interp = _PyInterpreterState_GET();
2006     if (check_tool(interp, tool_id)) {
2007         return -1;
2008     }
2009     if (code->_co_monitoring == NULL) {
2010         *events = 0;
2011         return 0;
2012     }
2013     _Py_LocalMonitors *local = &code->_co_monitoring->local_monitors;
2014     *events = get_local_events(local, tool_id);
2015     return 0;
2016 }
2017 
2018 /*[clinic input]
2019 module monitoring
2020 [clinic start generated code]*/
2021 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/
2022 /*[clinic end generated code]*/
2023 
2024 #include "clinic/instrumentation.c.h"
2025 
2026 static int
check_valid_tool(int tool_id)2027 check_valid_tool(int tool_id)
2028 {
2029     if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) {
2030         PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id);
2031         return -1;
2032     }
2033     return 0;
2034 }
2035 
2036 /*[clinic input]
2037 monitoring.use_tool_id
2038 
2039     tool_id: int
2040     name: object
2041     /
2042 
2043 [clinic start generated code]*/
2044 
2045 static PyObject *
monitoring_use_tool_id_impl(PyObject * module,int tool_id,PyObject * name)2046 monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name)
2047 /*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/
2048 {
2049     if (check_valid_tool(tool_id))  {
2050         return NULL;
2051     }
2052     if (!PyUnicode_Check(name)) {
2053         PyErr_SetString(PyExc_ValueError, "tool name must be a str");
2054         return NULL;
2055     }
2056     PyInterpreterState *interp = _PyInterpreterState_GET();
2057     if (interp->monitoring_tool_names[tool_id] != NULL) {
2058         PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id);
2059         return NULL;
2060     }
2061     interp->monitoring_tool_names[tool_id] = Py_NewRef(name);
2062     Py_RETURN_NONE;
2063 }
2064 
2065 /*[clinic input]
2066 monitoring.free_tool_id
2067 
2068     tool_id: int
2069     /
2070 
2071 [clinic start generated code]*/
2072 
2073 static PyObject *
monitoring_free_tool_id_impl(PyObject * module,int tool_id)2074 monitoring_free_tool_id_impl(PyObject *module, int tool_id)
2075 /*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/
2076 {
2077     if (check_valid_tool(tool_id))  {
2078         return NULL;
2079     }
2080     PyInterpreterState *interp = _PyInterpreterState_GET();
2081     Py_CLEAR(interp->monitoring_tool_names[tool_id]);
2082     Py_RETURN_NONE;
2083 }
2084 
2085 /*[clinic input]
2086 monitoring.get_tool
2087 
2088     tool_id: int
2089     /
2090 
2091 [clinic start generated code]*/
2092 
2093 static PyObject *
monitoring_get_tool_impl(PyObject * module,int tool_id)2094 monitoring_get_tool_impl(PyObject *module, int tool_id)
2095 /*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/
2096 
2097 /*[clinic end generated code]*/
2098 {
2099     if (check_valid_tool(tool_id))  {
2100         return NULL;
2101     }
2102     PyInterpreterState *interp = _PyInterpreterState_GET();
2103     PyObject *name = interp->monitoring_tool_names[tool_id];
2104     if (name == NULL) {
2105         Py_RETURN_NONE;
2106     }
2107     return Py_NewRef(name);
2108 }
2109 
2110 /*[clinic input]
2111 monitoring.register_callback
2112 
2113 
2114     tool_id: int
2115     event: int
2116     func: object
2117     /
2118 
2119 [clinic start generated code]*/
2120 
2121 static PyObject *
monitoring_register_callback_impl(PyObject * module,int tool_id,int event,PyObject * func)2122 monitoring_register_callback_impl(PyObject *module, int tool_id, int event,
2123                                   PyObject *func)
2124 /*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/
2125 {
2126     if (check_valid_tool(tool_id))  {
2127         return NULL;
2128     }
2129     if (_Py_popcount32(event) != 1) {
2130         PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time");
2131         return NULL;
2132     }
2133     int event_id = _Py_bit_length(event)-1;
2134     if (event_id < 0 || event_id >= _PY_MONITORING_EVENTS) {
2135         PyErr_Format(PyExc_ValueError, "invalid event %d", event);
2136         return NULL;
2137     }
2138     if (PySys_Audit("sys.monitoring.register_callback", "O", func) < 0) {
2139         return NULL;
2140     }
2141     if (func == Py_None) {
2142         func = NULL;
2143     }
2144     func = _PyMonitoring_RegisterCallback(tool_id, event_id, func);
2145     if (func == NULL) {
2146         Py_RETURN_NONE;
2147     }
2148     return func;
2149 }
2150 
2151 /*[clinic input]
2152 monitoring.get_events -> int
2153 
2154     tool_id: int
2155     /
2156 
2157 [clinic start generated code]*/
2158 
2159 static int
monitoring_get_events_impl(PyObject * module,int tool_id)2160 monitoring_get_events_impl(PyObject *module, int tool_id)
2161 /*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/
2162 {
2163     if (check_valid_tool(tool_id))  {
2164         return -1;
2165     }
2166     _Py_GlobalMonitors *m = &_PyInterpreterState_GET()->monitors;
2167     _PyMonitoringEventSet event_set = get_events(m, tool_id);
2168     return event_set;
2169 }
2170 
2171 /*[clinic input]
2172 monitoring.set_events
2173 
2174     tool_id: int
2175     event_set: int
2176     /
2177 
2178 [clinic start generated code]*/
2179 
2180 static PyObject *
monitoring_set_events_impl(PyObject * module,int tool_id,int event_set)2181 monitoring_set_events_impl(PyObject *module, int tool_id, int event_set)
2182 /*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/
2183 {
2184     if (check_valid_tool(tool_id))  {
2185         return NULL;
2186     }
2187     if (event_set < 0 || event_set >= (1 << _PY_MONITORING_EVENTS)) {
2188         PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set);
2189         return NULL;
2190     }
2191     if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) {
2192         PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently");
2193         return NULL;
2194     }
2195     event_set &= ~C_RETURN_EVENTS;
2196     if (_PyMonitoring_SetEvents(tool_id, event_set)) {
2197         return NULL;
2198     }
2199     Py_RETURN_NONE;
2200 }
2201 
2202 /*[clinic input]
2203 monitoring.get_local_events -> int
2204 
2205     tool_id: int
2206     code: object
2207     /
2208 
2209 [clinic start generated code]*/
2210 
2211 static int
monitoring_get_local_events_impl(PyObject * module,int tool_id,PyObject * code)2212 monitoring_get_local_events_impl(PyObject *module, int tool_id,
2213                                  PyObject *code)
2214 /*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/
2215 {
2216     if (!PyCode_Check(code)) {
2217         PyErr_Format(
2218             PyExc_TypeError,
2219             "code must be a code object"
2220         );
2221         return -1;
2222     }
2223     if (check_valid_tool(tool_id))  {
2224         return -1;
2225     }
2226     _PyMonitoringEventSet event_set = 0;
2227     _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring;
2228     if (data != NULL) {
2229         for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) {
2230             if ((data->local_monitors.tools[e] >> tool_id) & 1) {
2231                 event_set |= (1 << e);
2232             }
2233         }
2234     }
2235     return event_set;
2236 }
2237 
2238 /*[clinic input]
2239 monitoring.set_local_events
2240 
2241     tool_id: int
2242     code: object
2243     event_set: int
2244     /
2245 
2246 [clinic start generated code]*/
2247 
2248 static PyObject *
monitoring_set_local_events_impl(PyObject * module,int tool_id,PyObject * code,int event_set)2249 monitoring_set_local_events_impl(PyObject *module, int tool_id,
2250                                  PyObject *code, int event_set)
2251 /*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/
2252 {
2253     if (!PyCode_Check(code)) {
2254         PyErr_Format(
2255             PyExc_TypeError,
2256             "code must be a code object"
2257         );
2258         return NULL;
2259     }
2260     if (check_valid_tool(tool_id))  {
2261         return NULL;
2262     }
2263     if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) {
2264         PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently");
2265         return NULL;
2266     }
2267     event_set &= ~C_RETURN_EVENTS;
2268     if (event_set < 0 || event_set >= (1 << _PY_MONITORING_LOCAL_EVENTS)) {
2269         PyErr_Format(PyExc_ValueError, "invalid local event set 0x%x", event_set);
2270         return NULL;
2271     }
2272 
2273     if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) {
2274         return NULL;
2275     }
2276     Py_RETURN_NONE;
2277 }
2278 
2279 /*[clinic input]
2280 monitoring.restart_events
2281 
2282 [clinic start generated code]*/
2283 
2284 static PyObject *
monitoring_restart_events_impl(PyObject * module)2285 monitoring_restart_events_impl(PyObject *module)
2286 /*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/
2287 {
2288     /* We want to ensure that:
2289      * last restart version > instrumented version for all code objects
2290      * last restart version < current version
2291      */
2292     PyThreadState *tstate = _PyThreadState_GET();
2293     PyInterpreterState *interp = tstate->interp;
2294 
2295     _PyEval_StopTheWorld(interp);
2296     uint32_t restart_version = global_version(interp) + MONITORING_VERSION_INCREMENT;
2297     uint32_t new_version = restart_version + MONITORING_VERSION_INCREMENT;
2298     if (new_version <= MONITORING_VERSION_INCREMENT) {
2299         _PyEval_StartTheWorld(interp);
2300         PyErr_Format(PyExc_OverflowError, "events set too many times");
2301         return NULL;
2302     }
2303     interp->last_restart_version = restart_version;
2304     set_global_version(tstate, new_version);
2305     int res = instrument_all_executing_code_objects(interp);
2306     _PyEval_StartTheWorld(interp);
2307 
2308     if (res) {
2309         return NULL;
2310     }
2311     Py_RETURN_NONE;
2312 }
2313 
2314 static int
add_power2_constant(PyObject * obj,const char * name,int i)2315 add_power2_constant(PyObject *obj, const char *name, int i)
2316 {
2317     PyObject *val = PyLong_FromLong(1<<i);
2318     if (val == NULL) {
2319         return -1;
2320     }
2321     int err = PyObject_SetAttrString(obj, name, val);
2322     Py_DECREF(val);
2323     return err;
2324 }
2325 
2326 /*[clinic input]
2327 monitoring._all_events
2328 [clinic start generated code]*/
2329 
2330 static PyObject *
monitoring__all_events_impl(PyObject * module)2331 monitoring__all_events_impl(PyObject *module)
2332 /*[clinic end generated code: output=6b7581e2dbb690f6 input=62ee9672c17b7f0e]*/
2333 {
2334     PyInterpreterState *interp = _PyInterpreterState_GET();
2335     PyObject *res = PyDict_New();
2336     if (res == NULL) {
2337         return NULL;
2338     }
2339     for (int e = 0; e < _PY_MONITORING_UNGROUPED_EVENTS; e++) {
2340         uint8_t tools = interp->monitors.tools[e];
2341         if (tools == 0) {
2342             continue;
2343         }
2344         PyObject *tools_obj = PyLong_FromLong(tools);
2345         assert(tools_obj != NULL);
2346         int err = PyDict_SetItemString(res, event_names[e], tools_obj);
2347         Py_DECREF(tools_obj);
2348         if (err < 0) {
2349             Py_DECREF(res);
2350             return NULL;
2351         }
2352     }
2353     return res;
2354 }
2355 
2356 static PyMethodDef methods[] = {
2357     MONITORING_USE_TOOL_ID_METHODDEF
2358     MONITORING_FREE_TOOL_ID_METHODDEF
2359     MONITORING_GET_TOOL_METHODDEF
2360     MONITORING_REGISTER_CALLBACK_METHODDEF
2361     MONITORING_GET_EVENTS_METHODDEF
2362     MONITORING_SET_EVENTS_METHODDEF
2363     MONITORING_GET_LOCAL_EVENTS_METHODDEF
2364     MONITORING_SET_LOCAL_EVENTS_METHODDEF
2365     MONITORING_RESTART_EVENTS_METHODDEF
2366     MONITORING__ALL_EVENTS_METHODDEF
2367     {NULL, NULL}  // sentinel
2368 };
2369 
2370 static struct PyModuleDef monitoring_module = {
2371     PyModuleDef_HEAD_INIT,
2372     .m_name = "sys.monitoring",
2373     .m_size = -1, /* multiple "initialization" just copies the module dict. */
2374     .m_methods = methods,
2375 };
2376 
_Py_CreateMonitoringObject(void)2377 PyObject *_Py_CreateMonitoringObject(void)
2378 {
2379     PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION);
2380     if (mod == NULL) {
2381         return NULL;
2382     }
2383     if (PyObject_SetAttrString(mod, "DISABLE", &_PyInstrumentation_DISABLE)) {
2384         goto error;
2385     }
2386     if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) {
2387         goto error;
2388     }
2389     PyObject *events = _PyNamespace_New(NULL);
2390     if (events == NULL) {
2391         goto error;
2392     }
2393     int err = PyObject_SetAttrString(mod, "events", events);
2394     Py_DECREF(events);
2395     if (err) {
2396         goto error;
2397     }
2398     for (int i = 0; i < _PY_MONITORING_EVENTS; i++) {
2399         if (add_power2_constant(events, event_names[i], i)) {
2400             goto error;
2401         }
2402     }
2403     err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero());
2404     if (err) goto error;
2405     PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID);
2406     err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val);
2407     Py_DECREF(val);
2408     if (err) goto error;
2409     val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID);
2410     err = PyObject_SetAttrString(mod, "COVERAGE_ID", val);
2411     Py_DECREF(val);
2412     if (err) goto error;
2413     val = PyLong_FromLong(PY_MONITORING_PROFILER_ID);
2414     err = PyObject_SetAttrString(mod, "PROFILER_ID", val);
2415     Py_DECREF(val);
2416     if (err) goto error;
2417     val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID);
2418     err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val);
2419     Py_DECREF(val);
2420     if (err) goto error;
2421     return mod;
2422 error:
2423     Py_DECREF(mod);
2424     return NULL;
2425 }
2426 
2427 
2428 static int
capi_call_instrumentation(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject ** args,Py_ssize_t nargs,int event)2429 capi_call_instrumentation(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2430                           PyObject **args, Py_ssize_t nargs, int event)
2431 {
2432     PyThreadState *tstate = _PyThreadState_GET();
2433     PyInterpreterState *interp = tstate->interp;
2434 
2435     uint8_t tools = state->active;
2436     assert(args[1] == NULL);
2437     args[1] = codelike;
2438     if (offset < 0) {
2439         PyErr_SetString(PyExc_ValueError, "offset must be non-negative");
2440         return -1;
2441     }
2442     if (event != PY_MONITORING_EVENT_LINE) {
2443         PyObject *offset_obj = PyLong_FromLong(offset);
2444         if (offset_obj == NULL) {
2445             return -1;
2446         }
2447         assert(args[2] == NULL);
2448         args[2] = offset_obj;
2449     }
2450     size_t nargsf = (size_t) nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
2451     PyObject **callargs = &args[1];
2452     int err = 0;
2453 
2454     while (tools) {
2455         int tool = most_significant_bit(tools);
2456         assert(tool >= 0 && tool < 8);
2457         assert(tools & (1 << tool));
2458         tools ^= (1 << tool);
2459         int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event);
2460         if (res == 0) {
2461             /* Nothing to do */
2462         }
2463         else if (res < 0) {
2464             /* error */
2465             err = -1;
2466             break;
2467         }
2468         else {
2469             /* DISABLE */
2470             if (!PY_MONITORING_IS_INSTRUMENTED_EVENT(event)) {
2471                 PyErr_Format(PyExc_ValueError,
2472                              "Cannot disable %s events. Callback removed.",
2473                              event_names[event]);
2474                 /* Clear tool to prevent infinite loop */
2475                 Py_CLEAR(interp->monitoring_callables[tool][event]);
2476                 err = -1;
2477                 break;
2478             }
2479             else {
2480                 state->active &= ~(1 << tool);
2481             }
2482         }
2483     }
2484     return err;
2485 }
2486 
2487 int
PyMonitoring_EnterScope(PyMonitoringState * state_array,uint64_t * version,const uint8_t * event_types,Py_ssize_t length)2488 PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version,
2489                          const uint8_t *event_types, Py_ssize_t length)
2490 {
2491     PyInterpreterState *interp = _PyInterpreterState_GET();
2492     if (global_version(interp) == *version) {
2493         return 0;
2494     }
2495 
2496     _Py_GlobalMonitors *m = &interp->monitors;
2497     for (Py_ssize_t i = 0; i < length; i++) {
2498         int event = event_types[i];
2499         state_array[i].active = m->tools[event];
2500     }
2501     *version = global_version(interp);
2502     return 0;
2503 }
2504 
2505 int
PyMonitoring_ExitScope(void)2506 PyMonitoring_ExitScope(void)
2507 {
2508     return 0;
2509 }
2510 
2511 int
_PyMonitoring_FirePyStartEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2512 _PyMonitoring_FirePyStartEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2513 {
2514     assert(state->active);
2515     PyObject *args[3] = { NULL, NULL, NULL };
2516     return capi_call_instrumentation(state, codelike, offset, args, 2,
2517                                      PY_MONITORING_EVENT_PY_START);
2518 }
2519 
2520 int
_PyMonitoring_FirePyResumeEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2521 _PyMonitoring_FirePyResumeEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2522 {
2523     assert(state->active);
2524     PyObject *args[3] = { NULL, NULL, NULL };
2525     return capi_call_instrumentation(state, codelike, offset, args, 2,
2526                                      PY_MONITORING_EVENT_PY_RESUME);
2527 }
2528 
2529 
2530 
2531 int
_PyMonitoring_FirePyReturnEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * retval)2532 _PyMonitoring_FirePyReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2533                                 PyObject* retval)
2534 {
2535     assert(state->active);
2536     PyObject *args[4] = { NULL, NULL, NULL, retval };
2537     return capi_call_instrumentation(state, codelike, offset, args, 3,
2538                                      PY_MONITORING_EVENT_PY_RETURN);
2539 }
2540 
2541 int
_PyMonitoring_FirePyYieldEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * retval)2542 _PyMonitoring_FirePyYieldEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2543                                PyObject* retval)
2544 {
2545     assert(state->active);
2546     PyObject *args[4] = { NULL, NULL, NULL, retval };
2547     return capi_call_instrumentation(state, codelike, offset, args, 3,
2548                                      PY_MONITORING_EVENT_PY_YIELD);
2549 }
2550 
2551 int
_PyMonitoring_FireCallEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * callable,PyObject * arg0)2552 _PyMonitoring_FireCallEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2553                             PyObject* callable, PyObject *arg0)
2554 {
2555     assert(state->active);
2556     PyObject *args[5] = { NULL, NULL, NULL, callable, arg0 };
2557     return capi_call_instrumentation(state, codelike, offset, args, 4,
2558                                      PY_MONITORING_EVENT_CALL);
2559 }
2560 
2561 int
_PyMonitoring_FireLineEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,int lineno)2562 _PyMonitoring_FireLineEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2563                             int lineno)
2564 {
2565     assert(state->active);
2566     PyObject *lno = PyLong_FromLong(lineno);
2567     if (lno == NULL) {
2568         return -1;
2569     }
2570     PyObject *args[3] = { NULL, NULL, lno };
2571     int res= capi_call_instrumentation(state, codelike, offset, args, 2,
2572                                        PY_MONITORING_EVENT_LINE);
2573     Py_DECREF(lno);
2574     return res;
2575 }
2576 
2577 int
_PyMonitoring_FireJumpEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * target_offset)2578 _PyMonitoring_FireJumpEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2579                             PyObject *target_offset)
2580 {
2581     assert(state->active);
2582     PyObject *args[4] = { NULL, NULL, NULL, target_offset };
2583     return capi_call_instrumentation(state, codelike, offset, args, 3,
2584                                      PY_MONITORING_EVENT_JUMP);
2585 }
2586 
2587 int
_PyMonitoring_FireBranchEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * target_offset)2588 _PyMonitoring_FireBranchEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2589                               PyObject *target_offset)
2590 {
2591     assert(state->active);
2592     PyObject *args[4] = { NULL, NULL, NULL, target_offset };
2593     return capi_call_instrumentation(state, codelike, offset, args, 3,
2594                                      PY_MONITORING_EVENT_BRANCH);
2595 }
2596 
2597 int
_PyMonitoring_FireCReturnEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * retval)2598 _PyMonitoring_FireCReturnEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset,
2599                                PyObject *retval)
2600 {
2601     assert(state->active);
2602     PyObject *args[4] = { NULL, NULL, NULL, retval };
2603     return capi_call_instrumentation(state, codelike, offset, args, 3,
2604                                      PY_MONITORING_EVENT_C_RETURN);
2605 }
2606 
2607 static inline int
exception_event_setup(PyObject ** exc,int event)2608 exception_event_setup(PyObject **exc, int event) {
2609     *exc = PyErr_GetRaisedException();
2610     if (*exc == NULL) {
2611         PyErr_Format(PyExc_ValueError,
2612                      "Firing event %d with no exception set",
2613                      event);
2614         return -1;
2615     }
2616     return 0;
2617 }
2618 
2619 
2620 static inline int
exception_event_teardown(int err,PyObject * exc)2621 exception_event_teardown(int err, PyObject *exc) {
2622     if (err == 0) {
2623         PyErr_SetRaisedException(exc);
2624     }
2625     else {
2626         assert(PyErr_Occurred());
2627         Py_XDECREF(exc);
2628     }
2629     return err;
2630 }
2631 
2632 int
_PyMonitoring_FirePyThrowEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2633 _PyMonitoring_FirePyThrowEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2634 {
2635     int event = PY_MONITORING_EVENT_PY_THROW;
2636     assert(state->active);
2637     PyObject *exc;
2638     if (exception_event_setup(&exc, event) < 0) {
2639         return -1;
2640     }
2641     PyObject *args[4] = { NULL, NULL, NULL, exc };
2642     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2643     return exception_event_teardown(err, exc);
2644 }
2645 
2646 int
_PyMonitoring_FireRaiseEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2647 _PyMonitoring_FireRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2648 {
2649     int event = PY_MONITORING_EVENT_RAISE;
2650     assert(state->active);
2651     PyObject *exc;
2652     if (exception_event_setup(&exc, event) < 0) {
2653         return -1;
2654     }
2655     PyObject *args[4] = { NULL, NULL, NULL, exc };
2656     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2657     return exception_event_teardown(err, exc);
2658 }
2659 
2660 int
_PyMonitoring_FireCRaiseEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2661 _PyMonitoring_FireCRaiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2662 {
2663     int event = PY_MONITORING_EVENT_C_RAISE;
2664     assert(state->active);
2665     PyObject *exc;
2666     if (exception_event_setup(&exc, event) < 0) {
2667         return -1;
2668     }
2669     PyObject *args[4] = { NULL, NULL, NULL, exc };
2670     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2671     return exception_event_teardown(err, exc);
2672 }
2673 
2674 int
_PyMonitoring_FireReraiseEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2675 _PyMonitoring_FireReraiseEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2676 {
2677     int event = PY_MONITORING_EVENT_RERAISE;
2678     assert(state->active);
2679     PyObject *exc;
2680     if (exception_event_setup(&exc, event) < 0) {
2681         return -1;
2682     }
2683     PyObject *args[4] = { NULL, NULL, NULL, exc };
2684     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2685     return exception_event_teardown(err, exc);
2686 }
2687 
2688 int
_PyMonitoring_FireExceptionHandledEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2689 _PyMonitoring_FireExceptionHandledEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2690 {
2691     int event = PY_MONITORING_EVENT_EXCEPTION_HANDLED;
2692     assert(state->active);
2693     PyObject *exc;
2694     if (exception_event_setup(&exc, event) < 0) {
2695         return -1;
2696     }
2697     PyObject *args[4] = { NULL, NULL, NULL, exc };
2698     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2699     return exception_event_teardown(err, exc);
2700 }
2701 
2702 int
_PyMonitoring_FirePyUnwindEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset)2703 _PyMonitoring_FirePyUnwindEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset)
2704 {
2705     int event = PY_MONITORING_EVENT_PY_UNWIND;
2706     assert(state->active);
2707     PyObject *exc;
2708     if (exception_event_setup(&exc, event) < 0) {
2709         return -1;
2710     }
2711     PyObject *args[4] = { NULL, NULL, NULL, exc };
2712     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2713     return exception_event_teardown(err, exc);
2714 }
2715 
2716 int
_PyMonitoring_FireStopIterationEvent(PyMonitoringState * state,PyObject * codelike,int32_t offset,PyObject * value)2717 _PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike, int32_t offset, PyObject *value)
2718 {
2719     int event = PY_MONITORING_EVENT_STOP_ITERATION;
2720     assert(state->active);
2721     assert(!PyErr_Occurred());
2722     PyErr_SetObject(PyExc_StopIteration, value);
2723     PyObject *exc;
2724     if (exception_event_setup(&exc, event) < 0) {
2725         return -1;
2726     }
2727     PyObject *args[4] = { NULL, NULL, NULL, exc };
2728     int err = capi_call_instrumentation(state, codelike, offset, args, 3, event);
2729     Py_DECREF(exc);
2730     return exception_event_teardown(err, NULL);
2731 }
2732