Send Ctrl-C to app in LLDB - macos

I have an CLI app that is seg faulting during termination (After sending a Ctrl-C)
Pressing Ctrl-C in lldb naturally pauses execution.
Then I try:
(lldb)process signal SIGINT
(lldb)process continue
But that doesn't actually seem to do anything to terminate the app.
Also tried:
(lldb)process signal 2

The debugger uses ^C for interrupting the target, so it assumes that you don't actually want the ^C propagated to the target. You can change this behavior by using the "process handle" command:
(lldb) process handle SIGINT -p true
telling lldb to "pass" SIGINT to the process.
If you had stopped the process in lldb by issuing a ^C, then when you change the process handle as shown here and continue, that SIGINT will be forwarded to the process.
If you stopped for some other reason, after specifying SIGINT to be passed to the process, you can generate a SIGINT by getting the PID of the debugee using the process status and send a SIGINT directly to said process using platform shell:
(lldb) process status
(lldb) platform shell kill -INT {{PID from previous step}}
(lldb) continue

The easiest way I found was just to send the process a SIGINT directly. Take the pid of the debuggee process (which process status will show you) and run
kill -INT <pid>
from another terminal.

Related

How can I send a signal without the shell waiting for the currently running program to finish?

If I send a signal using kill, it seems to wait until the current program (in this example sleep 1000) finishes running. When I instead send SIGINT via pressing Ctrl+C in the shell, it receives the interrupt immediately however.
What I want, however, is for the interrupt to be received immediately after sending the signal via kill. Also, why does it behave like I would want it to when I press Ctrl+C?
#!/usr/bin/env sh
int_after_a_while() {
local pid=$1
sleep 2
echo "Attempting to kill $pid with SIGINT"
# Here I want to kill the process immediately, but it waits until sleep finishes
kill -s INT $pid
}
trap "echo Interrupt received!" INT
int_after_a_while $$ &
sleep 1000
I would appreciate any help on this issue. Thanks in advance!
As noted in the referenced answer https://unix.stackexchange.com/questions/282525/why-did-my-trap-not-trigger/282631#282631 the shell will normally wait for a utility to complete before running a trap. Some alternatives are:
Start the long running process in the background, then wait for it using the wait builtin. When a trapped signal is received during such a wait, the wait is interrupted and the trap is taken. Unfortunately, the exit status of wait does not distinguish between the child process exiting on a signal and a trap occurring. For example
sleep 1000 &
p=$!
wait "$p"
Send a signal to the whole process group via kill -s INT 0. The effect is much like if the user had pressed Ctrl+C, but may be more extreme than you want if your script is run from another script.
Use a shell such as zsh or FreeBSD sh that supports set -o trapsasync which allows running traps while waiting for a foreground job.

Background process getting killed when its parent is terminated?

I have code that looks something like this
function doTheThing{
# a potentially infinite while loop...
}
# other stuff...
doTheThing &
trap "kill $!" SIGINT SIGTERM
Strangely, when I ctrl-C out of the parent process before the loop is done, I get a message that the process doesn't exist. Furthermore, if I get rid of the trap, I can't find the process with a ps -aF. It looks like the background process is getting killed when its parent is terminated, but my understanding was that wasn't supposed to happen. I just want to make sure that I can safely leave out the trap and not leave zombie processes everywhere.
The POSIX specification says that when you type the interrupt character (normally Control-C) the SIGINT is sent to the foreground process group. So as long as the background process is running in the same process group as the script that invoked it, it will receive the signal at the same time as the script process.
Shells generally use process groups to implement job control, and by default this is only enabled in interactive shells, not shells running scripts. There's no standard way to run a function in its own process group, but you could use setsid to run it in a new session, which is an even higher level of grouping than process groups. Then it wouldn't receive the interrupt.
You might still want to write a trap command that kills the function on EXIT, though.
doTheThing&
trap "kill $!" EXIT
since exiting the script doesn't automatically kill the rest of the process group.

shell script process termination issue

/bin/sh -version
GNU sh, version 1.14.7(1)
exitfn () {
# Resore signal handling for SIGINT
echo "exiting with trap" >> /tmp/logfile
rm -f /var/run/lockfile.pid # Growl at user,
exit # then exit script.
}
trap 'exitfn; exit' SIGINT SIGQUIT SIGTERM SIGKILL SIGHUP
The above is my function in shell script.
I want to call it in some special conditions...like
when:
"kill -9" fires on pid of this script
"ctrl + z" press while it is running on -x mode
server reboots while script is executing ..
In short, with any kind of interrupt in script, should do some action
eg. rm -f /var/run/lockfile.pid
but my above function is not working properly; it works only for terminal close or "ctrl + c"
Kindly don't suggest to upgrade "bash / sh" version.
SIGKILL cannot be trapped by the trap command, or by any process. It is a guarenteed kill signal, that by it's definition cannot be trapped. Thus upgrading you sh/bash will not work anyway.
You can't trap kill -9 that's the whole point of it, to destroy processes violently that don't respond to other signals (there's a workaround for this, see below).
The server reboot should first deliver a signal to your script which should be caught with what you have.
As to the CTRL-Z, that also gives you a signal, SIGSTOP from memory, so you may want to add that. Though that wouldn't normally be a reason to shut down your process since it may be then put into the background and restarted (with bg).
As to what do do for those situations where your process dies without a catchable signal (like the -9 case), the program should check for that on startup.
By that, I mean lockfile.pid should store the actual PID of the process that created it (by using echo $$ >/var/run/myprog_lockfile.pid for example) and, if you try to start your program, it should check for the existence of that process.
If the process doesn't exist, or it exists but isn't the right one (based on name usually), your new process should delete the pidfile and carry on as if it was never there. If the old process both exists and is the right one, your new process should log a message and exit.

