tracexec_core/event/parent.rs
1//! Code for locating the id of parent event of an event.
2
3use super::EventId;
4use std::fmt::Debug;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum ParentEvent<T> {
8 /// The parent process destroys itself and become a new process
9 Become(T),
10 /// The parent process spawns a new process.
11 Spawn(T),
12}
13
14impl From<ParentEvent<Self>> for EventId {
15 fn from(value: ParentEvent<Self>) -> Self {
16 match value {
17 ParentEvent::Become(event_id) | ParentEvent::Spawn(event_id) => event_id,
18 }
19 }
20}
21
22impl<T> ParentEvent<T> {
23 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> ParentEvent<U> {
24 match self {
25 Self::Become(v) => ParentEvent::Become(f(v)),
26 Self::Spawn(v) => ParentEvent::Spawn(f(v)),
27 }
28 }
29}
30
31impl<T> ParentEvent<Option<T>> {
32 pub fn transpose(self) -> Option<ParentEvent<T>> {
33 match self {
34 Self::Become(v) => v.map(ParentEvent::Become),
35 Self::Spawn(v) => v.map(ParentEvent::Spawn),
36 }
37 }
38}
39
40pub type ParentEventId = ParentEvent<EventId>;
41
42/// How this works
43///
44/// Consider the following two situations:
45///
46/// pid 2
47/// Proc A
48/// │ fork pid 3
49/// pid 2 ├────────►Proc A
50/// Proc C exec│ │ pid 3
51/// ┌───◄────┘ │exec Proc B
52/// │ * └───►────┐
53/// │********* │
54/// │ alt exec │
55/// C exec Proc D
56///
57/// We will derive the following relations:
58///
59/// Unknown ?> A
60/// |- A spawns B
61/// |- A becomes C
62/// |- C becomes D
63///
64/// To achieve this, we
65/// 1) for `spawns`(A spawns B), record the id of last exec event(Unknown ?> A) of the parent process(A) at fork time.
66/// 2) for `becomes`(C becomes D), record the id of last exec event(A becomes C)
67///
68/// If the process itself have successful execs, then the parent event is `last_successful_exec`
69/// Otherwise, the parent is the corresponding successful exec event of its parent process.
70#[derive(Debug, Clone, Default)]
71pub struct ParentTracker {
72 /// The parent event recorded at fork time,
73 parent_last_exec: Option<EventId>,
74 /// The last exec event of this process
75 last_successful_exec: Option<EventId>,
76}
77
78impl ParentTracker {
79 pub fn new() -> Self {
80 Default::default()
81 }
82
83 pub fn save_parent_last_exec(&mut self, parent: &Self) {
84 self.parent_last_exec = parent.last_successful_exec.or(parent.parent_last_exec);
85 }
86
87 /// Updates parent tracker with an exec event
88 /// and returns the parent event id of this exec event
89 pub fn update_last_exec(&mut self, id: EventId, successful: bool) -> Option<ParentEventId> {
90 let has_successful_exec = self.last_successful_exec.is_some();
91 let old_last_exec = if successful {
92 self.last_successful_exec.replace(id)
93 } else {
94 self.last_successful_exec
95 };
96 // If a process has successful exec events, the parent should be the last successful exec,
97 // other wise it should point to the parent exec event
98 if has_successful_exec {
99 // This is at least the second time of exec for this process
100 old_last_exec.map(ParentEvent::Become)
101 } else {
102 self.parent_last_exec.map(ParentEvent::Spawn)
103 }
104 }
105}