deno_libffi_sys/
lib.rs

1#![doc(html_root_url = "https://docs.rs/libffi-sys/1.1.1")]
2//! Low-level Rust bindings for [libffi](https://sourceware.org/libffi/)
3//!
4//! The C libffi library provides two main facilities: assembling calls
5//! to functions dynamically, and creating closures that can be called
6//! as ordinary C functions.
7//!
8//! This is an undocumented wrapper, originally generated by bindgen then
9//! cleaned up manually, intended as the basis for higher-level bindings, but
10//! you can see the [C libffi
11//! documentation](http://www.atmark-techno.com/~yashi/libffi.html).
12//!
13//! See [the libffi crate](https://crates.io/crates/libffi/) for a
14//! higher-level API.
15//!
16//! # Usage
17//!
18//! `libffi-sys` can either build its own copy of the libffi C library [from
19//! github](https://github.com/libffi/libffi) or it can link against your
20//! system’s C libffi. By default it builds its own because many systems
21//! ship with an old C libffi; this requires that you have a working make,
22//! C compiler, automake, and autoconf first. If your system libffi
23//! is new enough (v3.2.1 as of October 2019), you can instead enable the
24//! `system` feature flag to use that. If you want this crate to build
25//! a C libffi for you, add
26//!
27//! ```toml
28//! [dependencies]
29//! libffi-sys = "1.1.1"
30//! ```
31//!
32//! to your `Cargo.toml`. If you want to use your system C libffi, then
33//!
34//! ```toml
35//! [dependencies.libffi-sys]
36//! version = "1.1.1"
37//! features = ["system"]
38//! ```
39//!
40//! to your `Cargo.toml` instead.
41//!
42//! This crate supports Rust version 1.32 and later.
43
44#![allow(non_camel_case_types)]
45#![allow(non_snake_case)]
46#![allow(non_upper_case_globals)]
47#![allow(improper_ctypes)]
48#![allow(unused_imports)]
49
50use std::fmt::{self, Debug};
51use std::mem::zeroed;
52use std::os::raw::{c_char, c_int, c_long, c_schar, c_uint, c_ulong, c_ushort, c_void};
53
54mod arch;
55pub use arch::*;
56use fmt::Formatter;
57
58pub type ffi_arg = c_ulong;
59pub type ffi_sarg = c_long;
60pub type ffi_abi = u32;
61pub type ffi_status = u32;
62pub type ffi_type_enum = u32;
63
64pub const FFI_64_BIT_MAX: u64 = 9223372036854775807;
65pub const FFI_CLOSURES: u32 = 1;
66pub const FFI_SIZEOF_ARG: usize = std::mem::size_of::<c_long>();
67// NOTE: This only differs from FFI_SIZEOF_ARG on ILP platforms, which Rust does not support
68pub const FFI_SIZEOF_JAVA_RAW: usize = FFI_SIZEOF_ARG;
69
70pub const FFI_TYPE_VOID: u32 = 0;
71pub const FFI_TYPE_INT: u32 = 1;
72pub const FFI_TYPE_FLOAT: u32 = 2;
73pub const FFI_TYPE_DOUBLE: u32 = 3;
74pub const FFI_TYPE_LONGDOUBLE: u32 = 4;
75pub const FFI_TYPE_UINT8: u32 = 5;
76pub const FFI_TYPE_SINT8: u32 = 6;
77pub const FFI_TYPE_UINT16: u32 = 7;
78pub const FFI_TYPE_SINT16: u32 = 8;
79pub const FFI_TYPE_UINT32: u32 = 9;
80pub const FFI_TYPE_SINT32: u32 = 10;
81pub const FFI_TYPE_UINT64: u32 = 11;
82pub const FFI_TYPE_SINT64: u32 = 12;
83pub const FFI_TYPE_STRUCT: u32 = 13;
84pub const FFI_TYPE_POINTER: u32 = 14;
85pub const FFI_TYPE_COMPLEX: u32 = 15;
86pub const FFI_TYPE_LAST: u32 = 15;
87
88pub const ffi_status_FFI_OK: ffi_status = 0;
89pub const ffi_status_FFI_BAD_TYPEDEF: ffi_status = 1;
90pub const ffi_status_FFI_BAD_ABI: ffi_status = 2;
91
92pub const ffi_type_enum_STRUCT: ffi_type_enum = 13;
93pub const ffi_type_enum_COMPLEX: ffi_type_enum = 15;
94
95#[repr(C)]
96#[derive(Debug, Copy, Clone)]
97pub struct ffi_type {
98    pub size: usize,
99    pub alignment: c_ushort,
100    pub type_: c_ushort,
101    pub elements: *mut *mut ffi_type,
102}
103
104impl Default for ffi_type {
105    fn default() -> Self {
106        unsafe { zeroed() }
107    }
108}
109
110#[repr(C)]
111#[derive(Debug, Copy, Clone)]
112pub struct ffi_cif {
113    pub abi: ffi_abi,
114    pub nargs: c_uint,
115    pub arg_types: *mut *mut ffi_type,
116    pub rtype: *mut ffi_type,
117    pub bytes: c_uint,
118    pub flags: c_uint,
119    #[cfg(all(target_arch = "aarch64", target_os = "windows"))]
120    pub is_variadic: c_uint,
121    #[cfg(all(target_arch = "aarch64", target_vendor = "apple"))]
122    pub aarch64_nfixedargs: c_uint,
123    #[cfg(all(target_arch = "arm"))]
124    pub vfp_used: c_int,
125    #[cfg(all(target_arch = "arm"))]
126    pub vfp_reg_free: c_ushort,
127    #[cfg(all(target_arch = "arm"))]
128    pub vfp_nargs: c_ushort,
129    #[cfg(all(target_arch = "arm"))]
130    pub vfp_args: [c_schar; 16],
131    #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
132    pub nfixedargs: c_uint,
133}
134
135impl Default for ffi_cif {
136    fn default() -> Self {
137        unsafe { zeroed() }
138    }
139}
140
141#[repr(C)]
142#[derive(Copy, Clone)]
143pub union ffi_raw {
144    pub sint: ffi_sarg,
145    pub uint: ffi_arg,
146    pub flt: f32,
147    pub data: [c_char; FFI_SIZEOF_ARG],
148    pub ptr: *mut c_void,
149    _bindgen_union_align: u64,
150}
151
152impl Default for ffi_raw {
153    fn default() -> Self {
154        unsafe { zeroed() }
155    }
156}
157
158pub type ffi_java_raw = ffi_raw;
159
160#[repr(C)]
161#[derive(Copy, Clone)]
162pub struct ffi_closure {
163    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
164    pub cif: *mut ffi_cif,
165    pub fun: Option<
166        unsafe extern "C" fn(
167            arg1: *mut ffi_cif,
168            arg2: *mut c_void,
169            arg3: *mut *mut c_void,
170            arg4: *mut c_void,
171        ),
172    >,
173    pub user_data: *mut c_void,
174}
175
176/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
177impl Debug for ffi_closure {
178    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
179        f.debug_struct("ffi_closure")
180            .field("tramp", &&self.tramp[..])
181            .field("cif", &self.cif)
182            .field("fun", &self.fun)
183            .field("user_data", &self.user_data)
184            .finish()
185    }
186}
187
188impl Default for ffi_closure {
189    fn default() -> Self {
190        unsafe { zeroed() }
191    }
192}
193
194#[repr(C)]
195#[derive(Copy, Clone)]
196pub struct ffi_raw_closure {
197    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
198    pub cif: *mut ffi_cif,
199    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L364
200    #[cfg(not(target_arch = "i686"))]
201    pub translate_args: Option<
202        unsafe extern "C" fn(
203            arg1: *mut ffi_cif,
204            arg2: *mut c_void,
205            arg3: *mut *mut c_void,
206            arg4: *mut c_void,
207        ),
208    >,
209    #[cfg(not(target_arch = "i686"))]
210    pub this_closure: *mut c_void,
211    pub fun: Option<
212        unsafe extern "C" fn(
213            arg1: *mut ffi_cif,
214            arg2: *mut c_void,
215            arg3: *mut ffi_raw,
216            arg4: *mut c_void,
217        ),
218    >,
219    pub user_data: *mut c_void,
220}
221
222/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
223impl Debug for ffi_raw_closure {
224    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
225        let mut debug_struct = f.debug_struct("ffi_raw_closure");
226        debug_struct
227            .field("tramp", &&self.tramp[..])
228            .field("cif", &self.cif);
229
230        #[cfg(not(target_arch = "i686"))]
231        debug_struct.field("translate_args", &self.translate_args);
232        #[cfg(not(target_arch = "i686"))]
233        debug_struct.field("this_closure", &self.this_closure);
234
235        debug_struct
236            .field("fun", &self.fun)
237            .field("user_data", &self.user_data)
238            .finish()
239    }
240}
241
242impl Default for ffi_raw_closure {
243    fn default() -> Self {
244        unsafe { zeroed() }
245    }
246}
247#[repr(C)]
248#[derive(Copy, Clone)]
249pub struct ffi_java_raw_closure {
250    pub tramp: [c_char; FFI_TRAMPOLINE_SIZE],
251    pub cif: *mut ffi_cif,
252    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L390
253    #[cfg(not(target_arch = "i686"))]
254    pub translate_args: Option<
255        unsafe extern "C" fn(
256            arg1: *mut ffi_cif,
257            arg2: *mut c_void,
258            arg3: *mut *mut c_void,
259            arg4: *mut c_void,
260        ),
261    >,
262    #[cfg(not(target_arch = "i686"))]
263    pub this_closure: *mut c_void,
264    pub fun: Option<
265        unsafe extern "C" fn(
266            arg1: *mut ffi_cif,
267            arg2: *mut c_void,
268            arg3: *mut ffi_java_raw,
269            arg4: *mut c_void,
270        ),
271    >,
272    pub user_data: *mut c_void,
273}
274
275/// Implements Debug manually since sometimes FFI_TRAMPOLINE_SIZE is too large
276impl Debug for ffi_java_raw_closure {
277    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
278        let mut debug_struct = f.debug_struct("ffi_java_raw_closure");
279        debug_struct
280            .field("tramp", &&self.tramp[..])
281            .field("cif", &self.cif);
282
283        #[cfg(not(target_arch = "i686"))]
284        debug_struct.field("translate_args", &self.translate_args);
285        #[cfg(not(target_arch = "i686"))]
286        debug_struct.field("this_closure", &self.this_closure);
287
288        debug_struct
289            .field("fun", &self.fun)
290            .field("user_data", &self.user_data)
291            .finish()
292    }
293}
294
295impl Default for ffi_java_raw_closure {
296    fn default() -> Self {
297        unsafe { zeroed() }
298    }
299}
300
301#[repr(C)]
302#[derive(Debug, Copy, Clone)]
303pub struct ffi_go_closure {
304    pub tramp: *mut c_void,
305    pub cif: *mut ffi_cif,
306    pub fun: Option<
307        unsafe extern "C" fn(
308            arg1: *mut ffi_cif,
309            arg2: *mut c_void,
310            arg3: *mut *mut c_void,
311            arg4: *mut c_void,
312        ),
313    >,
314}
315impl Default for ffi_go_closure {
316    fn default() -> Self {
317        unsafe { zeroed() }
318    }
319}
320
321extern "C" {
322    pub static mut ffi_type_void: ffi_type;
323    pub static mut ffi_type_uint8: ffi_type;
324    pub static mut ffi_type_sint8: ffi_type;
325    pub static mut ffi_type_uint16: ffi_type;
326    pub static mut ffi_type_sint16: ffi_type;
327    pub static mut ffi_type_uint32: ffi_type;
328    pub static mut ffi_type_sint32: ffi_type;
329    pub static mut ffi_type_uint64: ffi_type;
330    pub static mut ffi_type_sint64: ffi_type;
331    pub static mut ffi_type_float: ffi_type;
332    pub static mut ffi_type_double: ffi_type;
333    pub static mut ffi_type_pointer: ffi_type;
334
335    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
336    pub static mut ffi_type_longdouble: ffi_type;
337
338    #[cfg(feature = "complex")]
339    pub static mut ffi_type_complex_float: ffi_type;
340
341    #[cfg(feature = "complex")]
342    pub static mut ffi_type_complex_double: ffi_type;
343
344    #[cfg(feature = "complex")]
345    #[cfg(not(all(target_arch = "arm", target_os = "linux", target_env = "gnu")))]
346    pub static mut ffi_type_complex_longdouble: ffi_type;
347
348    pub fn ffi_raw_call(
349        cif: *mut ffi_cif,
350        fn_: Option<unsafe extern "C" fn()>,
351        rvalue: *mut c_void,
352        avalue: *mut ffi_raw,
353    );
354
355    pub fn ffi_ptrarray_to_raw(cif: *mut ffi_cif, args: *mut *mut c_void, raw: *mut ffi_raw);
356
357    pub fn ffi_raw_to_ptrarray(cif: *mut ffi_cif, raw: *mut ffi_raw, args: *mut *mut c_void);
358
359    pub fn ffi_raw_size(cif: *mut ffi_cif) -> usize;
360
361    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L286
362    #[cfg(not(target_arch = "i686"))]
363    pub fn ffi_java_raw_call(
364        cif: *mut ffi_cif,
365        fn_: Option<unsafe extern "C" fn()>,
366        rvalue: *mut c_void,
367        avalue: *mut ffi_java_raw,
368    );
369
370    pub fn ffi_java_ptrarray_to_raw(
371        cif: *mut ffi_cif,
372        args: *mut *mut c_void,
373        raw: *mut ffi_java_raw,
374    );
375
376    pub fn ffi_java_raw_to_ptrarray(
377        cif: *mut ffi_cif,
378        raw: *mut ffi_java_raw,
379        args: *mut *mut c_void,
380    );
381
382    pub fn ffi_java_raw_size(cif: *mut ffi_cif) -> usize;
383
384    pub fn ffi_closure_alloc(size: usize, code: *mut *mut c_void) -> *mut c_void;
385
386    pub fn ffi_closure_free(arg1: *mut c_void);
387
388    pub fn ffi_prep_closure(
389        arg1: *mut ffi_closure,
390        arg2: *mut ffi_cif,
391        fun: Option<
392            unsafe extern "C" fn(
393                arg1: *mut ffi_cif,
394                arg2: *mut c_void,
395                arg3: *mut *mut c_void,
396                arg4: *mut c_void,
397            ),
398        >,
399        user_data: *mut c_void,
400    ) -> ffi_status;
401
402    pub fn ffi_prep_closure_loc(
403        arg1: *mut ffi_closure,
404        arg2: *mut ffi_cif,
405        fun: Option<
406            unsafe extern "C" fn(
407                arg1: *mut ffi_cif,
408                arg2: *mut c_void,
409                arg3: *mut *mut c_void,
410                arg4: *mut c_void,
411            ),
412        >,
413        user_data: *mut c_void,
414        codeloc: *mut c_void,
415    ) -> ffi_status;
416
417    pub fn ffi_prep_raw_closure(
418        arg1: *mut ffi_raw_closure,
419        cif: *mut ffi_cif,
420        fun: Option<
421            unsafe extern "C" fn(
422                arg1: *mut ffi_cif,
423                arg2: *mut c_void,
424                arg3: *mut ffi_raw,
425                arg4: *mut c_void,
426            ),
427        >,
428        user_data: *mut c_void,
429    ) -> ffi_status;
430
431    pub fn ffi_prep_raw_closure_loc(
432        arg1: *mut ffi_raw_closure,
433        cif: *mut ffi_cif,
434        fun: Option<
435            unsafe extern "C" fn(
436                arg1: *mut ffi_cif,
437                arg2: *mut c_void,
438                arg3: *mut ffi_raw,
439                arg4: *mut c_void,
440            ),
441        >,
442        user_data: *mut c_void,
443        codeloc: *mut c_void,
444    ) -> ffi_status;
445
446    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
447    #[cfg(not(target_arch = "i686"))]
448    pub fn ffi_prep_java_raw_closure(
449        arg1: *mut ffi_java_raw_closure,
450        cif: *mut ffi_cif,
451        fun: Option<
452            unsafe extern "C" fn(
453                arg1: *mut ffi_cif,
454                arg2: *mut c_void,
455                arg3: *mut ffi_java_raw,
456                arg4: *mut c_void,
457            ),
458        >,
459        user_data: *mut c_void,
460    ) -> ffi_status;
461
462    // See: https://github.com/libffi/libffi/blob/3a7580da73b7f16f275277316d00e3497cbb5a8c/include/ffi.h.in#L419
463    #[cfg(not(target_arch = "i686"))]
464    pub fn ffi_prep_java_raw_closure_loc(
465        arg1: *mut ffi_java_raw_closure,
466        cif: *mut ffi_cif,
467        fun: Option<
468            unsafe extern "C" fn(
469                arg1: *mut ffi_cif,
470                arg2: *mut c_void,
471                arg3: *mut ffi_java_raw,
472                arg4: *mut c_void,
473            ),
474        >,
475        user_data: *mut c_void,
476        codeloc: *mut c_void,
477    ) -> ffi_status;
478
479    pub fn ffi_prep_go_closure(
480        arg1: *mut ffi_go_closure,
481        arg2: *mut ffi_cif,
482        fun: Option<
483            unsafe extern "C" fn(
484                arg1: *mut ffi_cif,
485                arg2: *mut c_void,
486                arg3: *mut *mut c_void,
487                arg4: *mut c_void,
488            ),
489        >,
490    ) -> ffi_status;
491
492    pub fn ffi_call_go(
493        cif: *mut ffi_cif,
494        fn_: Option<unsafe extern "C" fn()>,
495        rvalue: *mut c_void,
496        avalue: *mut *mut c_void,
497        closure: *mut c_void,
498    );
499
500    pub fn ffi_prep_cif(
501        cif: *mut ffi_cif,
502        abi: ffi_abi,
503        nargs: c_uint,
504        rtype: *mut ffi_type,
505        atypes: *mut *mut ffi_type,
506    ) -> ffi_status;
507
508    pub fn ffi_prep_cif_var(
509        cif: *mut ffi_cif,
510        abi: ffi_abi,
511        nfixedargs: c_uint,
512        ntotalargs: c_uint,
513        rtype: *mut ffi_type,
514        atypes: *mut *mut ffi_type,
515    ) -> ffi_status;
516
517    pub fn ffi_call(
518        cif: *mut ffi_cif,
519        fn_: Option<unsafe extern "C" fn()>,
520        rvalue: *mut c_void,
521        avalue: *mut *mut c_void,
522    );
523
524    pub fn ffi_get_struct_offsets(
525        abi: ffi_abi,
526        struct_type: *mut ffi_type,
527        offsets: *mut usize,
528    ) -> ffi_status;
529}
530
531#[cfg(test)]
532mod test {
533    use super::*;
534
535    extern "C" fn add(x: u64, y: u64) -> u64 {
536        x + y
537    }
538
539    #[test]
540    fn test_function_with_two_arguments() {
541        unsafe {
542            let mut cif: ffi_cif = Default::default();
543            let mut arg_types: Vec<*mut ffi_type> =
544                vec![&mut ffi_type_uint64, &mut ffi_type_uint64];
545
546            let prep_status = ffi_prep_cif(
547                &mut cif,
548                ffi_abi_FFI_DEFAULT_ABI,
549                2,
550                &mut ffi_type_uint64,
551                arg_types.as_mut_ptr(),
552            );
553
554            assert_eq!(prep_status, ffi_status_FFI_OK);
555
556            let mut rval = 0u64;
557            let func = &*(&(add as *mut extern "C" fn(u64, u64) -> u64) as *const _
558                as *const extern "C" fn());
559
560            ffi_call(
561                &mut cif,
562                Some(*func),
563                &mut rval as *mut _ as *mut c_void,
564                vec![
565                    &mut 4u64 as *mut _ as *mut c_void,
566                    &mut 5u64 as *mut _ as *mut c_void,
567                ]
568                .as_mut_ptr(),
569            );
570
571            assert_eq!(rval, 9);
572        }
573    }
574}