3333static void * FIRCLSMachExceptionServer (void * argument );
3434static bool FIRCLSMachExceptionThreadStart (FIRCLSMachExceptionReadContext * context );
3535static bool FIRCLSMachExceptionReadMessage (FIRCLSMachExceptionReadContext * context ,
36- MachExceptionMessage * message );
36+ MachExceptionProtectedMessage * message );
3737static kern_return_t FIRCLSMachExceptionDispatchMessage (FIRCLSMachExceptionReadContext * context ,
38- MachExceptionMessage * message );
38+ MachExceptionProtectedMessage * message );
3939static bool FIRCLSMachExceptionReply (FIRCLSMachExceptionReadContext * context ,
40- MachExceptionMessage * message ,
40+ MachExceptionProtectedMessage * message ,
4141 kern_return_t result );
4242static bool FIRCLSMachExceptionRegister (FIRCLSMachExceptionReadContext * context );
4343static bool FIRCLSMachExceptionUnregister (FIRCLSMachExceptionOriginalPorts * originalPorts ,
4444 exception_mask_t mask );
4545static bool FIRCLSMachExceptionRecord (FIRCLSMachExceptionReadContext * context ,
46- MachExceptionMessage * message );
47-
46+ MachExceptionProtectedMessage * message );
47+ static void FIRCLSCrashedThreadLookup ( MachExceptionProtectedMessage * message , thread_t * crashedThread );
4848#pragma mark - Initialization
4949void FIRCLSMachExceptionInit (FIRCLSMachExceptionReadContext * context ) {
5050 if (!FIRCLSUnlinkIfExists (context -> path )) {
@@ -166,7 +166,7 @@ static void* FIRCLSMachExceptionServer(void* argument) {
166166 pthread_setname_np ("com.google.firebase.crashlytics.MachExceptionServer" );
167167
168168 while (1 ) {
169- MachExceptionMessage message ;
169+ MachExceptionProtectedMessage message ;
170170
171171 // read the exception message
172172 if (!FIRCLSMachExceptionReadMessage (context , & message )) {
@@ -188,12 +188,12 @@ static void* FIRCLSMachExceptionServer(void* argument) {
188188}
189189
190190static bool FIRCLSMachExceptionReadMessage (FIRCLSMachExceptionReadContext * context ,
191- MachExceptionMessage * message ) {
191+ MachExceptionProtectedMessage * message ) {
192192 mach_msg_return_t r ;
193193
194- memset (message , 0 , sizeof (MachExceptionMessage ));
194+ memset (message , 0 , sizeof (MachExceptionProtectedMessage ));
195195
196- r = mach_msg (& message -> head , MACH_RCV_MSG | MACH_RCV_LARGE , 0 , sizeof (MachExceptionMessage ),
196+ r = mach_msg (& message -> head , MACH_RCV_MSG | MACH_RCV_LARGE , 0 , sizeof (MachExceptionProtectedMessage ),
197197 context -> port , MACH_MSG_TIMEOUT_NONE , MACH_PORT_NULL );
198198 if (r != MACH_MSG_SUCCESS ) {
199199 FIRCLSSDKLog ("Error receiving mach_msg (%d)\n" , r );
@@ -206,14 +206,19 @@ static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* conte
206206}
207207
208208static kern_return_t FIRCLSMachExceptionDispatchMessage (FIRCLSMachExceptionReadContext * context ,
209- MachExceptionMessage * message ) {
209+ MachExceptionProtectedMessage * message ) {
210210 FIRCLSSDKLog ("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n" , message -> exception ,
211211 message -> codeCnt , message -> codeCnt > 0 ? message -> code [0 ] : -1 ,
212212 message -> codeCnt > 1 ? message -> code [1 ] : -1 );
213213
214214 // This will happen if a child process raises an exception, as the exception ports are
215215 // inherited.
216- if (message -> task .name != mach_task_self ()) {
216+ mach_port_t actual_port ;
217+ kern_return_t kr ;
218+ task_id_token_t token = message -> task_id .name ;
219+ kr = task_identity_token_get_task_port (token , TASK_FLAVOR_CONTROL , & actual_port );
220+
221+ if (kr || actual_port != mach_task_self ()) {
217222 FIRCLSSDKLog ("Mach exception task mis-match, returning failure\n" );
218223 return KERN_FAILURE ;
219224 }
@@ -240,7 +245,7 @@ static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadC
240245}
241246
242247static bool FIRCLSMachExceptionReply (FIRCLSMachExceptionReadContext * context ,
243- MachExceptionMessage * message ,
248+ MachExceptionProtectedMessage * message ,
244249 kern_return_t result ) {
245250 MachExceptionReply reply ;
246251 mach_msg_return_t r ;
@@ -296,7 +301,7 @@ static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context)
296301
297302 // ORing with MACH_EXCEPTION_CODES will produce 64-bit exception data
298303 kr = task_swap_exception_ports (task , context -> mask , context -> port ,
299- EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES , THREAD_STATE_NONE ,
304+ EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES , THREAD_STATE_NONE ,
300305 context -> originalPorts .masks , & context -> originalPorts .count ,
301306 context -> originalPorts .ports , context -> originalPorts .behaviors ,
302307 context -> originalPorts .flavors );
@@ -333,7 +338,7 @@ static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* orig
333338
334339 // Finally, mark any masks we registered for that do not have an original port as unused.
335340 kr = task_set_exception_ports (mach_task_self (), mask , MACH_PORT_NULL ,
336- EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES , THREAD_STATE_NONE );
341+ EXCEPTION_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES , THREAD_STATE_NONE );
337342 if (kr != KERN_SUCCESS ) {
338343 FIRCLSSDKLog ("unable to unset unregistered mask: 0x%x" , mask );
339344 return false;
@@ -472,7 +477,7 @@ void FIRCLSMachExceptionNameLookup(exception_type_t number,
472477}
473478
474479static bool FIRCLSMachExceptionRecord (FIRCLSMachExceptionReadContext * context ,
475- MachExceptionMessage * message ) {
480+ MachExceptionProtectedMessage * message ) {
476481 if (!context || !message ) {
477482 return false;
478483 }
@@ -520,13 +525,53 @@ static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context,
520525
521526 FIRCLSFileWriteSectionEnd (& file );
522527
523- FIRCLSHandler (& file , message -> thread .name , NULL , true);
528+ thread_t crashedThread ;
529+ FIRCLSCrashedThreadLookup (message , & crashedThread );
530+ FIRCLSSDKLog ("Crashed threads: %d\n" , crashedThread );
531+ FIRCLSHandler (& file , crashedThread , NULL , true);
524532
525533 FIRCLSFileClose (& file );
526534
527535 return true;
528536}
529537
538+ static void FIRCLSCrashedThreadLookup (MachExceptionProtectedMessage * message , thread_t * crashedThread ) {
539+ thread_act_array_t threadList ;
540+ mach_msg_type_number_t threadCount ;
541+
542+ // last 32 bits include thread id info
543+ MachExceptionProtectedThreadInfo protected_thread_info = * (MachExceptionProtectedThreadInfo * ) & message -> thread_id ;
544+ kern_return_t kr = task_threads (mach_task_self (), & threadList , & threadCount );
545+
546+ if (kr != KERN_SUCCESS ) {
547+ FIRCLSSDKLogError ("Failed to get threads: %d\n" , kr );
548+ return ;
549+ }
550+ for (int i = 0 ; i < threadCount ; i ++ ) {
551+ thread_t thread = threadList [i ];
552+
553+ thread_basic_info_data_t basicInfo ;
554+ thread_identifier_info_data_t identifierInfo ;
555+ mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT ;
556+
557+ kr = thread_info (thread , THREAD_IDENTIFIER_INFO , (thread_info_t )& identifierInfo , & infoCount );
558+
559+ if (kr == KERN_SUCCESS ) {
560+ FIRCLSSDKLog ("Thread %d: Thread port: %d, thread id: %llx\n" , i , thread , identifierInfo .thread_id );
561+
562+ if (protected_thread_info .thread_id == identifierInfo .thread_id ) {
563+ FIRCLSSDKLog ("Find crashed thread: %d\n" , thread );
564+ * crashedThread = thread ;
565+ }
566+ }
567+
568+ // Note: You must deallocate the send right for each thread port
569+ // to prevent port leaks, as task_threads increments the ref count.
570+ mach_port_deallocate (mach_task_self (), thread );
571+ }
572+ vm_deallocate (mach_task_self (), (vm_address_t )threadList , threadCount * sizeof (thread_t ));
573+ }
574+
530575#else
531576
532577INJECT_STRIP_SYMBOL (cls_mach_exception )
0 commit comments