1*b4ff3cf3SPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later 2*b4ff3cf3SPaolo Bonzini 3*b4ff3cf3SPaolo Bonzini //! Error propagation for QEMU Rust code 4*b4ff3cf3SPaolo Bonzini //! 5*b4ff3cf3SPaolo Bonzini //! This module contains [`Error`], the bridge between Rust errors and 6*b4ff3cf3SPaolo Bonzini //! [`Result`](std::result::Result)s and QEMU's C [`Error`](bindings::Error) 7*b4ff3cf3SPaolo Bonzini //! struct. 8*b4ff3cf3SPaolo Bonzini //! 9*b4ff3cf3SPaolo Bonzini //! For FFI code, [`Error`] provides functions to simplify conversion between 10*b4ff3cf3SPaolo Bonzini //! the Rust ([`Result<>`](std::result::Result)) and C (`Error**`) conventions: 11*b4ff3cf3SPaolo Bonzini //! 12*b4ff3cf3SPaolo Bonzini //! * [`ok_or_propagate`](crate::Error::ok_or_propagate), 13*b4ff3cf3SPaolo Bonzini //! [`bool_or_propagate`](crate::Error::bool_or_propagate), 14*b4ff3cf3SPaolo Bonzini //! [`ptr_or_propagate`](crate::Error::ptr_or_propagate) can be used to build 15*b4ff3cf3SPaolo Bonzini //! a C return value while also propagating an error condition 16*b4ff3cf3SPaolo Bonzini //! 17*b4ff3cf3SPaolo Bonzini //! * [`err_or_else`](crate::Error::err_or_else) and 18*b4ff3cf3SPaolo Bonzini //! [`err_or_unit`](crate::Error::err_or_unit) can be used to build a `Result` 19*b4ff3cf3SPaolo Bonzini //! 20*b4ff3cf3SPaolo Bonzini //! This module is most commonly used at the boundary between C and Rust code; 21*b4ff3cf3SPaolo Bonzini //! other code will usually access it through the 22*b4ff3cf3SPaolo Bonzini //! [`qemu_api::Result`](crate::Result) type alias, and will use the 23*b4ff3cf3SPaolo Bonzini //! [`std::error::Error`] interface to let C errors participate in Rust's error 24*b4ff3cf3SPaolo Bonzini //! handling functionality. 25*b4ff3cf3SPaolo Bonzini //! 26*b4ff3cf3SPaolo Bonzini //! Rust code can also create use this module to create an error object that 27*b4ff3cf3SPaolo Bonzini //! will be passed up to C code, though in most cases this will be done 28*b4ff3cf3SPaolo Bonzini //! transparently through the `?` operator. Errors can be constructed from a 29*b4ff3cf3SPaolo Bonzini //! simple error string, from an [`anyhow::Error`] to pass any other Rust error 30*b4ff3cf3SPaolo Bonzini //! type up to C code, or from a combination of the two. 31*b4ff3cf3SPaolo Bonzini //! 32*b4ff3cf3SPaolo Bonzini //! The third case, corresponding to [`Error::with_error`], is the only one that 33*b4ff3cf3SPaolo Bonzini //! requires mentioning [`qemu_api::Error`](crate::Error) explicitly. Similar 34*b4ff3cf3SPaolo Bonzini //! to how QEMU's C code handles errno values, the string and the 35*b4ff3cf3SPaolo Bonzini //! `anyhow::Error` object will be concatenated with `:` as the separator. 36*b4ff3cf3SPaolo Bonzini 37*b4ff3cf3SPaolo Bonzini use std::{ 38*b4ff3cf3SPaolo Bonzini borrow::Cow, 39*b4ff3cf3SPaolo Bonzini ffi::{c_char, c_int, c_void, CStr}, 40*b4ff3cf3SPaolo Bonzini fmt::{self, Display}, 41*b4ff3cf3SPaolo Bonzini panic, ptr, 42*b4ff3cf3SPaolo Bonzini }; 43*b4ff3cf3SPaolo Bonzini 44*b4ff3cf3SPaolo Bonzini use foreign::{prelude::*, OwnedPointer}; 45*b4ff3cf3SPaolo Bonzini 46*b4ff3cf3SPaolo Bonzini use crate::bindings; 47*b4ff3cf3SPaolo Bonzini 48*b4ff3cf3SPaolo Bonzini pub type Result<T> = std::result::Result<T, Error>; 49*b4ff3cf3SPaolo Bonzini 50*b4ff3cf3SPaolo Bonzini #[derive(Debug)] 51*b4ff3cf3SPaolo Bonzini pub struct Error { 52*b4ff3cf3SPaolo Bonzini msg: Option<Cow<'static, str>>, 53*b4ff3cf3SPaolo Bonzini /// Appends the print string of the error to the msg if not None 54*b4ff3cf3SPaolo Bonzini cause: Option<anyhow::Error>, 55*b4ff3cf3SPaolo Bonzini file: &'static str, 56*b4ff3cf3SPaolo Bonzini line: u32, 57*b4ff3cf3SPaolo Bonzini } 58*b4ff3cf3SPaolo Bonzini 59*b4ff3cf3SPaolo Bonzini impl std::error::Error for Error { 60*b4ff3cf3SPaolo Bonzini fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { 61*b4ff3cf3SPaolo Bonzini self.cause.as_ref().map(AsRef::as_ref) 62*b4ff3cf3SPaolo Bonzini } 63*b4ff3cf3SPaolo Bonzini 64*b4ff3cf3SPaolo Bonzini #[allow(deprecated)] 65*b4ff3cf3SPaolo Bonzini fn description(&self) -> &str { 66*b4ff3cf3SPaolo Bonzini self.msg 67*b4ff3cf3SPaolo Bonzini .as_deref() 68*b4ff3cf3SPaolo Bonzini .or_else(|| self.cause.as_deref().map(std::error::Error::description)) 69*b4ff3cf3SPaolo Bonzini .expect("no message nor cause?") 70*b4ff3cf3SPaolo Bonzini } 71*b4ff3cf3SPaolo Bonzini } 72*b4ff3cf3SPaolo Bonzini 73*b4ff3cf3SPaolo Bonzini impl Display for Error { 74*b4ff3cf3SPaolo Bonzini fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 75*b4ff3cf3SPaolo Bonzini let mut prefix = ""; 76*b4ff3cf3SPaolo Bonzini if let Some(ref msg) = self.msg { 77*b4ff3cf3SPaolo Bonzini write!(f, "{msg}")?; 78*b4ff3cf3SPaolo Bonzini prefix = ": "; 79*b4ff3cf3SPaolo Bonzini } 80*b4ff3cf3SPaolo Bonzini if let Some(ref cause) = self.cause { 81*b4ff3cf3SPaolo Bonzini write!(f, "{prefix}{cause}")?; 82*b4ff3cf3SPaolo Bonzini } else if prefix.is_empty() { 83*b4ff3cf3SPaolo Bonzini panic!("no message nor cause?"); 84*b4ff3cf3SPaolo Bonzini } 85*b4ff3cf3SPaolo Bonzini Ok(()) 86*b4ff3cf3SPaolo Bonzini } 87*b4ff3cf3SPaolo Bonzini } 88*b4ff3cf3SPaolo Bonzini 89*b4ff3cf3SPaolo Bonzini impl From<String> for Error { 90*b4ff3cf3SPaolo Bonzini #[track_caller] 91*b4ff3cf3SPaolo Bonzini fn from(msg: String) -> Self { 92*b4ff3cf3SPaolo Bonzini let location = panic::Location::caller(); 93*b4ff3cf3SPaolo Bonzini Error { 94*b4ff3cf3SPaolo Bonzini msg: Some(Cow::Owned(msg)), 95*b4ff3cf3SPaolo Bonzini cause: None, 96*b4ff3cf3SPaolo Bonzini file: location.file(), 97*b4ff3cf3SPaolo Bonzini line: location.line(), 98*b4ff3cf3SPaolo Bonzini } 99*b4ff3cf3SPaolo Bonzini } 100*b4ff3cf3SPaolo Bonzini } 101*b4ff3cf3SPaolo Bonzini 102*b4ff3cf3SPaolo Bonzini impl From<&'static str> for Error { 103*b4ff3cf3SPaolo Bonzini #[track_caller] 104*b4ff3cf3SPaolo Bonzini fn from(msg: &'static str) -> Self { 105*b4ff3cf3SPaolo Bonzini let location = panic::Location::caller(); 106*b4ff3cf3SPaolo Bonzini Error { 107*b4ff3cf3SPaolo Bonzini msg: Some(Cow::Borrowed(msg)), 108*b4ff3cf3SPaolo Bonzini cause: None, 109*b4ff3cf3SPaolo Bonzini file: location.file(), 110*b4ff3cf3SPaolo Bonzini line: location.line(), 111*b4ff3cf3SPaolo Bonzini } 112*b4ff3cf3SPaolo Bonzini } 113*b4ff3cf3SPaolo Bonzini } 114*b4ff3cf3SPaolo Bonzini 115*b4ff3cf3SPaolo Bonzini impl From<anyhow::Error> for Error { 116*b4ff3cf3SPaolo Bonzini #[track_caller] 117*b4ff3cf3SPaolo Bonzini fn from(error: anyhow::Error) -> Self { 118*b4ff3cf3SPaolo Bonzini let location = panic::Location::caller(); 119*b4ff3cf3SPaolo Bonzini Error { 120*b4ff3cf3SPaolo Bonzini msg: None, 121*b4ff3cf3SPaolo Bonzini cause: Some(error), 122*b4ff3cf3SPaolo Bonzini file: location.file(), 123*b4ff3cf3SPaolo Bonzini line: location.line(), 124*b4ff3cf3SPaolo Bonzini } 125*b4ff3cf3SPaolo Bonzini } 126*b4ff3cf3SPaolo Bonzini } 127*b4ff3cf3SPaolo Bonzini 128*b4ff3cf3SPaolo Bonzini impl Error { 129*b4ff3cf3SPaolo Bonzini /// Create a new error, prepending `msg` to the 130*b4ff3cf3SPaolo Bonzini /// description of `cause` 131*b4ff3cf3SPaolo Bonzini #[track_caller] 132*b4ff3cf3SPaolo Bonzini pub fn with_error(msg: impl Into<Cow<'static, str>>, cause: impl Into<anyhow::Error>) -> Self { 133*b4ff3cf3SPaolo Bonzini let location = panic::Location::caller(); 134*b4ff3cf3SPaolo Bonzini Error { 135*b4ff3cf3SPaolo Bonzini msg: Some(msg.into()), 136*b4ff3cf3SPaolo Bonzini cause: Some(cause.into()), 137*b4ff3cf3SPaolo Bonzini file: location.file(), 138*b4ff3cf3SPaolo Bonzini line: location.line(), 139*b4ff3cf3SPaolo Bonzini } 140*b4ff3cf3SPaolo Bonzini } 141*b4ff3cf3SPaolo Bonzini 142*b4ff3cf3SPaolo Bonzini /// Consume a result, returning `false` if it is an error and 143*b4ff3cf3SPaolo Bonzini /// `true` if it is successful. The error is propagated into 144*b4ff3cf3SPaolo Bonzini /// `errp` like the C API `error_propagate` would do. 145*b4ff3cf3SPaolo Bonzini /// 146*b4ff3cf3SPaolo Bonzini /// # Safety 147*b4ff3cf3SPaolo Bonzini /// 148*b4ff3cf3SPaolo Bonzini /// `errp` must be a valid argument to `error_propagate`; 149*b4ff3cf3SPaolo Bonzini /// typically it is received from C code and need not be 150*b4ff3cf3SPaolo Bonzini /// checked further at the Rust↔C boundary. 151*b4ff3cf3SPaolo Bonzini pub unsafe fn bool_or_propagate(result: Result<()>, errp: *mut *mut bindings::Error) -> bool { 152*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees errp is valid 153*b4ff3cf3SPaolo Bonzini unsafe { Self::ok_or_propagate(result, errp) }.is_some() 154*b4ff3cf3SPaolo Bonzini } 155*b4ff3cf3SPaolo Bonzini 156*b4ff3cf3SPaolo Bonzini /// Consume a result, returning a `NULL` pointer if it is an error and 157*b4ff3cf3SPaolo Bonzini /// a C representation of the contents if it is successful. This is 158*b4ff3cf3SPaolo Bonzini /// similar to the C API `error_propagate`, but it panics if `*errp` 159*b4ff3cf3SPaolo Bonzini /// is not `NULL`. 160*b4ff3cf3SPaolo Bonzini /// 161*b4ff3cf3SPaolo Bonzini /// # Safety 162*b4ff3cf3SPaolo Bonzini /// 163*b4ff3cf3SPaolo Bonzini /// `errp` must be a valid argument to `error_propagate`; 164*b4ff3cf3SPaolo Bonzini /// typically it is received from C code and need not be 165*b4ff3cf3SPaolo Bonzini /// checked further at the Rust↔C boundary. 166*b4ff3cf3SPaolo Bonzini /// 167*b4ff3cf3SPaolo Bonzini /// See [`propagate`](Error::propagate) for more information. 168*b4ff3cf3SPaolo Bonzini #[must_use] 169*b4ff3cf3SPaolo Bonzini pub unsafe fn ptr_or_propagate<T: CloneToForeign>( 170*b4ff3cf3SPaolo Bonzini result: Result<T>, 171*b4ff3cf3SPaolo Bonzini errp: *mut *mut bindings::Error, 172*b4ff3cf3SPaolo Bonzini ) -> *mut T::Foreign { 173*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees errp is valid 174*b4ff3cf3SPaolo Bonzini unsafe { Self::ok_or_propagate(result, errp) }.clone_to_foreign_ptr() 175*b4ff3cf3SPaolo Bonzini } 176*b4ff3cf3SPaolo Bonzini 177*b4ff3cf3SPaolo Bonzini /// Consume a result in the same way as `self.ok()`, but also propagate 178*b4ff3cf3SPaolo Bonzini /// a possible error into `errp`. This is similar to the C API 179*b4ff3cf3SPaolo Bonzini /// `error_propagate`, but it panics if `*errp` is not `NULL`. 180*b4ff3cf3SPaolo Bonzini /// 181*b4ff3cf3SPaolo Bonzini /// # Safety 182*b4ff3cf3SPaolo Bonzini /// 183*b4ff3cf3SPaolo Bonzini /// `errp` must be a valid argument to `error_propagate`; 184*b4ff3cf3SPaolo Bonzini /// typically it is received from C code and need not be 185*b4ff3cf3SPaolo Bonzini /// checked further at the Rust↔C boundary. 186*b4ff3cf3SPaolo Bonzini /// 187*b4ff3cf3SPaolo Bonzini /// See [`propagate`](Error::propagate) for more information. 188*b4ff3cf3SPaolo Bonzini pub unsafe fn ok_or_propagate<T>( 189*b4ff3cf3SPaolo Bonzini result: Result<T>, 190*b4ff3cf3SPaolo Bonzini errp: *mut *mut bindings::Error, 191*b4ff3cf3SPaolo Bonzini ) -> Option<T> { 192*b4ff3cf3SPaolo Bonzini result.map_err(|err| unsafe { err.propagate(errp) }).ok() 193*b4ff3cf3SPaolo Bonzini } 194*b4ff3cf3SPaolo Bonzini 195*b4ff3cf3SPaolo Bonzini /// Equivalent of the C function `error_propagate`. Fill `*errp` 196*b4ff3cf3SPaolo Bonzini /// with the information container in `self` if `errp` is not NULL; 197*b4ff3cf3SPaolo Bonzini /// then consume it. 198*b4ff3cf3SPaolo Bonzini /// 199*b4ff3cf3SPaolo Bonzini /// This is similar to the C API `error_propagate`, but it panics if 200*b4ff3cf3SPaolo Bonzini /// `*errp` is not `NULL`. 201*b4ff3cf3SPaolo Bonzini /// 202*b4ff3cf3SPaolo Bonzini /// # Safety 203*b4ff3cf3SPaolo Bonzini /// 204*b4ff3cf3SPaolo Bonzini /// `errp` must be a valid argument to `error_propagate`; it can be 205*b4ff3cf3SPaolo Bonzini /// `NULL` or it can point to any of: 206*b4ff3cf3SPaolo Bonzini /// * `error_abort` 207*b4ff3cf3SPaolo Bonzini /// * `error_fatal` 208*b4ff3cf3SPaolo Bonzini /// * a local variable of (C) type `Error *` 209*b4ff3cf3SPaolo Bonzini /// 210*b4ff3cf3SPaolo Bonzini /// Typically `errp` is received from C code and need not be 211*b4ff3cf3SPaolo Bonzini /// checked further at the Rust↔C boundary. 212*b4ff3cf3SPaolo Bonzini pub unsafe fn propagate(self, errp: *mut *mut bindings::Error) { 213*b4ff3cf3SPaolo Bonzini if errp.is_null() { 214*b4ff3cf3SPaolo Bonzini return; 215*b4ff3cf3SPaolo Bonzini } 216*b4ff3cf3SPaolo Bonzini 217*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees that errp and *errp are valid 218*b4ff3cf3SPaolo Bonzini unsafe { 219*b4ff3cf3SPaolo Bonzini assert_eq!(*errp, ptr::null_mut()); 220*b4ff3cf3SPaolo Bonzini bindings::error_propagate(errp, self.clone_to_foreign_ptr()); 221*b4ff3cf3SPaolo Bonzini } 222*b4ff3cf3SPaolo Bonzini } 223*b4ff3cf3SPaolo Bonzini 224*b4ff3cf3SPaolo Bonzini /// Convert a C `Error*` into a Rust `Result`, using 225*b4ff3cf3SPaolo Bonzini /// `Ok(())` if `c_error` is NULL. Free the `Error*`. 226*b4ff3cf3SPaolo Bonzini /// 227*b4ff3cf3SPaolo Bonzini /// # Safety 228*b4ff3cf3SPaolo Bonzini /// 229*b4ff3cf3SPaolo Bonzini /// `c_error` must be `NULL` or valid; typically it was initialized 230*b4ff3cf3SPaolo Bonzini /// with `ptr::null_mut()` and passed by reference to a C function. 231*b4ff3cf3SPaolo Bonzini pub unsafe fn err_or_unit(c_error: *mut bindings::Error) -> Result<()> { 232*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees c_error is valid 233*b4ff3cf3SPaolo Bonzini unsafe { Self::err_or_else(c_error, || ()) } 234*b4ff3cf3SPaolo Bonzini } 235*b4ff3cf3SPaolo Bonzini 236*b4ff3cf3SPaolo Bonzini /// Convert a C `Error*` into a Rust `Result`, calling `f()` to 237*b4ff3cf3SPaolo Bonzini /// obtain an `Ok` value if `c_error` is NULL. Free the `Error*`. 238*b4ff3cf3SPaolo Bonzini /// 239*b4ff3cf3SPaolo Bonzini /// # Safety 240*b4ff3cf3SPaolo Bonzini /// 241*b4ff3cf3SPaolo Bonzini /// `c_error` must be `NULL` or point to a valid C [`struct 242*b4ff3cf3SPaolo Bonzini /// Error`](bindings::Error); typically it was initialized with 243*b4ff3cf3SPaolo Bonzini /// `ptr::null_mut()` and passed by reference to a C function. 244*b4ff3cf3SPaolo Bonzini pub unsafe fn err_or_else<T, F: FnOnce() -> T>( 245*b4ff3cf3SPaolo Bonzini c_error: *mut bindings::Error, 246*b4ff3cf3SPaolo Bonzini f: F, 247*b4ff3cf3SPaolo Bonzini ) -> Result<T> { 248*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees c_error is valid 249*b4ff3cf3SPaolo Bonzini let err = unsafe { Option::<Self>::from_foreign(c_error) }; 250*b4ff3cf3SPaolo Bonzini match err { 251*b4ff3cf3SPaolo Bonzini None => Ok(f()), 252*b4ff3cf3SPaolo Bonzini Some(err) => Err(err), 253*b4ff3cf3SPaolo Bonzini } 254*b4ff3cf3SPaolo Bonzini } 255*b4ff3cf3SPaolo Bonzini } 256*b4ff3cf3SPaolo Bonzini 257*b4ff3cf3SPaolo Bonzini impl FreeForeign for Error { 258*b4ff3cf3SPaolo Bonzini type Foreign = bindings::Error; 259*b4ff3cf3SPaolo Bonzini 260*b4ff3cf3SPaolo Bonzini unsafe fn free_foreign(p: *mut bindings::Error) { 261*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees p is valid 262*b4ff3cf3SPaolo Bonzini unsafe { 263*b4ff3cf3SPaolo Bonzini bindings::error_free(p); 264*b4ff3cf3SPaolo Bonzini } 265*b4ff3cf3SPaolo Bonzini } 266*b4ff3cf3SPaolo Bonzini } 267*b4ff3cf3SPaolo Bonzini 268*b4ff3cf3SPaolo Bonzini impl CloneToForeign for Error { 269*b4ff3cf3SPaolo Bonzini fn clone_to_foreign(&self) -> OwnedPointer<Self> { 270*b4ff3cf3SPaolo Bonzini // SAFETY: all arguments are controlled by this function 271*b4ff3cf3SPaolo Bonzini unsafe { 272*b4ff3cf3SPaolo Bonzini let err: *mut c_void = libc::malloc(std::mem::size_of::<bindings::Error>()); 273*b4ff3cf3SPaolo Bonzini let err: &mut bindings::Error = &mut *err.cast(); 274*b4ff3cf3SPaolo Bonzini *err = bindings::Error { 275*b4ff3cf3SPaolo Bonzini msg: format!("{self}").clone_to_foreign_ptr(), 276*b4ff3cf3SPaolo Bonzini err_class: bindings::ERROR_CLASS_GENERIC_ERROR, 277*b4ff3cf3SPaolo Bonzini src_len: self.file.len() as c_int, 278*b4ff3cf3SPaolo Bonzini src: self.file.as_ptr().cast::<c_char>(), 279*b4ff3cf3SPaolo Bonzini line: self.line as c_int, 280*b4ff3cf3SPaolo Bonzini func: ptr::null_mut(), 281*b4ff3cf3SPaolo Bonzini hint: ptr::null_mut(), 282*b4ff3cf3SPaolo Bonzini }; 283*b4ff3cf3SPaolo Bonzini OwnedPointer::new(err) 284*b4ff3cf3SPaolo Bonzini } 285*b4ff3cf3SPaolo Bonzini } 286*b4ff3cf3SPaolo Bonzini } 287*b4ff3cf3SPaolo Bonzini 288*b4ff3cf3SPaolo Bonzini impl FromForeign for Error { 289*b4ff3cf3SPaolo Bonzini unsafe fn cloned_from_foreign(c_error: *const bindings::Error) -> Self { 290*b4ff3cf3SPaolo Bonzini // SAFETY: caller guarantees c_error is valid 291*b4ff3cf3SPaolo Bonzini unsafe { 292*b4ff3cf3SPaolo Bonzini let error = &*c_error; 293*b4ff3cf3SPaolo Bonzini let file = if error.src_len < 0 { 294*b4ff3cf3SPaolo Bonzini // NUL-terminated 295*b4ff3cf3SPaolo Bonzini CStr::from_ptr(error.src).to_str() 296*b4ff3cf3SPaolo Bonzini } else { 297*b4ff3cf3SPaolo Bonzini // Can become str::from_utf8 with Rust 1.87.0 298*b4ff3cf3SPaolo Bonzini std::str::from_utf8(std::slice::from_raw_parts( 299*b4ff3cf3SPaolo Bonzini &*error.src.cast::<u8>(), 300*b4ff3cf3SPaolo Bonzini error.src_len as usize, 301*b4ff3cf3SPaolo Bonzini )) 302*b4ff3cf3SPaolo Bonzini }; 303*b4ff3cf3SPaolo Bonzini 304*b4ff3cf3SPaolo Bonzini Error { 305*b4ff3cf3SPaolo Bonzini msg: FromForeign::cloned_from_foreign(error.msg), 306*b4ff3cf3SPaolo Bonzini cause: None, 307*b4ff3cf3SPaolo Bonzini file: file.unwrap(), 308*b4ff3cf3SPaolo Bonzini line: error.line as u32, 309*b4ff3cf3SPaolo Bonzini } 310*b4ff3cf3SPaolo Bonzini } 311*b4ff3cf3SPaolo Bonzini } 312*b4ff3cf3SPaolo Bonzini } 313