diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index 5a81e201a1..8f399e4c65 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -171,7 +171,7 @@ where H: FnMut(&::Input) -> ExitKind + ?Sized, HB: BorrowMut, OT: ObserversTuple, - S: HasSolutions + HasClientPerfMonitor + HasCorpus, + S: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, { /// Create a new in mem executor. /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, @@ -255,7 +255,7 @@ where H: FnMut(&::Input) -> ExitKind + ?Sized, HB: BorrowMut, OT: ObserversTuple, - S: HasSolutions + HasClientPerfMonitor + HasCorpus, + S: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, { /// the timeout handler #[inline] @@ -350,7 +350,7 @@ impl InProcessHandlers { E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { #[cfg(unix)] @@ -380,7 +380,7 @@ impl InProcessHandlers { E: Executor + HasObservers + HasInProcessHandlers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { unsafe { @@ -591,7 +591,7 @@ pub fn run_observers_and_save_state( E: HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let observers = executor.observers_mut(); @@ -606,7 +606,7 @@ pub fn run_observers_and_save_state( .expect("In run_observers_and_save_state objective failure."); if interesting { - let mut new_testcase = Testcase::new(input.clone()); + let mut new_testcase = Testcase::with_executions(input.clone(), *state.executions()); new_testcase.add_metadata(exitkind); new_testcase.set_parent_id_optional(*state.corpus().current()); fuzzer @@ -657,7 +657,7 @@ pub mod unix_signal_handler { feedbacks::Feedback, fuzzer::HasObjective, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; pub(crate) type HandlerFuncPtr = unsafe fn( @@ -727,7 +727,7 @@ pub mod unix_signal_handler { E: HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let old_hook = panic::take_hook(); @@ -775,7 +775,7 @@ pub mod unix_signal_handler { E: HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { if !data.timeout_executor_ptr.is_null() @@ -825,7 +825,7 @@ pub mod unix_signal_handler { E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { #[cfg(all(target_os = "android", target_arch = "aarch64"))] @@ -937,7 +937,7 @@ pub mod windows_asan_handler { feedbacks::Feedback, fuzzer::HasObjective, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; /// # Safety @@ -947,7 +947,7 @@ pub mod windows_asan_handler { E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let data = &mut GLOBAL_STATE; @@ -1050,7 +1050,7 @@ pub mod windows_exception_handler { feedbacks::Feedback, fuzzer::HasObjective, inputs::UsesInput, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, }; pub(crate) type HandlerFuncPtr = @@ -1094,7 +1094,7 @@ pub mod windows_exception_handler { E: HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let old_hook = panic::take_hook(); @@ -1158,7 +1158,7 @@ pub mod windows_exception_handler { E: HasObservers + HasInProcessHandlers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let data: &mut InProcessExecutorHandlerData = @@ -1225,7 +1225,7 @@ pub mod windows_exception_handler { E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { // Have we set a timer_before? diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index c741685b80..2bddc0108b 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -231,7 +231,7 @@ impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where H: FnMut(&S::Input) -> ExitKind, - S: UsesInput + HasClientPerfMonitor + HasSolutions + HasCorpus, + S: UsesInput + HasClientPerfMonitor + HasSolutions + HasCorpus + HasExecutions, S::Input: HasTargetBytes, OT: ObserversTuple, RT: FridaRuntimeTuple, diff --git a/libafl_qemu/build_linux.rs b/libafl_qemu/build_linux.rs index 2400fdb8c6..516089432a 100644 --- a/libafl_qemu/build_linux.rs +++ b/libafl_qemu/build_linux.rs @@ -82,7 +82,11 @@ pub fn build() { .status() .expect("make failed") .success()); - assert!(Command::new("make") + let mut make = Command::new("make"); + if cfg!(debug_assertions) { + make.env("CFLAGS", "-DDEBUG=1"); + } + assert!(make .current_dir(out_dir_path) .env("CC", &cross_cc) .env("OUT_DIR", &target_dir) @@ -91,5 +95,6 @@ pub fn build() { .status() .expect("make failed") .success()); + println!("cargo:rerun-if-changed={}/libqasan.so", target_dir.display()); } } diff --git a/libafl_qemu/libafl_qemu_build/src/bindings.rs b/libafl_qemu/libafl_qemu_build/src/bindings.rs index 3c8955d674..9e918cf04f 100644 --- a/libafl_qemu/libafl_qemu_build/src/bindings.rs +++ b/libafl_qemu/libafl_qemu_build/src/bindings.rs @@ -61,6 +61,7 @@ const WRAPPER_HEADER: &str = r#" #endif #include "exec/cpu-common.h" +#include "exec/cpu-all.h" #include "exec/exec-all.h" #include "exec/translate-all.h" #include "exec/log.h" @@ -111,6 +112,7 @@ pub fn generate( .allowlist_function("target_mmap") .allowlist_function("target_mprotect") .allowlist_function("target_munmap") + .allowlist_function("page_check_range") .allowlist_function("cpu_memory_rw_debug") .allowlist_function("cpu_physical_memory_rw") .allowlist_function("cpu_reset") diff --git a/libafl_qemu/libafl_qemu_build/src/build.rs b/libafl_qemu/libafl_qemu_build/src/build.rs index b31bbaf4cf..4a05f8b188 100644 --- a/libafl_qemu/libafl_qemu_build/src/build.rs +++ b/libafl_qemu/libafl_qemu_build/src/build.rs @@ -8,7 +8,7 @@ use which::which; const QEMU_URL: &str = "https://github.com/AFLplusplus/qemu-libafl-bridge"; const QEMU_DIRNAME: &str = "qemu-libafl-bridge"; -const QEMU_REVISION: &str = "e42124c0c8363184ef286fde43dce1d5c607699b"; +const QEMU_REVISION: &str = "b0c827246517e36b480ad501cba5ac6e2c3f26f5"; fn build_dep_check(tools: &[&str]) { for tool in tools { diff --git a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs index b780f74d35..7f86c0117c 100644 --- a/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs +++ b/libafl_qemu/libafl_qemu_sys/src/x86_64_stub_bindings.rs @@ -1,9 +1,4 @@ -/* automatically generated by rust-bindgen 0.66.1 */ - -extern "C" { - #[doc = " qemu_target_page_size - return the target's page size"] - pub fn qemu_target_page_size() -> usize; -} +/* automatically generated by rust-bindgen 0.68.1 */ #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -85,8 +80,39 @@ where } } } +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); +impl __IncompleteArrayField { + #[inline] + pub const fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData, []) + } + #[inline] + pub fn as_ptr(&self) -> *const T { + self as *const _ as *const T + } + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + self as *mut _ as *mut T + } + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} pub type __off_t = ::std::os::raw::c_long; pub type __off64_t = ::std::os::raw::c_long; +pub type off_t = __off64_t; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct __sigset_t { @@ -1299,6 +1325,11 @@ impl Default for _GSList { } #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct AccelCPUState { + _unused: [u8; 0], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct AddressSpace { _unused: [u8; 0], } @@ -1334,11 +1365,6 @@ pub struct MemoryRegion { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct MemoryRegionSection { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct QDict { _unused: [u8; 0], } @@ -1434,6 +1460,9 @@ impl Default for QEnumLookup { } } } +extern "C" { + pub fn qemu_target_page_size() -> usize; +} #[repr(C)] #[derive(Copy, Clone)] pub struct QemuMutex { @@ -1584,6 +1613,36 @@ fn bindgen_test_layout_QemuThread() { } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] +pub struct QemuSpin { + pub value: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_QemuSpin() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(QemuSpin)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(QemuSpin)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).value) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(QemuSpin), + "::", + stringify!(value) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] pub struct QemuLockCnt { pub count: ::std::os::raw::c_uint, } @@ -1617,7 +1676,7 @@ fn bindgen_test_layout_QemuLockCnt() { #[derive(Debug, Default, Copy, Clone)] pub struct MemTxAttrs { pub _bitfield_align_1: [u16; 0], - pub _bitfield_1: __BindgenBitfieldUnit<[u8; 3usize]>, + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, } #[test] fn bindgen_test_layout_MemTxAttrs() { @@ -1656,86 +1715,98 @@ impl MemTxAttrs { } } #[inline] + pub fn space(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(2usize, 2u8) as u32) } + } + #[inline] + pub fn set_space(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(2usize, 2u8, val as u64) + } + } + #[inline] pub fn user(&self) -> ::std::os::raw::c_uint { - unsafe { ::std::mem::transmute(self._bitfield_1.get(2usize, 1u8) as u32) } + unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 1u8) as u32) } } #[inline] pub fn set_user(&mut self, val: ::std::os::raw::c_uint) { unsafe { let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(2usize, 1u8, val as u64) + self._bitfield_1.set(4usize, 1u8, val as u64) } } #[inline] pub fn memory(&self) -> ::std::os::raw::c_uint { - unsafe { ::std::mem::transmute(self._bitfield_1.get(3usize, 1u8) as u32) } + unsafe { ::std::mem::transmute(self._bitfield_1.get(5usize, 1u8) as u32) } } #[inline] pub fn set_memory(&mut self, val: ::std::os::raw::c_uint) { unsafe { let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(3usize, 1u8, val as u64) + self._bitfield_1.set(5usize, 1u8, val as u64) } } #[inline] pub fn requester_id(&self) -> ::std::os::raw::c_uint { - unsafe { ::std::mem::transmute(self._bitfield_1.get(4usize, 16u8) as u32) } + unsafe { ::std::mem::transmute(self._bitfield_1.get(6usize, 16u8) as u32) } } #[inline] pub fn set_requester_id(&mut self, val: ::std::os::raw::c_uint) { unsafe { let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(4usize, 16u8, val as u64) + self._bitfield_1.set(6usize, 16u8, val as u64) } } #[inline] pub fn byte_swap(&self) -> ::std::os::raw::c_uint { - unsafe { ::std::mem::transmute(self._bitfield_1.get(20usize, 1u8) as u32) } - } - #[inline] - pub fn set_byte_swap(&mut self, val: ::std::os::raw::c_uint) { - unsafe { - let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(20usize, 1u8, val as u64) - } - } - #[inline] - pub fn target_tlb_bit0(&self) -> ::std::os::raw::c_uint { - unsafe { ::std::mem::transmute(self._bitfield_1.get(21usize, 1u8) as u32) } - } - #[inline] - pub fn set_target_tlb_bit0(&mut self, val: ::std::os::raw::c_uint) { - unsafe { - let val: u32 = ::std::mem::transmute(val); - self._bitfield_1.set(21usize, 1u8, val as u64) - } - } - #[inline] - pub fn target_tlb_bit1(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(22usize, 1u8) as u32) } } #[inline] - pub fn set_target_tlb_bit1(&mut self, val: ::std::os::raw::c_uint) { + pub fn set_byte_swap(&mut self, val: ::std::os::raw::c_uint) { unsafe { let val: u32 = ::std::mem::transmute(val); self._bitfield_1.set(22usize, 1u8, val as u64) } } #[inline] - pub fn target_tlb_bit2(&self) -> ::std::os::raw::c_uint { + pub fn target_tlb_bit0(&self) -> ::std::os::raw::c_uint { unsafe { ::std::mem::transmute(self._bitfield_1.get(23usize, 1u8) as u32) } } #[inline] - pub fn set_target_tlb_bit2(&mut self, val: ::std::os::raw::c_uint) { + pub fn set_target_tlb_bit0(&mut self, val: ::std::os::raw::c_uint) { unsafe { let val: u32 = ::std::mem::transmute(val); self._bitfield_1.set(23usize, 1u8, val as u64) } } #[inline] + pub fn target_tlb_bit1(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(24usize, 1u8) as u32) } + } + #[inline] + pub fn set_target_tlb_bit1(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(24usize, 1u8, val as u64) + } + } + #[inline] + pub fn target_tlb_bit2(&self) -> ::std::os::raw::c_uint { + unsafe { ::std::mem::transmute(self._bitfield_1.get(25usize, 1u8) as u32) } + } + #[inline] + pub fn set_target_tlb_bit2(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(25usize, 1u8, val as u64) + } + } + #[inline] pub fn new_bitfield_1( unspecified: ::std::os::raw::c_uint, secure: ::std::os::raw::c_uint, + space: ::std::os::raw::c_uint, user: ::std::os::raw::c_uint, memory: ::std::os::raw::c_uint, requester_id: ::std::os::raw::c_uint, @@ -1743,8 +1814,8 @@ impl MemTxAttrs { target_tlb_bit0: ::std::os::raw::c_uint, target_tlb_bit1: ::std::os::raw::c_uint, target_tlb_bit2: ::std::os::raw::c_uint, - ) -> __BindgenBitfieldUnit<[u8; 3usize]> { - let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 3usize]> = Default::default(); + ) -> __BindgenBitfieldUnit<[u8; 4usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default(); __bindgen_bitfield_unit.set(0usize, 1u8, { let unspecified: u32 = unsafe { ::std::mem::transmute(unspecified) }; unspecified as u64 @@ -1753,31 +1824,35 @@ impl MemTxAttrs { let secure: u32 = unsafe { ::std::mem::transmute(secure) }; secure as u64 }); - __bindgen_bitfield_unit.set(2usize, 1u8, { + __bindgen_bitfield_unit.set(2usize, 2u8, { + let space: u32 = unsafe { ::std::mem::transmute(space) }; + space as u64 + }); + __bindgen_bitfield_unit.set(4usize, 1u8, { let user: u32 = unsafe { ::std::mem::transmute(user) }; user as u64 }); - __bindgen_bitfield_unit.set(3usize, 1u8, { + __bindgen_bitfield_unit.set(5usize, 1u8, { let memory: u32 = unsafe { ::std::mem::transmute(memory) }; memory as u64 }); - __bindgen_bitfield_unit.set(4usize, 16u8, { + __bindgen_bitfield_unit.set(6usize, 16u8, { let requester_id: u32 = unsafe { ::std::mem::transmute(requester_id) }; requester_id as u64 }); - __bindgen_bitfield_unit.set(20usize, 1u8, { + __bindgen_bitfield_unit.set(22usize, 1u8, { let byte_swap: u32 = unsafe { ::std::mem::transmute(byte_swap) }; byte_swap as u64 }); - __bindgen_bitfield_unit.set(21usize, 1u8, { + __bindgen_bitfield_unit.set(23usize, 1u8, { let target_tlb_bit0: u32 = unsafe { ::std::mem::transmute(target_tlb_bit0) }; target_tlb_bit0 as u64 }); - __bindgen_bitfield_unit.set(22usize, 1u8, { + __bindgen_bitfield_unit.set(24usize, 1u8, { let target_tlb_bit1: u32 = unsafe { ::std::mem::transmute(target_tlb_bit1) }; target_tlb_bit1 as u64 }); - __bindgen_bitfield_unit.set(23usize, 1u8, { + __bindgen_bitfield_unit.set(25usize, 1u8, { let target_tlb_bit2: u32 = unsafe { ::std::mem::transmute(target_tlb_bit2) }; target_tlb_bit2 as u64 }); @@ -2406,21 +2481,28 @@ pub type DeviceRealize = ::std::option::Option; pub type DeviceUnrealize = ::std::option::Option; pub type DeviceReset = ::std::option::Option; -#[doc = " DeviceClass:\n @props: Properties accessing state fields.\n @realize: Callback function invoked when the #DeviceState:realized\n property is changed to %true.\n @unrealize: Callback function invoked when the #DeviceState:realized\n property is changed to %false.\n @hotpluggable: indicates if #DeviceClass is hotpluggable, available\n as readonly \"hotpluggable\" property of #DeviceState instance\n\n # Realization #\n Devices are constructed in two stages,\n 1) object instantiation via object_initialize() and\n 2) device realization via #DeviceState:realized property.\n The former may not fail (and must not abort or exit, since it is called\n during device introspection already), and the latter may return error\n information to the caller and must be re-entrant.\n Trivial field initializations should go into #TypeInfo.instance_init.\n Operations depending on @props static properties should go into @realize.\n After successful realization, setting static properties will fail.\n\n As an interim step, the #DeviceState:realized property can also be\n set with qdev_realize().\n In the future, devices will propagate this state change to their children\n and along busses they expose.\n The point in time will be deferred to machine creation, so that values\n set in @realize will not be introspectable beforehand. Therefore devices\n must not create children during @realize; they should initialize them via\n object_initialize() in their own #TypeInfo.instance_init and forward the\n realization events appropriately.\n\n Any type may override the @realize and/or @unrealize callbacks but needs\n to call the parent type's implementation if keeping their functionality\n is desired. Refer to QOM documentation for further discussion and examples.\n\n \n \n Since TYPE_DEVICE doesn't implement @realize and @unrealize, types\n derived directly from it need not call their parent's @realize and\n @unrealize.\n For other types consult the documentation and implementation of the\n respective parent types.\n \n \n\n # Hiding a device #\n To hide a device, a DeviceListener function hide_device() needs to\n be registered.\n It can be used to defer adding a device and therefore hide it from\n the guest. The handler registering to this DeviceListener can save\n the QOpts passed to it for re-using it later. It must return if it\n wants the device to be hidden or visible. When the handler function\n decides the device shall be visible it will be added with\n qdev_device_add() and realized as any other device. Otherwise\n qdev_device_add() will return early without adding the device. The\n guest will not see a \"hidden\" device until it was marked visible\n and qdev_device_add called again.\n"] +#[doc = " struct DeviceClass - The base class for all devices.\n @props: Properties accessing state fields.\n @realize: Callback function invoked when the #DeviceState:realized\n property is changed to %true.\n @unrealize: Callback function invoked when the #DeviceState:realized\n property is changed to %false.\n @hotpluggable: indicates if #DeviceClass is hotpluggable, available\n as readonly \"hotpluggable\" property of #DeviceState instance\n"] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DeviceClass { pub parent_class: ObjectClass, pub categories: [::std::os::raw::c_ulong; 1usize], + #[doc = " @fw_name: name used to identify device to firmware interfaces"] pub fw_name: *const ::std::os::raw::c_char, + #[doc = " @desc: human readable description of device"] pub desc: *const ::std::os::raw::c_char, + #[doc = " @props_: properties associated with device, should only be\n assigned by using device_class_set_props(). The underscore\n ensures a compile-time error if someone attempts to assign\n dc->props directly."] pub props_: *mut Property, + #[doc = " @user_creatable: Can user instantiate with -device / device_add?\n\n All devices should support instantiation with device_add, and\n this flag should not exist. But we're not there, yet. Some\n devices fail to instantiate with cryptic error messages.\n Others instantiate, but don't work. Exposing users to such\n behavior would be cruel; clearing this flag will protect them.\n It should never be cleared without a comment explaining why it\n is cleared.\n\n TODO remove once we're there"] pub user_creatable: bool, pub hotpluggable: bool, + #[doc = " @reset: deprecated device reset method pointer\n\n Modern code should use the ResettableClass interface to\n implement a multi-phase reset.\n\n TODO: remove once every reset callback is unused"] pub reset: DeviceReset, pub realize: DeviceRealize, pub unrealize: DeviceUnrealize, + #[doc = " @vmsd: device state serialisation description for\n migration/save/restore"] pub vmsd: *const VMStateDescription, + #[doc = " @bus_type: bus type\n private: to qdev / bus."] pub bus_type: *const ::std::os::raw::c_char, } #[test] @@ -2865,150 +2947,165 @@ fn bindgen_test_layout_MemReentrancyGuard() { ) ); } -#[doc = " DeviceState:\n @reset: ResettableState for the device; handled by Resettable interface.\n\n This structure should not be accessed directly. We declare it here\n so that it can be embedded in individual device state structures."] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NamedGPIOListHead { + pub lh_first: *mut NamedGPIOList, +} +#[test] +fn bindgen_test_layout_NamedGPIOListHead() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(NamedGPIOListHead)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(NamedGPIOListHead)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(NamedGPIOListHead), + "::", + stringify!(lh_first) + ) + ); +} +impl Default for NamedGPIOListHead { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct NamedClockListHead { + pub lh_first: *mut NamedClockList, +} +#[test] +fn bindgen_test_layout_NamedClockListHead() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(NamedClockListHead)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(NamedClockListHead)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(NamedClockListHead), + "::", + stringify!(lh_first) + ) + ); +} +impl Default for NamedClockListHead { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BusStateHead { + pub lh_first: *mut BusState, +} +#[test] +fn bindgen_test_layout_BusStateHead() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(BusStateHead)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(BusStateHead)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(BusStateHead), + "::", + stringify!(lh_first) + ) + ); +} +impl Default for BusStateHead { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[doc = " struct DeviceState - common device state, accessed with qdev helpers\n\n This structure should not be accessed directly. We declare it here\n so that it can be embedded in individual device state structures."] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DeviceState { pub parent_obj: Object, + #[doc = " @id: global device id"] pub id: *mut ::std::os::raw::c_char, + #[doc = " @canonical_path: canonical path of realized device in the QOM tree"] pub canonical_path: *mut ::std::os::raw::c_char, + #[doc = " @realized: has device been realized?"] pub realized: bool, + #[doc = " @pending_deleted_event: track pending deletion events during unplug"] pub pending_deleted_event: bool, + #[doc = " @pending_deleted_expires_ms: optional timeout for deletion events"] pub pending_deleted_expires_ms: i64, + #[doc = " @opts: QDict of options for the device"] pub opts: *mut QDict, + #[doc = " @hotplugged: was device added after PHASE_MACHINE_READY?"] pub hotplugged: ::std::os::raw::c_int, + #[doc = " @allow_unplug_during_migration: can device be unplugged during migration"] pub allow_unplug_during_migration: bool, + #[doc = " @parent_bus: bus this device belongs to"] pub parent_bus: *mut BusState, - pub gpios: DeviceState__bindgen_ty_1, - pub clocks: DeviceState__bindgen_ty_2, - pub child_bus: DeviceState__bindgen_ty_3, + #[doc = " @gpios: QLIST of named GPIOs the device provides."] + pub gpios: NamedGPIOListHead, + #[doc = " @clocks: QLIST of named clocks the device provides."] + pub clocks: NamedClockListHead, + #[doc = " @child_bus: QLIST of child buses"] + pub child_bus: BusStateHead, + #[doc = " @num_child_bus: number of @child_bus entries"] pub num_child_bus: ::std::os::raw::c_int, + #[doc = " @instance_id_alias: device alias for handling legacy migration setups"] pub instance_id_alias: ::std::os::raw::c_int, + #[doc = " @alias_required_for_version: indicates @instance_id_alias is\n needed for migration"] pub alias_required_for_version: ::std::os::raw::c_int, + #[doc = " @reset: ResettableState for the device; handled by Resettable interface."] pub reset: ResettableState, + #[doc = " @unplug_blockers: list of reasons to block unplugging of device"] pub unplug_blockers: *mut GSList, + #[doc = " @mem_reentrancy_guard: Is the device currently in mmio/pio/dma?\n\n Used to prevent re-entrancy confusing things."] pub mem_reentrancy_guard: MemReentrancyGuard, } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DeviceState__bindgen_ty_1 { - pub lh_first: *mut NamedGPIOList, -} -#[test] -fn bindgen_test_layout_DeviceState__bindgen_ty_1() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(DeviceState__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(DeviceState__bindgen_ty_1)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(DeviceState__bindgen_ty_1), - "::", - stringify!(lh_first) - ) - ); -} -impl Default for DeviceState__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DeviceState__bindgen_ty_2 { - pub lh_first: *mut NamedClockList, -} -#[test] -fn bindgen_test_layout_DeviceState__bindgen_ty_2() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(DeviceState__bindgen_ty_2)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(DeviceState__bindgen_ty_2)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(DeviceState__bindgen_ty_2), - "::", - stringify!(lh_first) - ) - ); -} -impl Default for DeviceState__bindgen_ty_2 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct DeviceState__bindgen_ty_3 { - pub lh_first: *mut BusState, -} -#[test] -fn bindgen_test_layout_DeviceState__bindgen_ty_3() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!("Size of: ", stringify!(DeviceState__bindgen_ty_3)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(DeviceState__bindgen_ty_3)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).lh_first) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(DeviceState__bindgen_ty_3), - "::", - stringify!(lh_first) - ) - ); -} -impl Default for DeviceState__bindgen_ty_3 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} #[test] fn bindgen_test_layout_DeviceState() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); @@ -3362,7 +3459,112 @@ impl ::std::fmt::Debug for BusChild { ) } } -#[doc = " BusState:\n @hotplug_handler: link to a hotplug handler associated with bus.\n @reset: ResettableState for the bus; handled by Resettable interface."] +#[repr(C)] +#[derive(Copy, Clone)] +pub union BusChildHead { + pub tqh_first: *mut BusChild, + pub tqh_circ: QTailQLink, +} +#[test] +fn bindgen_test_layout_BusChildHead() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(BusChildHead)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(BusChildHead)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tqh_first) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(BusChildHead), + "::", + stringify!(tqh_first) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tqh_circ) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(BusChildHead), + "::", + stringify!(tqh_circ) + ) + ); +} +impl Default for BusChildHead { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for BusChildHead { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "BusChildHead {{ union }}") + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct BusStateEntry { + pub le_next: *mut BusState, + pub le_prev: *mut *mut BusState, +} +#[test] +fn bindgen_test_layout_BusStateEntry() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(BusStateEntry)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(BusStateEntry)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).le_next) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(BusStateEntry), + "::", + stringify!(le_next) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).le_prev) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(BusStateEntry), + "::", + stringify!(le_prev) + ) + ); +} +impl Default for BusStateEntry { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[doc = " struct BusState:\n @obj: parent object\n @parent: parent Device\n @name: name of bus\n @hotplug_handler: link to a hotplug handler associated with bus.\n @max_index: max number of child buses\n @realized: is the bus itself realized?\n @full: is the bus full?\n @num_children: current number of child buses"] #[repr(C)] #[derive(Copy, Clone)] pub struct BusState { @@ -3374,117 +3576,13 @@ pub struct BusState { pub realized: bool, pub full: bool, pub num_children: ::std::os::raw::c_int, - pub children: BusState__bindgen_ty_1, - pub sibling: BusState__bindgen_ty_2, + #[doc = " @children: an RCU protected QTAILQ, thus readers must use RCU\n to access it, and writers must hold the big qemu lock"] + pub children: BusChildHead, + #[doc = " @sibling: next bus"] + pub sibling: BusStateEntry, + #[doc = " @reset: ResettableState for the bus; handled by Resettable interface."] pub reset: ResettableState, } -#[repr(C)] -#[derive(Copy, Clone)] -pub union BusState__bindgen_ty_1 { - pub tqh_first: *mut BusChild, - pub tqh_circ: QTailQLink, -} -#[test] -fn bindgen_test_layout_BusState__bindgen_ty_1() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(BusState__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(BusState__bindgen_ty_1)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).tqh_first) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(BusState__bindgen_ty_1), - "::", - stringify!(tqh_first) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).tqh_circ) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(BusState__bindgen_ty_1), - "::", - stringify!(tqh_circ) - ) - ); -} -impl Default for BusState__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for BusState__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "BusState__bindgen_ty_1 {{ union }}") - } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct BusState__bindgen_ty_2 { - pub le_next: *mut BusState, - pub le_prev: *mut *mut BusState, -} -#[test] -fn bindgen_test_layout_BusState__bindgen_ty_2() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(BusState__bindgen_ty_2)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(BusState__bindgen_ty_2)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).le_next) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(BusState__bindgen_ty_2), - "::", - stringify!(le_next) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).le_prev) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(BusState__bindgen_ty_2), - "::", - stringify!(le_prev) - ) - ); -} -impl Default for BusState__bindgen_ty_2 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} #[test] fn bindgen_test_layout_BusState() { const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); @@ -4373,6 +4471,165 @@ extern "C" { } pub type hwaddr = u64; #[repr(C)] +#[derive(Copy, Clone)] +pub union CPUTLBEntry { + pub __bindgen_anon_1: CPUTLBEntry__bindgen_ty_1, + pub addr_idx: [u64; 4usize], +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CPUTLBEntry__bindgen_ty_1 { + pub addr_read: u64, + pub addr_write: u64, + pub addr_code: u64, + pub addend: usize, +} +#[test] +fn bindgen_test_layout_CPUTLBEntry__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(CPUTLBEntry__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBEntry__bindgen_ty_1)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_read) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntry__bindgen_ty_1), + "::", + stringify!(addr_read) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_write) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntry__bindgen_ty_1), + "::", + stringify!(addr_write) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_code) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntry__bindgen_ty_1), + "::", + stringify!(addr_code) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addend) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntry__bindgen_ty_1), + "::", + stringify!(addend) + ) + ); +} +#[test] +fn bindgen_test_layout_CPUTLBEntry() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(CPUTLBEntry)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBEntry)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).addr_idx) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntry), + "::", + stringify!(addr_idx) + ) + ); +} +impl Default for CPUTLBEntry { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLBEntry { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CPUTLBEntry {{ union }}") + } +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct CPUTLBDescFast { + pub mask: usize, + pub table: *mut CPUTLBEntry, +} +#[test] +fn bindgen_test_layout_CPUTLBDescFast() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(CPUTLBDescFast)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBDescFast)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mask) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDescFast), + "::", + stringify!(mask) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).table) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDescFast), + "::", + stringify!(table) + ) + ); +} +impl Default for CPUTLBDescFast { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] #[derive(Debug, Copy, Clone)] pub struct TCGCPUOps { _unused: [u8; 0], @@ -4382,7 +4639,7 @@ pub struct TCGCPUOps { pub struct SysemuCPUOps { _unused: [u8; 0], } -#[doc = " CPUClass:\n @class_by_name: Callback to map -cpu command line model name to an\n instantiatable CPU type.\n @parse_features: Callback to parse command line arguments.\n @reset_dump_flags: #CPUDumpFlags to use for reset logging.\n @has_work: Callback for checking if there is work to do.\n @memory_rw_debug: Callback for GDB memory access.\n @dump_state: Callback for dumping state.\n @query_cpu_fast:\n Fill in target specific information for the \"query-cpus-fast\"\n QAPI call.\n @get_arch_id: Callback for getting architecture-dependent CPU ID.\n @set_pc: Callback for setting the Program Counter register. This\n should have the semantics used by the target architecture when\n setting the PC from a source such as an ELF file entry point;\n for example on Arm it will also set the Thumb mode bit based\n on the least significant bit of the new PC value.\n If the target behaviour here is anything other than \"set\n the PC register to the value passed in\" then the target must\n also implement the synchronize_from_tb hook.\n @get_pc: Callback for getting the Program Counter register.\n As above, with the semantics of the target architecture.\n @gdb_read_register: Callback for letting GDB read a register.\n @gdb_write_register: Callback for letting GDB write a register.\n @gdb_adjust_breakpoint: Callback for adjusting the address of a\n breakpoint. Used by AVR to handle a gdb mis-feature with\n its Harvard architecture split code and data.\n @gdb_num_core_regs: Number of core registers accessible to GDB.\n @gdb_core_xml_file: File name for core registers GDB XML description.\n @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop\n before the insn which triggers a watchpoint rather than after it.\n @gdb_arch_name: Optional callback that returns the architecture name known\n to GDB. The caller must free the returned string with g_free.\n @gdb_get_dynamic_xml: Callback to return dynamically generated XML for the\n gdb stub. Returns a pointer to the XML contents for the specified XML file\n or NULL if the CPU doesn't have a dynamically generated content for it.\n @disas_set_info: Setup architecture specific components of disassembly info\n @adjust_watchpoint_address: Perform a target-specific adjustment to an\n address before attempting to match it against watchpoints.\n @deprecation_note: If this CPUClass is deprecated, this field provides\n related information.\n\n Represents a CPU family or model."] +#[doc = " CPUClass:\n @class_by_name: Callback to map -cpu command line model name to an\n instantiatable CPU type.\n @parse_features: Callback to parse command line arguments.\n @reset_dump_flags: #CPUDumpFlags to use for reset logging.\n @has_work: Callback for checking if there is work to do.\n @memory_rw_debug: Callback for GDB memory access.\n @dump_state: Callback for dumping state.\n @query_cpu_fast:\n Fill in target specific information for the \"query-cpus-fast\"\n QAPI call.\n @get_arch_id: Callback for getting architecture-dependent CPU ID.\n @set_pc: Callback for setting the Program Counter register. This\n should have the semantics used by the target architecture when\n setting the PC from a source such as an ELF file entry point;\n for example on Arm it will also set the Thumb mode bit based\n on the least significant bit of the new PC value.\n If the target behaviour here is anything other than \"set\n the PC register to the value passed in\" then the target must\n also implement the synchronize_from_tb hook.\n @get_pc: Callback for getting the Program Counter register.\n As above, with the semantics of the target architecture.\n @gdb_read_register: Callback for letting GDB read a register.\n @gdb_write_register: Callback for letting GDB write a register.\n @gdb_adjust_breakpoint: Callback for adjusting the address of a\n breakpoint. Used by AVR to handle a gdb mis-feature with\n its Harvard architecture split code and data.\n @gdb_num_core_regs: Number of core registers accessible to GDB.\n @gdb_core_xml_file: File name for core registers GDB XML description.\n @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop\n before the insn which triggers a watchpoint rather than after it.\n @gdb_arch_name: Optional callback that returns the architecture name known\n to GDB. The caller must free the returned string with g_free.\n @gdb_get_dynamic_xml: Callback to return dynamically generated XML for the\n gdb stub. Returns a pointer to the XML contents for the specified XML file\n or NULL if the CPU doesn't have a dynamically generated content for it.\n @disas_set_info: Setup architecture specific components of disassembly info\n @adjust_watchpoint_address: Perform a target-specific adjustment to an\n address before attempting to match it against watchpoints.\n @deprecation_note: If this CPUClass is deprecated, this field provides\n related information.\n\n Represents a CPU family or model."] #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct CPUClass { @@ -4433,7 +4690,7 @@ pub struct CPUClass { ::std::option::Option vaddr>, pub gdb_core_xml_file: *const ::std::os::raw::c_char, pub gdb_arch_name: - ::std::option::Option *mut gchar>, + ::std::option::Option *const gchar>, pub gdb_get_dynamic_xml: ::std::option::Option< unsafe extern "C" fn( cpu: *mut CPUState, @@ -4730,6 +4987,490 @@ impl Default for CPUClass { } #[repr(C)] #[derive(Copy, Clone)] +pub struct CPUTLBEntryFull { + pub xlat_section: hwaddr, + pub phys_addr: hwaddr, + pub attrs: MemTxAttrs, + pub prot: u8, + pub lg_page_size: u8, + pub slow_flags: [u8; 3usize], + pub extra: CPUTLBEntryFull__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union CPUTLBEntryFull__bindgen_ty_1 { + pub arm: CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1 { + pub pte_attrs: u8, + pub shareability: u8, + pub guarded: bool, +} +#[test] +fn bindgen_test_layout_CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 3usize, + concat!( + "Size of: ", + stringify!(CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!( + "Alignment of ", + stringify!(CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).pte_attrs) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(pte_attrs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).shareability) as usize - ptr as usize }, + 1usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(shareability) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).guarded) as usize - ptr as usize }, + 2usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull__bindgen_ty_1__bindgen_ty_1), + "::", + stringify!(guarded) + ) + ); +} +#[test] +fn bindgen_test_layout_CPUTLBEntryFull__bindgen_ty_1() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 3usize, + concat!("Size of: ", stringify!(CPUTLBEntryFull__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(CPUTLBEntryFull__bindgen_ty_1)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).arm) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull__bindgen_ty_1), + "::", + stringify!(arm) + ) + ); +} +impl Default for CPUTLBEntryFull__bindgen_ty_1 { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLBEntryFull__bindgen_ty_1 { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "CPUTLBEntryFull__bindgen_ty_1 {{ union }}") + } +} +#[test] +fn bindgen_test_layout_CPUTLBEntryFull() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(CPUTLBEntryFull)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBEntryFull)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).xlat_section) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(xlat_section) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(phys_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).attrs) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(attrs) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).prot) as usize - ptr as usize }, + 20usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(prot) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).lg_page_size) as usize - ptr as usize }, + 21usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(lg_page_size) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).slow_flags) as usize - ptr as usize }, + 22usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(slow_flags) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).extra) as usize - ptr as usize }, + 25usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBEntryFull), + "::", + stringify!(extra) + ) + ); +} +impl Default for CPUTLBEntryFull { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLBEntryFull { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CPUTLBEntryFull {{ attrs: {:?}, slow_flags: {:?}, extra: {:?} }}", + self.attrs, self.slow_flags, self.extra + ) + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct CPUTLBDesc { + pub large_page_addr: vaddr, + pub large_page_mask: vaddr, + pub window_begin_ns: i64, + pub window_max_entries: usize, + pub n_used_entries: usize, + pub vindex: usize, + pub vtable: [CPUTLBEntry; 8usize], + pub vfulltlb: [CPUTLBEntryFull; 8usize], + pub fulltlb: *mut CPUTLBEntryFull, +} +#[test] +fn bindgen_test_layout_CPUTLBDesc() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 568usize, + concat!("Size of: ", stringify!(CPUTLBDesc)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBDesc)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).large_page_addr) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(large_page_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).large_page_mask) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(large_page_mask) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).window_begin_ns) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(window_begin_ns) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).window_max_entries) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(window_max_entries) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).n_used_entries) as usize - ptr as usize }, + 32usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(n_used_entries) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vindex) as usize - ptr as usize }, + 40usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(vindex) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vtable) as usize - ptr as usize }, + 48usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(vtable) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).vfulltlb) as usize - ptr as usize }, + 304usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(vfulltlb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).fulltlb) as usize - ptr as usize }, + 560usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBDesc), + "::", + stringify!(fulltlb) + ) + ); +} +impl Default for CPUTLBDesc { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLBDesc { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CPUTLBDesc {{ vtable: {:?}, vfulltlb: {:?}, fulltlb: {:?} }}", + self.vtable, self.vfulltlb, self.fulltlb + ) + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct CPUTLBCommon { + pub lock: QemuSpin, + pub dirty: u16, + pub full_flush_count: usize, + pub part_flush_count: usize, + pub elide_flush_count: usize, +} +#[test] +fn bindgen_test_layout_CPUTLBCommon() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(CPUTLBCommon)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(CPUTLBCommon)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).lock) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBCommon), + "::", + stringify!(lock) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).dirty) as usize - ptr as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBCommon), + "::", + stringify!(dirty) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).full_flush_count) as usize - ptr as usize }, + 8usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBCommon), + "::", + stringify!(full_flush_count) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).part_flush_count) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBCommon), + "::", + stringify!(part_flush_count) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).elide_flush_count) as usize - ptr as usize }, + 24usize, + concat!( + "Offset of field: ", + stringify!(CPUTLBCommon), + "::", + stringify!(elide_flush_count) + ) + ); +} +#[repr(C)] +#[repr(align(16))] +#[derive(Copy, Clone)] +pub struct CPUTLB { + pub c: CPUTLBCommon, + pub d: [CPUTLBDesc; 16usize], + pub f: [CPUTLBDescFast; 16usize], +} +#[test] +fn bindgen_test_layout_CPUTLB() { + const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 9376usize, + concat!("Size of: ", stringify!(CPUTLB)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(CPUTLB)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).c) as usize - ptr as usize }, + 0usize, + concat!("Offset of field: ", stringify!(CPUTLB), "::", stringify!(c)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).d) as usize - ptr as usize }, + 32usize, + concat!("Offset of field: ", stringify!(CPUTLB), "::", stringify!(d)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).f) as usize - ptr as usize }, + 9120usize, + concat!("Offset of field: ", stringify!(CPUTLB), "::", stringify!(f)) + ); +} +impl Default for CPUTLB { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUTLB { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CPUTLB {{ c: {:?}, d: {:?}, f: {:?} }}", + self.c, self.d, self.f + ) + } +} +#[repr(C)] +#[derive(Copy, Clone)] pub union IcountDecr { pub u32_: u32, pub u16_: IcountDecr__bindgen_ty_1, @@ -4826,6 +5567,78 @@ impl ::std::fmt::Debug for IcountDecr { } } #[repr(C)] +#[repr(align(16))] +#[derive(Copy, Clone)] +pub struct CPUNegativeOffsetState { + pub tlb: CPUTLB, + pub icount_decr: IcountDecr, + pub can_do_io: bool, +} +#[test] +fn bindgen_test_layout_CPUNegativeOffsetState() { + const UNINIT: ::std::mem::MaybeUninit = + ::std::mem::MaybeUninit::uninit(); + let ptr = UNINIT.as_ptr(); + assert_eq!( + ::std::mem::size_of::(), + 9392usize, + concat!("Size of: ", stringify!(CPUNegativeOffsetState)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(CPUNegativeOffsetState)) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).tlb) as usize - ptr as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(CPUNegativeOffsetState), + "::", + stringify!(tlb) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).icount_decr) as usize - ptr as usize }, + 9376usize, + concat!( + "Offset of field: ", + stringify!(CPUNegativeOffsetState), + "::", + stringify!(icount_decr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).can_do_io) as usize - ptr as usize }, + 9380usize, + concat!( + "Offset of field: ", + stringify!(CPUNegativeOffsetState), + "::", + stringify!(can_do_io) + ) + ); +} +impl Default for CPUNegativeOffsetState { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl ::std::fmt::Debug for CPUNegativeOffsetState { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!( + f, + "CPUNegativeOffsetState {{ tlb: {:?}, icount_decr: {:?}, can_do_io: {:?} }}", + self.tlb, self.icount_decr, self.can_do_io + ) + } +} +#[repr(C)] #[derive(Copy, Clone)] pub struct CPUBreakpoint { pub pc: vaddr, @@ -5112,56 +5925,6 @@ impl ::std::fmt::Debug for CPUWatchpoint { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct SavedIOTLB { - pub section: *mut MemoryRegionSection, - pub mr_offset: hwaddr, -} -#[test] -fn bindgen_test_layout_SavedIOTLB() { - const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(SavedIOTLB)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!("Alignment of ", stringify!(SavedIOTLB)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).section) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(SavedIOTLB), - "::", - stringify!(section) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).mr_offset) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(SavedIOTLB), - "::", - stringify!(mr_offset) - ) - ); -} -impl Default for SavedIOTLB { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct KVMState { _unused: [u8; 0], } @@ -5172,22 +5935,12 @@ pub struct kvm_run { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct hax_vcpu_state { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct hvf_vcpu_state { - _unused: [u8; 0], -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct qemu_work_item { _unused: [u8; 0], } -#[doc = " CPUState:\n @cpu_index: CPU index (informative).\n @cluster_index: Identifies which cluster this CPU is in.\n For boards which don't define clusters or for \"loose\" CPUs not assigned\n to a cluster this will be UNASSIGNED_CLUSTER_INDEX; otherwise it will\n be the same as the cluster-id property of the CPU object's TYPE_CPU_CLUSTER\n QOM parent.\n Under TCG this value is propagated to @tcg_cflags.\n See TranslationBlock::TCG CF_CLUSTER_MASK.\n @tcg_cflags: Pre-computed cflags for this cpu.\n @nr_cores: Number of cores within this CPU package.\n @nr_threads: Number of threads within this CPU.\n @running: #true if CPU is currently running (lockless).\n @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;\n valid under cpu_list_lock.\n @created: Indicates whether the CPU thread has been successfully created.\n @interrupt_request: Indicates a pending interrupt request.\n @halted: Nonzero if the CPU is in suspended state.\n @stop: Indicates a pending stop request.\n @stopped: Indicates the CPU has been artificially stopped.\n @unplug: Indicates a pending CPU unplug request.\n @crash_occurred: Indicates the OS reported a crash (panic) for this CPU\n @singlestep_enabled: Flags for single-stepping.\n @icount_extra: Instructions until next timer event.\n @can_do_io: Nonzero if memory-mapped IO is safe. Deterministic execution\n requires that IO only be performed on the last instruction of a TB\n so that interrupts take effect immediately.\n @cpu_ases: Pointer to array of CPUAddressSpaces (which define the\n AddressSpaces this CPU has)\n @num_ases: number of CPUAddressSpaces in @cpu_ases\n @as: Pointer to the first AddressSpace, for the convenience of targets which\n only have a single AddressSpace\n @env_ptr: Pointer to subclass-specific CPUArchState field.\n @icount_decr_ptr: Pointer to IcountDecr field within subclass.\n @gdb_regs: Additional GDB registers.\n @gdb_num_regs: Number of total registers accessible to GDB.\n @gdb_num_g_regs: Number of registers in GDB 'g' packets.\n @next_cpu: Next CPU sharing TB cache.\n @opaque: User data.\n @mem_io_pc: Host Program Counter at which the memory was accessed.\n @kvm_fd: vCPU file descriptor for KVM.\n @work_mutex: Lock to prevent multiple access to @work_list.\n @work_list: List of pending asynchronous work.\n @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes\n to @trace_dstate).\n @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).\n @plugin_mask: Plugin event bitmap. Modified only via async work.\n @ignore_memory_transaction_failures: Cached copy of the MachineState\n flag of the same name: allows the board to suppress calling of the\n CPU do_transaction_failed hook function.\n @kvm_dirty_gfns: Points to the KVM dirty ring for this CPU when KVM dirty\n ring is enabled.\n @kvm_fetch_index: Keeps the index that we last fetched from the per-vCPU\n dirty ring structure.\n\n State of one CPU core or thread."] +#[doc = " CPUState:\n @cpu_index: CPU index (informative).\n @cluster_index: Identifies which cluster this CPU is in.\n For boards which don't define clusters or for \"loose\" CPUs not assigned\n to a cluster this will be UNASSIGNED_CLUSTER_INDEX; otherwise it will\n be the same as the cluster-id property of the CPU object's TYPE_CPU_CLUSTER\n QOM parent.\n Under TCG this value is propagated to @tcg_cflags.\n See TranslationBlock::TCG CF_CLUSTER_MASK.\n @tcg_cflags: Pre-computed cflags for this cpu.\n @nr_cores: Number of cores within this CPU package.\n @nr_threads: Number of threads within this CPU core.\n @running: #true if CPU is currently running (lockless).\n @has_waiter: #true if a CPU is currently waiting for the cpu_exec_end;\n valid under cpu_list_lock.\n @created: Indicates whether the CPU thread has been successfully created.\n @interrupt_request: Indicates a pending interrupt request.\n @halted: Nonzero if the CPU is in suspended state.\n @stop: Indicates a pending stop request.\n @stopped: Indicates the CPU has been artificially stopped.\n @unplug: Indicates a pending CPU unplug request.\n @crash_occurred: Indicates the OS reported a crash (panic) for this CPU\n @singlestep_enabled: Flags for single-stepping.\n @icount_extra: Instructions until next timer event.\n @neg.can_do_io: True if memory-mapped IO is allowed.\n @cpu_ases: Pointer to array of CPUAddressSpaces (which define the\n AddressSpaces this CPU has)\n @num_ases: number of CPUAddressSpaces in @cpu_ases\n @as: Pointer to the first AddressSpace, for the convenience of targets which\n only have a single AddressSpace\n @gdb_regs: Additional GDB registers.\n @gdb_num_regs: Number of total registers accessible to GDB.\n @gdb_num_g_regs: Number of registers in GDB 'g' packets.\n @next_cpu: Next CPU sharing TB cache.\n @opaque: User data.\n @mem_io_pc: Host Program Counter at which the memory was accessed.\n @accel: Pointer to accelerator specific state.\n @kvm_fd: vCPU file descriptor for KVM.\n @work_mutex: Lock to prevent multiple access to @work_list.\n @work_list: List of pending asynchronous work.\n @trace_dstate_delayed: Delayed changes to trace_dstate (includes all changes\n to @trace_dstate).\n @trace_dstate: Dynamic tracing state of events for this vCPU (bitmask).\n @plugin_mask: Plugin event bitmap. Modified only via async work.\n @ignore_memory_transaction_failures: Cached copy of the MachineState\n flag of the same name: allows the board to suppress calling of the\n CPU do_transaction_failed hook function.\n @kvm_dirty_gfns: Points to the KVM dirty ring for this CPU when KVM dirty\n ring is enabled.\n @kvm_fetch_index: Keeps the index that we last fetched from the per-vCPU\n dirty ring structure.\n\n State of one CPU core or thread.\n\n Align, in order to match possible alignment required by CPUArchState,\n and eliminate a hole between CPUState and CPUArchState within ArchCPU."] #[repr(C)] -#[derive(Copy, Clone)] +#[repr(align(16))] pub struct CPUState { pub parent_obj: DeviceState, pub cc: *mut CPUClass, @@ -5220,10 +5973,8 @@ pub struct CPUState { pub num_ases: ::std::os::raw::c_int, pub as_: *mut AddressSpace, pub memory: *mut MemoryRegion, - pub env_ptr: *mut CPUArchState, - pub icount_decr_ptr: *mut IcountDecr, pub tb_jmp_cache: *mut CPUJumpCache, - pub gdb_regs: *mut GDBRegisterState, + pub gdb_regs: *mut GArray, pub gdb_num_regs: ::std::os::raw::c_int, pub gdb_num_g_regs: ::std::os::raw::c_int, pub node: CPUState__bindgen_ty_2, @@ -5238,24 +5989,25 @@ pub struct CPUState { pub kvm_dirty_gfns: *mut kvm_dirty_gfn, pub kvm_fetch_index: u32, pub dirty_pages: u64, + pub kvm_vcpu_stats_fd: ::std::os::raw::c_int, pub in_ioctl_lock: QemuLockCnt, pub plugin_mask: [::std::os::raw::c_ulong; 1usize], pub plugin_mem_cbs: *mut GArray, - pub saved_iotlb: SavedIOTLB, pub cpu_index: ::std::os::raw::c_int, pub cluster_index: ::std::os::raw::c_int, pub tcg_cflags: u32, pub halted: u32, - pub can_do_io: u32, pub exception_index: i32, + pub accel: *mut AccelCPUState, pub vcpu_dirty: bool, pub throttle_thread_scheduled: bool, pub throttle_us_per_full: i64, pub ignore_memory_transaction_failures: bool, pub prctl_unalign_sigbus: bool, - pub hax_vcpu: *mut hax_vcpu_state, - pub hvf: *mut hvf_vcpu_state, pub iommu_notifiers: *mut GArray, + pub __bindgen_padding_0: [u8; 8usize], + pub neg_align: __IncompleteArrayField<::std::os::raw::c_char>, + pub neg: CPUNegativeOffsetState, } #[repr(C)] #[derive(Debug, Copy, Clone)] @@ -5482,12 +6234,12 @@ fn bindgen_test_layout_CPUState() { let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::size_of::(), - 816usize, + 10176usize, concat!("Size of: ", stringify!(CPUState)) ); assert_eq!( ::std::mem::align_of::(), - 8usize, + 16usize, concat!("Alignment of ", stringify!(CPUState)) ); assert_eq!( @@ -5800,29 +6552,9 @@ fn bindgen_test_layout_CPUState() { stringify!(memory) ) ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).env_ptr) as usize - ptr as usize }, - 544usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(env_ptr) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).icount_decr_ptr) as usize - ptr as usize }, - 552usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(icount_decr_ptr) - ) - ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tb_jmp_cache) as usize - ptr as usize }, - 560usize, + 544usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5832,7 +6564,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gdb_regs) as usize - ptr as usize }, - 568usize, + 552usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5842,7 +6574,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gdb_num_regs) as usize - ptr as usize }, - 576usize, + 560usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5852,7 +6584,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).gdb_num_g_regs) as usize - ptr as usize }, - 580usize, + 564usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5862,7 +6594,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).node) as usize - ptr as usize }, - 584usize, + 568usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5872,7 +6604,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).breakpoints) as usize - ptr as usize }, - 600usize, + 584usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5882,7 +6614,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).watchpoints) as usize - ptr as usize }, - 616usize, + 600usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5892,7 +6624,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).watchpoint_hit) as usize - ptr as usize }, - 632usize, + 616usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5902,7 +6634,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).opaque) as usize - ptr as usize }, - 640usize, + 624usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5912,7 +6644,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mem_io_pc) as usize - ptr as usize }, - 648usize, + 632usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5922,7 +6654,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_fd) as usize - ptr as usize }, - 656usize, + 640usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5932,7 +6664,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_state) as usize - ptr as usize }, - 664usize, + 648usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5942,7 +6674,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_run) as usize - ptr as usize }, - 672usize, + 656usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5952,7 +6684,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_dirty_gfns) as usize - ptr as usize }, - 680usize, + 664usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5962,7 +6694,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_fetch_index) as usize - ptr as usize }, - 688usize, + 672usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5972,7 +6704,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).dirty_pages) as usize - ptr as usize }, - 696usize, + 680usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5980,9 +6712,19 @@ fn bindgen_test_layout_CPUState() { stringify!(dirty_pages) ) ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).kvm_vcpu_stats_fd) as usize - ptr as usize }, + 688usize, + concat!( + "Offset of field: ", + stringify!(CPUState), + "::", + stringify!(kvm_vcpu_stats_fd) + ) + ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).in_ioctl_lock) as usize - ptr as usize }, - 704usize, + 692usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -5992,7 +6734,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).plugin_mask) as usize - ptr as usize }, - 712usize, + 696usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6002,7 +6744,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).plugin_mem_cbs) as usize - ptr as usize }, - 720usize, + 704usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6010,19 +6752,9 @@ fn bindgen_test_layout_CPUState() { stringify!(plugin_mem_cbs) ) ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).saved_iotlb) as usize - ptr as usize }, - 728usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(saved_iotlb) - ) - ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cpu_index) as usize - ptr as usize }, - 744usize, + 712usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6032,7 +6764,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cluster_index) as usize - ptr as usize }, - 748usize, + 716usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6042,7 +6774,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tcg_cflags) as usize - ptr as usize }, - 752usize, + 720usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6052,7 +6784,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).halted) as usize - ptr as usize }, - 756usize, + 724usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6060,19 +6792,9 @@ fn bindgen_test_layout_CPUState() { stringify!(halted) ) ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).can_do_io) as usize - ptr as usize }, - 760usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(can_do_io) - ) - ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_index) as usize - ptr as usize }, - 764usize, + 728usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6080,9 +6802,19 @@ fn bindgen_test_layout_CPUState() { stringify!(exception_index) ) ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).accel) as usize - ptr as usize }, + 736usize, + concat!( + "Offset of field: ", + stringify!(CPUState), + "::", + stringify!(accel) + ) + ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).vcpu_dirty) as usize - ptr as usize }, - 768usize, + 744usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6092,7 +6824,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).throttle_thread_scheduled) as usize - ptr as usize }, - 769usize, + 745usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6102,7 +6834,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).throttle_us_per_full) as usize - ptr as usize }, - 776usize, + 752usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6114,7 +6846,7 @@ fn bindgen_test_layout_CPUState() { unsafe { ::std::ptr::addr_of!((*ptr).ignore_memory_transaction_failures) as usize - ptr as usize }, - 784usize, + 760usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6124,7 +6856,7 @@ fn bindgen_test_layout_CPUState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).prctl_unalign_sigbus) as usize - ptr as usize }, - 785usize, + 761usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6132,29 +6864,9 @@ fn bindgen_test_layout_CPUState() { stringify!(prctl_unalign_sigbus) ) ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).hax_vcpu) as usize - ptr as usize }, - 792usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(hax_vcpu) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).hvf) as usize - ptr as usize }, - 800usize, - concat!( - "Offset of field: ", - stringify!(CPUState), - "::", - stringify!(hvf) - ) - ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).iommu_notifiers) as usize - ptr as usize }, - 808usize, + 768usize, concat!( "Offset of field: ", stringify!(CPUState), @@ -6162,6 +6874,26 @@ fn bindgen_test_layout_CPUState() { stringify!(iommu_notifiers) ) ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).neg_align) as usize - ptr as usize }, + 784usize, + concat!( + "Offset of field: ", + stringify!(CPUState), + "::", + stringify!(neg_align) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).neg) as usize - ptr as usize }, + 784usize, + concat!( + "Offset of field: ", + stringify!(CPUState), + "::", + stringify!(neg) + ) + ); } impl Default for CPUState { fn default() -> Self { @@ -6174,7 +6906,7 @@ impl Default for CPUState { } impl ::std::fmt::Debug for CPUState { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write ! (f , "CPUState {{ parent_obj: {:?}, cc: {:?}, nr_cores: {:?}, nr_threads: {:?}, thread: {:?}, thread_id: {:?}, running: {:?}, has_waiter: {:?}, halt_cond: {:?}, thread_kicked: {:?}, created: {:?}, stop: {:?}, stopped: {:?}, start_powered_off: {:?}, unplug: {:?}, crash_occurred: {:?}, exit_request: {:?}, exclusive_context_count: {:?}, singlestep_enabled: {:?}, jmp_env: {:?}, work_mutex: {:?}, work_list: {:?}, cpu_ases: {:?}, num_ases: {:?}, as: {:?}, memory: {:?}, env_ptr: {:?}, icount_decr_ptr: {:?}, tb_jmp_cache: {:?}, gdb_regs: {:?}, gdb_num_regs: {:?}, gdb_num_g_regs: {:?}, node: {:?}, breakpoints: {:?}, watchpoints: {:?}, watchpoint_hit: {:?}, opaque: {:?}, kvm_fd: {:?}, kvm_state: {:?}, kvm_run: {:?}, kvm_dirty_gfns: {:?}, in_ioctl_lock: {:?}, plugin_mask: {:?}, plugin_mem_cbs: {:?}, saved_iotlb: {:?}, cpu_index: {:?}, cluster_index: {:?}, vcpu_dirty: {:?}, throttle_thread_scheduled: {:?}, ignore_memory_transaction_failures: {:?}, prctl_unalign_sigbus: {:?}, hax_vcpu: {:?}, hvf: {:?}, iommu_notifiers: {:?} }}" , self . parent_obj , self . cc , self . nr_cores , self . nr_threads , self . thread , self . thread_id , self . running , self . has_waiter , self . halt_cond , self . thread_kicked , self . created , self . stop , self . stopped , self . start_powered_off , self . unplug , self . crash_occurred , self . exit_request , self . exclusive_context_count , self . singlestep_enabled , self . jmp_env , self . work_mutex , self . work_list , self . cpu_ases , self . num_ases , self . as_ , self . memory , self . env_ptr , self . icount_decr_ptr , self . tb_jmp_cache , self . gdb_regs , self . gdb_num_regs , self . gdb_num_g_regs , self . node , self . breakpoints , self . watchpoints , self . watchpoint_hit , self . opaque , self . kvm_fd , self . kvm_state , self . kvm_run , self . kvm_dirty_gfns , self . in_ioctl_lock , self . plugin_mask , self . plugin_mem_cbs , self . saved_iotlb , self . cpu_index , self . cluster_index , self . vcpu_dirty , self . throttle_thread_scheduled , self . ignore_memory_transaction_failures , self . prctl_unalign_sigbus , self . hax_vcpu , self . hvf , self . iommu_notifiers) + write ! (f , "CPUState {{ parent_obj: {:?}, cc: {:?}, nr_cores: {:?}, nr_threads: {:?}, thread: {:?}, thread_id: {:?}, running: {:?}, has_waiter: {:?}, halt_cond: {:?}, thread_kicked: {:?}, created: {:?}, stop: {:?}, stopped: {:?}, start_powered_off: {:?}, unplug: {:?}, crash_occurred: {:?}, exit_request: {:?}, exclusive_context_count: {:?}, singlestep_enabled: {:?}, jmp_env: {:?}, work_mutex: {:?}, work_list: {:?}, cpu_ases: {:?}, num_ases: {:?}, as: {:?}, memory: {:?}, tb_jmp_cache: {:?}, gdb_regs: {:?}, gdb_num_regs: {:?}, gdb_num_g_regs: {:?}, node: {:?}, breakpoints: {:?}, watchpoints: {:?}, watchpoint_hit: {:?}, opaque: {:?}, kvm_fd: {:?}, kvm_state: {:?}, kvm_run: {:?}, kvm_dirty_gfns: {:?}, kvm_vcpu_stats_fd: {:?}, in_ioctl_lock: {:?}, plugin_mask: {:?}, plugin_mem_cbs: {:?}, cpu_index: {:?}, cluster_index: {:?}, accel: {:?}, vcpu_dirty: {:?}, throttle_thread_scheduled: {:?}, ignore_memory_transaction_failures: {:?}, prctl_unalign_sigbus: {:?}, iommu_notifiers: {:?}, neg_align: {:?}, neg: {:?} }}" , self . parent_obj , self . cc , self . nr_cores , self . nr_threads , self . thread , self . thread_id , self . running , self . has_waiter , self . halt_cond , self . thread_kicked , self . created , self . stop , self . stopped , self . start_powered_off , self . unplug , self . crash_occurred , self . exit_request , self . exclusive_context_count , self . singlestep_enabled , self . jmp_env , self . work_mutex , self . work_list , self . cpu_ases , self . num_ases , self . as_ , self . memory , self . tb_jmp_cache , self . gdb_regs , self . gdb_num_regs , self . gdb_num_g_regs , self . node , self . breakpoints , self . watchpoints , self . watchpoint_hit , self . opaque , self . kvm_fd , self . kvm_state , self . kvm_run , self . kvm_dirty_gfns , self . kvm_vcpu_stats_fd , self . in_ioctl_lock , self . plugin_mask , self . plugin_mem_cbs , self . cpu_index , self . cluster_index , self . accel , self . vcpu_dirty , self . throttle_thread_scheduled , self . ignore_memory_transaction_failures , self . prctl_unalign_sigbus , self . iommu_notifiers , self . neg_align , self . neg) } } extern "C" { @@ -6183,82 +6915,6 @@ extern "C" { } pub type target_long = i64; pub type target_ulong = u64; -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct CPUTLB {} -#[test] -fn bindgen_test_layout_CPUTLB() { - assert_eq!( - ::std::mem::size_of::(), - 0usize, - concat!("Size of: ", stringify!(CPUTLB)) - ); - assert_eq!( - ::std::mem::align_of::(), - 1usize, - concat!("Alignment of ", stringify!(CPUTLB)) - ); -} -#[repr(C)] -#[derive(Copy, Clone)] -pub struct CPUNegativeOffsetState { - pub tlb: CPUTLB, - pub icount_decr: IcountDecr, -} -#[test] -fn bindgen_test_layout_CPUNegativeOffsetState() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 4usize, - concat!("Size of: ", stringify!(CPUNegativeOffsetState)) - ); - assert_eq!( - ::std::mem::align_of::(), - 4usize, - concat!("Alignment of ", stringify!(CPUNegativeOffsetState)) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).tlb) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(CPUNegativeOffsetState), - "::", - stringify!(tlb) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).icount_decr) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(CPUNegativeOffsetState), - "::", - stringify!(icount_decr) - ) - ); -} -impl Default for CPUNegativeOffsetState { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for CPUNegativeOffsetState { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "CPUNegativeOffsetState {{ tlb: {:?}, icount_decr: {:?} }}", - self.tlb, self.icount_decr - ) - } -} #[doc = " Property:\n @set_default: true if the default value should be set from @defval,\n in which case @info->set_default_value must not be NULL\n (if false then no default value is set by the property system\n and the field retains whatever value it was given by instance_init).\n @defval: default value for the property. This is used only if @set_default\n is true."] #[repr(C)] #[derive(Copy, Clone)] @@ -6929,7 +7585,7 @@ impl Default for float_status { } } } -pub type FeatureWordArray = [u64; 38usize]; +pub type FeatureWordArray = [u64; 39usize]; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct SegmentCache { @@ -8153,7 +8809,7 @@ fn bindgen_test_layout_CPUArchState() { let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::size_of::(), - 14880usize, + 14896usize, concat!("Size of: ", stringify!(CPUArchState)) ); assert_eq!( @@ -9717,7 +10373,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).user_features) as usize - ptr as usize }, - 13744usize, + 13752usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9727,7 +10383,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cpuid_model) as usize - ptr as usize }, - 14048usize, + 14064usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9737,7 +10393,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cache_info_cpuid2) as usize - ptr as usize }, - 14096usize, + 14112usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9747,7 +10403,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cache_info_cpuid4) as usize - ptr as usize }, - 14128usize, + 14144usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9757,7 +10413,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cache_info_amd) as usize - ptr as usize }, - 14160usize, + 14176usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9767,7 +10423,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mtrr_fixed) as usize - ptr as usize }, - 14192usize, + 14208usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9777,7 +10433,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mtrr_deftype) as usize - ptr as usize }, - 14280usize, + 14296usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9787,7 +10443,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mtrr_var) as usize - ptr as usize }, - 14288usize, + 14304usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9797,7 +10453,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mp_state) as usize - ptr as usize }, - 14416usize, + 14432usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9807,7 +10463,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_nr) as usize - ptr as usize }, - 14420usize, + 14436usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9817,7 +10473,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).interrupt_injected) as usize - ptr as usize }, - 14424usize, + 14440usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9827,7 +10483,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).soft_interrupt) as usize - ptr as usize }, - 14428usize, + 14444usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9837,7 +10493,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_pending) as usize - ptr as usize }, - 14429usize, + 14445usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9847,7 +10503,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_injected) as usize - ptr as usize }, - 14430usize, + 14446usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9857,7 +10513,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).has_error_code) as usize - ptr as usize }, - 14431usize, + 14447usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9867,7 +10523,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_has_payload) as usize - ptr as usize }, - 14432usize, + 14448usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9877,7 +10533,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).exception_payload) as usize - ptr as usize }, - 14440usize, + 14456usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9887,7 +10543,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).triple_fault_pending) as usize - ptr as usize }, - 14448usize, + 14464usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9897,7 +10553,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).ins_len) as usize - ptr as usize }, - 14452usize, + 14468usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9907,7 +10563,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).sipi_vector) as usize - ptr as usize }, - 14456usize, + 14472usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9917,7 +10573,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tsc_valid) as usize - ptr as usize }, - 14460usize, + 14476usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9927,7 +10583,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tsc_khz) as usize - ptr as usize }, - 14464usize, + 14480usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9937,7 +10593,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).user_tsc_khz) as usize - ptr as usize }, - 14472usize, + 14488usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9947,7 +10603,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).apic_bus_freq) as usize - ptr as usize }, - 14480usize, + 14496usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9957,7 +10613,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tsc) as usize - ptr as usize }, - 14488usize, + 14504usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9967,7 +10623,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mcg_cap) as usize - ptr as usize }, - 14496usize, + 14512usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9977,7 +10633,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mcg_ctl) as usize - ptr as usize }, - 14504usize, + 14520usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9987,7 +10643,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mcg_ext_ctl) as usize - ptr as usize }, - 14512usize, + 14528usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -9997,7 +10653,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mce_banks) as usize - ptr as usize }, - 14520usize, + 14536usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10007,7 +10663,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).xstate_bv) as usize - ptr as usize }, - 14840usize, + 14856usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10017,7 +10673,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).fpus_vmstate) as usize - ptr as usize }, - 14848usize, + 14864usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10027,7 +10683,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).fptag_vmstate) as usize - ptr as usize }, - 14850usize, + 14866usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10037,7 +10693,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).fpregs_format_vmstate) as usize - ptr as usize }, - 14852usize, + 14868usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10047,7 +10703,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).xss) as usize - ptr as usize }, - 14856usize, + 14872usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10057,7 +10713,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).umwait) as usize - ptr as usize }, - 14864usize, + 14880usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10067,7 +10723,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).tpr_access_type) as usize - ptr as usize }, - 14868usize, + 14884usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10077,7 +10733,7 @@ fn bindgen_test_layout_CPUArchState() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).nr_dies) as usize - ptr as usize }, - 14872usize, + 14888usize, concat!( "Offset of field: ", stringify!(CPUArchState), @@ -10109,11 +10765,8 @@ pub struct kvm_msrs { #[doc = " X86CPU:\n @env: #CPUX86State\n @migratable: If set, only migratable flags will be accepted when \"enforce\"\n mode is used, and only migratable flags will be included in the \"host\"\n CPU model.\n\n An x86 CPU."] #[repr(C)] #[repr(align(16))] -#[derive(Copy, Clone)] pub struct ArchCPU { pub parent_obj: CPUState, - pub neg: CPUNegativeOffsetState, - pub __bindgen_padding_0: u64, pub env: CPUX86State, pub vmsentry: *mut VMChangeStateEntry, pub ucode_rev: u64, @@ -10245,7 +10898,7 @@ fn bindgen_test_layout_ArchCPU() { let ptr = UNINIT.as_ptr(); assert_eq!( ::std::mem::size_of::(), - 16304usize, + 25664usize, concat!("Size of: ", stringify!(ArchCPU)) ); assert_eq!( @@ -10263,19 +10916,9 @@ fn bindgen_test_layout_ArchCPU() { stringify!(parent_obj) ) ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).neg) as usize - ptr as usize }, - 816usize, - concat!( - "Offset of field: ", - stringify!(ArchCPU), - "::", - stringify!(neg) - ) - ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).env) as usize - ptr as usize }, - 832usize, + 10176usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10285,7 +10928,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).vmsentry) as usize - ptr as usize }, - 15712usize, + 25072usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10295,7 +10938,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).ucode_rev) as usize - ptr as usize }, - 15720usize, + 25080usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10305,7 +10948,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_spinlock_attempts) as usize - ptr as usize }, - 15728usize, + 25088usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10315,7 +10958,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_vendor) as usize - ptr as usize }, - 15736usize, + 25096usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10325,7 +10968,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_synic_kvm_only) as usize - ptr as usize }, - 15744usize, + 25104usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10335,7 +10978,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_features) as usize - ptr as usize }, - 15752usize, + 25112usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10345,7 +10988,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_passthrough) as usize - ptr as usize }, - 15760usize, + 25120usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10355,7 +10998,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_no_nonarch_cs) as usize - ptr as usize }, - 15764usize, + 25124usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10365,7 +11008,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_vendor_id) as usize - ptr as usize }, - 15768usize, + 25128usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10375,7 +11018,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_interface_id) as usize - ptr as usize }, - 15780usize, + 25140usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10385,7 +11028,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_limits) as usize - ptr as usize }, - 15796usize, + 25156usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10395,7 +11038,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_enforce_cpuid) as usize - ptr as usize }, - 15808usize, + 25168usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10405,7 +11048,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_build) as usize - ptr as usize }, - 15812usize, + 25172usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10415,7 +11058,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_major) as usize - ptr as usize }, - 15816usize, + 25176usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10425,7 +11068,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_minor) as usize - ptr as usize }, - 15818usize, + 25178usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10435,7 +11078,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_sp) as usize - ptr as usize }, - 15820usize, + 25180usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10445,7 +11088,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_sb) as usize - ptr as usize }, - 15824usize, + 25184usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10455,7 +11098,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hyperv_ver_id_sn) as usize - ptr as usize }, - 15828usize, + 25188usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10465,7 +11108,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).check_cpuid) as usize - ptr as usize }, - 15832usize, + 25192usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10475,7 +11118,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).enforce_cpuid) as usize - ptr as usize }, - 15833usize, + 25193usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10485,7 +11128,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).force_features) as usize - ptr as usize }, - 15834usize, + 25194usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10495,7 +11138,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).expose_kvm) as usize - ptr as usize }, - 15835usize, + 25195usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10505,7 +11148,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).expose_tcg) as usize - ptr as usize }, - 15836usize, + 25196usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10515,7 +11158,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).migratable) as usize - ptr as usize }, - 15837usize, + 25197usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10525,7 +11168,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).migrate_smi_count) as usize - ptr as usize }, - 15838usize, + 25198usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10535,7 +11178,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).max_features) as usize - ptr as usize }, - 15839usize, + 25199usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10545,7 +11188,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).apic_id) as usize - ptr as usize }, - 15840usize, + 25200usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10555,7 +11198,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).vmware_cpuid_freq) as usize - ptr as usize }, - 15844usize, + 25204usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10565,7 +11208,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cache_info_passthrough) as usize - ptr as usize }, - 15845usize, + 25205usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10575,7 +11218,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).mwait) as usize - ptr as usize }, - 15848usize, + 25208usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10585,7 +11228,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).filtered_features) as usize - ptr as usize }, - 15864usize, + 25224usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10595,7 +11238,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).enable_pmu) as usize - ptr as usize }, - 16168usize, + 25536usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10605,7 +11248,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).lbr_fmt) as usize - ptr as usize }, - 16176usize, + 25544usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10615,7 +11258,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).enable_lmce) as usize - ptr as usize }, - 16184usize, + 25552usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10625,7 +11268,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).enable_l3_cache) as usize - ptr as usize }, - 16185usize, + 25553usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10635,7 +11278,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).legacy_cache) as usize - ptr as usize }, - 16186usize, + 25554usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10645,7 +11288,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).enable_cpuid_0xb) as usize - ptr as usize }, - 16187usize, + 25555usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10655,7 +11298,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).full_cpuid_auto_level) as usize - ptr as usize }, - 16188usize, + 25556usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10665,7 +11308,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).vendor_cpuid_only) as usize - ptr as usize }, - 16189usize, + 25557usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10675,7 +11318,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).intel_pt_auto_level) as usize - ptr as usize }, - 16190usize, + 25558usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10685,7 +11328,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).fill_mtrr_mask) as usize - ptr as usize }, - 16191usize, + 25559usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10695,7 +11338,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).host_phys_bits) as usize - ptr as usize }, - 16192usize, + 25560usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10705,7 +11348,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).host_phys_bits_limit) as usize - ptr as usize }, - 16193usize, + 25561usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10715,7 +11358,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_no_smi_migration) as usize - ptr as usize }, - 16194usize, + 25562usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10725,7 +11368,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_pv_enforce_cpuid) as usize - ptr as usize }, - 16195usize, + 25563usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10735,7 +11378,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).phys_bits) as usize - ptr as usize }, - 16196usize, + 25564usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10745,7 +11388,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).apic_state) as usize - ptr as usize }, - 16200usize, + 25568usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10755,7 +11398,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cpu_as_root) as usize - ptr as usize }, - 16208usize, + 25576usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10765,7 +11408,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).cpu_as_mem) as usize - ptr as usize }, - 16216usize, + 25584usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10775,7 +11418,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).smram) as usize - ptr as usize }, - 16224usize, + 25592usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10785,7 +11428,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).machine_done) as usize - ptr as usize }, - 16232usize, + 25600usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10795,7 +11438,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).kvm_msr_buf) as usize - ptr as usize }, - 16256usize, + 25624usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10805,7 +11448,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).node_id) as usize - ptr as usize }, - 16264usize, + 25632usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10815,7 +11458,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).socket_id) as usize - ptr as usize }, - 16268usize, + 25636usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10825,7 +11468,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).die_id) as usize - ptr as usize }, - 16272usize, + 25640usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10835,7 +11478,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).core_id) as usize - ptr as usize }, - 16276usize, + 25644usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10845,7 +11488,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).thread_id) as usize - ptr as usize }, - 16280usize, + 25648usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10855,7 +11498,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).hv_max_vps) as usize - ptr as usize }, - 16284usize, + 25652usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10865,7 +11508,7 @@ fn bindgen_test_layout_ArchCPU() { ); assert_eq!( unsafe { ::std::ptr::addr_of!((*ptr).xen_vapic) as usize - ptr as usize }, - 16288usize, + 25656usize, concat!( "Offset of field: ", stringify!(ArchCPU), @@ -10885,11 +11528,19 @@ impl Default for ArchCPU { } impl ::std::fmt::Debug for ArchCPU { fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write ! (f , "ArchCPU {{ parent_obj: {:?}, neg: {:?}, env: {:?}, vmsentry: {:?}, hyperv_vendor: {:?}, hyperv_synic_kvm_only: {:?}, hyperv_passthrough: {:?}, hyperv_no_nonarch_cs: {:?}, hyperv_vendor_id: {:?}, hyperv_interface_id: {:?}, hyperv_limits: {:?}, hyperv_enforce_cpuid: {:?}, check_cpuid: {:?}, enforce_cpuid: {:?}, force_features: {:?}, expose_kvm: {:?}, expose_tcg: {:?}, migratable: {:?}, migrate_smi_count: {:?}, max_features: {:?}, vmware_cpuid_freq: {:?}, cache_info_passthrough: {:?}, mwait: {:?}, filtered_features: {:?}, enable_pmu: {:?}, enable_lmce: {:?}, enable_l3_cache: {:?}, legacy_cache: {:?}, enable_cpuid_0xb: {:?}, full_cpuid_auto_level: {:?}, vendor_cpuid_only: {:?}, intel_pt_auto_level: {:?}, fill_mtrr_mask: {:?}, host_phys_bits: {:?}, kvm_no_smi_migration: {:?}, kvm_pv_enforce_cpuid: {:?}, apic_state: {:?}, cpu_as_root: {:?}, cpu_as_mem: {:?}, smram: {:?}, machine_done: {:?}, kvm_msr_buf: {:?}, xen_vapic: {:?} }}" , self . parent_obj , self . neg , self . env , self . vmsentry , self . hyperv_vendor , self . hyperv_synic_kvm_only , self . hyperv_passthrough , self . hyperv_no_nonarch_cs , self . hyperv_vendor_id , self . hyperv_interface_id , self . hyperv_limits , self . hyperv_enforce_cpuid , self . check_cpuid , self . enforce_cpuid , self . force_features , self . expose_kvm , self . expose_tcg , self . migratable , self . migrate_smi_count , self . max_features , self . vmware_cpuid_freq , self . cache_info_passthrough , self . mwait , self . filtered_features , self . enable_pmu , self . enable_lmce , self . enable_l3_cache , self . legacy_cache , self . enable_cpuid_0xb , self . full_cpuid_auto_level , self . vendor_cpuid_only , self . intel_pt_auto_level , self . fill_mtrr_mask , self . host_phys_bits , self . kvm_no_smi_migration , self . kvm_pv_enforce_cpuid , self . apic_state , self . cpu_as_root , self . cpu_as_mem , self . smram , self . machine_done , self . kvm_msr_buf , self . xen_vapic) + write ! (f , "ArchCPU {{ parent_obj: {:?}, env: {:?}, vmsentry: {:?}, hyperv_vendor: {:?}, hyperv_synic_kvm_only: {:?}, hyperv_passthrough: {:?}, hyperv_no_nonarch_cs: {:?}, hyperv_vendor_id: {:?}, hyperv_interface_id: {:?}, hyperv_limits: {:?}, hyperv_enforce_cpuid: {:?}, check_cpuid: {:?}, enforce_cpuid: {:?}, force_features: {:?}, expose_kvm: {:?}, expose_tcg: {:?}, migratable: {:?}, migrate_smi_count: {:?}, max_features: {:?}, vmware_cpuid_freq: {:?}, cache_info_passthrough: {:?}, mwait: {:?}, filtered_features: {:?}, enable_pmu: {:?}, enable_lmce: {:?}, enable_l3_cache: {:?}, legacy_cache: {:?}, enable_cpuid_0xb: {:?}, full_cpuid_auto_level: {:?}, vendor_cpuid_only: {:?}, intel_pt_auto_level: {:?}, fill_mtrr_mask: {:?}, host_phys_bits: {:?}, kvm_no_smi_migration: {:?}, kvm_pv_enforce_cpuid: {:?}, apic_state: {:?}, cpu_as_root: {:?}, cpu_as_mem: {:?}, smram: {:?}, machine_done: {:?}, kvm_msr_buf: {:?}, xen_vapic: {:?} }}" , self . parent_obj , self . env , self . vmsentry , self . hyperv_vendor , self . hyperv_synic_kvm_only , self . hyperv_passthrough , self . hyperv_no_nonarch_cs , self . hyperv_vendor_id , self . hyperv_interface_id , self . hyperv_limits , self . hyperv_enforce_cpuid , self . check_cpuid , self . enforce_cpuid , self . force_features , self . expose_kvm , self . expose_tcg , self . migratable , self . migrate_smi_count , self . max_features , self . vmware_cpuid_freq , self . cache_info_passthrough , self . mwait , self . filtered_features , self . enable_pmu , self . enable_lmce , self . enable_l3_cache , self . legacy_cache , self . enable_cpuid_0xb , self . full_cpuid_auto_level , self . vendor_cpuid_only , self . intel_pt_auto_level , self . fill_mtrr_mask , self . host_phys_bits , self . kvm_no_smi_migration , self . kvm_pv_enforce_cpuid , self . apic_state , self . cpu_as_root , self . cpu_as_mem , self . smram , self . machine_done , self . kvm_msr_buf , self . xen_vapic) } } pub type abi_ulong = target_ulong; pub type abi_long = target_long; +extern "C" { + #[doc = " page_check_range\n @start: first byte of range\n @len: length of range\n @flags: flags required for each page\n\n Return true if every page in [@start, @start+@len) has @flags set.\n Return false if any page is unmapped. Thus testing flags == 0 is\n equivalent to testing for flags == PAGE_VALID."] + pub fn page_check_range( + start: target_ulong, + last: target_ulong, + flags: ::std::os::raw::c_int, + ) -> bool; +} pub const MemOp_MO_8: MemOp = MemOp(0); pub const MemOp_MO_16: MemOp = MemOp(1); pub const MemOp_MO_32: MemOp = MemOp(2); @@ -10996,7 +11647,7 @@ extern "C" { prot: ::std::os::raw::c_int, flags: ::std::os::raw::c_int, fd: ::std::os::raw::c_int, - offset: abi_ulong, + offset: off_t, ) -> abi_long; } extern "C" { @@ -11008,7 +11659,7 @@ pub struct AccelCPUClass { pub parent_class: ObjectClass, pub cpu_class_init: ::std::option::Option, pub cpu_instance_init: ::std::option::Option, - pub cpu_realizefn: ::std::option::Option< + pub cpu_target_realize: ::std::option::Option< unsafe extern "C" fn(cpu: *mut CPUState, errp: *mut *mut Error) -> bool, >, } @@ -11057,13 +11708,13 @@ fn bindgen_test_layout_AccelCPUClass() { ) ); assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).cpu_realizefn) as usize - ptr as usize }, + unsafe { ::std::ptr::addr_of!((*ptr).cpu_target_realize) as usize - ptr as usize }, 112usize, concat!( "Offset of field: ", stringify!(AccelCPUClass), "::", - stringify!(cpu_realizefn) + stringify!(cpu_target_realize) ) ); } @@ -11123,173 +11774,12 @@ extern "C" { } #[doc = " struct qemu_plugin_hwaddr - opaque hw address handle"] #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] pub struct qemu_plugin_hwaddr { pub is_io: bool, pub is_store: bool, - pub v: qemu_plugin_hwaddr__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union qemu_plugin_hwaddr__bindgen_ty_1 { - pub io: qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1, - pub ram: qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1 { - pub section: *mut MemoryRegionSection, - pub offset: hwaddr, -} -#[test] -fn bindgen_test_layout_qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!( - "Size of: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!( - "Alignment of ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).section) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(section) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).offset) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1), - "::", - stringify!(offset) - ) - ); -} -impl Default for qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2 { - pub hostaddr: *mut ::std::os::raw::c_void, -} -#[test] -fn bindgen_test_layout_qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 8usize, - concat!( - "Size of: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2) - ) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!( - "Alignment of ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).hostaddr) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2), - "::", - stringify!(hostaddr) - ) - ); -} -impl Default for qemu_plugin_hwaddr__bindgen_ty_1__bindgen_ty_2 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[test] -fn bindgen_test_layout_qemu_plugin_hwaddr__bindgen_ty_1() { - const UNINIT: ::std::mem::MaybeUninit = - ::std::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::std::mem::size_of::(), - 16usize, - concat!("Size of: ", stringify!(qemu_plugin_hwaddr__bindgen_ty_1)) - ); - assert_eq!( - ::std::mem::align_of::(), - 8usize, - concat!( - "Alignment of ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).io) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1), - "::", - stringify!(io) - ) - ); - assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).ram) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(qemu_plugin_hwaddr__bindgen_ty_1), - "::", - stringify!(ram) - ) - ); -} -impl Default for qemu_plugin_hwaddr__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for qemu_plugin_hwaddr__bindgen_ty_1 { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "qemu_plugin_hwaddr__bindgen_ty_1 {{ union }}") - } + pub phys_addr: hwaddr, + pub mr: *mut MemoryRegion, } #[test] fn bindgen_test_layout_qemu_plugin_hwaddr() { @@ -11326,13 +11816,23 @@ fn bindgen_test_layout_qemu_plugin_hwaddr() { ) ); assert_eq!( - unsafe { ::std::ptr::addr_of!((*ptr).v) as usize - ptr as usize }, + unsafe { ::std::ptr::addr_of!((*ptr).phys_addr) as usize - ptr as usize }, 8usize, concat!( "Offset of field: ", stringify!(qemu_plugin_hwaddr), "::", - stringify!(v) + stringify!(phys_addr) + ) + ); + assert_eq!( + unsafe { ::std::ptr::addr_of!((*ptr).mr) as usize - ptr as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(qemu_plugin_hwaddr), + "::", + stringify!(mr) ) ); } @@ -11345,20 +11845,11 @@ impl Default for qemu_plugin_hwaddr { } } } -impl ::std::fmt::Debug for qemu_plugin_hwaddr { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!( - f, - "qemu_plugin_hwaddr {{ is_io: {:?}, is_store: {:?}, v: {:?} }}", - self.is_io, self.is_store, self.v - ) - } -} extern "C" { #[doc = " tlb_plugin_lookup: query last TLB lookup\n @cpu: cpu environment\n\n This function can be used directly after a memory operation to\n query information about the access. It is used by the plugin\n infrastructure to expose more information about the address.\n\n It would only fail if not called from an instrumented memory access\n which would be an abuse of the API."] pub fn tlb_plugin_lookup( cpu: *mut CPUState, - addr: target_ulong, + addr: vaddr, mmu_idx: ::std::os::raw::c_int, is_store: bool, data: *mut qemu_plugin_hwaddr, @@ -11366,11 +11857,6 @@ extern "C" { } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] -pub struct GDBRegisterState { - pub _address: u8, -} -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] pub struct kvm_dirty_gfn { pub _address: u8, } diff --git a/libafl_qemu/libqasan/Makefile b/libafl_qemu/libqasan/Makefile index a05527e212..858cb49aa2 100644 --- a/libafl_qemu/libqasan/Makefile +++ b/libafl_qemu/libqasan/Makefile @@ -15,11 +15,11 @@ OUT_DIR ?= . -CFLAGS += -Wno-int-to-void-pointer-cast -ggdb -LDFLAGS += -ldl -pthread +override CFLAGS += -Wno-int-to-void-pointer-cast -ggdb -O1 -fno-builtin +override LDFLAGS += -ldl -pthread -SRC := libqasan.c hooks.c malloc.c string.c uninstrument.c patch.c dlmalloc.c -HDR := libqasan.h +SRC := libqasan.c hooks.c malloc.c string.c uninstrument.c patch.c dlmalloc.c printf/printf.c +HDR := libqasan.h qasan.h map_macro.h printf/printf.h all: libqasan.so diff --git a/libafl_qemu/libqasan/libqasan.c b/libafl_qemu/libqasan/libqasan.c index 2701dad529..b9927d7697 100644 --- a/libafl_qemu/libqasan/libqasan.c +++ b/libafl_qemu/libqasan/libqasan.c @@ -37,7 +37,7 @@ void __libqasan_print_maps(void) { read(fd, buf, 4095); close(fd); - size_t len = strlen(buf); + size_t len = __libqasan_strlen(buf); QASAN_LOG("Guest process maps:\n"); int i; @@ -77,7 +77,7 @@ __attribute__((constructor)) void __libqasan_init() { "Copyright (C) 2019-2021 Andrea Fioraldi \n"); QASAN_LOG("\n"); - if (__qasan_log) { __libqasan_print_maps(); } + // if (__qasan_log) { __libqasan_print_maps(); } } int __libc_start_main(int (*main)(int, char **, char **), int argc, char **argv, diff --git a/libafl_qemu/libqasan/libqasan.h b/libafl_qemu/libqasan/libqasan.h index 655dd80b62..e611513000 100644 --- a/libafl_qemu/libqasan/libqasan.h +++ b/libafl_qemu/libqasan/libqasan.h @@ -40,24 +40,25 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "qasan.h" +#include "printf/printf.h" -#define QASAN_LOG(msg...) \ - do { \ - if (__qasan_log) { \ - fprintf(stderr, "==%d== ", getpid()); \ - fprintf(stderr, msg); \ - } \ - \ +#define QASAN_LOG(msg...) \ + do { \ + if (__qasan_log) { \ + __libqasan_printf("==%d== ", getpid()); \ + __libqasan_printf(msg); \ + __libqasan_flush(); \ + } \ } while (0) #ifdef DEBUG - #define QASAN_DEBUG(msg...) \ - do { \ - if (__qasan_debug) { \ - fprintf(stderr, "==%d== ", getpid()); \ - fprintf(stderr, msg); \ - } \ - \ + #define QASAN_DEBUG(msg...) \ + do { \ + if (__qasan_debug) { \ + __libqasan_printf("==%d== ", getpid()); \ + __libqasan_printf(msg); \ + __libqasan_flush(); \ + } \ } while (0) #else diff --git a/libafl_qemu/libqasan/malloc.c b/libafl_qemu/libqasan/malloc.c index 0a03e71b42..96afe333f9 100644 --- a/libafl_qemu/libqasan/malloc.c +++ b/libafl_qemu/libqasan/malloc.c @@ -23,6 +23,9 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ +// do not use dlmalloc for now +// #define USE_LIBC_ALLOC + #include "libqasan.h" #include #include @@ -30,6 +33,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#ifdef __GLIBC__ + #define USE_LIBC_ALLOC +#endif + #define REDZONE_SIZE 128 // 50 mb quarantine #define QUARANTINE_MAX_BYTES 52428800 @@ -63,7 +70,7 @@ struct chunk_struct { } __attribute__((packed)); -#ifdef __GLIBC__ +#ifdef USE_LIBC_ALLOC void *(*__lq_libc_malloc)(size_t); void (*__lq_libc_free)(void *); @@ -132,7 +139,7 @@ static int quarantine_push(struct chunk_begin *ck) { void __libqasan_init_malloc(void) { if (__libqasan_malloc_initialized) return; -#ifdef __GLIBC__ +#ifdef USE_LIBC_ALLOC __lq_libc_malloc = dlsym(RTLD_NEXT, "malloc"); __lq_libc_free = dlsym(RTLD_NEXT, "free"); #endif @@ -159,7 +166,7 @@ void *__libqasan_malloc(size_t size) { if (!__libqasan_malloc_initialized) { __libqasan_init_malloc(); -#ifdef __GLIBC__ +#ifdef USE_LIBC_ALLOC void *r = &__tmp_alloc_zone[__tmp_alloc_zone_idx]; if (size & (ALLOC_ALIGN_SIZE - 1)) @@ -203,7 +210,7 @@ void *__libqasan_malloc(size_t size) { void __libqasan_free(void *ptr) { if (!ptr) return; -#ifdef __GLIBC__ +#ifdef USE_LIBC_ALLOC if (ptr >= (void *)__tmp_alloc_zone && ptr < ((void *)__tmp_alloc_zone + TMP_ZONE_SIZE)) return; @@ -239,7 +246,7 @@ void __libqasan_free(void *ptr) { void *__libqasan_calloc(size_t nmemb, size_t size) { size *= nmemb; -#ifdef __GLIBC__ +#ifdef USE_LIBC_ALLOC if (!__libqasan_malloc_initialized) { void *r = &__tmp_alloc_zone[__tmp_alloc_zone_idx]; __tmp_alloc_zone_idx += size; diff --git a/libafl_qemu/libqasan/printf/.gitattributes b/libafl_qemu/libqasan/printf/.gitattributes new file mode 100644 index 0000000000..6d4472862e --- /dev/null +++ b/libafl_qemu/libqasan/printf/.gitattributes @@ -0,0 +1,2 @@ +# ignore test path +test/* linguist-vendored diff --git a/libafl_qemu/libqasan/printf/.travis.yml b/libafl_qemu/libqasan/printf/.travis.yml new file mode 100644 index 0000000000..7cff9cff6b --- /dev/null +++ b/libafl_qemu/libqasan/printf/.travis.yml @@ -0,0 +1,63 @@ +# Use a C++11 distro +dist: trusty +sudo: required + +# Enable C++ support +language: cpp + +# Compiler selection +compiler: gcc + +env: + global: + # coverity key + - secure: "NKZbBnMALGIIQJy/s2kc3EST/stw+gjhtrGq0jkbsWr7Wx3FH+lmLeHNsDXRnD1VbpG02c5YsLllqz9OVu+0yxWGepvKNmCz1cNITIALEHbrax8/Af9LzPRL/QZxS/Qe11sMuySp4X16mFBUyxMd/X+I9i96Xf1vKkZABklYD1Q=" + +# addons +addons: + apt: + packages: + - gcc-6 + - g++-6 + sources: + - ubuntu-toolchain-r-test + + coverity_scan: + project: + name: "mpaland/printf" + description: "Tiny printf implementation" + notification_email: marco@paland.com + build_command_prepend: "make clean" + build_command: "make" + branch_pattern: master + +before_install: + # connect coverity + - echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- + +# Active branches +branches: + only: + - master + +script: + # Link gcc-6 and g++-6 to their standard commands + - sudo rm /usr/bin/gcc + - sudo rm /usr/bin/g++ + - sudo ln -s /usr/bin/gcc-6 /usr/bin/gcc + - sudo ln -s /usr/bin/g++-6 /usr/bin/g++ + # Export CC and CXX + - export CC=/usr/bin/gcc-6 + - export CXX=/usr/bin/g++-6 + # Check versions of gcc, g++ + - gcc -v && g++ -v + # Run build commands + - make + # execute the text suite + - bin/test_suite -d yes + # coverall profiling + - tmp/cov/test_suite + +after_success: + ## Report to codecov + - bash <(curl -s https://codecov.io/bash) diff --git a/libafl_qemu/libqasan/printf/LICENSE b/libafl_qemu/libqasan/printf/LICENSE new file mode 100644 index 0000000000..8f7ebd0b98 --- /dev/null +++ b/libafl_qemu/libqasan/printf/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014 Marco Paland + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/libafl_qemu/libqasan/printf/Makefile b/libafl_qemu/libqasan/printf/Makefile new file mode 100644 index 0000000000..7b28a1a1a2 --- /dev/null +++ b/libafl_qemu/libqasan/printf/Makefile @@ -0,0 +1,271 @@ +# ------------------------------------------------------------------------------ +# +# Generic Makefile +# +# Copyright Marco Paland 2007 - 2017 +# Distributed under the MIT License +# +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# Paths +# ------------------------------------------------------------------------------ +PATH_TOOLS_CC = /usr/bin/ +PATH_TOOLS_CC_LIB = /usr/lib/ +PATH_TOOLS_UTIL = + +PATH_BIN = bin +PATH_TMP = tmp +PATH_NUL = /dev/null +PATH_OBJ = $(PATH_TMP)/obj +PATH_LST = $(PATH_TMP)/lst +PATH_ERR = $(PATH_TMP)/err +PATH_PRE = $(PATH_TMP)/pre +PATH_COV = $(PATH_TMP)/cov + + +# ------------------------------------------------------------------------------ +# Application to build +# ------------------------------------------------------------------------------ + +APP = test_suite + + +# ----------------------------------------------------------------------------- +# Project file list +# Format is: +# FILES_PRJ = file1 \ +# foo/file2 \ +# bar/file3 +# ----------------------------------------------------------------------------- + +FILES_PRJ = test/test_suite + + +# ------------------------------------------------------------------------------ +# Additional include files and compiler defines +# Format is: +# C_INCLUDES = -Iinclude_path1 \ +# -Iinclude_path2 \ +# -Iinclude_path3 \ +# ------------------------------------------------------------------------------ + +C_INCLUDES = + +C_DEFINES = + + +# ------------------------------------------------------------------------------ +# The target name and location +# ------------------------------------------------------------------------------ +TRG = $(PATH_BIN)/$(APP) + + +# ------------------------------------------------------------------------------ +# object files +# ------------------------------------------------------------------------------ +FILES_TMP = $(FILES_PRJ) +FILES_O = $(addsuffix .o, $(FILES_TMP)) + + +# ------------------------------------------------------------------------------ +# VPATH definition +# +# VPATH is required for the maker to find the C-/ASM-Source files. +# Extract the directory/module names from the file list with the dir +# command and remove the duplicated directory names with the sort command. +# FILES_PRJ is listed first to make sure that the source files in the project +# directory are searched first. +# ------------------------------------------------------------------------------ +VPATH := $(sort $(dir $(FILES_TMP))) + + +# ------------------------------------------------------------------------------ +# Development tools +# ------------------------------------------------------------------------------ +AR = $(PATH_TOOLS_CC)ar +AS = $(PATH_TOOLS_CC)g++ +CC = $(PATH_TOOLS_CC)g++ +CL = $(PATH_TOOLS_CC)g++ +NM = $(PATH_TOOLS_CC)nm +GCOV = $(PATH_TOOLS_CC)gcov +OBJDUMP = $(PATH_TOOLS_CC)objdump +OBJCOPY = $(PATH_TOOLS_CC)objcopy +READELF = $(PATH_TOOLS_CC)readelf +SIZE = $(PATH_TOOLS_CC)size + +ECHO = $(PATH_TOOLS_UTIL)echo +MAKE = $(PATH_TOOLS_UTIL)make +MKDIR = $(PATH_TOOLS_UTIL)mkdir +RM = $(PATH_TOOLS_UTIL)rm +SED = $(PATH_TOOLS_UTIL)sed + + +# ------------------------------------------------------------------------------ +# Compiler flags for the target architecture +# ------------------------------------------------------------------------------ + +GCCFLAGS = $(C_INCLUDES) \ + $(C_DEFINES) \ + -std=c++11 \ + -g \ + -Wall \ + -pedantic \ + -Wmain \ + -Wundef \ + -Wsign-conversion \ + -Wuninitialized \ + -Wshadow \ + -Wunreachable-code \ + -Wswitch-default \ + -Wswitch \ + -Wcast-align \ + -Wmissing-include-dirs \ + -Winit-self \ + -Wdouble-promotion \ + -gdwarf-2 \ + -fno-exceptions \ + -O2 \ + -ffunction-sections \ + -ffat-lto-objects \ + -fdata-sections \ + -fverbose-asm \ + -Wextra \ + -Wunused-parameter \ + -Wfloat-equal + +CFLAGS = $(GCCFLAGS) \ + -Wunsuffixed-float-constants \ + -x c \ + -std=c99 + +CPPFLAGS = $(GCCFLAGS) \ + -x c++ \ + -fno-rtti \ + -fstrict-enums \ + -fno-use-cxa-atexit \ + -fno-use-cxa-get-exception-ptr \ + -fno-nonansi-builtins \ + -fno-threadsafe-statics \ + -fno-enforce-eh-specs \ + -ftemplate-depth-64 \ + -fexceptions + +AFLAGS = $(GCCFLAGS) \ + -x assembler + +LFLAGS = $(GCCFLAGS) \ + -x none \ + -Wl,--gc-sections + +# ------------------------------------------------------------------------------ +# Targets +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# Main-Dependencies (app: all) +# ------------------------------------------------------------------------------ +.PHONY: all +all: clean_prj $(TRG) $(TRG)_nm.txt + + +# ------------------------------------------------------------------------------ +# Main-Dependencies (app: rebuild) +# ------------------------------------------------------------------------------ +.PHONY: rebuild +rebuild: clean $(TRG) $(TRG)_nm.txt + + +# ------------------------------------------------------------------------------ +# clean project +# ------------------------------------------------------------------------------ +.PHONY: clean_prj +clean_prj: + @-$(ECHO) +++ cleaning project + @-$(RM) -rf $(PATH_BIN) 2> $(PATH_NUL) + @-$(MKDIR) -p $(PATH_BIN) + @-$(MKDIR) -p $(PATH_OBJ) + @-$(MKDIR) -p $(PATH_ERR) + @-$(MKDIR) -p $(PATH_LST) + @-$(MKDIR) -p $(PATH_PRE) + @-$(MKDIR) -p $(PATH_COV) + + +# ------------------------------------------------------------------------------ +# clean all +# ------------------------------------------------------------------------------ +.PHONY: clean +clean: + @-$(ECHO) +++ cleaning all + @-$(RM) -rf $(PATH_BIN) 2> $(PATH_NUL) + @-$(RM) -rf $(PATH_TMP) 2> $(PATH_NUL) + @-$(MKDIR) -p $(PATH_BIN) + @-$(MKDIR) -p $(PATH_OBJ) + @-$(MKDIR) -p $(PATH_ERR) + @-$(MKDIR) -p $(PATH_LST) + @-$(MKDIR) -p $(PATH_COV) + + +# ------------------------------------------------------------------------------ +# print the GNUmake version and the compiler version +# ------------------------------------------------------------------------------ +.PHONY: version +version: + # Print the GNU make version and the compiler version + @$(ECHO) GNUmake version: + @$(MAKE) --version + @$(ECHO) GCC version: + @$(CL) -v + + +# ------------------------------------------------------------------------------ +# Rules +# ------------------------------------------------------------------------------ + +# ------------------------------------------------------------------------------ +# Link/locate application +# ------------------------------------------------------------------------------ +$(TRG) : $(FILES_O) + @-$(ECHO) +++ linkink application to generate: $(TRG) + @-$(CL) $(LFLAGS) -L. -lc $(PATH_OBJ)/*.o -Wl,-Map,$(TRG).map -o $(TRG) + # profiling + @-$(CL) $(LFLAGS) -L. -lc $(PATH_COV)/*.o --coverage -o $(PATH_COV)/$(APP) + + +# ------------------------------------------------------------------------------ +# parse the object files to obtain symbol information, and create a size summary +# ------------------------------------------------------------------------------ +$(TRG)_nm.txt : $(TRG) + @-$(ECHO) +++ parsing symbols with nm to generate: $(TRG)_nm.txt + @-$(NM) --numeric-sort --print-size $(TRG) > $(TRG)_nm.txt + @-$(ECHO) +++ demangling symbols with c++filt to generate: $(TRG)_cppfilt.txt + @-$(NM) --numeric-sort --print-size $(TRG) | $(CPPFILT) > $(TRG)_cppfilt.txt + @-$(ECHO) +++ creating size summary table with size to generate: $(TRG)_size.txt + @-$(SIZE) -A -t $(TRG) > $(TRG)_size.txt + + +%.o : %.cpp + @$(ECHO) +++ compile: $< + # Compile the source file + # ...and Reformat (using sed) any possible error/warning messages for the VisualStudio(R) output window + # ...and Create an assembly listing using objdump + # ...and Generate a dependency file (using the -MM flag) + @-$(CL) $(CPPFLAGS) $< -E -o $(PATH_PRE)/$(basename $(@F)).pre + @-$(CL) $(CPPFLAGS) $< -c -o $(PATH_OBJ)/$(basename $(@F)).o 2> $(PATH_ERR)/$(basename $(@F)).err + @-$(SED) -e 's|.h:\([0-9]*\),|.h(\1) :|' -e 's|:\([0-9]*\):|(\1) :|' $(PATH_ERR)/$(basename $(@F)).err + @-$(OBJDUMP) --disassemble --line-numbers -S $(PATH_OBJ)/$(basename $(@F)).o > $(PATH_LST)/$(basename $(@F)).lst + @-$(CL) $(CPPFLAGS) $< -MM > $(PATH_OBJ)/$(basename $(@F)).d + # profiling + @-$(CL) $(CPPFLAGS) -O0 --coverage $< -c -o $(PATH_COV)/$(basename $(@F)).o 2> $(PATH_NUL) + +%.o : %.c + @$(ECHO) +++ compile: $< + # Compile the source file + # ...and Reformat (using sed) any possible error/warning messages for the VisualStudio(R) output window + # ...and Create an assembly listing using objdump + # ...and Generate a dependency file (using the -MM flag) + @-$(CL) $(CFLAGS) $< -E -o $(PATH_PRE)/$(basename $(@F)).pre + @-$(CC) $(CFLAGS) $< -c -o $(PATH_OBJ)/$(basename $(@F)).o 2> $(PATH_ERR)/$(basename $(@F)).err + @-$(SED) -e 's|.h:\([0-9]*\),|.h(\1) :|' -e 's|:\([0-9]*\):|(\1) :|' $(PATH_ERR)/$(basename $(@F)).err + @-$(OBJDUMP) -S $(PATH_OBJ)/$(basename $(@F)).o > $(PATH_LST)/$(basename $(@F)).lst + @-$(CC) $(CFLAGS) $< -MM > $(PATH_OBJ)/$(basename $(@F)).d diff --git a/libafl_qemu/libqasan/printf/README.md b/libafl_qemu/libqasan/printf/README.md new file mode 100644 index 0000000000..76f8962d13 --- /dev/null +++ b/libafl_qemu/libqasan/printf/README.md @@ -0,0 +1,217 @@ + +Modified to add the `__libqasan_` prefix to avoid stdlib conflicts and an internal buffer without malloc usage. + +=========================================================== + +# A printf / sprintf Implementation for Embedded Systems + +[![Build Status](https://travis-ci.org/mpaland/printf.svg?branch=master)](https://travis-ci.org/mpaland/printf) +[![codecov](https://codecov.io/gh/mpaland/printf/branch/master/graph/badge.svg)](https://codecov.io/gh/mpaland/printf) +[![Coverity Status](https://img.shields.io/coverity/scan/14180.svg)](https://scan.coverity.com/projects/mpaland-printf) +[![Github Issues](https://img.shields.io/github/issues/mpaland/printf.svg)](http://github.com/mpaland/printf/issues) +[![Github Releases](https://img.shields.io/github/release/mpaland/printf.svg)](https://github.com/mpaland/printf/releases) +[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/mpaland/avl_array/master/LICENSE) + +This is a tiny but **fully loaded** printf, sprintf and (v)snprintf implementation. +Primarily designed for usage in embedded systems, where printf is not available due to memory issues or in avoidance of linking against libc. +Using the standard libc printf may pull **a lot** of unwanted library stuff and can bloat code size about 20k or is not 100% thread safe. In this cases the following implementation can be used. +Absolutely **NO dependencies** are required, *printf.c* brings all necessary routines, even its own fast `ftoa` (floating point), `ntoa` (decimal) conversion. + +If memory footprint is really a critical issue, floating point, exponential and 'long long' support and can be turned off via the `PRINTF_DISABLE_SUPPORT_FLOAT`, `PRINTF_DISABLE_SUPPORT_EXPONENTIAL` and `PRINTF_DISABLE_SUPPORT_LONG_LONG` compiler switches. +When using printf (instead of sprintf/snprintf) you have to provide your own `_putchar()` low level function as console/serial output. + + +## 2020 announcement +This project is not dead! I just had no time in 2019 for sufficient support, sorry. +Within the next weeks, I will have a look to all PRs and open issues. +Thank you all for supporting this project. + + +## Highlights and Design Goals + +There is a boatload of so called 'tiny' printf implementations around. So why this one? +I've tested many implementations, but most of them have very limited flag/specifier support, a lot of other dependencies or are just not standard compliant and failing most of the test suite. +Therefore I decided to write an own, final implementation which meets the following items: + + - Very small implementation (around 600 code lines) + - NO dependencies, no libs, just one module file + - Support of all important flags, width and precision sub-specifiers (see below) + - Support of decimal/floating number representation (with an own fast itoa/ftoa) + - Reentrant and thread-safe, malloc free, no static vars/buffers + - LINT and compiler L4 warning free, mature, coverity clean, automotive ready + - Extensive test suite (> 400 test cases) passing + - Simply the best *printf* around the net + - MIT license + + +## Usage + +Add/link *printf.c* to your project and include *printf.h*. That's it. +Implement your low level output function needed for `printf()`: +```C +void _putchar(char character) +{ + // send char to console etc. +} +``` + +Usage is 1:1 like the according stdio.h library version: +```C +int printf(const char* format, ...); +int sprintf(char* buffer, const char* format, ...); +int snprintf(char* buffer, size_t count, const char* format, ...); +int vsnprintf(char* buffer, size_t count, const char* format, va_list va); + +// use output function (instead of buffer) for streamlike interface +int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); +``` + +**Due to general security reasons it is highly recommended to prefer and use `snprintf` (with the max buffer size as `count` parameter) instead of `sprintf`.** +`sprintf` has no buffer limitation, so when needed - use it really with care! + +### Streamlike Usage +Besides the regular standard `printf()` functions, this module also provides `fctprintf()`, which takes an output function as first parameter to build a streamlike output like `fprintf()`: +```C +// define the output function +void my_stream_output(char character, void* arg) +{ + // opt. evaluate the argument and send the char somewhere +} + +{ + // in your code + void* arg = (void*)100; // this argument is passed to the output function + fctprintf(&my_stream_output, arg, "This is a test: %X", 0xAA); + fctprintf(&my_stream_output, nullptr, "Send to null dev"); +} +``` + +## Format Specifiers + +A format specifier follows this prototype: `%[flags][width][.precision][length]type` +The following format specifiers are supported: + + +### Supported Types + +| Type | Output | +|--------|--------| +| d or i | Signed decimal integer | +| u | Unsigned decimal integer | +| b | Unsigned binary | +| o | Unsigned octal | +| x | Unsigned hexadecimal integer (lowercase) | +| X | Unsigned hexadecimal integer (uppercase) | +| f or F | Decimal floating point | +| e or E | Scientific-notation (exponential) floating point | +| g or G | Scientific or decimal floating point | +| c | Single character | +| s | String of characters | +| p | Pointer address | +| % | A % followed by another % character will write a single % | + + +### Supported Flags + +| Flags | Description | +|-------|-------------| +| - | Left-justify within the given field width; Right justification is the default. | +| + | Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers.
By default, only negative numbers are preceded with a - sign. | +| (space) | If no sign is going to be written, a blank space is inserted before the value. | +| # | Used with o, b, x or X specifiers the value is preceded with 0, 0b, 0x or 0X respectively for values different than zero.
Used with f, F it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written. | +| 0 | Left-pads the number with zeros (0) instead of spaces when padding is specified (see width sub-specifier). | + + +### Supported Width + +| Width | Description | +|----------|-------------| +| (number) | Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger. | +| * | The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. | + + +### Supported Precision + +| Precision | Description | +|-----------|-------------| +| .number | For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits to be written. If the value to be written is shorter than this number, the result is padded with leading zeros. The value is not truncated even if the result is longer. A precision of 0 means that no character is written for the value 0.
For f and F specifiers: this is the number of digits to be printed after the decimal point. **By default, this is 6, maximum is 9**.
For s: this is the maximum number of characters to be printed. By default all characters are printed until the ending null character is encountered.
If the period is specified without an explicit value for precision, 0 is assumed. | +| .* | The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. | + + +### Supported Length + +The length sub-specifier modifies the length of the data type. + +| Length | d i | u o x X | +|--------|------|---------| +| (none) | int | unsigned int | +| hh | char | unsigned char | +| h | short int | unsigned short int | +| l | long int | unsigned long int | +| ll | long long int | unsigned long long int (if PRINTF_SUPPORT_LONG_LONG is defined) | +| j | intmax_t | uintmax_t | +| z | size_t | size_t | +| t | ptrdiff_t | ptrdiff_t (if PRINTF_SUPPORT_PTRDIFF_T is defined) | + + +### Return Value + +Upon successful return, all functions return the number of characters written, _excluding_ the terminating null character used to end the string. +Functions `snprintf()` and `vsnprintf()` don't write more than `count` bytes, _including_ the terminating null byte ('\0'). +Anyway, if the output was truncated due to this limit, the return value is the number of characters that _could_ have been written. +Notice that a value equal or larger than `count` indicates a truncation. Only when the returned value is non-negative and less than `count`, +the string has been completely written. +If any error is encountered, `-1` is returned. + +If `buffer` is set to `NULL` (`nullptr`) nothing is written and just the formatted length is returned. +```C +int length = sprintf(NULL, "Hello, world"); // length is set to 12 +``` + + +## Compiler Switches/Defines + +| Name | Default value | Description | +|------|---------------|-------------| +| PRINTF_INCLUDE_CONFIG_H | undefined | Define this as compiler switch (e.g. `gcc -DPRINTF_INCLUDE_CONFIG_H`) to include a "printf_config.h" definition file | +| PRINTF_NTOA_BUFFER_SIZE | 32 | ntoa (integer) conversion buffer size. This must be big enough to hold one converted numeric number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack | +| PRINTF_FTOA_BUFFER_SIZE | 32 | ftoa (float) conversion buffer size. This must be big enough to hold one converted float number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack | +| PRINTF_DEFAULT_FLOAT_PRECISION | 6 | Define the default floating point precision | +| PRINTF_MAX_FLOAT | 1e9 | Define the largest suitable value to be printed with %f, before using exponential representation | +| PRINTF_DISABLE_SUPPORT_FLOAT | undefined | Define this to disable floating point (%f) support | +| PRINTF_DISABLE_SUPPORT_EXPONENTIAL | undefined | Define this to disable exponential floating point (%e) support | +| PRINTF_DISABLE_SUPPORT_LONG_LONG | undefined | Define this to disable long long (%ll) support | +| PRINTF_DISABLE_SUPPORT_PTRDIFF_T | undefined | Define this to disable ptrdiff_t (%t) support | + + +## Caveats +None anymore (finally). + + +## Test Suite +For testing just compile, build and run the test suite located in `test/test_suite.cpp`. This uses the [catch](https://github.com/catchorg/Catch2) framework for unit-tests, which is auto-adding main(). +Running with the `--wait-for-keypress exit` option waits for the enter key after test end. + + +## Projects Using printf +- [turnkeyboard](https://github.com/mpaland/turnkeyboard) uses printf as log and generic tty (formatting) output. +- printf is part of [embeddedartistry/libc](https://github.com/embeddedartistry/libc), a libc targeted for embedded systems usage. +- The [Hatchling Platform]( https://github.com/adrian3git/HatchlingPlatform) uses printf. + +(Just send me a mail/issue/PR to get *your* project listed here) + + +## Contributing + +0. Give this project a :star: +1. Create an issue and describe your idea +2. [Fork it](https://github.com/mpaland/printf/fork) +3. Create your feature branch (`git checkout -b my-new-feature`) +4. Commit your changes (`git commit -am 'Add some feature'`) +5. Publish the branch (`git push origin my-new-feature`) +6. Create a new pull request +7. Profit! :heavy_check_mark: + + +## License +printf is written under the [MIT license](http://www.opensource.org/licenses/MIT). diff --git a/libafl_qemu/libqasan/printf/printf.c b/libafl_qemu/libqasan/printf/printf.c new file mode 100644 index 0000000000..b4e1a03eb4 --- /dev/null +++ b/libafl_qemu/libqasan/printf/printf.c @@ -0,0 +1,974 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for +// speed on +// embedded systems with a very limited resources. These routines are +// thread safe and reentrant! Use this instead of the bloated +// standard/newlib printf cause these use malloc for printf (and may not +// be thread safe). +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "printf.h" + +// qasan define +#define PRINTF_SUPPORT_FLOAT + +// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the +// printf_config.h header file +// default: undefined +#ifdef PRINTF_INCLUDE_CONFIG_H + #include "printf_config.h" +#endif + +// 'ntoa' conversion buffer size, this must be big enough to hold one converted +// numeric number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_NTOA_BUFFER_SIZE + #define PRINTF_NTOA_BUFFER_SIZE 32U +#endif + +// 'ftoa' conversion buffer size, this must be big enough to hold one converted +// float number including padded zeros (dynamically created on stack) +// default: 32 byte +#ifndef PRINTF_FTOA_BUFFER_SIZE + #define PRINTF_FTOA_BUFFER_SIZE 32U +#endif + +// support for the floating point type (%f) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_FLOAT + #define PRINTF_SUPPORT_FLOAT +#endif + +// support for exponential floating point notation (%e/%g) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL + #define PRINTF_SUPPORT_EXPONENTIAL +#endif + +// define the default floating point precision +// default: 6 digits +#ifndef PRINTF_DEFAULT_FLOAT_PRECISION + #define PRINTF_DEFAULT_FLOAT_PRECISION 6U +#endif + +// define the largest float suitable to print with %f +// default: 1e9 +#ifndef PRINTF_MAX_FLOAT + #define PRINTF_MAX_FLOAT 1e9 +#endif + +// support for the long long types (%llu or %p) +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG + #define PRINTF_SUPPORT_LONG_LONG +#endif + +// support for the ptrdiff_t type (%t) +// ptrdiff_t is normally defined in as long or long long type +// default: activated +#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T + #define PRINTF_SUPPORT_PTRDIFF_T +#endif + +/////////////////////////////////////////////////////////////////////////////// + +// internal flag definitions +#define FLAGS_ZEROPAD (1U << 0U) +#define FLAGS_LEFT (1U << 1U) +#define FLAGS_PLUS (1U << 2U) +#define FLAGS_SPACE (1U << 3U) +#define FLAGS_HASH (1U << 4U) +#define FLAGS_UPPERCASE (1U << 5U) +#define FLAGS_CHAR (1U << 6U) +#define FLAGS_SHORT (1U << 7U) +#define FLAGS_LONG (1U << 8U) +#define FLAGS_LONG_LONG (1U << 9U) +#define FLAGS_PRECISION (1U << 10U) +#define FLAGS_ADAPT_EXP (1U << 11U) + +// import float.h for DBL_MAX +#if defined(PRINTF_SUPPORT_FLOAT) + #include +#endif + +// output function type +typedef void (*out_fct_type)(char character, void *buffer, size_t idx, + size_t maxlen); + +// wrapper (used as buffer) for output function type +typedef struct { + void (*fct)(char character, void *arg); + void *arg; +} out_fct_wrap_type; + +// internal buffer output +static inline void _out_buffer(char character, void *buffer, size_t idx, + size_t maxlen) { + if (idx < maxlen) { ((char *)buffer)[idx] = character; } +} + +// internal null output +static inline void _out_null(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)character; + (void)buffer; + (void)idx; + (void)maxlen; +} + +// internal _putchar wrapper +static inline void _out_char(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)buffer; + (void)idx; + (void)maxlen; + if (character) { __libqasan_putchar(character); } +} + +// internal output function wrapper +static inline void _out_fct(char character, void *buffer, size_t idx, + size_t maxlen) { + (void)idx; + (void)maxlen; + if (character) { + // buffer is the output fct pointer + ((out_fct_wrap_type *)buffer) + ->fct(character, ((out_fct_wrap_type *)buffer)->arg); + } +} + +// internal secure strlen +// \return The length of the string (excluding the terminating 0) limited by +// 'maxsize' +static inline unsigned int _strnlen_s(const char *str, size_t maxsize) { + const char *s; + for (s = str; *s && maxsize--; ++s) + ; + return (unsigned int)(s - str); +} + +// internal test if char is a digit (0-9) +// \return true if char is a digit +static inline bool _is_digit(char ch) { + return (ch >= '0') && (ch <= '9'); +} + +// internal ASCII string to unsigned int conversion +static unsigned int _atoi(const char **str) { + unsigned int i = 0U; + while (_is_digit(**str)) { + i = i * 10U + (unsigned int)(*((*str)++) - '0'); + } + return i; +} + +// output the specified string in reverse, taking care of any zero-padding +static size_t _out_rev(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, const char *buf, size_t len, + unsigned int width, unsigned int flags) { + const size_t start_idx = idx; + + // pad spaces up to given width + if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { + for (size_t i = len; i < width; i++) { + out(' ', buffer, idx++, maxlen); + } + } + + // reverse string + while (len) { + out(buf[--len], buffer, idx++, maxlen); + } + + // append pad spaces up to given width + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) { + out(' ', buffer, idx++, maxlen); + } + } + + return idx; +} + +// internal itoa format +static size_t _ntoa_format(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, char *buf, size_t len, bool negative, + unsigned int base, unsigned int prec, + unsigned int width, unsigned int flags) { + // pad leading zeros + if (!(flags & FLAGS_LEFT)) { + if (width && (flags & FLAGS_ZEROPAD) && + (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + while ((flags & FLAGS_ZEROPAD) && (len < width) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + // handle hash + if (flags & FLAGS_HASH) { + if (!(flags & FLAGS_PRECISION) && len && + ((len == prec) || (len == width))) { + len--; + if (len && (base == 16U)) { len--; } + } + if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'x'; + } else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && + (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'X'; + } else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { + buf[len++] = 'b'; + } + if (len < PRINTF_NTOA_BUFFER_SIZE) { buf[len++] = '0'; } + } + + if (len < PRINTF_NTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + +// internal itoa for 'long' type +static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, unsigned long value, bool negative, + unsigned long base, unsigned int prec, + unsigned int width, unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { flags &= ~FLAGS_HASH; } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 + ? '0' + digit + : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, + (unsigned int)base, prec, width, flags); +} + +// internal itoa for 'long long' type +#if defined(PRINTF_SUPPORT_LONG_LONG) +static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, + size_t maxlen, unsigned long long value, + bool negative, unsigned long long base, + unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_NTOA_BUFFER_SIZE]; + size_t len = 0U; + + // no hash for 0 values + if (!value) { flags &= ~FLAGS_HASH; } + + // write if precision != 0 and value is != 0 + if (!(flags & FLAGS_PRECISION) || value) { + do { + const char digit = (char)(value % base); + buf[len++] = digit < 10 + ? '0' + digit + : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + value /= base; + } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); + } + + return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, + (unsigned int)base, prec, width, flags); +} +#endif // PRINTF_SUPPORT_LONG_LONG + +#if defined(PRINTF_SUPPORT_FLOAT) + + #if defined(PRINTF_SUPPORT_EXPONENTIAL) +// forward declaration so that _ftoa can switch to exp notation for values > +// PRINTF_MAX_FLOAT +static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags); + #endif + +// internal ftoa for fixed decimal floating point +static size_t _ftoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags) { + char buf[PRINTF_FTOA_BUFFER_SIZE]; + size_t len = 0U; + double diff = 0.0; + + // powers of 10 + static const double pow10[] = {1, 10, 100, 1000, + 10000, 100000, 1000000, 10000000, + 100000000, 1000000000}; + + // test for special values + if (value != value) + return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); + if (value < -DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); + if (value > DBL_MAX) + return _out_rev(out, buffer, idx, maxlen, + (flags & FLAGS_PLUS) ? "fni+" : "fni", + (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); + + // test for very large values + // standard printf behavior is to print EVERY whole number digit -- which + // could be 100s of characters overflowing your buffers == bad + if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { + #if defined(PRINTF_SUPPORT_EXPONENTIAL) + return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); + #else + return 0U; + #endif + } + + // test for negative + bool negative = false; + if (value < 0) { + negative = true; + value = 0 - value; + } + + // set default precision, if not set explicitly + if (!(flags & FLAGS_PRECISION)) { prec = PRINTF_DEFAULT_FLOAT_PRECISION; } + // limit precision to 9, cause a prec >= 10 can lead to overflow errors + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { + buf[len++] = '0'; + prec--; + } + + int whole = (int)value; + double tmp = (value - whole) * pow10[prec]; + unsigned long frac = (unsigned long)tmp; + diff = tmp - frac; + + if (diff > 0.5) { + ++frac; + // handle rollover, e.g. case 0.99 with prec 1 is 1.0 + if (frac >= pow10[prec]) { + frac = 0; + ++whole; + } + } else if (diff < 0.5) { + } else if ((frac == 0U) || (frac & 1U)) { + // if halfway, round up if odd OR if last digit is 0 + ++frac; + } + + if (prec == 0U) { + diff = value - (double)whole; + if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { + // exactly 0.5 and ODD, then round up + // 1.5 -> 2, but 2.5 -> 2 + ++whole; + } + } else { + unsigned int count = prec; + // now do fractional part, as an unsigned number + while (len < PRINTF_FTOA_BUFFER_SIZE) { + --count; + buf[len++] = (char)(48U + (frac % 10U)); + if (!(frac /= 10U)) { break; } + } + // add extra 0s + while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { + buf[len++] = '0'; + } + if (len < PRINTF_FTOA_BUFFER_SIZE) { + // add decimal + buf[len++] = '.'; + } + } + + // do whole part, number is reversed + while (len < PRINTF_FTOA_BUFFER_SIZE) { + buf[len++] = (char)(48 + (whole % 10)); + if (!(whole /= 10)) { break; } + } + + // pad leading zeros + if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { + if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { + width--; + } + while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { + buf[len++] = '0'; + } + } + + if (len < PRINTF_FTOA_BUFFER_SIZE) { + if (negative) { + buf[len++] = '-'; + } else if (flags & FLAGS_PLUS) { + buf[len++] = '+'; // ignore the space if the '+' exists + } else if (flags & FLAGS_SPACE) { + buf[len++] = ' '; + } + } + + return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); +} + + #if defined(PRINTF_SUPPORT_EXPONENTIAL) +// internal ftoa variant for exponential floating-point type, contributed by +// Martijn Jasperse +static size_t _etoa(out_fct_type out, char *buffer, size_t idx, size_t maxlen, + double value, unsigned int prec, unsigned int width, + unsigned int flags) { + // check for NaN and special values + if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { + return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); + } + + // determine the sign + const bool negative = value < 0; + if (negative) { value = -value; } + + // default precision + if (!(flags & FLAGS_PRECISION)) { prec = PRINTF_DEFAULT_FLOAT_PRECISION; } + + // determine the decimal exponent + // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) + union { + uint64_t U; + double F; + } conv; + + conv.F = value; + int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 + conv.U = (conv.U & ((1ULL << 52U) - 1U)) | + (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) + // now approximate log10 from the log2 integer part and an expansion of ln + // around 1.5 + int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + + (conv.F - 1.5) * 0.289529654602168); + // now we want to compute 10^expval but we want to be sure it won't overflow + exp2 = (int)(expval * 3.321928094887362 + 0.5); + const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; + const double z2 = z * z; + conv.U = (uint64_t)(exp2 + 1023) << 52U; + // compute exp(z) using continued fractions, see + // https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex + conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); + // correct for rounding errors + if (value < conv.F) { + expval--; + conv.F /= 10; + } + + // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 + // characters + unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; + + // in "%g" mode, "prec" is the number of *significant figures* not decimals + if (flags & FLAGS_ADAPT_EXP) { + // do we want to fall-back to "%f" mode? + if ((value >= 1e-4) && (value < 1e6)) { + if ((int)prec > expval) { + prec = (unsigned)((int)prec - expval - 1); + } else { + prec = 0; + } + flags |= FLAGS_PRECISION; // make sure _ftoa respects precision + // no characters in exponent + minwidth = 0U; + expval = 0; + } else { + // we use one sigfig for the whole part + if ((prec > 0) && (flags & FLAGS_PRECISION)) { --prec; } + } + } + + // will everything fit? + unsigned int fwidth = width; + if (width > minwidth) { + // we didn't fall-back so subtract the characters required for the exponent + fwidth -= minwidth; + } else { + // not enough characters, so go back to default sizing + fwidth = 0U; + } + if ((flags & FLAGS_LEFT) && minwidth) { + // if we're padding on the right, DON'T pad the floating part + fwidth = 0U; + } + + // rescale the float value + if (expval) { value /= conv.F; } + + // output the floating part + const size_t start_idx = idx; + idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, + flags & ~FLAGS_ADAPT_EXP); + + // output the exponent part + if (minwidth) { + // output the exponential symbol + out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); + // output the exponent value + idx = + _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, + expval < 0, 10, 0, minwidth - 1, FLAGS_ZEROPAD | FLAGS_PLUS); + // might need to right-pad spaces + if (flags & FLAGS_LEFT) { + while (idx - start_idx < width) + out(' ', buffer, idx++, maxlen); + } + } + return idx; +} + #endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + +// internal vsnprintf +static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, + const char *format, va_list va) { + unsigned int flags, width, precision, n; + size_t idx = 0U; + + if (!buffer) { + // use null output function + out = _out_null; + } + + while (*format) { + // format specifier? %[flags][width][.precision][length] + if (*format != '%') { + // no + out(*format, buffer, idx++, maxlen); + format++; + continue; + } else { + // yes, evaluate it + format++; + } + + // evaluate flags + flags = 0U; + do { + switch (*format) { + case '0': + flags |= FLAGS_ZEROPAD; + format++; + n = 1U; + break; + case '-': + flags |= FLAGS_LEFT; + format++; + n = 1U; + break; + case '+': + flags |= FLAGS_PLUS; + format++; + n = 1U; + break; + case ' ': + flags |= FLAGS_SPACE; + format++; + n = 1U; + break; + case '#': + flags |= FLAGS_HASH; + format++; + n = 1U; + break; + default: + n = 0U; + break; + } + } while (n); + + // evaluate width field + width = 0U; + if (_is_digit(*format)) { + width = _atoi(&format); + } else if (*format == '*') { + const int w = va_arg(va, int); + if (w < 0) { + flags |= FLAGS_LEFT; // reverse padding + width = (unsigned int)-w; + } else { + width = (unsigned int)w; + } + format++; + } + + // evaluate precision field + precision = 0U; + if (*format == '.') { + flags |= FLAGS_PRECISION; + format++; + if (_is_digit(*format)) { + precision = _atoi(&format); + } else if (*format == '*') { + const int prec = (int)va_arg(va, int); + precision = prec > 0 ? (unsigned int)prec : 0U; + format++; + } + } + + // evaluate length field + switch (*format) { + case 'l': + flags |= FLAGS_LONG; + format++; + if (*format == 'l') { + flags |= FLAGS_LONG_LONG; + format++; + } + break; + case 'h': + flags |= FLAGS_SHORT; + format++; + if (*format == 'h') { + flags |= FLAGS_CHAR; + format++; + } + break; +#if defined(PRINTF_SUPPORT_PTRDIFF_T) + case 't': + flags |= + (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; +#endif + case 'j': + flags |= + (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + case 'z': + flags |= + (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); + format++; + break; + default: + break; + } + + // evaluate specifier + switch (*format) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': { + // set the base + unsigned int base; + if (*format == 'x' || *format == 'X') { + base = 16U; + } else if (*format == 'o') { + base = 8U; + } else if (*format == 'b') { + base = 2U; + } else { + base = 10U; + flags &= ~FLAGS_HASH; // no hash for dec format + } + // uppercase + if (*format == 'X') { flags |= FLAGS_UPPERCASE; } + + // no plus or space flag for u, x, X, o, b + if ((*format != 'i') && (*format != 'd')) { + flags &= ~(FLAGS_PLUS | FLAGS_SPACE); + } + + // ignore '0' flag when precision is given + if (flags & FLAGS_PRECISION) { flags &= ~FLAGS_ZEROPAD; } + + // convert the integer + if ((*format == 'i') || (*format == 'd')) { + // signed + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + const long long value = va_arg(va, long long); + idx = _ntoa_long_long( + out, buffer, idx, maxlen, + (unsigned long long)(value > 0 ? value : 0 - value), value < 0, + base, precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + const long value = va_arg(va, long); + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned long)(value > 0 ? value : 0 - value), + value < 0, base, precision, width, flags); + } else { + const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) + : (flags & FLAGS_SHORT) + ? (short int)va_arg(va, int) + : va_arg(va, int); + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned int)(value > 0 ? value : 0 - value), + value < 0, base, precision, width, flags); + } + } else { + // unsigned + if (flags & FLAGS_LONG_LONG) { +#if defined(PRINTF_SUPPORT_LONG_LONG) + idx = _ntoa_long_long(out, buffer, idx, maxlen, + va_arg(va, unsigned long long), false, base, + precision, width, flags); +#endif + } else if (flags & FLAGS_LONG) { + idx = + _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), + false, base, precision, width, flags); + } else { + const unsigned int value = + (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) + : (flags & FLAGS_SHORT) + ? (unsigned short int)va_arg(va, unsigned int) + : va_arg(va, unsigned int); + idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, + precision, width, flags); + } + } + format++; + break; + } +#if defined(PRINTF_SUPPORT_FLOAT) + case 'f': + case 'F': + if (*format == 'F') flags |= FLAGS_UPPERCASE; + idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, + width, flags); + format++; + break; + #if defined(PRINTF_SUPPORT_EXPONENTIAL) + case 'e': + case 'E': + case 'g': + case 'G': + if ((*format == 'g') || (*format == 'G')) flags |= FLAGS_ADAPT_EXP; + if ((*format == 'E') || (*format == 'G')) flags |= FLAGS_UPPERCASE; + idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, + width, flags); + format++; + break; + #endif // PRINTF_SUPPORT_EXPONENTIAL +#endif // PRINTF_SUPPORT_FLOAT + case 'c': { + unsigned int l = 1U; + // pre padding + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // char output + out((char)va_arg(va, int), buffer, idx++, maxlen); + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 's': { + const char *p = va_arg(va, char *); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); + // pre padding + if (flags & FLAGS_PRECISION) { l = (l < precision ? l : precision); } + if (!(flags & FLAGS_LEFT)) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + // string output + while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { + out(*(p++), buffer, idx++, maxlen); + } + // post padding + if (flags & FLAGS_LEFT) { + while (l++ < width) { + out(' ', buffer, idx++, maxlen); + } + } + format++; + break; + } + + case 'p': { + width = sizeof(void *) * 2U; + flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; +#if defined(PRINTF_SUPPORT_LONG_LONG) + const bool is_ll = sizeof(uintptr_t) == sizeof(long long); + if (is_ll) { + idx = _ntoa_long_long(out, buffer, idx, maxlen, + (uintptr_t)va_arg(va, void *), false, 16U, + precision, width, flags); + } else { +#endif + idx = _ntoa_long(out, buffer, idx, maxlen, + (unsigned long)((uintptr_t)va_arg(va, void *)), + false, 16U, precision, width, flags); +#if defined(PRINTF_SUPPORT_LONG_LONG) + } +#endif + format++; + break; + } + + case '%': + out('%', buffer, idx++, maxlen); + format++; + break; + + default: + out(*format, buffer, idx++, maxlen); + format++; + break; + } + } + + // termination + out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + + // return written chars without terminating \0 + return (int)idx; +} + +/////////////////////////////////////////////////////////////////////////////// + +int __libqasan_printf(const char *format, ...) { + va_list va; + va_start(va, format); + char buffer[1]; + const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int __libqasan_sprintf(char *buffer, const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); + va_end(va); + return ret; +} + +int __libqasan_snprintf(char *buffer, size_t count, const char *format, ...) { + va_list va; + va_start(va, format); + const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); + va_end(va); + return ret; +} + +int __libqasan_vprintf(const char *format, va_list va) { + char buffer[1]; + return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); +} + +int __libqasan_vsnprintf(char *buffer, size_t count, const char *format, + va_list va) { + return _vsnprintf(_out_buffer, buffer, count, format, va); +} + +int __libqasan_fctprintf(void (*out)(char character, void *arg), void *arg, + const char *format, ...) { + va_list va; + va_start(va, format); + const out_fct_wrap_type out_fct_wrap = {out, arg}; + const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap, + (size_t)-1, format, va); + va_end(va); + return ret; +} + +//////////////////////////////// libqasan internal output buffer putchar + +#include +#include +#include + +static ssize_t reliable_write(int fd, const void *buf, size_t count) { + ssize_t total_written = 0; + ssize_t bytes_written; + + while (total_written < count) { + bytes_written = + syscall(SYS_write, fd, buf + total_written, count - total_written); + + if (bytes_written == -1) { + if (errno == EINTR) { + continue; + } else { + return -1; + } + } else if (bytes_written == 0) { + break; + } else { + total_written += bytes_written; + } + } + + return total_written; +} + +#define INTERNAL_BUF_SIZE 4096 + +static char output_internal_buf[INTERNAL_BUF_SIZE]; +static size_t output_internal_bug_idx = 0; + +void __libqasan_putchar(char character) { + if (output_internal_bug_idx >= INTERNAL_BUF_SIZE) __libqasan_flush(); + + output_internal_buf[output_internal_bug_idx++] = character; +} + +void __libqasan_flush(void) { + reliable_write(2, output_internal_buf, output_internal_bug_idx); + output_internal_bug_idx = 0; +} diff --git a/libafl_qemu/libqasan/printf/printf.h b/libafl_qemu/libqasan/printf/printf.h new file mode 100644 index 0000000000..8f329fd7ef --- /dev/null +++ b/libafl_qemu/libqasan/printf/printf.h @@ -0,0 +1,115 @@ +/////////////////////////////////////////////////////////////////////////////// +// \author (c) Marco Paland (info@paland.com) +// 2014-2019, PALANDesign Hannover, Germany +// +// \license The MIT License (MIT) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed +// on +// embedded systems with a very limited resources. +// Use this instead of bloated standard/newlib printf. +// These routines are thread safe and reentrant. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Output a character to a custom device like UART, used by the printf() + * function This function is declared here only. You have to write your custom + * implementation somewhere \param character Character to output + */ +void __libqasan_putchar(char character); + +/** + * Tiny printf implementation + * You have to implement _putchar if you use printf() + * To avoid conflicts with the regular printf() API it is overridden by macro + * defines and internal underscore-appended functions like printf_() are used + * \param format A string that specifies the format of the output + * \return The number of characters that are written into the array, not + * counting the terminating null character + */ +int __libqasan_printf(const char *format, ...); + +/** + * Tiny sprintf implementation + * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING + * (V)SNPRINTF INSTEAD! \param buffer A pointer to the buffer where to store the + * formatted string. MUST be big enough to store the output! \param format A + * string that specifies the format of the output \return The number of + * characters that are WRITTEN into the buffer, not counting the terminating + * null character + */ +int __libqasan_sprintf(char *buffer, const char *format, ...); + +/** + * Tiny snprintf/vsnprintf implementation + * \param buffer A pointer to the buffer where to store the formatted string + * \param count The maximum number of characters to store in the buffer, + * including a terminating null character \param format A string that specifies + * the format of the output \param va A value identifying a variable arguments + * list \return The number of characters that COULD have been written into the + * buffer, not counting the terminating null character. A value equal or larger + * than count indicates truncation. Only when the returned value is non-negative + * and less than count, the string has been completely written. + */ +int __libqasan_snprintf(char *buffer, size_t count, const char *format, ...); +int __libqasan_vsnprintf(char *buffer, size_t count, const char *format, + va_list va); + +/** + * Tiny vprintf implementation + * \param format A string that specifies the format of the output + * \param va A value identifying a variable arguments list + * \return The number of characters that are WRITTEN into the buffer, not + * counting the terminating null character + */ +int __libqasan_vprintf(const char *format, va_list va); + +/** + * printf with output function + * You may use this as dynamic alternative to printf() with its fixed _putchar() + * output \param out An output function which takes one character and an + * argument pointer \param arg An argument pointer for user data passed to + * output function \param format A string that specifies the format of the + * output \return The number of characters that are sent to the output function, + * not counting the terminating null character + */ +int __libqasan_fctprintf(void (*out)(char character, void *arg), void *arg, + const char *format, ...); + +// Flush the internal putchat buffer to stderr +void __libqasan_flush(void); + +#ifdef __cplusplus +} +#endif + +#endif // _PRINTF_H_ diff --git a/libafl_qemu/src/aarch64.rs b/libafl_qemu/src/aarch64.rs index 108b633a86..3734406a2d 100644 --- a/libafl_qemu/src/aarch64.rs +++ b/libafl_qemu/src/aarch64.rs @@ -85,6 +85,21 @@ impl crate::ArchExtras for crate::CPU { self.write_reg(Regs::Lr, val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0 => self.read_reg(Regs::X0), + 1 => self.read_reg(Regs::X1), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/arm.rs b/libafl_qemu/src/arm.rs index 87dc9fc7c9..2a1d6a7f9d 100644 --- a/libafl_qemu/src/arm.rs +++ b/libafl_qemu/src/arm.rs @@ -82,6 +82,21 @@ impl crate::ArchExtras for crate::CPU { self.write_reg(Regs::Lr, val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0 => self.read_reg(Regs::R0), + 1 => self.read_reg(Regs::R1), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/asan.rs b/libafl_qemu/src/asan.rs index 8f76318e77..458fa74034 100644 --- a/libafl_qemu/src/asan.rs +++ b/libafl_qemu/src/asan.rs @@ -21,7 +21,7 @@ use rangemap::RangeMap; use crate::{ calls::FullBacktraceCollector, emu::{EmuError, Emulator, MemAccessInfo, SyscallHookResult}, - helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, + helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, hooks::QemuHooks, GuestAddr, Regs, }; @@ -836,6 +836,16 @@ impl Default for QemuAsanHelper { } } +impl HasInstrumentationFilter for QemuAsanHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuAsanHelper where S: UsesInput + HasMetadata, @@ -847,6 +857,10 @@ where QT: QemuHelperTuple, { hooks.syscalls(qasan_fake_syscall::); + + if self.rt.error_callback.is_some() { + hooks.crash(oncrash_asan::); + } } fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) @@ -870,10 +884,6 @@ where Some(trace_write8_asan::), Some(trace_write_n_asan::), ); - - if self.rt.error_callback.is_some() { - hooks.crash(oncrash_asan::); - } } fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) { @@ -1284,6 +1294,7 @@ pub fn asan_report(rt: &AsanGiovese, emu: &Emulator, pc: GuestAddr, err: AsanErr info }; + eprintln!("================================================================="); let backtrace = FullBacktraceCollector::backtrace() .map(|r| { let mut v = r.to_vec(); @@ -1320,8 +1331,9 @@ pub fn asan_report(rt: &AsanGiovese, emu: &Emulator, pc: GuestAddr, err: AsanErr if let Some((chunk, item)) = rt.alloc_get_clone(addr) { eprintln!( - "Address {addr:#x} is {} bytes inside the chunk [{:#x},{:#x})", + "Address {addr:#x} is {} bytes inside the {}-byte chunk [{:#x},{:#x})", addr - chunk.start, + chunk.end - chunk.start, chunk.start, chunk.end ); @@ -1336,32 +1348,33 @@ pub fn asan_report(rt: &AsanGiovese, emu: &Emulator, pc: GuestAddr, err: AsanErr } found = true; eprintln!( - "Address {addr:#x} is {} bytes to the left of the chunk [{:#x},{:#x})", + "Address {addr:#x} is {} bytes to the left of the {}-byte chunk [{:#x},{:#x})", chunk.start - addr, + chunk.end - chunk.start, + chunk.start, + chunk.end + ); + print_bts(item); + }, + ); + found = false; + rt.alloc_map_interval( + ((addr - DEFAULT_REDZONE_SIZE as GuestAddr)..addr).into(), + |chunk, item| { + if found { + return; + } + found = true; + eprintln!( + "Address {addr:#x} is {} bytes to the right of the {}-byte chunk [{:#x},{:#x})", + addr - chunk.end, + chunk.end - chunk.start, chunk.start, chunk.end ); print_bts(item); }, ); - if !found { - rt.alloc_map_interval( - ((addr - DEFAULT_REDZONE_SIZE as GuestAddr)..addr).into(), - |chunk, item| { - if found { - return; - } - found = true; - eprintln!( - "Address {addr:#x} is {} bytes to the right of the chunk [{:#x},{:#x})", - addr - chunk.end, - chunk.start, - chunk.end - ); - print_bts(item); - }, - ); - } } } diff --git a/libafl_qemu/src/calls.rs b/libafl_qemu/src/calls.rs index 88fce7f0ed..19172f9336 100644 --- a/libafl_qemu/src/calls.rs +++ b/libafl_qemu/src/calls.rs @@ -12,7 +12,7 @@ use thread_local::ThreadLocal; use crate::{ capstone, emu::{ArchExtras, Emulator}, - helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, + helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, hooks::QemuHooks, GuestAddr, }; @@ -252,6 +252,9 @@ where } else { return; }; + if collectors.is_none() { + return; // TODO fix this, it can be None on races ret + } collectors .as_mut() .unwrap() @@ -327,6 +330,9 @@ where } else { return; }; + if collectors.is_none() { + return; // TODO fix this, it can be None on races ret + } collectors .as_mut() .unwrap() @@ -376,12 +382,25 @@ where } } +impl HasInstrumentationFilter for QemuCallTracerHelper +where + T: CallTraceCollectorTuple, +{ + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuCallTracerHelper where S: UsesInput, T: CallTraceCollectorTuple, { - fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where QT: QemuHelperTuple, { diff --git a/libafl_qemu/src/cmplog.rs b/libafl_qemu/src/cmplog.rs index f2716a09e7..4eae220540 100644 --- a/libafl_qemu/src/cmplog.rs +++ b/libafl_qemu/src/cmplog.rs @@ -1,13 +1,25 @@ +#[cfg(emulation_mode = "usermode")] +use capstone::{arch::BuildsCapstone, Capstone, InsnDetail}; use hashbrown::HashMap; use libafl::{inputs::UsesInput, state::HasMetadata}; pub use libafl_targets::{ - cmps::__libafl_targets_cmplog_instructions, CmpLogMap, CmpLogObserver, CMPLOG_MAP_H, - CMPLOG_MAP_PTR, CMPLOG_MAP_SIZE, CMPLOG_MAP_W, + cmps::{ + __libafl_targets_cmplog_instructions, __libafl_targets_cmplog_routines, CMPLOG_ENABLED, + }, + CmpLogMap, CmpLogObserver, CMPLOG_MAP_H, CMPLOG_MAP_PTR, CMPLOG_MAP_SIZE, CMPLOG_MAP_W, }; use serde::{Deserialize, Serialize}; +#[cfg(emulation_mode = "usermode")] use crate::{ - helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, + capstone, + emu::{ArchExtras, Emulator}, + CallingConvention, +}; +use crate::{ + helper::{ + hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter, + }, hooks::QemuHooks, GuestAddr, }; @@ -57,6 +69,16 @@ impl Default for QemuCmpLogHelper { } } +impl HasInstrumentationFilter for QemuCmpLogHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuCmpLogHelper where S: UsesInput + HasMetadata, @@ -193,3 +215,158 @@ pub extern "C" fn trace_cmp8_cmplog(id: u64, v0: u64, v1: u64, _data: u64) { __libafl_targets_cmplog_instructions(id as usize, 8, v0, v1); } } + +#[cfg(emulation_mode = "usermode")] +#[derive(Debug)] +pub struct QemuCmpLogRoutinesHelper { + filter: QemuInstrumentationFilter, + cs: Capstone, +} + +#[cfg(emulation_mode = "usermode")] +impl QemuCmpLogRoutinesHelper { + #[must_use] + pub fn new(filter: QemuInstrumentationFilter) -> Self { + Self { + filter, + cs: capstone().detail(true).build().unwrap(), + } + } + + #[must_use] + pub fn must_instrument(&self, addr: GuestAddr) -> bool { + self.filter.allowed(addr) + } + + extern "C" fn on_call(_pc: GuestAddr, k: u64) { + unsafe { + if CMPLOG_ENABLED == 0 { + return; + } + } + + let emu = Emulator::new_empty(); + + let a0: GuestAddr = emu + .read_function_argument(CallingConvention::Cdecl, 0) + .unwrap_or(0); + let a1: GuestAddr = emu + .read_function_argument(CallingConvention::Cdecl, 1) + .unwrap_or(0); + + if a0 == 0 || a1 == 0 { + return; + } + + // if !emu.access_ok(VerifyAccess::Read, a0, 0x20) || !emu.access_ok(VerifyAccess::Read, a1, 0x20) { return; } + + unsafe { + __libafl_targets_cmplog_routines(k as usize, emu.g2h(a0), emu.g2h(a1)); + } + } + + fn gen_blocks_calls( + hooks: &mut QemuHooks<'_, QT, S>, + _state: Option<&mut S>, + pc: GuestAddr, + ) -> Option + where + S: UsesInput, + QT: QemuHelperTuple, + { + if let Some(h) = hooks.helpers_mut().match_first_type_mut::() { + if !h.must_instrument(pc) { + return None; + } + + #[cfg(cpu_target = "arm")] + h.cs.set_mode(if pc & 1 == 1 { + capstone::arch::arm::ArchMode::Thumb.into() + } else { + capstone::arch::arm::ArchMode::Arm.into() + }) + .unwrap(); + } + + let emu = hooks.emulator(); + + if let Some(h) = hooks.helpers().match_first_type::() { + #[allow(unused_mut)] + let mut code = { + #[cfg(emulation_mode = "usermode")] + unsafe { + std::slice::from_raw_parts(emu.g2h(pc), 512) + } + #[cfg(emulation_mode = "systemmode")] + &mut [0; 512] + }; + #[cfg(emulation_mode = "systemmode")] + unsafe { + emu.read_mem(pc, code) + }; // TODO handle faults + + let mut iaddr = pc; + + 'disasm: while let Ok(insns) = h.cs.disasm_count(code, iaddr.into(), 1) { + if insns.is_empty() { + break; + } + let insn = insns.first().unwrap(); + let insn_detail: InsnDetail = h.cs.insn_detail(insn).unwrap(); + for detail in insn_detail.groups() { + match u32::from(detail.0) { + capstone::InsnGroupType::CS_GRP_CALL => { + let k = (hash_me(pc.into())) & (CMPLOG_MAP_W as u64 - 1); + emu.set_hook(insn.address() as GuestAddr, Self::on_call, k, false); + } + capstone::InsnGroupType::CS_GRP_RET + | capstone::InsnGroupType::CS_GRP_INVALID + | capstone::InsnGroupType::CS_GRP_JUMP + | capstone::InsnGroupType::CS_GRP_IRET + | capstone::InsnGroupType::CS_GRP_PRIVILEGE => { + break 'disasm; + } + _ => {} + } + } + + iaddr += insn.bytes().len() as GuestAddr; + + #[cfg(emulation_mode = "usermode")] + unsafe { + code = std::slice::from_raw_parts(emu.g2h(iaddr), 512); + } + #[cfg(emulation_mode = "systemmode")] + unsafe { + emu.read_mem(pc, code); + } // TODO handle faults + } + } + + None + } +} + +#[cfg(emulation_mode = "usermode")] +impl HasInstrumentationFilter for QemuCmpLogRoutinesHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + +#[cfg(emulation_mode = "usermode")] +impl QemuHelper for QemuCmpLogRoutinesHelper +where + S: UsesInput, +{ + fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + where + QT: QemuHelperTuple, + { + hooks.blocks(Some(Self::gen_blocks_calls::), None, None); + } +} diff --git a/libafl_qemu/src/drcov.rs b/libafl_qemu/src/drcov.rs index fdf04dbb6e..72c0733682 100644 --- a/libafl_qemu/src/drcov.rs +++ b/libafl_qemu/src/drcov.rs @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize}; use crate::{ emu::{GuestAddr, GuestUsize}, - helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, + helper::{HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, hooks::QemuHooks, Emulator, }; @@ -75,6 +75,16 @@ impl QemuDrCovHelper { } } +impl HasInstrumentationFilter for QemuDrCovHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuDrCovHelper where S: UsesInput + HasMetadata, diff --git a/libafl_qemu/src/edges.rs b/libafl_qemu/src/edges.rs index 90b39568c4..c9737dbb6b 100644 --- a/libafl_qemu/src/edges.rs +++ b/libafl_qemu/src/edges.rs @@ -3,14 +3,16 @@ use std::{cell::UnsafeCell, cmp::max}; use hashbrown::{hash_map::Entry, HashMap}; use libafl::{inputs::UsesInput, state::HasMetadata}; pub use libafl_targets::{ - edges_map_mut_slice, edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_NUM, - EDGES_MAP_SIZE, MAX_EDGES_NUM, + edges_map_mut_ptr, edges_map_mut_slice, edges_max_num, std_edges_map_observer, EDGES_MAP, + EDGES_MAP_PTR, EDGES_MAP_PTR_NUM, EDGES_MAP_SIZE, MAX_EDGES_NUM, }; use serde::{Deserialize, Serialize}; use crate::{ emu::GuestAddr, - helper::{hash_me, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter}, + helper::{ + hash_me, HasInstrumentationFilter, QemuHelper, QemuHelperTuple, QemuInstrumentationFilter, + }, hooks::QemuHooks, }; @@ -71,6 +73,16 @@ impl Default for QemuEdgeCoverageHelper { } } +impl HasInstrumentationFilter for QemuEdgeCoverageHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuEdgeCoverageHelper where S: UsesInput + HasMetadata, @@ -127,6 +139,16 @@ impl Default for QemuEdgeCoverageChildHelper { } } +impl HasInstrumentationFilter for QemuEdgeCoverageChildHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + impl QemuHelper for QemuEdgeCoverageChildHelper where S: UsesInput, @@ -152,6 +174,78 @@ where } } +#[derive(Debug)] +pub struct QemuEdgeCoverageClassicHelper { + filter: QemuInstrumentationFilter, + use_hitcounts: bool, +} + +impl QemuEdgeCoverageClassicHelper { + #[must_use] + pub fn new(filter: QemuInstrumentationFilter) -> Self { + Self { + filter, + use_hitcounts: true, + } + } + + #[must_use] + pub fn without_hitcounts(filter: QemuInstrumentationFilter) -> Self { + Self { + filter, + use_hitcounts: false, + } + } + + #[must_use] + pub fn must_instrument(&self, addr: GuestAddr) -> bool { + self.filter.allowed(addr) + } +} + +impl Default for QemuEdgeCoverageClassicHelper { + fn default() -> Self { + Self::new(QemuInstrumentationFilter::None) + } +} + +impl HasInstrumentationFilter for QemuEdgeCoverageClassicHelper { + fn filter(&self) -> &QemuInstrumentationFilter { + &self.filter + } + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter { + &mut self.filter + } +} + +impl QemuHelper for QemuEdgeCoverageClassicHelper +where + S: UsesInput, + S: HasMetadata, +{ + const HOOKS_DO_SIDE_EFFECTS: bool = false; + + fn first_exec(&self, hooks: &QemuHooks<'_, QT, S>) + where + QT: QemuHelperTuple, + { + if self.use_hitcounts { + hooks.blocks_raw( + Some(gen_hashed_block_ids::), + None, + Some(trace_block_transition_hitcount), + ); + } else { + hooks.blocks_raw( + Some(gen_hashed_block_ids::), + None, + Some(trace_block_transition_single), + ); + } + } +} + thread_local!(static PREV_LOC : UnsafeCell = UnsafeCell::new(0)); pub fn gen_unique_edge_ids( @@ -251,6 +345,7 @@ pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) { } } +/* pub fn gen_addr_block_ids( _hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, @@ -264,9 +359,10 @@ where #[allow(clippy::unnecessary_cast)] Some(pc as u64) } +*/ pub fn gen_hashed_block_ids( - _hooks: &mut QemuHooks<'_, QT, S>, + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, ) -> Option @@ -274,6 +370,14 @@ where S: UsesInput, QT: QemuHelperTuple, { + if let Some(h) = hooks + .helpers() + .match_first_type::() + { + if !h.must_instrument(pc) { + return None; + } + } // GuestAddress is u32 for 32 bit guests #[allow(clippy::unnecessary_cast)] Some(hash_me(pc as u64)) diff --git a/libafl_qemu/src/elf.rs b/libafl_qemu/src/elf.rs index 791cd58a1c..ae7dd1f929 100644 --- a/libafl_qemu/src/elf.rs +++ b/libafl_qemu/src/elf.rs @@ -94,7 +94,17 @@ impl<'a> EasyElf<'a> { None } - fn is_pic(&self) -> bool { + #[must_use] + pub fn entry_point(&self, load_addr: GuestAddr) -> Option { + if self.elf.entry == 0 { + None + } else { + Some(load_addr + self.elf.entry as GuestAddr) + } + } + + #[must_use] + pub fn is_pic(&self) -> bool { self.elf.header.e_type == ET_DYN } } diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 69a5e750c9..bc8f16e91c 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -195,6 +195,14 @@ impl IntoPy for MmapPerms { } } +#[cfg(emulation_mode = "usermode")] +#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, EnumIter, PartialEq, Eq)] +#[repr(i32)] +pub enum VerifyAccess { + Read = libc::PROT_READ, + Write = libc::PROT_READ | libc::PROT_WRITE, +} + #[repr(C)] #[cfg_attr(feature = "python", pyclass)] #[cfg_attr(feature = "python", derive(FromPyObject))] @@ -319,6 +327,7 @@ extern "C" { unsafe extern "C" fn(u64, i32, u64, u64, u64, u64, u64, u64, u64, u64) -> u64; static mut libafl_dump_core_hook: unsafe extern "C" fn(i32); + static mut libafl_force_dfl: i32; } #[cfg(emulation_mode = "systemmode")] @@ -544,6 +553,9 @@ pub trait ArchExtras { fn write_return_address(&self, val: T) -> Result<(), String> where T: Into; + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From; fn write_function_argument( &self, conv: CallingConvention, @@ -585,6 +597,15 @@ impl CPU { unsafe { (addr as usize - guest_base) as GuestAddr } } + #[cfg(emulation_mode = "usermode")] + #[must_use] + pub fn access_ok(&self, kind: VerifyAccess, addr: GuestAddr, size: usize) -> bool { + unsafe { + // TODO add support for tagged GuestAddr + libafl_qemu_sys::page_check_range(addr, size as GuestAddr, kind.into()) + } + } + #[cfg(emulation_mode = "systemmode")] #[must_use] pub fn get_phys_addr(&self, vaddr: GuestAddr) -> Option { @@ -948,6 +969,14 @@ impl Emulator { unsafe { (addr as usize - guest_base) as GuestAddr } } + #[cfg(emulation_mode = "usermode")] + #[must_use] + pub fn access_ok(&self, kind: VerifyAccess, addr: GuestAddr, size: usize) -> bool { + self.current_cpu() + .unwrap_or_else(|| self.cpu_from_index(0)) + .access_ok(kind, addr, size) + } + pub unsafe fn write_mem(&self, addr: GuestAddr, buf: &[u8]) { self.current_cpu() .unwrap_or_else(|| self.cpu_from_index(0)) @@ -1023,6 +1052,13 @@ impl Emulator { self.remove_breakpoint(addr); } + #[cfg(emulation_mode = "usermode")] + pub fn force_dfl(&self) { + unsafe { + libafl_force_dfl = 1; + } + } + pub fn set_hook( &self, addr: GuestAddr, @@ -1363,6 +1399,15 @@ impl ArchExtras for Emulator { .write_return_address::(val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + self.current_cpu() + .ok_or("Failed to get current CPU")? + .read_function_argument::(conv, idx) + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 6f67f250c8..172b9a951e 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -81,7 +81,7 @@ pub unsafe fn inproc_qemu_crash_handler( E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasExecutions + HasSolutions + HasClientPerfMonitor + HasCorpus, Z: HasObjective, { let real_crash = if USE_LIBAFL_CRASH_HANDLER { @@ -118,7 +118,7 @@ pub unsafe fn inproc_qemu_timeout_handler( E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, Z: HasObjective, { if BREAK_ON_TMOUT { diff --git a/libafl_qemu/src/helper.rs b/libafl_qemu/src/helper.rs index 620beb0613..88e35c20cc 100644 --- a/libafl_qemu/src/helper.rs +++ b/libafl_qemu/src/helper.rs @@ -143,7 +143,7 @@ where } } -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub enum QemuInstrumentationFilter { AllowList(Vec>), DenyList(Vec>), @@ -175,6 +175,17 @@ impl QemuInstrumentationFilter { } } +pub trait HasInstrumentationFilter { + fn filter(&self) -> &QemuInstrumentationFilter; + + fn filter_mut(&mut self) -> &mut QemuInstrumentationFilter; + + fn update_filter(&mut self, filter: QemuInstrumentationFilter, emu: &Emulator) { + *self.filter_mut() = filter; + emu.flush_jit(); + } +} + #[must_use] pub fn hash_me(mut x: u64) -> u64 { x = (x.overflowing_shr(16).0 ^ x).overflowing_mul(0x45d9f3b).0; diff --git a/libafl_qemu/src/hexagon.rs b/libafl_qemu/src/hexagon.rs index 5381e147eb..6a47e4fd4b 100644 --- a/libafl_qemu/src/hexagon.rs +++ b/libafl_qemu/src/hexagon.rs @@ -86,6 +86,18 @@ impl crate::ArchExtras for crate::CPU { self.write_reg(Regs::Lr, val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + // TODO + Err(format!("Unsupported argument: {idx:}")) + } + fn write_function_argument( &self, conv: CallingConvention, @@ -99,6 +111,7 @@ impl crate::ArchExtras for crate::CPU { return Err(format!("Unsupported calling convention: {conv:#?}")); } + // TODO Err(format!("Unsupported argument: {idx:}")) } } diff --git a/libafl_qemu/src/hooks.rs b/libafl_qemu/src/hooks.rs index 1d68708ffb..cc8901270e 100644 --- a/libafl_qemu/src/hooks.rs +++ b/libafl_qemu/src/hooks.rs @@ -739,6 +739,8 @@ where } } +static mut FIRST_EXEC: bool = true; + impl<'a, I, QT> QemuHooks<'a, QT, NopState> where QT: QemuHelperTuple>, @@ -752,7 +754,12 @@ where where H: FnMut(&I) -> ExitKind, { - self.helpers.first_exec_all(self); + unsafe { + if FIRST_EXEC { + self.helpers.first_exec_all(self); + FIRST_EXEC = false; + } + } self.helpers.pre_exec_all(self.emulator, input); let mut exit_kind = harness(input); diff --git a/libafl_qemu/src/i386.rs b/libafl_qemu/src/i386.rs index c54461356d..dc4a7bbfd1 100644 --- a/libafl_qemu/src/i386.rs +++ b/libafl_qemu/src/i386.rs @@ -70,6 +70,34 @@ impl crate::ArchExtras for crate::CPU { Ok(()) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0..=1 => { + let val: GuestReg = val.into(); + let stack_ptr: GuestAddr = self.read_reg(Regs::Sp)?; + /* + * Stack is full and descending. SP points to return address, arguments + * are in reverse order above that. + */ + let size: GuestAddr = size_of::() as GuestAddr; + let offset = size * (idx as GuestAddr + 1); + + let val = unsafe { + self.read_mem(stack_ptr + offset, size_of::()); + }; + Ok(GuestReg::from_le_bytes(val)) + } + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/mips.rs b/libafl_qemu/src/mips.rs index 7a1636e07d..abf32e356d 100644 --- a/libafl_qemu/src/mips.rs +++ b/libafl_qemu/src/mips.rs @@ -82,6 +82,21 @@ impl crate::ArchExtras for crate::CPU { self.write_reg(Regs::Ra, val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0 => self.read_reg(Regs::A0), + 1 => self.read_reg(Regs::A1), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/ppc.rs b/libafl_qemu/src/ppc.rs index 3a81b9bc67..3c71e4881c 100644 --- a/libafl_qemu/src/ppc.rs +++ b/libafl_qemu/src/ppc.rs @@ -122,6 +122,21 @@ impl crate::ArchExtras for crate::CPU { self.write_reg(Regs::Lr, val) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0 => self.read_reg(Regs::R3), + 1 => self.read_reg(Regs::R4), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_qemu/src/x86_64.rs b/libafl_qemu/src/x86_64.rs index f758cbe270..576d1a66d9 100644 --- a/libafl_qemu/src/x86_64.rs +++ b/libafl_qemu/src/x86_64.rs @@ -79,6 +79,21 @@ impl crate::ArchExtras for crate::CPU { Ok(()) } + fn read_function_argument(&self, conv: CallingConvention, idx: i32) -> Result + where + T: From, + { + if conv != CallingConvention::Cdecl { + return Err(format!("Unsupported calling convention: {conv:#?}")); + } + + match idx { + 0 => self.read_reg(Regs::Rdi), + 1 => self.read_reg(Regs::Rsi), + _ => Err(format!("Unsupported argument: {idx:}")), + } + } + fn write_function_argument( &self, conv: CallingConvention, diff --git a/libafl_targets/src/cmps/mod.rs b/libafl_targets/src/cmps/mod.rs index 8d4987bbdc..29ba3d9bc0 100644 --- a/libafl_targets/src/cmps/mod.rs +++ b/libafl_targets/src/cmps/mod.rs @@ -51,6 +51,9 @@ extern "C" { /// Logs an instruction for feedback during fuzzing pub fn __libafl_targets_cmplog_instructions(k: usize, shape: u8, arg1: u64, arg2: u64); + /// Logs a routine for feedback during fuzzing + pub fn __libafl_targets_cmplog_routines(k: usize, ptr1: *const u8, ptr2: *const u8); + /// Pointer to the `CmpLog` map pub static mut libafl_cmplog_map_ptr: *mut CmpLogMap; } diff --git a/libafl_targets/src/windows_asan.rs b/libafl_targets/src/windows_asan.rs index e062980362..25bbd87c63 100644 --- a/libafl_targets/src/windows_asan.rs +++ b/libafl_targets/src/windows_asan.rs @@ -4,7 +4,7 @@ use libafl::{ events::{EventFirer, EventRestarter}, executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers}, feedbacks::Feedback, - state::{HasClientPerfMonitor, HasCorpus, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions}, HasObjective, }; @@ -32,7 +32,7 @@ where E: Executor + HasObservers, EM: EventFirer + EventRestarter, OF: Feedback, - E::State: HasSolutions + HasClientPerfMonitor + HasCorpus, + E::State: HasSolutions + HasClientPerfMonitor + HasCorpus + HasExecutions, Z: HasObjective, { __sanitizer_set_death_callback(asan_death_handler::);