How can I make lldb ignore the EXC_BAD_ACCESS exception?

I am writing a program on Mac OSX depending on the sigaction / sa_handler mechanism. Run the code snippet from the user and be ready to catch signals / exceptions at any time. The program works fine, but the problem is that I cannot debug it with lldb. lldb seems unable to ignore any exceptions, even if I set

proc hand -p true -s false SIGSEGV 
proc hand -p true -s false SIGBUS

      

The control flow stops at the statement that throws the exception and doesn't go to the sa_handler I installed earlier, even tried the command c

. Output:

Process 764 stopped
* thread #2: tid = 0xf140, 0x00000001000b8000, stop reason = EXC_BAD_ACCESS (code=2, address=0x1000b8000)

      

How can I make lldb ignore the exception / signal and let the sa_handler program do its job?

EDIT: example code

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>

static void handler(int signo, siginfo_t *sigaction, void *context)
{
    printf("in handler.\n");
    signal(signo, SIG_DFL);
}

static void gen_exception()
{
    printf("gen_exception in.\n");
    *(int *)0 = 0;
    printf("gen_exception out.\n");
}

void *gen_exception_thread(void *parg)
{
    gen_exception();
    return 0;
}

int main()
{
    struct sigaction sa;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;

    if(sigaction(/*SIGBUS*/SIGSEGV, &sa, NULL) == -1) {
        printf("sigaction fails.\n");
        return 0;
    }

    pthread_t id;
    pthread_create(&id, NULL, gen_exception_thread, NULL);
    pthread_join(id, NULL);

    return 0;
}

      

+3


source to share


3 answers


I needed this on a recent project, so I just created my own LLDB. I have paved a line in tools/debugserver/source/MacOSX/MachTask.mm

from

err = ::task_set_exception_ports (task, m_exc_port_info.mask, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);

      

to



err = ::task_set_exception_ports (task, m_exc_port_info.mask & ~EXC_MASK_BAD_ACCESS, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);

      

which makes debugserver not catch exceptions EXC_BAD_ACCESS

. Now my custom LLDB works really well: it still catches SIGSEGV

and SIGBUS

but no longer goes into a silly endless loop when it encounters EXC_BAD_ACCESS

. Setting parameters process handle

on previously fatal signals is fine too, and now I can debug SEGV handlers with impunity.

Apple really should make this option in LLDB ... seems like a very lightweight solution for them.

+1


source


A bit of sample code might make a question like this much easier to answer ... I've never used the API sigaction

before, but I threw this together -

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void segv_handler (int in)
{
    puts ("in segv_handler()");
}

void sigbus_handler (int in)
{
    puts ("in sigbus_handler()");
}

int main ()
{
    struct sigaction action;
    action.sa_mask = 0;
    action.sa_flags = 0;


    action.sa_handler = segv_handler;
    sigaction (SIGSEGV, &action, NULL);
    action.sa_handler = sigbus_handler;
    sigaction (SIGBUS, &action, NULL);

    puts ("about to send SIGSEGV signal from main()");
    kill (getpid(), SIGSEGV);

    puts ("about to send SIGBUS signal from main()");
    kill (getpid(), SIGBUS);

    puts ("exiting main()");

}


% lldb a.out
(lldb) br s -n main
(lldb) r
(lldb) pr h -p true -s false SIGSEGV SIGBUS
(lldb) c
Process 54743 resuming
about to send SIGSEGV signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGSEGV
in segv_handler()
about to send SIGBUS signal from main()
Process 54743 stopped and restarted: thread 1 received signal: SIGBUS
in sigbus_handler()
exiting main()
Process 54743 exited with status = 0 (0x00000000) 
(lldb) 

      



Everything looks like it is working correctly here. If I added -n false

to the arguments process handle

, lldb would not print the lines about Process .. stopped and restarted

.

Note that these alarm settings are not saved across processes. So, if you start your debug session ( r

after you've already started the process once), you will need to reinstall it. You can create a shortcut with a command alias and place it in your file ~/.lldbinit

so that you can customize the process handling the way you prefer with a short cmd.

+1


source


This is a long-standing bug in the debugger interface on Mac OS X (gdb had the same problem ...) If you have a developer account, please post a bug from http://bugreport.apple.com . So few people actually use SIGSEGV handlers that the problem never pays attention to the kernel people, so more bugs are good ...

+1


source







All Articles