libsdb/
target.rs

1use std::any::Any;
2use std::cell::{RefCell, RefMut};
3use std::collections::HashMap;
4use std::io::Write;
5use std::path::{Path, PathBuf};
6use std::rc::{Rc, Weak};
7
8use elf::abi::STT_FUNC;
9use gimli::{DW_AT_location, DW_AT_object_pointer, DW_AT_type, DW_TAG_subprogram};
10use goblin::elf::sym::st_type;
11use nix::libc::{AT_ENTRY, SIGTRAP};
12use nix::unistd::Pid;
13use typed_builder::TypedBuilder;
14
15use super::bit::to_byte_vec;
16
17use super::traits::FromLowerHexStr;
18use super::types::BuiltinType;
19use super::types::SdbType;
20use super::types::TypedData;
21use super::types::{read_return_value, setup_arguments};
22
23use super::bit::memcpy_bits;
24
25use super::dwarf::DwarfExpressionResult;
26use super::dwarf::DwarfExpressionSimpleLocation;
27use super::register_info::register_info_by_dwarf;
28use super::registers::RegisterValue;
29
30use super::process::ThreadState;
31
32use super::elf::SdbElf64Ehdr;
33
34use super::elf::ElfCollection;
35
36use super::ffi::r_debug;
37
38use super::breakpoint::AddressBreakpoint;
39use super::breakpoint::FunctionBreakpoint;
40use super::breakpoint::LineBreakpoint;
41
42use super::stoppoint_collection::StoppointCollection;
43
44use super::dwarf::Die;
45use super::elf::SdbElf64Sym;
46
47use super::disassembler::Disassembler;
48use super::dwarf::LineTableIter;
49use super::elf::Elf;
50use super::process::Process;
51use super::process::StopReason;
52use super::process::{ProcessState, TrapType};
53use super::register_info::RegisterId;
54use super::sdb_error::SdbError;
55use super::stack::Stack;
56use super::traits::StoppointTrait;
57use super::types::FileAddress;
58use super::types::VirtualAddress;
59
60pub struct EvaluateExpressionResult {
61    pub return_value: TypedData,
62    pub id: u64,
63}
64
65pub struct Target {
66    process: Rc<Process>,
67    main_elf: Weak<Elf>,
68    elves: RefCell<ElfCollection>,
69    breakpoints: RefCell<StoppointCollection>,
70    dynamic_linker_rendezvous_address: RefCell<VirtualAddress>,
71    threads: RefCell<HashMap<Pid, SdbThread>>,
72    expression_results: RefCell<Vec<TypedData>>,
73}
74
75fn get_initial_variable_data(
76    target: &Target,
77    name: &str,
78    pc: &FileAddress,
79) -> Result<TypedData, SdbError> {
80    if let Some(name) = name.strip_prefix('$') {
81        let index = usize::from_integral(name);
82        if index.is_err() {
83            return SdbError::err("Invalid expression result index");
84        }
85        return target.get_expression_result(index.unwrap());
86    }
87
88    let var = target.find_variable(name, pc)?;
89    if var.is_none() {
90        return SdbError::err("Cannot find variable");
91    }
92    let var = var.unwrap();
93    let var_type = var.index(DW_AT_type.0 as u64)?.as_type();
94    let loc = var.index(DW_AT_location.0 as u64)?.as_evaluated_location(
95        &target.get_process(),
96        &target.get_stack(None).borrow().current_frame().registers,
97        false,
98    )?;
99    let data_vec = target.read_location_data(&loc, var_type.byte_size()?, None)?;
100
101    let mut address = None;
102    if let DwarfExpressionResult::SimpleLocation(simple_loc) = loc
103        && let DwarfExpressionSimpleLocation::Address { address: addr } = simple_loc
104    {
105        address = Some(addr);
106    }
107    Ok(TypedData::builder()
108        .data(data_vec)
109        .type_(var_type)
110        .address(address)
111        .build())
112}
113
114pub struct ResolveIndirectNameResult {
115    pub variable: Option<TypedData>,
116    pub funcs: Vec<Rc<Die>>,
117}
118
119impl Target {
120    pub fn notify_thread_lifecycle_event(self: &Rc<Self>, reason: &StopReason) {
121        let tid = reason.tid;
122        if reason.reason == ProcessState::Stopped {
123            let state = self
124                .process
125                .thread_states()
126                .borrow()
127                .get(&tid)
128                .unwrap()
129                .clone();
130            self.threads.borrow_mut().insert(
131                tid,
132                SdbThread::new(Rc::downgrade(&state), Stack::new(&Rc::downgrade(self), tid)),
133            );
134        } else {
135            self.threads.borrow_mut().remove(&tid);
136        }
137    }
138
139    pub fn create_address_breakpoint(
140        self: &Rc<Self>,
141        address: VirtualAddress,
142        is_hardware: bool,
143        is_internal: bool,
144    ) -> Result<Weak<RefCell<dyn StoppointTrait>>, SdbError> {
145        let breakpoint = Rc::new(RefCell::new(AddressBreakpoint::new(
146            self,
147            address,
148            is_hardware,
149            is_internal,
150        )?));
151        let breakpoint = self
152            .breakpoints
153            .borrow_mut()
154            .push_strong(breakpoint.clone());
155        Ok(breakpoint)
156    }
157
158    pub fn create_function_breakpoint(
159        self: &Rc<Self>,
160        function_name: &str,
161        is_hardware: bool,
162        is_internal: bool,
163    ) -> Result<Weak<RefCell<dyn StoppointTrait>>, SdbError> {
164        let breakpoint = Rc::new(RefCell::new(FunctionBreakpoint::new(
165            self,
166            function_name,
167            is_hardware,
168            is_internal,
169        )?));
170        let breakpoint = self
171            .breakpoints
172            .borrow_mut()
173            .push_strong(breakpoint.clone());
174        Ok(breakpoint)
175    }
176
177    pub fn create_line_breakpoint(
178        self: &Rc<Self>,
179        file: &Path,
180        line: usize,
181        is_hardware: bool,
182        is_internal: bool,
183    ) -> Result<Weak<RefCell<dyn StoppointTrait>>, SdbError> {
184        let breakpoint = Rc::new(RefCell::new(LineBreakpoint::new(
185            self,
186            file,
187            line,
188            is_hardware,
189            is_internal,
190        )?));
191        let breakpoint = self
192            .breakpoints
193            .borrow_mut()
194            .push_strong(breakpoint.clone());
195        Ok(breakpoint)
196    }
197
198    pub fn resolve_dynamic_linker_rendezvous(self: &Rc<Self>) -> Result<(), SdbError> {
199        if self.dynamic_linker_rendezvous_address.borrow().addr() != 0 {
200            return Ok(());
201        }
202
203        let dynamic_section = self
204            .main_elf
205            .upgrade()
206            .unwrap()
207            .get_section(".dynamic")
208            .unwrap();
209        let dynamic_start =
210            FileAddress::new(&self.main_elf.upgrade().unwrap(), dynamic_section.0.sh_addr);
211        let dynamic_size = dynamic_section.0.sh_size as usize;
212        let dynamic_bytes = self
213            .process
214            .read_memory(dynamic_start.to_virt_addr(), dynamic_size)?;
215
216        let entry_size = std::mem::size_of::<super::ffi::Elf64_Dyn>();
217        let num_entries = dynamic_size / entry_size;
218
219        for i in 0..num_entries {
220            let start_idx = i * entry_size;
221            let end_idx = start_idx + entry_size;
222            if end_idx > dynamic_bytes.len() {
223                break;
224            }
225
226            let entry_bytes = &dynamic_bytes[start_idx..end_idx];
227            let entry: super::ffi::Elf64_Dyn =
228                unsafe { std::ptr::read(entry_bytes.as_ptr() as *const super::ffi::Elf64_Dyn) };
229
230            if entry.d_tag == super::ffi::DT_DEBUG as i64 {
231                let rendezvous_addr = VirtualAddress::new(unsafe { entry.d_un.d_ptr });
232                *self.dynamic_linker_rendezvous_address.borrow_mut() = rendezvous_addr;
233                self.reload_dynamic_libraries()?;
234
235                let debug_info = self.read_dynamic_linker_rendezvous()?.unwrap();
236                let debug_state_addr = VirtualAddress::new(debug_info.r_brk);
237                let debug_state_bp =
238                    self.create_address_breakpoint(debug_state_addr, false, true)?;
239                let debug_state_bp = debug_state_bp.upgrade().unwrap();
240                let bp_ref = debug_state_bp.borrow_mut();
241                let mut bp = bp_ref as RefMut<dyn std::any::Any>;
242                let breakpoint = bp.downcast_mut::<AddressBreakpoint>().unwrap();
243                let target_clone = self.clone();
244                breakpoint
245                    .breakpoint
246                    .borrow_mut()
247                    .install_hit_handler(move || {
248                        target_clone.reload_dynamic_libraries()?;
249                        Ok(true)
250                    });
251                breakpoint.enable()?;
252            }
253        }
254
255        Ok(())
256    }
257
258    pub fn inferior_malloc(&self, size: usize) -> Result<VirtualAddress, SdbError> {
259        let saved_regs = self.process.get_registers(None);
260
261        let malloc_funcs = self.find_functions("malloc")?.elf_functions;
262        let malloc_func = malloc_funcs
263            .iter()
264            .find(|(_, sym)| sym.0.st_value != 0)
265            .ok_or_else(|| SdbError::new_err("malloc not found"))?;
266
267        let malloc_addr = FileAddress::new(&malloc_func.0, malloc_func.1.0.st_value);
268        let call_addr = malloc_addr.to_virt_addr();
269
270        let entry_point = VirtualAddress::new(self.process.get_auxv()[&(AT_ENTRY as i32)]);
271        {
272            let breakpoint = self.breakpoints.borrow().get_by_address(entry_point)?;
273            let mut breakpoint = breakpoint.borrow_mut() as RefMut<dyn Any>;
274            let breakpoint = breakpoint.downcast_mut::<AddressBreakpoint>().unwrap();
275            breakpoint
276                .breakpoint
277                .borrow_mut()
278                .install_hit_handler(move || Ok(false));
279        }
280
281        self.process.get_registers(None).borrow_mut().write_by_id(
282            RegisterId::rdi,
283            size as u64,
284            true,
285        )?;
286
287        let saved_regs_clone = saved_regs.borrow().clone();
288        let new_regs =
289            self.process
290                .inferior_call(call_addr, entry_point, saved_regs_clone, None)?;
291        let result = new_regs.read_by_id_as::<u64>(RegisterId::rax)?;
292
293        Ok(VirtualAddress::new(result))
294    }
295
296    pub fn evaluate_expression(
297        &self,
298        expr: &str,
299        otid: Option<Pid>, /* None */
300    ) -> Result<Option<EvaluateExpressionResult>, SdbError> {
301        let tid = otid.unwrap_or(self.process.current_thread());
302        let pc = self.get_pc_file_address(Some(tid));
303        let paren_pos = expr.find('(');
304        if paren_pos.is_none() {
305            return SdbError::err("Invalid expression");
306        }
307        let paren_pos = paren_pos.unwrap();
308
309        let name = &expr[..paren_pos + 1];
310        let res = self.resolve_indirect_name(name, &pc)?;
311        if res.funcs.is_empty() {
312            return SdbError::err("Invalid expression");
313        }
314
315        let entry_point = VirtualAddress::new(self.process.get_auxv()[&(AT_ENTRY as i32)]);
316        {
317            let breakpoint = self.breakpoints.borrow().get_by_address(entry_point)?;
318            let mut breakpoint = breakpoint.borrow_mut() as RefMut<dyn Any>;
319            let breakpoint = breakpoint.downcast_mut::<AddressBreakpoint>().unwrap();
320            breakpoint
321                .breakpoint
322                .borrow_mut()
323                .install_hit_handler(move || Ok(false));
324        }
325
326        let arg_string = &expr[paren_pos..];
327        let args = collect_arguments(self, tid, arg_string, &res.funcs, res.variable)?;
328        let func = resolve_overload(&res.funcs, &args)?;
329        let ret = inferior_call_from_dwarf(self, &func, &args, entry_point, tid)?;
330        if let Some(ret_data) = ret {
331            self.expression_results.borrow_mut().push(ret_data.clone());
332            return Ok(Some(EvaluateExpressionResult {
333                return_value: ret_data,
334                id: (self.expression_results.borrow().len() - 1) as u64,
335            }));
336        }
337        Ok(None)
338    }
339
340    pub fn get_expression_result(&self, index: usize) -> Result<TypedData, SdbError> {
341        let res = &self.expression_results.borrow()[index];
342        let new_data = self
343            .process
344            .read_memory(res.address().unwrap(), res.value_type().byte_size()?)?;
345        Ok(TypedData::builder()
346            .data(new_data)
347            .type_(res.value_type().clone())
348            .address(res.address())
349            .build())
350    }
351
352    pub fn resolve_indirect_name(
353        &self,
354        mut name: &str,
355        pc: &FileAddress,
356    ) -> Result<ResolveIndirectNameResult, SdbError> {
357        let mut op_pos = name
358            .chars()
359            .enumerate()
360            .find(|(_, c)| *c == '.' || *c == '-' || *c == '[' || *c == '(')
361            .map(|(i, _)| i)
362            .or(Some(name.len()));
363
364        if op_pos.unwrap() < name.len() && name.chars().nth(op_pos.unwrap()).unwrap() == '(' {
365            let func_name = &name[..op_pos.unwrap()];
366            let funcs = self.find_functions(func_name)?;
367            return Ok(ResolveIndirectNameResult {
368                variable: None,
369                funcs: funcs.dwarf_functions,
370            });
371        }
372
373        let var_name = &name[..op_pos.unwrap()];
374        let mut data = get_initial_variable_data(self, var_name, pc)?;
375        while let Some(pos) = op_pos
376            && pos < name.len()
377        {
378            if name.chars().nth(pos).unwrap() == '-' {
379                if name.chars().nth(pos + 1).map(|c| c != '>').unwrap_or(true) {
380                    return SdbError::err("Invalid operator");
381                }
382                data = data.deref_pointer(&self.get_process())?;
383                op_pos = Some(pos + 1);
384            }
385            if name.chars().nth(op_pos.unwrap()).unwrap() == '.'
386                || name.chars().nth(op_pos.unwrap()).unwrap() == '>'
387            {
388                let member_name_start = op_pos.unwrap() + 1;
389                op_pos = name
390                    .chars()
391                    .enumerate()
392                    .skip(member_name_start)
393                    .find(|(_, c)| *c == '.' || *c == '-' || *c == '[' || *c == '(' || *c == ',')
394                    .map(|(i, _)| i)
395                    .or(Some(name.len()));
396                let member_name = &name[member_name_start..op_pos.unwrap()];
397                if op_pos.is_some()
398                    && op_pos.unwrap() < name.len()
399                    && name.chars().nth(op_pos.unwrap()).unwrap() == '('
400                {
401                    let mut funcs = Vec::new();
402                    let stripped_value_type = data.value_type().strip_cvref_typedef()?;
403                    for child in stripped_value_type.get_die()?.children() {
404                        if child.abbrev_entry().tag as u16 == DW_TAG_subprogram.0
405                            && child.contains(DW_AT_object_pointer.0 as u64)
406                            && child
407                                .name()?
408                                .map(|name| name == member_name)
409                                .unwrap_or(false)
410                        {
411                            funcs.push(child);
412                        }
413                    }
414                    if funcs.is_empty() {
415                        return SdbError::err("No such member function");
416                    }
417                    return Ok(ResolveIndirectNameResult {
418                        variable: Some(data),
419                        funcs,
420                    });
421                }
422                data = data.read_member(&self.get_process(), member_name)?;
423                name = &name[member_name_start..];
424            } else if name.chars().nth(op_pos.unwrap()).unwrap() == '[' {
425                let int_end = name.find(']').unwrap_or(name.len());
426                let index_str = &name[op_pos.unwrap() + 1..int_end];
427                let index = usize::from_integral(index_str);
428                if index.is_err() {
429                    return SdbError::err("Invalid index");
430                }
431                data = data.index(&self.get_process(), index.unwrap())?;
432                name = &name[int_end + 1..];
433            }
434
435            op_pos = name
436                .chars()
437                .enumerate()
438                .find(|(_, c)| *c == '.' || *c == '-' || *c == '[' || *c == '(' || *c == ',')
439                .map(|(i, _)| i)
440                .or(Some(name.len()));
441        }
442
443        Ok(ResolveIndirectNameResult {
444            variable: Some(data),
445            funcs: Vec::new(),
446        })
447    }
448
449    pub fn find_variable(&self, name: &str, pc: &FileAddress) -> Result<Option<Rc<Die>>, SdbError> {
450        let dwarf = pc.rc_elf_file().get_dwarf();
451        let local = dwarf.find_local_variable(name, pc)?;
452        if local.is_some() {
453            return Ok(local);
454        }
455
456        let mut global = None;
457        for elf in self.elves.borrow().iter() {
458            let dwarf = elf.get_dwarf();
459            let found = dwarf.find_global_variable(name)?;
460            if found.is_some() {
461                global = found;
462            }
463        }
464        Ok(global)
465    }
466
467    pub fn read_location_data(
468        &self,
469        loc: &DwarfExpressionResult,
470        size: usize,
471        otid: Option<Pid>, /* None */
472    ) -> Result<Vec<u8>, SdbError> {
473        let tid = otid.unwrap_or(self.process.current_thread());
474
475        match loc {
476            DwarfExpressionResult::SimpleLocation(simple_loc) => match simple_loc {
477                DwarfExpressionSimpleLocation::Register { reg_num } => {
478                    let reg_info = register_info_by_dwarf(*reg_num as i32)?;
479                    let reg_value = self
480                        .threads
481                        .borrow()
482                        .get(&tid)
483                        .unwrap()
484                        .frames
485                        .borrow()
486                        .current_frame()
487                        .registers
488                        .read(&reg_info)?;
489
490                    let get_bytes = |value: RegisterValue| -> Vec<u8> {
491                        match value {
492                            RegisterValue::U8(v) => vec![v],
493                            RegisterValue::U16(v) => v.to_le_bytes().to_vec(),
494                            RegisterValue::U32(v) => v.to_le_bytes().to_vec(),
495                            RegisterValue::U64(v) => v.to_le_bytes().to_vec(),
496                            RegisterValue::I8(v) => (v as u8).to_le_bytes().to_vec(),
497                            RegisterValue::I16(v) => (v as u16).to_le_bytes().to_vec(),
498                            RegisterValue::I32(v) => (v as u32).to_le_bytes().to_vec(),
499                            RegisterValue::I64(v) => (v as u64).to_le_bytes().to_vec(),
500                            RegisterValue::Float(v) => v.to_le_bytes().to_vec(),
501                            RegisterValue::Double(v) => v.to_le_bytes().to_vec(),
502                            RegisterValue::LongDouble(v) => v.0.to_le_bytes().to_vec(),
503                            RegisterValue::Byte64(b) => b.to_vec(),
504                            RegisterValue::Byte128(b) => b.to_vec(),
505                        }
506                    };
507
508                    Ok(get_bytes(reg_value))
509                }
510                DwarfExpressionSimpleLocation::Address { address } => {
511                    Ok(self.process.read_memory(*address, size)?)
512                }
513                DwarfExpressionSimpleLocation::Data { data } => Ok(data.to_vec()),
514                DwarfExpressionSimpleLocation::Literal { value } => {
515                    let bytes = value.to_le_bytes();
516                    Ok(bytes[..size].to_vec())
517                }
518                DwarfExpressionSimpleLocation::Empty {} => SdbError::err("Empty location"),
519            },
520            DwarfExpressionResult::Pieces(pieces_res) => {
521                let mut data = vec![0u8; size];
522                let mut offset = 0usize;
523
524                for piece in &pieces_res.pieces {
525                    let byte_size = piece.bit_size.div_ceil(8);
526                    let piece_data = self.read_location_data(
527                        &DwarfExpressionResult::SimpleLocation(piece.location.clone()),
528                        byte_size as usize,
529                        otid,
530                    )?;
531
532                    if offset % 8 == 0 && piece.offset == 0 && piece.bit_size % 8 == 0 {
533                        let dest_byte_offset = offset / 8;
534                        let copy_len = piece_data.len().min(data.len() - dest_byte_offset);
535                        data[dest_byte_offset..dest_byte_offset + copy_len]
536                            .copy_from_slice(&piece_data[..copy_len]);
537                        offset += piece.bit_size as usize;
538                    } else {
539                        memcpy_bits(
540                            &mut data,
541                            0,
542                            &piece_data,
543                            piece.offset as u32,
544                            piece.bit_size as u32,
545                        );
546                    }
547                }
548
549                Ok(data)
550            }
551        }
552    }
553
554    pub fn threads(&self) -> &RefCell<HashMap<Pid, SdbThread>> {
555        &self.threads
556    }
557
558    fn new(process: Rc<Process>, elf: Rc<Elf>) -> Rc<Self> {
559        Rc::new_cyclic(|weak_self| Self {
560            process: process.clone(),
561            main_elf: Rc::downgrade(&elf),
562            elves: RefCell::new({
563                let mut t = ElfCollection::default();
564                t.push(elf.clone());
565                t
566            }),
567            breakpoints: RefCell::new(StoppointCollection::default()),
568            dynamic_linker_rendezvous_address: RefCell::new(VirtualAddress::default()),
569            threads: RefCell::new({
570                let threads = process.thread_states();
571                let mut ret = HashMap::new();
572                for (tid, state) in threads.borrow().iter() {
573                    ret.insert(
574                        *tid,
575                        SdbThread::new(Rc::downgrade(state), Stack::new(weak_self, *tid)),
576                    );
577                }
578                ret
579            }),
580            expression_results: RefCell::new(Vec::new()),
581        })
582    }
583
584    pub fn get_stack(&self, otid: Option<Pid>) -> Rc<RefCell<Stack>> {
585        let tid = otid.unwrap_or(self.process.current_thread());
586        self.threads.borrow().get(&tid).unwrap().frames.clone()
587    }
588
589    pub fn launch(path: &Path, stdout_replacement: Option<i32>) -> Result<Rc<Self>, SdbError> {
590        let proc = Process::launch(path, true, stdout_replacement)?;
591        let obj = create_loaded_elf(&proc, path)?;
592        let tgt = Target::new(proc, obj);
593        tgt.process.set_target(&tgt);
594        let entry_point = VirtualAddress::new(tgt.get_process().get_auxv()[&(AT_ENTRY as i32)]);
595        let entry_bp = tgt.create_address_breakpoint(entry_point, false, true)?;
596        let entry_bp = entry_bp.upgrade().unwrap();
597        let entry_bp = entry_bp.borrow_mut();
598        let mut entry_bp = entry_bp as RefMut<dyn Any>;
599        let entry_bp = entry_bp.downcast_mut::<AddressBreakpoint>().unwrap();
600        let tgt_clone = tgt.clone();
601        entry_bp
602            .breakpoint
603            .borrow_mut()
604            .install_hit_handler(move || {
605                tgt_clone.resolve_dynamic_linker_rendezvous()?;
606                Ok(true)
607            });
608        entry_bp.enable()?;
609        Ok(tgt)
610    }
611
612    pub fn attach(pid: Pid) -> Result<Rc<Self>, SdbError> {
613        let elf_path = PathBuf::from("/proc").join(pid.to_string()).join("exe");
614        let proc = Process::attach(pid)?;
615        let obj = create_loaded_elf(&proc, &elf_path)?;
616        let tgt = Target::new(proc, obj);
617        tgt.process.set_target(&tgt);
618        tgt.resolve_dynamic_linker_rendezvous()?;
619        Ok(tgt)
620    }
621
622    pub fn get_process(&self) -> Rc<Process> {
623        self.process.clone()
624    }
625
626    pub fn get_main_elf(&self) -> Weak<Elf> {
627        self.main_elf.clone()
628    }
629
630    pub fn notify_stop(&self, reason: &StopReason) -> Result<(), SdbError> {
631        self.threads
632            .borrow()
633            .get(&reason.tid)
634            .unwrap()
635            .frames
636            .borrow_mut()
637            .unwind()
638    }
639
640    pub fn get_pc_file_address(&self, otid: Option<Pid>) -> FileAddress {
641        self.process
642            .get_pc(otid)
643            .to_file_addr_elves(&self.elves.borrow())
644    }
645
646    pub fn step_in(&self, otid: Option<Pid>) -> Result<StopReason, SdbError> {
647        let tid = otid.unwrap_or(self.process.current_thread());
648        let stack = self.get_stack(Some(tid));
649        if stack.borrow().inline_height() > 0 {
650            stack.borrow_mut().simulate_inlined_step_in();
651            let reason = StopReason::builder()
652                .tid(tid)
653                .reason(ProcessState::Stopped)
654                .info(SIGTRAP)
655                .trap_reason(Some(TrapType::SingleStep))
656                .build();
657            self.threads
658                .borrow()
659                .get(&tid)
660                .unwrap()
661                .state
662                .upgrade()
663                .unwrap()
664                .borrow_mut()
665                .reason = reason;
666            return Ok(reason);
667        }
668        let orig_line = self.line_entry_at_pc(Some(tid))?;
669        loop {
670            let reason = self.process.step_instruction(Some(tid))?;
671            if !reason.is_step() {
672                self.threads
673                    .borrow()
674                    .get(&tid)
675                    .unwrap()
676                    .state
677                    .upgrade()
678                    .unwrap()
679                    .borrow_mut()
680                    .reason = reason;
681                return Ok(reason);
682            }
683            if !((self.line_entry_at_pc(Some(tid))? == orig_line
684                || self.line_entry_at_pc(Some(tid))?.get_current().end_sequence)
685                && !self.line_entry_at_pc(Some(tid))?.is_end())
686            {
687                break;
688            }
689        }
690        let pc = self.get_pc_file_address(Some(tid));
691        if pc.has_elf() {
692            let dwarf = pc.rc_elf_file().get_dwarf();
693            let func = dwarf.function_containing_address(&pc)?;
694            if func.is_some() && func.as_ref().unwrap().low_pc()? == pc {
695                let mut line = self.line_entry_at_pc(Some(tid))?;
696                if !line.is_end() {
697                    line.step()?;
698                    return self
699                        .run_until_address(line.get_current().address.to_virt_addr(), Some(tid));
700                }
701            }
702        }
703        Ok(StopReason::builder()
704            .tid(tid)
705            .reason(ProcessState::Stopped)
706            .info(SIGTRAP)
707            .trap_reason(Some(TrapType::SingleStep))
708            .build())
709    }
710
711    pub fn step_out(&self, otid: Option<Pid>) -> Result<StopReason, SdbError> {
712        let tid = otid.unwrap_or(self.process.current_thread());
713        let stack = self.get_stack(Some(tid));
714        let inline_stack = stack.borrow().inline_stack_at_pc()?;
715        let has_inline_frames = inline_stack.len() > 1;
716        let at_inline_frame = (stack.borrow().inline_height() as usize) < (inline_stack.len() - 1);
717        if has_inline_frames && at_inline_frame {
718            let current_frame =
719                &inline_stack[inline_stack.len() - stack.borrow().inline_height() as usize - 1];
720            let return_address = current_frame.high_pc()?.to_virt_addr();
721            return self.run_until_address(return_address, Some(tid));
722        }
723
724        let return_address = VirtualAddress::new(
725            stack.borrow().frames()[stack.borrow().current_frame_index() + 1]
726                .registers
727                .read_by_id_as::<u64>(RegisterId::rip)?,
728        );
729        let mut reason = StopReason::builder().build();
730        let frames = stack.borrow().frames().len();
731        while stack.borrow().frames().len() >= frames {
732            reason = self.run_until_address(return_address, Some(tid))?;
733            if !reason.is_breakpoint() || self.process.get_pc(None) != return_address {
734                return Ok(reason);
735            }
736        }
737        Ok(reason)
738    }
739
740    pub fn step_over(&self, otid: Option<Pid>) -> Result<StopReason, SdbError> {
741        let tid = otid.unwrap_or(self.process.current_thread());
742        let stack = self.get_stack(Some(tid));
743        let orig_line = self.line_entry_at_pc(Some(tid))?;
744        let disas = Disassembler::new(&self.process);
745        let mut reason;
746        loop {
747            let inline_stack = stack.borrow().inline_stack_at_pc()?;
748            let at_start_of_inline_frame = stack.borrow().inline_height() > 0;
749            if at_start_of_inline_frame {
750                let frame_to_skip =
751                    &inline_stack[inline_stack.len() - stack.borrow().inline_height() as usize];
752                let return_address = frame_to_skip.high_pc()?.to_virt_addr();
753                reason = self.run_until_address(return_address, Some(tid))?;
754                if !reason.is_step() || self.process.get_pc(Some(tid)) != return_address {
755                    self.threads
756                        .borrow()
757                        .get(&tid)
758                        .unwrap()
759                        .state
760                        .upgrade()
761                        .unwrap()
762                        .borrow_mut()
763                        .reason = reason;
764                    return Ok(reason);
765                }
766            } else {
767                let instructions = disas.disassemble(2, Some(self.process.get_pc(Some(tid))))?;
768                if instructions[0].text.rfind("call") == Some(0) {
769                    reason = self.run_until_address(instructions[1].address, Some(tid))?;
770                    if !reason.is_step()
771                        || self.process.get_pc(Some(tid)) != instructions[1].address
772                    {
773                        self.threads
774                            .borrow()
775                            .get(&tid)
776                            .unwrap()
777                            .state
778                            .upgrade()
779                            .unwrap()
780                            .borrow_mut()
781                            .reason = reason;
782                        return Ok(reason);
783                    }
784                } else {
785                    reason = self.process.step_instruction(Some(tid))?;
786                    if !reason.is_step() {
787                        self.threads
788                            .borrow()
789                            .get(&tid)
790                            .unwrap()
791                            .state
792                            .upgrade()
793                            .unwrap()
794                            .borrow_mut()
795                            .reason = reason;
796                        return Ok(reason);
797                    }
798                }
799            }
800
801            if !((self.line_entry_at_pc(Some(tid))? == orig_line
802                || self.line_entry_at_pc(Some(tid))?.get_current().end_sequence)
803                && !self.line_entry_at_pc(Some(tid))?.is_end())
804            {
805                break;
806            }
807        }
808        Ok(reason)
809    }
810
811    pub fn line_entry_at_pc(&self, otid: Option<Pid>) -> Result<LineTableIter, SdbError> {
812        let pc = self.get_pc_file_address(otid);
813        if !pc.has_elf() {
814            return Ok(LineTableIter::default());
815        }
816        let dwarf = pc.rc_elf_file().get_dwarf();
817        let cu = dwarf.compile_unit_containing_address(&pc)?;
818        if cu.is_none() {
819            return Ok(LineTableIter::default());
820        }
821        cu.unwrap().lines().get_entry_by_address(&pc)
822    }
823
824    fn run_until_address(
825        &self,
826        address: VirtualAddress,
827        otid: Option<Pid>,
828    ) -> Result<StopReason, SdbError> {
829        let tid = otid.unwrap_or(self.process.current_thread());
830        let mut breakpoint_to_remove = None;
831        if !self
832            .process
833            .breakpoint_sites()
834            .borrow()
835            .contains_address(address)
836        {
837            breakpoint_to_remove = Some(self.process.create_breakpoint_site(address, false, true)?);
838            breakpoint_to_remove
839                .as_ref()
840                .unwrap()
841                .upgrade()
842                .unwrap()
843                .borrow_mut()
844                .enable()?;
845        }
846        self.process.resume(Some(tid))?;
847        let mut reason = self.process.wait_on_signal(tid)?;
848        if reason.is_breakpoint() && self.process.get_pc(Some(tid)) == address {
849            reason.trap_reason = Some(TrapType::SingleStep);
850        }
851        if breakpoint_to_remove.is_some() {
852            self.process
853                .breakpoint_sites()
854                .borrow_mut()
855                .remove_by_address({
856                    breakpoint_to_remove
857                        .unwrap()
858                        .upgrade()
859                        .unwrap()
860                        .borrow()
861                        .address()
862                })?;
863        }
864        self.threads
865            .borrow_mut()
866            .get_mut(&tid)
867            .unwrap()
868            .state
869            .upgrade()
870            .unwrap()
871            .borrow_mut()
872            .reason = reason;
873        Ok(reason)
874    }
875
876    pub fn find_functions(&self, name: &str) -> Result<FindFunctionsResult, SdbError> {
877        let mut result = FindFunctionsResult {
878            dwarf_functions: Vec::new(),
879            elf_functions: Vec::new(),
880        };
881        for elf in self.elves.borrow().iter() {
882            let dwarf_found = elf.get_dwarf().find_functions(name)?;
883            if dwarf_found.is_empty() {
884                let elf_found = elf.get_symbols_by_name(name);
885                for sym in &elf_found {
886                    result.elf_functions.push((elf.clone(), sym.clone()));
887                }
888            } else {
889                result.dwarf_functions.extend(dwarf_found);
890            }
891        }
892
893        Ok(result)
894    }
895
896    pub fn breakpoints(&self) -> &RefCell<StoppointCollection> {
897        &self.breakpoints
898    }
899
900    pub fn function_name_at_address(&self, address: VirtualAddress) -> Result<String, SdbError> {
901        let file_address = address.to_file_addr_elves(&self.elves.borrow());
902        let obj = file_address.rc_elf_file();
903        let func = obj.get_dwarf().function_containing_address(&file_address)?;
904        let elf_filename = obj
905            .path()
906            .file_name()
907            .and_then(|name| name.to_str())
908            .unwrap_or("")
909            .to_string();
910        let mut func_name = String::new();
911
912        if let Some(func) = func
913            && let Some(name) = func.name()?
914        {
915            func_name = name;
916        } else {
917            let elf_func = obj.get_symbol_containing_file_address(file_address);
918            if let Some(elf_func) = elf_func
919                && st_type(elf_func.0.st_info) == STT_FUNC
920            {
921                func_name = obj.get_string(elf_func.0.st_name as usize).to_string();
922            }
923        }
924
925        if !func_name.is_empty() {
926            return Ok(format!("{elf_filename}`{func_name}"));
927        }
928        Ok(String::new())
929    }
930
931    pub fn read_dynamic_linker_rendezvous(&self) -> Result<Option<r_debug>, SdbError> {
932        if self.dynamic_linker_rendezvous_address.borrow().addr() != 0 {
933            return Ok(Some(self.process.read_memory_as::<r_debug>(
934                *self.dynamic_linker_rendezvous_address.borrow(),
935            )?));
936        }
937        Ok(None)
938    }
939
940    fn reload_dynamic_libraries(&self) -> Result<(), SdbError> {
941        let debug = self.read_dynamic_linker_rendezvous()?;
942        if debug.is_none() {
943            return Ok(());
944        }
945
946        let debug = debug.unwrap();
947        let mut entry_ptr = debug.r_map;
948
949        while !entry_ptr.is_null() {
950            let entry_addr = VirtualAddress::new(entry_ptr as u64);
951            let entry = self
952                .process
953                .read_memory_as::<super::ffi::link_map>(entry_addr)?;
954            entry_ptr = entry.l_next;
955
956            let name_addr = VirtualAddress::new(entry.l_name as u64);
957            let name_bytes = self.process.read_memory(name_addr, 4096)?;
958
959            let null_pos = name_bytes
960                .iter()
961                .position(|&b| b == 0)
962                .unwrap_or(name_bytes.len());
963            let name_str = String::from_utf8_lossy(&name_bytes[..null_pos]);
964            let name = PathBuf::from(name_str.as_ref());
965
966            if name_str.is_empty() {
967                continue;
968            }
969
970            const VDSO_NAME: &str = "linux-vdso.so.1";
971            let found = if name_str == VDSO_NAME {
972                self.elves.borrow().get_elf_by_filename(VDSO_NAME)
973            } else {
974                self.elves.borrow().get_elf_by_path(&name)
975            };
976
977            if found.upgrade().is_none() {
978                let elf_path = if name_str == VDSO_NAME {
979                    dump_vdso(&self.process, VirtualAddress::new(entry.l_addr))?
980                } else {
981                    name
982                };
983
984                let new_elf = Elf::new(&elf_path)?;
985                new_elf.notify_loaded(VirtualAddress::new(entry.l_addr));
986                self.elves.borrow_mut().push(new_elf);
987            }
988        }
989
990        for bp in self.breakpoints.borrow().iter() {
991            bp.borrow_mut().resolve()?;
992        }
993
994        Ok(())
995    }
996
997    pub fn get_elves(&self) -> &RefCell<ElfCollection> {
998        &self.elves
999    }
1000
1001    pub fn get_line_entries_by_line(
1002        &self,
1003        path: &Path,
1004        line: usize,
1005    ) -> Result<Vec<LineTableIter>, SdbError> {
1006        let mut entries = Vec::<LineTableIter>::new();
1007        for elf in self.elves.borrow().iter() {
1008            for cu in elf.get_dwarf().compile_units() {
1009                let new_entries = cu.lines().get_entries_by_line(path, line as u64)?;
1010                entries.extend(new_entries);
1011            }
1012        }
1013        Ok(entries)
1014    }
1015}
1016
1017fn dump_vdso(process: &Process, address: VirtualAddress) -> Result<PathBuf, SdbError> {
1018    let tmp_dir = "/tmp/sdb-233456".to_string();
1019    std::fs::create_dir_all(&tmp_dir)
1020        .map_err(|_| SdbError::new_err("Cannot create temp directory"))?;
1021    let mut vdso_dump_path = PathBuf::from(tmp_dir);
1022    vdso_dump_path.push("linux-vdso.so.1");
1023    let mut vdso_dump = std::fs::File::create(&vdso_dump_path)
1024        .map_err(|_| SdbError::new_err("Cannot create vdso dump file"))?;
1025    let vdso_header = process.read_memory_as::<SdbElf64Ehdr>(address)?;
1026    let vdso_size =
1027        vdso_header.0.e_shoff + vdso_header.0.e_shentsize as u64 * vdso_header.0.e_shnum as u64;
1028    let vdso_bytes = process.read_memory(address, vdso_size as usize)?;
1029    vdso_dump
1030        .write_all(&vdso_bytes)
1031        .map_err(|_| SdbError::new_err("Cannot write vdso dump file"))?;
1032    Ok(vdso_dump_path)
1033}
1034
1035pub struct FindFunctionsResult {
1036    pub dwarf_functions: Vec<Rc<Die>>,
1037    pub elf_functions: Vec<(Rc<Elf>, Rc<SdbElf64Sym>)>,
1038}
1039
1040fn create_loaded_elf(proc: &Process, path: &Path) -> Result<Rc<Elf>, SdbError> {
1041    let auxv = proc.get_auxv();
1042    let obj = Elf::new(path)?;
1043    obj.notify_loaded(VirtualAddress::new(
1044        auxv[&(AT_ENTRY as i32)] - obj.get_header().0.e_entry,
1045    ));
1046    Ok(obj)
1047}
1048
1049#[derive(TypedBuilder)]
1050pub struct SdbThread {
1051    pub state: Weak<RefCell<ThreadState>>,
1052    pub frames: Rc<RefCell<Stack>>,
1053}
1054
1055impl SdbThread {
1056    pub fn new(state: Weak<RefCell<ThreadState>>, frames: Stack) -> Self {
1057        Self {
1058            state,
1059            frames: Rc::new(RefCell::new(frames)),
1060        }
1061    }
1062}
1063
1064fn parse_argument(target: &Target, tid: Pid, arg: &str) -> Result<TypedData, SdbError> {
1065    if arg.is_empty() {
1066        return SdbError::err("Empty argument");
1067    }
1068    if arg.len() > 2 && arg.starts_with('"') && arg.ends_with('"') {
1069        let ptr = target.inferior_malloc(arg.len() - 1)?;
1070        let arg_str = &arg[1..arg.len() - 1];
1071        let data_bytes = arg_str.as_bytes();
1072        let mut data_with_null = data_bytes.to_vec();
1073        data_with_null.push(0);
1074        target.process.write_memory(ptr, &data_with_null)?;
1075        return Ok(TypedData::builder()
1076            .data(to_byte_vec(&ptr))
1077            .type_(SdbType::new_builtin(BuiltinType::String))
1078            .build());
1079    } else if arg == "true" || arg == "false" {
1080        let value = arg == "true";
1081        return Ok(TypedData::builder()
1082            .data(vec![if value { 1u8 } else { 0u8 }])
1083            .type_(SdbType::new_builtin(BuiltinType::Boolean))
1084            .build());
1085    } else if arg.starts_with('\'') {
1086        if arg.len() != 3 || !arg.ends_with('\'') {
1087            return SdbError::err("Invalid character literal");
1088        }
1089        let char_byte = arg.chars().nth(1).unwrap() as u8;
1090        return Ok(TypedData::builder()
1091            .data(vec![char_byte])
1092            .type_(SdbType::new_builtin(BuiltinType::Character))
1093            .build());
1094    } else if arg.starts_with('-') || arg.chars().next().unwrap().is_ascii_digit() {
1095        if arg.contains('.') {
1096            let value: Result<f64, _> = arg.parse();
1097            if value.is_err() {
1098                return SdbError::err("Invalid floating point literal");
1099            }
1100            return Ok(TypedData::builder()
1101                .data(value.unwrap().to_le_bytes().to_vec())
1102                .type_(SdbType::new_builtin(BuiltinType::FloatingPoint))
1103                .build());
1104        } else {
1105            let value: Result<i64, _> = arg.parse();
1106            if value.is_err() {
1107                return SdbError::err("Invalid integer literal");
1108            }
1109            return Ok(TypedData::builder()
1110                .data(value.unwrap().to_le_bytes().to_vec())
1111                .type_(SdbType::new_builtin(BuiltinType::Integer))
1112                .build());
1113        }
1114    } else {
1115        let pc = target.get_pc_file_address(Some(tid));
1116        let res = target.resolve_indirect_name(arg, &pc)?;
1117        if !res.funcs.is_empty() {
1118            return SdbError::err("Nested function calls not supported");
1119        }
1120        Ok(res.variable.unwrap())
1121    }
1122}
1123
1124fn collect_arguments(
1125    target: &Target,
1126    tid: Pid,
1127    arg_string: &str,
1128    funcs: &[Rc<Die>],
1129    object: Option<TypedData>,
1130) -> Result<Vec<TypedData>, SdbError> {
1131    let mut args = Vec::new();
1132    let proc = target.get_process();
1133
1134    if let Some(object) = object {
1135        let data = if let Some(address) = object.address() {
1136            address.addr().to_le_bytes().to_vec()
1137        } else {
1138            let regs = proc.get_registers(Some(tid));
1139            let mut rsp = regs.borrow().read_by_id_as::<u64>(RegisterId::rsp)?;
1140            rsp -= object.value_type().byte_size()? as u64;
1141            proc.write_memory(VirtualAddress::new(rsp), object.data())?;
1142            regs.borrow_mut().write_by_id(RegisterId::rsp, rsp, true)?;
1143            rsp.to_le_bytes().to_vec()
1144        };
1145        let obj_ptr_die = funcs[0]
1146            .index(DW_AT_object_pointer.0 as u64)?
1147            .as_reference();
1148        let this_type = obj_ptr_die.index(DW_AT_type.0 as u64)?.as_type();
1149        args.push(TypedData::builder().data(data).type_(this_type).build());
1150    }
1151
1152    let mut args_start = 1;
1153    let args_end = arg_string.find(')').unwrap_or(arg_string.len());
1154
1155    while args_start < args_end {
1156        let comma_pos = arg_string
1157            .chars()
1158            .enumerate()
1159            .skip(args_start)
1160            .find(|(_, c)| *c == ',')
1161            .map(|(pos, _)| pos)
1162            .unwrap_or(args_end);
1163        let arg_expr = &arg_string[args_start..comma_pos];
1164        args.push(parse_argument(target, tid, arg_expr)?);
1165        args_start = comma_pos + 1;
1166    }
1167    Ok(args)
1168}
1169
1170fn resolve_overload(funcs: &[Rc<Die>], args: &[TypedData]) -> Result<Rc<Die>, SdbError> {
1171    let mut matching_func: Option<Rc<Die>> = None;
1172    for func in funcs {
1173        let mut matches = true;
1174        let params = func.parameter_types()?;
1175
1176        if args.len() == params.len() {
1177            for (param_type, arg) in params.iter().zip(args.iter()) {
1178                if *param_type != *arg.value_type() {
1179                    matches = false;
1180                    break;
1181                }
1182            }
1183        } else {
1184            matches = false;
1185        }
1186
1187        if matches {
1188            if matching_func.is_some() {
1189                return SdbError::err("Ambiguous function call");
1190            }
1191            matching_func = Some(func.clone());
1192        }
1193    }
1194
1195    matching_func.ok_or_else(|| SdbError::new_err("No matching function"))
1196}
1197
1198fn inferior_call_from_dwarf(
1199    target: &Target,
1200    func: &Rc<Die>,
1201    args: &[TypedData],
1202    return_addr: VirtualAddress,
1203    tid: Pid,
1204) -> Result<Option<TypedData>, SdbError> {
1205    let regs = target.get_process().get_registers(Some(tid));
1206    let saved_regs = regs.borrow().clone();
1207
1208    let call_addr = if func.contains(gimli::DW_AT_low_pc.0 as u64)
1209        || func.contains(gimli::DW_AT_ranges.0 as u64)
1210    {
1211        func.low_pc()?.to_virt_addr()
1212    } else {
1213        let def = func
1214            .cu()
1215            .dwarf_info()
1216            .get_member_function_definition(func)?;
1217        match def {
1218            Some(d) => d.low_pc()?.to_virt_addr(),
1219            None => return SdbError::err("No function definition found"),
1220        }
1221    };
1222
1223    let return_slot = if func.contains(DW_AT_type.0 as u64) {
1224        let ret_type = func.index(DW_AT_type.0 as u64)?.as_type();
1225        Some(target.inferior_malloc(ret_type.byte_size()?)?)
1226    } else {
1227        None
1228    };
1229
1230    setup_arguments(
1231        target,
1232        func,
1233        args.to_vec(),
1234        &mut regs.borrow_mut(),
1235        return_slot,
1236    )?;
1237    let new_regs = target.get_process().inferior_call(
1238        call_addr,
1239        return_addr,
1240        saved_regs.clone(),
1241        Some(tid),
1242    )?;
1243
1244    if func.contains(DW_AT_type.0 as u64) {
1245        return Ok(Some(read_return_value(
1246            target,
1247            func,
1248            return_slot.unwrap(),
1249            &new_regs,
1250        )?));
1251    }
1252    Ok(None)
1253}