I'd like to debug a thread crash in a TUI program. When I do it with rust-gdb the normal way, gdb's stdout and the TUI's stdout interfere with one another. When the crash happens, I'm unable to execute commands like down to examine what happened. I see things like this when I type:
How can I properly TUI programs with gdb? Is there, for example, a trick to launch the process in one terminal window and attach gdb to it in another?
Not sure if attaching a debugger will automatically capture stdout/stderr from the debugged process though. Not currently on a system with gdb, so I can't check.
Another way to do it is to run gdbserver in the window where you want the TUI, then attach to that from a separate gdb session. The server will be the direct parent for ptrace-security considerations.
If I understand the sources correctly, there's a security policy preventing processes from debugging arbitrary processes unless I somehow manage to run the debugger as a child process of the debug target?
It has been years since I used it, and I'm on my phone so can't easily check right now. But I believe another option is to tell gdb to use a different TTY for the child program. I seem to remember doing this many years ago.
However, on a developer computer it is not unreasonable to run with (or occasionally switch to) the laxer policy that allows tracing any other program from the same user.
I've also read that in C it's possible to let your debug target do a special call at the start of execution to allow other processes to debug it, but I haven't found a Rust equivalent to it yet.
For now I suppose I can work around it by temporarily disabling the security as Vorpal suggests. For completeness' sake, this is the command:
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
Remember to set it back to its original value afterwards. For me this was 1. Quoting the man page:
0 ("classic ptrace permissions")
No additional restrictions on operations that perform PTRACE_MODE_ATTACH checks (beyond those imposed by the commoncap and other LSMs).
The use of PTRACE_TRACEME is unchanged.
1 ("restricted ptrace") [default value]
When performing an operation that requires a PTRACE_MODE_ATTACH check, the calling process must either have the CAP_SYS_PTRACE capability
in the user namespace of the target process or it must have a predefined relationship with the target process. By default, the predefined
relationship is that the target process must be a descendant of the caller.
A target process can employ the prctl(2) PR_SET_PTRACER operation to declare an additional PID that is allowed to perform PTRACE_MODE_AT‐
TACH operations on the target. See the kernel source file Documentation/admin-guide/LSM/Yama.rst (or Documentation/security/Yama.txt be‐
fore Linux 4.13) for further details.
The use of PTRACE_TRACEME is unchanged.
You could do the exact same call. Just use the libc crate or maybe nix or rustix. I would expect at least one of them have mapped the specific flag values and prctl will be mapped for sure. For libc you will need unsafe for sure, you might not need it for the other ones.
That's an interesting idea, although I haven't really bridged from Rust to C before. I've seen the official code example but I'm not sure how this works with the #include <sys/prctl.h> dependency. The LLM I asked about it outputted something fairly convoluted.
The nix crate has a prctl module. I don't see a function in there that seems to allow any ptracer though.
and any other constant you might need (I think there were two in total?)
Nix might not have a wrapper, it tries to be higher level, so it a nice option when it has it. And rustix doesn't seem to have much in this case at all (it is narrower in scope and usually somewhere in between libc and nix in terms of abstraction level).