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 <AvailabilityMacros.h>
18 #include <string.h>
19
20 #include <algorithm>
21 #include <vector>
22
23 #include "base/logging.h"
24 #include "base/stl_util.h"
25 #include "util/mac/mac_util.h"
26 #include "util/mach/composite_mach_message_server.h"
27 #include "util/mach/exc.h"
28 #include "util/mach/excServer.h"
29 #include "util/mach/exception_behaviors.h"
30 #include "util/mach/mach_exc.h"
31 #include "util/mach/mach_excServer.h"
32 #include "util/mach/mach_message.h"
33
34 namespace crashpad {
35
36 namespace {
37
38 // Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
39 // the exc subsystem.
40 struct ExcTraits {
41 using ExceptionCode = exception_data_type_t;
42
43 using RequestUnion = __RequestUnion__exc_subsystem;
44 using ReplyUnion = __ReplyUnion__exc_subsystem;
45
46 using ExceptionRaiseRequest = __Request__exception_raise_t;
47 using ExceptionRaiseStateRequest = __Request__exception_raise_state_t;
48 using ExceptionRaiseStateIdentityRequest =
49 __Request__exception_raise_state_identity_t;
50
51 using ExceptionRaiseReply = __Reply__exception_raise_t;
52 using ExceptionRaiseStateReply = __Reply__exception_raise_state_t;
53 using ExceptionRaiseStateIdentityReply =
54 __Reply__exception_raise_state_identity_t;
55
56 // The MIG-generated __MIG_check__Request__*() functions are not declared as
57 // accepting const data, but they could have been because they in fact do not
58 // modify the data.
59
MIGCheckRequestExceptionRaisecrashpad::__anon7ba16b890111::ExcTraits60 static kern_return_t MIGCheckRequestExceptionRaise(
61 const ExceptionRaiseRequest* in_request) {
62 return __MIG_check__Request__exception_raise_t(
63 const_cast<ExceptionRaiseRequest*>(in_request));
64 }
65
MIGCheckRequestExceptionRaiseStatecrashpad::__anon7ba16b890111::ExcTraits66 static kern_return_t MIGCheckRequestExceptionRaiseState(
67 const ExceptionRaiseStateRequest* in_request,
68 const ExceptionRaiseStateRequest** in_request_1) {
69 return __MIG_check__Request__exception_raise_state_t(
70 const_cast<ExceptionRaiseStateRequest*>(in_request),
71 const_cast<ExceptionRaiseStateRequest**>(in_request_1));
72 }
73
MIGCheckRequestExceptionRaiseStateIdentitycrashpad::__anon7ba16b890111::ExcTraits74 static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
75 const ExceptionRaiseStateIdentityRequest* in_request,
76 const ExceptionRaiseStateIdentityRequest** in_request_1) {
77 return __MIG_check__Request__exception_raise_state_identity_t(
78 const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
79 const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
80 }
81
82 // There are no predefined constants for these.
83 static const mach_msg_id_t kMachMessageIDExceptionRaise = 2401;
84 static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2402;
85 static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2403;
86
87 static const exception_behavior_t kExceptionBehavior = 0;
88 };
89
90 // Traits for ExcServer<> and SimplifiedExcServer<> adapting them for use with
91 // the mach_exc subsystem.
92 struct MachExcTraits {
93 using ExceptionCode = mach_exception_data_type_t;
94
95 using RequestUnion = __RequestUnion__mach_exc_subsystem;
96 using ReplyUnion = __ReplyUnion__mach_exc_subsystem;
97
98 using ExceptionRaiseRequest = __Request__mach_exception_raise_t;
99 using ExceptionRaiseStateRequest = __Request__mach_exception_raise_state_t;
100 using ExceptionRaiseStateIdentityRequest =
101 __Request__mach_exception_raise_state_identity_t;
102
103 using ExceptionRaiseReply = __Reply__mach_exception_raise_t;
104 using ExceptionRaiseStateReply = __Reply__mach_exception_raise_state_t;
105 using ExceptionRaiseStateIdentityReply =
106 __Reply__mach_exception_raise_state_identity_t;
107
108 // The MIG-generated __MIG_check__Request__*() functions are not declared as
109 // accepting const data, but they could have been because they in fact do not
110 // modify the data.
111
MIGCheckRequestExceptionRaisecrashpad::__anon7ba16b890111::MachExcTraits112 static kern_return_t MIGCheckRequestExceptionRaise(
113 const ExceptionRaiseRequest* in_request) {
114 return __MIG_check__Request__mach_exception_raise_t(
115 const_cast<ExceptionRaiseRequest*>(in_request));
116 }
117
MIGCheckRequestExceptionRaiseStatecrashpad::__anon7ba16b890111::MachExcTraits118 static kern_return_t MIGCheckRequestExceptionRaiseState(
119 const ExceptionRaiseStateRequest* in_request,
120 const ExceptionRaiseStateRequest** in_request_1) {
121 return __MIG_check__Request__mach_exception_raise_state_t(
122 const_cast<ExceptionRaiseStateRequest*>(in_request),
123 const_cast<ExceptionRaiseStateRequest**>(in_request_1));
124 }
125
MIGCheckRequestExceptionRaiseStateIdentitycrashpad::__anon7ba16b890111::MachExcTraits126 static kern_return_t MIGCheckRequestExceptionRaiseStateIdentity(
127 const ExceptionRaiseStateIdentityRequest* in_request,
128 const ExceptionRaiseStateIdentityRequest** in_request_1) {
129 return __MIG_check__Request__mach_exception_raise_state_identity_t(
130 const_cast<ExceptionRaiseStateIdentityRequest*>(in_request),
131 const_cast<ExceptionRaiseStateIdentityRequest**>(in_request_1));
132 }
133
134 // There are no predefined constants for these.
135 static const mach_msg_id_t kMachMessageIDExceptionRaise = 2405;
136 static const mach_msg_id_t kMachMessageIDExceptionRaiseState = 2406;
137 static const mach_msg_id_t kMachMessageIDExceptionRaiseStateIdentity = 2407;
138
139 static const exception_behavior_t kExceptionBehavior = MACH_EXCEPTION_CODES;
140 };
141
142 //! \brief A server interface for the `exc` or `mach_exc` Mach subsystems.
143 template <typename Traits>
144 class ExcServer : public MachMessageServer::Interface {
145 public:
146 //! \brief An interface that the different request messages that are a part of
147 //! the `exc` or `mach_exc` Mach subsystems can be dispatched to.
148 class Interface {
149 public:
150 //! \brief Handles exceptions raised by `exception_raise()` or
151 //! `mach_exception_raise()`.
152 //!
153 //! This behaves equivalently to a `catch_exception_raise()` function used
154 //! with `exc_server()`, or a `catch_mach_exception_raise()` function used
155 //! with `mach_exc_server()`.
156 //!
157 //! \param[in] trailer The trailer received with the request message.
158 //! \param[out] destroy_request `true` if the request message is to be
159 //! destroyed even when this method returns success. See
160 //! MachMessageServer::Interface.
161 virtual kern_return_t CatchExceptionRaise(
162 exception_handler_t exception_port,
163 thread_t thread,
164 task_t task,
165 exception_type_t exception,
166 const typename Traits::ExceptionCode* code,
167 mach_msg_type_number_t code_count,
168 const mach_msg_trailer_t* trailer,
169 bool* destroy_request) = 0;
170
171 //! \brief Handles exceptions raised by `exception_raise_state()` or
172 //! `mach_exception_raise_state()`.
173 //!
174 //! This behaves equivalently to a `catch_exception_raise_state()` function
175 //! used with `exc_server()`, or a `catch_mach_exception_raise_state()`
176 //! function used with `mach_exc_server()`.
177 //!
178 //! There is no \a destroy_request parameter because, unlike
179 //! CatchExceptionRaise() and CatchExceptionRaiseStateIdentity(), the
180 //! request message is not complex (it does not carry the \a thread or \a
181 //! task port rights) and thus there is nothing to destroy.
182 //!
183 //! \param[in] trailer The trailer received with the request message.
184 virtual kern_return_t CatchExceptionRaiseState(
185 exception_handler_t exception_port,
186 exception_type_t exception,
187 const typename Traits::ExceptionCode* code,
188 mach_msg_type_number_t code_count,
189 thread_state_flavor_t* flavor,
190 ConstThreadState old_state,
191 mach_msg_type_number_t old_state_count,
192 thread_state_t new_state,
193 mach_msg_type_number_t* new_state_count,
194 const mach_msg_trailer_t* trailer) = 0;
195
196 //! \brief Handles exceptions raised by `exception_raise_state_identity()`
197 //! or `mach_exception_raise_state_identity()`.
198 //!
199 //! This behaves equivalently to a `catch_exception_raise_state_identity()`
200 //! function used with `exc_server()`, or a
201 //! `catch_mach_exception_raise_state_identity()` function used with
202 //! `mach_exc_server()`.
203 //!
204 //! \param[in] trailer The trailer received with the request message.
205 //! \param[out] destroy_request `true` if the request message is to be
206 //! destroyed even when this method returns success. See
207 //! MachMessageServer::Interface.
208 virtual kern_return_t CatchExceptionRaiseStateIdentity(
209 exception_handler_t exception_port,
210 thread_t thread,
211 task_t task,
212 exception_type_t exception,
213 const typename Traits::ExceptionCode* code,
214 mach_msg_type_number_t code_count,
215 thread_state_flavor_t* flavor,
216 ConstThreadState old_state,
217 mach_msg_type_number_t old_state_count,
218 thread_state_t new_state,
219 mach_msg_type_number_t* new_state_count,
220 const mach_msg_trailer_t* trailer,
221 bool* destroy_request) = 0;
222
223 protected:
~Interface()224 ~Interface() {}
225 };
226
227 //! \brief Constructs an object of this class.
228 //!
229 //! \param[in] interface The interface to dispatch requests to. Weak.
ExcServer(Interface * interface)230 explicit ExcServer(Interface* interface)
231 : MachMessageServer::Interface(), interface_(interface) {}
232
233 // MachMessageServer::Interface:
234
235 bool MachMessageServerFunction(const mach_msg_header_t* in_header,
236 mach_msg_header_t* out_header,
237 bool* destroy_complex_request) override;
238
MachMessageServerRequestIDs()239 std::set<mach_msg_id_t> MachMessageServerRequestIDs() override {
240 constexpr mach_msg_id_t request_ids[] = {
241 Traits::kMachMessageIDExceptionRaise,
242 Traits::kMachMessageIDExceptionRaiseState,
243 Traits::kMachMessageIDExceptionRaiseStateIdentity,
244 };
245 return std::set<mach_msg_id_t>(&request_ids[0],
246 &request_ids[base::size(request_ids)]);
247 }
248
MachMessageServerRequestSize()249 mach_msg_size_t MachMessageServerRequestSize() override {
250 return sizeof(typename Traits::RequestUnion);
251 }
252
MachMessageServerReplySize()253 mach_msg_size_t MachMessageServerReplySize() override {
254 return sizeof(typename Traits::ReplyUnion);
255 }
256
257 private:
258 Interface* interface_; // weak
259
260 DISALLOW_COPY_AND_ASSIGN(ExcServer);
261 };
262
263 template <typename Traits>
MachMessageServerFunction(const mach_msg_header_t * in_header,mach_msg_header_t * out_header,bool * destroy_complex_request)264 bool ExcServer<Traits>::MachMessageServerFunction(
265 const mach_msg_header_t* in_header,
266 mach_msg_header_t* out_header,
267 bool* destroy_complex_request) {
268 PrepareMIGReplyFromRequest(in_header, out_header);
269
270 const mach_msg_trailer_t* in_trailer =
271 MachMessageTrailerFromHeader(in_header);
272
273 switch (in_header->msgh_id) {
274 case Traits::kMachMessageIDExceptionRaise: {
275 // exception_raise(), catch_exception_raise(), mach_exception_raise(),
276 // catch_mach_exception_raise().
277 using Request = typename Traits::ExceptionRaiseRequest;
278 const Request* in_request = reinterpret_cast<const Request*>(in_header);
279 kern_return_t kr = Traits::MIGCheckRequestExceptionRaise(in_request);
280 if (kr != MACH_MSG_SUCCESS) {
281 SetMIGReplyError(out_header, kr);
282 return true;
283 }
284
285 using Reply = typename Traits::ExceptionRaiseReply;
286 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
287 out_reply->RetCode =
288 interface_->CatchExceptionRaise(in_header->msgh_local_port,
289 in_request->thread.name,
290 in_request->task.name,
291 in_request->exception,
292 in_request->code,
293 in_request->codeCnt,
294 in_trailer,
295 destroy_complex_request);
296 if (out_reply->RetCode != KERN_SUCCESS) {
297 return true;
298 }
299
300 out_header->msgh_size = sizeof(*out_reply);
301 return true;
302 }
303
304 case Traits::kMachMessageIDExceptionRaiseState: {
305 // exception_raise_state(), catch_exception_raise_state(),
306 // mach_exception_raise_state(), catch_mach_exception_raise_state().
307 using Request = typename Traits::ExceptionRaiseStateRequest;
308 const Request* in_request = reinterpret_cast<const Request*>(in_header);
309
310 // in_request_1 is used for the portion of the request after the codes,
311 // which in theory can be variable-length. The check function will set it.
312 const Request* in_request_1;
313 kern_return_t kr =
314 Traits::MIGCheckRequestExceptionRaiseState(in_request, &in_request_1);
315 if (kr != MACH_MSG_SUCCESS) {
316 SetMIGReplyError(out_header, kr);
317 return true;
318 }
319
320 using Reply = typename Traits::ExceptionRaiseStateReply;
321 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
322 out_reply->flavor = in_request_1->flavor;
323 out_reply->new_stateCnt = base::size(out_reply->new_state);
324 out_reply->RetCode =
325 interface_->CatchExceptionRaiseState(in_header->msgh_local_port,
326 in_request->exception,
327 in_request->code,
328 in_request->codeCnt,
329 &out_reply->flavor,
330 in_request_1->old_state,
331 in_request_1->old_stateCnt,
332 out_reply->new_state,
333 &out_reply->new_stateCnt,
334 in_trailer);
335 if (out_reply->RetCode != KERN_SUCCESS) {
336 return true;
337 }
338
339 out_header->msgh_size =
340 sizeof(*out_reply) - sizeof(out_reply->new_state) +
341 sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
342 return true;
343 }
344
345 case Traits::kMachMessageIDExceptionRaiseStateIdentity: {
346 // exception_raise_state_identity(),
347 // catch_exception_raise_state_identity(),
348 // mach_exception_raise_state_identity(),
349 // catch_mach_exception_raise_state_identity().
350 using Request = typename Traits::ExceptionRaiseStateIdentityRequest;
351 const Request* in_request = reinterpret_cast<const Request*>(in_header);
352
353 // in_request_1 is used for the portion of the request after the codes,
354 // which in theory can be variable-length. The check function will set it.
355 const Request* in_request_1;
356 kern_return_t kr = Traits::MIGCheckRequestExceptionRaiseStateIdentity(
357 in_request, &in_request_1);
358 if (kr != MACH_MSG_SUCCESS) {
359 SetMIGReplyError(out_header, kr);
360 return true;
361 }
362
363 using Reply = typename Traits::ExceptionRaiseStateIdentityReply;
364 Reply* out_reply = reinterpret_cast<Reply*>(out_header);
365 out_reply->flavor = in_request_1->flavor;
366 out_reply->new_stateCnt = base::size(out_reply->new_state);
367 out_reply->RetCode = interface_->CatchExceptionRaiseStateIdentity(
368 in_header->msgh_local_port,
369 in_request->thread.name,
370 in_request->task.name,
371 in_request->exception,
372 in_request->code,
373 in_request->codeCnt,
374 &out_reply->flavor,
375 in_request_1->old_state,
376 in_request_1->old_stateCnt,
377 out_reply->new_state,
378 &out_reply->new_stateCnt,
379 in_trailer,
380 destroy_complex_request);
381 if (out_reply->RetCode != KERN_SUCCESS) {
382 return true;
383 }
384
385 out_header->msgh_size =
386 sizeof(*out_reply) - sizeof(out_reply->new_state) +
387 sizeof(out_reply->new_state[0]) * out_reply->new_stateCnt;
388 return true;
389 }
390
391 default: {
392 SetMIGReplyError(out_header, MIG_BAD_ID);
393 return false;
394 }
395 }
396 }
397
398 //! \brief A server interface for the `exc` or `mach_exc` Mach subsystems,
399 //! simplified to have only a single interface method needing
400 //! implementation.
401 template <typename Traits>
402 class SimplifiedExcServer final : public ExcServer<Traits>,
403 public ExcServer<Traits>::Interface {
404 public:
405 //! \brief An interface that the different request messages that are a part of
406 //! the `exc` or `mach_exc` Mach subsystems can be dispatched to.
407 class Interface {
408 public:
409 //! \brief Handles exceptions raised by `exception_raise()`,
410 //! `exception_raise_state()`, and `exception_raise_state_identity()`;
411 //! or `mach_exception_raise()`, `mach_exception_raise_state()`, and
412 //! `mach_exception_raise_state_identity()`.
413 //!
414 //! For convenience in implementation, these different “behaviors” of
415 //! exception messages are all mapped to a single interface method. The
416 //! exception’s original “behavior” is specified in the \a behavior
417 //! parameter. Only parameters that were supplied in the request message
418 //! are populated, other parameters are set to reasonable default values.
419 //!
420 //! The meanings of most parameters are identical to that of
421 //! ExcServer<>::Interface::CatchExceptionRaiseStateIdentity().
422 //!
423 //! \param[in] behavior `EXCEPTION_DEFAULT`, `EXCEPTION_STATE`, or
424 //! `EXCEPTION_STATE_IDENTITY`, identifying which exception request
425 //! message was processed and thus which other parameters are valid.
426 //! When used with the `mach_exc` subsystem, `MACH_EXCEPTION_CODES` will
427 //! be ORed in to this parameter.
428 virtual kern_return_t CatchException(
429 exception_behavior_t behavior,
430 exception_handler_t exception_port,
431 thread_t thread,
432 task_t task,
433 exception_type_t exception,
434 const typename Traits::ExceptionCode* code,
435 mach_msg_type_number_t code_count,
436 thread_state_flavor_t* flavor,
437 ConstThreadState old_state,
438 mach_msg_type_number_t old_state_count,
439 thread_state_t new_state,
440 mach_msg_type_number_t* new_state_count,
441 const mach_msg_trailer_t* trailer,
442 bool* destroy_complex_request) = 0;
443
444 protected:
~Interface()445 ~Interface() {}
446 };
447
448 //! \brief Constructs an object of this class.
449 //!
450 //! \param[in] interface The interface to dispatch requests to. Weak.
SimplifiedExcServer(Interface * interface)451 explicit SimplifiedExcServer(Interface* interface)
452 : ExcServer<Traits>(this),
453 ExcServer<Traits>::Interface(),
454 interface_(interface) {}
455
456 // ExcServer::Interface:
457
CatchExceptionRaise(exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const typename Traits::ExceptionCode * code,mach_msg_type_number_t code_count,const mach_msg_trailer_t * trailer,bool * destroy_request)458 kern_return_t CatchExceptionRaise(exception_handler_t exception_port,
459 thread_t thread,
460 task_t task,
461 exception_type_t exception,
462 const typename Traits::ExceptionCode* code,
463 mach_msg_type_number_t code_count,
464 const mach_msg_trailer_t* trailer,
465 bool* destroy_request) override {
466 thread_state_flavor_t flavor = THREAD_STATE_NONE;
467 mach_msg_type_number_t new_state_count = 0;
468 return interface_->CatchException(
469 Traits::kExceptionBehavior | EXCEPTION_DEFAULT,
470 exception_port,
471 thread,
472 task,
473 exception,
474 code_count ? code : nullptr,
475 code_count,
476 &flavor,
477 nullptr,
478 0,
479 nullptr,
480 &new_state_count,
481 trailer,
482 destroy_request);
483 }
484
CatchExceptionRaiseState(exception_handler_t exception_port,exception_type_t exception,const typename Traits::ExceptionCode * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer)485 kern_return_t CatchExceptionRaiseState(
486 exception_handler_t exception_port,
487 exception_type_t exception,
488 const typename Traits::ExceptionCode* code,
489 mach_msg_type_number_t code_count,
490 thread_state_flavor_t* flavor,
491 ConstThreadState old_state,
492 mach_msg_type_number_t old_state_count,
493 thread_state_t new_state,
494 mach_msg_type_number_t* new_state_count,
495 const mach_msg_trailer_t* trailer) override {
496 bool destroy_complex_request = false;
497 return interface_->CatchException(
498 Traits::kExceptionBehavior | EXCEPTION_STATE,
499 exception_port,
500 THREAD_NULL,
501 TASK_NULL,
502 exception,
503 code_count ? code : nullptr,
504 code_count,
505 flavor,
506 old_state_count ? old_state : nullptr,
507 old_state_count,
508 new_state_count ? new_state : nullptr,
509 new_state_count,
510 trailer,
511 &destroy_complex_request);
512 }
513
CatchExceptionRaiseStateIdentity(exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const typename Traits::ExceptionCode * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_request)514 kern_return_t CatchExceptionRaiseStateIdentity(
515 exception_handler_t exception_port,
516 thread_t thread,
517 task_t task,
518 exception_type_t exception,
519 const typename Traits::ExceptionCode* code,
520 mach_msg_type_number_t code_count,
521 thread_state_flavor_t* flavor,
522 ConstThreadState old_state,
523 mach_msg_type_number_t old_state_count,
524 thread_state_t new_state,
525 mach_msg_type_number_t* new_state_count,
526 const mach_msg_trailer_t* trailer,
527 bool* destroy_request) override {
528 return interface_->CatchException(
529 Traits::kExceptionBehavior | EXCEPTION_STATE_IDENTITY,
530 exception_port,
531 thread,
532 task,
533 exception,
534 code_count ? code : nullptr,
535 code_count,
536 flavor,
537 old_state_count ? old_state : nullptr,
538 old_state_count,
539 new_state_count ? new_state : nullptr,
540 new_state_count,
541 trailer,
542 destroy_request);
543 }
544
545 private:
546 Interface* interface_; // weak
547
548 DISALLOW_COPY_AND_ASSIGN(SimplifiedExcServer);
549 };
550
551 } // namespace
552
553 namespace internal {
554
555 class UniversalMachExcServerImpl final
556 : public CompositeMachMessageServer,
557 public SimplifiedExcServer<ExcTraits>::Interface,
558 public SimplifiedExcServer<MachExcTraits>::Interface {
559 public:
UniversalMachExcServerImpl(UniversalMachExcServer::Interface * interface)560 explicit UniversalMachExcServerImpl(
561 UniversalMachExcServer::Interface* interface)
562 : CompositeMachMessageServer(),
563 SimplifiedExcServer<ExcTraits>::Interface(),
564 SimplifiedExcServer<MachExcTraits>::Interface(),
565 exc_server_(this),
566 mach_exc_server_(this),
567 interface_(interface) {
568 AddHandler(&exc_server_);
569 AddHandler(&mach_exc_server_);
570 }
571
~UniversalMachExcServerImpl()572 ~UniversalMachExcServerImpl() {}
573
574 // SimplifiedExcServer<ExcTraits>::Interface:
CatchException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const exception_data_type_t * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_complex_request)575 kern_return_t CatchException(exception_behavior_t behavior,
576 exception_handler_t exception_port,
577 thread_t thread,
578 task_t task,
579 exception_type_t exception,
580 const exception_data_type_t* code,
581 mach_msg_type_number_t code_count,
582 thread_state_flavor_t* flavor,
583 ConstThreadState old_state,
584 mach_msg_type_number_t old_state_count,
585 thread_state_t new_state,
586 mach_msg_type_number_t* new_state_count,
587 const mach_msg_trailer_t* trailer,
588 bool* destroy_complex_request) {
589 std::vector<mach_exception_data_type_t> mach_codes;
590 mach_codes.reserve(code_count);
591 for (size_t index = 0; index < code_count; ++index) {
592 mach_codes.push_back(code[index]);
593 }
594
595 return interface_->CatchMachException(behavior,
596 exception_port,
597 thread,
598 task,
599 exception,
600 code_count ? &mach_codes[0] : nullptr,
601 code_count,
602 flavor,
603 old_state_count ? old_state : nullptr,
604 old_state_count,
605 new_state_count ? new_state : nullptr,
606 new_state_count,
607 trailer,
608 destroy_complex_request);
609 }
610
611 // SimplifiedExcServer<MachExcTraits>::Interface:
CatchException(exception_behavior_t behavior,exception_handler_t exception_port,thread_t thread,task_t task,exception_type_t exception,const mach_exception_data_type_t * code,mach_msg_type_number_t code_count,thread_state_flavor_t * flavor,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count,const mach_msg_trailer_t * trailer,bool * destroy_complex_request)612 kern_return_t CatchException(exception_behavior_t behavior,
613 exception_handler_t exception_port,
614 thread_t thread,
615 task_t task,
616 exception_type_t exception,
617 const mach_exception_data_type_t* code,
618 mach_msg_type_number_t code_count,
619 thread_state_flavor_t* flavor,
620 ConstThreadState old_state,
621 mach_msg_type_number_t old_state_count,
622 thread_state_t new_state,
623 mach_msg_type_number_t* new_state_count,
624 const mach_msg_trailer_t* trailer,
625 bool* destroy_complex_request) {
626 return interface_->CatchMachException(behavior,
627 exception_port,
628 thread,
629 task,
630 exception,
631 code_count ? code : nullptr,
632 code_count,
633 flavor,
634 old_state_count ? old_state : nullptr,
635 old_state_count,
636 new_state_count ? new_state : nullptr,
637 new_state_count,
638 trailer,
639 destroy_complex_request);
640 }
641
642 private:
643 SimplifiedExcServer<ExcTraits> exc_server_;
644 SimplifiedExcServer<MachExcTraits> mach_exc_server_;
645 UniversalMachExcServer::Interface* interface_; // weak
646
647 DISALLOW_COPY_AND_ASSIGN(UniversalMachExcServerImpl);
648 };
649
650 } // namespace internal
651
UniversalMachExcServer(UniversalMachExcServer::Interface * interface)652 UniversalMachExcServer::UniversalMachExcServer(
653 UniversalMachExcServer::Interface* interface)
654 : MachMessageServer::Interface(),
655 impl_(new internal::UniversalMachExcServerImpl(interface)) {
656 }
657
~UniversalMachExcServer()658 UniversalMachExcServer::~UniversalMachExcServer() {
659 }
660
MachMessageServerFunction(const mach_msg_header_t * in_header,mach_msg_header_t * out_header,bool * destroy_complex_request)661 bool UniversalMachExcServer::MachMessageServerFunction(
662 const mach_msg_header_t* in_header,
663 mach_msg_header_t* out_header,
664 bool* destroy_complex_request) {
665 return impl_->MachMessageServerFunction(
666 in_header, out_header, destroy_complex_request);
667 }
668
MachMessageServerRequestIDs()669 std::set<mach_msg_id_t> UniversalMachExcServer::MachMessageServerRequestIDs() {
670 return impl_->MachMessageServerRequestIDs();
671 }
672
MachMessageServerRequestSize()673 mach_msg_size_t UniversalMachExcServer::MachMessageServerRequestSize() {
674 return impl_->MachMessageServerRequestSize();
675 }
676
MachMessageServerReplySize()677 mach_msg_size_t UniversalMachExcServer::MachMessageServerReplySize() {
678 return impl_->MachMessageServerReplySize();
679 }
680
ExcServerSuccessfulReturnValue(exception_type_t exception,exception_behavior_t behavior,bool set_thread_state)681 kern_return_t ExcServerSuccessfulReturnValue(exception_type_t exception,
682 exception_behavior_t behavior,
683 bool set_thread_state) {
684 if (exception == EXC_CRASH
685 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11
686 && MacOSXMinorVersion() >= 11
687 #endif
688 ) {
689 return KERN_SUCCESS;
690 }
691
692 if (!set_thread_state && ExceptionBehaviorHasState(behavior)) {
693 return MACH_RCV_PORT_DIED;
694 }
695
696 return KERN_SUCCESS;
697 }
698
ExcServerCopyState(exception_behavior_t behavior,ConstThreadState old_state,mach_msg_type_number_t old_state_count,thread_state_t new_state,mach_msg_type_number_t * new_state_count)699 void ExcServerCopyState(exception_behavior_t behavior,
700 ConstThreadState old_state,
701 mach_msg_type_number_t old_state_count,
702 thread_state_t new_state,
703 mach_msg_type_number_t* new_state_count) {
704 if (ExceptionBehaviorHasState(behavior)) {
705 *new_state_count = std::min(old_state_count, *new_state_count);
706 memcpy(new_state, old_state, *new_state_count * sizeof(old_state[0]));
707 }
708 }
709
710 } // namespace crashpad
711