1 #include <darwintest.h> 
   3 #include <mach/mach_types.h> 
   5 #include <mach/thread_act.h> 
   6 #include <mach_debug/ipc_info.h> 
   9         T_META_NAMESPACE("xnu.ipc"), 
  10         T_META_RUN_CONCURRENTLY(true)); 
  12 T_DECL(exception_ports_info
, "Test {task, thread}_get_exception_ports_info") 
  15         mach_port_t exc_port1
, exc_port2
, exc_port3
; 
  17         mach_msg_type_number_t count 
= EXC_TYPES_COUNT
; 
  18         exception_mask_t masks
[EXC_TYPES_COUNT
]; 
  19         ipc_info_port_t ports_info
[EXC_TYPES_COUNT
]; 
  20         exception_behavior_t behaviors
[EXC_TYPES_COUNT
]; 
  21         thread_state_flavor_t flavors
[EXC_TYPES_COUNT
]; 
  23         mach_msg_type_number_t count2 
= EXC_TYPES_COUNT
; 
  24         exception_mask_t masks2
[EXC_TYPES_COUNT
]; 
  25         mach_port_t ports
[EXC_TYPES_COUNT
]; 
  26         exception_behavior_t behaviors2
[EXC_TYPES_COUNT
]; 
  27         thread_state_flavor_t flavors2
[EXC_TYPES_COUNT
]; 
  29         unsigned int exc_port1_kotype 
= 0, exc_port1_kaddr 
= 0; 
  30         unsigned int exc_port2_kotype 
= 0, exc_port2_kaddr 
= 0; 
  31         unsigned int kotype 
= 0, kobject 
= 0, exc_port3_kotype 
= 0, exc_port3_kaddr 
= 0; 
  32         boolean_t found_exc_port1 
= false; 
  33         boolean_t found_exc_port2 
= false; 
  34         boolean_t found_exc_port3 
= false; 
  36         ipc_info_space_t info_space
; 
  37         ipc_info_name_array_t table
; 
  38         ipc_info_tree_name_array_t tree
; 
  39         mach_msg_type_number_t tblcnt 
= 0, treecnt 
= 0; 
  41         /* Create the mach port the exception messages will be sent to. */ 
  42         kr 
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exc_port1
); 
  43         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Allocated mach exception port"); 
  44         kr 
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exc_port2
); 
  45         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Allocated mach exception port"); 
  46         kr 
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &exc_port3
); 
  47         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Allocated mach exception port"); 
  50          * Insert a send right into the exception port that the kernel will use to 
  51          * send the exception thread the exception messages. 
  53         kr 
= mach_port_insert_right(mach_task_self(), exc_port1
, exc_port1
, MACH_MSG_TYPE_MAKE_SEND
); 
  54         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Inserted a SEND right into the exception port"); 
  55         kr 
= mach_port_insert_right(mach_task_self(), exc_port2
, exc_port2
, MACH_MSG_TYPE_MAKE_SEND
); 
  56         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Inserted a SEND right into the exception port"); 
  57         kr 
= mach_port_insert_right(mach_task_self(), exc_port3
, exc_port3
, MACH_MSG_TYPE_MAKE_SEND
); 
  58         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Inserted a SEND right into the exception port"); 
  60         T_LOG("exc_port1: 0x%x", exc_port1
); 
  61         T_LOG("exc_port2: 0x%x", exc_port2
); 
  62         T_LOG("exc_port3: 0x%x", exc_port3
); 
  64         /* Tell the kernel what port to send exceptions to. */ 
  65         kr 
