rbspy_testdata/
lib.rs

1//! Data for use in rbspy tests and benchmarks :-)
2
3use std::fs::File;
4use std::io::{self, BufReader, Read};
5use std::path::Path;
6
7use anyhow::{Context, Result};
8use goblin::elf;
9use remoteprocess::{Error as ProcessError, ProcessMemory};
10
11use flate2::bufread::GzDecoder;
12
13/// Open data file `name`.
14fn data_file(name: &str) -> Result<File> {
15    let path = Path::new(env!("CARGO_MANIFEST_DIR"))
16        .join("data")
17        .join(name);
18
19    Ok(File::open(&path).context(format!("could not open data file `{}`", path.display()))?)
20}
21
22/// Get contents of gzipped data file `name`.
23fn data_file_gz_contents(name: &str) -> Result<Vec<u8>> {
24    let file = BufReader::new(data_file(&name)?);
25    let mut data = vec![];
26    GzDecoder::new(file)
27        .read_to_end(&mut data)
28        .context(format!("failed to read gzipped data file `{}`", name))?;
29    Ok(data)
30}
31
32/// Load coredump from gzipped data file `name`.
33fn load_coredump(name: &str) -> Result<CoreDump> {
34    CoreDump::new(data_file_gz_contents(name)?)
35}
36
37pub fn coredump_1_9_3() -> CoreDump {
38    load_coredump("ruby-coredump-1.9.3.gz").unwrap()
39}
40pub fn coredump_2_1_6() -> CoreDump {
41    load_coredump("ruby-coredump-2.1.6.gz").unwrap()
42}
43pub fn coredump_2_1_6_c_function() -> CoreDump {
44    load_coredump("ruby-coredump-2.1.6_c_function.gz").unwrap()
45}
46pub fn coredump_2_4_0() -> CoreDump {
47    load_coredump("ruby-coredump-2.4.0.gz").unwrap()
48}
49pub fn coredump_2_5_0() -> CoreDump {
50    load_coredump("ruby-coredump-2.5.0.gz").unwrap()
51}
52
53pub fn coredump_2_7_2() -> CoreDump {
54    load_coredump("ruby-coredump-2.7.2.gz").unwrap()
55}
56
57pub fn coredump_3_0_0() -> CoreDump {
58    load_coredump("ruby-coredump-3.0.0.gz").unwrap()
59}
60
61pub fn coredump_3_1_0() -> CoreDump {
62    load_coredump("ruby-coredump-3.1.0.gz").unwrap()
63}
64
65pub fn coredump_3_2_0() -> CoreDump {
66    load_coredump("ruby-coredump-3.2.0.gz").unwrap()
67}
68
69pub fn coredump_3_3_0() -> CoreDump {
70    load_coredump("ruby-coredump-3.3.0.gz").unwrap()
71}
72
73pub fn coredump_with_classes_3_3_0() -> CoreDump {
74    load_coredump("ruby-coredump-with-classes-3.3.0.gz").unwrap()
75}
76
77pub fn coredump_complex_3_4_5() -> CoreDump {
78    load_coredump("ruby-coredump-complex-3.4.5.gz").unwrap()
79}
80
81pub fn coredump_4_0_0() -> CoreDump {
82    load_coredump("ruby-coredump-4.0.0.gz").unwrap()
83}
84
85/// Allows testing offline with a core dump of a Ruby process.
86pub struct CoreDump {
87    raw_memory: Vec<u8>,
88    elf_section_headers: Vec<elf::SectionHeader>,
89}
90
91impl CoreDump {
92    pub fn new(raw_memory: Vec<u8>) -> Result<Self> {
93        let elf = elf::Elf::parse(&raw_memory).context("failed to parse ELF header")?;
94        let elf_section_headers = elf.section_headers;
95        Ok(CoreDump {
96            raw_memory,
97            elf_section_headers,
98        })
99    }
100}
101
102impl ProcessMemory for CoreDump {
103    fn read(&self, addr: usize, buf: &mut [u8]) -> Result<(), ProcessError> {
104        let start = addr as u64;
105        let end = (addr + buf.len()) as u64;
106        match self
107            .elf_section_headers
108            .iter()
109            .find(|section| section.sh_addr <= start && end <= section.sh_addr + section.sh_size)
110        {
111            Some(sec) => {
112                let start = sec.sh_offset as usize + addr - sec.sh_addr as usize;
113                let end = start + buf.len();
114                buf.copy_from_slice(&self.raw_memory[start..end]);
115                Ok(())
116            }
117            None => {
118                let io_error = io::Error::from_raw_os_error(libc::EFAULT);
119                Err(ProcessError::IOError(io_error))
120            }
121        }
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_load_coredump() {
131        let coredump = load_coredump("ruby-coredump-1.9.3.gz").unwrap();
132        assert_eq!(coredump.elf_section_headers.len(), 36);
133        let buf = &mut [0u8; 16];
134        coredump.read(0x823930, buf).expect("read failed");
135        assert_eq!(buf, &[32, 21, 73, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
136
137        let coredump = load_coredump("ruby-coredump-2.1.6.gz").unwrap();
138        assert_eq!(coredump.elf_section_headers.len(), 40);
139        let buf = &mut [0u8; 16];
140        coredump.read(0x562658abd7f0, buf).expect("read failed");
141        assert_eq!(
142            buf,
143            &[176, 165, 200, 89, 38, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
144        );
145
146        let coredump = load_coredump("ruby-coredump-2.1.6_c_function.gz").unwrap();
147        assert_eq!(coredump.elf_section_headers.len(), 102);
148        let buf = &mut [0u8; 16];
149        coredump.read(0x562efcd577f0, buf).expect("read failed");
150        assert_eq!(
151            buf,
152            &[176, 198, 255, 254, 46, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
153        );
154
155        let coredump = load_coredump("ruby-coredump-2.4.0.gz").unwrap();
156        assert_eq!(coredump.elf_section_headers.len(), 38);
157        let buf = &mut [0u8; 16];
158        coredump.read(0x55df44959920, buf).expect("read failed");
159        assert_eq!(
160            buf,
161            &[208, 165, 37, 70, 223, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
162        );
163
164        let coredump = load_coredump("ruby-coredump-2.5.0.gz").unwrap();
165        assert_eq!(coredump.elf_section_headers.len(), 38);
166        let buf = &mut [0u8; 16];
167        coredump.read(0x55dd8c3b7758, buf).expect("read failed");
168        assert_eq!(
169            buf,
170            &[216, 136, 151, 140, 221, 85, 0, 0, 32, 127, 151, 140, 221, 85, 0, 0]
171        );
172
173        let coredump = load_coredump("ruby-coredump-2.7.2.gz").unwrap();
174        assert_eq!(coredump.elf_section_headers.len(), 119);
175        let buf = &mut [0u8; 16];
176        coredump.read(0x7fdd8d626070, buf).expect("read failed");
177        assert_eq!(
178            buf,
179            &[208, 166, 207, 100, 196, 85, 0, 0, 160, 155, 207, 100, 196, 85, 0, 0]
180        );
181
182        let coredump = load_coredump("ruby-coredump-3.0.0.gz").unwrap();
183        assert_eq!(coredump.elf_section_headers.len(), 119);
184        let buf = &mut [0u8; 16];
185        coredump.read(0x7fdacdab7470, buf).expect("read failed");
186        assert_eq!(
187            buf,
188            &[160, 235, 191, 181, 200, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
189        );
190
191        let coredump = load_coredump("ruby-coredump-3.1.0.gz").unwrap();
192        assert_eq!(coredump.elf_section_headers.len(), 119);
193        let buf = &mut [0u8; 16];
194        coredump.read(0x7f0dc0c83c58, buf).expect("read failed");
195        assert_eq!(
196            buf,
197            &[64, 186, 97, 2, 255, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
198        );
199
200        let coredump = load_coredump("ruby-coredump-3.2.0.gz").unwrap();
201        assert_eq!(coredump.elf_section_headers.len(), 120);
202        let buf = &mut [0u8; 16];
203        coredump.read(0xffffb8034578, buf).expect("read failed");
204        assert_eq!(
205            buf,
206            &[208, 250, 146, 227, 170, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
207        );
208
209        let coredump = load_coredump("ruby-coredump-3.3.0.gz").unwrap();
210        assert_eq!(coredump.elf_section_headers.len(), 151);
211        let buf = &mut [0u8; 16];
212        coredump.read(0x7f43435f4988, buf).expect("read failed");
213        assert_eq!(
214            buf,
215            &[16, 51, 89, 134, 131, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
216        );
217
218        let coredump = load_coredump("ruby-coredump-with-classes-3.3.0.gz").unwrap();
219        assert_eq!(coredump.elf_section_headers.len(), 124);
220        let buf = &mut [0u8; 16];
221        coredump.read(0x7f58cb7f4988, buf).expect("read failed");
222        assert_eq!(
223            buf,
224            &[16, 115, 177, 241, 196, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
225        );
226
227        let coredump = load_coredump("ruby-coredump-complex-3.4.5.gz").unwrap();
228        assert_eq!(coredump.elf_section_headers.len(), 152);
229        let buf = &mut [0u8; 16];
230        coredump.read(0x7f271feb5390, buf).expect("read failed");
231        assert_eq!(
232            buf,
233            &[16, 19, 104, 91, 119, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
234        );
235
236        let coredump = load_coredump("ruby-coredump-4.0.0.gz").unwrap();
237        assert_eq!(coredump.elf_section_headers.len(), 93);
238        let buf = &mut [0u8; 16];
239        coredump.read(0x7fa56b875738, buf).expect("read failed");
240        assert_eq!(
241            buf,
242            &[16, 147, 75, 251, 241, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
243        );
244    }
245}