Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: util/mach/exc_server_variants_test.cc

Issue 545053003: Add exc_server_variants including UniversalMachExcServer and its test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/mach/mach_extensions.h"
25 #include "util/test/mac/mach_errors.h"
26 #include "util/test/mac/mach_multiprocess.h"
27
28 namespace {
29
30 using namespace crashpad;
31 using namespace crashpad::test;
32 using namespace testing;
33
34 // Fake Mach ports. These aren’t used as ports in these tests, they’re just used
35 // as cookies to make sure that the correct values get passed to the correct
36 // places.
37 const mach_port_t kClientRemotePort = 0x01010101;
38 const mach_port_t kServerLocalPort = 0x02020202;
39 const mach_port_t kExceptionThreadPort = 0x03030303;
40 const mach_port_t kExceptionTaskPort = 0x04040404;
41
42 // Other fake exception values.
43 const exception_type_t kExceptionType = EXC_BAD_ACCESS;
44
45 // Test using an exception code with the high bit set to ensure that it gets
46 // promoted to the wider mach_exception_data_type_t type as a signed quantity.
47 const exception_data_type_t kExceptionCodes[] = {
48 KERN_PROTECTION_FAILURE,
49 static_cast<exception_data_type_t>(0xfedcba98),
50 };
51
52 const exception_data_type_t kMachExceptionCodes[] = {
53 KERN_PROTECTION_FAILURE,
54 static_cast<exception_data_type_t>(0xfedcba9876543210),
55 };
56
57 const thread_state_flavor_t kThreadStateFlavor = MACHINE_THREAD_STATE;
58 const mach_msg_type_number_t kThreadStateFlavorCount =
59 MACHINE_THREAD_STATE_COUNT;
60
61 void InitializeMachMsgPortDescriptor(mach_msg_port_descriptor_t* descriptor,
62 mach_port_t port) {
63 descriptor->name = port;
64 descriptor->disposition = MACH_MSG_TYPE_MOVE_SEND;
65 descriptor->type = MACH_MSG_PORT_DESCRIPTOR;
66 }
67
68 // The definitions of the request and reply structures from mach_exc.h aren’t
69 // available here. They need custom initialization code, and the reply
70 // structures need verification code too, so duplicate the expected definitions
71 // of the structures from both exc.h and mach_exc.h here in this file, and
72 // provide the initialization and verification code as methods in true
73 // object-oriented fashion.
74
75 struct __attribute__((packed, aligned(4))) ExceptionRaiseRequest {
76 mach_msg_header_t Head;
77 mach_msg_body_t msgh_body;
78 mach_msg_port_descriptor_t thread;
79 mach_msg_port_descriptor_t task;
80 NDR_record_t NDR;
81 exception_type_t exception;
82 mach_msg_type_number_t codeCnt;
83 integer_t code[2];
84
85 void InitializeForTesting() {
86 memset(this, 0xa5, sizeof(*this));
87 Head.msgh_bits =
88 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) |
89 MACH_MSGH_BITS_COMPLEX;
90 Head.msgh_size = sizeof(*this);
91 Head.msgh_remote_port = kClientRemotePort;
92 Head.msgh_local_port = kServerLocalPort;
93 Head.msgh_id = 2401;
94 msgh_body.msgh_descriptor_count = 2;
95 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
96 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
97 NDR = NDR_record;
98 exception = kExceptionType;
99 codeCnt = 2;
100 code[0] = kExceptionCodes[0];
101 code[1] = kExceptionCodes[1];
102 }
103 };
104
105 struct __attribute__((packed, aligned(4))) ExceptionRaiseReply {
106 mach_msg_header_t Head;
107 NDR_record_t NDR;
108 kern_return_t RetCode;
109
110 void InitializeForTesting() {
111 memset(this, 0x5a, sizeof(*this));
112 RetCode = KERN_FAILURE;
113 }
114
115 // Verify accepts a |behavior| parameter because the same message format and
116 // verification function is used for ExceptionRaiseReply and
117 // MachExceptionRaiseReply. Knowing which behavior is expected allows the
118 // message ID to be checked.
119 void Verify(exception_behavior_t behavior) {
120 EXPECT_EQ(static_cast<mach_msg_bits_t>(
121 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)),
122 Head.msgh_bits);
123 EXPECT_EQ(sizeof(*this), Head.msgh_size);
124 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port);
125 EXPECT_EQ(kMachPortNull, Head.msgh_local_port);
126 switch (behavior) {
127 case EXCEPTION_DEFAULT:
128 EXPECT_EQ(2501, Head.msgh_id);
129 break;
130 case static_cast<exception_behavior_t>(EXCEPTION_DEFAULT |
131 MACH_EXCEPTION_CODES):
132 EXPECT_EQ(2505, Head.msgh_id);
133 break;
134 default:
135 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id "
136 << Head.msgh_id;
137 break;
138 }
139 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR)));
140 EXPECT_EQ(KERN_SUCCESS, RetCode);
141 }
142 };
143
144 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateRequest {
145 mach_msg_header_t Head;
146 NDR_record_t NDR;
147 exception_type_t exception;
148 mach_msg_type_number_t codeCnt;
149 integer_t code[2];
150 int flavor;
151 mach_msg_type_number_t old_stateCnt;
152 natural_t old_state[THREAD_STATE_MAX];
153
154 void InitializeForTesting() {
155 memset(this, 0xa5, sizeof(*this));
156 Head.msgh_bits =
157 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
158 Head.msgh_size = sizeof(*this);
159 Head.msgh_remote_port = kClientRemotePort;
160 Head.msgh_local_port = kServerLocalPort;
161 Head.msgh_id = 2402;
162 NDR = NDR_record;
163 exception = kExceptionType;
164 codeCnt = 2;
165 code[0] = kExceptionCodes[0];
166 code[1] = kExceptionCodes[1];
167 flavor = kThreadStateFlavor;
168 old_stateCnt = kThreadStateFlavorCount;
169
170 // Adjust the message size for the data that it’s actually carrying, which
171 // may be smaller than the maximum that it can carry.
172 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
173 }
174 };
175
176 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateReply {
177 mach_msg_header_t Head;
178 NDR_record_t NDR;
179 kern_return_t RetCode;
180 int flavor;
181 mach_msg_type_number_t new_stateCnt;
182 natural_t new_state[THREAD_STATE_MAX];
183
184 void InitializeForTesting() {
185 memset(this, 0x5a, sizeof(*this));
186 RetCode = KERN_FAILURE;
187 }
188
189 // Verify accepts a |behavior| parameter because the same message format and
190 // verification function is used for ExceptionRaiseStateReply,
191 // ExceptionRaiseStateIdentityReply, MachExceptionRaiseStateReply, and
192 // MachExceptionRaiseStateIdentityReply. Knowing which behavior is expected
193 // allows the message ID to be checked.
194 void Verify(exception_behavior_t behavior) {
195 EXPECT_EQ(static_cast<mach_msg_bits_t>(
196 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)),
197 Head.msgh_bits);
198 EXPECT_EQ(sizeof(*this), Head.msgh_size);
199 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port);
200 EXPECT_EQ(kMachPortNull, Head.msgh_local_port);
201 switch (behavior) {
202 case EXCEPTION_STATE:
203 EXPECT_EQ(2502, Head.msgh_id);
204 break;
205 case EXCEPTION_STATE_IDENTITY:
206 EXPECT_EQ(2503, Head.msgh_id);
207 break;
208 case static_cast<exception_behavior_t>(EXCEPTION_STATE |
209 MACH_EXCEPTION_CODES):
210 EXPECT_EQ(2506, Head.msgh_id);
211 break;
212 case static_cast<exception_behavior_t>(EXCEPTION_STATE_IDENTITY |
213 MACH_EXCEPTION_CODES):
214 EXPECT_EQ(2507, Head.msgh_id);
215 break;
216 default:
217 ADD_FAILURE() << "behavior " << behavior << ", Head.msgh_id "
218 << Head.msgh_id;
219 break;
220 }
221 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR)));
222 EXPECT_EQ(KERN_SUCCESS, RetCode);
223 EXPECT_EQ(kThreadStateFlavor, flavor);
224 EXPECT_EQ(arraysize(new_state), new_stateCnt);
225 }
226 };
227
228 struct __attribute__((packed, aligned(4))) ExceptionRaiseStateIdentityRequest {
229 mach_msg_header_t Head;
230 mach_msg_body_t msgh_body;
231 mach_msg_port_descriptor_t thread;
232 mach_msg_port_descriptor_t task;
233 NDR_record_t NDR;
234 exception_type_t exception;
235 mach_msg_type_number_t codeCnt;
236 integer_t code[2];
237 int flavor;
238 mach_msg_type_number_t old_stateCnt;
239 natural_t old_state[THREAD_STATE_MAX];
240
241 void InitializeForTesting() {
242 memset(this, 0xa5, sizeof(*this));
243 Head.msgh_bits =
244 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) |
245 MACH_MSGH_BITS_COMPLEX;
246 Head.msgh_size = sizeof(*this);
247 Head.msgh_remote_port = kClientRemotePort;
248 Head.msgh_local_port = kServerLocalPort;
249 Head.msgh_id = 2403;
250 msgh_body.msgh_descriptor_count = 2;
251 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
252 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
253 NDR = NDR_record;
254 exception = kExceptionType;
255 codeCnt = 2;
256 code[0] = kExceptionCodes[0];
257 code[1] = kExceptionCodes[1];
258 flavor = kThreadStateFlavor;
259 old_stateCnt = kThreadStateFlavorCount;
260
261 // Adjust the message size for the data that it’s actually carrying, which
262 // may be smaller than the maximum that it can carry.
263 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
264 }
265 };
266
267 // The reply messages for exception_raise_state and
268 // exception_raise_state_identity are identical.
269 typedef ExceptionRaiseStateReply ExceptionRaiseStateIdentityReply;
270
271 struct __attribute__((packed, aligned(4))) MachExceptionRaiseRequest {
272 mach_msg_header_t Head;
273 mach_msg_body_t msgh_body;
274 mach_msg_port_descriptor_t thread;
275 mach_msg_port_descriptor_t task;
276 NDR_record_t NDR;
277 exception_type_t exception;
278 mach_msg_type_number_t codeCnt;
279 int64_t code[2];
280
281 void InitializeForTesting() {
282 memset(this, 0xa5, sizeof(*this));
283 Head.msgh_bits =
284 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) |
285 MACH_MSGH_BITS_COMPLEX;
286 Head.msgh_size = sizeof(*this);
287 Head.msgh_remote_port = kClientRemotePort;
288 Head.msgh_local_port = kServerLocalPort;
289 Head.msgh_id = 2405;
290 msgh_body.msgh_descriptor_count = 2;
291 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
292 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
293 NDR = NDR_record;
294 exception = kExceptionType;
295 codeCnt = 2;
296 code[0] = kMachExceptionCodes[0];
297 code[1] = kMachExceptionCodes[1];
298 }
299 };
300
301 // The reply messages for exception_raise and mach_exception_raise are
302 // identical.
303 typedef ExceptionRaiseReply MachExceptionRaiseReply;
304
305 struct __attribute__((packed, aligned(4))) MachExceptionRaiseStateRequest {
306 mach_msg_header_t Head;
307 NDR_record_t NDR;
308 exception_type_t exception;
309 mach_msg_type_number_t codeCnt;
310 int64_t code[2];
311 int flavor;
312 mach_msg_type_number_t old_stateCnt;
313 natural_t old_state[THREAD_STATE_MAX];
314
315 void InitializeForTesting() {
316 memset(this, 0xa5, sizeof(*this));
317 Head.msgh_bits =
318 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
319 Head.msgh_size = sizeof(*this);
320 Head.msgh_remote_port = kClientRemotePort;
321 Head.msgh_local_port = kServerLocalPort;
322 Head.msgh_id = 2406;
323 NDR = NDR_record;
324 exception = kExceptionType;
325 codeCnt = 2;
326 code[0] = kMachExceptionCodes[0];
327 code[1] = kMachExceptionCodes[1];
328 flavor = kThreadStateFlavor;
329 old_stateCnt = kThreadStateFlavorCount;
330
331 // Adjust the message size for the data that it’s actually carrying, which
332 // may be smaller than the maximum that it can carry.
333 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
334 }
335 };
336
337 // The reply messages for exception_raise_state and mach_exception_raise_state
338 // are identical.
339 typedef ExceptionRaiseStateReply MachExceptionRaiseStateReply;
340
341 struct __attribute__((packed,
342 aligned(4))) MachExceptionRaiseStateIdentityRequest {
343 mach_msg_header_t Head;
344 mach_msg_body_t msgh_body;
345 mach_msg_port_descriptor_t thread;
346 mach_msg_port_descriptor_t task;
347 NDR_record_t NDR;
348 exception_type_t exception;
349 mach_msg_type_number_t codeCnt;
350 int64_t code[2];
351 int flavor;
352 mach_msg_type_number_t old_stateCnt;
353 natural_t old_state[THREAD_STATE_MAX];
354
355 void InitializeForTesting() {
356 memset(this, 0xa5, sizeof(*this));
357 Head.msgh_bits =
358 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) |
359 MACH_MSGH_BITS_COMPLEX;
360 Head.msgh_size = sizeof(*this);
361 Head.msgh_remote_port = kClientRemotePort;
362 Head.msgh_local_port = kServerLocalPort;
363 Head.msgh_id = 2407;
364 msgh_body.msgh_descriptor_count = 2;
365 InitializeMachMsgPortDescriptor(&thread, kExceptionThreadPort);
366 InitializeMachMsgPortDescriptor(&task, kExceptionTaskPort);
367 NDR = NDR_record;
368 exception = kExceptionType;
369 codeCnt = 2;
370 code[0] = kMachExceptionCodes[0];
371 code[1] = kMachExceptionCodes[1];
372 flavor = kThreadStateFlavor;
373 old_stateCnt = kThreadStateFlavorCount;
374
375 // Adjust the message size for the data that it’s actually carrying, which
376 // may be smaller than the maximum that it can carry.
377 Head.msgh_size += sizeof(old_state[0]) * old_stateCnt - sizeof(old_state);
378 }
379 };
380
381 // The reply messages for exception_raise_state_identity and
382 // mach_exception_raise_state_identity are identical.
383 typedef ExceptionRaiseStateIdentityReply MachExceptionRaiseStateIdentityReply;
384
385 // InvalidRequest and BadIDErrorReply are used to test that
386 // UniversalMachExcServer deals appropriately with messages that it does not
387 // understand: messages with an unknown Head.msgh_id.
388
389 struct __attribute__((packed, aligned(4))) InvalidRequest
390 : public mach_msg_empty_send_t {
391 void InitializeForTesting(mach_msg_id_t id) {
392 memset(this, 0xa5, sizeof(*this));
393 header.msgh_bits =
394 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
395 header.msgh_size = sizeof(*this);
396 header.msgh_remote_port = kClientRemotePort;
397 header.msgh_local_port = kServerLocalPort;
398 header.msgh_id = id;
399 }
400 };
401
402 struct __attribute__((packed, aligned(4))) BadIDErrorReply
403 : public mig_reply_error_t {
404 void InitializeForTesting() {
405 memset(this, 0x5a, sizeof(*this));
406 RetCode = KERN_FAILURE;
407 }
408
409 void Verify(mach_msg_id_t id) {
410 EXPECT_EQ(static_cast<mach_msg_bits_t>(
411 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0)),
412 Head.msgh_bits);
413 EXPECT_EQ(sizeof(*this), Head.msgh_size);
414 EXPECT_EQ(kClientRemotePort, Head.msgh_remote_port);
415 EXPECT_EQ(kMachPortNull, Head.msgh_local_port);
416 EXPECT_EQ(id + 100, Head.msgh_id);
417 EXPECT_EQ(0, memcmp(&NDR, &NDR_record, sizeof(NDR)));
418 EXPECT_EQ(MIG_BAD_ID, RetCode);
419 }
420 };
421
422 class MockUniversalMachExcServer : public UniversalMachExcServer {
423 public:
424 struct ConstExceptionCodes {
425 const mach_exception_data_type_t* code;
426 mach_msg_type_number_t code_count;
427 };
428 struct ThreadState {
429 thread_state_t state;
430 mach_msg_type_number_t* state_count;
431 };
432 struct ConstThreadState {
433 const natural_t* state;
434 mach_msg_type_number_t* state_count;
435 };
436
437 // CatchMachException is the method to mock, but it has 13 parameters, and
438 // gmock can only mock methods with up to 10 parameters. Coalesce some related
439 // parameters together into structs, and call a mocked method.
440 virtual kern_return_t CatchMachException(
441 exception_behavior_t behavior,
442 exception_handler_t exception_port,
443 thread_t thread,
444 task_t task,
445 exception_type_t exception,
446 const mach_exception_data_type_t* code,
447 mach_msg_type_number_t code_count,
448 thread_state_flavor_t* flavor,
449 const natural_t* old_state,
450 mach_msg_type_number_t old_state_count,
451 thread_state_t new_state,
452 mach_msg_type_number_t* new_state_count,
453 bool* destroy_complex_request) override {
454 *destroy_complex_request = true;
455 const ConstExceptionCodes exception_codes = {code, code_count};
456 const ConstThreadState old_thread_state = {old_state, &old_state_count};
457 ThreadState new_thread_state = {new_state, new_state_count};
458 return MockCatchMachException(behavior,
459 exception_port,
460 thread,
461 task,
462 exception,
463 &exception_codes,
464 flavor,
465 &old_thread_state,
466 &new_thread_state);
467 }
468
469 MOCK_METHOD9(MockCatchMachException,
470 kern_return_t(exception_behavior_t behavior,
471 exception_handler_t exception_port,
472 thread_t thread,
473 task_t task,
474 exception_type_t exception,
475 const ConstExceptionCodes* exception_codes,
476 thread_state_flavor_t* flavor,
477 const ConstThreadState* old_thread_state,
478 ThreadState* new_thread_state));
479 };
480
481 // Matcher for ConstExceptionCodes, testing that it carries 2 codes matching
482 // code_0 and code_1.
483 MATCHER_P2(AreExceptionCodes, code_0, code_1, "") {
484 if (!arg) {
485 return false;
486 }
487
488 if (arg->code_count == 2 && arg->code[0] == code_0 &&
489 arg->code[1] == code_1) {
490 return true;
491 }
492
493 *result_listener << "codes (";
494 for (size_t index = 0; index < arg->code_count; ++index) {
495 *result_listener << arg->code[index];
496 if (index < arg->code_count - 1) {
497 *result_listener << ", ";
498 }
499 }
500 *result_listener << ")";
501
502 return false;
503 }
504
505 // Matcher for ThreadState and ConstThreadState, testing that *state_count is
506 // present and matches the specified value. If 0 is specified for the count,
507 // state must be NULL (not present), otherwise state must be non-NULL (present).
508 MATCHER_P(IsThreadStateCount, state_count, "") {
509 if (!arg) {
510 return false;
511 }
512 if (!arg->state_count) {
513 *result_listener << "state_count NULL";
514 return false;
515 }
516 if (*(arg->state_count) != state_count) {
517 *result_listener << "*state_count " << *(arg->state_count);
518 return false;
519 }
520 if (state_count) {
521 if (!arg->state) {
522 *result_listener << "*state_count " << state_count << ", state NULL";
523 return false;
524 }
525 } else {
526 if (arg->state) {
527 *result_listener << "*state_count 0, state non-NULL (" << arg->state
528 << ")";
529 return false;
530 }
531 }
532 return true;
533 }
534
535 template <typename T>
536 class ScopedDefaultValue {
537 public:
538 explicit ScopedDefaultValue(const T& default_value) {
539 DefaultValue<T>::Set(default_value);
540 }
541
542 ~ScopedDefaultValue() { DefaultValue<T>::Clear(); }
543 };
544
545 TEST(ExcServerVariants, MockExceptionRaise) {
546 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
547
548 MockUniversalMachExcServer server;
549
550 ExceptionRaiseRequest request;
551 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
552 request.InitializeForTesting();
553
554 ExceptionRaiseReply reply;
555 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
556 reply.InitializeForTesting();
557
558 const exception_behavior_t kExceptionBehavior = EXCEPTION_DEFAULT;
559
560 EXPECT_CALL(server,
561 MockCatchMachException(
562 kExceptionBehavior,
563 kServerLocalPort,
564 kExceptionThreadPort,
565 kExceptionTaskPort,
566 kExceptionType,
567 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]),
568 Pointee(Eq(THREAD_STATE_NONE)),
569 IsThreadStateCount(0u),
570 IsThreadStateCount(0u)))
571 .WillOnce(Return(KERN_SUCCESS))
572 .RetiresOnSaturation();
573
574 bool destroy_complex_request = false;
575 EXPECT_TRUE(server.MachMessageServerFunction(
576 reinterpret_cast<mach_msg_header_t*>(&request),
577 reinterpret_cast<mach_msg_header_t*>(&reply),
578 &destroy_complex_request));
579 EXPECT_TRUE(destroy_complex_request);
580
581 reply.Verify(kExceptionBehavior);
582 }
583
584 TEST(ExcServerVariants, MockExceptionRaiseState) {
585 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
586
587 MockUniversalMachExcServer server;
588
589 ExceptionRaiseStateRequest request;
590 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
591 request.InitializeForTesting();
592
593 ExceptionRaiseStateReply reply;
594 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
595 reply.InitializeForTesting();
596
597 const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE;
598
599 EXPECT_CALL(server,
600 MockCatchMachException(
601 kExceptionBehavior,
602 kServerLocalPort,
603 MACH_PORT_NULL,
604 MACH_PORT_NULL,
605 kExceptionType,
606 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]),
607 Pointee(Eq(kThreadStateFlavor)),
608 IsThreadStateCount(kThreadStateFlavorCount),
609 IsThreadStateCount(arraysize(reply.new_state))))
610 .WillOnce(Return(KERN_SUCCESS))
611 .RetiresOnSaturation();
612
613 bool destroy_complex_request = false;
614 EXPECT_TRUE(server.MachMessageServerFunction(
615 reinterpret_cast<mach_msg_header_t*>(&request),
616 reinterpret_cast<mach_msg_header_t*>(&reply),
617 &destroy_complex_request));
618
619 // The request wasn’t complex, so nothing got a chance to change the value of
620 // this variable.
621 EXPECT_FALSE(destroy_complex_request);
622
623 reply.Verify(kExceptionBehavior);
624 }
625
626 TEST(ExcServerVariants, MockExceptionRaiseStateIdentity) {
627 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
628
629 MockUniversalMachExcServer server;
630
631 ExceptionRaiseStateIdentityRequest request;
632 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
633 request.InitializeForTesting();
634
635 ExceptionRaiseStateIdentityReply reply;
636 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
637 reply.InitializeForTesting();
638
639 const exception_behavior_t kExceptionBehavior = EXCEPTION_STATE_IDENTITY;
640
641 EXPECT_CALL(server,
642 MockCatchMachException(
643 kExceptionBehavior,
644 kServerLocalPort,
645 kExceptionThreadPort,
646 kExceptionTaskPort,
647 kExceptionType,
648 AreExceptionCodes(kExceptionCodes[0], kExceptionCodes[1]),
649 Pointee(Eq(kThreadStateFlavor)),
650 IsThreadStateCount(kThreadStateFlavorCount),
651 IsThreadStateCount(arraysize(reply.new_state))))
652 .WillOnce(Return(KERN_SUCCESS))
653 .RetiresOnSaturation();
654
655 bool destroy_complex_request = false;
656 EXPECT_TRUE(server.MachMessageServerFunction(
657 reinterpret_cast<mach_msg_header_t*>(&request),
658 reinterpret_cast<mach_msg_header_t*>(&reply),
659 &destroy_complex_request));
660 EXPECT_TRUE(destroy_complex_request);
661
662 reply.Verify(kExceptionBehavior);
663 }
664
665 TEST(ExcServerVariants, MockMachExceptionRaise) {
666 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
667
668 MockUniversalMachExcServer server;
669
670 MachExceptionRaiseRequest request;
671 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
672 request.InitializeForTesting();
673
674 MachExceptionRaiseReply reply;
675 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
676 reply.InitializeForTesting();
677
678 const exception_behavior_t kExceptionBehavior =
679 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES;
680
681 EXPECT_CALL(
682 server,
683 MockCatchMachException(
684 kExceptionBehavior,
685 kServerLocalPort,
686 kExceptionThreadPort,
687 kExceptionTaskPort,
688 kExceptionType,
689 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]),
690 Pointee(Eq(THREAD_STATE_NONE)),
691 IsThreadStateCount(0u),
692 IsThreadStateCount(0u)))
693 .WillOnce(Return(KERN_SUCCESS))
694 .RetiresOnSaturation();
695
696 bool destroy_complex_request = false;
697 EXPECT_TRUE(server.MachMessageServerFunction(
698 reinterpret_cast<mach_msg_header_t*>(&request),
699 reinterpret_cast<mach_msg_header_t*>(&reply),
700 &destroy_complex_request));
701 EXPECT_TRUE(destroy_complex_request);
702
703 reply.Verify(kExceptionBehavior);
704 }
705
706 TEST(ExcServerVariants, MockMachExceptionRaiseState) {
707 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
708
709 MockUniversalMachExcServer server;
710
711 MachExceptionRaiseStateRequest request;
712 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
713 request.InitializeForTesting();
714
715 MachExceptionRaiseStateReply reply;
716 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
717 reply.InitializeForTesting();
718
719 const exception_behavior_t kExceptionBehavior =
720 EXCEPTION_STATE | MACH_EXCEPTION_CODES;
721
722 EXPECT_CALL(
723 server,
724 MockCatchMachException(
725 kExceptionBehavior,
726 kServerLocalPort,
727 MACH_PORT_NULL,
728 MACH_PORT_NULL,
729 kExceptionType,
730 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]),
731 Pointee(Eq(kThreadStateFlavor)),
732 IsThreadStateCount(kThreadStateFlavorCount),
733 IsThreadStateCount(arraysize(reply.new_state))))
734 .WillOnce(Return(KERN_SUCCESS))
735 .RetiresOnSaturation();
736
737 bool destroy_complex_request = false;
738 EXPECT_TRUE(server.MachMessageServerFunction(
739 reinterpret_cast<mach_msg_header_t*>(&request),
740 reinterpret_cast<mach_msg_header_t*>(&reply),
741 &destroy_complex_request));
742
743 // The request wasn’t complex, so nothing got a chance to change the value of
744 // this variable.
745 EXPECT_FALSE(destroy_complex_request);
746
747 reply.Verify(kExceptionBehavior);
748 }
749
750 TEST(ExcServerVariants, MockMachExceptionRaiseStateIdentity) {
751 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
752
753 MockUniversalMachExcServer server;
754
755 MachExceptionRaiseStateIdentityRequest request;
756 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
757 request.InitializeForTesting();
758
759 MachExceptionRaiseStateIdentityReply reply;
760 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
761 reply.InitializeForTesting();
762
763 const exception_behavior_t kExceptionBehavior =
764 EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES;
765
766 EXPECT_CALL(
767 server,
768 MockCatchMachException(
769 kExceptionBehavior,
770 kServerLocalPort,
771 kExceptionThreadPort,
772 kExceptionTaskPort,
773 kExceptionType,
774 AreExceptionCodes(kMachExceptionCodes[0], kMachExceptionCodes[1]),
775 Pointee(Eq(kThreadStateFlavor)),
776 IsThreadStateCount(kThreadStateFlavorCount),
777 IsThreadStateCount(arraysize(reply.new_state))))
778 .WillOnce(Return(KERN_SUCCESS))
779 .RetiresOnSaturation();
780
781 bool destroy_complex_request = false;
782 EXPECT_TRUE(server.MachMessageServerFunction(
783 reinterpret_cast<mach_msg_header_t*>(&request),
784 reinterpret_cast<mach_msg_header_t*>(&reply),
785 &destroy_complex_request));
786 EXPECT_TRUE(destroy_complex_request);
787
788 reply.Verify(kExceptionBehavior);
789 }
790
791 TEST(ExcServerVariants, MockUnknownID) {
792 ScopedDefaultValue<kern_return_t> default_kern_return_t(KERN_FAILURE);
793
794 MockUniversalMachExcServer server;
795
796 // Make sure that a message with an unknown ID is handled appropriately.
797 // UniversalMachExcServer should not dispatch the message to
798 // MachMessageServerFunction, but should generate a MIG_BAD_ID error reply.
799
800 const mach_msg_id_t unknown_ids[] = {
801 // Reasonable things to check.
802 -101,
803 -100,
804 -99,
805 -1,
806 0,
807 1,
808 99,
809 100,
810 101,
811
812 // Invalid IDs right around valid ones.
813 2400,
814 2404,
815 2408,
816
817 // Valid and invalid IDs in the range used for replies, not requests.
818 2500,
819 2501,
820 2502,
821 2503,
822 2504,
823 2505,
824 2506,
825 2507,
826 2508,
827 };
828
829 for (size_t index = 0; index < arraysize(unknown_ids); ++index) {
830 mach_msg_id_t id = unknown_ids[index];
831
832 SCOPED_TRACE(base::StringPrintf("unknown id %d", id));
833
834 InvalidRequest request;
835 EXPECT_LE(sizeof(request), server.MachMessageServerRequestSize());
836 request.InitializeForTesting(id);
837
838 BadIDErrorReply reply;
839 EXPECT_LE(sizeof(reply), server.MachMessageServerReplySize());
840 reply.InitializeForTesting();
841
842 bool destroy_complex_request = false;
843 EXPECT_FALSE(server.MachMessageServerFunction(
844 reinterpret_cast<mach_msg_header_t*>(&request),
845 reinterpret_cast<mach_msg_header_t*>(&reply),
846 &destroy_complex_request));
847
848 // The request wasn’t handled, nothing got a chance to change the value of
849 // this variable. MachMessageServer would destroy the request if it was
850 // complex, regardless of what was done to this variable, because the
851 // return code was not KERN_SUCCESS or MIG_NO_REPLY.
852 EXPECT_FALSE(destroy_complex_request);
853
854 reply.Verify(id);
855 }
856 }
857
858 class TestExcServerVariants : public UniversalMachExcServer,
859 public MachMultiprocess {
860 public:
861 TestExcServerVariants(exception_behavior_t behavior,
862 thread_state_flavor_t flavor,
863 mach_msg_type_number_t state_count)
864 : UniversalMachExcServer(),
865 MachMultiprocess(),
866 behavior_(behavior),
867 flavor_(flavor),
868 state_count_(state_count),
869 handled_(false) {
870 }
871
872 // UniversalMachExcServer:
873
874 virtual kern_return_t CatchMachException(
875 exception_behavior_t behavior,
876 exception_handler_t exception_port,
877 thread_t thread,
878 task_t task,
879 exception_type_t exception,
880 const mach_exception_data_type_t* code,
881 mach_msg_type_number_t code_count,
882 thread_state_flavor_t* flavor,
883 const natural_t* old_state,
884 mach_msg_type_number_t old_state_count,
885 thread_state_t new_state,
886 mach_msg_type_number_t* new_state_count,
887 bool* destroy_complex_request) override {
888 *destroy_complex_request = true;
889
890 EXPECT_FALSE(handled_);
891 handled_ = true;
892
893 EXPECT_EQ(behavior_, behavior);
894 exception_behavior_t basic_behavior = behavior & ~MACH_EXCEPTION_CODES;
895 const bool has_identity = basic_behavior == EXCEPTION_DEFAULT ||
896 basic_behavior == EXCEPTION_STATE_IDENTITY;
897 const bool has_state = basic_behavior == EXCEPTION_STATE ||
898 basic_behavior == EXCEPTION_STATE_IDENTITY;
899
900 EXPECT_EQ(LocalPort(), exception_port);
901
902 if (has_identity) {
903 EXPECT_NE(kMachPortNull, thread);
904 EXPECT_EQ(ChildTask(), task);
905 } else {
906 EXPECT_EQ(kMachPortNull, thread);
907 EXPECT_EQ(kMachPortNull, task);
908 }
909
910 EXPECT_EQ(EXC_CRASH, exception);
911 EXPECT_EQ(2u, code_count);
912
913 if (code_count > 1) {
914 // The signal that terminated the process is stored in code[0] along with
915 // some other data. See 10.9.4 xnu-2422.110.17/bsd/kern/kern_exit.c
916 // proc_prepareexit().
917 int sig = (code[0] >> 24) & 0xff;
918 SetExpectedChildTermination(kTerminationSignal, sig);
919 }
920
921 if (has_state) {
922 EXPECT_EQ(flavor_, *flavor);
923 EXPECT_EQ(state_count_, old_state_count);
924 EXPECT_NE(static_cast<const natural_t*>(NULL), old_state);
925 EXPECT_EQ(static_cast<mach_msg_type_number_t>(THREAD_STATE_MAX),
926 *new_state_count);
927 EXPECT_NE(static_cast<const natural_t*>(NULL), new_state);
928 } else {
929 EXPECT_EQ(THREAD_STATE_NONE, *flavor);
930 EXPECT_EQ(0u, old_state_count);
931 EXPECT_EQ(NULL, old_state);
932 EXPECT_EQ(0u, *new_state_count);
933 EXPECT_EQ(NULL, new_state);
934 }
935
936 // Even for an EXC_CRASH handler, returning KERN_SUCCESS with a
937 // state-carrying reply will cause the kernel to try to set a new thread
938 // state, leading to a perceptible waste of time. Returning
939 // MACH_RCV_PORT_DIED is the only way to suppress this behavior while also
940 // preventing the kernel from looking for another (host-level) EXC_CRASH
941 // handler. See 10.9.4 xnu-2422.110.17/osfmk/kern/exception.c
942 // exception_triage().
943 return has_state ? MACH_RCV_PORT_DIED : KERN_SUCCESS;
944 }
945
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
OLDNEW
« no previous file with comments | « util/mach/exc_server_variants.cc ('k') | util/mach/mach_extensions.h » ('j') | util/util.gyp » ('J')

Powered by Google App Engine
This is Rietveld 408576698