Coverage Report

Created: 2026-10-31 06:21

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