<div dir="ltr"><div><span style="color:rgb(0,0,0);white-space:pre-wrap">(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.)</span><font color="#000000"><span style="white-space:pre-wrap"><br>
</span></font></div><div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap">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.</span></font></div>
<div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap">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.</span></font></div>
<div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap">Is there a way to be notified when a thread is created so I can subscribe to its messages?</span></font></div>
<div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap">Also, I still see LLDB hanging when a use thread_set_exception_ports. Am I doing something wrong? My code is below:</span></font></div>
<div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><div style="white-space:pre-wrap">kern_return_t catch_exception_raise(mach_port_t exception_port,</div><div style="white-space:pre-wrap">
                                    mach_port_t thread,</div><div style="white-space:pre-wrap">                                    mach_port_t task,</div><div style="white-space:pre-wrap">                                    exception_type_t exception,</div>
<div style="white-space:pre-wrap">                                    exception_data_t code_vector,</div><div style="white-space:pre-wrap">                                    mach_msg_type_number_t code_count) {</div><div style="white-space:pre-wrap">
    x86_exception_state32_t x86_exception_state32;</div><div> <span style="white-space:pre-wrap">    mach_msg_type_number_t sc = x86_EXCEPTION_STATE32_COUNT;</span></div><div style="white-space:pre-wrap">    </div><div><span style="white-space:pre-wrap">    thread_get_state(thread,</span></div>
<div style="white-space:pre-wrap">                             x86_EXCEPTION_STATE32,</div><div style="white-space:pre-wrap">                             (thread_state_t)&x86_exception_state32,</div><div style="white-space:pre-wrap">
                             &sc);</div><div style="white-space:pre-wrap"><br></div><div style="white-space:pre-wrap">    // pull fault address from x86_exception_state32</div><div style="white-space:pre-wrap">    // check that it is an expected address</div>
<div style="white-space:pre-wrap">    // make the page read-write</div><div style="white-space:pre-wrap">    // do cleanup</div><div style="white-space:pre-wrap"><br></div><div style="white-space:pre-wrap">    return KERN_SUCCESS;  </div>
<div style="white-space:pre-wrap">}</div></font></div><div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap"><div>void *exception_handler(void *arg) {</div>
<div>    extern boolean_t exc_server();</div><div>    mach_port_t port = (mach_port_t) arg;</div><div>    mach_msg_server(exc_server, 2048, port, 0);</div><div>    abort(); // without this GCC complains (it doesn't know that mach_msg_server never returns)</div>
<div>}</div></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap"><br></span></font></div><div><font color="#000000"><span style="white-space:pre-wrap">// Does this need to be called on every thread?</span></font></div>
<div><font color="#000000"><span style="white-space:pre-wrap">// I assume exception_port can be reused. Is this true?</span></font></div><div><font color="#000000"><span style="white-space:pre-wrap"><div>void setup_mach_exception_port() {</div>
<div>    static mach_port_t exception_port = MACH_PORT_NULL;</div><div>    mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &exception_port);</div><div>    mach_port_insert_right(mach_task_self(), exception_port, exception_port, MACH_MSG_TYPE_MAKE_SEND);</div>
<div>    // using task_set_exception_ports causes LLDB to hang...</div><div>    // ...whenever it hits breakpoint outside of catch_exception_raise</div></span></font><font color="#000000"><span style="white-space:pre-wrap"><div>
    // <span style="color:rgb(34,34,34)">task_set_exception_ports(mach_task_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);</span></div></span></font>







<font color="#000000"><span style="white-space:pre-wrap"><div>    thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, exception_port, EXCEPTION_DEFAULT, MACHINE_THREAD_STATE);</div><div>    pthread_t returned_thread;</div>
<div>    pthread_create(&returned_thread, NULL, exception_handler, (void*) exception_port);</div><div>}</div></span></font></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap"><br></span></div><div><span style="color:rgb(0,0,0);white-space:pre-wrap">On Jul 8, 2013, at 12:41 PM, Greg Clayton <gclayton at <a href="http://apple.com">apple.com</a></span><span style="color:rgb(0,0,0);white-space:pre-wrap">> wrote:</span> </div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">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.<br>
We do know about the issue and have plans to address this in the future.<br>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.<br>
Greg Clayton</blockquote><br><br>-Heath Borders<br><a href="mailto:heath.borders@gmail.com">heath.borders@gmail.com</a><br>Twitter: heathborders<br><a href="http://heath-tech.blogspot.com">http://heath-tech.blogspot.com</a></div>