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>, ) -> 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>, ) -> 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(®_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}