= task_set_exception_ports( 
  69                 (exception_behavior_t
)(EXCEPTION_STATE_IDENTITY 
| MACH_EXCEPTION_CODES
), 
  71         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Set the exception port to my custom handler"); 
  73         kr 
= task_set_exception_ports( 
  75                 EXC_MASK_RPC_ALERT
,  /* why can't be EXC_CRASH or EXC_MASK_CORPSE_NOTIFY ? */ 
  77                 (exception_behavior_t
)(EXCEPTION_STATE_IDENTITY 
| MACH_EXCEPTION_CODES
), 
  79         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Set the exception port to my custom handler"); 
  81         kr 
= task_set_exception_ports( 
  83                 EXC_MASK_RESOURCE 
| EXC_MASK_BREAKPOINT 
| EXC_MASK_SYSCALL
, 
  85                 (exception_behavior_t
)(EXCEPTION_STATE_IDENTITY 
| MACH_EXCEPTION_CODES
), 
  87         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "Set the exception port to my custom handler"); 
  89         /* now, get exception ports info */ 
  90         kr 
= thread_get_exception_ports(mach_thread_self(), EXC_MASK_ALL
, masks2
, &count2
, ports
, behaviors2
, flavors2
); 
  91         T_EXPECT_MACH_SUCCESS(kr
, "thread_get_exception_ports(): 0x%x", kr
); 
  92         T_EXPECT_EQ(count2
, 0, "should have 0 exception ports"); 
  94         kr 
= thread_get_exception_ports_info(mach_thread_self(), EXC_MASK_ALL
, masks
, &count
, ports_info
, behaviors
, flavors
); 
  95         T_EXPECT_MACH_SUCCESS(kr
, "thread_get_exception_ports_info(): 0x%x", kr
); 
  96         T_EXPECT_EQ(count
, 0, "should have 0 exception ports"); 
  98         count 
= EXC_TYPES_COUNT
; 
  99         count2 
= EXC_TYPES_COUNT
; 
 101         kr 
= task_get_exception_ports_info(mach_task_self(), EXC_MASK_ALL
, masks
, &count
, ports_info
, behaviors
, flavors
); 
 102         T_EXPECT_MACH_SUCCESS(kr
, "task_get_exception_ports_info(): 0x%x", kr
); 
 103         T_EXPECT_EQ(count
, 4, "should have 4 masks"); /* Returns 3 if one exc_port registers for EXC_CRASH */ 
 105         /* get exception ports */ 
 106         kr 
= task_get_exception_ports(mach_task_self(), EXC_MASK_ALL
, masks2
, &count2
, ports
, behaviors2
, flavors2
); 
 107         T_EXPECT_MACH_SUCCESS(kr
, "task_get_exception_ports(): 0x%x", kr
); 
 109         for (int i 
= 0; i 
< count2
; i
++) { 
 110                 T_LOG("exception port name: 0x%x", ports
[i
]); 
 112         T_EXPECT_EQ(count
, count2
, "should return same mask count"); 
 114         kr 
= memcmp(masks
, masks2
, count 
* sizeof(exception_mask_t
)); 
 115         T_EXPECT_EQ(kr
, 0, "masks should be the same"); 
 117         kr 
= memcmp(behaviors
, behaviors2
, count 
* sizeof(exception_behavior_t
)); 
 118         T_EXPECT_EQ(kr
, 0, "behaviors should be the same"); 
 120         kr 
= memcmp(flavors
, flavors
, count 
* sizeof(thread_state_flavor_t
)); 
 121         T_EXPECT_EQ(kr
, 0, "flavors should be the same"); 
 123         kr 
= mach_port_kernel_object(mach_task_self(), mach_task_self(), &kotype
, &kobject
); 
 124         T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_port_kernel_object(): 0x%x", kr
); 
 125         T_LOG("task_self kobject: 0x%x", kobject
); 
 127         T_QUIET
; T_EXPECT_MACH_SUCCESS(mach_port_space_info(mach_task_self(), &info_space
, &table
, 
 128             &tblcnt
, &tree
, &treecnt
), "mach_port_space_info(): 0x%x", kr
); 
 130         for (int i 
= 0; i 
< tblcnt
; i
++) { 
 131                 if (table
[i
].iin_name 
== exc_port1
) { 
 132                         exc_port1_kaddr 
= table
[i
].iin_object
; 
 134                 if (table
[i
].iin_name 
== exc_port2
) { 
 135                         exc_port2_kaddr 
= table
[i
].iin_object
; 
 137                 if (table
[i
].iin_name 
== exc_port3
) { 
 138                         exc_port3_kaddr 
= table
[i
].iin_object
; 
 142         T_LOG("exc_port_1_kaddr: 0x%x", exc_port1_kaddr
); 
 143         T_LOG("exc_port_2_kaddr: 0x%x", exc_port2_kaddr
); 
 144         T_LOG("exc_port_3_kaddr: 0x%x", exc_port3_kaddr
); 
 146         for (int i 
= 0; i 
< count
; i
++) { 
 147                 T_LOG("ports_info[%d].iip_port_object: 0x%x", i
, ports_info
[i
].iip_port_object
); 
 149                 if (ports_info
[i
].iip_port_object 
== exc_port1_kaddr
) { 
 150                         T_EXPECT_NE(ports_info
[i
].iip_port_object
, 0, 
 151                             "on debug/kernel, port object should be non-zero: 0x%x", ports_info
[i
].iip_port_object
); 
 152                         T_EXPECT_EQ(ports_info
[i
].iip_receiver_object
, kobject
, 
 153                             "receiver object should match task self kobject: 0x%x", ports_info
[i
].iip_receiver_object
); 
 154                         T_EXPECT_EQ(masks
[i
], EXC_MASK_GUARD
, "check if mask for exc_port1 is correct"); 
 155                         found_exc_port1 
= true; 
 157                 if (ports_info
[i
].iip_port_object 
== exc_port2_kaddr
) { 
 158                         T_EXPECT_NE(ports_info
[i
].iip_port_object
, 0, 
 159                             "on debug/kernel, port object should be non-zero: 0x%x", ports_info
[i
].iip_port_object
); 
 160                         T_EXPECT_EQ(ports_info
[i
].iip_receiver_object
, kobject
, 
 161                             "receiver object should match task self kobject: 0x%x", ports_info
[i
].iip_receiver_object
); 
 162                         T_EXPECT_EQ(masks
[i
], EXC_MASK_RPC_ALERT
, "check if mask for exc_port2 is correct"); 
 163                         found_exc_port2 
= true; 
 165                 if (ports_info
[i
].iip_port_object 
== exc_port3_kaddr
) { 
 166                         T_EXPECT_NE(ports_info
[i
].iip_port_object
, 0, 
 167                             "on debug/kernel, port object should be non-zero: 0x%x", ports_info
[i
].iip_port_object
); 
 168                         T_EXPECT_EQ(ports_info
[i
].iip_receiver_object
, kobject
, 
 169                             "receiver object should match task self kobject: 0x%x", ports_info
[i
].iip_receiver_object
); 
 170                         T_EXPECT_EQ(masks
[i
], EXC_MASK_RESOURCE 
| EXC_MASK_BREAKPOINT 
| EXC_MASK_SYSCALL
, "check if mask for exc_port3 is correct"); 
 171                         found_exc_port3 
= true; 
 175         T_EXPECT_TRUE(found_exc_port1
, "should find exc_port1"); 
 176         T_EXPECT_TRUE(found_exc_port2
, "should find exc_port2"); 
 177         T_EXPECT_TRUE(found_exc_port3
, "should find exc_port3");