1 // Copyright 2017 The Fuchsia Authors 2 // 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file or at 5 // https://opensource.org/licenses/MIT 6 7 #pragma once 8 9 #include <stdint.h> 10 11 #include <arch/exception.h> 12 #include <kernel/lockdep.h> 13 #include <kernel/mutex.h> 14 #include <object/dispatcher.h> 15 16 #include <zircon/syscalls/exception.h> 17 #include <zircon/syscalls/port.h> 18 #include <zircon/types.h> 19 #include <fbl/canary.h> 20 #include <fbl/intrusive_double_list.h> 21 #include <fbl/mutex.h> 22 #include <fbl/ref_counted.h> 23 #include <fbl/ref_ptr.h> 24 25 class ThreadDispatcher; 26 class ProcessDispatcher; 27 class PortDispatcher; 28 29 // Represents the binding of an exception port to a specific target 30 // (job/process/thread). Multiple ExceptionPorts may exist for a 31 // single underlying PortDispatcher. 32 class ExceptionPort : public fbl::DoublyLinkedListable<fbl::RefPtr<ExceptionPort>> 33 , public fbl::RefCounted<ExceptionPort> { 34 public: 35 enum class Type { NONE, JOB_DEBUGGER, DEBUGGER, THREAD, PROCESS, JOB}; 36 37 static zx_status_t Create(Type type, fbl::RefPtr<PortDispatcher> port, 38 uint64_t port_key, 39 fbl::RefPtr<ExceptionPort>* eport); 40 ~ExceptionPort(); 41 type()42 Type type() const { return type_; } 43 44 zx_status_t SendPacket(ThreadDispatcher* thread, uint32_t type); 45 46 void OnThreadStartForDebugger(ThreadDispatcher* thread); 47 void OnThreadExitForDebugger(ThreadDispatcher* thread); 48 void OnProcessStartForDebugger(ThreadDispatcher* thread); 49 50 // Records the target that the ExceptionPort is bound to, so it can 51 // unbind when the underlying PortDispatcher dies. 52 void SetTarget(const fbl::RefPtr<JobDispatcher>& target); 53 void SetTarget(const fbl::RefPtr<ProcessDispatcher>& target); 54 void SetTarget(const fbl::RefPtr<ThreadDispatcher>& target); 55 56 // Drops the ExceptionPort's references to its target and PortDispatcher. 57 // Called by the target when the port is explicitly unbound. 58 void OnTargetUnbind(); 59 60 // Validates that this eport is associated with the given instance. 61 bool PortMatches(const PortDispatcher* port, bool allow_null); 62 63 static void BuildArchReport(zx_exception_report_t* report, uint32_t type, 64 const arch_exception_context_t* arch_context); 65 66 private: 67 friend class PortDispatcher; 68 69 ExceptionPort(Type type, fbl::RefPtr<PortDispatcher> port, uint64_t port_key); 70 71 ExceptionPort(const ExceptionPort&) = delete; 72 ExceptionPort& operator=(const ExceptionPort&) = delete; 73 74 zx_status_t SendPacketWorker(uint32_t type, zx_koid_t pid, zx_koid_t tid); 75 76 // Unbinds from the target if bound, and drops the ref to |port_|. 77 // Called by |port_| when it reaches zero handles. 78 void OnPortZeroHandles(); 79 80 // Returns true if the ExceptionPort is currently bound to a target. IsBoundLocked()81 bool IsBoundLocked() const TA_REQ(lock_) { 82 return target_ != nullptr; 83 } 84 85 static void BuildReport(zx_exception_report_t* report, uint32_t type); 86 87 fbl::Canary<fbl::magic("EXCP")> canary_; 88 89 // These aren't locked as once the exception port is created these are 90 // immutable (the port itself has its own locking though). 91 const Type type_; 92 const uint64_t port_key_; 93 94 // The underlying port. If null, the ExceptionPort has been unbound. 95 fbl::RefPtr<PortDispatcher> port_ TA_GUARDED(lock_); 96 97 // The target of the exception port. 98 // The system exception port doesn't have a Dispatcher, hence the bool. 99 fbl::RefPtr<Dispatcher> target_ TA_GUARDED(lock_); 100 101 DECLARE_MUTEX(ExceptionPort) lock_; 102 103 // NOTE: The DoublyLinkedListNodeState is guarded by |port_|'s lock, 104 // and should only be touched using port_->LinkExceptionPort() 105 // or port_->UnlinkExceptionPort(). This goes for ::InContainer(), too. 106 }; 107