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

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: Include live tests of crashing children 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/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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698