1#![allow(clippy::too_many_arguments)]
2
3use dlopen::wrapper::WrapperApi;
4use dlopen_derive::WrapperApi;
5use nix::libc;
6use nix::unistd::Pid;
7use object::{Object, ObjectSymbol};
8use std::collections::HashMap;
9use std::path::Path;
10use std::{fs, io};
11
12#[derive(Copy, Clone)]
13pub struct TdThrHandle {
14 _th_ta_p: *mut TdThrAgent,
15 _th_unique: *mut PsAddr,
16}
17
18#[derive(Debug)]
19#[repr(C)]
20pub enum TdThrState {
21 AnyState,
22 Unknown,
23 Stopped,
24 Run,
25 Active,
26 Zombie,
27 Sleep,
28 StoppedAsleep,
29}
30
31#[derive(Debug)]
32#[repr(C)]
33pub enum TdErr {
34 Ok,
36 Err,
38 NoThr,
40 NoSv,
42 NoLWP,
44 BadPH,
46 BadTH,
48 BadSH,
50 BadTA,
52 BadKEY,
54 NoMsg,
56 NoFPRegs,
58 NoLibthread,
60 NoEvent,
62 NoCapab,
64 DbErr,
66 NoAplic,
68 NoTSD,
70 Malloc,
72 PartialReg,
74 NoXregs,
76 TLSDefer,
78 NoTalloc,
79 Version,
81 NoTLS,
83}
84
85pub type TdThrAgent = libc::c_void;
86pub type PsAddr = libc::c_void;
87
88#[allow(dead_code)]
90#[derive(Debug)]
91#[repr(C)]
92pub enum TdThrType {
93 AnyType,
94 User,
95 System,
96}
97
98#[derive(Debug)]
100#[repr(C)]
101pub struct TdThrEvents {
102 event_bits: [u32; 2],
103}
104
105#[repr(C)]
107#[derive(Debug)]
108pub struct TdTaStats {
109 pub nthreads: i32,
111 pub r_concurrency: i32,
113 pub nrunnable_num: i32,
115 pub nrunnable_den: i32,
117 pub a_concurrency_num: i32,
119 pub a_concurrency_den: i32,
121 pub nlwps_num: i32,
123 pub nlwps_den: i32,
125 pub nidle_num: i32,
127 pub nidle_den: i32,
129}
130
131#[repr(C)]
133#[derive(Debug)]
134pub struct TdThrInfo {
135 ti_ta_p: *mut TdThrAgent,
137 ti_user_flags: libc::c_uint,
139 pub ti_tid: libc::pthread_t,
141 pub ti_tls: *mut u8,
143 pub ti_startfunc: *mut PsAddr,
145 pub ti_stkbase: *mut PsAddr,
147 pub ti_stksize: libc::c_long,
149 ti_ro_area: *mut PsAddr,
151 ti_ro_size: libc::c_int,
153 pub ti_state: TdThrState,
155 pub ti_db_suspended: libc::c_uchar,
157 pub ti_type: TdThrType,
159 ti_pc: libc::intptr_t,
161 ti_sp: libc::intptr_t,
163 ti_flags: libc::c_ushort,
165 pub ti_pri: libc::c_int,
167 pub ti_lid: libc::pid_t,
169 pub ti_sigmask: libc::sigset_t,
171 pub ti_traceme: libc::c_uchar,
173 ti_preemptflag: libc::c_uchar,
175 ti_pirecflag: libc::c_uchar,
177 pub ti_pending: libc::sigset_t,
179 pub ti_events: TdThrEvents,
181}
182
183type SymbolMapping = HashMap<String, HashMap<String, usize>>;
184
185pub struct ProcHandle {
186 pub pid: Pid,
187 pub symbols: SymbolMapping,
188}
189
190impl ProcHandle {
191 pub fn new(pid: Pid) -> io::Result<ProcHandle> {
192 Ok(ProcHandle {
193 pid,
194 symbols: Self::extract_symbols(pid)?,
195 })
196 }
197
198 fn extract_symbols(pid: Pid) -> io::Result<SymbolMapping> {
199 proc_maps::get_process_maps(pid.as_raw())?
200 .into_iter()
201 .filter(|map| map.offset == 0)
202 .filter_map(|map| map.filename().map(|path| (path.to_path_buf(), map.start())))
203 .filter(|(path, _)| path.starts_with("/"))
204 .map(
205 |(path, start)| -> Result<(String, HashMap<String, usize>), io::Error> {
206 let k = path.to_str().unwrap_or_default().to_owned();
207 let v = extract_symbols_from_lib(&path, start)?;
208 Ok((k, v))
209 },
210 )
211 .collect()
212 }
213}
214
215fn extract_symbols_from_lib(
216 lib_path: &Path,
217 map_addr: usize,
218) -> io::Result<HashMap<String, usize>> {
219 let mut symbols = HashMap::new();
220
221 let bin_data = fs::read(lib_path)?;
222 let binary = object::File::parse(&*bin_data)
223 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
224
225 for sym in binary.symbols() {
226 if let Ok(name) = sym.name() {
227 symbols.insert(name.to_string(), sym.address() as usize + map_addr);
228 }
229 }
230 for sym in binary.dynamic_symbols() {
231 if let Ok(name) = sym.name() {
232 symbols.insert(name.to_string(), sym.address() as usize + map_addr);
233 }
234 }
235 Ok(symbols)
236}
237
238#[derive(WrapperApi)]
239pub struct ThreadDb {
240 td_init: unsafe extern "C" fn() -> TdErr,
242 td_ta_new: unsafe extern "C" fn(ps: *mut ProcHandle, ta: *mut *mut TdThrAgent) -> TdErr,
244 td_ta_delete: unsafe extern "C" fn(ta: *mut TdThrAgent) -> TdErr,
246
247 td_ta_get_nthreads: unsafe extern "C" fn(ta: *const TdThrAgent, np: *mut i32) -> TdErr,
249
250 td_ta_enable_stats: unsafe extern "C" fn(ta: *mut TdThrAgent, enable: i32) -> TdErr,
252 td_ta_reset_stats: unsafe extern "C" fn(ta: *mut TdThrAgent) -> TdErr,
254 td_ta_get_stats: unsafe extern "C" fn(ta: *const TdThrAgent, stats: *mut TdTaStats) -> TdErr,
256
257 td_ta_thr_iter: unsafe extern "C" fn(
259 ta: *mut TdThrAgent,
260 callback: unsafe extern "C" fn(handle: *const TdThrHandle, cbdata: *mut libc::c_void) -> i32,
261 cbdata: *mut libc::c_void,
262 state: TdThrState,
263 pri: i32,
264 ti_sigmask: *mut libc::sigset_t,
265 ti_user_flags: u32,
266 ) -> TdErr,
267
268 td_thr_validate: unsafe extern "C" fn(handle: *const TdThrHandle) -> TdErr,
270
271 td_ta_map_lwp2thr: unsafe extern "C" fn(
273 ta: *const TdThrAgent,
274 pid: libc::pid_t,
275 handle: *mut TdThrHandle,
276 ) -> TdErr,
277
278 td_thr_get_info:
280 unsafe extern "C" fn(handle: *const TdThrHandle, info: *mut TdThrInfo) -> TdErr,
281
282 td_thr_tlsbase: unsafe extern "C" fn(
284 handle: *const TdThrHandle,
285 modid: u32,
286 base: *mut *mut libc::c_void,
287 ) -> TdErr,
288
289 td_thr_tls_get_addr: unsafe extern "C" fn(
291 handle: *const TdThrHandle,
292 map_address: *const libc::c_void,
293 offset: libc::size_t,
294 addr: *mut *mut libc::c_void,
295 ) -> TdErr,
296}