3 ms·
ptrace is a genuinely terrible API. There is literally nothing it's well-designed for -- any task more complex than stopping a process and reading/writing a sin
by duskwuff 6y ago
ptrace is a genuinely terrible API. There is literally nothing it's well-designed for -- any task more complex than stopping a process and reading/writing a single memory location or register is awkward to execute and prone to errors. Special mention goes to its use of signals for IPC, which makes ptrace() nearly impossible to use in multithreaded applications or high-level languages, and is especially prone to "gotchas" and implementation errors. (IIRC, tracing a process which receives an external SIGTRAP signal is especially difficult, as ptrace() uses that signal to indicate that the traced process made a system call.)
- saagarjha 6y ago> There is literally nothing it's well-designed for -- any task more complex than stopping a process and reading/writing a single memory location or register is awkward to execute and prone to errors. Not only that, if you're writing a debugger you all but have to lean on parsing procfs, which itself is a really horrible API… > Special mention goes to its use of signals for IPC, which makes ptrace() nearly impossible to use in multithreaded applications or high-level languages, and is especially prone to "gotchas" and implementation errors. Yep, you really gotta keep track of all your tracees. If you're not aggressively making sure you're notified of every single thing a tracee can possibly do to change itself (and there sure is a lot) you're going to have a really bad time. > IIRC, tracing a process which receives an external SIGTRAP signal is especially difficult, as ptrace() uses that signal to indicate that the traced process made a system call. Ooh, I know this! I just came off of implementing it on the kernel side because GDB obviously cares (and if you don't do it right, it won't "rewind" one instruction after the child stops when necessary and your disassembly will be off). You're supposed to call ptrace(PTRACE_GETSIGINFO, …) and check si_code, which for a real signal will be SIGTRAP (yes, the value of SIGTRAP itself; 5 on my machine) and for a syscall stop will be SI_USER (0 on my machine). Of course you'll only get a stop on a system call if you specifically request it, and I think some newer kernels support PTRACE_O_TRACESYSGOOD, which is meant for this kind of thing, but I did the laziest job I possibly could in my implementation and just told userspace I don't support such things ;)