Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | |
| 2 // | |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 4 // you may not use this file except in compliance with the License. | |
| 5 // You may obtain a copy of the License at | |
| 6 // | |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 8 // | |
| 9 // Unless required by applicable law or agreed to in writing, software | |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 12 // See the License for the specific language governing permissions and | |
| 13 // limitations under the License. | |
| 14 | |
| 15 #include "util/mach/exc_server_variants.h" | |
| 16 | |
| 17 #include <mach/mach.h> | |
| 18 #include <string.h> | |
| 19 | |
| 20 #include "base/basictypes.h" | |
| 21 #include "base/strings/stringprintf.h" | |
| 22 #include "gmock/gmock.h" | |
| 23 #include "gtest/gtest.h" | |
| 24 #include "util/test/mac/mach_errors.h" | |
| 25 #include "util/test/mac/mach_multiprocess.h" | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 using namespace crashpad; | |
| 30 using namespace crashpad::test; | |
| 31 using namespace testing; | |
| 32 | |
| 33 // Fake Mach ports. These aren’t used as ports in these tests, they’re just used | |
| 34 // as cookies to make sure that the correct values get passed to the correct | |
| 35 // places. | |
| 36 const mach_port_t kClientRemotePort = 0x01010101; | |
| 37 const mach_port_t kServerLocalPort = 0x02020202; | |
| 38 const mach_port_t kExceptionThreadPort = 0x03030303; | |
| 39 const mach_port_t kExceptionTaskPort = 0x04040404; | |
| 40 | |
| 41 // Other fake exception values. | |
| 42 const exception_type_t kExceptionType = EXC_BAD_ACCESS; | |
| 43 | |
| 44 // Test using an exception code with the high bit set to ensure that it gets | |
| 45 // promoted to the wider mach_exception_data_type_t type as a signed quantity. | |
| 46 const exception_data_type_t kExceptionCodes[] = { | |
| 47 KERN_PROTECTION_FAILURE, | |
| 48 static_cast<exception_data_type_t>(0xfedcba98), | |
| 49 }; | |
| 50 | |
| 51 const exception_data_type_t kMachExceptionCodes[] = { | |
| 52 KERN_PROTECTION_FAILURE, | |
| 53 static_cast<exception_data_type_t>(0xfedcba9876543210), | |
| 54 }; | |
| 55 | |
| 56 const thread_state_flavor_t kThreadStateFlavor = MACHINE_THREAD_STATE; | |
| 57 const mach_msg_type_number_t kThreadStateFlavorCount = | |
| 58 MACHINE_THREAD_STATE_COUNT; | |
| 59 | |
| 60 void InitializeMachMsgPortDescriptor(mach_msg_port_descriptor_t* descriptor, | |
| 61 mach_port_t port) { | |
| 62 descriptor->name = port; | |
| 63 descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND; | |
| 64 descriptor->type = MACH_MSG_PORT_DESCRIPTOR; | |
| 65 } | |
| 66 | |
| 67 // The definitions of the request and reply structures from mach_exc.h aren’t | |
| 68 // available here. They need custom initialization code, and the reply | |
| 69 // structures need verification code too, so duplicate the expected definitions | |
| 70 // of the structures from both exc.h and mach_exc.h here in this file, and | |
| 71 // provide the initialization and verification code as methods in true | |
| 72 // object-oriented fashion. | |
| 73 | |
| 74 struct __attribute__((packed, aligned(4))) ExceptionRaiseRequest { | |
| 75 mach_msg_header_t Head; | |
| 76 mach_msg_body_t msgh_body; | |
| 77 mach_msg_port_descriptor_t thread; | |
| 78 mach_msg_port_descriptor_t task; | |
| 79 NDR_record_t NDR; | |
| 80 exception_type_t exception; | |
| 81 mach_msg_type_number_t codeCnt; | |
| 82 integer_t code[2]; | |
| 83 | |
| 84 void InitializeForTesting() { | |
| 85 memset(this, 0xa5, sizeof(*this)); | |
| 86 Head.msgh_bits = | |
| 87 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | | |
| 88 MACH_MSGH_BITS_COMPLEX; | |
| 89 Head.msgh_size = sizeof(*this); | |
| 90 Head.msgh_remote_port = kClientRemotePort; | |
| 91 Head.msgh_local_port = kServerLocalPort; | |
| 92 Head.msgh_id = 2401; | |
| 93 msgh_body.msgh_descriptor_count = 2; | |
| 94 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort); | |
| 95 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort); | |
| 96 NDR = NDR_record; | |
| 97 exception = kExceptionType; | |
| 98 codeCnt = 2; | |
| 99 code[0] = kExceptionCodes[0]; | |
| 100 code[1] = kExceptionCodes[1]; | |
| 101 } | |
| 102 }; | |
| 103 | |
| 104 struct __attribute__((packed, aligned(4))) ExceptionRaiseReply { | |
| 105 mach_msg_header_t Head; | |
| 106 NDR_record_t NDR; | |
| 107 kern_return_t RetCode; | |
| 108 | |
| 109 void InitializeForTesting() { | |
| 110 memset(this, 0x5a, sizeof(*this)); | |
| 111 RetCode = KERN_FAILURE; | |
| 112 } | |
| 113 | |
| 114 // Verify accepts a |behavior| parameter because the same message format and | |
| 115 // verification function is used for ExceptionRaiseReply and | |
| 116 // MachExceptionRaiseReply. Knowing which behavior is expected allows the | |
| 117 // message ID to be checked. | |
| 118 void Verify(exception_behavior_t behavior) { | |
| 119 EXPECT_EQ(static_cast<mach_msg_bits_t>( | |
| 120 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)), | |
| 121 Head.msgh_bits); | |
| 122 EXPECT_EQ(sizeof(*this), Head.msgh_size); | |
| 123 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port); | |
| 124 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), Head.msgh_local_port); | |
| 125 switch (behavior) { | |
| 126 case EXCEPTION_DEFAULT: | |
| 127 EXPECT_EQ(2501, Head.msgh_id); | |
| 128 break; | |
| 129 case static_cast<exception_behavior_t>(EXCEPTION_DEFAULT | | |
| 130 MACH_EXCEPTION_CODES): | |
| 131 EXPECT_EQ(2505, Head.msgh_id); | |
| 132 break; | |
| 133 default: | |
| 134 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id " | |
| 135 << Head.msgh_id; | |
| 136 break; | |
| 137 } | |
| 138 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR))); | |
| 139 EXPECT_EQ(KERN_SUCCESS, RetCode); | |
| 140 } | |
| 141 }; | |
| 142 | |
| 143 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest { | |
| 144 mach_msg_header_t Head; | |
| 145 NDR_record_t NDR; | |
| 146 exception_type_t exception; | |
| 147 mach_msg_type_number_t codeCnt; | |
| 148 integer_t code[2]; | |
| 149 int flavor; | |
| 150 mach_msg_type_number_t old_stateCnt; | |
| 151 natural_t old_state[THREAD_STATE_MAX]; | |
| 152 | |
| 153 void InitializeForTesting() { | |
| 154 memset(this, 0xa5, sizeof(*this)); | |
| 155 Head.msgh_bits = | |
| 156 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); | |
| 157 Head.msgh_size = sizeof(*this); | |
| 158 Head.msgh_remote_port = kClientRemotePort; | |
| 159 Head.msgh_local_port = kServerLocalPort; | |
| 160 Head.msgh_id = 2402; | |
| 161 NDR = NDR_record; | |
| 162 exception = kExceptionType; | |
| 163 codeCnt = 2; | |
| 164 code[0] = kExceptionCodes[0]; | |
| 165 code[1] = kExceptionCodes[1]; | |
| 166 flavor = kThreadStateFlavor; | |
| 167 old_stateCnt = kThreadStateFlavorCount; | |
| 168 | |
| 169 // Adjust the message size for the data that it’s actually carrying, which | |
| 170 // may be smaller than the maximum that it can carry. | |
| 171 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); | |
| 172 } | |
| 173 }; | |
| 174 | |
| 175 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateReply { | |
| 176 mach_msg_header_t Head; | |
| 177 NDR_record_t NDR; | |
| 178 kern_return_t RetCode; | |
| 179 int flavor; | |
| 180 mach_msg_type_number_t new_stateCnt; | |
| 181 natural_t new_state[THREAD_STATE_MAX]; | |
| 182 | |
| 183 void InitializeForTesting() { | |
| 184 memset(this, 0x5a, sizeof(*this)); | |
| 185 RetCode = KERN_FAILURE; | |
| 186 } | |
| 187 | |
| 188 // Verify accepts a |behavior| parameter because the same message format and | |
| 189 // verification function is used for ExceptionRaiseStateReply, | |
| 190 // ExceptionRaiseStateIdentityReply, MachExceptionRaiseStateReply, and | |
| 191 // MachExceptionRaiseStateIdentityReply. Knowing which behavior is expected | |
| 192 // allows the message ID to be checked. | |
| 193 void Verify(exception_behavior_t behavior) { | |
| 194 EXPECT_EQ(static_cast<mach_msg_bits_t>( | |
| 195 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)), | |
| 196 Head.msgh_bits); | |
| 197 EXPECT_EQ(sizeof(*this), Head.msgh_size); | |
| 198 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port); | |
| 199 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), Head.msgh_local_port); | |
| 200 switch (behavior) { | |
| 201 case EXCEPTION_STATE: | |
| 202 EXPECT_EQ(2502, Head.msgh_id); | |
| 203 break; | |
| 204 case EXCEPTION_STATE_IDENTITY: | |
| 205 EXPECT_EQ(2503, Head.msgh_id); | |
| 206 break; | |
| 207 case static_cast<exception_behavior_t>(EXCEPTION_STATE | | |
| 208 MACH_EXCEPTION_CODES): | |
| 209 EXPECT_EQ(2506, Head.msgh_id); | |
| 210 break; | |
| 211 case static_cast<exception_behavior_t>(EXCEPTION_STATE_IDENTITY | | |
| 212 MACH_EXCEPTION_CODES): | |
| 213 EXPECT_EQ(2507, Head.msgh_id); | |
| 214 break; | |
| 215 default: | |
| 216 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id " | |
| 217 << Head.msgh_id; | |
| 218 break; | |
| 219 } | |
| 220 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR))); | |
| 221 EXPECT_EQ(KERN_SUCCESS, RetCode); | |
| 222 EXPECT_EQ(kThreadStateFlavor, flavor); | |
| 223 EXPECT_EQ(arraysize(new_state), new_stateCnt); | |
| 224 } | |
| 225 }; | |
| 226 | |
| 227 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest { | |
| 228 mach_msg_header_t Head; | |
| 229 mach_msg_body_t msgh_body; | |
| 230 mach_msg_port_descriptor_t thread; | |
| 231 mach_msg_port_descriptor_t task; | |
| 232 NDR_record_t NDR; | |
| 233 exception_type_t exception; | |
| 234 mach_msg_type_number_t codeCnt; | |
| 235 integer_t code[2]; | |
| 236 int flavor; | |
| 237 mach_msg_type_number_t old_stateCnt; | |
| 238 natural_t old_state[THREAD_STATE_MAX]; | |
| 239 | |
| 240 void InitializeForTesting() { | |
| 241 memset(this, 0xa5, sizeof(*this)); | |
| 242 Head.msgh_bits = | |
| 243 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | | |
| 244 MACH_MSGH_BITS_COMPLEX; | |
| 245 Head.msgh_size = sizeof(*this); | |
| 246 Head.msgh_remote_port = kClientRemotePort; | |
| 247 Head.msgh_local_port = kServerLocalPort; | |
| 248 Head.msgh_id = 2403; | |
| 249 msgh_body.msgh_descriptor_count = 2; | |
| 250 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort); | |
| 251 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort); | |
| 252 NDR = NDR_record; | |
| 253 exception = kExceptionType; | |
| 254 codeCnt = 2; | |
| 255 code[0] = kExceptionCodes[0]; | |
| 256 code[1] = kExceptionCodes[1]; | |
| 257 flavor = kThreadStateFlavor; | |
| 258 old_stateCnt = kThreadStateFlavorCount; | |
| 259 | |
| 260 // Adjust the message size for the data that it’s actually carrying, which | |
| 261 // may be smaller than the maximum that it can carry. | |
| 262 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); | |
| 263 } | |
| 264 }; | |
| 265 | |
| 266 // The reply messages for exception_raise_state and | |
| 267 // exception_raise_state_identity are identical. | |
| 268 typedef ExceptionRaiseStateReply ExceptionRaiseStateIdentityReply; | |
| 269 | |
| 270 struct __attribute__((packed, aligned(4))) MachExceptionRaiseRequest { | |
| 271 mach_msg_header_t Head; | |
| 272 mach_msg_body_t msgh_body; | |
| 273 mach_msg_port_descriptor_t thread; | |
| 274 mach_msg_port_descriptor_t task; | |
| 275 NDR_record_t NDR; | |
| 276 exception_type_t exception; | |
| 277 mach_msg_type_number_t codeCnt; | |
| 278 int64_t code[2]; | |
| 279 | |
| 280 void InitializeForTesting() { | |
| 281 memset(this, 0xa5, sizeof(*this)); | |
| 282 Head.msgh_bits = | |
| 283 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | | |
| 284 MACH_MSGH_BITS_COMPLEX; | |
| 285 Head.msgh_size = sizeof(*this); | |
| 286 Head.msgh_remote_port = kClientRemotePort; | |
| 287 Head.msgh_local_port = kServerLocalPort; | |
| 288 Head.msgh_id = 2405; | |
| 289 msgh_body.msgh_descriptor_count = 2; | |
| 290 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort); | |
| 291 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort); | |
| 292 NDR = NDR_record; | |
| 293 exception = kExceptionType; | |
| 294 codeCnt = 2; | |
| 295 code[0] = kMachExceptionCodes[0]; | |
| 296 code[1] = kMachExceptionCodes[1]; | |
| 297 } | |
| 298 }; | |
| 299 | |
| 300 // The reply messages for exception_raise and mach_exception_raise are | |
| 301 // identical. | |
| 302 typedef ExceptionRaiseReply MachExceptionRaiseReply; | |
| 303 | |
| 304 struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest { | |
| 305 mach_msg_header_t Head; | |
| 306 NDR_record_t NDR; | |
| 307 exception_type_t exception; | |
| 308 mach_msg_type_number_t codeCnt; | |
| 309 int64_t code[2]; | |
| 310 int flavor; | |
| 311 mach_msg_type_number_t old_stateCnt; | |
| 312 natural_t old_state[THREAD_STATE_MAX]; | |
| 313 | |
| 314 void InitializeForTesting() { | |
| 315 memset(this, 0xa5, sizeof(*this)); | |
| 316 Head.msgh_bits = | |
| 317 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); | |
| 318 Head.msgh_size = sizeof(*this); | |
| 319 Head.msgh_remote_port = kClientRemotePort; | |
| 320 Head.msgh_local_port = kServerLocalPort; | |
| 321 Head.msgh_id = 2406; | |
| 322 NDR = NDR_record; | |
| 323 exception = kExceptionType; | |
| 324 codeCnt = 2; | |
| 325 code[0] = kMachExceptionCodes[0]; | |
| 326 code[1] = kMachExceptionCodes[1]; | |
| 327 flavor = kThreadStateFlavor; | |
| 328 old_stateCnt = kThreadStateFlavorCount; | |
| 329 | |
| 330 // Adjust the message size for the data that it’s actually carrying, which | |
| 331 // may be smaller than the maximum that it can carry. | |
| 332 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); | |
| 333 } | |
| 334 }; | |
| 335 | |
| 336 // The reply messages for exception_raise_state and mach_exception_raise_state | |
| 337 // are identical. | |
| 338 typedef ExceptionRaiseStateReply MachExceptionRaiseStateReply; | |
| 339 | |
| 340 struct __attribute__((packed, | |
| 341 aligned(4))) MachExceptionRaiseStateIdentityRequest { | |
| 342 mach_msg_header_t Head; | |
| 343 mach_msg_body_t msgh_body; | |
| 344 mach_msg_port_descriptor_t thread; | |
| 345 mach_msg_port_descriptor_t task; | |
| 346 NDR_record_t NDR; | |
| 347 exception_type_t exception; | |
| 348 mach_msg_type_number_t codeCnt; | |
| 349 int64_t code[2]; | |
| 350 int flavor; | |
| 351 mach_msg_type_number_t old_stateCnt; | |
| 352 natural_t old_state[THREAD_STATE_MAX]; | |
| 353 | |
| 354 void InitializeForTesting() { | |
| 355 memset(this, 0xa5, sizeof(*this)); | |
| 356 Head.msgh_bits = | |
| 357 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | | |
| 358 MACH_MSGH_BITS_COMPLEX; | |
| 359 Head.msgh_size = sizeof(*this); | |
| 360 Head.msgh_remote_port = kClientRemotePort; | |
| 361 Head.msgh_local_port = kServerLocalPort; | |
| 362 Head.msgh_id = 2407; | |
| 363 msgh_body.msgh_descriptor_count = 2; | |
| 364 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort); | |
| 365 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort); | |
| 366 NDR = NDR_record; | |
| 367 exception = kExceptionType; | |
| 368 codeCnt = 2; | |
| 369 code[0] = kMachExceptionCodes[0]; | |
| 370 code[1] = kMachExceptionCodes[1]; | |
| 371 flavor = kThreadStateFlavor; | |
| 372 old_stateCnt = kThreadStateFlavorCount; | |
| 373 | |
| 374 // Adjust the message size for the data that it’s actually carrying, which | |
| 375 // may be smaller than the maximum that it can carry. | |
| 376 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state); | |
| 377 } | |
| 378 }; | |
| 379 | |
| 380 // The reply messages for exception_raise_state_identity and | |
| 381 // mach_exception_raise_state_identity are identical. | |
| 382 typedef ExceptionRaiseStateIdentityReply MachExceptionRaiseStateIdentityReply; | |
| 383 | |
| 384 // InvalidRequest and BadIDErrorReply are used to test that | |
| 385 // UniversalMachExcServer deals appropriately with messages that it does not | |
| 386 // understand: messages with an unknown Head.msgh_id. | |
| 387 | |
| 388 struct __attribute__((packed, aligned(4))) InvalidRequest | |
| 389 : public mach_msg_empty_send_t { | |
| 390 void InitializeForTesting(mach_msg_id_t id) { | |
| 391 memset(this, 0xa5, sizeof(*this)); | |
| 392 header.msgh_bits = | |
| 393 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE); | |
| 394 header.msgh_size = sizeof(*this); | |
| 395 header.msgh_remote_port = kClientRemotePort; | |
| 396 header.msgh_local_port = kServerLocalPort; | |
| 397 header.msgh_id = id; | |
| 398 } | |
| 399 }; | |
| 400 | |
| 401 struct __attribute__((packed, aligned(4))) BadIDErrorReply | |
| 402 : public mig_reply_error_t { | |
| 403 void InitializeForTesting() { | |
| 404 memset(this, 0x5a, sizeof(*this)); | |
| 405 RetCode = KERN_FAILURE; | |
| 406 } | |
| 407 | |
| 408 void Verify(mach_msg_id_t id) { | |
| 409 EXPECT_EQ(static_cast<mach_msg_bits_t>( | |
| 410 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)), | |
| 411 Head.msgh_bits); | |
| 412 EXPECT_EQ(sizeof(*this), Head.msgh_size); | |
| 413 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port); | |
| 414 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), Head.msgh_local_port); | |
| 415 EXPECT_EQ(id + 100, Head.msgh_id); | |
| 416 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR))); | |
| 417 EXPECT_EQ(MIG_BAD_ID, RetCode); | |
| 418 } | |
| 419 }; | |
| 420 | |
| 421 class MockUniversalMachExcServer : public UniversalMachExcServer { | |
| 422 public: | |
| 423 struct ConstExceptionCodes { | |
| 424 const mach_exception_data_type_t* code; | |
| 425 mach_msg_type_number_t code_count; | |
| 426 }; | |
| 427 struct ThreadState { | |
| 428 thread_state_t state; | |
| 429 mach_msg_type_number_t* state_count; | |
| 430 }; | |
| 431 struct ConstThreadState { | |
| 432 const natural_t* state; | |
| 433 mach_msg_type_number_t* state_count; | |
| 434 }; | |
| 435 | |
| 436 // CatchMachException is the method to mock, but it has 13 parameters, and | |
| 437 // gmock can only mock methods with up to 10 parameters. Coalesce some related | |
| 438 // parameters together into structs, and call a mocked method. | |
| 439 virtual kern_return_t CatchMachException( | |
| 440 exception_behavior_t behavior, | |
| 441 exception_handler_t exception_port, | |
| 442 thread_t thread, | |
| 443 task_t task, | |
| 444 exception_type_t exception, | |
| 445 const mach_exception_data_type_t* code, | |
| 446 mach_msg_type_number_t code_count, | |
| 447 thread_state_flavor_t* flavor, | |
| 448 const natural_t* old_state, | |
| 449 mach_msg_type_number_t old_state_count, | |
| 450 thread_state_t new_state, | |
| 451 mach_msg_type_number_t* new_state_count, | |
| 452 bool* destroy_complex_request) override { | |
| 453 *destroy_complex_request = true; | |
| 454 const ConstExceptionCodes exception_codes = {code, code_count}; | |
| 455 const ConstThreadState old_thread_state = {old_state, &old_state_count}; | |
| 456 ThreadState new_thread_state = {new_state, new_state_count}; | |
| 457 return MockCatchMachException(behavior, | |
| 458 exception_port, | |
| 459 thread, | |
| 460 task, | |
| 461 exception, | |
| 462 &exception_codes, | |
| 463 flavor, | |
| 464 &old_thread_state, | |
| 465 &new_thread_state); | |
| 466 } | |
| 467 | |
| 468 MOCK_METHOD9(MockCatchMachException, | |
| 469 kern_return_t(exception_behavior_t behavior, | |
| 470 exception_handler_t exception_port, | |
| 471 thread_t thread, | |
| 472 task_t task, | |
| 473 exception_type_t exception, | |
| 474 const ConstExceptionCodes* exception_codes, | |
| 475 thread_state_flavor_t* flavor, | |
| 476 const ConstThreadState* old_thread_state, | |
| 477 ThreadState* new_thread_state)); | |
| 478 }; | |
| 479 | |
| 480 // Matcher for ConstExceptionCodes, testing that it carries 2 codes matching | |
| 481 // code_0 and code_1. | |
| 482 MATCHER_P2(AreExceptionCodes, code_0, code_1, "") { | |
| 483 if (!arg) { | |
| 484 return false; | |
| 485 } | |
| 486 | |
| 487 if (arg->code_count == 2 && arg->code[0] == code_0 && | |
| 488 arg->code[1] == code_1) { | |
| 489 return true; | |
| 490 } | |
| 491 | |
| 492 *result_listener << "codes ("; | |
| 493 for (size_t index = 0; index < arg->code_count; ++index) { | |
| 494 *result_listener << arg->code[index]; | |
| 495 if (index < arg->code_count - 1) { | |
| 496 *result_listener << ", "; | |
| 497 } | |
| 498 } | |
| 499 *result_listener << ")"; | |
| 500 | |
| 501 return false; | |
| 502 } | |
| 503 | |
| 504 // Matcher for ThreadState and ConstThreadState, testing that *state_count is | |
| 505 // present and matches the specified value. If 0 is specified for the count, | |
| 506 // state must be NULL (not present), otherwise state must be non-NULL (present). | |
| 507 MATCHER_P(IsThreadStateCount, state_count, "") { | |
| 508 if (!arg) { | |
| 509 return false; | |
| 510 } | |
| 511 if (!arg->state_count) { | |
| 512 *result_listener << "state_count NULL"; | |
| 513 return false; | |
| 514 } | |
| 515 if (*(arg->state_count) != state_count) { | |
| 516 *result_listener << "*state_count " << *(arg->state_count); | |
| 517 return false; | |
| 518 } | |
| 519 if (state_count) { | |
| 520 if (!arg->state) { | |
| 521 *result_listener << "*state_count " << state_count << ", state NULL"; | |
| 522 return false; | |
| 523 } | |
| 524 } else { | |
| 525 if (arg->state) { | |
| 526 *result_listener << "*state_count 0, state non-NULL (" << arg->state | |
| 527 << ")"; | |
| 528 return false; | |
| 529 } | |
| 530 } | |
| 531 return true; | |
| 532 } | |
| 533 | |
| 534 template <typename T> | |
| 535 class ScopedDefaultValue { | |
| 536 public: | |
| 537 explicit ScopedDefaultValue(const T& default_value) { | |
| 538 DefaultValue<T>::Set(default_value); | |
|
Robert Sesek
2014/09/10 16:44:41
Where's DefaultValue defined?
Mark Mentovai
2014/09/10 20:12:56
rsesek wrote:
| |
| 539 } | |
| 540 | |
| 541 ~ScopedDefaultValue() { DefaultValue<T>::Clear(); } | |
| 542 }; | |
| 543 | |
| 544 TEST(ExcServerVariants, MockExceptionRaise) { | |
| 545 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
|
Robert Sesek
2014/09/10 16:44:41
… I don't understand how this is used.
| |
| 546 | |
| 547 MockUniversalMachExcServer server; | |
| 548 | |
| 549 ExceptionRaiseRequest request; | |
| 550 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 551 request.InitializeForTesting(); | |
| 552 | |
| 553 ExceptionRaiseReply reply; | |
| 554 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 555 reply.InitializeForTesting(); | |
| 556 | |
| 557 const exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT; | |
| 558 | |
| 559 EXPECT_CALL(server, | |
| 560 MockCatchMachException( | |
| 561 kExceptionBehavior, | |
| 562 kServerLocalPort, | |
| 563 kExceptionThreadPort, | |
| 564 kExceptionTaskPort, | |
| 565 kExceptionType, | |
| 566 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]), | |
| 567 Pointee(Eq(THREAD_STATE_NONE)), | |
| 568 IsThreadStateCount(0u), | |
| 569 IsThreadStateCount(0u))) | |
| 570 .WillOnce(Return(KERN_SUCCESS)) | |
| 571 .RetiresOnSaturation(); | |
| 572 | |
| 573 bool destroy_complex_request = false; | |
| 574 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 575 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 576 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 577 &destroy_complex_request)); | |
| 578 EXPECT_TRUE(destroy_complex_request); | |
| 579 | |
| 580 reply.Verify(kExceptionBehavior); | |
| 581 } | |
| 582 | |
| 583 TEST(ExcServerVariants, MockExceptionRaiseState) { | |
| 584 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 585 | |
| 586 MockUniversalMachExcServer server; | |
| 587 | |
| 588 ExceptionRaiseStateRequest request; | |
| 589 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 590 request.InitializeForTesting(); | |
| 591 | |
| 592 ExceptionRaiseStateReply reply; | |
| 593 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 594 reply.InitializeForTesting(); | |
| 595 | |
| 596 const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE; | |
| 597 | |
| 598 EXPECT_CALL(server, | |
| 599 MockCatchMachException( | |
| 600 kExceptionBehavior, | |
| 601 kServerLocalPort, | |
| 602 MACH_PORT_NULL, | |
| 603 MACH_PORT_NULL, | |
| 604 kExceptionType, | |
| 605 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]), | |
| 606 Pointee(Eq(kThreadStateFlavor)), | |
| 607 IsThreadStateCount(kThreadStateFlavorCount), | |
| 608 IsThreadStateCount(arraysize(reply.new_state)))) | |
| 609 .WillOnce(Return(KERN_SUCCESS)) | |
| 610 .RetiresOnSaturation(); | |
| 611 | |
| 612 bool destroy_complex_request = false; | |
| 613 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 614 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 615 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 616 &destroy_complex_request)); | |
| 617 | |
| 618 // The request wasn’t complex, so nothing got a chance to change the value of | |
| 619 // this variable. | |
| 620 EXPECT_FALSE(destroy_complex_request); | |
| 621 | |
| 622 reply.Verify(kExceptionBehavior); | |
| 623 } | |
| 624 | |
| 625 TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) { | |
| 626 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 627 | |
| 628 MockUniversalMachExcServer server; | |
| 629 | |
| 630 ExceptionRaiseStateIdentityRequest request; | |
| 631 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 632 request.InitializeForTesting(); | |
| 633 | |
| 634 ExceptionRaiseStateIdentityReply reply; | |
| 635 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 636 reply.InitializeForTesting(); | |
| 637 | |
| 638 const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY; | |
| 639 | |
| 640 EXPECT_CALL(server, | |
| 641 MockCatchMachException( | |
| 642 kExceptionBehavior, | |
| 643 kServerLocalPort, | |
| 644 kExceptionThreadPort, | |
| 645 kExceptionTaskPort, | |
| 646 kExceptionType, | |
| 647 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]), | |
| 648 Pointee(Eq(kThreadStateFlavor)), | |
| 649 IsThreadStateCount(kThreadStateFlavorCount), | |
| 650 IsThreadStateCount(arraysize(reply.new_state)))) | |
| 651 .WillOnce(Return(KERN_SUCCESS)) | |
| 652 .RetiresOnSaturation(); | |
| 653 | |
| 654 bool destroy_complex_request = false; | |
| 655 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 656 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 657 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 658 &destroy_complex_request)); | |
| 659 EXPECT_TRUE(destroy_complex_request); | |
| 660 | |
| 661 reply.Verify(kExceptionBehavior); | |
| 662 } | |
| 663 | |
| 664 TEST(ExcServerVariants, MockMachExceptionRaise) { | |
| 665 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 666 | |
| 667 MockUniversalMachExcServer server; | |
| 668 | |
| 669 MachExceptionRaiseRequest request; | |
| 670 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 671 request.InitializeForTesting(); | |
| 672 | |
| 673 MachExceptionRaiseReply reply; | |
| 674 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 675 reply.InitializeForTesting(); | |
| 676 | |
| 677 const exception_behavior_t kExceptionBehavior = | |
| 678 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES; | |
| 679 | |
| 680 EXPECT_CALL( | |
| 681 server, | |
| 682 MockCatchMachException( | |
| 683 kExceptionBehavior, | |
| 684 kServerLocalPort, | |
| 685 kExceptionThreadPort, | |
| 686 kExceptionTaskPort, | |
| 687 kExceptionType, | |
| 688 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]), | |
| 689 Pointee(Eq(THREAD_STATE_NONE)), | |
| 690 IsThreadStateCount(0u), | |
| 691 IsThreadStateCount(0u))) | |
| 692 .WillOnce(Return(KERN_SUCCESS)) | |
| 693 .RetiresOnSaturation(); | |
| 694 | |
| 695 bool destroy_complex_request = false; | |
| 696 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 697 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 698 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 699 &destroy_complex_request)); | |
| 700 EXPECT_TRUE(destroy_complex_request); | |
| 701 | |
| 702 reply.Verify(kExceptionBehavior); | |
| 703 } | |
| 704 | |
| 705 TEST(ExcServerVariants, MockMachExceptionRaiseState) { | |
| 706 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 707 | |
| 708 MockUniversalMachExcServer server; | |
| 709 | |
| 710 MachExceptionRaiseStateRequest request; | |
| 711 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 712 request.InitializeForTesting(); | |
| 713 | |
| 714 MachExceptionRaiseStateReply reply; | |
| 715 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 716 reply.InitializeForTesting(); | |
| 717 | |
| 718 const exception_behavior_t kExceptionBehavior = | |
| 719 EXCEPTION_STATE | MACH_EXCEPTION_CODES; | |
| 720 | |
| 721 EXPECT_CALL( | |
| 722 server, | |
| 723 MockCatchMachException( | |
| 724 kExceptionBehavior, | |
| 725 kServerLocalPort, | |
| 726 MACH_PORT_NULL, | |
| 727 MACH_PORT_NULL, | |
| 728 kExceptionType, | |
| 729 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]), | |
| 730 Pointee(Eq(kThreadStateFlavor)), | |
| 731 IsThreadStateCount(kThreadStateFlavorCount), | |
| 732 IsThreadStateCount(arraysize(reply.new_state)))) | |
| 733 .WillOnce(Return(KERN_SUCCESS)) | |
| 734 .RetiresOnSaturation(); | |
| 735 | |
| 736 bool destroy_complex_request = false; | |
| 737 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 738 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 739 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 740 &destroy_complex_request)); | |
| 741 | |
| 742 // The request wasn’t complex, so nothing got a chance to change the value of | |
| 743 // this variable. | |
| 744 EXPECT_FALSE(destroy_complex_request); | |
| 745 | |
| 746 reply.Verify(kExceptionBehavior); | |
| 747 } | |
| 748 | |
| 749 TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) { | |
| 750 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 751 | |
| 752 MockUniversalMachExcServer server; | |
| 753 | |
| 754 MachExceptionRaiseStateIdentityRequest request; | |
| 755 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 756 request.InitializeForTesting(); | |
| 757 | |
| 758 MachExceptionRaiseStateIdentityReply reply; | |
| 759 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 760 reply.InitializeForTesting(); | |
| 761 | |
| 762 const exception_behavior_t kExceptionBehavior = | |
| 763 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES; | |
| 764 | |
| 765 EXPECT_CALL( | |
| 766 server, | |
| 767 MockCatchMachException( | |
| 768 kExceptionBehavior, | |
| 769 kServerLocalPort, | |
| 770 kExceptionThreadPort, | |
| 771 kExceptionTaskPort, | |
| 772 kExceptionType, | |
| 773 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]), | |
| 774 Pointee(Eq(kThreadStateFlavor)), | |
| 775 IsThreadStateCount(kThreadStateFlavorCount), | |
| 776 IsThreadStateCount(arraysize(reply.new_state)))) | |
| 777 .WillOnce(Return(KERN_SUCCESS)) | |
| 778 .RetiresOnSaturation(); | |
| 779 | |
| 780 bool destroy_complex_request = false; | |
| 781 EXPECT_TRUE(server.MachMessageServerFunction( | |
| 782 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 783 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 784 &destroy_complex_request)); | |
| 785 EXPECT_TRUE(destroy_complex_request); | |
| 786 | |
| 787 reply.Verify(kExceptionBehavior); | |
| 788 } | |
| 789 | |
| 790 TEST(ExcServerVariants, MockUnknownID) { | |
| 791 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE); | |
| 792 | |
| 793 MockUniversalMachExcServer server; | |
| 794 | |
| 795 // Make sure that a message with an unknown ID is handled appropriately. | |
| 796 // UniversalMachExcServer should not dispatch the message to | |
| 797 // MachMessageServerFunction, but should generate a MIG_BAD_ID error reply. | |
| 798 | |
| 799 const mach_msg_id_t unknown_ids[] = { | |
| 800 // Reasonable things to check. | |
| 801 -101, | |
| 802 -100, | |
| 803 -99, | |
| 804 -1, | |
| 805 0, | |
| 806 1, | |
| 807 99, | |
| 808 100, | |
| 809 101, | |
| 810 | |
| 811 // Invalid IDs right around valid ones. | |
| 812 2400, | |
| 813 2404, | |
| 814 2408, | |
| 815 | |
| 816 // Valid and invalid IDs in the range used for replies, not requests. | |
| 817 2500, | |
| 818 2501, | |
| 819 2502, | |
| 820 2503, | |
| 821 2504, | |
| 822 2505, | |
| 823 2506, | |
| 824 2507, | |
| 825 2508, | |
| 826 }; | |
| 827 | |
| 828 for (size_t index = 0; index < arraysize(unknown_ids); ++index) { | |
| 829 mach_msg_id_t id = unknown_ids[index]; | |
| 830 | |
| 831 SCOPED_TRACE(base::StringPrintf("unknown id %d", id)); | |
| 832 | |
| 833 InvalidRequest request; | |
| 834 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize()); | |
| 835 request.InitializeForTesting(id); | |
| 836 | |
| 837 BadIDErrorReply reply; | |
| 838 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize()); | |
| 839 reply.InitializeForTesting(); | |
| 840 | |
| 841 bool destroy_complex_request = false; | |
| 842 EXPECT_FALSE(server.MachMessageServerFunction( | |
| 843 reinterpret_cast<mach_msg_header_t*>(&request), | |
| 844 reinterpret_cast<mach_msg_header_t*>(&reply), | |
| 845 &destroy_complex_request)); | |
| 846 | |
| 847 // The request wasn’t handled, nothing got a chance to change the value of | |
| 848 // this variable. MachMessageServer would destroy the request if it was | |
| 849 // complex, regardless of what was done to this variable, because the | |
| 850 // return code was not KERN_SUCCESS or MIG_NO_REPLY. | |
| 851 EXPECT_FALSE(destroy_complex_request); | |
| 852 | |
| 853 reply.Verify(id); | |
| 854 } | |
| 855 } | |
| 856 | |
| 857 class TestExcServerVariants : public UniversalMachExcServer, | |
| 858 public MachMultiprocess { | |
| 859 public: | |
| 860 TestExcServerVariants(exception_behavior_t behavior, | |
| 861 thread_state_flavor_t flavor, | |
| 862 mach_msg_type_number_t state_count) | |
| 863 : UniversalMachExcServer(), | |
| 864 MachMultiprocess(), | |
| 865 behavior_(behavior), | |
| 866 flavor_(flavor), | |
| 867 state_count_(state_count), | |
| 868 handled_(false) { | |
| 869 } | |
| 870 | |
| 871 // UniversalMachExcServer: | |
| 872 | |
| 873 virtual kern_return_t CatchMachException( | |
| 874 exception_behavior_t behavior, | |
| 875 exception_handler_t exception_port, | |
| 876 thread_t thread, | |
| 877 task_t task, | |
| 878 exception_type_t exception, | |
| 879 const mach_exception_data_type_t* code, | |
| 880 mach_msg_type_number_t code_count, | |
| 881 thread_state_flavor_t* flavor, | |
| 882 const natural_t* old_state, | |
| 883 mach_msg_type_number_t old_state_count, | |
| 884 thread_state_t new_state, | |
| 885 mach_msg_type_number_t* new_state_count, | |
| 886 bool* destroy_complex_request) override { | |
| 887 *destroy_complex_request = true; | |
| 888 | |
| 889 EXPECT_FALSE(handled_); | |
| 890 handled_ = true; | |
| 891 | |
| 892 EXPECT_EQ(behavior_, behavior); | |
| 893 exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES; | |
| 894 const bool has_identity = basic_behavior == EXCEPTION_DEFAULT || | |
| 895 basic_behavior == EXCEPTION_STATE_IDENTITY; | |
| 896 const bool has_state = basic_behavior == EXCEPTION_STATE || | |
| 897 basic_behavior == EXCEPTION_STATE_IDENTITY; | |
| 898 | |
| 899 EXPECT_EQ(LocalPort(), exception_port); | |
| 900 | |
| 901 if (has_identity) { | |
| 902 EXPECT_NE(static_cast<mach_port_t>(MACH_PORT_NULL), thread); | |
|
Robert Sesek
2014/09/10 16:44:41
You write this cast enough that it could be a hand
Mark Mentovai
2014/09/10 20:12:56
rsesek wrote:
| |
| 903 EXPECT_EQ(ChildTask(), task); | |
| 904 } else { | |
| 905 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), thread); | |
| 906 EXPECT_EQ(static_cast<mach_port_t>(MACH_PORT_NULL), task); | |
| 907 } | |
| 908 | |
| 909 EXPECT_EQ(EXC_CRASH, exception); | |
| 910 EXPECT_EQ(2u, code_count); | |
| 911 | |
| 912 if (code_count > 1) { | |
| 913 // The signal that terminated the process is stored in code[0] along with | |
| 914 // some other data. See 10.9.4 xnu-2422.110.17/bsd/kern/kern_exit.c | |
| 915 // proc_prepareexit(). | |
| 916 int sig = (code[0] >> 24) & 0xff; | |
| 917 SetExpectedChildTermination(kTerminationSignal, sig); | |
| 918 } | |
| 919 | |
| 920 if (has_state) { | |
| 921 EXPECT_EQ(flavor_, *flavor); | |
| 922 EXPECT_EQ(state_count_, old_state_count); | |
| 923 EXPECT_NE(static_cast<const natural_t*>(NULL), old_state); | |
| 924 EXPECT_EQ(static_cast<mach_msg_type_number_t>(THREAD_STATE_MAX), | |
| 925 *new_state_count); | |
| 926 EXPECT_NE(static_cast<const natural_t*>(NULL), new_state); | |
| 927 } else { | |
| 928 EXPECT_EQ(THREAD_STATE_NONE, *flavor); | |
| 929 EXPECT_EQ(0u, old_state_count); | |
| 930 EXPECT_EQ(NULL, old_state); | |
| 931 EXPECT_EQ(0u, *new_state_count); | |
| 932 EXPECT_EQ(NULL, new_state); | |
| 933 } | |
| 934 | |
| 935 // Even for an EXC_CRASH handler, returning KERN_SUCCESS with a | |
| 936 // state-carrying reply will cause the kernel to try to set a new thread | |
| 937 // state, leading to a perceptible waste of time. Returning | |
| 938 // MACH_RCV_PORT_DIED is the only way to suppress this behavior while also | |
| 939 // preventing the kernel from looking for another (host-level) EXC_CRASH | |
| 940 // handler. See 10.9.4 xnu-2422.110.17/osfmk/kern/exception.c | |
| 941 // exception_triage(). | |
| 942 return has_state ? MACH_RCV_PORT_DIED : KERN_SUCCESS; | |
| 943 } | |
| 944 | |
| 945 | |
|
Robert Sesek
2014/09/10 16:44:41
nit: double blank line
| |
| 946 private: | |
| 947 // MachMultiprocess: | |
| 948 | |
| 949 virtual void MachMultiprocessParent() override { | |
| 950 kern_return_t kr = MachMessageServer::Run(this, | |
| 951 LocalPort(), | |
| 952 MACH_MSG_OPTION_NONE, | |
| 953 MachMessageServer::kOneShot, | |
| 954 MachMessageServer::kBlocking, | |
| 955 0); | |
| 956 EXPECT_EQ(KERN_SUCCESS, kr) | |
| 957 << MachErrorMessage(kr, "MachMessageServer::Run"); | |
| 958 | |
| 959 EXPECT_TRUE(handled_); | |
| 960 } | |
| 961 | |
| 962 virtual void MachMultiprocessChild() override { | |
| 963 // Set the parent as the exception handler for EXC_CRASH. | |
| 964 kern_return_t kr = task_set_exception_ports( | |
| 965 mach_task_self(), EXC_MASK_CRASH, RemotePort(), behavior_, flavor_); | |
| 966 ASSERT_EQ(KERN_SUCCESS, kr) | |
| 967 << MachErrorMessage(kr, "task_set_exception_ports"); | |
| 968 | |
| 969 // Now crash. | |
| 970 __builtin_trap(); | |
| 971 } | |
| 972 | |
| 973 exception_behavior_t behavior_; | |
| 974 thread_state_flavor_t flavor_; | |
| 975 mach_msg_type_number_t state_count_; | |
| 976 bool handled_; | |
| 977 | |
| 978 DISALLOW_COPY_AND_ASSIGN(TestExcServerVariants); | |
| 979 }; | |
| 980 | |
| 981 TEST(ExcServerVariants, ExceptionRaise) { | |
| 982 TestExcServerVariants test_exc_server_variants( | |
| 983 EXCEPTION_DEFAULT, THREAD_STATE_NONE, 0); | |
| 984 test_exc_server_variants.Run(); | |
| 985 } | |
| 986 | |
| 987 TEST(ExcServerVariants, ExceptionRaiseState) { | |
| 988 TestExcServerVariants test_exc_server_variants( | |
| 989 EXCEPTION_STATE, MACHINE_THREAD_STATE, MACHINE_THREAD_STATE_COUNT); | |
| 990 test_exc_server_variants.Run(); | |
| 991 } | |
| 992 | |
| 993 TEST(ExcServerVariants, ExceptionRaiseStateIdentity) { | |
| 994 TestExcServerVariants test_exc_server_variants(EXCEPTION_STATE_IDENTITY, | |
| 995 MACHINE_THREAD_STATE, | |
| 996 MACHINE_THREAD_STATE_COUNT); | |
| 997 test_exc_server_variants.Run(); | |
| 998 } | |
| 999 | |
| 1000 TEST(ExcServerVariants, MachExceptionRaise) { | |
| 1001 TestExcServerVariants test_exc_server_variants( | |
| 1002 MACH_EXCEPTION_CODES | EXCEPTION_DEFAULT, THREAD_STATE_NONE, 0); | |
| 1003 test_exc_server_variants.Run(); | |
| 1004 } | |
| 1005 | |
| 1006 TEST(ExcServerVariants, MachExceptionRaiseState) { | |
| 1007 TestExcServerVariants test_exc_server_variants( | |
| 1008 MACH_EXCEPTION_CODES | EXCEPTION_STATE, | |
| 1009 MACHINE_THREAD_STATE, | |
| 1010 MACHINE_THREAD_STATE_COUNT); | |
| 1011 test_exc_server_variants.Run(); | |
| 1012 } | |
| 1013 | |
| 1014 TEST(ExcServerVariants, MachExceptionRaiseStateIdentity) { | |
| 1015 TestExcServerVariants test_exc_server_variants( | |
| 1016 MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY, | |
| 1017 MACHINE_THREAD_STATE, | |
| 1018 MACHINE_THREAD_STATE_COUNT); | |
| 1019 test_exc_server_variants.Run(); | |
| 1020 } | |
| 1021 | |
| 1022 TEST(ExcServerVariants, ThreadStates) { | |
| 1023 // So far, all of the tests worked with MACHINE_THREAD_STATE. Now try all of | |
| 1024 // the other thread state flavors that are expected to work. | |
| 1025 | |
| 1026 struct TestData { | |
| 1027 thread_state_flavor_t flavor; | |
| 1028 mach_msg_type_number_t count; | |
| 1029 }; | |
| 1030 const TestData test_data[] = { | |
| 1031 #if defined(ARCH_CPU_X86_FAMILY) | |
| 1032 #if defined(ARCH_CPU_X86) | |
| 1033 { x86_THREAD_STATE32, x86_THREAD_STATE32_COUNT }, | |
| 1034 { x86_FLOAT_STATE32, x86_FLOAT_STATE32_COUNT }, | |
| 1035 { x86_EXCEPTION_STATE32, x86_EXCEPTION_STATE32_COUNT }, | |
| 1036 { x86_DEBUG_STATE32, x86_DEBUG_STATE32_COUNT }, | |
| 1037 // Don’t test x86_AVX_STATE32 because it’s not available on all CPUs and | |
| 1038 // OS versionns. | |
| 1039 #endif | |
| 1040 #if defined(ARCH_CPU_X86_64) | |
| 1041 { x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT }, | |
| 1042 { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT }, | |
| 1043 { x86_EXCEPTION_STATE64, x86_EXCEPTION_STATE64_COUNT }, | |
| 1044 { x86_DEBUG_STATE64, x86_DEBUG_STATE64_COUNT }, | |
| 1045 // Don’t test x86_AVX_STATE64 because it’s not available on all CPUs and | |
| 1046 // OS versions. | |
| 1047 #endif | |
| 1048 { x86_THREAD_STATE, x86_THREAD_STATE_COUNT }, | |
| 1049 { x86_FLOAT_STATE, x86_FLOAT_STATE_COUNT }, | |
| 1050 { x86_EXCEPTION_STATE, x86_EXCEPTION_STATE_COUNT }, | |
| 1051 { x86_DEBUG_STATE, x86_DEBUG_STATE_COUNT }, | |
| 1052 // Don’t test x86_AVX_STATE because it’s not available on all CPUs and OS | |
| 1053 // versions. | |
| 1054 #else | |
| 1055 #error Port this test to your CPU architecture. | |
| 1056 #endif | |
| 1057 }; | |
| 1058 | |
| 1059 for (size_t index = 0; index < arraysize(test_data); ++index) { | |
| 1060 const TestData& test = test_data[index]; | |
| 1061 SCOPED_TRACE(base::StringPrintf( | |
| 1062 "index %zu, flavor %d", index, test.flavor)); | |
| 1063 | |
| 1064 TestExcServerVariants test_exc_server_variants( | |
| 1065 MACH_EXCEPTION_CODES | EXCEPTION_STATE_IDENTITY, | |
| 1066 test.flavor, | |
| 1067 test.count); | |
| 1068 test_exc_server_variants.Run(); | |
| 1069 } | |
| 1070 } | |
| 1071 | |
| 1072 } // namespace | |
| OLD | NEW |