How does trap / kill work in bash on Linux?

My sample file
traptest.sh:
#!/bin/bash
trap 'echo trapped' TERM
while :
do
sleep 1000
done
$ traptest.sh &
[1] 4280
$ kill %1 <-- kill by job number works
Terminated
trapped
$ traptest.sh &
[1] 4280
$ kill 4280 <-- kill by process id doesn't work?
(sound of crickets, process isn't killed)
If I remove the trap statement completely, kill process-id works again?
Running some RHEL 2.6.18-194.11.4.el5 at work. I am really confused by this behaviour, is it right?
kill [pid]
send the TERM signal exclusively to the specified PID.
kill %1
send the TERM signal to the job #1's entire process group, in this case to the script pid + his children (sleep).
I've verified that with strace on sleep process and on script process
Anyway, someone got a similar problem here (but with SIGINT instead of SIGTERM): http://www.vidarholen.net/contents/blog/?p=34.
Quoting the most important sentence:
kill -INT %1 sends the signal to the job’s process group, not the backgrounded pid!
This is expected behavior. Default signal sent by kill is SIGTERM, which you are catching by your trap. Consider this:
#!/bin/bash
# traptest.sh
trap "echo Booh!" SIGINT SIGTERM
echo "pid is $$"
while : # This is the same as "while true".
do
a=1
done
(sleep really creates a new process and the behavior is clearer with my example I guess).
So if you run traptest.sh in one terminal and kill TRAPTEST_PROCESS_ID from another terminal, output in the terminal running traptest will be Booh! as expected (and the process will NOT be killed). If you try sending kill -s HUP TRAPTEST_PROCESS_ID, it will kill the traptest process.
This should clear up the %1 confusion.
Note: the code example is taken from tldp
Davide Berra explained the difference between kill %<jobspec> and kill <PID>, but not how that difference results in what you observed. After all, Unix signal handlers should be called pretty much instantaneously, so why does sending a SIGTERM to the script alone not trigger its trap handler?
The bash man page explains why, in the last paragraph of the SIGNALS section:
If bash is waiting for a command to complete and receives a signal for
which a trap has been set, the trap will not be executed until the
command completes.
So, the signal was delivered immediately, but the handler execution was deferred until sleep exited.
Hence, with kill %<jobspec>:
Both the script and sleep received SIGTERM
bash registered the signal, noticed that a trap was set for it, and queued the handler for future execution
sleep exited immediately
bash noted sleep's exit, and ran the trap handler
whereas with kill <script_PID>:
Only the script received SIGTERM
bash registered the signal, noticed that a trap was set for it, and queued the handler for future execution
sleep exited after 1000 seconds
bash noted sleep's exit, and ran the trap handler
Obviously, you didn't want long enough to see that last bit. :)
If you're interested in the gory details, download the bash source code and look in trap.c, specifically the trap_handler() and run_pending_traps() functions.

How do I generate a SIGINT when using XCode to debug?

My console app traps SIGINT so it can exit gracefully.
Pressing CTRL+C inside XCode while the program is being debugged, though, has no effect.
I can find the process and use a terminal window to send a SIGINT to my process, however I'm hoping there's a simpler solution that I can do within XCode.
The pause button of the debugger console actually sends a SIGINT to your app.
If you want to make the debugger pass the signal to your app you can do the following:
Press the pause button of the debugger and wait for the debug console to gain focus
Type handle SIGINT pass and press ENTER
Press the Continue button
Now pressing again the Pause button of the debugger console of Xcode will make the SIGINT hit your app.
If you don't want the debugger to stop as soon as the SIGINT is caught you might also want to add handle SIGINT nostop to the previous list.
Update for 2017 / Xcode 8: the proper command(s) for informing lldb of your intention for handling interrupts:
process handle SIGINT -s false
process handle SIGINT -p true
In my experience, even with the above commands, the pause feature of the debugger still will interrupt the app and yield control to the debugger's stack pointer, however a pkill -2 appname at the terminal will trigger your interrupt function without any interaction with the debugger, for example:
void on_signal(int sig) {
is_interrupted = 1;
}
int main(int argc, const char * argv[]) {
signal(SIGINT, on_signal);
// ... do stuff
}
In Xcode 5+ (llvm):
Pause the process
At the (llvm) prompt, enter process signal SIGINT
Resume execution
One solution is to use the UNIX kill or killall commands.
If you know the Process ID you can open the Terminal application and type:
kill -SIGINT 415
(where 415 is the PID for this process)
Or, perhaps easier, you can type
killall -SIGINT my_console_app
(where my_console_app is the name of your app, i.e. the name of the binary created — not the bundle if it's in one)
This will send the signal to all instances of the application, as the name killall suggests, so it may not be appropriate. It might be worth checking if there are other processes with the same name running before you do a killall (;
One of the work-arounds to the hassel of working with interrupts is making a MainMenu with a CTRL-C short-cut that executes your requested routine, or sends itself a SIGINT, if you really need the sig.
Update for XCode 12+
In the modern versions of XCode it is hard to intercept SIGINT. For debug purposes it is better to use SIGINFO in place of SIGINT. You can generate that in Terminal using ^T (CTRL+T).
So during debugging temporary replace SIGINT with SIGINFO in your code. To intercept SIGINFO try next steps all together:
Go to Product > Scheme > Edit Scheme > Run > Options and change Console from Use Xcode to Use Terminal.
Run your program
Pause the program
In the Xcode console, enter this:
(lldb) process handle -p true -s false -n false SIGINFO
You will get:
NAME PASS STOP NOTIFY
=========== ===== ===== ======
SIGINFO true false false
Resume the program
Switch to Terminal and press CTRL+T.
Your signal handler will fire.
Don't forget to return SIGINT back after finishing debugging!

Resources