diff --git a/Cargo.toml b/Cargo.toml index 477909111..9fc8b3c83 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ exclude = [ [dependencies] cfg-if = "1.0" rustc-demangle = "0.1.4" -libc = { version = "0.2.94", default-features = false } +libc = { version = "0.2.139", default-features = false } # Optionally enable the ability to serialize a `Backtrace`, controlled through # the `serialize-*` features below. diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index cd4cec58c..129741e82 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -41,6 +41,7 @@ cfg_if::cfg_if! { target_os = "openbsd", target_os = "solaris", target_os = "illumos", + target_os = "nto", ))] { #[path = "gimli/mmap_unix.rs"] mod mmap; @@ -179,6 +180,7 @@ cfg_if::cfg_if! { target_os = "freebsd", target_os = "openbsd", all(target_os = "android", feature = "dl_iterate_phdr"), + target_os = "nto", ), not(target_env = "uclibc"), ))] { diff --git a/src/symbolize/gimli/libs_dl_iterate_phdr.rs b/src/symbolize/gimli/libs_dl_iterate_phdr.rs index 9f0304ce8..71ec5776f 100644 --- a/src/symbolize/gimli/libs_dl_iterate_phdr.rs +++ b/src/symbolize/gimli/libs_dl_iterate_phdr.rs @@ -34,7 +34,8 @@ fn infer_current_exe(base_addr: usize) -> OsString { // `info` should be a valid pointers. // `vec` should be a valid pointer to a `std::Vec`. unsafe extern "C" fn callback( - info: *mut libc::dl_phdr_info, + #[cfg(not(target_os = "nto"))] info: *mut libc::dl_phdr_info, + #[cfg(target_os = "nto")] info: *const libc::dl_phdr_info, _size: libc::size_t, vec: *mut libc::c_void, ) -> libc::c_int { diff --git a/src/symbolize/gimli/parse_running_mmaps_unix.rs b/src/symbolize/gimli/parse_running_mmaps_unix.rs index a196ffcfb..ea7064c72 100644 --- a/src/symbolize/gimli/parse_running_mmaps_unix.rs +++ b/src/symbolize/gimli/parse_running_mmaps_unix.rs @@ -53,19 +53,34 @@ pub(super) struct MapsEntry { pathname: OsString, } -pub(super) fn parse_maps() -> Result, &'static str> { - let mut v = Vec::new(); +fn concat_str(a: &str, b: &str) -> String { + let mut e = String::from(a); + e += b; + e +} + +fn read_file(file: &str) -> Result { let mut proc_self_maps = - File::open("/proc/self/maps").map_err(|_| "Couldn't open /proc/self/maps")?; + File::open(file).map_err(|_| concat_str("Couldn't open file: ", file))?; let mut buf = String::new(); let _bytes_read = proc_self_maps .read_to_string(&mut buf) - .map_err(|_| "Couldn't read /proc/self/maps")?; - for line in buf.lines() { - v.push(line.parse()?); - } + .map_err(|_| concat_str("Couldn't read file: ", file))?; + Ok(buf) +} - Ok(v) +pub(super) fn parse_maps() -> Result, String> { + let (file, skip) = config(); + let content = read_file(file)?; + parse_maps_lines(&content, skip) +} + +fn parse_maps_lines(content: &str, skip: usize) -> Result, String> { + let mut data = Vec::new(); + for line in content.lines().skip(skip) { + data.push(line.parse()?); + } + Ok(data) } impl MapsEntry { @@ -78,6 +93,12 @@ impl MapsEntry { } } +#[cfg(not(target_os = "nto"))] +pub fn config() -> (&'static str, usize) { + ("/proc/self/maps", 0) +} + +#[cfg(not(target_os = "nto"))] impl FromStr for MapsEntry { type Err = &'static str; @@ -141,13 +162,73 @@ impl FromStr for MapsEntry { } } +#[cfg(target_os = "nto")] +pub fn config() -> (&'static str, usize) { + ("/proc/self/pmap", 1) +} + +#[cfg(target_os = "nto")] +impl FromStr for MapsEntry { + type Err = &'static str; + + // Format: vaddr,size,flags,prot,maxprot,dev,ino,offset,rsv,guardsize,refcnt,mapcnt,path + // e.g.: "0x00000022fa36b000,0x0000000000002000,0x00000071,0x05,0x0f,0x0000040b,0x00000000000000dd, + // 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/proc/boot/cat" + fn from_str(s: &str) -> Result { + let mut parts = s.split(','); + let vaddr_str = parts.next().ok_or("Couldn't find virtual address")?; + let size_str = parts.next().ok_or("Couldn't find size")?; + let _flags_str = parts.next().ok_or("Couldn't find flags")?; + let prot_str = parts.next().ok_or("Couldn't find protection")?; + let _maxprot_str = parts.next().ok_or("Couldn't find maximum protection")?; + let dev_str = parts.next().ok_or("Couldn't find device")?; + let ino_str = parts.next().ok_or("Couldn't find inode")?; + let offset_str = parts.next().ok_or("Couldn't find offset")?; + let _rsv_str = parts.next().ok_or("Couldn't find reserved pages")?; + let _guardsize_str = parts.next().ok_or("Couldn't find guard size")?; + let _refcnt_str = parts.next().ok_or("Couldn't find reference count")?; + let _mapcnt_str = parts.next().ok_or("Couldn't find mapped count")?; + let pathname_str = parts.next().unwrap_or(""); // pathname may be omitted. + + let hex = + |s: &str| usize::from_str_radix(&s[2..], 16).map_err(|_| "Couldn't parse hex number"); + let address = { (hex(vaddr_str)?, hex(vaddr_str)? + hex(size_str)?) }; + + // TODO: Probably a rust'ier way of doing this + let mut perms: [char; 4] = ['-', '-', '-', '-']; + let perm_str: [char; 3] = ['r', 'w', 'x']; + let perm_bits: [usize; 3] = [0x1, 0x2, 0x4]; + + for (pos, val) in perm_bits.iter().enumerate() { + let prot = hex(prot_str)?; + if val & prot != 0 { + perms[pos] = perm_str[pos] + } + } + + let offset = hex(offset_str)?; + let dev = { (hex(dev_str)?, 0x00000000) }; + let inode = hex(ino_str)?; + let pathname = pathname_str.into(); + + Ok(MapsEntry { + address, + perms, + offset, + dev, + inode, + pathname, + }) + } +} + // Make sure we can parse 64-bit sample output if we're on a 64-bit target. -#[cfg(target_pointer_width = "64")] +#[cfg(all(target_pointer_width = "64", not(target_os = "nto")))] #[test] fn check_maps_entry_parsing_64bit() { assert_eq!( "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 \ - [vsyscall]" + [vsyscall]" .parse::() .unwrap(), MapsEntry { @@ -162,7 +243,7 @@ fn check_maps_entry_parsing_64bit() { assert_eq!( "7f5985f46000-7f5985f48000 rw-p 00039000 103:06 76021795 \ - /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" + /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2" .parse::() .unwrap(), MapsEntry { @@ -190,6 +271,7 @@ fn check_maps_entry_parsing_64bit() { } // (This output was taken from a 32-bit machine, but will work on any target) +#[cfg(not(target_os = "nto"))] #[test] fn check_maps_entry_parsing_32bit() { /* Example snippet of output: @@ -240,3 +322,51 @@ fn check_maps_entry_parsing_32bit() { } ); } + +#[cfg(target_os = "nto")] +#[test] +fn check_maps_entry_parsing_64bit() { + assert_eq!( + "0xffffffffff600000,0x0000000000001000,0x00000071,0x04,0x0f,0x00000000,0x0000000000000000,\ + 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/proc/boot/foo" + .parse::() + .unwrap(), + MapsEntry { + address: (0xffffffffff600000, 0xffffffffff601000), + perms: ['-', '-', 'x', '-'], + offset: 0x00000000, + dev: (0x00, 0x00), + inode: 0x0, + pathname: "/proc/boot/foo".into(), + } + ); + + assert_eq!( + "0x00007f5985f46000,0x0000000000002000,0x00000071,0x03,0x0f,0x00000103,0x0000000076021795,\ + 0x0000000000039000,0x0000000000000000,0x00000000,0x00000005,0x00000003,/usr/lib/ldqnx-64.so.2" + .parse::() + .unwrap(), + MapsEntry { + address: (0x7f5985f46000, 0x7f5985f48000), + perms: ['r', 'w', '-', '-'], + offset: 0x00039000, + dev: (0x103, 0x0), + inode: 0x76021795, + pathname: "/usr/lib/ldqnx-64.so.2".into(), + } + ); + assert_eq!( + "0x00000035b1a21000,0x0000000000001000,0x00000071,0x03,0x0f,0x00000000,0x0000000000000000,\ + 0x0000000000000000,0x0000000000000000,0x00000000,0x00000005,0x00000003," + .parse::() + .unwrap(), + MapsEntry { + address: (0x35b1a21000, 0x35b1a22000), + perms: ['r', 'w', '-', '-'], + offset: 0x00000000, + dev: (0x00, 0x00), + inode: 0x0, + pathname: Default::default(), + } + ); +}