On Oct 19, 2013, at 11:11 PM, Heath Borders <[email protected]> wrote:

> (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.

If you were watching all the exception types on the task exception port, then 
it would make sense to me that we would hang trying to continue, since lldb 
uses EXC_BREAKPOINT for its own purposes and if it is not seeing that, it won't 
be able to run its execution logic.  But if you are only watching for the 
EXC_BAD_ACCESS exception then lldb it shouldn't care about this (besides that 
lldb won't ever see real crashes.)  

Anyway, check that you really are only registering for the EXC_BAD_ACCESS 
exception when you do the {task,thread}_set_exception_ports.  Or, see below, 
maybe this is happening because you aren't replying to the exception message?

> 
> 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?

Not that I am aware of.  There's no very good way to to watch for exceptions on 
threads you didn't create using the thread exception port, at least not one I 
know about.

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

Is lldb hanging, or is your program hanging?  If lldb is hanging, can you file 
a bug with the backtrace of lldb (and a sample program if you can easily whip 
one up...)

If it is your program that is hanging make sure you are sending on the reply 
message that you get when your catch_exception_raise returns KERN_SUCCESS.  
Maybe that is what mach_msg_server does, I've never used that function so I 
don't know.  In lldb we call mach_exc_server to trigger the call to 
catch_exception_raise and that returns a reply right that you have to send on 
to the appropriate exception port for the process to continue.  If you don't do 
that your program won't make progress.  As I said, that may be already handled 
in mach_msg_server, I don't know, not having done it that way, but that's the 
only thing I can think of that might hang you up.  You can check out how lldb 
does this here:

http://llvm.org/svn/llvm-project/lldb/trunk/tools/debugserver/source/MacOSX/MachException.cpp

Jim


> 
> 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
> [email protected]
> Twitter: heathborders
> http://heath-tech.blogspot.com
> _______________________________________________
> lldb-dev mailing list
> [email protected]
> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

_______________________________________________
lldb-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev

Reply via email to