gdb_command/
mappings.rs

1//! The `MappedFiles` struct holds information about all mapped files in process.
2use std::fmt;
3
4use crate::error;
5
6/// `File` struct represents unit (segment) in proccess address space.
7#[derive(Clone, Default, Debug)]
8pub struct File {
9    /// Start address of objfile
10    pub start: u64,
11    /// End address of objfile
12    pub end: u64,
13    /// Offset in file.
14    pub offset: u64,
15    /// Full path to binary module.
16    pub name: String,
17}
18
19impl File {
20    /// Constructs Mapped file from components.
21    ///
22    /// # Arguments
23    ///
24    /// * `start` - linear address of module load.
25    ///
26    /// * `end` - linear address of module end.
27    ///
28    /// * `offset` - offset in file.
29    ///
30    ///* `fname` - full path to binary module.
31    pub fn new(start: u64, end: u64, offset: u64, fname: &str) -> Self {
32        File {
33            start,
34            end,
35            offset,
36            name: String::from(fname),
37        }
38    }
39}
40
41impl fmt::Display for File {
42    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43        write!(
44            f,
45            "File {{ Start: 0x{:x}, End: 0x{:x}, offset: 0x{:x}, path: {} }}",
46            self.start, self.end, self.offset, self.name
47        )
48    }
49}
50
51/// `MappedFiles` all mapped files in process.
52pub type MappedFiles = Vec<File>;
53
54pub trait MappedFilesExt {
55    /// Construct `MappedFiels` from string
56    ///
57    /// # Arguments
58    ///
59    /// * 'mapping' - gdb output string with mapped files
60    fn from_gdb<T: AsRef<str>>(mapping: T) -> error::Result<MappedFiles>;
61
62    /// Determine which file contains the address
63    ///
64    /// # Arguments
65    ///
66    /// * 'addr' - given address
67    fn find(&self, addr: u64) -> Option<File>;
68}
69
70impl MappedFilesExt for MappedFiles {
71    fn from_gdb<T: AsRef<str>>(mapping: T) -> error::Result<MappedFiles> {
72        let mut hlp = mapping
73            .as_ref()
74            .lines()
75            .map(|s| s.trim().to_string())
76            .collect::<Vec<String>>();
77
78        if let Some(pos) = hlp.iter().position(|x| x.contains("Start Addr")) {
79            hlp.drain(0..pos + 1);
80        }
81
82        // Split mapped files info in columns.
83        let mut info = Vec::new();
84        let mut name_idx = 0;
85        for x in hlp.iter() {
86            let filevec = x
87                .split_whitespace()
88                .map(|s| s.trim().to_string())
89                .filter(|s| !s.is_empty())
90                .collect::<Vec<String>>();
91            if filevec.len() < 4 {
92                return Err(error::Error::MappedFilesParse(format!(
93                    "Expected at least 4 columns in {x}"
94                )));
95            }
96
97            // Get index for module name. Different gdb versions have varying
98            // number of fields.
99            name_idx = name_idx.max(filevec.len() - 1);
100
101            info.push(filevec);
102        }
103
104        let mut files = MappedFiles::new();
105
106        // Parse and collect mapped files info.
107        for x in info.iter() {
108            let f = File {
109                start: u64::from_str_radix(x[0].get(2..).unwrap_or(&x[0]), 16)?,
110                end: u64::from_str_radix(x[1].get(2..).unwrap_or(&x[1]), 16)?,
111                offset: u64::from_str_radix(x[3].get(2..).unwrap_or(&x[3]), 16)?,
112                name: x.get(name_idx).unwrap_or(&String::new()).clone(),
113            };
114            files.push(f);
115        }
116
117        Ok(files)
118    }
119
120    fn find(&self, addr: u64) -> Option<File> {
121        self.iter()
122            .find(|&x| (x.start <= addr) && (x.end > addr))
123            .cloned()
124    }
125}