]> git.saurik.com Git - apple/system_cmds.git/blob - KDBG/MachineProcess.hpp
system_cmds-671.10.3.tar.gz
[apple/system_cmds.git] / KDBG / MachineProcess.hpp
1 //
2 // MachineProcess.hpp
3 // KDBG
4 //
5 // Created by James McIlree on 10/26/12.
6 // Copyright (c) 2014 Apple. All rights reserved.
7 //
8
9 //
10 // Process life cycle
11 //
12 // There are four ways a process can be created:
13 //
14 // 1) CreatedByPreviousMachineState
15 //
16 // It is a carryover from a previous Machine state. This happens when a
17 // live trace creates a machine state that is a union of a previous state
18 // and new event data.
19 //
20 // 2) CreatedByThreadMap
21 //
22 // It is a process that was running at the time the trace events were
23 // taken. The kernel provides this data.
24 //
25 // 3) CreatedByExecEvent
26 //
27 // It is a process that "reused" an existing pid, and exec'd a new process
28 // in place. The Machine State will completely close down the old process
29 // and create a new one to track data for the newly exec'd process.
30 //
31 // 4) CreatedByForkExecEvent
32 //
33 // An existing process "forked", creating a new pid, and then "exec'd".
34 // This is seen in trace events as a TRACE_DATA_NEWTHREAD with a pid that
35 // does not match the callers pid.
36 //
37 // There are also two catch-all processes, "Unknown", and "Kernel". The kernel
38 // process contains all kernel only threads, and unknown contains threads that
39 // are encountered without any previous identifying information.
40 //
41
42 enum class kMachineProcessFlag : std::uint32_t {
43 CreatedByPreviousMachineState = 0x00000001,
44 CreatedByThreadMap = 0x00000002,
45 CreatedByForkExecEvent = 0x00000004,
46 CreatedByExecEvent = 0x00000008,
47 IsForkExecInProgress = 0x00000010,
48 IsExecInProgress = 0x00000020,
49 IsUnknownProcess = 0x00000040,
50 IsKernelProcess = 0x00000080,
51 IsExitBySyscall = 0x00000100,
52 IsExitByJetsam = 0x00000400,
53 IsExitByExec = 0x00000800,
54 IsTraceTerminated = 0x00001000
55 };
56
57 template <typename SIZE> class Machine;
58
59 template <typename SIZE>
60 class MachineProcess {
61 protected:
62 pid_t _pid;
63 char _name[20]; // Actual limit is 16, we round up for NULL terminator
64 AbsInterval _timespan; // This is set at trace termination, or in post_initialize if still live.
65 AbsTime _exit_initiated_timestamp;
66 std::vector<MachineThread<SIZE>*> _threads_by_time;
67 uint32_t _flags;
68 int32_t _exit_status;
69 int32_t _apptype; // Unset == -1
70
71 //
72 // Mutable API
73 //
74
75 friend class Machine<SIZE>;
76
77 void set_flags(kMachineProcessFlag flags) { _flags |= (uint32_t)flags; }
78 void clear_flags(kMachineProcessFlag flags) { _flags &= ~(uint32_t)flags; }
79 bool is_flag_set(kMachineProcessFlag flag) const { return (_flags & (uint32_t)flag) > 0; }
80
81 //
82 // Process exit lifecycle
83 //
84 // Processes start to exit / terminate when one of the following happens:
85 //
86 // syscall to proc exit
87 // jetsam causes a SIGKILL
88 // syscall to exec
89 //
90 // It may be that more than one of these events happen. For example, jetsam
91 // may cause a process to die via a SIGKILL.
92 //
93 // For the purposes of this API, only the first method of initiating exit
94 // is recorded. This includes the timestamp; if you ask for the exit timestamp
95 // you will get the timestamp for the first invocation of any of the exit
96 // paths.
97 //
98 // Once a process starts terminating, it will eventually reach the point
99 // where no futher events will ever be seen for that process. When the
100 // last thread in the process is marked as trace terminated, the process
101 // is marked as trace terminated.
102 //
103 // The definitive test for a process being entirely done is trace termination.
104 //
105
106 //
107 // The exit code and conditions are a bit of a mess.
108 // All processes exit. This is triggered by the BSD_PROC_EXIT
109 // tracepoint. Some processes chose to exit, some are forced to
110 // exit by signals (SIGKILL, for example). Some processes are
111 // forced to exit by a mechanism that appears to be a signal but
112 // we want to track them separately (jetsam).
113 //
114 // The upshot of this is the exit code is stored in waitpid
115 // style. See waitpid(2) for the macros used to decode this.
116 //
117 void set_exit_by_syscall(AbsTime timestamp, int exit_status);
118 void set_exit_by_jetsam(AbsTime timestamp);
119 void set_exit_by_exec(AbsTime timestamp);
120 void set_trace_terminated(AbsTime timestamp); // Also sets last timestamp
121
122 void set_apptype(uint32_t apptype);
123 void set_apptype_from_trequested(uint32_t apptype);
124 void set_name(const char* name);
125
126 void add_thread(MachineThread<SIZE>* thread);
127
128 bool is_exec_in_progress() const { return (_flags & (uint32_t)kMachineProcessFlag::IsExecInProgress) > 0; }
129 bool is_fork_exec_in_progress() const { return (_flags & (uint32_t)kMachineProcessFlag::IsForkExecInProgress) > 0; }
130
131 void clear_fork_exec_in_progress();
132 void clear_exec_in_progress();
133
134 // This is called after all events have been processed, to allow the
135 // threads to be sorted.
136 void post_initialize(AbsTime last_machine_timestamp);
137
138 public:
139 MachineProcess(pid_t pid,
140 const char* name,
141 AbsTime create_timestamp,
142 kMachineProcessFlag flags);
143
144 pid_t pid() const { return _pid; }
145 const char* name() const { return _name; }
146 AbsInterval timespan() const { return _timespan; }
147 AbsTime exit_timestamp() const { return _exit_initiated_timestamp; }
148 int32_t exit_status() const { return _exit_status; }
149 int32_t apptype() const { return _apptype; }
150
151 uint32_t flags() const { return _flags; }
152
153 const std::vector<const MachineThread<SIZE>*>& threads() const { return *reinterpret_cast<const std::vector<const MachineThread<SIZE>*>*>(&_threads_by_time); }
154
155 bool is_exit_by_syscall() const { return is_flag_set(kMachineProcessFlag::IsExitBySyscall); }
156 bool is_exit_by_jetsam() const { return is_flag_set(kMachineProcessFlag::IsExitByJetsam); }
157 bool is_exit_by_exec() const { return is_flag_set(kMachineProcessFlag::IsExitByExec); }
158
159 // The invariant is that trace_terminated may not be set without is_exiting() set
160 bool is_exiting() const { return is_exit_by_syscall() || is_exit_by_jetsam() || is_exit_by_exec(); }
161 bool is_trace_terminated() const { return is_flag_set(kMachineProcessFlag::IsTraceTerminated); }
162
163 bool is_unknown() const { return is_flag_set(kMachineProcessFlag::IsUnknownProcess); }
164 bool is_kernel() const { return is_flag_set(kMachineProcessFlag::IsKernelProcess); }
165
166 bool is_created_by_previous_machine_state() const { return is_flag_set(kMachineProcessFlag::CreatedByPreviousMachineState); }
167 bool is_created_by_thread_map() const { return is_flag_set(kMachineProcessFlag::CreatedByThreadMap); }
168 bool is_created_by_fork_exec() const { return is_flag_set(kMachineProcessFlag::CreatedByForkExecEvent); }
169 bool is_created_by_exec() const { return is_flag_set(kMachineProcessFlag::CreatedByExecEvent); }
170
171 DEBUG_ONLY(void validate() const;)
172 };
173