X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/1a7e3f61d38d679bba59130891c2031b5a0092b6..bd6521f0fc816ab056bc71376f9706a69b3b52c1:/KDBG/Machine.hpp diff --git a/KDBG/Machine.hpp b/KDBG/Machine.hpp new file mode 100644 index 0000000..48586f5 --- /dev/null +++ b/KDBG/Machine.hpp @@ -0,0 +1,143 @@ +// +// Machine.hpp +// KDBG +// +// Created by James McIlree on 10/25/12. +// Copyright (c) 2014 Apple. All rights reserved. +// + +enum class kMachineFlag : std::uint32_t { + LostEvents = 0x00000001 +}; + +template +class Machine { + protected: + std::vector> _cpus; + + std::unordered_multimap> _processes_by_pid; + std::unordered_multimap*, ConstCharHash, ConstCharEqualTo> _processes_by_name; + std::vector*> _processes_by_time; + + std::unordered_multimap > _threads_by_tid; + std::vector*> _threads_by_time; + + std::vector> _mach_msgs; + std::unordered_map _mach_msgs_by_event_index; + std::unordered_map> _mach_msg_nursery; + + // + // Vouchers are a bit special. We install pointers to vouchers in + // MachineThreads and MachineMachMsg. This means that vouchers cannot + // be moved once allocated. We could do two passes to exactly size + // the data structures, this should be investigated in the future. + // + // On create or first observed use, a voucher goes into the nursery. + // It stays there until a destroy event, or the end of Machine events. + // Once flushed from the nursery, we have a map of addresses, which + // points to a vector sorted by time. This allows addr @ time lookups + // later. + // + std::unordered_map>> _voucher_nursery; + std::unordered_map>>> _vouchers_by_addr; + + std::unordered_map> _io_by_uid; // uid == unique id, not user id + std::vector> _all_io; + std::vector _all_io_active_intervals; + + MachineProcess* _kernel_task; + const KDEvent* _events; + uintptr_t _event_count; + uint32_t _flags; + int32_t _unknown_process_pid; // We need unique negative pid's for previously unknown TID's + + // + // Protected initialization code + // + void raw_initialize(const KDCPUMapEntry* cpumaps, + uint32_t cpumap_count, + const KDThreadMapEntry* threadmaps, + uint32_t threadmap_count, + const KDEvent* events, + uintptr_t event_count); + + void post_initialize(); + + // + // Mutable API, for use during construction + // + + pid_t next_unknown_pid() { return --_unknown_process_pid; } + + MachineProcess* create_process(pid_t pid, const char* name, AbsTime create_timestamp, kMachineProcessFlag flags); + MachineThread* create_thread(MachineProcess* process, typename SIZE::ptr_t tid, MachineVoucher* voucher, AbsTime create_timestamp, kMachineThreadFlag flags); + MachineVoucher* create_voucher(typename SIZE::ptr_t address, AbsTime create_timestamp, kMachineVoucherFlag flags, uint32_t content_bytes_capacity); + + void destroy_voucher(typename SIZE::ptr_t address, AbsTime timestamp); + + void set_flags(kMachineFlag flag) { _flags |= (uint32_t)flag; } + + void set_process_name(MachineProcess* process, const char* name); + + MachineProcess* mutable_process(pid_t pid, AbsTime time) { return const_cast*>(process(pid, time)); } + MachineThread* mutable_thread(typename SIZE::ptr_t tid, AbsTime time) { return const_cast*>(thread(tid, time)); } + + MachineProcess* youngest_mutable_process(pid_t pid); + MachineThread* youngest_mutable_thread(typename SIZE::ptr_t tid); + + MachineVoucher* process_event_voucher_lookup(typename SIZE::ptr_t address, uint32_t msgh_bits); + MachineThread* process_event_tid_lookup(typename SIZE::ptr_t tid, AbsTime now); + + MachineVoucher* thread_forwarding_voucher_lookup(const MachineVoucher* original_thread_voucher); + + void begin_io(MachineThread* thread, AbsTime time, typename SIZE::ptr_t uid, typename SIZE::ptr_t size); + void end_io(AbsTime time, typename SIZE::ptr_t uid); + + bool process_event(const KDEvent& event); + void process_trequested_task(pid_t pid, typename SIZE::ptr_t trequested_0, typename SIZE::ptr_t trequested_1); + void process_trequested_thread(typename SIZE::ptr_t tid, typename SIZE::ptr_t trequested_0, typename SIZE::ptr_t trequested_1); + + void initialize_cpu_idle_intr_states(); + + public: + static MachineVoucher UnsetVoucher; + static MachineVoucher NullVoucher; + + Machine(KDCPUMapEntry* cpumaps, uint32_t cpumap_count, KDThreadMapEntry* threadmaps, uint32_t threadmap_count, KDEvent* events, uintptr_t event_count); + // Destructive, mutates parent! + Machine(Machine& parent, KDEvent* events, uintptr_t event_count); + Machine(const TraceFile& file); + + bool lost_events() const { return (_flags & (uint32_t)kMachineFlag::LostEvents) > 0; } + + const MachineProcess* process(pid_t pid, AbsTime time) const; + const MachineThread* thread(typename SIZE::ptr_t tid, AbsTime time) const; + const MachineVoucher* voucher(typename SIZE::ptr_t address, AbsTime time) const; + const MachineMachMsg* mach_msg(uintptr_t event_index) const; + + const std::vector*>& processes() const; + const std::vector*>& threads() const; + const std::vector>& cpus() const; + + const KDEvent* events() const { return _events; } + uintptr_t event_count() const { return _event_count; } + + AbsInterval timespan() const; + + // Returns the number of cpus that have timeline data. + // (IOW, typically the number of AP(s) on a machine, but might be less if you've disabled some so they generate no trace data) + uint32_t active_cpus() const; + + // If summary_cpu == NULL , all cpus are matched. + CPUSummary summary_for_timespan(AbsInterval timespan, const MachineCPU* summary_cpu) const; + + // This attempts to analyze various pieces of data and guess + // if the Machine represents an ios device or not. + bool is_ios() const; + + DEBUG_ONLY(void validate() const;) +}; + +template MachineVoucher Machine::UnsetVoucher(SIZE::PTRMAX, AbsInterval(AbsTime(0),AbsTime(UINT64_MAX)), kMachineVoucherFlag::IsUnsetVoucher, 0); +template MachineVoucher Machine::NullVoucher(0, AbsInterval(AbsTime(0),AbsTime(UINT64_MAX)), kMachineVoucherFlag::IsNullVoucher, 0); +