Skip to main content

minidump_writer/linux/thread_info/
mod.rs

1use {
2    super::{
3        Pid,
4        process_inspection::{self, ProcessInspector, regs},
5    },
6    crate::serializers::*,
7    std::{
8        io::{self, BufRead},
9        path,
10    },
11};
12
13type Result<T> = std::result::Result<T, ThreadInfoError>;
14
15#[derive(thiserror::Error, Debug, serde::Serialize)]
16pub enum ThreadInfoError {
17    #[error("Index out of bounds: Got {0}, only have {1}")]
18    IndexOutOfBounds(usize, usize),
19    #[error("Either ppid ({1}) or tgid ({2}) not found in {0}")]
20    InvalidPid(String, Pid, Pid),
21    #[error("failed reading /proc/<tid>/status")]
22    ReadFileFailed(#[source] process_inspection::Error),
23    #[error("IO error")]
24    IOError(
25        #[from]
26        #[serde(serialize_with = "serialize_io_error")]
27        std::io::Error,
28    ),
29    #[error("Couldn't parse address")]
30    UnparsableInteger(
31        #[from]
32        #[serde(skip)]
33        std::num::ParseIntError,
34    ),
35    #[error("ptrace error")]
36    PtraceError(#[source] process_inspection::Error),
37    #[error("Invalid line in /proc/{0}/status: {1}")]
38    InvalidProcStatusFile(Pid, String),
39}
40
41cfg_if::cfg_if! {
42    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
43        mod x86;
44        pub type ThreadInfo = x86::ThreadInfoX86;
45
46        #[cfg(target_arch = "x86_64")]
47        pub use x86::copy_u32_registers;
48    } else if #[cfg(target_arch = "arm")] {
49        mod arm;
50        pub type ThreadInfo = arm::ThreadInfoArm;
51    } else if #[cfg(target_arch = "aarch64")] {
52        mod aarch64;
53        pub type ThreadInfo = aarch64::ThreadInfoAarch64;
54    }
55}
56
57fn get_ppid_and_tgid(process_inspector: &ProcessInspector, tid: Pid) -> Result<(Pid, Pid)> {
58    let mut ppid = -1;
59    let mut tgid = -1;
60
61    let status_path = path::PathBuf::from(format!("/proc/{tid}/status"));
62    let status_file = process_inspector
63        .read_file(status_path)
64        .map_err(ThreadInfoError::ReadFileFailed)?;
65    for line in io::BufReader::new(status_file).lines() {
66        let l = line?;
67        let start = l
68            .get(0..6)
69            .ok_or_else(|| ThreadInfoError::InvalidProcStatusFile(tid, l.clone()))?;
70        match start {
71            "Tgid:\t" => {
72                tgid = l
73                    .get(6..)
74                    .ok_or_else(|| ThreadInfoError::InvalidProcStatusFile(tid, l.clone()))?
75                    .parse::<Pid>()?;
76            }
77            "PPid:\t" => {
78                ppid = l
79                    .get(6..)
80                    .ok_or_else(|| ThreadInfoError::InvalidProcStatusFile(tid, l.clone()))?
81                    .parse::<Pid>()?;
82            }
83            _ => continue,
84        }
85    }
86    if ppid == -1 || tgid == -1 {
87        return Err(ThreadInfoError::InvalidPid(
88            format!("/proc/{tid}/status"),
89            ppid,
90            tgid,
91        ));
92    }
93    Ok((ppid, tgid))
94}