Skip to content

Commit 613e832

Browse files
committed
Propagate generic type T in udbserver to support custom Unicorn user data
1 parent 729cc0c commit 613e832

3 files changed

Lines changed: 65 additions & 43 deletions

File tree

examples/server.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use unicorn_engine::unicorn_const::{Arch, Mode, Prot};
22
use unicorn_engine::{RegisterARM, Unicorn};
33

4+
struct CustomData {
5+
pub _val: u32,
6+
}
7+
48
fn main() {
59
let arm_code32: Vec<u8> = vec![
610
0x0f, 0x00, 0xa0, 0xe1, 0x14, 0x00, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5, 0x14, 0x10, 0x81, 0xe2, 0x00, 0x10, 0x80, 0xe5, 0xfb, 0xff, 0xff, 0xea,

src/emu.rs

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,29 +33,29 @@ fn copy_range_to_buf(data: &[u8], offset: u64, length: usize, buf: &mut [u8]) ->
3333
copy_to_buf(data, buf)
3434
}
3535

36-
fn step_cb(uc: &mut Unicorn<()>, _addr: u64, _size: u32) {
36+
fn step_cb<T: 'static>(uc: &mut Unicorn<T>, _addr: u64, _size: u32) {
3737
if *STEP_STATE.get() {
3838
STEP_STATE.replace(false);
3939
return;
4040
}
4141
if let Some(step_hook) = STEP_HOOK.take() {
4242
uc.remove_hook(step_hook).expect("Failed to remove step hook");
4343
}
44-
crate::udbserver_resume(WATCH_ADDR.take()).expect("Failed to resume udbserver");
44+
crate::udbserver_resume::<T>(WATCH_ADDR.take()).expect("Failed to resume udbserver");
4545
}
4646

47-
fn watch_cb(uc: &mut Unicorn<()>, _mem_type: MemType, addr: u64, _size: usize, _value: i64) -> bool {
47+
fn watch_cb<T: 'static>(uc: &mut Unicorn<T>, _mem_type: MemType, addr: u64, _size: usize, _value: i64) -> bool {
4848
if WATCH_ADDR.is_none() {
4949
WATCH_ADDR.replace(addr);
5050
if STEP_HOOK.is_none() {
51-
STEP_HOOK.replace(uc.add_code_hook(1, 0, step_cb).expect("Failed to add code hook"));
51+
STEP_HOOK.replace(uc.add_code_hook(1, 0, step_cb::<T>).expect("Failed to add code hook"));
5252
}
5353
}
5454
true
5555
}
5656

57-
pub struct Emu {
58-
uc: &'static mut Unicorn<'static, ()>,
57+
pub struct Emu<T: 'static> {
58+
uc: &'static mut Unicorn<'static, T>,
5959
reg: Register,
6060
code_hook: UcHookId,
6161
mem_hook: UcHookId,
@@ -66,8 +66,8 @@ pub struct Emu {
6666
wp_rw_hooks: HashMap<u64, HashMap<u64, UcHookId>>,
6767
}
6868

69-
impl Emu {
70-
pub fn new(uc: &'static mut Unicorn<'static, ()>, code_hook: UcHookId, mem_hook: UcHookId) -> DynResult<Emu> {
69+
impl<T: 'static> Emu<T> {
70+
pub fn new(uc: &'static mut Unicorn<'static, T>, code_hook: UcHookId, mem_hook: UcHookId) -> DynResult<Emu<T>> {
7171
let arch = uc.get_arch();
7272
let query_mode = uc.query(Query::MODE).expect("Failed to query mode");
7373
let mode = Mode::try_from(query_mode as i32).unwrap();
@@ -86,14 +86,14 @@ impl Emu {
8686
}
8787
}
8888

89-
impl Drop for Emu {
89+
impl<T: 'static> Drop for Emu<T> {
9090
fn drop(&mut self) {
9191
self.uc.remove_hook(self.code_hook).expect("Failed to remove empty code hook");
9292
self.uc.remove_hook(self.mem_hook).expect("Failed to remove empty mem hook");
9393
}
9494
}
9595

96-
impl target::Target for Emu {
96+
impl<T: 'static> target::Target for Emu<T> {
9797
type Arch = arch::GenericArch;
9898
type Error = &'static str;
9999

@@ -113,7 +113,7 @@ impl target::Target for Emu {
113113
}
114114
}
115115

116-
impl target::ext::base::singlethread::SingleThreadBase for Emu {
116+
impl<T: 'static> target::ext::base::singlethread::SingleThreadBase for Emu<T> {
117117
fn read_registers(&mut self, regs: &mut arch::GenericRegs) -> TargetResult<(), Self> {
118118
regs.buf = Vec::new();
119119
for reg in self.reg.list() {
@@ -166,7 +166,7 @@ impl target::ext::base::singlethread::SingleThreadBase for Emu {
166166
}
167167
}
168168

169-
impl target::ext::base::singlethread::SingleThreadResume for Emu {
169+
impl<T: 'static> target::ext::base::singlethread::SingleThreadResume for Emu<T> {
170170
fn resume(&mut self, _signal: Option<Signal>) -> Result<(), Self::Error> {
171171
Ok(())
172172
}
@@ -177,20 +177,20 @@ impl target::ext::base::singlethread::SingleThreadResume for Emu {
177177
}
178178
}
179179

180-
impl target::ext::base::singlethread::SingleThreadSingleStep for Emu {
180+
impl<T: 'static> target::ext::base::singlethread::SingleThreadSingleStep for Emu<T> {
181181
fn step(&mut self, signal: Option<Signal>) -> Result<(), Self::Error> {
182182
if signal.is_some() {
183183
return Err("no support for stepping with signal");
184184
}
185185

186186
STEP_STATE.replace(true);
187-
STEP_HOOK.replace(self.uc.add_code_hook(1, 0, step_cb).map_err(|_| "Failed to add code hook")?);
187+
STEP_HOOK.replace(self.uc.add_code_hook(1, 0, step_cb::<T>).map_err(|_| "Failed to add code hook")?);
188188

189189
Ok(())
190190
}
191191
}
192192

193-
impl target::ext::breakpoints::Breakpoints for Emu {
193+
impl<T: 'static> target::ext::breakpoints::Breakpoints for Emu<T> {
194194
#[inline(always)]
195195
fn support_sw_breakpoint(&mut self) -> Option<target::ext::breakpoints::SwBreakpointOps<'_, Self>> {
196196
Some(self)
@@ -209,15 +209,18 @@ impl target::ext::breakpoints::Breakpoints for Emu {
209209

210210
macro_rules! add_breakpoint {
211211
( $self:ident, $addr:ident, $hook_map:ident ) => {{
212-
let hook = match $self.uc.add_code_hook($addr.into(), $addr.into(), step_cb) {
212+
let hook = match $self.uc.add_code_hook($addr.into(), $addr.into(), step_cb::<T>) {
213213
Ok(h) => h,
214214
Err(_) => return Ok(false),
215215
};
216216
$self.$hook_map.insert($addr.into(), hook);
217217
Ok(true)
218218
}};
219219
( $self:ident, $mem_type:ident, $addr:ident, $len:ident, $hook_map:ident ) => {{
220-
let hook = match $self.uc.add_mem_hook(HookType::$mem_type, $addr.into(), ($addr + $len - 1).into(), watch_cb) {
220+
let hook = match $self
221+
.uc
222+
.add_mem_hook(HookType::$mem_type, $addr.into(), ($addr + $len - 1).into(), watch_cb::<T>)
223+
{
221224
Ok(h) => h,
222225
Err(_) => return Ok(false),
223226
};
@@ -253,7 +256,7 @@ macro_rules! remove_breakpoint {
253256
}};
254257
}
255258

256-
impl target::ext::breakpoints::SwBreakpoint for Emu {
259+
impl<T: 'static> target::ext::breakpoints::SwBreakpoint for Emu<T> {
257260
fn add_sw_breakpoint(&mut self, addr: u64, _kind: usize) -> TargetResult<bool, Self> {
258261
add_breakpoint!(self, addr, bp_sw_hooks)
259262
}
@@ -263,7 +266,7 @@ impl target::ext::breakpoints::SwBreakpoint for Emu {
263266
}
264267
}
265268

266-
impl target::ext::breakpoints::HwBreakpoint for Emu {
269+
impl<T: 'static> target::ext::breakpoints::HwBreakpoint for Emu<T> {
267270
fn add_hw_breakpoint(&mut self, addr: u64, _kind: usize) -> TargetResult<bool, Self> {
268271
add_breakpoint!(self, addr, bp_hw_hooks)
269272
}
@@ -273,7 +276,7 @@ impl target::ext::breakpoints::HwBreakpoint for Emu {
273276
}
274277
}
275278

276-
impl target::ext::breakpoints::HwWatchpoint for Emu {
279+
impl<T: 'static> target::ext::breakpoints::HwWatchpoint for Emu<T> {
277280
fn add_hw_watchpoint(&mut self, addr: u64, len: u64, kind: WatchKind) -> TargetResult<bool, Self> {
278281
match kind {
279282
WatchKind::Read => add_breakpoint!(self, MEM_READ, addr, len, wp_r_hooks),
@@ -291,7 +294,7 @@ impl target::ext::breakpoints::HwWatchpoint for Emu {
291294
}
292295
}
293296

294-
impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu {
297+
impl<T: 'static> target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu<T> {
295298
fn read_register(&mut self, _tid: (), reg_id: arch::GenericRegId, buf: &mut [u8]) -> TargetResult<usize, Self> {
296299
let reg = self.reg.get(reg_id.0)?;
297300
if reg.1 <= 8 {
@@ -323,7 +326,7 @@ impl target::ext::base::single_register_access::SingleRegisterAccess<()> for Emu
323326
}
324327
}
325328

326-
impl target::ext::target_description_xml_override::TargetDescriptionXmlOverride for Emu {
329+
impl<T: 'static> target::ext::target_description_xml_override::TargetDescriptionXmlOverride for Emu<T> {
327330
fn target_description_xml(&self, _annex: &[u8], offset: u64, length: usize, buf: &mut [u8]) -> TargetResult<usize, Self> {
328331
let xml = self.reg.description_xml().as_bytes();
329332
Ok(copy_range_to_buf(xml, offset, length, buf))

src/lib.rs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@ use gdbstub::stub::state_machine::GdbStubStateMachine;
1010
use gdbstub::stub::{DisconnectReason, GdbStubBuilder, SingleThreadStopReason};
1111
use gdbstub::target::ext::breakpoints::WatchKind;
1212
use singlyton::SingletonOption;
13+
use std::any::Any;
1314
use std::borrow::BorrowMut;
1415
use std::net::{TcpListener, TcpStream};
1516
use unicorn_engine::unicorn_const::HookType;
1617
use unicorn_engine::Unicorn;
1718

1819
type DynResult<T> = Result<T, Box<dyn std::error::Error>>;
1920

20-
static GDBSTUB: SingletonOption<GdbStubStateMachine<emu::Emu, TcpStream>> = SingletonOption::new();
21-
static EMU: SingletonOption<emu::Emu> = SingletonOption::new();
21+
static GDBSTUB: SingletonOption<Box<dyn Any>> = SingletonOption::new();
22+
static EMU: SingletonOption<Box<dyn Any>> = SingletonOption::new();
2223

2324
fn wait_for_tcp(port: u16) -> DynResult<TcpStream> {
2425
let sockaddr = format!("0.0.0.0:{}", port);
@@ -31,38 +32,45 @@ fn wait_for_tcp(port: u16) -> DynResult<TcpStream> {
3132
Ok(stream)
3233
}
3334

34-
pub fn udbserver<T>(uc: &mut Unicorn<T>, port: u16, start_addr: u64) -> DynResult<()> {
35+
pub fn udbserver<T: 'static>(uc: &mut Unicorn<T>, port: u16, start_addr: u64) -> DynResult<()> {
3536
let code_hook = uc.add_code_hook(1, 0, |_, _, _| {}).expect("Failed to add empty code hook");
3637
let mem_hook = uc
3738
.add_mem_hook(HookType::MEM_READ, 1, 0, |_, _, _, _, _| true)
3839
.expect("Failed to add empty mem hook");
3940
if start_addr != 0 {
40-
uc.add_code_hook(start_addr, start_addr, move |_, _, _| udbserver_start(port).expect("Failed to start udbserver"))
41-
.expect("Failed to add udbserver hook");
41+
uc.add_code_hook(start_addr, start_addr, move |_, _, _| {
42+
udbserver_start::<T>(port).expect("Failed to start udbserver")
43+
})
44+
.expect("Failed to add udbserver hook");
4245
}
4346
let emu = emu::Emu::new(
44-
unsafe { std::mem::transmute::<&mut Unicorn<T>, &'static mut Unicorn<'static, ()>>(uc) },
47+
unsafe { std::mem::transmute::<&mut Unicorn<T>, &'static mut Unicorn<'static, T>>(uc) },
4548
code_hook,
4649
mem_hook,
4750
)?;
48-
EMU.replace(emu);
51+
EMU.replace(Box::new(emu));
4952
if start_addr == 0 {
50-
udbserver_start(port).expect("Failed to start udbserver");
53+
udbserver_start::<T>(port).expect("Failed to start udbserver");
5154
}
5255
Ok(())
5356
}
5457

55-
fn udbserver_start(port: u16) -> DynResult<()> {
58+
fn udbserver_start<T: 'static>(port: u16) -> DynResult<()> {
5659
if GDBSTUB.is_some() {
5760
return Ok(());
5861
}
59-
let gdbstub = GdbStubBuilder::new(wait_for_tcp(port)?).build()?.run_state_machine(&mut *EMU.get_mut())?;
60-
GDBSTUB.replace(gdbstub);
61-
udbserver_loop()
62+
let mut emu_any = EMU.get_mut();
63+
let emu = emu_any.downcast_mut::<emu::Emu<T>>().expect("Failed to downcast EMU");
64+
let gdbstub = GdbStubBuilder::new(wait_for_tcp(port)?).build()?.run_state_machine(emu)?;
65+
GDBSTUB.replace(Box::new(gdbstub));
66+
udbserver_loop::<T>()
6267
}
6368

64-
fn udbserver_resume(addr: Option<u64>) -> DynResult<()> {
65-
let mut gdb = GDBSTUB.take().unwrap();
69+
pub(crate) fn udbserver_resume<T: 'static>(addr: Option<u64>) -> DynResult<()> {
70+
let gdb_any = GDBSTUB.take().unwrap();
71+
let mut gdb = *gdb_any
72+
.downcast::<GdbStubStateMachine<emu::Emu<T>, TcpStream>>()
73+
.expect("Failed to downcast GDBSTUB");
6674
let reason = if let Some(watch_addr) = addr {
6775
SingleThreadStopReason::Watch {
6876
tid: (),
@@ -73,29 +81,36 @@ fn udbserver_resume(addr: Option<u64>) -> DynResult<()> {
7381
SingleThreadStopReason::DoneStep
7482
};
7583
if let GdbStubStateMachine::Running(gdb_inner) = gdb {
76-
match gdb_inner.report_stop(EMU.get_mut().borrow_mut(), reason) {
84+
let mut emu_any = EMU.get_mut();
85+
let emu = emu_any.downcast_mut::<emu::Emu<T>>().expect("Failed to downcast EMU");
86+
match gdb_inner.report_stop(emu.borrow_mut(), reason) {
7787
Ok(gdb_state) => gdb = gdb_state,
7888
Err(_) => return Ok(()),
7989
}
8090
}
81-
GDBSTUB.replace(gdb);
82-
udbserver_loop()
91+
GDBSTUB.replace(Box::new(gdb));
92+
udbserver_loop::<T>()
8393
}
8494

85-
fn udbserver_loop() -> DynResult<()> {
86-
let mut gdb = GDBSTUB.take().unwrap();
95+
fn udbserver_loop<T: 'static>() -> DynResult<()> {
96+
let gdb_any = GDBSTUB.take().unwrap();
97+
let mut gdb = *gdb_any
98+
.downcast::<GdbStubStateMachine<emu::Emu<T>, TcpStream>>()
99+
.expect("Failed to downcast GDBSTUB");
87100
loop {
88101
gdb = match gdb {
89102
GdbStubStateMachine::Idle(mut gdb_inner) => {
90103
let byte = gdb_inner.borrow_conn().read()?;
91-
gdb_inner.incoming_data(EMU.get_mut().borrow_mut(), byte)?
104+
let mut emu_any = EMU.get_mut();
105+
let emu = emu_any.downcast_mut::<emu::Emu<T>>().expect("Failed to downcast EMU");
106+
gdb_inner.incoming_data(emu.borrow_mut(), byte)?
92107
}
93108
GdbStubStateMachine::Running(_) => break,
94109
GdbStubStateMachine::CtrlCInterrupt(_) => break,
95110
GdbStubStateMachine::Disconnected(gdb_inner) => return handle_disconnect(gdb_inner.get_reason()),
96111
}
97112
}
98-
GDBSTUB.replace(gdb);
113+
GDBSTUB.replace(Box::new(gdb));
99114
Ok(())
100115
}
101116

0 commit comments

Comments
 (0)