diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h index 32f68378ea5d72..10314cd05cc463 100644 --- a/Include/cpython/pystate.h +++ b/Include/cpython/pystate.h @@ -200,6 +200,8 @@ struct _ts { The PyThreadObject must hold the only reference to this value. */ PyObject *threading_local_sentinel; + + int debugger_pending_call; }; #ifdef Py_DEBUG diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index d4291b87261ae0..8bb4b95158d6be 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -192,6 +192,11 @@ typedef struct _Py_DebugOffsets { uint64_t size; uint64_t collecting; } gc; + + struct _debugger_support { + uint64_t eval_breaker; + uint64_t debugger_pending_call; + } debugger_support; } _Py_DebugOffsets; /* Reference tracer state */ diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h index e6adb98eb19130..12ce9d3da329a6 100644 --- a/Include/internal/pycore_runtime_init.h +++ b/Include/internal/pycore_runtime_init.h @@ -135,6 +135,10 @@ extern PyTypeObject _PyExc_MemoryError; .size = sizeof(struct _gc_runtime_state), \ .collecting = offsetof(struct _gc_runtime_state, collecting), \ }, \ + .debugger_support = { \ + .eval_breaker = offsetof(PyThreadState, eval_breaker), \ + .debugger_pending_call = offsetof(PyThreadState, debugger_pending_call), \ + }, \ }, \ .allocators = { \ .standard = _pymem_allocators_standard_INIT(runtime), \ diff --git a/Modules/_testexternalinspection.c b/Modules/_testexternalinspection.c index 2476346777c319..e9860a92cfad38 100644 --- a/Modules/_testexternalinspection.c +++ b/Modules/_testexternalinspection.c @@ -409,6 +409,59 @@ read_memory(pid_t pid, void* remote_address, size_t len, void* dst) return total_bytes_read; } +ssize_t +write_memory(pid_t pid, void* remote_address, size_t len, const void* src) +{ + ssize_t total_bytes_written = 0; +#if defined(__linux__) && HAVE_PROCESS_VM_WRITEV + struct iovec local[1]; + struct iovec remote[1]; + ssize_t result = 0; + ssize_t written = 0; + + do { + local[0].iov_base = (void*)((char*)src + result); + local[0].iov_len = len - result; + remote[0].iov_base = (void*)((char*)remote_address + result); + remote[0].iov_len = len - result; + + written = process_vm_writev(pid, local, 1, remote, 1, 0); + if (written < 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + + result += written; + } while ((size_t)written != local[0].iov_len); + total_bytes_written = result; +#elif defined(__APPLE__) && TARGET_OS_OSX + ssize_t result = -1; + kern_return_t kr = mach_vm_write( + pid_to_task(pid), + (mach_vm_address_t)remote_address, + (vm_offset_t)src, + (mach_msg_type_number_t)len); + + if (kr != KERN_SUCCESS) { + switch (kr) { + case KERN_PROTECTION_FAILURE: + PyErr_SetString(PyExc_PermissionError, "Not enough permissions to write memory"); + break; + case KERN_INVALID_ARGUMENT: + PyErr_SetString(PyExc_PermissionError, "Invalid argument to mach_vm_write"); + break; + default: + PyErr_SetString(PyExc_RuntimeError, "Unknown error writing memory"); + } + return -1; + } + total_bytes_written = len; +#else + return -1; +#endif + return total_bytes_written; +} + int read_string(pid_t pid, _Py_DebugOffsets* debug_offsets, void* address, char* buffer, Py_ssize_t size) { @@ -588,6 +641,30 @@ get_stack_trace(PyObject* self, PyObject* args) // No Python frames are available for us (can happen at tear-down). if (address_of_thread != NULL) { + + uintptr_t eval_breaker; + (void)read_memory( + pid, + (void*)(address_of_thread + local_debug_offsets.debugger_support.eval_breaker), + sizeof(uintptr_t), + &eval_breaker); + + eval_breaker |= (1U <<5); + + (void)write_memory( + pid, + (void*)(address_of_thread + local_debug_offsets.debugger_support.eval_breaker), + sizeof(uintptr_t), + &eval_breaker); + + int pending_call = 1; + (void)write_memory( + pid, + (void*)(address_of_thread + local_debug_offsets.debugger_support.debugger_pending_call), + sizeof(int), + &pending_call); + + void* address_of_current_frame; (void)read_memory( pid, diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 1d9381d09dfb62..8706e59f46b1f7 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -1315,5 +1315,19 @@ _Py_HandlePending(PyThreadState *tstate) return -1; } } + + if (tstate->debugger_pending_call) { + tstate->debugger_pending_call = 0; + PyObject* debug = _PyImport_GetModuleAttrString("debug", "debug_with_fifo"); + if (debug == NULL) { + return -1; + } + printf("Debug: %p\n", debug); + PyObject* result = PyObject_CallNoArgs(debug); + if (!result) { + return -1; + } + Py_DECREF(result); + } return 0; } diff --git a/Python/pystate.c b/Python/pystate.c index 6b85e5a64fefcf..f464470827adb2 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1738,6 +1738,8 @@ PyThreadState_Clear(PyThreadState *tstate) Py_CLEAR(tstate->context); + tstate->debugger_pending_call = 0; + #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. struct _Py_freelists *freelists = _Py_freelists_GET(); diff --git a/asserts.py b/asserts.py new file mode 100644 index 00000000000000..54212d3b941666 --- /dev/null +++ b/asserts.py @@ -0,0 +1,185 @@ +code = """ +# Python Assert Statement Examples + +# Basic assertions +assert True +assert not False +assert 1 == 1 +assert 2 + 2 == 4 +assert len("hello") == 5 +assert "python" in "I love python programming" +assert isinstance(42, int) +assert callable(len) + +# Numeric assertions +assert 10 > 5 +assert 7 < 9 +assert 3 <= 3 +assert 4 >= 4 +assert 2**3 == 8 +assert 10 % 3 == 1 +assert abs(-5) == 5 +assert round(3.14159, 2) == 3.14 + +# String assertions +assert "hello".upper() == "HELLO" +assert "WORLD".lower() == "world" +assert "python".capitalize() == "Python" +assert " strip ".strip() == "strip" +assert "hello world".split() == ["hello", "world"] +assert ",".join(["a", "b", "c"]) == "a,b,c" +assert "python".startswith("py") +assert "python".endswith("on") + +# List assertions +assert [1, 2, 3] + [4, 5] == [1, 2, 3, 4, 5] +assert [1, 2, 3] * 2 == [1, 2, 3, 1, 2, 3] +assert 2 in [1, 2, 3] +assert 4 not in [1, 2, 3] +assert [1, 2, 3].index(2) == 1 +assert [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].count(5) == 3 +assert sorted([3, 1, 4, 1, 5, 9, 2]) == [1, 1, 2, 3, 4, 5, 9] +assert list(reversed([1, 2, 3])) == [3, 2, 1] + +# Dictionary assertions +assert {"a": 1, "b": 2} == {"b": 2, "a": 1} +assert "key" in {"key": "value"} +assert "value" in {"key": "value"}.values() +assert len({"a": 1, "b": 2, "c": 3}) == 3 +assert {"a": 1, "b": 2}.get("c", 3) == 3 +assert list({"a": 1, "b": 2}.keys()) == ["a", "b"] +assert list({"a": 1, "b": 2}.values()) == [1, 2] +assert list({"a": 1, "b": 2}.items()) == [("a", 1), ("b", 2)] + +# Set assertions +assert {1, 2, 3} == {3, 2, 1} +assert {1, 2, 3}.issubset({1, 2, 3, 4, 5}) +assert {1, 2, 3, 4, 5}.issuperset({1, 2, 3}) +assert {1, 2, 3}.union({3, 4, 5}) == {1, 2, 3, 4, 5} +assert {1, 2, 3}.intersection({2, 3, 4}) == {2, 3} +assert {1, 2, 3}.difference({2, 3, 4}) == {1} +assert {1, 2, 3}.symmetric_difference({2, 3, 4}) == {1, 4} + +# Type assertions +assert type(42) is int +assert type("hello") is str +assert type([1, 2, 3]) is list +assert type({"a": 1}) is dict +assert type({1, 2, 3}) is set +assert type((1, 2, 3)) is tuple + +# Identity assertions +a = [1, 2, 3] +b = a +c = [1, 2, 3] +assert a is b +assert a is not c +assert a == c + +# Membership assertions +assert 2 in [1, 2, 3] +assert 4 not in [1, 2, 3] +assert "h" in "hello" +assert "x" not in "hello" + +# Boolean logic assertions +assert True and True +assert not (True and False) +assert True or False +assert not (False or False) +assert True is not False +assert (True or False) and (True and not False) + +# Comparison assertions +assert 1 < 2 < 3 +assert 3 > 2 > 1 +assert 1 <= 1 <= 2 +assert 2 >= 2 >= 1 +assert 1 != 2 != 3 + +# Math function assertions +import math + +assert math.sqrt(16) == 4 +assert math.ceil(3.14) == 4 +assert math.floor(3.14) == 3 +assert math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9) +assert math.gcd(18, 24) == 6 +assert math.lcm(4, 6) == 12 + +# String method assertions +assert "hello".replace("l", "L") == "heLLo" +assert "hello world".title() == "Hello World" +assert " hello ".strip() == "hello" +assert "hello".zfill(10) == "00000hello" +assert "hello".center(11, "-") == "---hello---" +assert "hello".isalpha() +assert "123".isdigit() +assert "hello123".isalnum() +assert "HELLO".isupper() +assert "hello".islower() + +# List comprehension assertion +assert [x**2 for x in range(5)] == [0, 1, 4, 9, 16] + +# Generator expression assertion +assert list(x**2 for x in range(5)) == [0, 1, 4, 9, 16] + +# Zip function assertion +assert list(zip([1, 2, 3], ["a", "b", "c"])) == [(1, "a"), (2, "b"), (3, "c")] + +# Enumerate function assertion +assert list(enumerate(["a", "b", "c"])) == [(0, "a"), (1, "b"), (2, "c")] + +# Any and all function assertions +assert any([False, True, False]) +assert all([True, True, True]) +assert not any([False, False, False]) +assert not all([True, False, True]) + +# Map function assertion +assert list(map(str, [1, 2, 3])) == ["1", "2", "3"] + +# Filter function assertion +assert list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5])) == [2, 4] + +# Sum function assertion +assert sum([1, 2, 3, 4, 5]) == 15 + +# Max and min function assertions +assert max([1, 5, 3, 2, 4]) == 5 +assert min([1, 5, 3, 2, 4]) == 1 + +# Sorted function with key assertion +assert sorted(["apple", "banana", "cherry"], key=len) == ["apple", "cherry", "banana"] + +# Lambda function assertion +assert (lambda x: x**2)(4) == 16 + + +# Class and instance assertions +class TestClass: + def __init__(self, value): + self.value = value + + def double(self): + return self.value * 2 + + +test_instance = TestClass(5) +assert isinstance(test_instance, TestClass) +assert hasattr(test_instance, "value") +assert hasattr(test_instance, "double") +assert test_instance.value == 5 +assert test_instance.double() == 10 + +# Exception assertions +try: + 1 / 0 +except ZeroDivisionError: + assert True +else: + assert False + +""" +compile(code, "a", "exec") diff --git a/blech.stuff b/blech.stuff new file mode 100644 index 00000000000000..a271d96372984d --- /dev/null +++ b/blech.stuff @@ -0,0 +1,271 @@ +execve("/usr/bin/less", ["less", "lol.py"], 0xffffccb20438 /* 15 vars */) = 0 +brk(NULL) = 0xaaaaf0d39000 +mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffff7f831000 +faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=10655, ...}) = 0 +mmap(NULL, 10655, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f82e000 +close(3) = 0 +openat(AT_FDCWD, "/lib64/libtinfo.so.6", O_RDONLY|O_CLOEXEC) = 3 +read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832 +fstat(3, {st_mode=S_IFREG|0755, st_size=334856, ...}) = 0 +mmap(NULL, 395456, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff7f787000 +mmap(0xffff7f790000, 329920, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff7f790000 +munmap(0xffff7f787000, 36864) = 0 +munmap(0xffff7f7e1000, 26816) = 0 +mprotect(0xffff7f79e000, 253952, PROT_NONE) = 0 +mmap(0xffff7f7a0000, 77824, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x10000) = 0xffff7f7a0000 +mmap(0xffff7f7c0000, 65536, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x30000) = 0xffff7f7c0000 +mmap(0xffff7f7dc000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4c000) = 0xffff7f7dc000 +close(3) = 0 +openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 +read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0h\f\3\0\0\0\0\0"..., 832) = 832 +pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784 +fstat(3, {st_mode=S_IFREG|0755, st_size=2364376, ...}) = 0 +pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784 +mmap(NULL, 2002368, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff7f5a7000 +mmap(0xffff7f5b0000, 1936832, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff7f5b0000 +munmap(0xffff7f5a7000, 36864) = 0 +munmap(0xffff7f789000, 28096) = 0 +mprotect(0xffff7f5dc000, 1708032, PROT_NONE) = 0 +mmap(0xffff7f5e0000, 1216512, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x30000) = 0xffff7f5e0000 +mmap(0xffff7f710000, 364544, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x160000) = 0xffff7f710000 +mmap(0xffff7f77d000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0xffff7f77d000 +mmap(0xffff7f782000, 28096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xffff7f782000 +close(3) = 0 +mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffff7f82c000 +set_tid_address(0xffff7f82c0f0) = 41672 +set_robust_list(0xffff7f82c100, 24) = 0 +rseq(0xffff7f82c740, 0x20, 0, 0xd428bc00) = 0 +mprotect(0xffff7f77d000, 12288, PROT_READ) = 0 +mprotect(0xffff7f7dc000, 16384, PROT_READ) = 0 +mprotect(0xaaaab216f000, 4096, PROT_READ) = 0 +mprotect(0xffff7f836000, 8192, PROT_READ) = 0 +prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 +munmap(0xffff7f82e000, 10655) = 0 +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +getrandom("\xab\xa4\x28\x64\x73\x25\xe0\xde", 8, GRND_NONBLOCK) = 8 +brk(NULL) = 0xaaaaf0d39000 +brk(0xaaaaf0d5a000) = 0xaaaaf0d5a000 +openat(AT_FDCWD, "/usr/bin/.sysless", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/etc/syslesskey", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/etc/sysless", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.config/lesskey", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.lesskey", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.config/less", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.less", O_RDONLY) = -1 ENOENT (No such file or directory) +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +getuid() = 0 +geteuid() = 0 +getgid() = 0 +getegid() = 0 +getuid() = 0 +geteuid() = 0 +getgid() = 0 +getegid() = 0 +newfstatat(AT_FDCWD, "/root/.terminfo", 0xaaaaf0d39950, 0) = -1 ENOENT (No such file or directory) +newfstatat(AT_FDCWD, "/etc/terminfo", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0 +newfstatat(AT_FDCWD, "/usr/share/terminfo", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0 +faccessat(AT_FDCWD, "/etc/terminfo/x/xterm", R_OK) = -1 ENOENT (No such file or directory) +faccessat(AT_FDCWD, "/usr/share/terminfo/x/xterm", R_OK) = 0 +getuid() = 0 +setfsuid(0) = 0 +getgid() = 0 +setfsgid(0) = 0 +openat(AT_FDCWD, "/usr/share/terminfo/x/xterm", O_RDONLY) = 3 +geteuid() = 0 +setfsuid(0) = 0 +getegid() = 0 +setfsgid(0) = 0 +fstat(3, {st_mode=S_IFREG|0644, st_size=3977, ...}) = 0 +read(3, "\32\0010\0&\0\17\0\235\1\20\6xterm|xterm terminal"..., 32768) = 3977 +read(3, "", 28672) = 0 +close(3) = 0 +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(1, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(1, TIOCGWINSZ, {ws_row=45, ws_col=156, ws_xpixel=0, ws_ypixel=0}) = 0 +ioctl(2, TIOCGWINSZ, {ws_row=45, ws_col=156, ws_xpixel=0, ws_ypixel=0}) = 0 +openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=2998, ...}) = 0 +read(3, "# Locale name alias data base.\n#"..., 4096) = 2998 +read(3, "", 4096) = 0 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=258, ...}) = 0 +mmap(NULL, 258, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f830000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib64/gconv/gconv-modules.cache", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=2258, ...}) = 0 +mmap(NULL, 2258, PROT_READ, MAP_SHARED, 3, 0) = 0xffff7f82f000 +close(3) = 0 +futex(0xffff7f78166c, FUTEX_WAKE_PRIVATE, 2147483647) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=23, ...}) = 0 +mmap(NULL, 23, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f82e000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=47, ...}) = 0 +mmap(NULL, 47, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f82b000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=127, ...}) = 0 +mmap(NULL, 127, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f82a000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NAME", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=62, ...}) = 0 +mmap(NULL, 62, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f829000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_PAPER", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=34, ...}) = 0 +mmap(NULL, 34, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f828000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MESSAGES/SYS_LC_MESSAGES", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=48, ...}) = 0 +mmap(NULL, 48, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f827000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_MONETARY", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=270, ...}) = 0 +mmap(NULL, 270, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f826000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_COLLATE", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=1406, ...}) = 0 +mmap(NULL, 1406, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f825000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_TIME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_TIME", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=3360, ...}) = 0 +mmap(NULL, 3360, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f824000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_NUMERIC", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=50, ...}) = 0 +mmap(NULL, 50, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f823000 +close(3) = 0 +openat(AT_FDCWD, "/usr/lib/locale/C.UTF-8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/usr/lib/locale/C.utf8/LC_CTYPE", O_RDONLY|O_CLOEXEC) = 3 +fstat(3, {st_mode=S_IFREG|0644, st_size=360460, ...}) = 0 +mmap(NULL, 360460, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff7f557000 +close(3) = 0 +openat(AT_FDCWD, "/root/.local/state", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.lesshst", O_RDONLY) = -1 ENOENT (No such file or directory) +getcwd("/src", 1024) = 5 +readlinkat(AT_FDCWD, "/src/lol.py", 0xffffc41d8560, 1023) = -1 EINVAL (Invalid argument) +getcwd("/src", 1024) = 5 +readlinkat(AT_FDCWD, "/src/lol.py", 0xffffc41d8560, 1023) = -1 EINVAL (Invalid argument) +ioctl(2, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(2, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +fstat(2, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0 +readlinkat(AT_FDCWD, "/proc/self/fd/2", "/dev/pts/0", 4095) = 10 +newfstatat(AT_FDCWD, "/dev/pts/0", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}, 0) = 0 +openat(AT_FDCWD, "/dev/pts/0", O_RDONLY) = 3 +ioctl(3, TCGETS, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +ioctl(3, TCSETSW, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|XTABS|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +rt_sigaction(SIGINT, {sa_handler=0xaaaab214c5a8, sa_mask=[INT], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 +rt_sigaction(SIGTSTP, {sa_handler=0xaaaab21431ac, sa_mask=[TSTP], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 +rt_sigaction(SIGWINCH, {sa_handler=0xaaaab2143164, sa_mask=[WINCH], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 +rt_sigaction(SIGQUIT, {sa_handler=SIG_IGN, sa_mask=[QUIT], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 +rt_sigaction(SIGTERM, {sa_handler=0xaaaab213f960, sa_mask=[TERM], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0 +newfstatat(AT_FDCWD, "lol.py", {st_mode=S_IFREG|0644, st_size=708, ...}, 0) = 0 +newfstatat(AT_FDCWD, "lol.py", {st_mode=S_IFREG|0644, st_size=708, ...}, 0) = 0 +openat(AT_FDCWD, "lol.py", O_RDONLY) = 4 +lseek(4, 1, SEEK_SET) = 1 +lseek(4, 0, SEEK_SET) = 0 +read(4, "import asyncio\nimport time\n\nasyn"..., 256) = 256 +ioctl(4, TCGETS, 0xffffc41d9750) = -1 ENOTTY (Inappropriate ioctl for device) +lseek(4, 1, SEEK_SET) = 1 +fstat(4, {st_mode=S_IFREG|0644, st_size=708, ...}) = 0 +lseek(4, 0, SEEK_SET) = 0 +newfstatat(AT_FDCWD, "lol.py", {st_mode=S_IFREG|0644, st_size=708, ...}, 0) = 0 +write(1, "\33[?1049h\33[22;0;0t\33[45;1H\33[?1h\33=\r", 32) = 32 +read(4, "import asyncio\nimport time\n\nasyn"..., 8192) = 708 +write(1, "import asyncio\nimport time\n\nasyn"..., 732) = 732 +read(3, "/", 1) = 1 +write(1, "\r\33[K/", 5) = 5 +read(3, "f", 1) = 1 +write(1, "\33[Kf\10f", 6) = 6 +read(3, "d", 1) = 1 +write(1, "\33[Kd\10d", 6) = 6 +read(3, "g", 1) = 1 +write(1, "\33[Kg\10g", 6) = 6 +read(3, "j", 1) = 1 +write(1, "\33[Kj\10j", 6) = 6 +read(3, "i", 1) = 1 +write(1, "\33[Ki\10i", 6) = 6 +read(3, "d", 1) = 1 +write(1, "\33[Kd\10d", 6) = 6 +read(3, "f", 1) = 1 +write(1, "\33[Kf\10f", 6) = 6 +read(3, "o", 1) = 1 +write(1, "\33[Ko\10o", 6) = 6 +read(3, "j", 1) = 1 +write(1, "\33[Kj\10j", 6) = 6 +read(3, "g", 1) = 1 +write(1, "\33[Kg\10g", 6) = 6 +read(3, "i", 1) = 1 +write(1, "\33[Ki\10i", 6) = 6 +read(3, "o", 1) = 1 +write(1, "\33[Ko\10o", 6) = 6 +read(3, "d", 1) = 1 +write(1, "\33[Kd\10d", 6) = 6 +read(3, "f", 1) = 1 +write(1, "\33[Kf\10f", 6) = 6 +read(3, "j", 1) = 1 +write(1, "\33[Kj\10j", 6) = 6 +read(3, "g", 1) = 1 +write(1, "\33[Kg\10g", 6) = 6 +read(3, "o", 1) = 1 +write(1, "\33[Ko\10o", 6) = 6 +read(3, "i", 1) = 1 +write(1, "\33[Ki\10i", 6) = 6 +read(3, "j", 1) = 1 +write(1, "\33[Kj\10j", 6) = 6 +read(3, "d", 1) = 1 +write(1, "\33[Kd\10d", 6) = 6 +read(3, "f", 1) = 1 +write(1, "\33[Kf\10f", 6) = 6 +read(3, "o", 1) = 1 +write(1, "\33[Ko\10o", 6) = 6 +read(3, "i", 1) = 1 +write(1, "\33[Ki\10i", 6) = 6 +read(3, "g", 1) = 1 +write(1, "\33[Kg\10g", 6) = 6 +read(3, "j", 1) = 1 +write(1, "\33[Kj\10j", 6) = 6 +read(3, 0xffffc41d9907, 1) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) +--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} --- +rt_sigaction(SIGINT, {sa_handler=0xaaaab214c5a8, sa_mask=[INT], sa_flags=SA_RESTART}, {sa_handler=0xaaaab214c5a8, sa_mask=[INT], sa_flags=SA_RESTART}, 8) = 0 +rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 +write(1, "\7\33[H\33[2J\33[H\33[H\33[2J\33[Himport asyn"..., 856) = 856 +read(3, "q", 1) = 1 +write(1, "\r\33[K\33[?1l\33>\33[?1049l\33[23;0;0t", 28) = 28 +close(4) = 0 +openat(AT_FDCWD, "/root/.local/state", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.lesshst", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.local/state", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.lesshsQ", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4 +fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0 +fchmod(4, 0600) = 0 +fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0 +openat(AT_FDCWD, "/root/.local/state", O_RDONLY) = -1 ENOENT (No such file or directory) +openat(AT_FDCWD, "/root/.lesshst", O_RDONLY) = -1 ENOENT (No such file or directory) +write(4, ".less-history-file:\n.search\n\"fdg"..., 55) = 55 +close(4) = 0 +renameat(AT_FDCWD, "/root/.lesshsQ", AT_FDCWD, "/root/.lesshst") = 0 +ioctl(3, TCSETSW, {c_iflag=ICRNL|IXON, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 +exit_group(0) = ? ++++ exited with 0 +++ diff --git a/drive.py b/drive.py new file mode 100644 index 00000000000000..0288f51aaa95a0 --- /dev/null +++ b/drive.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +import os +import select +import sys + +# Define FIFO paths (same as in the debug script) +INPUT_FIFO = "/tmp/pdb_input_fifo" +OUTPUT_FIFO = "/tmp/pdb_output_fifo" + + +def read_fifo(fifo, timeout=0.1): + rlist, _, _ = select.select([fifo], [], [], timeout) + if rlist: + return fifo.readline().strip() + return None + + +def main(): + if not os.path.exists(INPUT_FIFO) or not os.path.exists(OUTPUT_FIFO): + print("Error: FIFOs not found. Make sure the debug script is running.") + sys.exit(1) + + print("PDB FIFO Driver") + print("Type 'quit' or 'exit' to end the session.") + + with open(INPUT_FIFO, "w") as input_fifo, open(OUTPUT_FIFO, "r") as output_fifo: + while True: + # Check for any pending output + while True: + output = read_fifo(output_fifo) + if output is None: + break + print(output) + + # Get user input + try: + command = input("(Pdb) ") + except EOFError: + break + + if command.lower() in ("quit", "exit"): + break + + # Send command to PDB + input_fifo.write(command + "\n") + input_fifo.flush() + + # Wait for and print the response + while True: + output = read_fifo(output_fifo) + if output is None: + break + print(output) + + print("PDB session ended.") + + +if __name__ == "__main__": + main() diff --git a/lel.py b/lel.py new file mode 100644 index 00000000000000..4fe5e30036cc2d --- /dev/null +++ b/lel.py @@ -0,0 +1,13 @@ +import time + + +def foo(): + bar() + + +def bar(): + for _ in range(100): + time.sleep(1) + + +foo() diff --git a/lol.py b/lol.py new file mode 100644 index 00000000000000..7e633ead7b6178 --- /dev/null +++ b/lol.py @@ -0,0 +1,35 @@ +import asyncio +import time +import os + +async def test_stack_tgroup(): + + stack_for_c5 = None + + def c5(): + nonlocal stack_for_c5 + time.sleep(1000) + + async def c4(): + await asyncio.sleep(0) + c5() + + async def c3(): + await c4() + + async def c2(): + await c3() + + async def c1(task): + await task + + async def main(): + async with asyncio.TaskGroup() as tg: + task = tg.create_task(c2(), name="c2_root") + tg.create_task(c1(task), name="sub_main_1") + tg.create_task(c1(task), name="sub_main_2") + + await main() + +print(os.getpid()) +asyncio.run(test_stack_tgroup()) diff --git a/the_inspect.py b/the_inspect.py new file mode 100644 index 00000000000000..98252e05c0c863 --- /dev/null +++ b/the_inspect.py @@ -0,0 +1,4 @@ +from _testexternalinspection import get_stack_trace +import sys + +print(get_stack_trace(int(sys.argv[1])))