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