FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
cpython/Modules/_remote_debugging/_remote_debugging.h at 3.15 · python/cpython · GitHub
python
cpython
Repository navigation
Code
Issues
5k+
(5k+)
Pull requests
2.3k
(2.3k)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cpython
/
Modules
/
_remote_debugging
/
_remote_debugging.h
Copy path
More file actions
More file actions
Latest commit
History
History
History
790 lines (681 loc) · 27.4 KB
Breadcrumbs
cpython
/
Modules
/
_remote_debugging
/
_remote_debugging.h
Copy path
File metadata and controls
790 lines (681 loc) · 27.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
/******************************************************************************
* Python Remote Debugging Module - Shared Header
*
* This header provides common declarations, types, and utilities shared
* across the remote debugging module implementation files.
******************************************************************************/
#ifndef
Py_REMOTE_DEBUGGING_H
#define
Py_REMOTE_DEBUGGING_H
/* _GNU_SOURCE must be defined before any system headers */
#ifndef
_GNU_SOURCE
#define
_GNU_SOURCE
#endif
#ifdef
__cplusplus
extern
"C"
{
#endif
#ifndef
Py_BUILD_CORE_BUILTIN
# ifndef
Py_BUILD_CORE_MODULE
# define
Py_BUILD_CORE_MODULE
1
# endif
#endif
#include
"Python.h"
#include
"internal/pycore_debug_offsets.h"
// _Py_DebugOffsets
#include
"internal/pycore_frame.h"
// FRAME_SUSPENDED_YIELD_FROM
#include
"internal/pycore_interpframe.h"
// FRAME_OWNED_BY_INTERPRETER
#include
"internal/pycore_llist.h"
// struct llist_node
#include
"internal/pycore_long.h"
// _PyLong_GetZero
#include
"internal/pycore_pyerrors.h"
// _PyErr_FormatFromCause
#include
"internal/pycore_pyhash.h"
// _Py_HashPointerRaw
#include
"internal/pycore_stackref.h"
// Py_TAG_BITS
#include
"../../Python/remote_debug.h"
#include
<assert.h>
#include
<errno.h>
#include
<fcntl.h>
#include
<stddef.h>
#include
<stdint.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#ifndef
HAVE_PROCESS_VM_READV
# define
HAVE_PROCESS_VM_READV
0
#endif
#if
defined(
__APPLE__
)
#include
<TargetConditionals.h>
# if
!defined(
TARGET_OS_OSX
)
/* Older macOS SDKs do not define TARGET_OS_OSX */
# define
TARGET_OS_OSX
1
# endif
# if
TARGET_OS_OSX
# include
<libproc.h>
# include
<sys/types.h>
# define
MAX_NATIVE_THREADS
4096
# endif
#endif
// Platforms that support pausing/resuming threads for accurate stack sampling
#if
defined(
MS_WINDOWS
)
||
defined(
__linux__
)
||
(defined(
__APPLE__
)
&&
TARGET_OS_OSX
)
# define
Py_REMOTE_DEBUG_SUPPORTS_BLOCKING
1
#endif
#ifdef
MS_WINDOWS
#include
<windows.h>
#include
<winternl.h>
#endif
#if
defined(
__APPLE__
)
&&
TARGET_OS_OSX
typedef
struct
{
mach_port_t
task
;
int
suspended
;
}
_Py_RemoteDebug_ThreadsState
;
#elif
defined(
__linux__
)
typedef
struct
{
pid_t
*
tids
;
// Points to unwinder's reusable buffer
size_t
count
;
// Number of threads currently seized
}
_Py_RemoteDebug_ThreadsState
;
#elif
defined(
MS_WINDOWS
)
typedef
NTSTATUS
(
NTAPI
*
NtSuspendProcessFunc
)(
HANDLE
ProcessHandle
);
typedef
NTSTATUS
(
NTAPI
*
NtResumeProcessFunc
)(
HANDLE
ProcessHandle
);
typedef
struct
{
HANDLE
hProcess
;
int
suspended
;
}
_Py_RemoteDebug_ThreadsState
;
#else
typedef
struct
{
int
dummy
;
}
_Py_RemoteDebug_ThreadsState
;
#endif
#ifdef
MS_WINDOWS
#define
STATUS_SUCCESS
((NTSTATUS)0x00000000L)
#define
STATUS_INFO_LENGTH_MISMATCH
((NTSTATUS)0xC0000004L)
#define
STATUS_NO_MORE_ENTRIES
((NTSTATUS)0x8000001AL)
typedef
enum
_WIN32_THREADSTATE
{
WIN32_THREADSTATE_INITIALIZED
=
0
,
WIN32_THREADSTATE_READY
=
1
,
WIN32_THREADSTATE_RUNNING
=
2
,
WIN32_THREADSTATE_STANDBY
=
3
,
WIN32_THREADSTATE_TERMINATED
=
4
,
WIN32_THREADSTATE_WAITING
=
5
,
WIN32_THREADSTATE_TRANSITION
=
6
,
WIN32_THREADSTATE_UNKNOWN
=
7
}
WIN32_THREADSTATE
;
#endif
/* ============================================================================
* MACROS AND CONSTANTS
* ============================================================================ */
#define
GET_MEMBER
(
type
,
obj
,
offset
) \
(*(const type *)memcpy(&(type){0}, (const char *)(obj) + (offset), sizeof(type)))
#define
CLEAR_PTR_TAG
(
ptr
) (((uintptr_t)(ptr) & ~Py_TAG_BITS))
#define
GET_MEMBER_NO_TAG
(
type
,
obj
,
offset
) (type)(CLEAR_PTR_TAG(GET_MEMBER(type, obj, offset)))
/* Size macros for opaque buffers */
#define
SIZEOF_BYTES_OBJ
sizeof(PyBytesObject)
#define
SIZEOF_CODE_OBJ
sizeof(PyCodeObject)
#define
SIZEOF_GEN_OBJ
sizeof(PyGenObject)
#define
SIZEOF_INTERP_FRAME
sizeof(_PyInterpreterFrame)
#define
SIZEOF_LLIST_NODE
sizeof(struct llist_node)
#define
SIZEOF_PAGE_CACHE_ENTRY
sizeof(page_cache_entry_t)
#define
SIZEOF_PYOBJECT
sizeof(PyObject)
#define
SIZEOF_SET_OBJ
sizeof(PySetObject)
#define
SIZEOF_TASK_OBJ
4096
#define
SIZEOF_THREAD_STATE
sizeof(PyThreadState)
#define
SIZEOF_TYPE_OBJ
sizeof(PyTypeObject)
#define
SIZEOF_UNICODE_OBJ
sizeof(PyUnicodeObject)
#define
SIZEOF_LONG_OBJ
sizeof(PyLongObject)
#define
SIZEOF_GC_RUNTIME_STATE
sizeof(struct _gc_runtime_state)
#define
SIZEOF_INTERPRETER_STATE
sizeof(PyInterpreterState)
/* Maximum sizes for validation to prevent buffer overflows from corrupted data */
#define
MAX_STACK_CHUNK_SIZE
(16 * 1024 * 1024)
/* 16 MB max for stack chunks */
#define
MAX_LONG_DIGITS
64
/* Allows values up to ~2^1920 */
#define
MAX_SET_TABLE_SIZE
(1 << 20)
/* 1 million entries max for set iteration */
#define
MAX_FRAME_CHAIN_DEPTH
(1024 + 512)
/* Iteration bound for frame chain walks */
#define
MAX_TASK_WAITER_WALK_TASKS
(1 << 14)
/* Total-task bound for waiter walks */
#ifndef
MAX
#define
MAX
(
a
,
b
) ((a) > (b) ? (a) : (b))
#endif
#ifdef
Py_GIL_DISABLED
#define
INTERP_STATE_MIN_SIZE
MAX(MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \
offsetof(PyInterpreterState, tlbc_indices.tlbc_generation) + sizeof(uint32_t)), \
offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \
offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)), \
offsetof(PyInterpreterState, gc.frame) + sizeof(_PyInterpreterFrame *))
#else
#define
INTERP_STATE_MIN_SIZE
MAX(MAX(MAX(offsetof(PyInterpreterState, _code_object_generation) + sizeof(uint64_t), \
offsetof(PyInterpreterState, threads.head) + sizeof(void*)), \
offsetof(PyInterpreterState, _gil.last_holder) + sizeof(PyThreadState*)), \
offsetof(PyInterpreterState, gc.frame) + sizeof(_PyInterpreterFrame *))
#endif
#define
INTERP_STATE_BUFFER_SIZE
MAX(INTERP_STATE_MIN_SIZE, 256)
#define
MAX_TLBC_SIZE
2048
/* Thread status flags */
#define
THREAD_STATUS_HAS_GIL
(1 << 0)
#define
THREAD_STATUS_ON_CPU
(1 << 1)
#define
THREAD_STATUS_UNKNOWN
(1 << 2)
#define
THREAD_STATUS_GIL_REQUESTED
(1 << 3)
#define
THREAD_STATUS_HAS_EXCEPTION
(1 << 4)
#define
THREAD_STATUS_MAIN_THREAD
(1 << 5)
/* Exception cause macro */
#define
set_exception_cause
(
unwinder
,
exc_type
,
message
) \
do { \
assert(PyErr_Occurred() && "function returned -1 without setting exception"); \
if (unwinder->debug && !_Py_RemoteDebug_IsFatalReadError()) { \
_set_debug_exception_cause(exc_type, message); \
} \
} while (0)
/* ============================================================================
* TYPE DEFINITIONS
* ============================================================================ */
struct
_Py_AsyncioModuleDebugOffsets
{
struct
_asyncio_task_object
{
uint64_t
size
;
uint64_t
task_name
;
uint64_t
task_awaited_by
;
uint64_t
task_is_task
;
uint64_t
task_awaited_by_is_set
;
uint64_t
task_coro
;
uint64_t
task_node
;
}
asyncio_task_object
;
struct
_asyncio_interpreter_state
{
uint64_t
size
;
uint64_t
asyncio_tasks_head
;
}
asyncio_interpreter_state
;
struct
_asyncio_thread_state
{
uint64_t
size
;
uint64_t
asyncio_running_loop
;
uint64_t
asyncio_running_task
;
uint64_t
asyncio_tasks_head
;
}
asyncio_thread_state
;
};
typedef
struct
{
PyObject
*
func_name
;
PyObject
*
file_name
;
int
first_lineno
;
PyObject
*
linetable
;
// bytes
PyObject
*
last_frame_info
;
ptrdiff_t
last_addrq
;
uintptr_t
addr_code_adaptive
;
}
CachedCodeMetadata
;
/* Frame cache constants and types */
#define
FRAME_CACHE_MAX_THREADS
32
#define
FRAME_CACHE_MAX_FRAMES
1024
typedef
struct
{
uintptr_t
frame
;
uintptr_t
seq
;
}
FrameCacheAnchor
;
typedef
struct
{
uint64_t
thread_id
;
// 0 = empty slot
uintptr_t
thread_state_addr
;
uintptr_t
last_profiled_frame_seq
;
// sequence paired with addrs[0]
uintptr_t
addrs
[
FRAME_CACHE_MAX_FRAMES
];
Py_ssize_t
num_addrs
;
PyObject
*
thread_id_obj
;
// owned reference, NULL if empty
PyObject
*
frame_list
;
// owned reference, NULL if empty
}
FrameCacheEntry
;
#define
INTERPRETER_THREAD_CACHE_SIZE
32
#if
(
INTERPRETER_THREAD_CACHE_SIZE
&
(
INTERPRETER_THREAD_CACHE_SIZE
-
1
))
!=
0
# error
"INTERPRETER_THREAD_CACHE_SIZE must be a power of two"
#endif
// The two per-interpreter L2 caches below are split into per-field tables so
// that a writer rebinding one slot cannot leave stale data in a field owned by
// the other when the slot is reused across interpreters.
typedef
struct
{
uintptr_t
interpreter_addr
;
uintptr_t
thread_state_addr
;
}
InterpreterTstateCacheEntry
;
typedef
struct
{
uintptr_t
interpreter_addr
;
uint64_t
code_object_generation
;
}
InterpreterGenerationCacheEntry
;
// Carries already-read thread state and/or frame buffers across helpers so the
// downstream callee can skip a remote read. Address fields are caller-supplied
// inputs; buffer pointers (tstate, frame) are NULL unless a prior batched read
// successfully populated them.
typedef
struct
{
const
char
*
tstate
;
uintptr_t
tstate_addr
;
const
char
*
frame
;
uintptr_t
frame_addr
;
}
RemoteReadPrefetch
;
/* Statistics for profiling performance analysis */
typedef
struct
{
uint64_t
total_samples
;
// Total number of get_stack_trace calls
uint64_t
frame_cache_hits
;
// Full cache hits (entire stack unchanged)
uint64_t
frame_cache_misses
;
// Cache misses requiring full walk
uint64_t
frame_cache_partial_hits
;
// Partial hits (stopped at cached frame)
uint64_t
frames_read_from_cache
;
// Total frames retrieved from cache
uint64_t
frames_read_from_memory
;
// Total frames read from remote memory
uint64_t
memory_reads
;
// Total remote memory read operations
uint64_t
memory_bytes_read
;
// Total bytes read from remote memory
uint64_t
code_object_cache_hits
;
// Code object cache hits
uint64_t
code_object_cache_misses
;
// Code object cache misses
uint64_t
stale_cache_invalidations
;
// Times stale entries were cleared
uint64_t
batched_read_attempts
;
// Batched remote-read attempts
uint64_t
batched_read_successes
;
// Attempts that read all requested segments
uint64_t
batched_read_misses
;
// Attempts that fell back or partially read
uint64_t
batched_read_segments_requested
;
// Segments requested by batched reads
uint64_t
batched_read_segments_completed
;
// Segments completed by batched reads
}
UnwinderStats
;
#if
defined(
__GNUC__
)
||
defined(
__clang__
)
# define
REMOTE_DEBUG_UNLIKELY
(
value
) __builtin_expect(!!(value), 0)
#else
# define
REMOTE_DEBUG_UNLIKELY
(
value
) (value)
#endif
/* Stats tracking macros - no-op when stats collection is disabled */
#define
STATS_INC
(
unwinder
,
field
) \
do { if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) (unwinder)->stats.field++; } while(0)
#define
STATS_ADD
(
unwinder
,
field
,
val
) \
do { if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) (unwinder)->stats.field += (val); } while(0)
#if
HAVE_PROCESS_VM_READV
# define
STATS_BATCHED_READ
(
unwinder
,
requested
,
completed
) \
do { \
if (REMOTE_DEBUG_UNLIKELY((unwinder)->collect_stats)) { \
(unwinder)->stats.batched_read_attempts++; \
(unwinder)->stats.batched_read_segments_requested += (uint64_t)(requested); \
(unwinder)->stats.batched_read_segments_completed += (uint64_t)(completed); \
if ((completed) == (requested)) { \
(unwinder)->stats.batched_read_successes++; \
} \
else { \
(unwinder)->stats.batched_read_misses++; \
} \
} \
} while(0)
#else
# define
STATS_BATCHED_READ
(
unwinder
,
requested
,
completed
) ((void)0)
#endif
typedef
struct
{
PyTypeObject
*
RemoteDebugging_Type
;
PyTypeObject
*
TaskInfo_Type
;
PyTypeObject
*
LocationInfo_Type
;
PyTypeObject
*
FrameInfo_Type
;
PyTypeObject
*
CoroInfo_Type
;
PyTypeObject
*
ThreadInfo_Type
;
PyTypeObject
*
InterpreterInfo_Type
;
PyTypeObject
*
AwaitedInfo_Type
;
PyTypeObject
*
GCStatsInfo_Type
;
PyTypeObject
*
BinaryWriter_Type
;
PyTypeObject
*
BinaryReader_Type
;
PyTypeObject
*
GCMonitor_Type
;
}
RemoteDebuggingState
;
enum
_ThreadState
{
THREAD_STATE_RUNNING
,
THREAD_STATE_IDLE
,
THREAD_STATE_GIL_WAIT
,
THREAD_STATE_UNKNOWN
};
enum
_ProfilingMode
{
PROFILING_MODE_WALL
=
0
,
PROFILING_MODE_CPU
=
1
,
PROFILING_MODE_GIL
=
2
,
PROFILING_MODE_ALL
=
3
,
PROFILING_MODE_EXCEPTION
=
4
};
typedef
struct
{
PyObject_HEAD
proc_handle_t
handle
;
uintptr_t
runtime_start_address
;
struct
_Py_DebugOffsets
debug_offsets
;
int
async_debug_offsets_available
;
struct
_Py_AsyncioModuleDebugOffsets
async_debug_offsets
;
uintptr_t
interpreter_addr
;
uintptr_t
tstate_addr
;
_Py_hashtable_t
*
code_object_cache
;
int
debug
;
int
only_active_thread
;
int
mode
;
int
skip_non_matching_threads
;
int
native
;
int
gc
;
int
opcodes
;
int
cache_frames
;
int
collect_stats
;
// whether to collect statistics
uint32_t
stale_invalidation_counter
;
// counter for throttling frame_cache_invalidate_stale
// L1 single-entry shortcut over cached_tstates[]: most workloads sample one
// interpreter, so check these pairs before hashing into the table below.
uintptr_t
cached_tstate_interpreter_addr
;
uintptr_t
cached_tstate_addr
;
uintptr_t
cached_generation_interpreter_addr
;
uint64_t
cached_code_object_generation
;
RemoteDebuggingState
*
cached_state
;
FrameCacheEntry
*
frame_cache
;
// preallocated array of FRAME_CACHE_MAX_THREADS entries
UnwinderStats
stats
;
// statistics for performance analysis
InterpreterTstateCacheEntry
cached_tstates
[
INTERPRETER_THREAD_CACHE_SIZE
];
InterpreterGenerationCacheEntry
cached_generations
[
INTERPRETER_THREAD_CACHE_SIZE
];
#ifdef
Py_GIL_DISABLED
uint32_t
tlbc_generation
;
_Py_hashtable_t
*
tlbc_cache
;
#endif
#ifdef
__APPLE__
uint64_t
thread_id_offset
;
int
thread_id_offset_initialized
;
#endif
#ifdef
MS_WINDOWS
PVOID
win_process_buffer
;
ULONG
win_process_buffer_size
;
#endif
// Thread stopping state (only on platforms that support it)
#ifdef
Py_REMOTE_DEBUG_SUPPORTS_BLOCKING
_Py_RemoteDebug_ThreadsState
threads_state
;
int
threads_stopped
;
// 1 if threads are currently stopped
#endif
#ifdef
__linux__
pid_t
*
thread_tids
;
// Reusable buffer for thread IDs
size_t
thread_tids_capacity
;
// Current capacity of thread_tids buffer
#endif
}
RemoteUnwinderObject
;
#define
RemoteUnwinder_CAST
(
op
) ((RemoteUnwinderObject *)(op))
typedef
struct
{
int
lineno
;
int
end_lineno
;
int
column
;
int
end_column
;
}
LocationInfo
;
typedef
struct
{
uintptr_t
remote_addr
;
size_t
size
;
void
*
local_copy
;
}
StackChunkInfo
;
typedef
struct
{
StackChunkInfo
*
chunks
;
size_t
count
;
}
StackChunkList
;
typedef
struct
{
proc_handle_t
handle
;
uintptr_t
runtime_start_address
;
struct
_Py_DebugOffsets
debug_offsets
;
int
debug
;
}
RuntimeOffsets
;
/*
* Context for frame chain traversal operations.
*/
typedef
struct
{
/* Inputs */
uintptr_t
frame_addr
;
// Starting frame address
uintptr_t
thread_state_addr
;
// Owning thread state address
uintptr_t
base_frame_addr
;
// Sentinel at bottom (for validation)
uintptr_t
gc_frame
;
// GC frame address (0 if not tracking)
FrameCacheAnchor
last_profiled
;
// Last cached frame anchor
StackChunkList
*
chunks
;
// Pre-copied stack chunks
int
skip_first_frame
;
// Skip frame_addr itself (continue from its caller)
RemoteReadPrefetch
prefetch
;
// Optional already-read thread/frame buffers
/* Outputs */
PyObject
*
frame_info
;
// List to append FrameInfo objects
uintptr_t
*
frame_addrs
;
// Array of visited frame addresses
Py_ssize_t
num_addrs
;
// Count of addresses collected
Py_ssize_t
max_addrs
;
// Capacity of frame_addrs array
uintptr_t
last_frame_visited
;
// Last frame address visited
int
stopped_at_cached_frame
;
// Whether we stopped at cached frame
}
FrameWalkContext
;
/*
* Context for code object parsing.
*/
typedef
struct
{
uintptr_t
code_addr
;
// Code object address in remote process
uintptr_t
instruction_pointer
;
// Current instruction pointer
int32_t
tlbc_index
;
// Thread-local bytecode index (free-threading)
}
CodeObjectContext
;
typedef
struct
{
PyObject_HEAD
RuntimeOffsets
offsets
;
}
GCMonitorObject
;
#define
GCMonitor_CAST
(
op
) ((GCMonitorObject *)(op))
/* Function pointer types for iteration callbacks */
typedef
int
(
*
thread_processor_func
)(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
thread_state_addr
,
unsigned long
tid
,
void
*
context
);
typedef
int
(
*
interpreter_processor_func
)(
RuntimeOffsets
*
offsets
,
uintptr_t
interpreter_state_addr
,
int64_t
iid
,
void
*
context
);
/* ============================================================================
* STRUCTSEQ DESCRIPTORS (extern declarations)
* ============================================================================ */
extern
PyStructSequence_Desc
TaskInfo_desc
;
extern
PyStructSequence_Desc
LocationInfo_desc
;
extern
PyStructSequence_Desc
FrameInfo_desc
;
extern
PyStructSequence_Desc
CoroInfo_desc
;
extern
PyStructSequence_Desc
ThreadInfo_desc
;
extern
PyStructSequence_Desc
InterpreterInfo_desc
;
extern
PyStructSequence_Desc
AwaitedInfo_desc
;
extern
PyStructSequence_Desc
GCStatsInfo_desc
;
/* ============================================================================
* UTILITY FUNCTION DECLARATIONS
* ============================================================================ */
/* State access functions */
extern
RemoteDebuggingState
*
RemoteDebugging_GetState
(
PyObject
*
module
);
extern
RemoteDebuggingState
*
RemoteDebugging_GetStateFromType
(
PyTypeObject
*
type
);
extern
RemoteDebuggingState
*
RemoteDebugging_GetStateFromObject
(
PyObject
*
obj
);
extern
int
RemoteDebugging_InitState
(
RemoteDebuggingState
*
st
);
/* Cache management */
extern
void
cached_code_metadata_destroy
(
void
*
ptr
);
/* Validation */
extern
int
is_prerelease_version
(
uint64_t
version
);
extern
int
validate_debug_offsets
(
struct
_Py_DebugOffsets
*
debug_offsets
);
#define
PY_REMOTE_DEBUG_INVALID_ASYNC_DEBUG_OFFSETS
(-2)
/* ============================================================================
* MEMORY READING FUNCTION DECLARATIONS
* ============================================================================ */
extern
int
read_ptr
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
,
uintptr_t
*
result
);
extern
int
read_char
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
,
char
*
result
);
extern
int
read_py_ptr
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
,
uintptr_t
*
ptr_addr
);
/* Python object reading */
extern
PyObject
*
read_py_str
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
,
Py_ssize_t
max_len
);
extern
PyObject
*
read_py_bytes
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
,
Py_ssize_t
max_len
);
extern
long
read_py_long
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address
);
/* ============================================================================
* CODE OBJECT FUNCTION DECLARATIONS
* ============================================================================ */
extern
int
parse_code_object
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
*
result
,
const
CodeObjectContext
*
ctx
);
extern
PyObject
*
make_location_info
(
RemoteUnwinderObject
*
unwinder
,
int
lineno
,
int
end_lineno
,
int
col_offset
,
int
end_col_offset
);
extern
PyObject
*
make_frame_info
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
file
,
PyObject
*
location
,
// LocationInfo structseq or None for synthetic frames
PyObject
*
func
,
PyObject
*
opcode
);
/* Line table parsing */
extern
bool
parse_linetable
(
const
uintptr_t
addrq
,
const
char
*
linetable
,
Py_ssize_t
linetable_size
,
int
firstlineno
,
LocationInfo
*
info
);
/* TLBC cache (only for Py_GIL_DISABLED) */
#ifdef
Py_GIL_DISABLED
typedef
struct
{
void
*
tlbc_array
;
Py_ssize_t
tlbc_array_size
;
uint32_t
generation
;
}
TLBCCacheEntry
;
extern
void
tlbc_cache_entry_destroy
(
void
*
ptr
);
extern
TLBCCacheEntry
*
get_tlbc_cache_entry
(
RemoteUnwinderObject
*
self
,
uintptr_t
code_addr
,
uint32_t
current_generation
);
extern
int
cache_tlbc_array
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
code_addr
,
uintptr_t
tlbc_array_addr
,
uint32_t
generation
);
#endif
/* ============================================================================
* FRAME FUNCTION DECLARATIONS
* ============================================================================ */
extern
int
is_frame_valid
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
frame_addr
,
uintptr_t
code_object_addr
);
extern
int
parse_frame_object
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
*
result
,
uintptr_t
address
,
uintptr_t
*
address_of_code_object
,
uintptr_t
*
previous_frame
);
extern
int
parse_frame_from_chunks
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
*
result
,
uintptr_t
address
,
uintptr_t
*
previous_frame
,
uintptr_t
*
stackpointer
,
StackChunkList
*
chunks
);
/* Stack chunk management */
extern
void
cleanup_stack_chunks
(
StackChunkList
*
chunks
);
extern
int
copy_stack_chunks
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
tstate_addr
,
StackChunkList
*
out_chunks
);
extern
void
*
find_frame_in_chunks
(
StackChunkList
*
chunks
,
uintptr_t
remote_ptr
);
extern
int
process_frame_chain
(
RemoteUnwinderObject
*
unwinder
,
FrameWalkContext
*
ctx
);
/* Frame cache functions */
extern
int
frame_cache_init
(
RemoteUnwinderObject
*
unwinder
);
extern
void
frame_cache_cleanup
(
RemoteUnwinderObject
*
unwinder
);
extern
FrameCacheEntry
*
frame_cache_find
(
RemoteUnwinderObject
*
unwinder
,
uint64_t
thread_id
);
extern
FrameCacheEntry
*
frame_cache_find_by_tstate
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
tstate_addr
);
extern
int
clear_last_profiled_frames
(
RemoteUnwinderObject
*
unwinder
);
extern
int
set_last_profiled_frame
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
tstate_addr
,
uintptr_t
frame_addr
);
extern
void
frame_cache_invalidate_stale
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
result
);
extern
int
frame_cache_lookup_and_extend
(
RemoteUnwinderObject
*
unwinder
,
uint64_t
thread_id
,
uintptr_t
thread_state_addr
,
FrameCacheAnchor
anchor
,
PyObject
*
frame_info
,
uintptr_t
*
frame_addrs
,
Py_ssize_t
*
num_addrs
,
Py_ssize_t
max_addrs
);
extern
int
frame_cache_anchor_matches
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
thread_state_addr
,
FrameCacheAnchor
anchor
);
// Returns: 1 = stored, 0 = not stored (graceful), -1 = error
// Only stores complete stacks that reach base_frame_addr
extern
int
frame_cache_store
(
RemoteUnwinderObject
*
unwinder
,
uint64_t
thread_id
,
PyObject
*
frame_list
,
const
uintptr_t
*
addrs
,
Py_ssize_t
num_addrs
,
uintptr_t
thread_state_addr
,
uintptr_t
last_profiled_frame_seq
,
uintptr_t
base_frame_addr
,
uintptr_t
last_frame_visited
);
extern
int
collect_frames_with_cache
(
RemoteUnwinderObject
*
unwinder
,
FrameWalkContext
*
ctx
,
uint64_t
thread_id
);
/* ============================================================================
* THREAD FUNCTION DECLARATIONS
* ============================================================================ */
extern
int
iterate_threads
(
RemoteUnwinderObject
*
unwinder
,
thread_processor_func
processor
,
void
*
context
);
extern
int
populate_initial_state_data
(
int
all_threads
,
RemoteUnwinderObject
*
unwinder
,
uintptr_t
runtime_start_address
,
uintptr_t
*
interpreter_state
,
uintptr_t
*
tstate
);
extern
int
find_running_frame
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
address_of_thread
,
uintptr_t
*
frame
);
extern
int
get_thread_status
(
RemoteUnwinderObject
*
unwinder
,
uint64_t
tid
,
uint64_t
pthread_id
);
extern
PyObject
*
unwind_stack_for_thread
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
*
current_tstate
,
uintptr_t
gil_holder_tstate
,
uintptr_t
gc_frame
,
uintptr_t
main_thread_tstate
,
const
RemoteReadPrefetch
*
prefetch
);
/* Thread stopping functions (for blocking mode) */
extern
void
_Py_RemoteDebug_InitThreadsState
(
RemoteUnwinderObject
*
unwinder
,
_Py_RemoteDebug_ThreadsState
*
st
);
extern
int
_Py_RemoteDebug_StopAllThreads
(
RemoteUnwinderObject
*
unwinder
,
_Py_RemoteDebug_ThreadsState
*
st
);
extern
void
_Py_RemoteDebug_ResumeAllThreads
(
RemoteUnwinderObject
*
unwinder
,
_Py_RemoteDebug_ThreadsState
*
st
);
/* ============================================================================
* INTERPRETER FUNCTION DECLARATIONS
* ============================================================================ */
extern
int
iterate_interpreters
(
RuntimeOffsets
*
offsets
,
interpreter_processor_func
processor
,
void
*
context
);
/* ============================================================================
* ASYNCIO FUNCTION DECLARATIONS
* ============================================================================ */
extern
uintptr_t
_Py_RemoteDebug_GetAsyncioDebugAddress
(
proc_handle_t
*
handle
);
extern
int
read_async_debug
(
RemoteUnwinderObject
*
unwinder
);
extern
int
ensure_async_debug_offsets
(
RemoteUnwinderObject
*
unwinder
);
/* Task parsing */
extern
PyObject
*
parse_task_name
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
task_address
);
extern
int
parse_task
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
task_address
,
PyObject
*
render_to
);
extern
int
parse_async_frame_chain
(
RemoteUnwinderObject
*
unwinder
,
PyObject
*
calls
,
uintptr_t
address_of_thread
,
uintptr_t
running_task_frame
);
extern
int
process_single_task_node
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
task_addr
,
PyObject
*
*
task_info
,
PyObject
*
result
);
extern
int
find_running_task_in_thread
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
thread_state_addr
,
uintptr_t
*
running_task_addr
);
extern
int
get_task_frame
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
task_addr
,
uintptr_t
*
frame_addr
);
extern
int
append_awaited_by
(
RemoteUnwinderObject
*
unwinder
,
unsigned long
tid
,
uintptr_t
head_addr
,
PyObject
*
result
);
/* Thread processors for asyncio */
extern
int
process_thread_for_awaited_by
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
thread_state_addr
,
unsigned long
tid
,
void
*
context
);
extern
int
process_thread_for_async_stack_trace
(
RemoteUnwinderObject
*
unwinder
,
uintptr_t
thread_state_addr
,
unsigned long
tid
,
void
*
context
);
/* ============================================================================
* SUBPROCESS ENUMERATION FUNCTION DECLARATIONS
* ============================================================================ */
/* Get all child PIDs of a process.
* Returns a new Python list of PIDs, or NULL on error with exception set.
* If recursive is true, includes all descendants (children, grandchildren, etc.)
*/
extern
PyObject
*
enumerate_child_pids
(
pid_t
target_pid
,
int
recursive
);
#ifdef
__cplusplus
}
#endif
#endif
/* Py_REMOTE_DEBUGGING_H */
Back
|
FazBrowse Home
|
New Git URL