//! This crate provides types for identifiers of object files, such as executables, dynamic //! libraries or debug companion files. The concept originates in Google Breakpad and defines two //! types: //! //! - [`CodeId`]: Identifies the file containing source code, i.e. the actual library or //! executable. The identifier is platform dependent and implementation defined. Thus, there is //! no canonical representation. //! - [`DebugId`]: Identifies a debug information file, which may or may not use information from //! the Code ID. The contents are also implementation defined, but as opposed to `CodeId`, the //! structure is streamlined across platforms. It is also guaranteed to be 32 bytes in size. //! //! [`CodeId`]: struct.CodeId.html //! [`DebugId`]: struct.DebugId.html
#![warn(missing_docs)]
use std::error; use std::fmt; use std::fmt::Write; use std::str;
use uuid::{Bytes, Uuid};
/// Indicates an error parsing a [`DebugId`](struct.DebugId.html). #[derive(Clone, Copy, Debug, Eq, PartialEq)] pubstruct ParseDebugIdError;
/// Unique identifier for debug information files and their debug information. /// /// This type is analogous to [`CodeId`], except that it identifies a debug file instead of the /// actual library or executable. One some platforms, a `DebugId` is an alias for a `CodeId` but the /// exact rules around this are complex. On Windows, the identifiers are completely different and /// refer to separate files. /// /// The string representation must be between 33 and 40 characters long and consist of: /// /// 1. 36 character hyphenated hex representation of the UUID field /// 2. 1-16 character lowercase hex representation of the u32 appendix /// /// The debug identifier is compatible to Google Breakpad. Use [`DebugId::breakpad`] to get a /// breakpad string representation of this debug identifier. /// /// There is one exception to this: for the old PDB 2.0 format the debug identifier consists /// of only a 32-bit integer + age resulting in a string representation of between 9 and 16 /// hex characters. /// /// # Example /// /// ``` /// # extern crate debugid; /// use std::str::FromStr; /// use debugid::DebugId; /// /// # fn foo() -> Result<(), ::debugid::ParseDebugIdError> { /// let id = DebugId::from_str("dfb8e43a-f242-3d73-a453-aeb6a777ef75-a")?; /// assert_eq!("dfb8e43a-f242-3d73-a453-aeb6a777ef75-a".to_string(), id.to_string()); /// # Ok(()) /// # } /// /// # fn main() { foo().unwrap() } /// ``` /// /// # In-memory representation /// /// The in-memory representation takes up 32 bytes and can be directly written to storage /// and mapped back into an object reference. /// /// ``` /// use std::str::FromStr; /// use debugid::DebugId; /// /// let debug_id = DebugId::from_str("dfb8e43a-f242-3d73-a453-aeb6a777ef75-a").unwrap(); /// /// let slice = &[debug_id]; /// let ptr = slice.as_ptr() as *const u8; /// let len = std::mem::size_of_val(slice); /// let buf: &[u8] = unsafe { std::slice::from_raw_parts(ptr, len) }; /// /// let mut new_buf: Vec<u8> = Vec::new(); /// std::io::copy(&mut std::io::Cursor::new(buf), &mut new_buf).unwrap(); /// /// let ptr = new_buf.as_ptr() as *const DebugId; /// let new_debug_id = unsafe { &*ptr }; /// /// assert_eq!(*new_debug_id, debug_id); /// ``` /// /// As long the bytes were written using the same major version of this crate you will be /// able to read it again like this. /// /// [`CodeId`]: struct.CodeId.html /// [`DebugId::breakpad`]: struct.DebugId.html#method.breakpad // This needs to be backwards compatible also in its exact in-memory byte-layout since this // struct is directly mapped from disk in e.g. Symbolic SymCache formats. The first version // of this struct was defined as: // // ```rust // struct DebugId { // uuid: Uuid, // appendix: u32, // _padding: [u8; 12], // } // ``` // // For this reason the current `typ` byte represents the type of `DebugId` stored in the // `Bytes`: // // - `0u8`: The `bytes` field contains a UUID. // - `1u8`: The first 4 bytes of the `bytes` field contain a big-endian u32, the remaining // bytes are 0. #[repr(C, packed)] #[derive(Default, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] pubstruct DebugId {
bytes: Bytes,
appendix: u32,
_padding: [u8; 11],
typ: u8,
}
impl DebugId { /// Constructs an empty debug identifier, containing only zeros. pubfn nil() -> Self { Self::default()
}
/// Constructs a `DebugId` from its `uuid`. pubfn from_uuid(uuid: Uuid) -> Self { Self::from_parts(uuid, 0)
}
/// Constructs a `DebugId` from its `uuid` and `appendix` parts. pubfn from_parts(uuid: Uuid, appendix: u32) -> Self {
DebugId {
bytes: *uuid.as_bytes(),
appendix,
typ: 0,
_padding: [0; 11],
}
}
/// Constructs a `DebugId` from a Microsoft little-endian GUID and age. pubfn from_guid_age(guid: &[u8], age: u32) -> Result<Self, ParseDebugIdError> { if guid.len() != 16 { return Err(ParseDebugIdError);
}
/// Constructs a `DebugId` from a PDB 2.0 timestamp and age. pubfn from_pdb20(timestamp: u32, age: u32) -> Self { // The big-endian byte-order here has to match the one used to read this number in // the DebugId::timestamp method.
DebugId {
bytes: [
(timestamp >> 24) as u8,
(timestamp >> 16) as u8,
(timestamp >> 8) as u8,
timestamp as u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
],
appendix: age,
_padding: [0u8; 11],
typ: 1u8,
}
}
/// Parses a breakpad identifier from a string. pubfn from_breakpad(string: &str) -> Result<Self, ParseDebugIdError> { let options = ParseOptions {
allow_hyphens: false,
require_appendix: true,
allow_tail: false,
}; Self::parse_str(string, options).ok_or(ParseDebugIdError)
}
/// Returns the UUID part of the code module's debug_identifier. /// /// If this is a debug identifier for the PDB 2.0 format an invalid UUID is returned /// where only the first 4 bytes are filled in and the remainder of the bytes are 0. /// This means the UUID has variant [`uuid::Variant::NCS`] and an unknown version, /// [`Uuid::get_version`] will return `None`, which is not a valid UUID. /// /// This may seem odd however does seem reasonable: /// /// - Every [`DebugId`] can be represented as [`Uuid`] and will still mostly look /// reasonable e.g. in comparisons etc. /// - The PDB 2.0 format is very old and very unlikely to appear practically. pubfn uuid(&self) -> Uuid {
Uuid::from_bytes(self.bytes)
}
/// Returns the appendix part of the code module's debug identifier. /// /// On Windows, this is an incrementing counter to identify the build. /// On all other platforms, this value will always be zero. pubfn appendix(&self) -> u32 { self.appendix
}
/// Returns whether this identifier is nil, i.e. it consists only of zeros. pubfn is_nil(&self) -> bool { self.bytes == [0u8; 16] && self.appendix == 0
}
/// Returns whether this identifier is from the PDB 2.0 format. pubfn is_pdb20(&self) -> bool { self.typ == 1
}
/// Returns a wrapper which when formatted via `fmt::Display` will format a /// a breakpad identifier. pubfn breakpad(&self) -> BreakpadFormat<'_> {
BreakpadFormat { inner: self }
}
// Can the PDB 2.0 format match? This can never be true for a valid UUID. let min_len = if is_hyphenated { 10 } else { 9 }; let max_len = if is_hyphenated { 17 } else { 16 }; if min_len <= string.len() && string.len() <= max_len { let timestamp_str = string.get(..8)?; let timestamp = u32::from_str_radix(timestamp_str, 16).ok()?; let appendix_str = match is_hyphenated { true => string.get(9..)?, false => string.get(8..)?,
}; let appendix = u32::from_str_radix(appendix_str, 16).ok()?; return Some(Self::from_pdb20(timestamp, appendix));
}
let uuid_len = if is_hyphenated { 36 } else { 32 }; let uuid = string.get(..uuid_len)?.parse().ok()?; if !options.require_appendix && string.len() == uuid_len { return Some(Self::from_parts(uuid, 0));
}
letmut appendix_str = &string[uuid_len..]; if is_hyphenated ^ appendix_str.starts_with('-') { return None; // Require a hyphen if and only if we're hyphenated.
} elseif is_hyphenated {
appendix_str = &appendix_str[1..]; // Skip the hyphen for parsing.
}
// Parse the appendix, which fails on empty strings. let appendix = u32::from_str_radix(appendix_str, 16).ok()?;
Some(Self::from_parts(uuid, appendix))
}
/// Returns the PDB 2.0 timestamp. /// /// Only valid if you know this is a PDB 2.0 debug identifier. fn timestamp(&self) -> u32 {
u32::from_be_bytes([self.bytes[0], self.bytes[1], self.bytes[2], self.bytes[3]])
}
}
/// Unique platform-dependent identifier of code files. /// /// This identifier assumes a string representation that depends on the platform and compiler used. /// The representation only retains hex characters and canonically stores lower case. /// /// There are the following known formats: /// /// - **MachO UUID**: The unique identifier of a Mach binary, specified in the `LC_UUID` load /// command header. /// - **GNU Build ID**: Contents of the `.gnu.build-id` note or section contents formatted as /// lowercase hex string. /// - **PE Timestamp**: Timestamp and size of image values from a Windows PE header. The size of /// image value is truncated, so the length of the `CodeId` might not be a multiple of 2. #[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pubstruct CodeId {
inner: String,
}
#[cfg(feature = "serde")] mod serde_support { use serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor}; use serde::ser::{Serialize, Serializer};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.