udbg/os/linux/
udbg.rs

1use super::*;
2use crate::elf::*;
3use crate::os::udbg::{EventHandler, HandleResult};
4use crate::range::RangeValue;
5
6use anyhow::Context;
7use goblin::elf::sym::Sym;
8use nix::sys::ptrace::Options;
9use nix::sys::wait::waitpid;
10use parking_lot::RwLock;
11use procfs::process::{Stat as ThreadStat, Task};
12use serde_value::Value;
13use std::cell::{Cell, UnsafeCell};
14use std::collections::HashSet;
15use std::mem::transmute;
16use std::ops::Deref;
17use std::time::{Duration, Instant};
18
19const TRAP_BRKPT: i32 = 1;
20const TRAP_TRACE: i32 = 2;
21const TRAP_BRANCH: i32 = 3;
22const TRAP_HWBKPT: i32 = 4;
23const TRAP_UNK: i32 = 5;
24
25cfg_if! {
26    if #[cfg(target_os = "android")] {
27        const PTRACE_INTERRUPT: c_uint = 0x4207;
28        const PTRACE_SEIZE: c_uint = 0x4206;
29    }
30}
31
32pub struct ElfSymbol {
33    pub sym: Sym,
34    pub name: Arc<str>,
35}
36
37impl Deref for ElfSymbol {
38    type Target = Sym;
39
40    #[inline]
41    fn deref(&self) -> &Self::Target {
42        &self.sym
43    }
44}
45
46impl From<ElfSym<'_>> for ElfSymbol {
47    fn from(s: ElfSym<'_>) -> Self {
48        ElfSymbol {
49            sym: s.sym,
50            name: s.name.into(),
51        }
52    }
53}
54
55#[derive(Deref)]
56pub struct NixThread {
57    #[deref]
58    base: ThreadData,
59    stat: ThreadStat,
60}
61
62impl TryFrom<Task> for NixThread {
63    type Error = procfs::ProcError;
64
65    fn try_from(task: Task) -> Result<Self, Self::Error> {
66        Ok(NixThread {
67            base: ThreadData {
68                tid: task.tid,
69                wow64: false,
70            },
71            stat: task.stat()?,
72        })
73    }
74}
75
76impl GetProp for NixThread {}
77
78impl UDbgThread for NixThread {
79    fn name(&self) -> Arc<str> {
80        self.stat.comm.as_str().into()
81    }
82    fn status(&self) -> Arc<str> {
83        self.stat.state.to_string().into()
84    }
85    fn priority(&self) -> Option<i64> {
86        Some(self.stat.priority)
87    }
88}
89
90#[inline(always)]
91fn to_symbol(s: ElfSym) -> Symbol {
92    let flags = if s.is_function() {
93        SymbolFlags::FUNCTION
94    } else {
95        SymbolFlags::NONE
96    };
97    Symbol {
98        offset: s.st_value as u32,
99        name: s.name.into(),
100        flags: flags.bits(),
101        len: s.st_size as u32,
102        type_id: 0,
103    }
104}
105
106impl SymbolsData {
107    fn from_elf(path: &str) -> Self {
108        let mut this = Self::default();
109        this.load(path);
110        this
111    }
112
113    fn load(&mut self, path: &str) -> anyhow::Result<()> {
114        let map = Utils::mapfile(path.as_ref()).context("map")?;
115        let e = ElfHelper::parse(&map).context("parse")?;
116        let mut push_symbol = |s: ElfSym| {
117            if s.name.starts_with("$x.") {
118                return;
119            }
120            self.exports
121                .entry(s.offset())
122                .or_insert_with(|| to_symbol(s));
123        };
124        e.enum_symbol().for_each(&mut push_symbol);
125        e.enum_export().for_each(&mut push_symbol);
126        Ok(())
127    }
128}
129
130struct TimeCheck {
131    last: Cell<Instant>,
132    pub duration: Cell<Duration>,
133}
134
135impl TimeCheck {
136    pub fn new(duration: Duration) -> Self {
137        Self {
138            last: Instant::now().checked_sub(duration).unwrap().into(),
139            duration: duration.into(),
140        }
141    }
142
143    pub fn check(&self, mut callback: impl FnMut()) {
144        if self.last.get().elapsed() > self.duration.get() {
145            callback();
146            self.last.set(Instant::now());
147        }
148    }
149}
150
151#[derive(Deref)]
152pub struct TargetCommon {
153    #[deref]
154    _base: CommonBase,
155    pub threads: RwLock<HashSet<tid_t>>,
156    tc_module: TimeCheck,
157    tc_memory: TimeCheck,
158    mem_pages: RwLock<Vec<MemoryPage>>,
159    waiting: Cell<bool>,
160    pub trace_opts: Options,
161    pub hwbps: UnsafeCell<user_hwdebug_state>,
162}
163
164impl TargetCommon {
165    pub fn new(ps: Process) -> Self {
166        const TIMEOUT: Duration = Duration::from_secs(5);
167
168        let mut base = CommonBase::new(ps);
169        let image_path = base.process.image_path().unwrap_or_default();
170        base.process
171            .enum_module()
172            .ok()
173            .and_then(|mut iter| iter.find(|m| m.path.as_ref() == &image_path))
174            .map(|m| base.image_base = m.base);
175
176        let trace_opts = Options::PTRACE_O_EXITKILL
177            | Options::PTRACE_O_TRACECLONE
178            | Options::PTRACE_O_TRACEEXEC
179            | Options::PTRACE_O_TRACEVFORK
180            | Options::PTRACE_O_TRACEFORK;
181        Self {
182            _base: base,
183            tc_module: TimeCheck::new(Duration::from_secs(10)),
184            tc_memory: TimeCheck::new(Duration::from_secs(10)),
185            mem_pages: RwLock::new(Vec::new()),
186            threads: RwLock::new(HashSet::new()),
187            trace_opts,
188            waiting: Cell::new(false),
189            hwbps: unsafe { core::mem::zeroed() },
190        }
191    }
192
193    pub fn update_memory_page(&self) -> IoResult<()> {
194        *self.mem_pages.write() = self.process.enum_memory()?.collect::<Vec<_>>();
195        Ok(())
196    }
197
198    fn update_memory_page_check_time(&self) {
199        self.tc_memory.check(|| {
200            self.update_memory_page();
201        });
202    }
203
204    // fn update_thread(&self) {
205    //     let ts = unsafe { mutable(&self.threads) };
206    //     let mut maps: HashSet<pid_t> = HashSet::new();
207    //     for tid in process_tasks(self.pid) {
208    //         if !ts.contains(&tid) {
209    //             self.dbg.map(|d| d.thread_create(tid as u32));
210    //         }
211    //         maps.insert(tid);
212    //     }
213    //     *ts = maps;
214    // }
215
216    fn module_name<'a>(&self, name: &'a str) -> &'a str {
217        let tv = trim_ver(name);
218        let te = trim_allext(name);
219        let base = self.symgr.base.read();
220        if tv.len() < te.len() && !base.contains(tv) {
221            return tv;
222        }
223        if !base.contains(te) {
224            return te;
225        }
226        let te = trim_lastext(name);
227        if !base.contains(te) {
228            return te;
229        }
230        name
231    }
232
233    pub fn update_module(&self) -> IoResult<()> {
234        use goblin::elf::header::header32::Header as Header32;
235        use goblin::elf::header::header64::Header as Header64;
236        use std::io::Read;
237
238        // self.md.write().clear();
239        for m in self.process.enum_module()? {
240            if self.find_module(m.base).is_some()
241                || m.name.ends_with(".oat")
242                || m.name.ends_with(".apk")
243            {
244                continue;
245            }
246            let name = self.module_name(&m.name);
247
248            // TODO: use memory data
249            let mut f = match File::open(m.path.as_ref()) {
250                Ok(f) => f,
251                Err(_) => {
252                    // error!("open module file: {}", m.path);
253                    continue;
254                }
255            };
256
257            // Non-File device will block the progress
258            if !f
259                .metadata()
260                .map(|m| m.file_type().is_file())
261                .unwrap_or(false)
262            {
263                continue;
264            }
265
266            let mut buf: Header64 = unsafe { core::mem::zeroed() };
267            if f.read(buf.as_mut_byte_array()).is_err() {
268                // error!("read file: {}", m.path);
269                continue;
270            }
271
272            let arch = match ElfHelper::arch_name(buf.e_machine) {
273                Some(a) => a,
274                None => {
275                    // error!("error e_machine: {} {}", buf.e_machine, m.path);
276                    continue;
277                }
278            };
279
280            let entry = match arch {
281                "arm64" | "x86_64" => buf.e_entry as usize,
282                "x86" | "arm" => unsafe { transmute::<_, &Header32>(&buf).e_entry as usize },
283                a => {
284                    // error!("error arch: {}", a);
285                    continue;
286                }
287            };
288
289            let base = m.base;
290            let path = m.path.clone();
291            self.symgr.base.write().add(Module {
292                data: ModuleData {
293                    base,
294                    size: m.size,
295                    arch,
296                    entry,
297                    user_module: false.into(),
298                    name: name.into(),
299                    path: path.clone(),
300                },
301                loaded: false.into(),
302                syms: SymbolsData::from_elf(&path).into(),
303            });
304            // TODO:
305            // self.base.module_load(&path, base);
306        }
307        Ok(())
308    }
309
310    fn wait_event(&self, tb: &mut TraceBuf) -> Option<WaitStatus> {
311        self.waiting.set(true);
312        let mut status = 0;
313        let tid = unsafe { libc::waitpid(-1, &mut status, __WALL | WUNTRACED) };
314        // let status = ::nix::sys::wait::waitpid(None, WaitPidFlag::__WALL | WaitPidFlag::__WNOTHREAD | WaitPidFlag::WNOHANG).unwrap();
315        self.waiting.set(false);
316        self.base.event_tid.set(tid);
317
318        if tid <= 0 {
319            return None;
320        }
321
322        let status = WaitStatus::from_raw(Pid::from_raw(tid), status).unwrap();
323        println!("[status] {status:?}");
324        Some(status)
325    }
326
327    pub fn hwbps(&self) -> &mut user_hwdebug_state {
328        unsafe { self.hwbps.get().as_mut().unwrap() }
329    }
330
331    pub fn get_bp_(&self, id: BpID) -> Option<Arc<Breakpoint>> {
332        Some(self.bp_map.read().get(&id)?.clone())
333    }
334
335    pub fn handle_breakpoint(
336        &self,
337        this: &dyn UDbgTarget,
338        eh: &mut dyn EventHandler,
339        tb: &mut TraceBuf,
340    ) -> UDbgResult<HandleResult> {
341        // correct the pc register
342        let mut address = *tb.user.regs.ip();
343        let is_step = tb.si.si_code == TRAP_TRACE;
344        if IS_X86 {
345            if is_step || tb.si.si_code == TRAP_HWBKPT {
346                address = unsafe { tb.si.si_addr() as _ };
347            } else {
348                address -= 1;
349            }
350        }
351        *tb.user.regs.ip() = address;
352
353        let tid = self.base.event_tid.get();
354        let bp = match self
355            .get_bp_(address as _)
356            .or_else(|| self.get_hwbp(tb))
357            .ok_or(UDbgError::NotFound)
358        {
359            Ok(bp) => bp,
360            Err(_) if is_step => {
361                tb.user.set_step(false);
362                self.handle_reply(this, tb.call(UEvent::Step), &mut tb.user);
363                return Ok(None);
364            }
365            Err(err) => return Err(err),
366        };
367
368        bp.hit_count.set(bp.hit_count.get() + 1);
369        if bp.temp.get() {
370            self.remove_breakpoint(this, &bp);
371        }
372
373        // handle by user
374        let hitted = bp.hit_tid.map(|t| t == tid).unwrap_or(true);
375        if hitted {
376            self.handle_reply(this, tb.call(UEvent::Breakpoint(bp.clone())), &mut tb.user);
377        }
378
379        let id = bp.get_id();
380
381        #[cfg(target_arch = "x86_64")]
382        if bp.is_hard() && self.get_bp(id).is_some() {
383            tb.user.disable_hwbp_temporarily();
384        }
385
386        // int3 breakpoint revert
387        if bp.is_soft() && self.get_bp(id).is_some() {
388            // if bp is not deleted by user during the interruption
389            if bp.enabled.get() {
390                // disabled temporarily, in order to be able to continue
391                self.enable_breadpoint(this, &bp, false)
392                    .log_error("disable bp");
393                assert_ne!(&this.read_value::<BpInsn>(bp.address()).unwrap(), BP_INSN);
394
395                let user_step = tb.user.is_step();
396
397                // step once and revert
398                tb.user.set_step(true);
399                #[cfg(any(target_arch = "aarch64"))]
400                ptrace::step(Pid::from_raw(tid), None);
401                loop {
402                    eh.cont(None, tb);
403                    match eh.fetch(tb) {
404                        Some(_) => {
405                            if core::ptr::eq(self, &tb.target.0) && self.base.event_tid.get() == tid
406                            {
407                                break;
408                            } else if let Some(s) = eh.handle(tb) {
409                                eh.cont(s, tb);
410                            } else {
411                                return Ok(None);
412                            }
413                        }
414                        None => return Ok(None),
415                    }
416                }
417
418                self.enable_breadpoint(this, &bp, true)
419                    .log_error("enable bp");
420                return if user_step {
421                    Ok(eh.handle(tb).unwrap_or(None))
422                } else {
423                    tb.user.set_step(false);
424                    // tb.regs_dirty = false;
425                    Ok(None)
426                };
427            }
428        }
429
430        Ok(None)
431    }
432
433    fn enum_module<'a>(
434        &'a self,
435    ) -> UDbgResult<Box<dyn Iterator<Item = Arc<dyn UDbgModule + 'a>> + 'a>> {
436        self.update_module();
437        Ok(self.symgr.enum_module())
438    }
439
440    fn enum_memory<'a>(&'a self) -> Result<Box<dyn Iterator<Item = MemoryPage> + 'a>, UDbgError> {
441        self.update_memory_page();
442        Ok(Box::new(self.mem_pages.read().clone().into_iter()))
443    }
444
445    fn enum_handle<'a>(&'a self) -> UDbgResult<Box<dyn Iterator<Item = HandleInfo> + 'a>> {
446        use procfs::process::FDTarget;
447
448        Ok(Box::new(
449            self.process.fd().context("fd iter")?.flatten().map(|fd| {
450                let (ty, name) = match fd.target {
451                    FDTarget::Path(p) => ("Path".into(), p.to_string_lossy().into_owned()),
452                    FDTarget::Socket(s) => ("Socket".into(), s.to_string()),
453                    FDTarget::Net(n) => ("Net".into(), n.to_string()),
454                    FDTarget::Pipe(p) => ("Pipe".into(), p.to_string()),
455                    FDTarget::AnonInode(i) => ("INode".into(), i),
456                    FDTarget::MemFD(m) => ("MemFD".into(), m),
457                    FDTarget::Other(a, b) => (a.into(), b.to_string()),
458                };
459                HandleInfo {
460                    pid: self.process.pid,
461                    ty: 0,
462                    handle: fd.fd as _,
463                    name,
464                    type_name: ty,
465                }
466            }),
467        ))
468    }
469
470    pub fn enable_hwbp(
471        &self,
472        dbg: &dyn UDbgTarget,
473        bp: &Breakpoint,
474        info: HwbpInfo,
475        enable: bool,
476    ) -> UDbgResult<bool> {
477        let mut result = Ok(enable);
478        // Set Context for each thread
479        for &tid in self.threads.read().iter() {
480            if bp.hit_tid.is_some() && bp.hit_tid != Some(tid) {
481                continue;
482            }
483            // Set Debug Register
484            result = self.enable_hwbp_for_thread(tid, bp, info, enable);
485            if let Err(e) = &result {
486                udbg_ui().error(format!("enable_hwbp_for_thread for {} failed {:?}", tid, e));
487                // break;
488            }
489        }
490        // TODO: Set Context for current thread, update eflags from user
491
492        if result.is_ok() {
493            bp.enabled.set(enable);
494        }
495        result
496    }
497
498    // #[cfg(target_arch = "x86_64")]
499    // fn get_reg(&self, reg: &str, r: Option<&mut Registers>) -> Result<CpuReg, UDbgError> {
500    //     let regs = self.regs();
501    //     if let Some(r) = r {
502    //         r.rax = regs.rax;
503    //         r.rbx = regs.rbx;
504    //         r.rcx = regs.rcx;
505    //         r.rdx = regs.rdx;
506    //         r.rbp = regs.rbp;
507    //         r.rsp = regs.rsp;
508    //         r.rsi = regs.rsi;
509    //         r.rdi = regs.rdi;
510    //         r.r8 = regs.r8;
511    //         r.r9 = regs.r9;
512    //         r.r10 = regs.r10;
513    //         r.r11 = regs.r11;
514    //         r.r12 = regs.r12;
515    //         r.r13 = regs.r13;
516    //         r.r14 = regs.r14;
517    //         r.r15 = regs.r15;
518    //         r.rip = regs.rip;
519    //         r.rflags = regs.eflags as reg_t;
520    //         Ok(0.into())
521    //     } else {
522    //         Ok(CpuReg::Int(match reg {
523    //             "rax" => regs.rax,
524    //             "rbx" => regs.rbx,
525    //             "rcx" => regs.rcx,
526    //             "rdx" => regs.rdx,
527    //             "rbp" => regs.rbp,
528    //             "rsp" | "_sp" => regs.rsp,
529    //             "rsi" => regs.rsi,
530    //             "rdi" => regs.rdi,
531    //             "r8" => regs.r8,
532    //             "r9" => regs.r9,
533    //             "r10" => regs.r10,
534    //             "r11" => regs.r11,
535    //             "r12" => regs.r12,
536    //             "r13" => regs.r13,
537    //             "r14" => regs.r14,
538    //             "r15" => regs.r15,
539    //             "rip" | "_pc" => regs.rip,
540    //             "rflags" => regs.eflags as reg_t,
541    //             _ => return Err(UDbgError::InvalidRegister),
542    //         } as usize))
543    //     }
544    // }
545
546    // #[cfg(target_arch = "arm")]
547    // fn get_reg(&self, reg: &str, r: Option<&mut Registers>) -> Result<CpuReg, UDbgError> {
548    //     let regs = self.regs();
549    //     if let Some(r) = r {
550    //         *r = unsafe { transmute(*regs) };
551    //         Ok(CpuReg::Int(0))
552    //     } else {
553    //         Ok(CpuReg::Int(match reg {
554    //             "r0" => regs.regs[0],
555    //             "r1" => regs.regs[1],
556    //             "r2" => regs.regs[2],
557    //             "r3" => regs.regs[3],
558    //             "r4" => regs.regs[4],
559    //             "r5" => regs.regs[5],
560    //             "r6" => regs.regs[6],
561    //             "r7" => regs.regs[7],
562    //             "r8" => regs.regs[8],
563    //             "r9" => regs.regs[9],
564    //             "r10" => regs.regs[10],
565    //             "r11" => regs.regs[11],
566    //             "r12" => regs.regs[12],
567    //             "_sp" | "r13" => regs.regs[13],
568    //             "r14" => regs.regs[14],
569    //             "_pc" | "r15" => regs.regs[15],
570    //             "r16" => regs.regs[16],
571    //             "r17" => regs.regs[17],
572    //             _ => return Err(UDbgError::InvalidRegister),
573    //         } as usize))
574    //     }
575    // }
576
577    // #[cfg(target_arch = "aarch64")]
578    // fn get_reg(&self, reg: &str, r: Option<&mut Registers>) -> Result<CpuReg, UDbgError> {
579    //     let regs = self.regs();
580    //     if let Some(r) = r {
581    //         *r = unsafe { transmute(*regs) };
582    //         Ok(CpuReg::Int(0))
583    //     } else {
584    //         Ok(CpuReg::Int(match reg {
585    //             "pc" | "_pc" => regs.pc,
586    //             "sp" | "_sp" => regs.sp,
587    //             "pstate" => regs.pstate,
588    //             "x0" => regs.regs[0],
589    //             "x1" => regs.regs[1],
590    //             "x2" => regs.regs[2],
591    //             "x3" => regs.regs[3],
592    //             "x4" => regs.regs[4],
593    //             "x5" => regs.regs[5],
594    //             "x6" => regs.regs[6],
595    //             "x7" => regs.regs[7],
596    //             "x8" => regs.regs[8],
597    //             "x9" => regs.regs[9],
598    //             "x10" => regs.regs[10],
599    //             "x11" => regs.regs[11],
600    //             "x12" => regs.regs[12],
601    //             "x13" => regs.regs[13],
602    //             "x14" => regs.regs[14],
603    //             "x15" => regs.regs[15],
604    //             "x16" => regs.regs[16],
605    //             "x17" => regs.regs[17],
606    //             "x18" => regs.regs[18],
607    //             "x19" => regs.regs[19],
608    //             "x20" => regs.regs[20],
609    //             "x21" => regs.regs[21],
610    //             "x22" => regs.regs[22],
611    //             "x23" => regs.regs[23],
612    //             "x24" => regs.regs[24],
613    //             "x25" => regs.regs[25],
614    //             "x26" => regs.regs[26],
615    //             "x27" => regs.regs[27],
616    //             "x28" => regs.regs[28],
617    //             "x29" => regs.regs[29],
618    //             "x30" => regs.regs[30],
619    //             _ => return Err(UDbgError::InvalidRegister),
620    //         } as usize))
621    //     }
622    // }
623}
624
625fn trim_ver(name: &str) -> &str {
626    use regex::Regex;
627    &name[..Regex::new(r"-\d")
628        .unwrap()
629        .find(name)
630        .map(|p| p.start())
631        .unwrap_or(name.len())]
632}
633
634#[inline]
635fn trim_allext(name: &str) -> &str {
636    &name[..name.find(|c| c == '.').unwrap_or(name.len())]
637}
638
639#[inline]
640fn trim_lastext(name: &str) -> &str {
641    &name[..name.rfind(|c| c == '.').unwrap_or(name.len())]
642}
643
644pub fn ptrace_interrupt(tid: tid_t) -> bool {
645    unsafe { ptrace(PTRACE_INTERRUPT as _, tid, 0, 0) == 0 }
646}
647
648pub fn ptrace_seize(tid: tid_t, flags: c_int) -> bool {
649    unsafe { ptrace(PTRACE_SEIZE as _, tid, 0, flags) == 0 }
650}
651
652pub fn ptrace_getevtmsg<T: Copy>(tid: tid_t, result: &mut T) -> bool {
653    unsafe { ptrace(PTRACE_GETEVENTMSG, tid, 0, result) == 0 }
654}
655
656pub fn ptrace_step_and_wait(tid: pid_t) -> bool {
657    let tid = Pid::from_raw(tid);
658    ptrace::step(tid, None);
659    match waitpid(tid, None) {
660        Ok(t) => {
661            let pid = t.pid();
662            if pid == Some(tid) {
663                return true;
664            }
665            udbg_ui().error(format!("step unexpect tid: {pid:?}"));
666            false
667        }
668        Err(_) => false,
669    }
670}
671
672#[derive(Deref)]
673pub struct ProcessTarget(pub TargetCommon);
674
675unsafe impl Send for ProcessTarget {}
676unsafe impl Sync for ProcessTarget {}
677
678impl ProcessTarget {
679    pub fn open(pid: pid_t) -> UDbgResult<Arc<Self>> {
680        let ps = Process::from_pid(pid)?;
681        Ok(Arc::new(Self(TargetCommon::new(ps))))
682    }
683
684    pub fn insert_thread(&self, tid: tid_t) -> bool {
685        if self.threads.write().insert(tid) {
686            if let Err(err) = ptrace::setoptions(Pid::from_raw(tid), self.trace_opts) {
687                udbg_ui().error(format!("ptrace_setopt {tid} {err:?}",));
688            }
689            true
690        } else {
691            false
692        }
693    }
694
695    pub fn remove_thread(&self, tid: tid_t, s: i32, tb: &mut TraceBuf) -> bool {
696        let mut threads = self.threads.write();
697        if threads.remove(&tid) {
698            tb.call(UEvent::ThreadExit(s as u32));
699            if threads.is_empty() {
700                tb.call(UEvent::ProcessExit(s as u32));
701            }
702        } else {
703            udbg_ui().error(&format!("tid {tid} not found"));
704        }
705        threads.is_empty()
706    }
707}
708
709impl WriteMemory for ProcessTarget {
710    fn write_memory(&self, addr: usize, data: &[u8]) -> Option<usize> {
711        self.process.write_memory(addr, data)
712        // ptrace_write(self.pid.get(), addr, data);
713        // Some(data.len())
714    }
715}
716
717impl TargetMemory for ProcessTarget {
718    fn enum_memory<'a>(&'a self) -> UDbgResult<Box<dyn Iterator<Item = MemoryPage> + 'a>> {
719        self.0.enum_memory()
720    }
721
722    fn virtual_query(&self, address: usize) -> Option<MemoryPage> {
723        self.update_memory_page_check_time();
724        RangeValue::binary_search(&self.mem_pages.read().as_slice(), address).map(|r| r.clone())
725    }
726
727    fn collect_memory_info(&self) -> Vec<MemoryPage> {
728        self.0.enum_memory().unwrap().collect::<Vec<_>>()
729    }
730}
731
732impl GetProp for ProcessTarget {
733    fn get_prop(&self, key: &str) -> UDbgResult<serde_value::Value> {
734        // match key {
735        //     "moduleTimeout" => { self.tc_module.duration.set(Duration::from_secs_f64(s.args(3))); }
736        //     "memoryTimeout" => { self.tc_memory.duration.set(Duration::from_secs_f64(s.args(3))); }
737        //     _ => {}
738        // }
739        Ok(Value::Unit)
740    }
741}
742
743impl TargetControl for ProcessTarget {
744    fn detach(&self) -> UDbgResult<()> {
745        let attached = self.base.status.get() == UDbgStatus::Attached;
746        self.base.status.set(UDbgStatus::Detaching);
747        if attached {
748            self.breakk()
749        } else {
750            Ok(())
751        }
752    }
753
754    fn kill(&self) -> UDbgResult<()> {
755        if unsafe { kill(self.process.pid, SIGKILL) } == 0 {
756            Ok(())
757        } else {
758            Err(UDbgError::system())
759        }
760    }
761
762    fn breakk(&self) -> UDbgResult<()> {
763        self.base.check_attached()?;
764        // for tid in self.enum_thread()? {
765        //     if ptrace_interrupt(tid) {
766        //         return Ok(());
767        //     } else {
768        //         println!("ptrace_interrupt({tid}) failed");
769        //     }
770        // }
771        // return Err(UDbgError::system());
772        Ok(nix::sys::signal::kill(
773            Pid::from_raw(self.pid()),
774            Signal::SIGSTOP,
775        )?)
776    }
777
778    fn wait_exit(&self, timeout: Option<u32>) -> UDbgResult<Option<u32>> {
779        match nix::sys::wait::waitpid(Pid::from_raw(self.pid()), None).context("wait")? {
780            WaitStatus::Exited(_, code) => Ok(Some(code as _)),
781            err => Err(anyhow::anyhow!("unexpected status: {err:?}").into()),
782        }
783    }
784
785    fn suspend(&self) -> UDbgResult<()> {
786        if self.status() == UDbgStatus::Detaching || self.status() == UDbgStatus::Attached {
787            return Err(anyhow::anyhow!("target is attached").into());
788        }
789
790        Ok(nix::sys::signal::kill(
791            Pid::from_raw(self.pid()),
792            Signal::SIGSTOP,
793        )?)
794    }
795
796    fn resume(&self) -> UDbgResult<()> {
797        if self.status() == UDbgStatus::Detaching || self.status() == UDbgStatus::Attached {
798            return Err(anyhow::anyhow!("target is attached").into());
799        }
800
801        Ok(nix::sys::signal::kill(
802            Pid::from_raw(self.pid()),
803            Signal::SIGCONT,
804        )?)
805    }
806}
807
808// impl TargetSymbol for ProcessTarget {
809// }
810
811impl Target for ProcessTarget {
812    fn base(&self) -> &TargetBase {
813        &self._base
814    }
815
816    fn process(&self) -> Option<&Process> {
817        Some(&self.process)
818    }
819
820    fn enum_module<'a>(
821        &'a self,
822    ) -> UDbgResult<Box<dyn Iterator<Item = Arc<dyn UDbgModule + 'a>> + 'a>> {
823        self.0.enum_module()
824    }
825
826    fn find_module(&self, module: usize) -> Option<Arc<dyn UDbgModule>> {
827        let mut result = self.symgr.find_module(module);
828        self.tc_module.check(|| {
829            self.update_module();
830            result = self.symgr.find_module(module);
831        });
832        Some(result?)
833    }
834
835    fn get_module(&self, module: &str) -> Option<Arc<dyn UDbgModule>> {
836        Some(self.symgr.get_module(module).or_else(|| {
837            self.0.update_module();
838            self.symgr.get_module(module)
839        })?)
840    }
841
842    fn open_thread(&self, tid: tid_t) -> UDbgResult<Box<dyn UDbgThread>> {
843        let task = self.process.task_from_tid(tid).context("task")?;
844        Ok(Box::new(NixThread {
845            base: ThreadData { tid, wow64: false },
846            stat: task.stat().context("stat")?,
847        }))
848    }
849
850    fn enum_handle<'a>(&'a self) -> UDbgResult<Box<dyn Iterator<Item = HandleInfo> + 'a>> {
851        self.0.enum_handle()
852    }
853
854    fn enum_thread(
855        &self,
856        detail: bool,
857    ) -> UDbgResult<Box<dyn Iterator<Item = Box<dyn UDbgThread>> + '_>> {
858        Ok(Box::new(
859            self.process
860                .tasks()?
861                .filter_map(Result::ok)
862                .filter_map(|task| {
863                    Some(Box::new(NixThread::try_from(task).log_error("task stat")?)
864                        as Box<dyn UDbgThread>)
865                }),
866        ))
867    }
868}
869
870impl UDbgTarget for ProcessTarget {}
871
872impl EventHandler for DefaultEngine {
873    fn fetch(&mut self, buf: &mut TraceBuf) -> Option<()> {
874        loop {
875            self.status = waitpid(None, Some(WaitPidFlag::__WALL)).ok()?;
876            // info!("[status] {:?}", self.status);
877            self.tid = self
878                .status
879                .pid()
880                .map(|p| p.as_raw() as tid_t)
881                .unwrap_or_default();
882
883            if matches!(
884                self.status,
885                WaitStatus::Stopped(_, _) //  | WaitStatus::Signaled(_, _, _)
886            ) {
887                buf.update_regs(self.tid);
888                buf.update_siginfo(self.tid);
889                // info!(
890                //     "si: {:?}, address: {:p}, ip: {:x}",
891                //     buf.si,
892                //     unsafe { buf.si.si_addr() },
893                //     *crate::register::AbstractRegs::ip(&mut buf.user)
894                // );
895            }
896
897            let target = self
898                .targets
899                .iter()
900                .find(|&t| self.tid == t.pid() as tid_t || t.threads.read().contains(&self.tid))
901                .cloned()
902                .or_else(|| {
903                    self.targets
904                        .iter()
905                        .find(|&t| t.process.task_from_tid(self.tid).is_ok())
906                        .cloned()
907                });
908
909            if let Some(target) = target {
910                buf.target = target.clone();
911                buf.target.base.event_tid.set(self.tid as _);
912
913                if target.base.status.get() == UDbgStatus::Detaching {
914                    break;
915                }
916
917                let mut cont = false;
918                if target.base.status.get() < UDbgStatus::Attached {
919                    target.base.status.set(UDbgStatus::Attached);
920                    // buf.call(UEvent::ProcessCreate);
921                    cont = true;
922                }
923
924                // set trace options for new thread
925                if buf.target.insert_thread(self.tid) {
926                    buf.call(UEvent::ThreadCreate(self.tid));
927                    cont = true;
928                }
929
930                if cont {
931                    ptrace::cont(Pid::from_raw(self.tid), None);
932                    continue;
933                }
934
935                break;
936            } else {
937                udbg_ui().warn(format!("{} is not traced", self.tid));
938                ptrace::cont(Pid::from_raw(self.tid), None);
939            }
940        }
941        Some(())
942    }
943
944    fn handle(&mut self, buf: &mut TraceBuf) -> Option<HandleResult> {
945        let status = self.status.clone();
946        let this = buf.target.clone();
947        let tid = self.tid;
948
949        if this.base.status.get() == UDbgStatus::Detaching {
950            return Some(None);
951        }
952        Some(match status {
953            WaitStatus::Stopped(_, sig) => loop {
954                if sig == Signal::SIGTRAP {
955                    if let Some(result) = this
956                        .handle_breakpoint(this.as_ref(), self, buf)
957                        .log_error("handle trap")
958                    {
959                        break result;
960                    }
961                }
962                break match buf.call(UEvent::Exception {
963                    first: true,
964                    code: sig as _,
965                }) {
966                    UserReply::Run(false) => Some(sig),
967                    reply => {
968                        this.handle_reply(this.as_ref(), reply, &mut buf.user);
969                        None
970                    }
971                };
972            },
973            WaitStatus::PtraceEvent(_, sig, code) => {
974                match code {
975                    PTRACE_EVENT_STOP => {
976                        this.insert_thread(tid);
977                    }
978                    PTRACE_EVENT_CLONE => {
979                        let new_tid =
980                            ptrace::getevent(Pid::from_raw(tid)).unwrap_or_default() as tid_t;
981                        buf.call(UEvent::ThreadCreate(new_tid));
982                        // trace new thread
983                        ptrace::attach(Pid::from_raw(new_tid));
984                    }
985                    PTRACE_EVENT_FORK | PTRACE_EVENT_VFORK => {
986                        let new_pid =
987                            ptrace::getevent(Pid::from_raw(tid)).unwrap_or_default() as pid_t;
988                        // info!("forked new pid: {new_pid}");
989                        // let newpid = Pid::from_raw(new_pid);
990                        // ptrace::detach(newpid, None);
991                        // ptrace::cont(newpid, None);
992                        ProcessTarget::open(new_pid)
993                            .log_error("open child")
994                            .map(|t| {
995                                t.base.status.set(if udbg_ui().base().trace_child.get() {
996                                    UDbgStatus::Attached
997                                } else {
998                                    UDbgStatus::Detaching
999                                });
1000                                self.targets.push(t);
1001                            });
1002                    }
1003                    PTRACE_EVENT_EXEC => {
1004                        buf.call(UEvent::ProcessCreate);
1005                    }
1006                    _ => {}
1007                }
1008                None
1009            }
1010            // exited with exception
1011            WaitStatus::Signaled(_, sig, coredump) => {
1012                buf.call(UEvent::Exception {
1013                    first: false,
1014                    code: sig as _,
1015                });
1016                let code = ptrace::getevent(Pid::from_raw(self.tid)).unwrap_or(-1);
1017                if !matches!(sig, Signal::SIGSTOP) {
1018                    if this.remove_thread(tid, code as _, buf) {
1019                        self.targets.retain(|t| !Arc::ptr_eq(t, &this));
1020                    }
1021                }
1022                Some(sig)
1023            }
1024            // exited normally
1025            WaitStatus::Exited(_, code) => {
1026                if this.remove_thread(tid, code, buf) {
1027                    self.targets.retain(|t| !Arc::ptr_eq(t, &this));
1028                }
1029                None
1030            }
1031            _ => unreachable!("status: {status:?}"),
1032        })
1033    }
1034
1035    fn cont(&mut self, sig: HandleResult, buf: &mut TraceBuf) {
1036        let this = buf.target.clone();
1037        let tid = Pid::from_raw(self.tid as _);
1038
1039        if this.base.status.get() == UDbgStatus::Detaching {
1040            for bp in this.get_breakpoints() {
1041                bp.enable(false);
1042            }
1043            for &tid in this.threads.read().iter() {
1044                ptrace::detach(Pid::from_raw(tid as _), None)
1045                    .log_error_with(|err| format!("ptrace_detach({tid}) failed: {err:?}"));
1046            }
1047            self.targets.retain(|t| !Arc::ptr_eq(&this, t));
1048            this.base.status.set(UDbgStatus::Detached);
1049        } else if buf.regs_dirty {
1050            buf.regs_dirty = false;
1051            buf.write_regs(self.tid);
1052        }
1053
1054        ptrace::cont(tid, sig);
1055    }
1056}
1057
1058pub struct DefaultEngine {
1059    pub targets: Vec<Arc<ProcessTarget>>,
1060    pub status: WaitStatus,
1061    pub inited: bool,
1062    pub cloned_tids: HashSet<tid_t>,
1063    pub tid: tid_t,
1064}
1065
1066impl Default for DefaultEngine {
1067    fn default() -> Self {
1068        Self {
1069            targets: Default::default(),
1070            status: WaitStatus::StillAlive,
1071            inited: false,
1072            tid: 0,
1073            cloned_tids: Default::default(),
1074        }
1075    }
1076}
1077
1078impl UDbgEngine for DefaultEngine {
1079    fn open(&mut self, pid: pid_t) -> UDbgResult<Arc<dyn UDbgTarget>> {
1080        Ok(ProcessTarget::open(pid)?)
1081    }
1082
1083    fn attach(&mut self, pid: pid_t) -> UDbgResult<Arc<dyn UDbgTarget>> {
1084        let this = ProcessTarget::open(pid)?;
1085        // attach each of threads
1086        for tid in this.process.tasks()?.filter_map(|t| t.ok().map(|t| t.tid)) {
1087            ptrace::attach(Pid::from_raw(tid)).with_context(|| format!("attach {tid}"))?;
1088        }
1089        // wait main thread
1090        waitpid(Pid::from_raw(pid), Some(WaitPidFlag::WUNTRACED))
1091            .with_context(|| format!("waitpid({pid})"))?;
1092        self.targets.push(this.clone());
1093        Ok(this)
1094    }
1095
1096    fn create(
1097        &mut self,
1098        path: &str,
1099        cwd: Option<&str>,
1100        args: &[&str],
1101    ) -> UDbgResult<Arc<dyn UDbgTarget>> {
1102        match unsafe { libc::fork() } {
1103            0 => unsafe {
1104                use std::ffi::CString;
1105                ptrace::traceme();
1106                let path = CString::new(path).unwrap();
1107                let args = args
1108                    .iter()
1109                    .map(|&arg| CString::new(arg).unwrap())
1110                    .collect::<Vec<_>>();
1111                let mut argv = args.iter().map(|arg| arg.as_ptr()).collect::<Vec<_>>();
1112                argv.insert(0, path.as_ptr());
1113                argv.push(core::ptr::null());
1114                libc::execvp(path.as_ptr().cast(), argv.as_ptr());
1115                unreachable!();
1116            },
1117            -1 => Err(UDbgError::system()),
1118            pid => {
1119                waitpid(Pid::from_raw(pid), Some(WaitPidFlag::WUNTRACED))
1120                    .with_context(|| format!("waitpid({pid})"))?;
1121                let ps = Process::from_pid(pid).context("open")?;
1122                let this = Arc::new(ProcessTarget(TargetCommon::new(ps)));
1123                self.targets.push(this.clone());
1124                Ok(this)
1125            }
1126        }
1127    }
1128
1129    fn event_loop<'a>(&mut self, callback: &mut UDbgCallback<'a>) -> UDbgResult<()> {
1130        self.targets.iter().for_each(|t| {
1131            t.update_module();
1132            t.update_memory_page();
1133        });
1134
1135        let target = self
1136            .targets
1137            .iter()
1138            .next()
1139            .map(Clone::clone)
1140            .context("no attached target")?;
1141
1142        self.tid = target.process.pid;
1143        let buf = &mut TraceBuf {
1144            callback,
1145            user: unsafe { core::mem::zeroed() },
1146            si: unsafe { core::mem::zeroed() },
1147            regs_dirty: false,
1148            target,
1149        };
1150
1151        buf.target.base.event_tid.set(self.tid);
1152        buf.target.insert_thread(self.tid);
1153
1154        if buf.target.base.status.get() == UDbgStatus::Detaching {
1155            self.cont(None, buf);
1156            return Ok(());
1157        }
1158        buf.target.base.status.set(UDbgStatus::Attached);
1159
1160        buf.call(UEvent::InitBp);
1161        buf.call(UEvent::ProcessCreate);
1162        buf.call(UEvent::ThreadCreate(self.tid));
1163        self.cont(None, buf);
1164
1165        while let Some(s) = self.fetch(buf).and_then(|_| self.handle(buf)) {
1166            self.cont(s, buf);
1167            if self.targets.is_empty() {
1168                break;
1169            }
1170        }
1171
1172        Ok(())
1173    }
1174}