ptrace.rs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //! Note: This module is not going to be clean. We're not going to be
  2. //! able to follow the specs 100%. Linux ptrace is very, very,
  3. //! different to Redox. Many people agree that Linux ptrace is bad, so
  4. //! we are NOT going to bend our API for the sake of
  5. //! compatibility. So, this module will be a hellhole.
  6. use super::super::types::*;
  7. use super::super::{errno, Pal, PalPtrace, PalSignal, Sys};
  8. use crate::c_str::CString;
  9. use crate::fs::File;
  10. use crate::header::sys_user::user_regs_struct;
  11. use crate::header::{errno as errnoh, fcntl, signal, sys_ptrace};
  12. use crate::io::{self, prelude::*};
  13. use crate::sync::{Mutex, Once};
  14. use alloc::collections::BTreeMap;
  15. use alloc::collections::btree_map::Entry;
  16. use syscall;
  17. pub struct Session {
  18. pub tracer: File,
  19. pub mem: File,
  20. pub regs: File,
  21. pub fpregs: File
  22. }
  23. pub struct State {
  24. pub sessions: Mutex<BTreeMap<pid_t, Session>>
  25. }
  26. impl State {
  27. fn new() -> Self {
  28. Self {
  29. sessions: Mutex::new(BTreeMap::new())
  30. }
  31. }
  32. }
  33. static STATE: Once<State> = Once::new();
  34. pub fn init_state() -> &'static State {
  35. STATE.call_once(|| State::new())
  36. }
  37. fn inner_ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> io::Result<c_int> {
  38. let state = init_state();
  39. if request == sys_ptrace::PTRACE_TRACEME {
  40. // let pid = Sys::getpid();
  41. // todo: only auto-open session on host if this happens
  42. return Ok(0);
  43. }
  44. const NEW_FLAGS: c_int = fcntl::O_RDWR | fcntl::O_CLOEXEC;
  45. let mut sessions = state.sessions.lock();
  46. let session = match sessions.entry(pid) {
  47. Entry::Vacant(entry) => entry.insert(Session {
  48. tracer: File::open(&CString::new(format!("proc:{}/trace", pid)).unwrap(), NEW_FLAGS | fcntl::O_NONBLOCK)?,
  49. mem: File::open(&CString::new(format!("proc:{}/mem", pid)).unwrap(), NEW_FLAGS)?,
  50. regs: File::open(&CString::new(format!("proc:{}/regs/int", pid)).unwrap(), NEW_FLAGS)?,
  51. fpregs: File::open(&CString::new(format!("proc:{}/regs/float", pid)).unwrap(), NEW_FLAGS)?,
  52. }),
  53. Entry::Occupied(entry) => entry.into_mut()
  54. };
  55. match request {
  56. sys_ptrace::PTRACE_CONT | sys_ptrace::PTRACE_SINGLESTEP |
  57. sys_ptrace::PTRACE_SYSCALL | sys_ptrace::PTRACE_SYSEMU |
  58. sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => {
  59. Sys::kill(pid, signal::SIGCONT as _);
  60. (&mut &session.tracer).write(&[match request {
  61. sys_ptrace::PTRACE_CONT => syscall::PTRACE_CONT,
  62. sys_ptrace::PTRACE_SINGLESTEP => syscall::PTRACE_SINGLESTEP,
  63. sys_ptrace::PTRACE_SYSCALL => syscall::PTRACE_SYSCALL,
  64. sys_ptrace::PTRACE_SYSEMU => syscall::PTRACE_SYSEMU | syscall::PTRACE_SYSCALL,
  65. sys_ptrace::PTRACE_SYSEMU_SINGLESTEP => syscall::PTRACE_SYSEMU | syscall::PTRACE_SINGLESTEP,
  66. _ => unreachable!("unhandled ptrace request type {}", request)
  67. }])?;
  68. Ok(0)
  69. },
  70. sys_ptrace::PTRACE_GETREGS => {
  71. let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
  72. let mut redox_regs = syscall::IntRegisters::default();
  73. (&mut &session.regs).read(&mut redox_regs)?;
  74. *c_regs = user_regs_struct {
  75. r15: redox_regs.r15 as _,
  76. r14: redox_regs.r14 as _,
  77. r13: redox_regs.r13 as _,
  78. r12: redox_regs.r12 as _,
  79. rbp: redox_regs.rbp as _,
  80. rbx: redox_regs.rbx as _,
  81. r11: redox_regs.r11 as _,
  82. r10: redox_regs.r10 as _,
  83. r9: redox_regs.r9 as _,
  84. r8: redox_regs.r8 as _,
  85. rax: redox_regs.rax as _,
  86. rcx: redox_regs.rcx as _,
  87. rdx: redox_regs.rdx as _,
  88. rsi: redox_regs.rsi as _,
  89. rdi: redox_regs.rdi as _,
  90. orig_rax: redox_regs.rax as _, // redox_regs.orig_rax as _,
  91. rip: redox_regs.rip as _,
  92. cs: redox_regs.cs as _,
  93. eflags: redox_regs.rflags as _,
  94. rsp: redox_regs.rsp as _,
  95. ss: redox_regs.ss as _,
  96. fs_base: 0, // fs_base: redox_regs.fs_base as _,
  97. gs_base: 0, // gs_base: redox_regs.gs_base as _,
  98. ds: 0, // ds: redox_regs.ds as _,
  99. es: 0, // es: redox_regs.es as _,
  100. fs: redox_regs.fs as _,
  101. gs: 0, // gs: redox_regs.gs as _,
  102. };
  103. Ok(0)
  104. },
  105. sys_ptrace::PTRACE_SETREGS => {
  106. let c_regs = unsafe { &*(data as *mut user_regs_struct) };
  107. let redox_regs = syscall::IntRegisters {
  108. r15: c_regs.r15 as _,
  109. r14: c_regs.r14 as _,
  110. r13: c_regs.r13 as _,
  111. r12: c_regs.r12 as _,
  112. rbp: c_regs.rbp as _,
  113. rbx: c_regs.rbx as _,
  114. r11: c_regs.r11 as _,
  115. r10: c_regs.r10 as _,
  116. r9: c_regs.r9 as _,
  117. r8: c_regs.r8 as _,
  118. rax: c_regs.orig_rax as _, // c_regs.rax as _,
  119. rcx: c_regs.rcx as _,
  120. rdx: c_regs.rdx as _,
  121. rsi: c_regs.rsi as _,
  122. rdi: c_regs.rdi as _,
  123. // orig_rax: c_regs.orig_rax as _,
  124. rip: c_regs.rip as _,
  125. cs: c_regs.cs as _,
  126. rflags: c_regs.eflags as _,
  127. rsp: c_regs.rsp as _,
  128. ss: c_regs.ss as _,
  129. // fs_base: c_regs.fs_base as _,
  130. // gs_base: c_regs.gs_base as _,
  131. // ds: c_regs.ds as _,
  132. // es: c_regs.es as _,
  133. fs: c_regs.fs as _,
  134. // gs: c_regs.gs as _,
  135. };
  136. (&mut &session.regs).write(&redox_regs)?;
  137. Ok(0)
  138. },
  139. _ => unimplemented!()
  140. }
  141. }
  142. impl PalPtrace for Sys {
  143. fn ptrace(request: c_int, pid: pid_t, addr: *mut c_void, data: *mut c_void) -> c_int {
  144. inner_ptrace(request, pid, addr, data).unwrap_or(-1)
  145. }
  146. }