1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 
11 //! Common support for resolving with `dladdr`, often used as a fallback if
12 //! other strategies don't work.
13 
14 #![allow(dead_code)]
15 
16 cfg_if::cfg_if! {
17     if #[cfg(all(unix, not(target_os = "emscripten"), feature = "dladdr"))] {
18         use core::ffi::c_void;
19         use core::marker;
20         use core::{mem, slice};
21         use crate::SymbolName;
22         use crate::types::BytesOrWideString;
23         use libc::{self, Dl_info};
24 
25         pub struct Symbol<'a> {
26             inner: Dl_info,
27             _marker: marker::PhantomData<&'a i32>,
28         }
29 
30         impl Symbol<'_> {
31             pub fn name(&self) -> Option<SymbolName> {
32                 if self.inner.dli_sname.is_null() {
33                     None
34                 } else {
35                     let ptr = self.inner.dli_sname as *const u8;
36                     unsafe {
37                         let len = libc::strlen(self.inner.dli_sname);
38                         Some(SymbolName::new(slice::from_raw_parts(ptr, len)))
39                     }
40                 }
41             }
42 
43             pub fn addr(&self) -> Option<*mut c_void> {
44                 Some(self.inner.dli_saddr as *mut _)
45             }
46 
47             pub fn filename_raw(&self) -> Option<BytesOrWideString> {
48                 None
49             }
50 
51             #[cfg(feature = "std")]
52             pub fn filename(&self) -> Option<&::std::path::Path> {
53                 None
54             }
55 
56             pub fn lineno(&self) -> Option<u32> {
57                 None
58             }
59         }
60 
61         pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(Symbol<'static>)) {
62             let mut info = Symbol {
63                 inner: mem::zeroed(),
64                 _marker: marker::PhantomData,
65             };
66             // Skip null addresses to avoid calling into libc and having it do
67             // things with the dynamic symbol table for no reason.
68             if !addr.is_null() && libc::dladdr(addr as *mut _, &mut info.inner) != 0 {
69                 cb(info)
70             }
71         }
72     } else {
73         use core::ffi::c_void;
74         use core::marker;
75         use crate::symbolize::SymbolName;
76         use crate::types::BytesOrWideString;
77 
78         pub struct Symbol<'a> {
79             a: Void,
80             _b: marker::PhantomData<&'a i32>,
81         }
82 
83         enum Void {}
84 
85         impl Symbol<'_> {
86             pub fn name(&self) -> Option<SymbolName> {
87                 match self.a {}
88             }
89 
90             pub fn addr(&self) -> Option<*mut c_void> {
91                 match self.a {}
92             }
93 
94             pub fn filename_raw(&self) -> Option<BytesOrWideString> {
95                 match self.a {}
96             }
97 
98             #[cfg(feature = "std")]
99             pub fn filename(&self) -> Option<&::std::path::Path> {
100                 match self.a {}
101             }
102 
103             pub fn lineno(&self) -> Option<u32> {
104                 match self.a {}
105             }
106         }
107 
108         pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(Symbol<'static>)) {
109             drop((addr, cb));
110         }
111     }
112 }
113