Skip to content

Commit 190a8da

Browse files
committed
feat: Add support for single register access in GDB stub
1 parent 783ac9a commit 190a8da

3 files changed

Lines changed: 143 additions & 3 deletions

File tree

edbgserver-cli/src/target.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ impl MultiThreadBase for EdbgTarget {
230230
_tid: gdbstub::common::Tid,
231231
) -> TargetResult<(), Self> {
232232
warn!("write_registers not fully implemented (requires ptrace or inline hooking)");
233-
Ok(())
233+
Err(TargetError::NonFatal)
234234
}
235235

236236
fn read_addrs(
@@ -310,4 +310,13 @@ impl MultiThreadBase for EdbgTarget {
310310
fn support_resume(&mut self) -> Option<MultiThreadResumeOps<'_, Self>> {
311311
Some(self)
312312
}
313+
314+
#[inline(always)]
315+
fn support_single_register_access(
316+
&mut self,
317+
) -> Option<
318+
gdbstub::target::ext::base::single_register_access::SingleRegisterAccessOps<'_, Tid, Self>,
319+
> {
320+
Some(self)
321+
}
313322
}

edbgserver-cli/src/target/arch/aarch64.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ use capstone::{
44
prelude::*,
55
};
66
use edbgserver_common::DataT;
7-
use log::{debug, error};
7+
use gdbstub::{
8+
common::Tid,
9+
target::{TargetError, TargetResult, ext::base::single_register_access::SingleRegisterAccess},
10+
};
11+
use log::{debug, error, warn};
812

913
use crate::target::EdbgTarget;
1014

@@ -94,6 +98,53 @@ pub fn fill_regs(regs: &mut AArch64MinimalRegs, ctx: &DataT) {
9498
regs.cpsr = ctx.pstate as u32;
9599
}
96100

101+
impl SingleRegisterAccess<Tid> for EdbgTarget {
102+
fn read_register(
103+
&mut self,
104+
tid: Tid,
105+
reg_id: <Self::Arch as gdbstub::arch::Arch>::RegId,
106+
buf: &mut [u8],
107+
) -> TargetResult<usize, Self> {
108+
let ctx = match &self.context {
109+
Some(c) if !self.is_multi_thread || c.tid == tid.get() as u32 => c,
110+
_ => {
111+
warn!("read_register: no context with tid {}", tid.get());
112+
return Ok(0);
113+
}
114+
};
115+
116+
match reg_id {
117+
gdbstub_arch::aarch64::reg::id::AArch64RegId::X(n) => {
118+
buf.copy_from_slice(&ctx.regs[n as usize].to_le_bytes());
119+
Ok(8)
120+
}
121+
gdbstub_arch::aarch64::reg::id::AArch64RegId::Sp => {
122+
buf.copy_from_slice(&ctx.sp.to_le_bytes());
123+
Ok(8)
124+
}
125+
gdbstub_arch::aarch64::reg::id::AArch64RegId::Pc => {
126+
buf.copy_from_slice(&ctx.pc.to_le_bytes());
127+
Ok(8)
128+
}
129+
gdbstub_arch::aarch64::reg::id::AArch64RegId::Pstate => {
130+
buf.copy_from_slice(&ctx.pstate.to_le_bytes());
131+
Ok(8)
132+
}
133+
_ => Ok(0),
134+
}
135+
}
136+
137+
fn write_register(
138+
&mut self,
139+
_tid: Tid,
140+
_reg_id: <Self::Arch as gdbstub::arch::Arch>::RegId,
141+
_val: &[u8],
142+
) -> TargetResult<(), Self> {
143+
warn!("write single register not fully implemented (requires ptrace or inline hooking)");
144+
Err(TargetError::NonFatal)
145+
}
146+
}
147+
97148
impl EdbgTarget {
98149
fn create_capstone() -> Result<Capstone> {
99150
Capstone::new()

edbgserver-cli/src/target/arch/x86_64.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ use capstone::{
55
prelude::*,
66
};
77
use edbgserver_common::DataT;
8-
use gdbstub_arch::x86::reg::X86_64CoreRegs;
8+
use gdbstub::{
9+
common::Tid,
10+
target::{TargetError, TargetResult, ext::base::single_register_access::SingleRegisterAccess},
11+
};
12+
use gdbstub_arch::x86::reg::{
13+
X86_64CoreRegs,
14+
id::{X86_64CoreRegId, X86SegmentRegId},
15+
};
916
use log::{debug, error, trace, warn};
1017

1118
use crate::target::EdbgTarget;
@@ -32,6 +39,79 @@ pub fn fill_regs(regs: &mut X86_64CoreRegs, ctx: &DataT) {
3239
regs.eflags = ctx.eflags as u32;
3340
}
3441

42+
impl SingleRegisterAccess<Tid> for EdbgTarget {
43+
fn read_register(
44+
&mut self,
45+
tid: Tid,
46+
reg_id: <Self::Arch as gdbstub::arch::Arch>::RegId,
47+
buf: &mut [u8],
48+
) -> TargetResult<usize, Self> {
49+
let ctx = match &self.context {
50+
Some(c) if !self.is_multi_thread || c.tid == tid.get() as u32 => c,
51+
_ => {
52+
warn!("read_register: no context with tid {}", tid.get());
53+
return Ok(0);
54+
}
55+
};
56+
57+
match reg_id {
58+
X86_64CoreRegId::Gpr(i) => {
59+
// RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
60+
let val = match i {
61+
0 => ctx.rax,
62+
1 => ctx.rbx,
63+
2 => ctx.rcx,
64+
3 => ctx.rdx,
65+
4 => ctx.rsi,
66+
5 => ctx.rdi,
67+
6 => ctx.rbp,
68+
7 => ctx.rsp,
69+
8 => ctx.r8,
70+
9 => ctx.r9,
71+
10 => ctx.r10,
72+
11 => ctx.r11,
73+
12 => ctx.r12,
74+
13 => ctx.r13,
75+
14 => ctx.r14,
76+
15 => ctx.r15,
77+
_ => return Ok(0),
78+
};
79+
buf.copy_from_slice(&val.to_le_bytes());
80+
Ok(8)
81+
}
82+
X86_64CoreRegId::Rip => {
83+
buf.copy_from_slice(&ctx.rip.to_le_bytes());
84+
Ok(8)
85+
}
86+
X86_64CoreRegId::Eflags => {
87+
let val = ctx.eflags as u32;
88+
buf.copy_from_slice(&val.to_le_bytes());
89+
Ok(4)
90+
}
91+
X86_64CoreRegId::Segment(segments) => {
92+
let val = match segments {
93+
X86SegmentRegId::CS => ctx.cs,
94+
X86SegmentRegId::SS => ctx.ss,
95+
_ => 0,
96+
};
97+
buf.copy_from_slice(&(val as u32).to_le_bytes());
98+
Ok(4)
99+
}
100+
_ => Ok(0),
101+
}
102+
}
103+
104+
fn write_register(
105+
&mut self,
106+
_tid: Tid,
107+
_reg_id: <Self::Arch as gdbstub::arch::Arch>::RegId,
108+
_val: &[u8],
109+
) -> TargetResult<(), Self> {
110+
warn!("write single register not fully implemented (requires ptrace or inline hooking)");
111+
Err(TargetError::NonFatal)
112+
}
113+
}
114+
35115
impl EdbgTarget {
36116
fn create_capstone() -> Result<Capstone> {
37117
Capstone::new()

0 commit comments

Comments
 (0)