1use once_cell::unsync::OnceCell;
2use vmi_core::{
3 Architecture, Pa, Va, VmiDriver, VmiError, VmiOs, VmiState, VmiVa,
4 os::{ProcessId, ProcessObject, VmiOsImageArchitecture, VmiOsProcess},
5};
6
7use super::{LinuxFsStruct, LinuxMmStruct, LinuxPath, LinuxVmAreaStruct, macros::impl_offsets};
8use crate::{ArchAdapter, LinuxError, LinuxOs};
9
10pub struct LinuxTaskStruct<'a, Driver>
19where
20 Driver: VmiDriver,
21 Driver::Architecture: Architecture + ArchAdapter<Driver>,
22{
23 vmi: VmiState<'a, Driver, LinuxOs<Driver>>,
25
26 va: Va,
28
29 flags: OnceCell<u32>,
31}
32
33impl<Driver> VmiVa for LinuxTaskStruct<'_, Driver>
34where
35 Driver: VmiDriver,
36 Driver::Architecture: Architecture + ArchAdapter<Driver>,
37{
38 fn va(&self) -> Va {
39 self.va
40 }
41}
42
43impl<'a, Driver> LinuxTaskStruct<'a, Driver>
44where
45 Driver: VmiDriver,
46 Driver::Architecture: Architecture + ArchAdapter<Driver>,
47{
48 impl_offsets!();
49
50 pub fn new(vmi: VmiState<'a, Driver, LinuxOs<Driver>>, process: ProcessObject) -> Self {
52 Self {
53 vmi,
54 va: process.0,
55 flags: OnceCell::new(),
56 }
57 }
58
59 pub fn flags(&self) -> Result<u32, VmiError> {
68 self.flags
69 .get_or_try_init(|| {
70 let offsets = self.offsets();
71 let __task_struct = &offsets.task_struct;
72
73 self.vmi.read_u32(self.va + __task_struct.flags.offset())
74 })
75 .copied()
76 }
77
78 pub fn mm(&self) -> Result<Option<LinuxMmStruct<'a, Driver>>, VmiError> {
87 let offsets = self.offsets();
88 let __task_struct = &offsets.task_struct;
89
90 let mm = self
91 .vmi
92 .read_va_native(self.va + __task_struct.mm.offset())?;
93
94 if mm.is_null() {
95 return Ok(None);
96 }
97
98 Ok(Some(LinuxMmStruct::new(self.vmi, mm)))
99 }
100
101 pub fn active_mm(&self) -> Result<LinuxMmStruct<'a, Driver>, VmiError> {
118 let offsets = self.offsets();
119 let __task_struct = &offsets.task_struct;
120
121 let mm = self
122 .vmi
123 .read_va_native(self.va + __task_struct.active_mm.offset())?;
124
125 if mm.is_null() {
126 return Err(LinuxError::CorruptedStruct("task_struct->active_mm").into());
127 }
128
129 Ok(LinuxMmStruct::new(self.vmi, mm))
130 }
131
132 pub fn fs(&self) -> Result<Option<LinuxFsStruct<'a, Driver>>, VmiError> {
150 let offsets = self.offsets();
151 let __task_struct = &offsets.task_struct;
152 let __fs_struct = &offsets.fs_struct;
153
154 let fs = self
155 .vmi
156 .read_va_native(self.va + __task_struct.fs.offset())?;
157
158 if fs.is_null() {
159 return Ok(None);
160 }
161
162 Ok(Some(LinuxFsStruct::new(self.vmi, fs)))
163 }
164
165 pub fn d_path(&self, path: &LinuxPath<Driver>) -> Result<Option<String>, VmiError> {
178 let root = match self.fs()? {
179 Some(root) => root.root()?,
180 None => return Ok(None),
181 };
182
183 Ok(Some(LinuxOs::<Driver>::construct_path(
184 self.vmi, path, &root,
185 )?))
186 }
187
188 pub fn image_path(&self) -> Result<Option<String>, VmiError> {
197 let flags = self.flags()?;
198
199 const PF_EXITING: u32 = 0x00000004; const PF_KTHREAD: u32 = 0x00200000; if flags & PF_KTHREAD != 0 {
203 return Ok(None);
204 }
205
206 if flags & PF_EXITING != 0 {
207 return Ok(None);
208 }
209
210 let mm = match self.mm()? {
211 Some(mm) => mm,
212 None => return Ok(None),
213 };
214
215 let exe_file = match mm.exe_file()? {
216 Some(exe_file) => exe_file,
217 None => return Ok(None),
218 };
219
220 self.d_path(&exe_file.path()?)
221 }
222}
223
224impl<'a, Driver> VmiOsProcess<'a, Driver> for LinuxTaskStruct<'a, Driver>
225where
226 Driver: VmiDriver,
227 Driver::Architecture: Architecture + ArchAdapter<Driver>,
228{
229 type Os = LinuxOs<Driver>;
230
231 fn id(&self) -> Result<ProcessId, VmiError> {
232 let offsets = self.offsets();
233 let __task_struct = &offsets.task_struct;
234
235 let result = self.vmi.read_u32(self.va + __task_struct.tgid.offset())?;
236
237 Ok(ProcessId(result))
238 }
239
240 fn object(&self) -> Result<ProcessObject, VmiError> {
241 Ok(ProcessObject(self.va))
242 }
243
244 fn name(&self) -> Result<String, VmiError> {
245 let task_struct_comm_offset = 0xBC0;
246
247 self.vmi.read_string(self.va + task_struct_comm_offset)
248 }
249
250 fn parent_id(&self) -> Result<ProcessId, VmiError> {
251 unimplemented!()
252 }
253
254 fn architecture(&self) -> Result<VmiOsImageArchitecture, VmiError> {
255 unimplemented!()
256 }
257
258 fn translation_root(&self) -> Result<Pa, VmiError> {
259 unimplemented!()
260 }
261
262 fn user_translation_root(&self) -> Result<Pa, VmiError> {
263 unimplemented!()
264 }
265
266 fn image_base(&self) -> Result<Va, VmiError> {
267 unimplemented!()
268 }
269
270 fn regions(
271 &self,
272 ) -> Result<
273 impl Iterator<Item = Result<<Self::Os as VmiOs<Driver>>::Region<'a>, VmiError>>,
274 VmiError,
275 > {
276 let mut result = Vec::new();
277
278 let mm = match self.mm()? {
279 Some(mm) => mm,
280 None => return Ok(result.into_iter()),
281 };
282
283 let mt = mm.mm_mt()?;
284 mt.enumerate(|node| {
285 println!("XXXNode: {}", node);
286 if !node.is_null() {
287 result.push(Ok(LinuxVmAreaStruct::new(self.vmi, node)));
288 }
289 true
290 })?;
291
292 Ok(result.into_iter())
293 }
294
295 fn find_region(
296 &self,
297 _address: Va,
298 ) -> Result<Option<<Self::Os as VmiOs<Driver>>::Region<'a>>, VmiError> {
299 unimplemented!()
300 }
301
302 fn threads(
303 &self,
304 ) -> Result<
305 impl Iterator<Item = Result<<Self::Os as VmiOs<Driver>>::Thread<'a>, VmiError>>,
306 VmiError,
307 > {
308 #[expect(unreachable_code)]
309 {
310 unimplemented!() as Result<std::iter::Empty<_>, VmiError>
311 }
312 }
313
314 fn is_valid_address(&self, _address: Va) -> Result<Option<bool>, VmiError> {
315 unimplemented!()
316 }
317}