tl;dr: Using gdb to manipulate a running process is fun and just the right amount of danger to be exiting
Just to document this (a friend asked me): If you ever wanted for example to
globally change your $PATH, or add a global $LD_PRELOAD (for example to use
insulterr ;) ), without restarting
your session, gdb is your friend.
You can call arbitrary functions in the context of any process (that you are
priviledged to attach a debugger, it has to run under your uid or you have to
be root, see ptrace(2) for specifics), as long as they are linked. Almost
everything is linked to libld, so with enough effort this actually means
every function.
For example, suppose you are running i3wm and want to add
/home/user/insulterr/insulterr.so to your $LD_PRELOAD in every process
started by i3:
$ gdb -p `pidof i3` `which i3`
<lots of output of gdb>
gdb $ call setenv("LD_PRELOAD", "/home/user/insulterr/insulterr.so")
gdb $ quit
A debugging session is active.
Inferior 1 [process 2] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/bin/i3, process 2
This is of course a terrible hack, by high standards. Things to look out for are (off the top of my head):
- You call a function that manipulates
errnoor does some other non-reentrent things. If you are attaching the debugger right in the middle of a library call (or immediately after) this might make the program unhappy because it does not detect an error (or falsely thinks there is an error). - You call a function that does not work in a multithreaded context and another thread modifies it at the same time. Bad.
- You interrupt a badly checked
read(2)/write(2)/whatever(…)call and a badly written program doesn’t realize it got less data then expected (and/or crashes). Shouldn’t happen in practice, if it does, file a bug. - You try to use symbols that are not available. This is actually not very bad
and can be worked around (a friend of mine had the problem of needing
falseand just substituted 0). - You use a daemon (like
urxvtd(1)) for your terminals and the environment does not get passed correctly. This is also not very bad, just confusing. Attach your debugger to the daemon and change the environment there too. - You attach the debugger to some process vital to the interaction with your debugger. Your window manager is a mild example. The terminal daemon is slightly worse (because, well, you can’t actually type in the terminal window that your debugger is running in, ergo you can’t stop it…), but you can change to a virtual terminal. Something like getty or init might be killing it.
Have fun!