[lldb-dev] Not stopping on EXC_BAD_ACCESS

Heath Borders heath.borders at gmail.com
Sat Oct 19 23:11:34 PDT 2013


(Sorry, I just discovered this list, and I don't know how to properly jump
into a thread I didn't receive in email. I tried to replicate quoting
one-level deep.)

I want to be notified when a __weak reference in one of my objects is about
to be nil-ed. I accomplish this by allocating the object into a specific VM
page and then marking the page as read-only. When ARC nils the __weak
reference, I get an EXC_BAD_ACCESS, and I can mark the VM page as
read-write, run my tear-down code while the object is still valid, and then
return KERN_SUCCESS, which will allow ARC to continue on. However, as
Richard described earlier, LLDB hangs when I set a breakpoint inside any
code that isn't my exception handler when I use task_set_exception_ports.

You suggested using thread_set_exception_ports to fix this issue. I assume
that thread_set_exception_ports only takes over exceptions that occur on
the thread given to thread_set_exception_ports, and not for the whole task,
like task_set_exception_ports does. Thus, I would need to call
thread_set_exception_ports on every thread since I care about getting an
EXC_BAD_ACCESS exception that occurs on any thread, right? My handler isn't
called if I register for exceptions with a different thread.

Is there a way to be notified when a thread is created so I can subscribe
to its messages?

Also, I still see LLDB hanging when a use thread_set_exception_ports. Am I
doing something wrong? My code is below:

kern_return_t catch_exception_raise(mach_port_t exception_port,
                                    mach_port_t thread,
                                    mach_port_t task,
                                    exception_type_t exception,
                                    exception_data_t code_vector,
                                    mach_msg_type_number_t code_count) {
    x86_exception_state32_t x86_exception_state32;
 mach_msg_type_number_t sc = x86_EXCEPTION_STATE32_COUNT;

thread_get_state(thread,
                     x86_EXCEPTION_STATE32,
                     (thread_state_t)&x86_exception_state32,
                     &sc);

// pull fault address from x86_exception_state32
// check that it is an expected address
// make the page read-write
// do cleanup

    return KERN_SUCCESS;
}

void *exception_handler(void *arg) {
    extern boolean_t exc_server();
    mach_port_t port = (mach_port_t) arg;
    mach_msg_server(exc_server, 2048, port, 0);
    abort(); // without this GCC complains (it doesn't know that
mach_msg_server never returns)
}

// Does this need to be called on every thread?
// I assume exception_port can be reused. Is this true?
void setup_mach_exception_port() {
    static mach_port_t exception_port = MACH_PORT_NULL;
    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
&exception_port);
    mach_port_insert_right(mach_task_self(), exception_port,
exception_port, MACH_MSG_TYPE_MAKE_SEND);
// using task_set_exception_ports causes LLDB to hang...
// ...whenever it hits breakpoint outside of catch_exception_raise
// task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS,
exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
    thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS,
exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);
    pthread_t returned_thread;
    pthread_create(&returned_thread, NULL, exception_handler, (void*)
exception_port);
}

On Jul 8, 2013, at 12:41 PM, Greg Clayton <gclayton at apple.com> wrote:

> Not many people actually take over their own mach exception ports, so this
> isn't something that hits a lot of people. It mainly hits the GC folks and
> the Runtime (Java) folks that need to intercept NULL derefs.
> We do know about the issue and have plans to address this in the future.
> The solution that works right now is to take over EXC_BAD_ACCESS on the
> _thread_ mach port. GDB and LLDB take over the task exception ports but we
> leave the thread exception ports alone. The thread mach ports will get the
> exception first, and if not handled, will pass it along to the task
> exception ports. Depending on your architecture, you might easily be able
> to do this, or it might be difficult.
> Greg Clayton



-Heath Borders
heath.borders at gmail.com
Twitter: heathborders
http://heath-tech.blogspot.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/lldb-dev/attachments/20131020/bb899574/attachment.html>


More information about the lldb-dev mailing list