1#![allow(non_upper_case_globals)]
9#![allow(non_camel_case_types)]
10#![allow(non_snake_case)]
11
12include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
13
14pub use crate::native::*;
15
16#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
17#[cfg_attr(target_arch = "x86", path = "x86.rs")]
18#[cfg_attr(target_arch = "arm", path = "arm.rs")]
19mod native;
20
21#[cfg(test)]
22mod tests {
23 extern crate libc;
24
25 use crate::*;
26 use libc::c_char;
27 use std::ffi::CStr;
28 use std::ffi::CString;
29 use std::mem::MaybeUninit;
30 use std::path::PathBuf;
31 use std::process::Command;
32 use libc::c_void;
33 use std::ptr;
34 use std::thread;
35 use std::time::Duration;
36 use std::io;
37
38 #[test]
39 #[cfg(target_arch = "x86_64")]
40 fn test_core_unwind() {
41 unsafe {
42 let mut libc_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
43 libc_path_buf.push("data/libc-2.23.so");
44 let mut test_callstack_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
45 test_callstack_path_buf.push("data/test_callstack");
46 let mut core_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
47 core_path_buf.push("data/core.test_callstack");
48
49 let test_callstack_start:u64 = 0x400000;
50 let libc_start:u64 = 0x00007f9ac7468000;
51 let test_callstack_path = CString::new(test_callstack_path_buf.to_str().unwrap()).unwrap();
52 let libc_path = CString::new(libc_path_buf.to_str().unwrap()).unwrap();
53 let core_path = CString::new(core_path_buf.to_str().unwrap()).unwrap();
54
55 let asp = unw_create_addr_space(&mut _UCD_accessors ,0);
56 let ui: * mut UCD_info = _UCD_create(core_path.as_ptr());
57 let mut c = MaybeUninit::uninit();
58 let _ret = unw_init_remote(c.as_mut_ptr(),asp,ui as * mut libc::c_void );
59 _UCD_add_backing_file_at_vaddr(ui, test_callstack_start, test_callstack_path.as_ptr());
60
61 _UCD_add_backing_file_at_vaddr(ui, libc_start, libc_path.as_ptr());
62 let mut ip: unw_word_t = 0;
63 let mut sp: unw_word_t = 0;
64 let mut val: unw_word_t = 0;
65 let mut backtrace = String::new();
66 loop {
67 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_IP as ::std::os::raw::c_int, &mut ip);
68 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_SP as ::std::os::raw::c_int, &mut sp);
69 let ret = _UCD_access_mem(asp, sp, &mut val, 0,ui as * mut libc::c_void);
70 if ret < 0 {
71 assert!(false);
72 }
73 let mut off = MaybeUninit::uninit();
74 let mut name_vec:Vec<c_char> = vec![0;64];
75 unw_get_proc_name(c.as_mut_ptr(), name_vec.as_mut_ptr(),64, off.as_mut_ptr());
76 let name = CStr::from_ptr(name_vec.as_mut_ptr());
77 backtrace.push_str(&format!("0x{:x} in {:?} ()\n", ip, name.to_str().unwrap()));
78 let ret = unw_step(c.as_mut_ptr());
79 if ret <= 0 {
80 break;
81 }
82 }
83 assert!(backtrace.contains("main"), true);
84 assert!(backtrace.contains("first"), true);
85 assert!(backtrace.contains("second"), true);
86 assert!(backtrace.contains("third"), true);
87 }
88 }
89 #[test]
90 #[cfg(target_arch = "x86_64")]
91 fn test_core_unwind_heap_error() {
92 unsafe {
93 let mut libc_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
94 libc_path_buf.push("data/libc-2.23.so");
95 let mut test_heap_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
96 test_heap_path_buf.push("data/test_heapError");
97 let mut core_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
98 core_path_buf.push("data/core.test_heapError");
99
100 let test_heap_start:u64 = 0x000055b7b218c000;
101 let libc_start:u64 = 0x00007f90e058b000;
102 let test_heap_path = CString::new(test_heap_path_buf.to_str().unwrap()).unwrap();
103 let libc_path = CString::new(libc_path_buf.to_str().unwrap()).unwrap();
104 let core_path = CString::new(core_path_buf.to_str().unwrap()).unwrap();
105 let asp = unw_create_addr_space(&mut _UCD_accessors ,0);
106 let ui: * mut UCD_info = _UCD_create(core_path.as_ptr());
107 let mut c = MaybeUninit::uninit();
108 let _ret = unw_init_remote(c.as_mut_ptr(),asp,ui as * mut libc::c_void );
109 _UCD_add_backing_file_at_vaddr(ui, test_heap_start, test_heap_path.as_ptr());
110
111 _UCD_add_backing_file_at_vaddr(ui, libc_start, libc_path.as_ptr());
112 let mut ip: unw_word_t = 0;
113 let mut sp: unw_word_t = 0;
114 let mut val: unw_word_t = 0;
115 let mut backtrace = String::new();
116 loop {
117 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_IP as ::std::os::raw::c_int, &mut ip);
118 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_SP as ::std::os::raw::c_int, &mut sp);
119 let ret = _UCD_access_mem(asp, sp, &mut val, 0,ui as * mut libc::c_void);
120 if ret < 0 {
121 assert!(false);
122 }
123 let mut off = MaybeUninit::uninit();
124 let mut name_vec:Vec<c_char> = vec![0;64];
125 unw_get_proc_name(c.as_mut_ptr(), name_vec.as_mut_ptr(),64, off.as_mut_ptr());
126 let name = CStr::from_ptr(name_vec.as_mut_ptr());
127 backtrace.push_str(&format!("0x{:x} in {:?} ()\n", ip, name.to_str().unwrap()));
128 let ret = unw_step(c.as_mut_ptr());
129 if ret <= 0 {
130 break;
131 }
132 }
133 assert!(backtrace.contains("main"), true);
134 assert!(backtrace.contains("cfree"), true);
135 }
136 }
137 #[test]
138 #[cfg(target_arch = "x86_64")]
139 fn test_core_unwind_canary() {
140 unsafe {
141 let mut libc_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
142 libc_path_buf.push("data/libc-2.23.so");
143 let mut test_canary_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
144 test_canary_path_buf.push("data/test_canary");
145 let mut core_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
146 core_path_buf.push("data/core.test_canary");
147
148 let test_canary_start:u64 = 0x0000558672376000;
149 let libc_start:u64 = 0x00007fc14b336000;
150 let test_canary_path = CString::new(test_canary_path_buf.to_str().unwrap()).unwrap();
151 let libc_path = CString::new(libc_path_buf.to_str().unwrap()).unwrap();
152 let core_path = CString::new(core_path_buf.to_str().unwrap()).unwrap();
153 let asp = unw_create_addr_space(&mut _UCD_accessors ,0);
154 let ui: * mut UCD_info = _UCD_create(core_path.as_ptr());
155 let mut c = MaybeUninit::uninit();
156 let _ret = unw_init_remote(c.as_mut_ptr(),asp,ui as * mut libc::c_void );
157 _UCD_add_backing_file_at_vaddr(ui, test_canary_start, test_canary_path.as_ptr());
158
159 _UCD_add_backing_file_at_vaddr(ui, libc_start, libc_path.as_ptr());
160 let mut ip: unw_word_t = 0;
161 let mut sp: unw_word_t = 0;
162 let mut val: unw_word_t = 0;
163 let mut backtrace = String::new();
164 loop {
165 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_IP as ::std::os::raw::c_int, &mut ip);
166 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_SP as ::std::os::raw::c_int, &mut sp);
167 let ret = _UCD_access_mem(asp, sp, &mut val, 0,ui as * mut libc::c_void);
168 if ret < 0 {
169 assert!(false);
170 }
171 let mut off = MaybeUninit::uninit();
172 let mut name_vec:Vec<c_char> = vec![0;64];
173 unw_get_proc_name(c.as_mut_ptr(), name_vec.as_mut_ptr(),64, off.as_mut_ptr());
174 let name = CStr::from_ptr(name_vec.as_mut_ptr());
175 backtrace.push_str(&format!("0x{:x} in {:?} ()\n", ip, name.to_str().unwrap()));
176 let ret = unw_step(c.as_mut_ptr());
177 if ret <= 0 {
178 break;
179 }
180 }
181 assert!(backtrace.contains("main"), true);
182 assert!(backtrace.contains("fortify_fail"), true);
183 }
184 }
185 #[test]
186 #[cfg(target_arch = "x86_64")]
187 fn test_local_unwind() {
188 unsafe {
189 let mut c = MaybeUninit::uninit();
190 let mut uc = MaybeUninit::uninit();
191 let mut ip: unw_word_t = 0;
192 let _ret = unw_getcontext(uc.as_mut_ptr());
193 let _ret = unw_init_local(c.as_mut_ptr(),uc.as_mut_ptr());
194 let mut backtrace = String::new();
195 loop {
196 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_IP as ::std::os::raw::c_int, &mut ip);
197 let mut off = MaybeUninit::uninit();
198 let mut name_vec:Vec<c_char> = vec![0;64];
199 unw_get_proc_name(c.as_mut_ptr(), name_vec.as_mut_ptr(),64, off.as_mut_ptr());
200 let name = CStr::from_ptr(name_vec.as_mut_ptr());
201 backtrace.push_str(&format!("0x{:x} in {:?} ()\n", ip, name.to_str().unwrap()));
202 let ret = unw_step(c.as_mut_ptr());
203 if ret <= 0 {
204 break;
205 }
206 }
207 println!("{}", backtrace);
208 assert!(backtrace.contains("test_local_unwind"), true);
209 assert!(backtrace.contains("start_thread") || backtrace.contains("start"), true);
210 }
211 }
212
213 #[test]
214 #[cfg(all(feature = "ptrace", target_arch = "x86_64"))]
215 fn test_remote_unwind() {
216 unsafe {
217 let mut c = MaybeUninit::uninit();
218 let mut ip: unw_word_t = 0;
219 let asp = unw_create_addr_space(&mut _UPT_accessors ,0);
220 let mut test_callstack_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
222 test_callstack_path_buf.push("data/test_callstack_remote");
223 let mut child = Command::new(test_callstack_path_buf.to_str().unwrap())
224 .spawn()
225 .expect("failed to execute child");
226 thread::sleep(Duration::from_millis(10));
227 let ret = libc::ptrace(
228 libc::PTRACE_ATTACH,
229 child.id() as libc::pid_t,
230 ptr::null_mut::<c_void>(),
231 ptr::null_mut::<c_void>(),
232 );
233 if ret != 0 {
234 panic!("{}", io::Error::last_os_error());
235 }
236
237 loop {
238 let mut status = 0;
239 let ret = libc::waitpid(child.id() as libc::pid_t, &mut status, 0);
240 if ret < 0 {
241 panic!("{}", io::Error::last_os_error());
242 }
243 if libc::WIFSTOPPED(status) {
244 break;
245 }
246 }
247
248 let ui: *mut ::std::os::raw::c_void = _UPT_create(child.id() as i32);
249 let mut backtrace = String::new();
250
251 let _ret = unw_init_remote(c.as_mut_ptr(),asp,ui as * mut libc::c_void );
252 loop {
253 unw_get_reg(c.as_mut_ptr(), UNW_TDEP_IP as ::std::os::raw::c_int, &mut ip);
254 let mut off = MaybeUninit::uninit();
255 let mut name_vec:Vec<c_char> = vec![0;64];
256 unw_get_proc_name(c.as_mut_ptr(), name_vec.as_mut_ptr(),64, off.as_mut_ptr());
257 let name = CStr::from_ptr(name_vec.as_mut_ptr());
258 backtrace.push_str(&format!("0x{:x} in {:?} ()\n", ip, name.to_str().unwrap()));
259 let ret = unw_step(c.as_mut_ptr());
260 if ret <= 0 {
261 break;
262 }
263 }
264 assert!(backtrace.contains("main"), true);
265 assert!(backtrace.contains("first"), true);
266 assert!(backtrace.contains("second"), true);
267 assert!(backtrace.contains("third"), true);
268 _UPT_destroy(ui);
269 unw_destroy_addr_space(asp);
270 child.kill().unwrap();
271 }
272 }
273}