Catch SIGINT in Xcode 12.5.1

In Xcode, I want to do something when ctrl + c is pressed, but it looks like lldb doesn't catch SIGINT signal.

I also tried the solution:

process handle SIGINT -s false
process handle SIGINT -p true

Still, it does nothing. What am I doing wrong?

I’m not entirely sure what you goal is here. You mentioned Xcode, so it seems like your using LLDB via Xcode’s GUI. Right? And you wrote:

I want to do something when ctrl + c is pressed

Do what? Stop the debugged process in the debugger? If so, ^C isn’t how that works in Xcode. Rather, you press the Pause button (or choose Debug > Pause, or press command-control-Y).

If that’s not what you’re looking for, please clarify.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Example:

#include <stdio.h>
#include <signal.h>
  
void sigintHandler(int sig_num)
{
    signal(SIGINT, sigintHandler);
    printf("I'm doing something \n");
    fflush(stdout);
}
  
int main ()
{
    signal(SIGINT, sigintHandler);
  
    while(1)
    {        
    }
    return 0;
}

Yes, I am using LLDB.

So, to be clear, you’re running a program in Xcode and thus using Xcode’s built-in LLDB to debug it? Right? As opposed to running the program using the lldb command line tool?

Assuming that, you’re correct that Xcode’s console panel does not map ^C to SIGINT.

I have a bunch of hints and tips on this front.

The traditional BSD approach for this is to use SIGINFO rather than SIGINT. You can generate that in Terminal using ^T.

Of course, Xcode’s console panel doesn’t support that either (-: To get around this, run your program with its standard I/O channels connect to a Terminal window. To do this, go to Product > Scheme > Edit Scheme > Run > Options and change Console from Use Xcode to Use Terminal.

You’ll also need to disable SIGINFO handling in LLDB:

(lldb) process handle -p true -s false -n false SIGINFO

When SIGINT is received by the program, I want to print out a simple string.

Example:

Your example is not safe because it calls routines that are not async signal safe. See the sigaction man page for a list of those routines (it’s very short!).


So, tying this all together:

  1. Create a new command-line tool project whose main.c looks like this:

    #include <sys/time.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    static void handleSIGINFO(int _) {
        #pragma unused(_)
        write(STDERR_FILENO, "Hello Cruel World!\n", 19);
    }
    
    int main(int argc, char **argv) {
        #pragma unused(argc)
        #pragma unused(argv)
        signal(SIGINFO, handleSIGINFO);
        while (1) {
            struct timeval tv;
            gettimeofday(&tv, NULL);
            fprintf(stderr, "%ld.%ld\n", (long) tv.tv_sec, (long) tv.tv_usec);
            sleep(1);
        }
        return EXIT_SUCCESS;
    }
    
  2. Set it to use Terminal as the console, per the instructions above.

  3. Run it.

  4. Choose Debug > Pause.

  5. In the Xcode console, enter this:

    (lldb) process handle -p true -s false -n false SIGINFO
    NAME         PASS   STOP   NOTIFY
    ===========  =====  =====  ======
    SIGINFO      true   false  false
    

    Note You can automate this step using LLDB scripting.

  6. Resume the program.

  7. Switch to Terminal and press ^T.

  8. You’ll see output like this:

    % … lots of Xcode goo …
    … even more Xcode goo …
    1638792673.625175
    …
    1638792683.125808
    ^T
    load: 1.37  cmd: xxot 38172 running 0.24u 0.05s
    Hello Cruel World!
    1638792683.703585
    …
    

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Catch SIGINT in Xcode 12.5.1
 
 
Q