minidump_writer/linux/thread_info/
mod.rs1use {
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}