commonlibsse_ng_proc_macro_common\relocate_fn/
mod.rs

1mod attr_args;
2
3use crate::fn_args_parser::{FnArgs, create_fn_args};
4use proc_macro2::TokenStream;
5
6pub fn gen_relocate_fn(
7    attrs: TokenStream,
8    item_fn: syn::ItemFn,
9    crate_root_name: TokenStream,
10) -> TokenStream {
11    let args = {
12        let attr_args = match darling::ast::NestedMeta::parse_meta_list(attrs) {
13            Ok(v) => v,
14            Err(e) => {
15                return darling::Error::from(e).write_errors();
16            }
17        };
18
19        match <attr_args::MacroArgs as darling::FromMeta>::from_list(&attr_args) {
20            Ok(v) => v,
21            Err(e) => {
22                return e.write_errors();
23            }
24        }
25    };
26    generate_code(args, item_fn, crate_root_name)
27}
28
29fn generate_code(
30    args: attr_args::MacroArgs,
31    item_fn: syn::ItemFn,
32    crate_root_name: TokenStream,
33) -> TokenStream {
34    let attr_args::MacroArgs { se_id, ae_id, vr_id } = args;
35    let vr_id = vr_id.unwrap_or(se_id);
36
37    let syn::ItemFn { attrs, vis, sig, block } = &item_fn;
38    let syn::Signature {
39        constness,
40        asyncness,
41        unsafety,
42        abi,
43        ident,
44        generics,
45        inputs: fn_inputs,
46        variadic,
47        output: fn_output,
48        ..
49    } = &sig;
50
51    let FnArgs { call_args, type_args, self_type, cast_self } = create_fn_args(fn_inputs, variadic);
52
53    let fn_type = quote::quote! { #constness #asyncness #unsafety #abi fn #generics (#self_type #type_args) #fn_output };
54
55    let fn_sig = quote::quote! { #vis #constness #asyncness #unsafety #abi fn #ident #generics (#fn_inputs) #fn_output };
56    let stmts = &block.stmts;
57
58    #[cfg(feature = "tracing")]
59    let database_err_log = quote::quote! { #crate_root_name::__private::tracing::error!("[Critical Error] Failed to resolve address: {err}") };
60    #[cfg(not(feature = "tracing"))]
61    let database_err_log = quote::quote! {};
62
63    #[cfg(feature = "tracing")]
64    let ptr_err_log = quote::quote! {
65        #crate_root_name::__private::tracing::error!(
66            "Resolved Address, but no permission permission to access this address: {:#?} (se_id: {}, ae_id: {}, vr_id: {})",
67            fn_ptr.as_ptr(),
68            #se_id,
69            #ae_id,
70            #vr_id
71        );
72    };
73    #[cfg(not(feature = "tracing"))]
74    let ptr_err_log = quote::quote! {};
75
76    quote::quote! {
77        #(#attrs)*
78        #[allow(clippy::use_self)]
79        #fn_sig {
80            #(#stmts)*
81
82            /// Function signature for self.
83            /// `self` is automatically `this: *const ()`, `this: *mut ()`, etc..
84            ///
85            /// This is created because Rust does not have a function equivalent to `decltype(T)` in C++.
86            type SelfSignature = #fn_type;
87
88            {
89                static FUNC: std::sync::LazyLock<SelfSignature> = std::sync::LazyLock::new(|| {
90                    use core::ptr::NonNull;
91
92                    use #crate_root_name::rel::id::RelocationID;
93                    use #crate_root_name::rel::ResolvableAddress as _;
94
95                    let fn_ptr = RelocationID::new(#se_id, #ae_id, #vr_id).address().unwrap_or_else(|err| {
96                        #database_err_log;
97                        panic!("Failed to resolve address: {err}");
98                    });
99                    if !#crate_root_name::rex::win32::is_valid_range(fn_ptr.as_ptr().cast(), core::mem::size_of::<usize>()) {
100                        #ptr_err_log;
101                    }
102                    unsafe { core::mem::transmute::<NonNull<core::ffi::c_void>, SelfSignature>(fn_ptr) }
103                });
104                FUNC(#cast_self #call_args)
105            }
106        }
107    }
108}