From 46f490386bcfdfd82edf4989c0c6213d394f6ceb Mon Sep 17 00:00:00 2001 From: Sophie Wallace Date: Thu, 18 May 2023 19:17:44 +0100 Subject: [PATCH] 515.1606 support & minor fixes * 515.1606 support * betterer assoc list rendering * cargo fmt * instruction hooking uses UnsafeCell instead of thread local --- auxcov/src/codecov.rs | 105 ++++++++++++++---------- auxcov/src/lib.rs | 68 ++++++++------- auxtools/src/hooks.rs | 9 +- auxtools/src/lib.rs | 28 +++---- auxtools/src/sigscan.rs | 103 ++++++++++++++++------- auxtools/src/sigscan/linux.rs | 7 +- debug_server/src/instruction_hooking.rs | 12 ++- debug_server/src/lib.rs | 23 +++--- debug_server/src/server.rs | 27 +++--- instruction_hooking/src/lib.rs | 75 ++++++++--------- 10 files changed, 264 insertions(+), 193 deletions(-) diff --git a/auxcov/src/codecov.rs b/auxcov/src/codecov.rs index 1cfdcc5f..fac8553e 100644 --- a/auxcov/src/codecov.rs +++ b/auxcov/src/codecov.rs @@ -7,24 +7,24 @@ use std::panic::catch_unwind; use std::path::{Path, PathBuf}; use std::rc::Rc; -use auxtools::*; use auxtools::raw_types::strings::StringId; +use auxtools::*; use dmasm::Instruction; -use grcov::{output_cobertura, CovResult, ResultTuple, FunctionMap}; -use instruction_hooking::InstructionHook; +use grcov::{output_cobertura, CovResult, FunctionMap, ResultTuple}; use instruction_hooking::disassemble_env::DisassembleEnv; +use instruction_hooking::InstructionHook; struct TrackerContext { output_file_name: String, proc_id_map: Vec>>>>, - filename_map: HashMap::>>> + filename_map: HashMap>>>, } pub struct Tracker { hittable_lines: HashMap>, contexts: Vec, - total_procs: u32 + total_procs: u32, } impl Tracker { @@ -53,7 +53,7 @@ impl Tracker { Ok(string_ref) => current_file_option = Some(string_ref), Err(_) => current_file_option = None, } - }, + } Instruction::DbgLine(line) => { if let Some(current_file) = ¤t_file_option { let mut file_name = current_file.to_string(); @@ -64,10 +64,13 @@ impl Tracker { continue; } - hittable_lines.entry(file_name).or_insert(HashSet::new()).insert(line); + hittable_lines + .entry(file_name) + .or_insert(HashSet::new()) + .insert(line); } } - _ => { } + _ => {} } } } @@ -76,19 +79,23 @@ impl Tracker { Tracker { hittable_lines, contexts: Vec::new(), - total_procs: i + total_procs: i, } } pub fn init_context(&mut self, output_file_name: String) -> bool { - if self.contexts.iter().any(|context| context.output_file_name == *output_file_name) { + if self + .contexts + .iter() + .any(|context| context.output_file_name == *output_file_name) + { return false; } let mut context: TrackerContext = TrackerContext { output_file_name, proc_id_map: Vec::new(), - filename_map: HashMap::new() + filename_map: HashMap::new(), }; context.proc_id_map.reserve(self.total_procs as usize); @@ -119,7 +126,11 @@ impl Tracker { } // returns true if we need to pause - pub fn process_dbg_line(&mut self, ctx: &raw_types::procs::ExecutionContext, proc_instance: &raw_types::procs::ProcInstance) { + pub fn process_dbg_line( + &mut self, + ctx: &raw_types::procs::ExecutionContext, + proc_instance: &raw_types::procs::ProcInstance, + ) { if ctx.line == 0 || !ctx.filename.valid() { return; } @@ -133,9 +144,10 @@ impl Tracker { match &known_file_name { Some(file_name) => { context.process_dbg_line(filename_id, proc_map_index, line, Some(file_name)); - }, + } None => { - let processed_file_name = context.process_dbg_line(filename_id, proc_map_index, line, None); + let processed_file_name = + context.process_dbg_line(filename_id, proc_map_index, line, None); if let Some((file_name, valid)) = processed_file_name { if !valid { break; @@ -174,14 +186,14 @@ impl Tracker { fn finalize(&mut self) -> Result<(), Vec> { let mut errors_option = None; for context in &self.contexts { - let result = context.finalize(); // dropping the results because what can ya do? + let result = context.finalize(); // dropping the results because what can ya do? if let Err(error) = result { match &mut errors_option { None => { let mut new_error_vec = Vec::new(); new_error_vec.push(error); errors_option = Some(new_error_vec); - }, + } Some(existing_vec) => { existing_vec.push(error); } @@ -200,14 +212,14 @@ impl Tracker { } impl Drop for Tracker { - fn drop(&mut self) { + fn drop(&mut self) { let _result = self.finalize(); // dropping the result here because what can ya do? - } + } } impl InstructionHook for Tracker { - fn handle_instruction(&mut self, ctx: *mut raw_types::procs::ExecutionContext) { - let ctx_ref; + fn handle_instruction(&mut self, ctx: *mut raw_types::procs::ExecutionContext) { + let ctx_ref; let proc_instance_ref; unsafe { ctx_ref = &*ctx; @@ -215,7 +227,7 @@ impl InstructionHook for Tracker { } self.process_dbg_line(ctx_ref, proc_instance_ref); - } + } } impl TrackerContext { @@ -224,7 +236,8 @@ impl TrackerContext { filename_id: StringId, proc_map_index: usize, line: usize, - known_file_name: Option<&String>) -> Option<(String, bool)> { + known_file_name: Option<&String>, + ) -> Option<(String, bool)> { let needs_extending = self.proc_id_map.len() < proc_map_index + 1; if !needs_extending { @@ -293,7 +306,7 @@ impl TrackerContext { hit_map[i] = current_hits + 1; self.proc_id_map[proc_map_index] = Some(hit_map_cell.clone()); - }, + } None => { // Slower: Need to insert both file and proc let mut hit_map = Vec::::new(); @@ -311,7 +324,8 @@ impl TrackerContext { hit_map[i] = current_hits + 1; let hit_map_rc = Rc::new(RefCell::new(hit_map)); - self.filename_map.insert(file_name.clone(), hit_map_rc.clone()); + self.filename_map + .insert(file_name.clone(), hit_map_rc.clone()); self.proc_id_map[proc_map_index] = Some(hit_map_rc); } } @@ -320,28 +334,31 @@ impl TrackerContext { } fn finalize(&self) -> Result<(), Error> { - let result_tuples: Vec = self.filename_map.iter().map(|(file_name, hit_map)|{ - let mut new_map = BTreeMap::::new(); - for (line_minus_one, hits) in hit_map.borrow().iter().enumerate() { - if *hits == 0 { - continue; - } - - new_map.insert((line_minus_one + 1).try_into().unwrap(), *hits - 1); - } + let result_tuples: Vec = self + .filename_map + .iter() + .map(|(file_name, hit_map)| { + let mut new_map = BTreeMap::::new(); + for (line_minus_one, hits) in hit_map.borrow().iter().enumerate() { + if *hits == 0 { + continue; + } - let path = PathBuf::from(file_name); - ( - path.clone(), - path, - CovResult { - lines: new_map, - branches: BTreeMap::default(), - functions: FunctionMap::default(), + new_map.insert((line_minus_one + 1).try_into().unwrap(), *hits - 1); } - ) - }) - .collect(); + + let path = PathBuf::from(file_name); + ( + path.clone(), + path, + CovResult { + lines: new_map, + branches: BTreeMap::default(), + functions: FunctionMap::default(), + }, + ) + }) + .collect(); let output_path = Path::new(&self.output_file_name); let mut path_buf = output_path.to_path_buf(); diff --git a/auxcov/src/lib.rs b/auxcov/src/lib.rs index ce7da80b..53b9a077 100644 --- a/auxcov/src/lib.rs +++ b/auxcov/src/lib.rs @@ -1,7 +1,7 @@ mod codecov; use codecov::Tracker; -use instruction_hooking::{InstructionHook, INSTRUCTION_HOOKS}; +use instruction_hooking::INSTRUCTION_HOOKS; use std::any::{Any, TypeId}; @@ -9,13 +9,15 @@ use auxtools::*; fn with_tracker_option(f: F, create: bool) where - F: FnOnce(&mut Tracker) { - INSTRUCTION_HOOKS.with(|hooks|{ - let mut hooks_ref: std::cell::RefMut>> = hooks.borrow_mut(); + F: FnOnce(&mut Tracker), +{ + unsafe { + let hooks = INSTRUCTION_HOOKS.get_mut(); + let tracker_tid = TypeId::of::(); - let tracker_option = hooks_ref + let tracker_option = hooks .iter_mut() - .find(|hook|(*hook).as_ref().type_id() == tracker_tid); + .find(|hook| (*hook).as_ref().type_id() == tracker_tid); match tracker_option { Some(existing_hook) => { @@ -23,16 +25,16 @@ where let any_hook = mut_hook.as_any(); let existing_tracker = any_hook.downcast_mut::().unwrap(); f(existing_tracker); - }, + } None => { if create { let mut created_tracker = Tracker::new(); f(&mut created_tracker); - hooks_ref.push(Box::new(created_tracker)); + hooks.push(Box::new(created_tracker)); } } } - }); + } } // INSTRUCTION_HOOKS are cleared on shutdown so we don't need to worry about that. @@ -46,9 +48,12 @@ fn start_code_coverage(coverage_file: Value) { let coverage_file_string = coverage_file_string_result.unwrap(); let mut init_result = false; - with_tracker_option(|tracker|{ - init_result = tracker.init_context(coverage_file_string.clone()); - }, true); + with_tracker_option( + |tracker| { + init_result = tracker.init_context(coverage_file_string.clone()); + }, + true, + ); if !init_result { return Err(runtime!( @@ -70,25 +75,28 @@ fn stop_code_coverage(coverage_file: Value) { let coverage_file_string = coverage_file_string_result.unwrap(); let mut result = Ok(Value::null()); - with_tracker_option(|tracker|{ - let inner_result = tracker.finalize_context(&coverage_file_string); - result = match inner_result { - Ok(had_entry) => { - if !had_entry { - Err(runtime!( - "A code coverage context for {} does not exist!", - coverage_file_string - )) - } else { - Ok(Value::null()) + with_tracker_option( + |tracker| { + let inner_result = tracker.finalize_context(&coverage_file_string); + result = match inner_result { + Ok(had_entry) => { + if !had_entry { + Err(runtime!( + "A code coverage context for {} does not exist!", + coverage_file_string + )) + } else { + Ok(Value::null()) + } } - }, - Err(error) => Err(runtime!( - "A error occurred while trying to save the coverage file: {}", - error - )) - } - }, false); + Err(error) => Err(runtime!( + "A error occurred while trying to save the coverage file: {}", + error + )), + } + }, + false, + ); result } diff --git a/auxtools/src/hooks.rs b/auxtools/src/hooks.rs index 9c5743b8..8436eb4d 100644 --- a/auxtools/src/hooks.rs +++ b/auxtools/src/hooks.rs @@ -41,12 +41,15 @@ extern "C" { struct Detours { pub runtime_detour: Option, - pub call_proc_detour: Option + pub call_proc_detour: Option, } impl Detours { pub fn new() -> Self { - Self{ runtime_detour: None, call_proc_detour: None } + Self { + runtime_detour: None, + call_proc_detour: None, + } } } @@ -99,7 +102,7 @@ pub fn init() -> Result<(), String> { Ok(()) } -pub fn shutdown(){ +pub fn shutdown() { unsafe { DETOURS.with(|detours_cell| { let detours = detours_cell.borrow(); diff --git a/auxtools/src/lib.rs b/auxtools/src/lib.rs index 48bc96b2..2f6b0483 100644 --- a/auxtools/src/lib.rs +++ b/auxtools/src/lib.rs @@ -19,31 +19,28 @@ mod string; mod string_intern; mod value; mod value_from; -mod version; +pub mod version; mod weak_value; use init::{get_init_level, set_init_level, InitLevel}; -use sigscan::{Signature, SignatureMap, SignatureTreatment}; -pub use auxtools_impl::{hook, init, runtime_handler, shutdown, full_shutdown, pin_dll}; +pub use auxtools_impl::{full_shutdown, hook, init, pin_dll, runtime_handler, shutdown}; +/// Used by the [pin_dll] macro to set dll pinning +pub use ctor; pub use hooks::{CompileTimeHook, RuntimeErrorHook}; -pub use init::{FullInitFunc, PartialInitFunc, PartialShutdownFunc, FullShutdownFunc}; +pub use init::{FullInitFunc, FullShutdownFunc, PartialInitFunc, PartialShutdownFunc}; +/// Used by the [hook](attr.hook.html) macro to aggregate all compile-time hooks +pub use inventory; pub use list::List; pub use proc::Proc; pub use raw_types::variables::VariableNameIdTable; pub use runtime::{DMResult, Runtime}; use std::ffi::c_void; +use std::sync::atomic::{AtomicBool, Ordering}; pub use string::StringRef; pub use string_intern::InternedString; pub use value::Value; pub use weak_value::WeakValue; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::ops::RangeBounds; -use once_cell::sync::Lazy; -/// Used by the [hook](attr.hook.html) macro to aggregate all compile-time hooks -pub use inventory; -/// Used by the [pin_dll] macro to set dll pinning -pub use ctor; // We need winapi to call GetModuleHandleExW which lets us prevent our DLL from unloading. #[cfg(windows)] @@ -164,7 +161,6 @@ pub static PIN_DLL: AtomicBool = AtomicBool::new(true); #[cfg(windows)] fn pin_dll() -> Result<(), ()> { unsafe { - use winapi::um::libloaderapi::{ GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_PIN, @@ -173,14 +169,10 @@ fn pin_dll() -> Result<(), ()> { let flags = match PIN_DLL.load(Ordering::Relaxed) { true => GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, - false => GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + false => GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, }; - let res = GetModuleHandleExW( - flags, - pin_dll as *const _, - &mut module, - ); + let res = GetModuleHandleExW(flags, pin_dll as *const _, &mut module); if res == 0 { return Err(()); diff --git a/auxtools/src/sigscan.rs b/auxtools/src/sigscan.rs index 0b42dc4f..170092c7 100644 --- a/auxtools/src/sigscan.rs +++ b/auxtools/src/sigscan.rs @@ -3,7 +3,7 @@ mod linux; #[cfg(windows)] mod windows; -use std::ops::{RangeBounds, Bound}; +use std::ops::{Bound, RangeBounds}; #[cfg(unix)] pub use linux::Scanner; @@ -12,10 +12,12 @@ pub use windows::Scanner; pub use auxtools_impl::convert_signature; +pub use once_cell; + #[macro_export] macro_rules! signature { ($sig:tt) => { - sigscan::convert_signature!($sig) + $crate::sigscan::convert_signature!($sig) }; } @@ -23,10 +25,10 @@ macro_rules! signature { macro_rules! signatures { ( $( $name:ident => $sig:expr ),*) => { struct Signatures { - $( pub $name: SignatureMap, )* + $( pub $name: $crate::sigscan::SignatureMap, )* } - static SIGNATURES0: Lazy = Lazy::new(|| Signatures { + static SIGNATURES0: $crate::sigscan::once_cell::sync::Lazy = $crate::sigscan::once_cell::sync::Lazy::new(|| Signatures { $( $name: $sig, )* }); }; @@ -35,24 +37,33 @@ macro_rules! signatures { #[macro_export] macro_rules! signature_struct { (call, $sig:tt) => { - Signature{ treatment: SignatureTreatment::OffsetByCall, bytes: signature!($sig) } + $crate::sigscan::Signature { + treatment: $crate::sigscan::SignatureTreatment::OffsetByCall, + bytes: signature!($sig), + } }; ($offset:literal, $sig:tt) => { - Signature{ treatment: SignatureTreatment::OffsetByInt($offset), bytes: signature!($sig) } + $crate::sigscan::Signature { + treatment: $crate::sigscan::SignatureTreatment::OffsetByInt($offset), + bytes: signature!($sig), + } }; (($spec:tt, $sig:tt)) => { signature_struct!($spec, $sig) }; ($sig:tt) => { - Signature{ treatment: SignatureTreatment::NoOffset, bytes: signature!($sig) } + $crate::sigscan::Signature { + treatment: $crate::sigscan::SignatureTreatment::NoOffset, + bytes: signature!($sig), + } }; } #[macro_export] macro_rules! version_dependent_signature { ( $($range:expr => $sig:tt),* ) => { - SignatureMap::VersionDependent(vec![ - $((($range.start_bound(), $range.end_bound()), signature_struct!($sig)),)* + $crate::sigscan::SignatureMap::VersionDependent(vec![ + $(((std::ops::RangeBounds::start_bound(&$range), std::ops::RangeBounds::end_bound(&$range)), signature_struct!($sig)),)* ]) }; } @@ -60,13 +71,13 @@ macro_rules! version_dependent_signature { #[macro_export] macro_rules! universal_signature { (call, $sig:tt) => { - SignatureMap::AllVersions(signature_struct!(call, $sig)) + $crate::sigscan::SignatureMap::AllVersions(signature_struct!(call, $sig)) }; ($offset:literal, $sig:tt) => { - SignatureMap::AllVersions(signature_struct!($offset, $sig)) + $crate::sigscan::SignatureMap::AllVersions(signature_struct!($offset, $sig)) }; ($sig:tt) => { - SignatureMap::AllVersions(signature_struct!($sig)) + $crate::sigscan::SignatureMap::AllVersions(signature_struct!($sig)) }; } @@ -74,7 +85,7 @@ macro_rules! universal_signature { macro_rules! find_signature_inner { ($scanner:ident, $name:ident, $type:ty) => { let $name: $type; - if let Some(ptr) = SIGNATURES0.$name.find(&$scanner, version::get().1) { + if let Some(ptr) = SIGNATURES0.$name.find(&$scanner, $crate::version::get().1) { $name = ptr as $type; } else { return Some(format!("FAILED (Couldn't find {})", stringify!($name))); @@ -82,6 +93,18 @@ macro_rules! find_signature_inner { }; } +#[macro_export] +macro_rules! find_signature_inner_result { + ($scanner:ident, $name:ident, $type:ty) => { + let $name: $type; + if let Some(ptr) = SIGNATURES0.$name.find(&$scanner, $crate::version::get().1) { + $name = ptr as $type; + } else { + return Err(format!("FAILED (Couldn't find {})", stringify!($name))); + } + }; +} + #[macro_export] macro_rules! find_signature { ($scanner:ident, $name:ident as $type:ty) => { @@ -97,6 +120,21 @@ macro_rules! find_signature { }; } +#[macro_export] +macro_rules! find_signature_result { + ($scanner:ident, $name:ident as $type:ty) => { + find_signature_inner_result!($scanner, $name, $type); + }; + + ($scanner:ident, ($name:ident as $type:ty)) => { + find_signature_inner_result!($scanner, $name, $type); + }; + + ($scanner:ident, $name:ident) => { + find_signature_inner_result!($scanner, $name, *const c_void); + }; +} + #[macro_export] macro_rules! find_signatures { ($scanner:ident, $($sig:tt),* ) => { @@ -106,24 +144,36 @@ macro_rules! find_signatures { }; } +#[macro_export] +macro_rules! find_signatures_result { + ($scanner:ident, $($sig:tt),* ) => { + $( + find_signature_result!($scanner, $sig); + )* + }; +} -pub(crate) enum SignatureTreatment { +pub enum SignatureTreatment { NoOffset, OffsetByInt(isize), - OffsetByCall + OffsetByCall, } -pub(crate) struct Signature { +pub struct Signature { pub treatment: SignatureTreatment, - pub bytes: &'static [Option] + pub bytes: &'static [Option], } impl Signature { pub fn find(&self, scanner: &Scanner) -> Option<*const std::ffi::c_void> { scanner.find(&self.bytes).map(|address| unsafe { match self.treatment { - SignatureTreatment::NoOffset | SignatureTreatment::OffsetByInt(0) => std::mem::transmute(address as *const std::ffi::c_void), - SignatureTreatment::OffsetByInt(i) => *(address.offset(i) as *const *const std::ffi::c_void), + SignatureTreatment::NoOffset | SignatureTreatment::OffsetByInt(0) => { + std::mem::transmute(address as *const std::ffi::c_void) + } + SignatureTreatment::OffsetByInt(i) => { + *(address.offset(i) as *const *const std::ffi::c_void) + } SignatureTreatment::OffsetByCall => { let offset = *(address.offset(1) as *const isize); address.offset(5).offset(offset) as *const () as *const std::ffi::c_void @@ -133,22 +183,19 @@ impl Signature { } } -pub(crate) enum SignatureMap { +pub enum SignatureMap { AllVersions(Signature), - VersionDependent(Vec<((Bound<&'static u32>, Bound<&'static u32>), Signature)>) + VersionDependent(Vec<((Bound<&'static u32>, Bound<&'static u32>), Signature)>), } impl SignatureMap { pub fn find(&self, scanner: &Scanner, version: u32) -> Option<*const std::ffi::c_void> { match self { Self::AllVersions(signature) => signature.find(scanner), - Self::VersionDependent(map) => { - map.iter().find(|(version_range, _)| { - version_range.contains(&version) - }).and_then(|(_, signature)| { - signature.find(scanner) - }) - } + Self::VersionDependent(map) => map + .iter() + .find(|(version_range, _)| version_range.contains(&version)) + .and_then(|(_, signature)| signature.find(scanner)), } } } diff --git a/auxtools/src/sigscan/linux.rs b/auxtools/src/sigscan/linux.rs index 2da9319e..213b0a35 100644 --- a/auxtools/src/sigscan/linux.rs +++ b/auxtools/src/sigscan/linux.rs @@ -60,7 +60,12 @@ impl Scanner { memory_len: 0, memory_area: None, }; - unsafe { dl_iterate_phdr(Some(dl_phdr_callback), &mut data as *mut CallbackData as *mut c_void) }; + unsafe { + dl_iterate_phdr( + Some(dl_phdr_callback), + &mut data as *mut CallbackData as *mut c_void, + ) + }; let mut data_current = data.memory_start as *mut u8; let data_end = (data.memory_start + data.memory_len) as *mut u8; diff --git a/debug_server/src/instruction_hooking.rs b/debug_server/src/instruction_hooking.rs index 22eb57cb..03bf2da8 100644 --- a/debug_server/src/instruction_hooking.rs +++ b/debug_server/src/instruction_hooking.rs @@ -1,9 +1,15 @@ -use std::cell::UnsafeCell; -use instruction_hooking::{InstructionHook, disassemble_env::{DisassembleEnv, self}}; -use crate::{server_types::{BreakpointReason, ContinueKind}, server::Server}; use crate::DEBUG_SERVER; +use crate::{ + server::Server, + server_types::{BreakpointReason, ContinueKind}, +}; use auxtools::*; +use instruction_hooking::{ + disassemble_env::{self, DisassembleEnv}, + InstructionHook, +}; use lazy_static::lazy_static; +use std::cell::UnsafeCell; use std::collections::HashMap; use std::sync::Mutex; diff --git a/debug_server/src/lib.rs b/debug_server/src/lib.rs index b4b4fa82..1da49558 100644 --- a/debug_server/src/lib.rs +++ b/debug_server/src/lib.rs @@ -14,7 +14,7 @@ mod mem_profiler; #[cfg(not(windows))] mod mem_profiler_stub; -use ::instruction_hooking::{INSTRUCTION_HOOKS, InstructionHook}; +use ::instruction_hooking::{InstructionHook, INSTRUCTION_HOOKS}; #[cfg(not(windows))] use mem_profiler_stub as mem_profiler; @@ -52,15 +52,15 @@ fn get_default_port() -> u16 { } struct DebugServerInstructionHook<'a> { - debug_server: &'a mut UnsafeCell> + debug_server: &'a mut UnsafeCell>, } impl InstructionHook for DebugServerInstructionHook<'static> { - fn handle_instruction(&mut self, ctx: *mut raw_types::procs::ExecutionContext) { - if let Some(debug_server) = self.debug_server.get_mut() { + fn handle_instruction(&mut self, ctx: *mut raw_types::procs::ExecutionContext) { + if let Some(debug_server) = self.debug_server.get_mut() { debug_server.handle_instruction(ctx); } - } + } } #[hook("/proc/enable_debugging")] @@ -100,16 +100,13 @@ fn enable_debugging(mode: Value, port: Value) { unsafe { *DEBUG_SERVER.get() = Some(server); debug_server_instruction_hook = DebugServerInstructionHook { - debug_server: &mut DEBUG_SERVER + debug_server: &mut DEBUG_SERVER, }; - } - let hook_box = Box::new(debug_server_instruction_hook); - - INSTRUCTION_HOOKS.with(|hooks|{ - let mut hooks_ref = hooks.borrow_mut(); - hooks_ref.push(hook_box); - }); + INSTRUCTION_HOOKS + .get_mut() + .push(Box::new(debug_server_instruction_hook)); + } Ok(Value::null()) } diff --git a/debug_server/src/server.rs b/debug_server/src/server.rs index 60d77f14..2a0ffc06 100644 --- a/debug_server/src/server.rs +++ b/debug_server/src/server.rs @@ -12,7 +12,7 @@ use std::{ }; use clap::{Arg, Command}; -use instruction_hooking::{disassemble_env}; +use instruction_hooking::disassemble_env; use super::server_types::*; use auxtools::raw_types::values::{ValueData, ValueTag}; @@ -350,15 +350,22 @@ impl Server { for i in 1..=len { let key = list.get(i)?; - if let Ok(value) = list.get(&key) { - if value.raw.tag != raw_types::values::ValueTag::Null { - // assoc entry - variables.push(Variable { - name: format!("[{}]", i), - value: format!("{} = {}", Self::stringify(&key), Self::stringify(&value)), - variables: Some(state.get_ref(Variables::ListPair { key, value })), - }); - continue; + // assoc entry + if key.raw.tag != raw_types::values::ValueTag::Number { + if let Ok(value) = list.get(&key) { + if value.raw.tag != raw_types::values::ValueTag::Null { + variables.push(Variable { + name: format!("[{}]", i), + value: format!( + "{} = {}", + Self::stringify(&key), + Self::stringify(&value) + ), + variables: Some(state.get_ref(Variables::ListPair { key, value })), + }); + + continue; + } } } diff --git a/instruction_hooking/src/lib.rs b/instruction_hooking/src/lib.rs index 449e2d5c..650d517c 100644 --- a/instruction_hooking/src/lib.rs +++ b/instruction_hooking/src/lib.rs @@ -1,30 +1,40 @@ pub mod disassemble_env; -use std::{cell::RefCell, ffi::c_void, any::Any}; +use std::{any::Any, cell::UnsafeCell, ffi::c_void}; use auxtools::*; use detour::RawDetour; +#[cfg(windows)] +signatures! { + execute_instruction => version_dependent_signature!( + 1590.. => "0F B7 48 ?? 8B ?? ?? 8B F1 8B ?? ?? 81 ?? ?? ?? 00 00 0F 87 ?? ?? ?? ??", + ..1590 => "0F B7 48 ?? 8B 78 ?? 8B F1 8B 14 ?? 81 FA ?? ?? 00 00 0F 87 ?? ?? ?? ??" + ) +} + +#[cfg(unix)] +signatures! { + execute_instruction => universal_signature!("0F B7 47 ?? 8B 57 ?? 0F B7 D8 8B 0C ?? 81 F9 ?? ?? 00 00 77 ?? FF 24 8D ?? ?? ?? ??") +} + // stackoverflow copypasta https://old.reddit.com/r/rust/comments/kkap4e/how_to_cast_a_boxdyn_mytrait_to_an_actual_struct/ pub trait InstructionHookToAny: 'static { - fn as_any(&mut self) -> &mut dyn Any; + fn as_any(&mut self) -> &mut dyn Any; } impl InstructionHookToAny for T { - fn as_any(&mut self) -> &mut dyn Any { - self - } + fn as_any(&mut self) -> &mut dyn Any { + self + } } -pub trait InstructionHook : InstructionHookToAny { +pub trait InstructionHook: InstructionHookToAny { fn handle_instruction(&mut self, ctx: *mut raw_types::procs::ExecutionContext); } -thread_local! { - pub static INSTRUCTION_HOOKS: RefCell>> = RefCell::new(Vec::new()); -} - -static mut EXECUTE_INSTRUCTION: *const c_void = std::ptr::null(); +pub static mut INSTRUCTION_HOOKS: UnsafeCell>> = + UnsafeCell::new(Vec::new()); extern "C" { // Trampoline to the original un-hooked BYOND execute_instruction code @@ -38,39 +48,19 @@ extern "C" { fn instruction_hooking_init() -> Result<(), String> { let byondcore = sigscan::Scanner::for_module(BYONDCORE).unwrap(); - if cfg!(windows) { - let ptr = byondcore - .find(signature!( - "0F B7 48 ?? 8B 78 ?? 8B F1 8B 14 ?? 81 FA ?? ?? 00 00 0F 87 ?? ?? ?? ??" - )) - .ok_or_else(|| "Couldn't find EXECUTE_INSTRUCTION")?; - - unsafe { - EXECUTE_INSTRUCTION = ptr as *const c_void; - } - } - - if cfg!(unix) { - let ptr = byondcore - .find(signature!( - "0F B7 47 ?? 8B 57 ?? 0F B7 D8 8B 0C ?? 81 F9 ?? ?? 00 00 77 ?? FF 24 8D ?? ?? ?? ??" - )) - .ok_or_else(|| "Couldn't find EXECUTE_INSTRUCTION")?; - - unsafe { - EXECUTE_INSTRUCTION = ptr as *const c_void; - } + find_signatures_result! { byondcore, + execute_instruction } unsafe { let hook = RawDetour::new( - EXECUTE_INSTRUCTION as *const (), + execute_instruction as *const (), execute_instruction_hook as *const (), ) - .map_err(|_| "Couldn't detour EXECUTE_INSTRUCTION")?; + .map_err(|_| "Couldn't detour execute_instruction")?; hook.enable() - .map_err(|_| "Couldn't enable EXECUTE_INSTRUCTION detour")?; + .map_err(|_| "Couldn't enable execute_instruction detour")?; execute_instruction_original = std::mem::transmute(hook.trampoline()); @@ -83,8 +73,9 @@ fn instruction_hooking_init() -> Result<(), String> { #[shutdown] fn instruction_hooking_shutdown() { - INSTRUCTION_HOOKS.with(|hooks| - hooks.borrow_mut().clear()); + unsafe { + INSTRUCTION_HOOKS.get_mut().clear(); + } } // Handles any instruction BYOND tries to execute. @@ -93,13 +84,11 @@ fn instruction_hooking_shutdown() { extern "C" fn handle_instruction( ctx: *mut raw_types::procs::ExecutionContext, ) -> *const raw_types::procs::ExecutionContext { - INSTRUCTION_HOOKS.with(|hooks_cell|{ - let mut hooks_ref = hooks_cell.borrow_mut(); - let iter = hooks_ref.iter_mut(); - for vec_box in iter { + unsafe { + for vec_box in &mut *INSTRUCTION_HOOKS.get() { vec_box.handle_instruction(ctx); } - }); + } ctx }