diff --git a/plugins/pdb-ng/CMakeLists.txt b/plugins/pdb-ng/CMakeLists.txt index 50f0f2af8a..e96749cb8b 100644 --- a/plugins/pdb-ng/CMakeLists.txt +++ b/plugins/pdb-ng/CMakeLists.txt @@ -4,7 +4,10 @@ project(pdb_import_plugin) file(GLOB PLUGIN_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/Cargo.toml - ${PROJECT_SOURCE_DIR}/src/*.rs) + ${PROJECT_SOURCE_DIR}/src/*.rs + ${PROJECT_SOURCE_DIR}/vendor/pdb-rs/Cargo.toml + ${PROJECT_SOURCE_DIR}/vendor/pdb-rs/src/*.rs + ${PROJECT_SOURCE_DIR}/vendor/pdb-rs/src/*/*.rs) if(CMAKE_BUILD_TYPE MATCHES Debug) if(DEMO) diff --git a/plugins/pdb-ng/Cargo.toml b/plugins/pdb-ng/Cargo.toml index 44cf5f03cb..06a952fe13 100644 --- a/plugins/pdb-ng/Cargo.toml +++ b/plugins/pdb-ng/Cargo.toml @@ -13,9 +13,9 @@ anyhow = "^1.0" binaryninja.workspace = true binaryninjacore-sys.workspace = true itertools = "0.14" -pdb = { git = "https://github.com/Vector35/pdb-rs", rev = "6016177" } +pdb = { path = "vendor/pdb-rs" } regex = "1" tracing = "0.1" [features] -demo = [] \ No newline at end of file +demo = [] diff --git a/plugins/pdb-ng/demo/Cargo.toml b/plugins/pdb-ng/demo/Cargo.toml index 590cacca5c..4e51330885 100644 --- a/plugins/pdb-ng/demo/Cargo.toml +++ b/plugins/pdb-ng/demo/Cargo.toml @@ -13,7 +13,7 @@ anyhow = "^1.0" binaryninja = { workspace = true, features = ["demo"]} binaryninjacore-sys.workspace = true itertools = "0.14" -pdb = { git = "https://github.com/Vector35/pdb-rs", rev = "6016177" } +pdb = { path = "../vendor/pdb-rs" } regex = "1" tracing = "0.1" diff --git a/plugins/pdb-ng/vendor/pdb-rs/Cargo.toml b/plugins/pdb-ng/vendor/pdb-rs/Cargo.toml new file mode 100644 index 0000000000..542f0c4224 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "pdb" +version = "0.8.0" +description = "A parser for Microsoft PDB (Program Database) debugging information" +repository = "https://github.com/willglynn/pdb" +authors = ["Jan Michael Auer ", "Will Glynn "] +readme = "README.md" +license = "MIT OR Apache-2.0" +edition = "2018" +exclude = [ + "fixtures/*", + "scripts/*", +] + +[dependencies] +fallible-iterator = "0.2.0" +scroll = "0.11.0" +uuid = "1.0.0" + +[dev-dependencies] +# for examples/ +getopts = "0.2.21" + +[package.metadata.release] +pre-release-commit-message = "Release {{version}}" +tag-name = "{{version}}" +tag-message = "Release {{version}}" +dev-version = false diff --git a/plugins/pdb-ng/vendor/pdb-rs/LICENSE-APACHE b/plugins/pdb-ng/vendor/pdb-rs/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/plugins/pdb-ng/vendor/pdb-rs/LICENSE-MIT b/plugins/pdb-ng/vendor/pdb-rs/LICENSE-MIT new file mode 100644 index 0000000000..8c1e8e1f07 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2017 pdb Developers + +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/plugins/pdb-ng/vendor/pdb-rs/README.md b/plugins/pdb-ng/vendor/pdb-rs/README.md new file mode 100644 index 0000000000..1b0ddebc03 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/README.md @@ -0,0 +1,99 @@ +`pdb` +=== + +[![](https://img.shields.io/crates/v/pdb.svg)](https://crates.io/crates/pdb) [![](https://docs.rs/pdb/badge.svg)](https://docs.rs/pdb/) ![Build Status](https://github.com/willglynn/pdb/actions/workflows/ci.yml/badge.svg) + +This is a Rust library that parses Microsoft PDB (Program Database) files. +These files contain debugging information produced by most compilers that +target Windows, including information about symbols, types, modules, and so on. + +The PDB format is not documented per sé, but Microsoft has [published +information](https://github.com/Microsoft/microsoft-pdb) in the form of C++ +code relating to its use. The PDB format is full of... history, including +support for debugging 16-bit executables, COBOL user-defined types, and myriad +other features. `pdb` does not understand everything about the PDB format, +but it does cover enough to be useful for typical programs compiled today. + +[Documentation on docs.rs](https://docs.rs/pdb/). + +Design +--- + +`pdb`'s design objectives are similar to +[`gimli`](https://github.com/gimli-rs/gimli): + +* `pdb` works with the original data as it's formatted on-disk as long as + possible. + +* `pdb` parses only what you ask. + +* `pdb` can read PDBs anywhere. There's no dependency on Windows, on the + [DIA SDK](https://msdn.microsoft.com/en-us/library/x93ctkx8.aspx), or on + the target's native byte ordering. + +Usage Example +--- + +```rust +use pdb::FallibleIterator; +use std::fs::File; + +fn main() -> pdb::Result<()> { + let file = File::open("fixtures/self/foo.pdb")?; + let mut pdb = pdb::PDB::open(file)?; + + let symbol_table = pdb.global_symbols()?; + let address_map = pdb.address_map()?; + + let mut symbols = symbol_table.iter(); + while let Some(symbol) = symbols.next()? { + match symbol.parse() { + Ok(pdb::SymbolData::Public(data)) if data.function => { + // we found the location of a function! + let rva = data.offset.to_rva(&address_map).unwrap_or_default + println!("{} is {}", rva, data.name); + } + _ => {} + } + } + + Ok(()) +} +``` + +Example Programs +--- + +Run with `cargo run --release --example `: + +* [`pdb_symbols`](examples/pdb_symbols.rs) is a toy program that prints the name and location of every function and + data value defined in the symbol table. + +* [`pdb2hpp`](examples/pdb2hpp.rs) is a somewhat larger program that prints an approximation of a C++ header file for + a requested type given only a PDB. + +* [`pdb_lines`](examples/pdb_lines.rs) outputs line number information for every symbol in every module contained in + a PDB. + +Real-world examples: + +* [`mstange/pdb-addr2line`](https://github.com/mstange/pdb-addr2line) resolves addresses to function names, and to file name and line number information, with the help of a PDB file. Inline stacks are supported. + +* [`getsentry/symbolic`](https://github.com/getsentry/symbolic) is a high-level symbolication library supporting most common debug file formats, demangling, and more. + +License +--- + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +Contribution +--- + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/common.rs b/plugins/pdb-ng/vendor/pdb-rs/src/common.rs new file mode 100644 index 0000000000..c90c34b717 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/common.rs @@ -0,0 +1,1302 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::borrow::Cow; +use std::fmt; +use std::io; +use std::mem; +use std::ops::{Add, AddAssign, Sub}; +use std::result; +use std::slice; + +use scroll::ctx::TryFromCtx; +use scroll::{self, Endian, Pread, LE}; + +use crate::tpi::constants; + +/// An error that occurred while reading or parsing the PDB. +#[non_exhaustive] +#[derive(Debug)] +pub enum Error { + /// The input data was not recognized as a MSF (PDB) file. + UnrecognizedFileFormat, + + /// The MSF header specifies an invalid page size. + InvalidPageSize(u32), + + /// MSF referred to page number out of range. + /// + /// This likely indicates file corruption. + PageReferenceOutOfRange(u32), + + /// The requested stream is not stored in this file. + StreamNotFound(u32), + + /// A stream requested by name was not found. + StreamNameNotFound, + + /// Invalid length or alignment of a stream. + InvalidStreamLength(&'static str), + + /// An IO error occurred while reading from the data source. + IoError(io::Error), + + /// Unexpectedly reached end of input. + UnexpectedEof, + + /// This data might be understandable, but the code needed to understand it hasn't been written. + UnimplementedFeature(&'static str), + + /// The global shared symbol table is missing. + GlobalSymbolsNotFound, + + /// A symbol record's length value was impossibly small. + SymbolTooShort, + + /// Support for symbols of this kind is not implemented. + UnimplementedSymbolKind(u16), + + /// The type information header was invalid. + InvalidTypeInformationHeader(&'static str), + + /// A type record's length value was impossibly small. + TypeTooShort, + + /// Type or Id not found. + TypeNotFound(u32), + + /// Type or Id not indexed -- the requested type (`.0`) is larger than the maximum index covered + /// by the `ItemFinder` (`.1`). + TypeNotIndexed(u32, u32), + + /// Support for types of this kind is not implemented. + UnimplementedTypeKind(u16), + + /// A type record recursed more deeply than the parser allows. + TypeRecordRecursionLimit(&'static str, usize), + + /// Type index is not a cross module reference. + NotACrossModuleRef(u32), + + /// Cross module reference not found in imports. + CrossModuleRefNotFound(u32), + + /// Variable-length numeric parsing encountered an unexpected prefix. + UnexpectedNumericPrefix(u16), + + /// Required mapping for virtual addresses (OMAP) was not found. + AddressMapNotFound, + + /// A parse error from scroll. + ScrollError(scroll::Error), + + /// This debug subsection kind is unknown or unimplemented. + UnimplementedDebugSubsection(u32), + + /// This source file checksum kind is unknown or unimplemented. + UnimplementedFileChecksumKind(u8), + + /// There is no source file checksum at the given offset. + InvalidFileChecksumOffset(u32), + + /// The lines table is missing. + LinesNotFound, + + /// A binary annotation was compressed incorrectly. + InvalidCompressedAnnotation, + + /// An unknown binary annotation was encountered. + UnknownBinaryAnnotation(u32), + + /// An unknown register index was encountered. + UnknownRegister(u16), +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::IoError(error) => Some(error), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> ::std::result::Result<(), fmt::Error> { + match self { + Self::PageReferenceOutOfRange(p) => { + write!(f, "MSF referred to page number ({}) out of range", p) + } + Self::InvalidPageSize(n) => write!( + f, + "The MSF header specifies an invalid page size ({} bytes)", + n + ), + Self::StreamNotFound(s) => { + write!(f, "The requested stream ({}) is not stored in this file", s) + } + Self::InvalidStreamLength(s) => write!( + f, + "{} stream has an invalid length or alignment for its records", + s + ), + Self::IoError(ref e) => write!(f, "IO error while reading PDB: {}", e), + Self::UnimplementedFeature(feature) => { + write!(f, "Unimplemented PDB feature: {}", feature) + } + Self::UnimplementedSymbolKind(kind) => write!( + f, + "Support for symbols of kind {:#06x} is not implemented", + kind + ), + Self::InvalidTypeInformationHeader(reason) => { + write!(f, "The type information header was invalid: {}", reason) + } + Self::TypeNotFound(type_index) => write!(f, "Type {} not found", type_index), + Self::TypeNotIndexed(type_index, indexed_count) => write!( + f, + "Type {} not indexed (index covers {})", + type_index, indexed_count + ), + Self::UnimplementedTypeKind(kind) => write!( + f, + "Support for types of kind {:#06x} is not implemented", + kind + ), + Self::TypeRecordRecursionLimit(kind, limit) => write!( + f, + "Type record nesting exceeded the parser limit while parsing {} ({})", + kind, limit + ), + Self::NotACrossModuleRef(index) => { + write!(f, "Type {:#06x} is not a cross module reference", index) + } + Self::CrossModuleRefNotFound(index) => write!( + f, + "Cross module reference {:#06x} not found in imports", + index + ), + Self::UnexpectedNumericPrefix(prefix) => write!( + f, + "Variable-length numeric parsing encountered an unexpected prefix ({:#06x}", + prefix + ), + Self::UnimplementedDebugSubsection(kind) => write!( + f, + "Debug module subsection of kind {:#06x} is not implemented", + kind + ), + Self::UnimplementedFileChecksumKind(kind) => { + write!(f, "Unknown source file checksum kind {}", kind) + } + Self::InvalidFileChecksumOffset(offset) => { + write!(f, "Invalid source file checksum offset {:#x}", offset) + } + Self::UnknownBinaryAnnotation(num) => write!(f, "Unknown binary annotation {}", num), + _ => fmt::Debug::fmt(self, f), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Self { + Self::IoError(e) + } +} + +impl From for Error { + fn from(e: scroll::Error) -> Self { + match e { + // Convert a couple of scroll errors into EOF. + scroll::Error::BadOffset(_) | scroll::Error::TooBig { .. } => Self::UnexpectedEof, + _ => Self::ScrollError(e), + } + } +} + +/// The result type returned by this crate. +pub type Result = result::Result; + +/// Implements `Pread` using the inner type. +macro_rules! impl_pread { + ($type:ty) => { + impl<'a> TryFromCtx<'a, Endian> for $type { + type Error = scroll::Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> scroll::Result<(Self, usize)> { + TryFromCtx::try_from_ctx(this, le).map(|(i, s)| (Self(i), s)) + } + } + }; +} + +/// Displays the type as hexadecimal number. Debug prints the type name around. +macro_rules! impl_hex_fmt { + ($type:ty) => { + impl fmt::Display for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#x}", self.0) + } + } + + impl fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, concat!(stringify!($type), "({})"), self) + } + } + }; +} + +/// Implements bidirectional conversion traits for the newtype. +macro_rules! impl_convert { + ($type:ty, $inner:ty) => { + impl From<$inner> for $type { + fn from(offset: $inner) -> Self { + Self(offset) + } + } + + impl From<$type> for $inner { + fn from(string_ref: $type) -> Self { + string_ref.0 + } + } + }; +} + +/// Declares that the given value represents `None`. +/// +/// - `Type::none` and `Default::default` return the none value. +/// - `Type::is_some` and `Type::is_none` check for the none value. +macro_rules! impl_opt { + ($type:ty, $none:literal) => { + impl $type { + /// Returns an index that points to no value. + #[inline] + pub const fn none() -> Self { + Self($none) + } + + /// Returns `true` if the index points to a valid value. + #[inline] + #[must_use] + pub fn is_some(self) -> bool { + self.0 != $none + } + + /// Returns `true` if the index indicates the absence of a value. + #[inline] + #[must_use] + pub fn is_none(self) -> bool { + self.0 == $none + } + } + + impl Default for $type { + #[inline] + fn default() -> Self { + Self::none() + } + } + }; +} + +/// Implements common functionality for virtual addresses. +macro_rules! impl_va { + ($type:ty) => { + impl $type { + /// Checked addition of an offset. Returns `None` if overflow occurred. + pub fn checked_add(self, offset: u32) -> Option { + Some(Self(self.0.checked_add(offset)?)) + } + + /// Checked computation of an offset between two addresses. Returns `None` if `other` is + /// larger. + pub fn checked_sub(self, other: Self) -> Option { + self.0.checked_sub(other.0) + } + + /// Saturating addition of an offset, clipped at the numeric bounds. + pub fn saturating_add(self, offset: u32) -> Self { + Self(self.0.saturating_add(offset)) + } + + /// Saturating computation of an offset between two addresses, clipped at zero. + pub fn saturating_sub(self, other: Self) -> u32 { + self.0.saturating_sub(other.0) + } + + /// Wrapping (modular) addition of an offset. + pub fn wrapping_add(self, offset: u32) -> Self { + Self(self.0.wrapping_add(offset)) + } + + /// Wrapping (modular) computation of an offset between two addresses. + pub fn wrapping_sub(self, other: Self) -> u32 { + self.0.wrapping_sub(other.0) + } + } + + impl Add for $type { + type Output = Self; + + /// Adds the given offset to this address. + #[inline] + fn add(mut self, offset: u32) -> Self { + self.0 += offset; + self + } + } + + impl AddAssign for $type { + /// Adds the given offset to this address. + #[inline] + fn add_assign(&mut self, offset: u32) { + self.0 += offset; + } + } + + impl Sub for $type { + type Output = u32; + + fn sub(self, other: Self) -> Self::Output { + self.0 - other.0 + } + } + + impl_convert!($type, u32); + impl_hex_fmt!($type); + }; +} + +/// A Relative Virtual Address as it appears in a PE file. +/// +/// RVAs are always relative to the image base address, as it is loaded into process memory. This +/// address is reported by debuggers in stack traces and may refer to symbols or instruction +/// pointers. +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Rva(pub u32); + +impl_va!(Rva); + +/// A Relative Virtual Address in an unoptimized PE file. +/// +/// An internal RVA points into the PDB internal address space and may not correspond to RVAs of the +/// executable. It can be converted into an actual [`Rva`] suitable for debugging purposes using +/// [`to_rva`](Self::to_rva). +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct PdbInternalRva(pub u32); + +impl_va!(PdbInternalRva); +impl_pread!(PdbInternalRva); + +/// Implements common functionality for section offsets. +macro_rules! impl_section_offset { + ($type:ty) => { + impl $type { + /// Creates a new section offset. + pub fn new(section: u16, offset: u32) -> Self { + Self { offset, section } + } + + /// Returns whether this section offset points to a valid section or into the void. + pub fn is_valid(self) -> bool { + self.section != 0 + } + + /// Checked addition of an offset. Returns `None` if overflow occurred. + /// + /// This does not check whether the offset is still valid within the given section. If + /// the offset is out of bounds, the conversion to `Rva` will return `None`. + pub fn checked_add(mut self, offset: u32) -> Option { + self.offset = self.offset.checked_add(offset)?; + Some(self) + } + + /// Saturating addition of an offset, clipped at the numeric bounds. + /// + /// This does not check whether the offset is still valid within the given section. If + /// the offset is out of bounds, the conversion to `Rva` will return `None`. + pub fn saturating_add(mut self, offset: u32) -> Self { + self.offset = self.offset.saturating_add(offset); + self + } + + /// Wrapping (modular) addition of an offset. + /// + /// This does not check whether the offset is still valid within the given section. If + /// the offset is out of bounds, the conversion to `Rva` will return `None`. + pub fn wrapping_add(mut self, offset: u32) -> Self { + self.offset = self.offset.wrapping_add(offset); + self + } + } + + impl Add for $type { + type Output = Self; + + /// Adds the given offset to this section offset. + /// + /// This does not check whether the offset is still valid within the given section. If + /// the offset is out of bounds, the conversion to `Rva` will return `None`. + #[inline] + fn add(mut self, offset: u32) -> Self { + self.offset += offset; + self + } + } + + impl AddAssign for $type { + /// Adds the given offset to this section offset. + /// + /// This does not check whether the offset is still valid within the given section. If + /// the offset is out of bounds, the conversion to `Rva` will return `None`. + #[inline] + fn add_assign(&mut self, offset: u32) { + self.offset += offset; + } + } + + impl PartialOrd for $type { + /// Compares offsets if they reside in the same section. + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + if self.section == other.section { + Some(self.offset.cmp(&other.offset)) + } else { + None + } + } + } + + impl fmt::Debug for $type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($type)) + .field("section", &format_args!("{:#x}", self.section)) + .field("offset", &format_args!("{:#x}", self.offset)) + .finish() + } + } + }; +} + +/// An offset relative to a PE section. +/// +/// This offset can be converted to an `Rva` to receive the address relative to the entire image. +/// Note that this offset applies to the actual PE headers. The PDB debug information actually +/// stores [`PdbInternalSectionOffset`]s. +#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)] +pub struct SectionOffset { + /// The memory offset relative from the start of the section's memory. + pub offset: u32, + + /// The index of the section in the PE's section headers list, incremented by `1`. A value of + /// `0` indicates an invalid or missing reference. + pub section: u16, +} + +impl_section_offset!(SectionOffset); + +/// An offset relative to a PE section in the original unoptimized binary. +/// +/// For optimized Microsoft binaries, this offset points to a virtual address space before the +/// rearrangement of sections has been performed. This kind of offset is usually stored in PDB debug +/// information. It can be converted to an RVA in the transformed address space of the optimized +/// binary using [`to_rva`](PdbInternalSectionOffset::to_rva). Likewise, there is a conversion to [`SectionOffset`] in the actual address +/// space. +/// +/// For binaries and their PDBs that have not been optimized, both address spaces are equal and the +/// offsets are interchangeable. The conversion operations are cheap no-ops in this case. +#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)] +pub struct PdbInternalSectionOffset { + /// The memory offset relative from the start of the section's memory. + pub offset: u32, + + /// The index of the section in the PDB's section headers list, incremented by `1`. A value of + /// `0` indicates an invalid or missing reference. + pub section: u16, +} + +impl<'t> TryFromCtx<'t, Endian> for PdbInternalSectionOffset { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + offset: this.gread_with(&mut offset, le)?, + section: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl_section_offset!(PdbInternalSectionOffset); + +/// Index of a PDB stream. +/// +/// This index can either refer to a stream, or indicate the absence of a stream. Check +/// [`is_none`](Self::is_none) to see whether a stream should exist. +/// +/// Use [`get`](Self::get) to load data for this stream. +#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct StreamIndex(pub u16); + +impl StreamIndex { + /// Returns the MSF stream number, if this stream is not a NULL stream. + #[inline] + pub(crate) fn msf_number(self) -> Option { + match self.0 { + 0xffff => None, + index => Some(u32::from(index)), + } + } +} + +impl fmt::Display for StreamIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.msf_number() { + Some(number) => write!(f, "{}", number), + None => write!(f, "None"), + } + } +} + +impl fmt::Debug for StreamIndex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "StreamIndex({})", self) + } +} + +impl_opt!(StreamIndex, 0xffff); +impl_pread!(StreamIndex); + +/// An index into either the [`TypeInformation`](crate::TypeInformation) or +/// [`IdInformation`](crate::IdInformation) stream. +pub trait ItemIndex: + Copy + Default + fmt::Debug + fmt::Display + PartialEq + PartialOrd + From + Into +{ + /// Returns `true` if this is a cross module reference. + /// + /// When compiling with LTO, the compiler may reference types and ids across modules. In such + /// cases, a lookup in the global streams will not succeed. Instead, the import must be resolved + /// using cross module references: + /// + /// 1. Look up the index in [`CrossModuleImports`](crate::CrossModuleImports) of the current + /// module. + /// 2. Use [`StringTable`](crate::StringTable) to resolve the name of the referenced module. + /// 3. Find the [`Module`](crate::Module) with the same module name and load its + /// [`ModuleInfo`](crate::ModuleInfo). Note that this comparison needs to be done + /// case-insensitively as the name in the DBI stream and name table are known to not + /// have matching cases. + /// 4. Resolve the [`Local`](crate::Local) index into a global one using + /// [`CrossModuleExports`](crate::CrossModuleExports). + /// + /// Cross module references are specially formatted indexes with the most significant bit set to + /// `1`. The remaining bits are divided into a module and index offset into the + /// [`CrossModuleImports`](crate::CrossModuleImports) section. + fn is_cross_module(self) -> bool { + (self.into() & 0x8000_0000) != 0 + } +} + +/// Index of [`TypeData`](crate::TypeData) in the [`TypeInformation`](crate::TypeInformation) stream. +/// +/// If this index is a [cross module reference](ItemIndex::is_cross_module), it must be resolved +/// before lookup in the stream. +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct TypeIndex(pub u32); + +impl_convert!(TypeIndex, u32); +impl_hex_fmt!(TypeIndex); +impl_pread!(TypeIndex); + +impl ItemIndex for TypeIndex {} + +/// Index of an [`Id`](crate::Id) in [`IdInformation`](crate::IdInformation) stream. +/// +/// If this index is a [cross module reference](ItemIndex::is_cross_module), it must be resolved +/// before lookup in the stream. +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct IdIndex(pub u32); + +impl_convert!(IdIndex, u32); +impl_hex_fmt!(IdIndex); +impl_pread!(IdIndex); + +impl ItemIndex for IdIndex {} + +/// An [`ItemIndex`] that is local to a module. +/// +/// This index is usually part of a [`CrossModuleRef`](crate::CrossModuleRef). It cannot be used to +/// query the [`TypeInformation`](crate::TypeInformation) or [`IdInformation`](crate::IdInformation) +/// streams directly. Instead, it must be looked up in the +/// [`CrossModuleImports`](crate::CrossModuleImports) of the module it belongs to in order to obtain +/// the global index. +/// +/// See [`ItemIndex::is_cross_module`] for more information. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Local(pub I); + +impl fmt::Display for Local +where + I: ItemIndex + fmt::Display, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } +} + +/// A reference to a string in the string table. +/// +/// This type stores an offset into the global string table of the PDB. To retrieve the string +/// value, use [`to_raw_string`](Self::to_raw_string), [`to_string_lossy`](Self::to_string_lossy) or +/// methods on [`StringTable`](crate::StringTable). +#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct StringRef(pub u32); + +impl_convert!(StringRef, u32); +impl_hex_fmt!(StringRef); +impl_pread!(StringRef); + +/// Index of a file entry in the module. +/// +/// Use the [`LineProgram`](crate::LineProgram) to resolve information on the file from this offset. +#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct FileIndex(pub u32); + +impl_convert!(FileIndex, u32); +impl_hex_fmt!(FileIndex); +impl_pread!(FileIndex); + +/// A reference into the symbol table of a module. +/// +/// To retrieve the symbol referenced by this index, use +/// [`ModuleInfo::symbols_at`](crate::ModuleInfo::symbols_at). When iterating, use +/// [`SymbolIter::seek`](crate::SymbolIter::seek) to jump between symbols. +#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct SymbolIndex(pub u32); + +impl_convert!(SymbolIndex, u32); +impl_hex_fmt!(SymbolIndex); +impl_pread!(SymbolIndex); + +/// A register referred to by its number. +#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct Register(pub u16); + +impl_convert!(Register, u16); +impl_pread!(Register); + +/// Provides little-endian access to a &[u8]. +#[derive(Debug, Default, Clone)] +pub(crate) struct ParseBuffer<'b>(&'b [u8], usize); + +macro_rules! def_parse { + ( $( ($n:ident, $t:ty) ),* $(,)* ) => { + $(#[doc(hidden)] + #[inline] + #[allow(unused)] + pub fn $n(&mut self) -> Result<$t> { + self.parse() + })* + } +} + +macro_rules! def_peek { + ( $( ($n:ident, $t:ty) ),* $(,)* ) => { + $(#[doc(hidden)] + #[inline] + pub fn $n(&mut self) -> Result<$t> { + Ok(self.0.pread_with(self.1, LE)?) + })* + } +} + +impl<'b> ParseBuffer<'b> { + /// Return the remaining length of the buffer. + #[inline] + pub fn len(&self) -> usize { + self.0.len() - self.1 + } + + /// Determines whether this ParseBuffer has been consumed. + #[inline] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Return the position within the parent slice. + #[inline] + pub fn pos(&self) -> usize { + self.1 + } + + /// Seek to the given absolute position. + #[inline] + pub fn seek(&mut self, pos: usize) { + self.1 = std::cmp::min(pos, self.0.len()); + } + + /// Truncates the buffer at the given absolute position. + #[inline] + pub fn truncate(&mut self, len: usize) -> Result<()> { + if self.0.len() >= len { + self.0 = &self.0[..len]; + Ok(()) + } else { + Err(Error::UnexpectedEof) + } + } + + /// Align the current position to the next multiple of `alignment` bytes. + #[inline] + pub fn align(&mut self, alignment: usize) -> Result<()> { + let diff = self.1 % alignment; + if diff > 0 { + if self.len() < (alignment - diff) { + return Err(Error::UnexpectedEof); + } + self.1 += alignment - diff; + } + Ok(()) + } + + /// Parse an object that implements `Pread`. + pub fn parse(&mut self) -> Result + where + T: TryFromCtx<'b, Endian, [u8]>, + T::Error: From, + Error: From, + { + Ok(self.0.gread_with(&mut self.1, LE)?) + } + + /// Parse an object that implements `Pread` with the given context. + pub fn parse_with(&mut self, ctx: C) -> Result + where + T: TryFromCtx<'b, C, [u8]>, + T::Error: From, + Error: From, + C: Copy, + { + Ok(self.0.gread_with(&mut self.1, ctx)?) + } + + def_parse!( + (parse_u8, u8), + (parse_u16, u16), + (parse_i16, i16), + (parse_u32, u32), + (parse_i32, i32), + (parse_u64, u64), + (parse_i64, i64), + ); + + def_peek!((peek_u8, u8), (peek_u16, u16),); + + /// Parse a NUL-terminated string from the input. + #[inline] + pub fn parse_cstring(&mut self) -> Result> { + let input = &self.0[self.1..]; + let null_idx = input.iter().position(|ch| *ch == 0); + + if let Some(idx) = null_idx { + self.1 += idx + 1; + Ok(RawString::from(&input[..idx])) + } else { + Err(Error::UnexpectedEof) + } + } + + /// Parse a u8-length-prefixed string from the input. + #[inline] + pub fn parse_u8_pascal_string(&mut self) -> Result> { + let length = self.parse_u8()? as usize; + Ok(RawString::from(self.take(length)?)) + } + + /// Take n bytes from the input + #[inline] + pub fn take(&mut self, n: usize) -> Result<&'b [u8]> { + let input = &self.0[self.1..]; + if input.len() >= n { + self.1 += n; + Ok(&input[..n]) + } else { + Err(Error::UnexpectedEof) + } + } +} + +impl<'b> From<&'b [u8]> for ParseBuffer<'b> { + fn from(buf: &'b [u8]) -> Self { + ParseBuffer(buf, 0) + } +} + +impl<'b> fmt::LowerHex for ParseBuffer<'b> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> { + write!(f, "ParseBuf::from(\"")?; + for byte in self.0 { + write!(f, "\\x{:02x}", byte)?; + } + write!(f, "\").as_bytes() at offset {}", self.1) + } +} + +/// Value of an enumerate type. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[allow(missing_docs)] +pub enum Variant { + U8(u8), + U16(u16), + U32(u32), + U64(u64), + I8(i8), + I16(i16), + I32(i32), + I64(i64), +} + +impl fmt::Display for Variant { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::U8(value) => write!(f, "{}", value), + Self::U16(value) => write!(f, "{}", value), + Self::U32(value) => write!(f, "{}", value), + Self::U64(value) => write!(f, "{}", value), + Self::I8(value) => write!(f, "{}", value), + Self::I16(value) => write!(f, "{}", value), + Self::I32(value) => write!(f, "{}", value), + Self::I64(value) => write!(f, "{}", value), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for Variant { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let mut offset = 0; + + let variant = match this.gread_with(&mut offset, le)? { + value if value < constants::LF_NUMERIC => Self::U16(value), + constants::LF_CHAR => Self::I8(this.gread_with(&mut offset, le)?), + constants::LF_SHORT => Self::I16(this.gread_with(&mut offset, le)?), + constants::LF_LONG => Self::I32(this.gread_with(&mut offset, le)?), + constants::LF_QUADWORD => Self::I64(this.gread_with(&mut offset, le)?), + constants::LF_USHORT => Self::U16(this.gread_with(&mut offset, le)?), + constants::LF_ULONG => Self::U32(this.gread_with(&mut offset, le)?), + constants::LF_UQUADWORD => Self::U64(this.gread_with(&mut offset, le)?), + _ if cfg!(debug_assertions) => unreachable!(), + other => return Err(Error::UnexpectedNumericPrefix(other)), + }; + + Ok((variant, offset)) + } +} + +/// `RawString` refers to a `&[u8]` that physically resides somewhere inside a PDB data structure. +/// +/// A `RawString` may not be valid UTF-8. +#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct RawString<'b>(&'b [u8]); + +impl fmt::Debug for RawString<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "RawString({:?})", self.to_string()) + } +} + +impl fmt::Display for RawString<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.to_string()) + } +} + +impl<'b> RawString<'b> { + /// Return the raw bytes of this string, as found in the PDB file. + #[inline] + pub fn as_bytes(&self) -> &'b [u8] { + self.0 + } + + /// Return the length of this string in bytes. + #[inline] + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns a boolean indicating if this string is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.0.len() == 0 + } + + /// Returns a UTF-8 `String`, substituting in replacement characters as needed. + /// + /// This uses [`String::from_utf8_lossy`] and thus avoids copying in cases where the original + /// string was valid UTF-8. This is the expected case for strings that appear in PDB files, + /// since they are almost always composed of printable 7-bit ASCII characters. + #[inline] + pub fn to_string(&self) -> Cow<'b, str> { + String::from_utf8_lossy(self.0) + } +} + +impl<'b> From> for &'b [u8] { + fn from(str: RawString<'b>) -> Self { + str.as_bytes() + } +} + +impl<'b> From<&'b str> for RawString<'b> { + fn from(buf: &'b str) -> Self { + RawString(buf.as_bytes()) + } +} + +impl<'b> From<&'b [u8]> for RawString<'b> { + fn from(buf: &'b [u8]) -> Self { + RawString(buf) + } +} + +/// Cast a binary slice to a slice of types. +/// +/// This function performs a cast of a binary slice to a slice of some type, returning `Some` if the +/// following two conditions are met: +/// +/// 1. The size of the slize must be a multiple of the type's size. +/// 2. The slice must be aligned to the alignment of the type. +/// +/// Note that this function will not convert any endianness. The types must be capable of reading +/// endianness correclty in case data from other hosts is read. +pub(crate) fn cast_aligned(data: &[u8]) -> Option<&[T]> { + let alignment = mem::align_of::(); + let size = mem::size_of::(); + + let ptr = data.as_ptr(); + let bytes = data.len(); + + match (bytes % size, ptr.align_offset(alignment)) { + (0, 0) => Some(unsafe { slice::from_raw_parts(ptr as *const T, bytes / size) }), + (_, _) => None, + } +} + +#[cfg(test)] +mod tests { + mod parse_buffer { + use crate::common::*; + + #[test] + fn test_parse_u8() { + let vec: Vec = vec![1, 2, 3, 4]; + let mut buf = ParseBuffer::from(vec.as_slice()); + assert_eq!(buf.pos(), 0); + + assert_eq!(buf.peek_u8().expect("peek"), 1); + assert_eq!(buf.peek_u8().expect("peek"), 1); + assert_eq!(buf.peek_u8().expect("peek"), 1); + let val = buf.parse_u8().unwrap(); + assert_eq!(buf.len(), 3); + assert_eq!(buf.pos(), 1); + assert_eq!(val, 1); + + assert_eq!(buf.peek_u8().expect("peek"), 2); + let val = buf.parse_u8().unwrap(); + assert_eq!(buf.len(), 2); + assert_eq!(buf.pos(), 2); + assert_eq!(val, 2); + + assert_eq!(buf.peek_u8().expect("peek"), 3); + let val = buf.parse_u8().unwrap(); + assert_eq!(buf.len(), 1); + assert_eq!(buf.pos(), 3); + assert_eq!(val, 3); + + assert_eq!(buf.peek_u8().expect("peek"), 4); + let val = buf.parse_u8().unwrap(); + assert_eq!(buf.len(), 0); + assert_eq!(buf.pos(), 4); + assert_eq!(val, 4); + + match buf.parse_u8() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_u16() { + let vec: Vec = vec![1, 2, 3]; + let mut buf = ParseBuffer::from(vec.as_slice()); + + assert_eq!(buf.peek_u16().expect("peek"), 0x0201); + assert_eq!(buf.peek_u16().expect("peek"), 0x0201); + + let val = buf.parse_u16().unwrap(); + assert_eq!(buf.len(), 1); + assert_eq!(buf.pos(), 2); + assert_eq!(val, 0x0201); + + match buf.parse_u16() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + match buf.parse_u16() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_u32() { + let vec: Vec = vec![1, 2, 3, 4, 5, 6, 7]; + let mut buf = ParseBuffer::from(vec.as_slice()); + + let val = buf.parse_u32().unwrap(); + assert_eq!(buf.len(), 3); + assert_eq!(buf.pos(), 4); + assert_eq!(val, 0x0403_0201); + + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + assert_eq!(buf.pos(), 5); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + assert_eq!(buf.pos(), 6); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + assert_eq!(buf.pos(), 7); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_u64() { + let vec: Vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; + let mut buf = ParseBuffer::from(vec.as_slice()); + + let val = buf.parse_u64().unwrap(); + assert_eq!(val, 0x0807_0605_0403_0201); + + match buf.parse_u64() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_i32() { + let vec: Vec = vec![254, 255, 255, 255, 5, 6, 7]; + let mut buf = ParseBuffer::from(vec.as_slice()); + + let val = buf.parse_i32().unwrap(); + assert_eq!(buf.len(), 3); + assert_eq!(val, -2); + assert_eq!(buf.pos(), 4); + + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + + buf.take(1).unwrap(); + match buf.parse_u32() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_cstring() { + let mut buf = ParseBuffer::from(&b"hello\x00world\x00\x00\x01"[..]); + + let val = buf.parse_cstring().unwrap(); + assert_eq!(buf.len(), 8); + assert_eq!(buf.pos(), 6); + assert_eq!(val, RawString::from(&b"hello"[..])); + + let val = buf.parse_cstring().unwrap(); + assert_eq!(buf.len(), 2); + assert_eq!(buf.pos(), 12); + assert_eq!(val, RawString::from(&b"world"[..])); + + let val = buf.parse_cstring().unwrap(); + assert_eq!(buf.len(), 1); + assert_eq!(buf.pos(), 13); + assert_eq!(val, RawString::from(&b""[..])); + + match buf.parse_cstring() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_u8_pascal_string() { + let mut buf = ParseBuffer::from(&b"\x05hello\x05world\x00\x01"[..]); + + let val = buf.parse_u8_pascal_string().unwrap(); + assert_eq!(buf.len(), 8); + assert_eq!(buf.pos(), 6); + assert_eq!(val, RawString::from(&b"hello"[..])); + + let val = buf.parse_u8_pascal_string().unwrap(); + assert_eq!(buf.len(), 2); + assert_eq!(buf.pos(), 12); + assert_eq!(val, RawString::from(&b"world"[..])); + + let val = buf.parse_u8_pascal_string().unwrap(); + assert_eq!(buf.len(), 1); + assert_eq!(buf.pos(), 13); + assert_eq!(val, RawString::from(&b""[..])); + + match buf.parse_u8_pascal_string() { + Err(Error::UnexpectedEof) => (), + _ => panic!("expected EOF"), + } + } + + #[test] + fn test_parse_buffer_align() { + let mut buf = ParseBuffer::from(&b"1234"[..]); + buf.take(1).unwrap(); + assert!(buf.align(4).is_ok()); + assert_eq!(buf.pos(), 4); + assert_eq!(buf.len(), 0); + + let mut buf = ParseBuffer::from(&b"1234"[..]); + buf.take(3).unwrap(); + assert!(buf.align(4).is_ok()); + assert_eq!(buf.pos(), 4); + assert_eq!(buf.len(), 0); + + let mut buf = ParseBuffer::from(&b"12345"[..]); + buf.take(3).unwrap(); + assert!(buf.align(4).is_ok()); + assert_eq!(buf.pos(), 4); + assert_eq!(buf.len(), 1); + + let mut buf = ParseBuffer::from(&b"123"[..]); + buf.take(3).unwrap(); + assert!(buf.align(4).is_err()); + } + + #[test] + fn test_seek() { + let mut buf = ParseBuffer::from(&b"hello"[..]); + buf.seek(5); + assert_eq!(buf.pos(), 5); + buf.seek(2); + assert_eq!(buf.pos(), 2); + buf.seek(10); + assert_eq!(buf.pos(), 5); + } + } + + mod newtypes { + use crate::common::*; + + // These tests use SymbolIndex as a proxy for all other types. + + #[test] + fn test_format_newtype() { + let val = SymbolIndex(0x42); + assert_eq!(format!("{}", val), "0x42"); + } + + #[test] + fn test_debug_newtype() { + let val = SymbolIndex(0x42); + assert_eq!(format!("{:?}", val), "SymbolIndex(0x42)"); + } + + #[test] + fn test_pread() { + let mut buf = ParseBuffer::from(&[0x42, 0, 0, 0][..]); + let val = buf.parse::().expect("parse"); + assert_eq!(val, SymbolIndex(0x42)); + assert!(buf.is_empty()); + } + } + + mod cast_aligned { + use crate::common::cast_aligned; + use std::slice; + + #[test] + fn test_cast_aligned() { + let data: &[u32] = &[1, 2, 3]; + + let ptr = data.as_ptr() as *const u8; + let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 12) }; + + assert_eq!(cast_aligned(bin), Some(data)); + } + + #[test] + fn test_cast_empty() { + let data: &[u32] = &[]; + + let ptr = data.as_ptr() as *const u8; + let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 0) }; + + assert_eq!(cast_aligned(bin), Some(data)); + } + + #[test] + fn test_cast_unaligned() { + let data: &[u32] = &[1, 2, 3]; + + let ptr = data.as_ptr() as *const u8; + let bin: &[u8] = unsafe { slice::from_raw_parts(ptr.offset(2), 8) }; + + assert_eq!(cast_aligned::(bin), None); + } + + #[test] + fn test_cast_wrong_size() { + let data: &[u32] = &[1, 2, 3]; + + let ptr = data.as_ptr() as *const u8; + let bin: &[u8] = unsafe { slice::from_raw_parts(ptr, 11) }; + + assert_eq!(cast_aligned::(bin), None); + } + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/dbi.rs b/plugins/pdb-ng/vendor/pdb-rs/src/dbi.rs new file mode 100644 index 0000000000..ce21c70760 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/dbi.rs @@ -0,0 +1,692 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +// DBI = "Debug Information" + +use std::borrow::Cow; +use std::fmt; +use std::result; + +use crate::common::*; +use crate::msf::*; +use crate::{FallibleIterator, SectionCharacteristics}; + +/// Provides access to the "DBI" stream inside the PDB. +/// +/// This is only minimally implemented; it's really just so `PDB` can find the global symbol table. +/// +/// # Example +/// +/// ``` +/// # use pdb::FallibleIterator; +/// # +/// # fn test() -> pdb::Result { +/// let file = std::fs::File::open("fixtures/self/foo.pdb")?; +/// let mut pdb = pdb::PDB::open(file)?; +/// +/// let dbi = pdb.debug_information()?; + +/// +/// # let mut count: usize = 0; +/// let mut modules = dbi.modules()?; +/// while let Some(module) = modules.next()? { +/// println!("module name: {}, object file name: {}", +/// module.module_name(), module.object_file_name()); +/// # count += 1; +/// } +/// +/// # Ok(count) +/// # } +/// # assert!(test().expect("test") == 194); +#[derive(Debug)] +pub struct DebugInformation<'s> { + stream: Stream<'s>, + header: DBIHeader, + header_len: usize, +} + +impl<'s> DebugInformation<'s> { + pub(crate) fn parse(stream: Stream<'s>) -> Result { + let mut buf = stream.parse_buffer(); + let header = DBIHeader::parse_buf(&mut buf)?; + let header_len = buf.pos(); + + Ok(DebugInformation { + stream, + header, + header_len, + }) + } + + pub(crate) fn header(&self) -> DBIHeader { + self.header + } + + /// Returns the target's machine type (architecture). + pub fn machine_type(&self) -> Result { + Ok(self.header.machine_type.into()) + } + + /// Returns this PDB's original `age`. + /// + /// This number is written by the linker and should be equal to the image's `age` value. In + /// contrast, [`PDBInformation::age`] may be bumped by other tools and should be greater or + /// equal to the image's `age` value. + /// + /// Old PDB files may not specify an age, in which case only [`PDBInformation::age`] should be + /// checked for matching the image. + /// + /// [`PDBInformation::age`]: crate::PDBInformation::age + pub fn age(&self) -> Option { + match self.header.age { + 0 => None, + age => Some(age), + } + } + + /// Returns an iterator that can traverse the modules list in sequential order. + pub fn modules(&self) -> Result> { + let mut buf = self.stream.parse_buffer(); + // drop the header + buf.take(self.header_len)?; + let modules_buf = buf.take(self.header.module_list_size as usize)?; + Ok(ModuleIter { + buf: modules_buf.into(), + }) + } + + /// Returns an iterator that can traverse the section contributions list in sequential order. + pub fn section_contributions(&self) -> Result> { + let mut buf = self.stream.parse_buffer(); + // drop the header and modules list + buf.take(self.header_len + self.header.module_list_size as usize)?; + let contributions_buf = buf.take(self.header.section_contribution_size as usize)?; + DBISectionContributionIter::parse(contributions_buf.into()) + } +} + +/// The version of the PDB format. +/// +/// This version type is used in multiple locations: the DBI header, and the PDBI header. +#[non_exhaustive] +#[derive(Debug, Copy, Clone)] +#[allow(missing_docs)] +pub enum HeaderVersion { + V41, + V50, + V60, + V70, + V110, + OtherValue(u32), +} + +impl From for HeaderVersion { + #[allow(clippy::inconsistent_digit_grouping)] + fn from(v: u32) -> Self { + match v { + 93_08_03 => Self::V41, + 1996_03_07 => Self::V50, + 1997_06_06 => Self::V60, + 1999_09_03 => Self::V70, + 2009_12_01 => Self::V110, + _ => Self::OtherValue(v), + } + } +} + +/// A DBI header -- `NewDBIHdr`, really -- parsed from a stream. +/// +/// Reference: +/// +#[derive(Debug, Copy, Clone)] +#[allow(dead_code)] // reason = "unused fields added for completeness" +pub(crate) struct DBIHeader { + pub signature: u32, + pub version: HeaderVersion, + pub age: u32, + pub gs_symbols_stream: StreamIndex, + + /* + https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/dbi.h#L143-L155: + union { + struct { + USHORT usVerPdbDllMin : 8; // minor version and + USHORT usVerPdbDllMaj : 7; // major version and + USHORT fNewVerFmt : 1; // flag telling us we have rbld stored elsewhere (high bit of original major version) + } vernew; // that built this pdb last. + struct { + USHORT usVerPdbDllRbld: 4; + USHORT usVerPdbDllMin : 7; + USHORT usVerPdbDllMaj : 5; + } verold; + USHORT usVerAll; + }; + */ + pub internal_version: u16, + pub ps_symbols_stream: StreamIndex, + // "build version of the pdb dll that built this pdb last." + pub pdb_dll_build_version: u16, + + pub symbol_records_stream: StreamIndex, + + // "rbld version of the pdb dll that built this pdb last." + pub pdb_dll_rbld_version: u16, + pub module_list_size: u32, + pub section_contribution_size: u32, + pub section_map_size: u32, + pub file_info_size: u32, + + // "size of the Type Server Map substream" + pub type_server_map_size: u32, + + // "index of MFC type server" + pub mfc_type_server_index: u32, + + // "size of optional DbgHdr info appended to the end of the stream" + pub debug_header_size: u32, + + // "number of bytes in EC substream, or 0 if EC no EC enabled Mods" + pub ec_substream_size: u32, + + /* + https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/dbi.h#L187-L192: + USHORT fIncLink:1; // true if linked incrmentally (really just if ilink thunks are present) + USHORT fStripped:1; // true if PDB::CopyTo stripped the private data out + USHORT fCTypes:1; // true if this PDB is using CTypes. + USHORT unused:13; // reserved, must be 0. + */ + pub flags: u16, + + pub machine_type: u16, + pub reserved: u32, +} + +impl DBIHeader { + pub fn parse(stream: Stream<'_>) -> Result { + Self::parse_buf(&mut stream.parse_buffer()) + } + + fn parse_buf(buf: &mut ParseBuffer<'_>) -> Result { + let header = Self { + signature: buf.parse_u32()?, + version: From::from(buf.parse_u32()?), + age: buf.parse_u32()?, + gs_symbols_stream: buf.parse()?, + internal_version: buf.parse_u16()?, + ps_symbols_stream: buf.parse()?, + pdb_dll_build_version: buf.parse_u16()?, + symbol_records_stream: buf.parse()?, + pdb_dll_rbld_version: buf.parse_u16()?, + module_list_size: buf.parse_u32()?, + section_contribution_size: buf.parse_u32()?, + section_map_size: buf.parse_u32()?, + file_info_size: buf.parse_u32()?, + type_server_map_size: buf.parse_u32()?, + mfc_type_server_index: buf.parse_u32()?, + debug_header_size: buf.parse_u32()?, + ec_substream_size: buf.parse_u32()?, + flags: buf.parse_u16()?, + machine_type: buf.parse_u16()?, + reserved: buf.parse_u32()?, + }; + + if header.signature != u32::max_value() { + // this is likely a DBIHdr, not a NewDBIHdr + // it could be promoted: + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/dbi.cpp#L291-L313 + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/langapi/include/pdb.h#L1180-L1184 + // but that seems like a lot of work + return Err(Error::UnimplementedFeature("ancient DBI header")); + } + + Ok(header) + } +} + +/// The target machine's architecture. +/// Reference: +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum MachineType { + /// The contents of this field are assumed to be applicable to any machine type. + Unknown = 0x0, + /// Matsushita AM33 + Am33 = 0x13, + /// x64 + Amd64 = 0x8664, + /// ARM little endian + Arm = 0x1C0, + /// ARM64 little endian + Arm64 = 0xAA64, + /// ARM Thumb-2 little endian + ArmNT = 0x1C4, + /// EFI byte code + Ebc = 0xEBC, + /// Intel 386 or later processors and compatible processors + X86 = 0x14C, + /// Intel Itanium processor family + Ia64 = 0x200, + /// Mitsubishi M32R little endian + M32R = 0x9041, + /// MIPS16 + Mips16 = 0x266, + /// MIPS with FPU + MipsFpu = 0x366, + /// MIPS16 with FPU + MipsFpu16 = 0x466, + /// Power PC little endian + PowerPC = 0x1F0, + /// Power PC with floating point support + PowerPCFP = 0x1F1, + /// MIPS little endian + R4000 = 0x166, + /// RISC-V 32-bit address space + RiscV32 = 0x5032, + /// RISC-V 64-bit address space + RiscV64 = 0x5064, + /// RISC-V 128-bit address space + RiscV128 = 0x5128, + /// Hitachi SH3 + SH3 = 0x1A2, + /// Hitachi SH3 DSP + SH3DSP = 0x1A3, + /// Hitachi SH4 + SH4 = 0x1A6, + /// Hitachi SH5 + SH5 = 0x1A8, + /// Thumb + Thumb = 0x1C2, + /// MIPS little-endian WCE v2 + WceMipsV2 = 0x169, + /// Invalid value + Invalid = 0xffff, +} + +impl fmt::Display for MachineType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Invalid => write!(f, "Invalid"), + Self::Unknown => write!(f, "Unknown"), + Self::Am33 => write!(f, "Am33"), + Self::Amd64 => write!(f, "Amd64"), + Self::Arm => write!(f, "Arm"), + Self::Arm64 => write!(f, "Arm64"), + Self::ArmNT => write!(f, "ArmNT"), + Self::Ebc => write!(f, "Ebc"), + Self::X86 => write!(f, "X86"), + Self::Ia64 => write!(f, "Ia64"), + Self::M32R => write!(f, "M32R"), + Self::Mips16 => write!(f, "Mips16"), + Self::MipsFpu => write!(f, "MipsFpu"), + Self::MipsFpu16 => write!(f, "MipsFpu16"), + Self::PowerPC => write!(f, "PowerPC"), + Self::PowerPCFP => write!(f, "PowerPCFP"), + Self::R4000 => write!(f, "R4000"), + Self::RiscV32 => write!(f, "RiscV32"), + Self::RiscV64 => write!(f, "RiscV64"), + Self::RiscV128 => write!(f, "RiscV128"), + Self::SH3 => write!(f, "SH3"), + Self::SH3DSP => write!(f, "SH3DSP"), + Self::SH4 => write!(f, "SH4"), + Self::SH5 => write!(f, "SH5"), + Self::Thumb => write!(f, "Thumb"), + Self::WceMipsV2 => write!(f, "WceMipsV2"), + } + } +} + +impl From for MachineType { + fn from(value: u16) -> Self { + match value { + 0xffff => Self::Invalid, + 0x0 => Self::Unknown, + 0x13 => Self::Am33, + 0x8664 => Self::Amd64, + 0x1C0 => Self::Arm, + 0xAA64 => Self::Arm64, + 0x1C4 => Self::ArmNT, + 0xEBC => Self::Ebc, + 0x14C => Self::X86, + 0x200 => Self::Ia64, + 0x9041 => Self::M32R, + 0x266 => Self::Mips16, + 0x366 => Self::MipsFpu, + 0x466 => Self::MipsFpu16, + 0x1F0 => Self::PowerPC, + 0x1F1 => Self::PowerPCFP, + 0x166 => Self::R4000, + 0x5032 => Self::RiscV32, + 0x5064 => Self::RiscV64, + 0x5128 => Self::RiscV128, + 0x1A2 => Self::SH3, + 0x1A3 => Self::SH3DSP, + 0x1A6 => Self::SH4, + 0x1A8 => Self::SH5, + 0x1C2 => Self::Thumb, + 0x169 => Self::WceMipsV2, + _ => Self::Unknown, + } + } +} + +/// Information about a module's contribution to a section. +/// `struct SC` in Microsoft's code: +/// +#[derive(Debug, Copy, Clone)] +pub struct DBISectionContribution { + /// Start offset of the section. + pub offset: PdbInternalSectionOffset, + /// The size of the contribution, in bytes. + pub size: u32, + /// The characteristics, which map to [`ImageSectionHeader::characteristics`] in binaries. + /// + /// [`ImageSectionHeader::characteristics`]: crate::ImageSectionHeader::characteristics + pub characteristics: SectionCharacteristics, + /// Index of the module in [`DebugInformation::modules`] containing the actual symbol. + pub module: usize, + /// CRC of the contribution(?) + pub data_crc: u32, + /// CRC of relocations(?) + pub reloc_crc: u32, +} + +impl DBISectionContribution { + fn parse(buf: &mut ParseBuffer<'_>) -> Result { + let section = buf.parse_u16()?; + let _padding = buf.parse_u16()?; + let offset = buf.parse_u32()?; + let size = buf.parse_u32()?; + let characteristics = buf.parse()?; + let module = buf.parse_u16()?.into(); + let _padding = buf.parse_u16()?; + + Ok(Self { + offset: PdbInternalSectionOffset { offset, section }, + size, + characteristics, + module, + data_crc: buf.parse_u32()?, + reloc_crc: buf.parse_u32()?, + }) + } +} + +/// Information about a module parsed from the DBI stream. +/// +/// Named `MODI` in the Microsoft PDB source: +/// +#[derive(Debug, Copy, Clone)] +#[allow(dead_code)] // reason = "unused fields added for completeness" +pub(crate) struct DBIModuleInfo { + /// Currently open module. + pub opened: u32, + /// This module's first section contribution. + pub section: DBISectionContribution, + /// Flags, expressed as bitfields in the C struct: + /// written, EC enabled, unused, tsm + /// + pub flags: u16, + /// Stream number of module debug info (syms, lines, fpo). + pub stream: StreamIndex, + /// Size of local symbols debug info in `stream`. + pub symbols_size: u32, + /// Size of line number debug info in `stream`. + pub lines_size: u32, + /// Size of C13 style line number info in `stream`. + pub c13_lines_size: u32, + /// Number of files contributing to this module. + pub files: u16, + _padding: u16, + /// Used as a pointer into an array of filename indicies in the Microsoft code. + pub filename_offsets: u32, + /// Source file name index. + pub source: u32, + /// Path to compiler PDB name index. + pub compiler: u32, +} + +impl DBIModuleInfo { + fn parse(buf: &mut ParseBuffer<'_>) -> Result { + Ok(Self { + opened: buf.parse_u32()?, + section: DBISectionContribution::parse(buf)?, + flags: buf.parse_u16()?, + stream: buf.parse()?, + symbols_size: buf.parse_u32()?, + lines_size: buf.parse_u32()?, + c13_lines_size: buf.parse_u32()?, + files: buf.parse_u16()?, + _padding: buf.parse_u16()?, + filename_offsets: buf.parse_u32()?, + source: buf.parse_u32()?, + compiler: buf.parse_u32()?, + }) + } +} + +/// Represents a module from the DBI stream. +/// +/// A `Module` is a single item that contributes to the binary, such as an object file or import +/// library. +/// +/// Much of the useful information for a `Module` is stored in a separate stream in the PDB. It can +/// be retrieved by calling [`PDB::module_info`](crate::PDB::module_info) with a specific module. +#[derive(Debug, Clone)] +pub struct Module<'m> { + info: DBIModuleInfo, + module_name: RawString<'m>, + object_file_name: RawString<'m>, +} + +impl<'m> Module<'m> { + /// The `DBIModuleInfo` from the module info substream in the DBI stream. + pub(crate) fn info(&self) -> &DBIModuleInfo { + &self.info + } + /// The module name. + /// + /// Usually either a full path to an object file or a string of the form `Import:`. + pub fn module_name(&self) -> Cow<'m, str> { + self.module_name.to_string() + } + /// The object file name. + /// + /// May be the same as `module_name` for object files passed directly + /// to the linker. For modules from static libraries, this is usually + /// the full path to the archive. + pub fn object_file_name(&self) -> Cow<'m, str> { + self.object_file_name.to_string() + } +} + +/// A `ModuleIter` iterates over the modules in the DBI section, producing `Module`s. +#[derive(Debug)] +pub struct ModuleIter<'m> { + buf: ParseBuffer<'m>, +} + +impl<'m> FallibleIterator for ModuleIter<'m> { + type Item = Module<'m>; + type Error = Error; + + fn next(&mut self) -> result::Result, Self::Error> { + // see if we're at EOF + if self.buf.is_empty() { + return Ok(None); + } + + let info = DBIModuleInfo::parse(&mut self.buf)?; + let module_name = self.buf.parse_cstring()?; + let object_file_name = self.buf.parse_cstring()?; + self.buf.align(4)?; + Ok(Some(Module { + info, + module_name, + object_file_name, + })) + } +} + +/// The version of the section contribution stream. +#[derive(Debug, Copy, Clone, PartialEq)] +#[allow(missing_docs)] +enum DBISectionContributionStreamVersion { + V60, + V2, + OtherValue(u32), +} + +impl From for DBISectionContributionStreamVersion { + fn from(v: u32) -> Self { + const V60: u32 = 0xeffe_0000 + 19_970_605; + const V2: u32 = 0xeffe_0000 + 20_140_516; + match v { + V60 => Self::V60, + V2 => Self::V2, + _ => Self::OtherValue(v), + } + } +} + +/// A `DBISectionContributionIter` iterates over the section contributions in the DBI section, producing `DBISectionContribution`s. +#[derive(Debug)] +pub struct DBISectionContributionIter<'c> { + buf: ParseBuffer<'c>, + version: DBISectionContributionStreamVersion, +} + +impl<'c> DBISectionContributionIter<'c> { + fn parse(mut buf: ParseBuffer<'c>) -> Result { + let version = buf.parse_u32()?.into(); + Ok(Self { buf, version }) + } +} + +impl<'c> FallibleIterator for DBISectionContributionIter<'c> { + type Item = DBISectionContribution; + type Error = Error; + + fn next(&mut self) -> result::Result, Self::Error> { + // see if we're at EOF + if self.buf.is_empty() { + return Ok(None); + } + + let contribution = DBISectionContribution::parse(&mut self.buf)?; + if self.version == DBISectionContributionStreamVersion::V2 { + self.buf.parse_u32()?; + } + Ok(Some(contribution)) + } +} + +/// A `DbgDataHdr`, which contains a series of (optional) MSF stream numbers. +#[derive(Debug, Copy, Clone)] +#[allow(dead_code)] // reason = "unused fields added for completeness" +pub(crate) struct DBIExtraStreams { + // The struct itself is defined at: + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/dbi.h#L250-L274 + // It's just an array of stream numbers; `u16`s where 0xffff means "no stream". + // + // The array indices are: + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/langapi/include/pdb.h#L439-L449 + // We'll map those to fields. + // + // The struct itself can be truncated. This is an internal struct; we'll treat missing fields as + // StreamIndex::none() even if it's a short read, so long as the short read stops on a u16 boundary. + pub fpo: StreamIndex, + pub exception: StreamIndex, + pub fixup: StreamIndex, + pub omap_to_src: StreamIndex, + pub omap_from_src: StreamIndex, + pub section_headers: StreamIndex, + pub token_rid_map: StreamIndex, + pub xdata: StreamIndex, + pub pdata: StreamIndex, + pub framedata: StreamIndex, + pub original_section_headers: StreamIndex, +} + +impl DBIExtraStreams { + pub(crate) fn new(debug_info: &DebugInformation<'_>) -> Result { + // calculate the location of the extra stream information + let header = debug_info.header; + let offset = debug_info.header_len + + (header.module_list_size + + header.section_contribution_size + + header.section_map_size + + header.file_info_size + + header.type_server_map_size + + header.ec_substream_size) as usize; + + // seek + let mut buf = debug_info.stream.parse_buffer(); + buf.take(offset)?; + + // grab that section as bytes + let bytes = buf.take(header.debug_header_size as _)?; + + // parse those bytes + let mut extra_streams_buf = ParseBuffer::from(bytes); + Self::parse(&mut extra_streams_buf) + } + + pub(crate) fn parse(buf: &mut ParseBuffer<'_>) -> Result { + // short reads are okay, as are long reads -- this struct is actually an array + // what's _not_ okay are + if buf.len() % 2 != 0 { + return Err(Error::InvalidStreamLength("DbgDataHdr")); + } + + fn next_index(buf: &mut ParseBuffer<'_>) -> Result { + if buf.is_empty() { + Ok(StreamIndex::none()) + } else { + buf.parse() + } + } + + Ok(Self { + fpo: next_index(buf)?, + exception: next_index(buf)?, + fixup: next_index(buf)?, + omap_to_src: next_index(buf)?, + omap_from_src: next_index(buf)?, + section_headers: next_index(buf)?, + token_rid_map: next_index(buf)?, + xdata: next_index(buf)?, + pdata: next_index(buf)?, + framedata: next_index(buf)?, + original_section_headers: next_index(buf)?, + }) + } +} + +#[cfg(test)] +mod tests { + use crate::dbi::*; + + #[test] + fn test_dbi_extra_streams() { + let bytes = vec![0xff, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff, 0xff, 0x05, 0x06]; + + let mut buf = ParseBuffer::from(bytes.as_slice()); + let extra_streams = DBIExtraStreams::parse(&mut buf).expect("parse"); + + // check readback + assert_eq!(extra_streams.fpo, StreamIndex::none()); + assert_eq!(extra_streams.exception, StreamIndex(0x0201)); + assert_eq!(extra_streams.fixup, StreamIndex(0x0403)); + assert_eq!(extra_streams.omap_to_src, StreamIndex::none()); + assert_eq!(extra_streams.omap_from_src, StreamIndex(0x0605)); + + // check that short reads => StreamIndex::none() + assert_eq!(extra_streams.section_headers, StreamIndex::none()); + assert_eq!(extra_streams.token_rid_map, StreamIndex::none()); + assert_eq!(extra_streams.original_section_headers, StreamIndex::none()); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/framedata.rs b/plugins/pdb-ng/vendor/pdb-rs/src/framedata.rs new file mode 100644 index 0000000000..a258f33898 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/framedata.rs @@ -0,0 +1,599 @@ +// Copyright 2018 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! Facilities for parsing legacy FPO and FrameData streams. + +use std::cmp::Ordering; +use std::fmt; + +use crate::common::*; +use crate::msf::Stream; +use crate::FallibleIterator; + +/// A compiler specific frame type. +/// +/// This frame type is used by the old FPO data and has been superseeded by program strings. Its +/// values are originally specified in [`enum StackFrameTypeEnum`]. +/// +/// [`enum StackFrameTypeEnum`]: https://docs.microsoft.com/en-us/visualstudio/debugger/debug-interface-access/stackframetypeenum?view=vs-2017 +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(u8)] +pub enum FrameType { + /// Frame which does not have any debug info. + Unknown = 0xff, + + /// Frame pointer omitted, FPO info available. + FPO = 0, + + /// Kernel Trap frame. + Trap = 1, + + /// Kernel Trap frame. + TSS = 2, + + /// Standard EBP stackframe. + Standard = 3, + + /// Frame pointer omitted, FrameData info available. + FrameData = 4, +} + +impl fmt::Display for FrameType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Unknown => write!(f, "unknown"), + Self::FPO => write!(f, "fpo"), + Self::Trap => write!(f, "trap"), + Self::TSS => write!(f, "tss"), + Self::Standard => write!(f, "std"), + Self::FrameData => write!(f, "fdata"), + } + } +} + +/// New frame data format. +/// +/// This format is used in the `DEBUG_S_FRAMEDATA` subsection in C13 module information, as well as +/// in the `dbgFRAMEDATA` stream defined in the optional debug header. Effectively, all recent PDBs +/// contain frame infos in this format. +/// +/// The definition corresponds to [`struct tagFRAMEDATA`]. +/// +/// ```c +/// struct tagFRAMEDATA { +/// unsigned long ulRvaStart; +/// unsigned long cbBlock; +/// unsigned long cbLocals; +/// unsigned long cbParams; +/// unsigned long cbStkMax; +/// unsigned long frameFunc; +/// unsigned short cbProlog; +/// unsigned short cbSavedRegs; +/// +/// unsigned long fHasSEH : 1; +/// unsigned long fHasEH : 1; +/// unsigned long fIsFunctionStart : 1; +/// unsigned long reserved : 29; +/// }; +/// ``` +/// +/// [`struct tagFRAMEDATA`]: https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4635 +#[repr(C)] +struct NewFrameData { + code_start: u32, + code_size: u32, + locals_size: u32, + params_size: u32, + max_stack_size: u32, + frame_func: u32, + prolog_size: u16, + saved_regs_size: u16, + flags: u32, +} + +impl NewFrameData { + pub fn code_start(&self) -> PdbInternalRva { + PdbInternalRva(u32::from_le(self.code_start)) + } + + pub fn code_size(&self) -> u32 { + u32::from_le(self.code_size) + } + + pub fn locals_size(&self) -> u32 { + u32::from_le(self.locals_size) + } + + pub fn params_size(&self) -> u32 { + u32::from_le(self.params_size) + } + + pub fn max_stack_size(&self) -> u32 { + u32::from_le(self.max_stack_size) + } + + pub fn frame_func(&self) -> StringRef { + StringRef(u32::from_le(self.frame_func)) + } + + pub fn prolog_size(&self) -> u16 { + u16::from_le(self.prolog_size) + } + + pub fn saved_regs_size(&self) -> u16 { + u16::from_le(self.saved_regs_size) + } + + pub fn has_seh(&self) -> bool { + self.flags() & 1 != 0 + } + + pub fn has_eh(&self) -> bool { + self.flags() & 2 != 0 + } + + pub fn is_function_start(&self) -> bool { + self.flags() & 4 != 0 + } + + fn flags(&self) -> u32 { + u32::from_le(self.flags) + } +} + +impl fmt::Debug for NewFrameData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("NewFrameData") + .field("code_start", &self.code_start()) + .field("code_size", &self.code_size()) + .field("locals_size", &self.locals_size()) + .field("params_size", &self.params_size()) + .field("max_stack_size", &self.max_stack_size()) + .field("frame_func", &self.frame_func()) + .field("prolog_size", &self.prolog_size()) + .field("saved_regs_size", &self.saved_regs_size()) + .field("has_seh", &self.has_seh()) + .field("has_eh", &self.has_eh()) + .field("is_function_start", &self.is_function_start()) + .finish() + } +} + +/// Initial structure used for describing stack frames. +/// +/// This structure corresponds to [`struct _FPO_DATA`] in the PE/COFF spec. It was used to describe +/// the layout of stack frames in the `dbgFPO` stream defined in the optional debug header. Since, +/// it has been superseeded by the `tagFRAMEDATA` structure (see [`NewFrameData`]). +/// +/// Even if the newer FrameData stream is present, a PDB might still contain an additional FPO +/// stream. This is due to the fact that the linker simply copies over the stream. As a result, both +/// stream might describe the same RVA. +/// +/// [`struct _FPO_DATA`]: https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#debug-type +/// +/// ```c +/// typedef struct _FPO_DATA { +/// DWORD ulOffStart; // offset 1st byte of function code +/// DWORD cbProcSize; // # bytes in function +/// DWORD cdwLocals; // # bytes in locals/4 +/// WORD cdwParams; // # bytes in params/4 +/// +/// WORD cbProlog : 8; // # bytes in prolog +/// WORD cbRegs : 3; // # regs saved +/// WORD fHasSEH : 1; // TRUE if SEH in func +/// WORD fUseBP : 1; // TRUE if EBP has been allocated +/// WORD reserved : 1; // reserved for future use +/// WORD cbFrame : 2; // frame type +/// } FPO_DATA; +/// ``` +#[repr(C)] +struct OldFrameData { + code_start: u32, + code_size: u32, + locals_size: u32, + params_size: u16, + attributes: u16, +} + +impl OldFrameData { + pub fn code_start(&self) -> PdbInternalRva { + PdbInternalRva(u32::from_le(self.code_start)) + } + + pub fn code_size(&self) -> u32 { + u32::from_le(self.code_size) + } + + pub fn locals_size(&self) -> u32 { + u32::from_le(self.locals_size) + } + + pub fn params_size(&self) -> u16 { + u16::from_le(self.params_size) + } + + pub fn prolog_size(&self) -> u16 { + self.attributes() & 0xf + } + + pub fn saved_regs_size(&self) -> u16 { + (self.attributes() >> 8) & 0x7 + } + + pub fn has_seh(&self) -> bool { + self.attributes() & 0x200 != 0 + } + + pub fn uses_base_pointer(&self) -> bool { + self.attributes() & 0x400 != 0 + } + + pub fn frame_type(&self) -> FrameType { + match self.attributes() >> 14 { + 0x00 => FrameType::FPO, + 0x01 => FrameType::Trap, + 0x02 => FrameType::TSS, + 0x03 => FrameType::Standard, + 0x04 => FrameType::FrameData, + _ => FrameType::Unknown, + } + } + + fn attributes(&self) -> u16 { + u16::from_le(self.attributes) + } +} + +impl fmt::Debug for OldFrameData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OldFrameData") + .field("code_start", &self.code_start()) + .field("code_size", &self.code_size()) + .field("locals_size", &self.locals_size()) + .field("params_size", &self.params_size()) + .field("prolog_size", &self.prolog_size()) + .field("saved_regs_size", &self.saved_regs_size()) + .field("has_seh", &self.has_seh()) + .field("uses_base_pointer", &self.uses_base_pointer()) + .field("frame_type", &self.frame_type()) + .finish() + } +} + +/// Frame data for a code block. +#[derive(Clone, Debug)] +pub struct FrameData { + /// Compiler-specific frame type. + pub ty: FrameType, + + /// Relative virtual address of the start of the code block. + /// + /// Note that this address is internal to the PDB. To convert this to an actual [`Rva`], use + /// [`PdbInternalRva::to_rva`]. + pub code_start: PdbInternalRva, + + /// Size of the code block covered by this frame data in bytes. + pub code_size: u32, + + /// Size of local variables pushed on the stack in bytes. + pub locals_size: u32, + + /// Size of parameters pushed on the stack in bytes. + pub params_size: u32, + + /// Number of bytes of prologue code in the block. + pub prolog_size: u16, + + /// Size of saved registers pushed on the stack in bytes. + pub saved_regs_size: u16, + + /// The maximum number of bytes pushed on the stack. + pub max_stack_size: Option, + + /// Indicates that structured exception handling is in effect. + pub has_structured_eh: bool, + + /// Indicates that C++ exception handling is in effect. + pub has_cpp_eh: bool, + + /// Indicates that this frame is the start of a function. + pub is_function_start: bool, + + /// Indicates that this function uses the EBP register. + pub uses_base_pointer: bool, + + /// A program string allowing to reconstruct register values for this frame. + /// + /// The program string is a sequence of macros that is interpreted in order to establish the + /// prologue. For example, a typical stack frame might use the program string `"$T0 $ebp = $eip + /// $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + ="`. The format is reverse polish notation, where the + /// operators follow the operands. `T0` represents a temporary variable on the stack. + /// + /// Note that the program string is specific to the CPU and to the calling convention set up for + /// the function represented by the current stack frame. + pub program: Option, +} + +impl From<&'_ OldFrameData> for FrameData { + fn from(data: &OldFrameData) -> Self { + Self { + ty: data.frame_type(), + code_start: data.code_start(), + code_size: data.code_size(), + prolog_size: data.prolog_size(), + locals_size: data.locals_size() * 4, + params_size: u32::from(data.params_size()) * 4, + saved_regs_size: data.saved_regs_size() * 4, + max_stack_size: None, + has_structured_eh: data.has_seh(), + has_cpp_eh: false, + is_function_start: false, + uses_base_pointer: data.uses_base_pointer(), + program: None, + } + } +} + +impl From<&'_ NewFrameData> for FrameData { + fn from(data: &NewFrameData) -> Self { + Self { + ty: FrameType::FrameData, + code_start: data.code_start(), + code_size: data.code_size(), + prolog_size: data.prolog_size(), + locals_size: data.locals_size(), + params_size: data.params_size(), + saved_regs_size: data.saved_regs_size(), + max_stack_size: Some(data.max_stack_size()), + has_structured_eh: data.has_seh(), + has_cpp_eh: data.has_eh(), + is_function_start: data.is_function_start(), + uses_base_pointer: false, + program: Some(data.frame_func()), + } + } +} + +/// Iterator over entries in a [`FrameTable`]. +#[derive(Debug, Default)] +pub struct FrameDataIter<'t> { + old_frames: &'t [OldFrameData], + new_frames: &'t [NewFrameData], + old_index: usize, + new_index: usize, +} + +impl FallibleIterator for FrameDataIter<'_> { + type Item = FrameData; + type Error = Error; + + fn next(&mut self) -> Result> { + let old_opt = self.old_frames.get(self.old_index); + let new_opt = self.new_frames.get(self.new_index); + + Ok(Some(match (old_opt, new_opt) { + (Some(old_frame), Some(new_frame)) => { + match new_frame.code_start().cmp(&old_frame.code_start()) { + Ordering::Less => { + self.new_index += 1; + new_frame.into() + } + Ordering::Equal => { + self.new_index += 1; + self.old_index += 1; + new_frame.into() + } + Ordering::Greater => { + self.old_index += 1; + old_frame.into() + } + } + } + (Some(old_frame), None) => { + self.old_index += 1; + old_frame.into() + } + (None, Some(new_frame)) => { + self.new_index += 1; + new_frame.into() + } + (None, None) => return Ok(None), + })) + } +} + +/// An object that spans a code range. +trait AddrRange { + /// The start RVA of the block. + fn start(&self) -> PdbInternalRva; + + /// The size of the block in bytes. + fn size(&self) -> u32; + + /// The non-inclusive end of the block. + #[inline] + fn end(&self) -> PdbInternalRva { + self.start() + self.size() + } + + /// Returns whether this item includes the given Rva. + #[inline] + fn contains(&self, rva: PdbInternalRva) -> bool { + rva >= self.start() && rva < self.end() + } +} + +impl AddrRange for OldFrameData { + fn start(&self) -> PdbInternalRva { + self.code_start() + } + + fn size(&self) -> u32 { + self.code_size() + } +} + +impl AddrRange for NewFrameData { + fn start(&self) -> PdbInternalRva { + self.code_start() + } + + fn size(&self) -> u32 { + self.code_size() + } +} + +/// Searches for a frame data entry covering the given `PdbInternalRva`. +fn binary_search_by_rva(frames: &[R], rva: PdbInternalRva) -> usize { + match frames.binary_search_by_key(&rva, |f| f.start()) { + Ok(index) => index, + Err(index) => { + if index > 0 && frames[index - 1].contains(rva) { + index - 1 + } else { + index + } + } + } +} + +/// Describes stack frame layout of functions. +/// +/// The table contains [`FrameData`] entries ordered by [`PdbInternalRva`]. Each entry describes a +/// range of instructions starting at `code_rva` for `code_size` bytes. +/// +/// A procedure/function might be described by multiple entries, with the first one declaring +/// `is_function_start`. To retrieve frame information for a specific function, use +/// [`FrameTable::iter_at_rva`]. +/// +/// Not every function in the image file must have frame data defined for it. Those functions that +/// do not have frame data are assumed to have normal stack frames. +/// +/// # Example +/// +/// ```rust +/// # use pdb::{PDB, Rva, FallibleIterator}; +/// # +/// # fn test() -> pdb::Result<()> { +/// # let source = std::fs::File::open("fixtures/self/foo.pdb")?; +/// let mut pdb = PDB::open(source)?; +/// +/// // Read the frame table once and reuse it +/// let frame_table = pdb.frame_table()?; +/// let mut frames = frame_table.iter(); +/// +/// // Iterate frame data in RVA order +/// while let Some(frame) = frames.next()? { +/// println!("{:#?}", frame); +/// } +/// # Ok(()) +/// # } +/// # test().unwrap() +/// ``` +pub struct FrameTable<'s> { + old_stream: Option>, + new_stream: Option>, +} + +impl<'s> FrameTable<'s> { + /// Parses frame data from raw streams. + pub(crate) fn parse( + old_stream: Option>, + new_stream: Option>, + ) -> Result { + if let Some(ref stream) = old_stream { + if cast_aligned::(stream.as_slice()).is_none() { + return Err(Error::InvalidStreamLength("FrameData")); + } + } + + if let Some(ref stream) = new_stream { + if cast_aligned::(stream.as_slice()).is_none() { + return Err(Error::InvalidStreamLength("FPO")); + } + } + + Ok(FrameTable { + old_stream, + new_stream, + }) + } + + /// Returns an iterator over all frame data in this table, ordered by `code_rva`. + pub fn iter(&self) -> FrameDataIter<'_> { + FrameDataIter { + old_frames: self.old_frames(), + new_frames: self.new_frames(), + old_index: 0, + new_index: 0, + } + } + + /// Returns an iterator over frame data starting at the given `PdbInternalRva`. + /// + /// The first item returned by this iterator covers the given RVA. If the address is not a + /// direct start of a function or block, this is the closest element preceding the block. If no + /// frame data covers the given RVA, the iterator starts at the first item **after** the RVA. + /// Therefore, check for the desired RVA range when iterating frame data. + /// + /// To obtain a `PdbInternalRva`, use [`PdbInternalSectionOffset::to_internal_rva`] or + /// [`Rva::to_internal_rva`]. + pub fn iter_at_rva(&self, rva: PdbInternalRva) -> FrameDataIter<'_> { + let old_frames = self.old_frames(); + let old_index = binary_search_by_rva(old_frames, rva); + + let new_frames = self.new_frames(); + let new_index = binary_search_by_rva(new_frames, rva); + + FrameDataIter { + old_frames, + new_frames, + old_index, + new_index, + } + } + + /// Indicates whether any frame data is available. + pub fn is_empty(&self) -> bool { + self.new_frames().is_empty() && self.old_frames().is_empty() + } + + fn old_frames(&self) -> &[OldFrameData] { + match self.old_stream { + // alignment checked during parsing + Some(ref stream) => cast_aligned(stream.as_slice()).unwrap(), + None => &[], + } + } + + fn new_frames(&self) -> &[NewFrameData] { + match self.new_stream { + // alignment checked during parsing + Some(ref stream) => cast_aligned(stream.as_slice()).unwrap(), + None => &[], + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::mem; + + #[test] + fn test_new_frame_data() { + assert_eq!(mem::size_of::(), 32); + assert_eq!(mem::align_of::(), 4); + } + + #[test] + fn test_old_frame_data() { + assert_eq!(mem::size_of::(), 16); + assert_eq!(mem::align_of::(), 4); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/lib.rs b/plugins/pdb-ng/vendor/pdb-rs/src/lib.rs new file mode 100644 index 0000000000..1a0d71bd73 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/lib.rs @@ -0,0 +1,81 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! The `pdb` create parses Microsoft PDB (Program Database) files. PDB files contain debugging +//! information produced by most compilers that target Windows, including information about symbols, +//! types, modules, and so on. +//! +//! # Usage +//! +//! PDB files are accessed via the [`pdb::PDB`] object. +//! +//! # Example +//! +//! ``` +//! # use pdb::FallibleIterator; +//! # +//! # fn test() -> pdb::Result { +//! let file = std::fs::File::open("fixtures/self/foo.pdb")?; +//! let mut pdb = pdb::PDB::open(file)?; +//! +//! let symbol_table = pdb.global_symbols()?; +//! let address_map = pdb.address_map()?; +//! +//! # let mut count: usize = 0; +//! let mut symbols = symbol_table.iter(); +//! while let Some(symbol) = symbols.next()? { +//! match symbol.parse() { +//! Ok(pdb::SymbolData::Public(data)) if data.function => { +//! // we found the location of a function! +//! let rva = data.offset.to_rva(&address_map).unwrap_or_default(); +//! println!("{} is {}", rva, data.name); +//! # count += 1; +//! } +//! _ => {} +//! } +//! } +//! +//! # Ok(count) +//! # } +//! # assert!(test().expect("test") > 2000); +//! ``` + +#![allow(non_upper_case_globals)] + +// modules +mod common; +mod dbi; +mod framedata; +mod modi; +mod msf; +mod omap; +mod pdb; +mod pdbi; +mod pe; +pub mod register; +mod source; +mod strings; +mod symbol; +mod tpi; + +// exports +pub use crate::common::*; +pub use crate::dbi::*; +pub use crate::framedata::*; +pub use crate::modi::*; +pub use crate::omap::*; +pub use crate::pdb::*; +pub use crate::pdbi::*; +pub use crate::pe::*; +pub use crate::source::*; +pub use crate::strings::*; +pub use crate::symbol::*; +pub use crate::tpi::*; + +// re-export FallibleIterator for convenience +#[doc(no_inline)] +pub use fallible_iterator::FallibleIterator; diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/modi/c13.rs b/plugins/pdb-ng/vendor/pdb-rs/src/modi/c13.rs new file mode 100644 index 0000000000..645d0b057d --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/modi/c13.rs @@ -0,0 +1,1933 @@ +use std::fmt; +use std::mem; +use std::slice; + +use scroll::{ctx::TryFromCtx, Endian, Pread}; + +use crate::common::*; +use crate::modi::{ + constants, CrossModuleExport, CrossModuleRef, FileChecksum, FileIndex, FileInfo, LineInfo, + LineInfoKind, ModuleRef, +}; +use crate::symbol::{BinaryAnnotation, BinaryAnnotationsIter, InlineSiteSymbol}; +use crate::FallibleIterator; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[repr(u32)] +#[allow(unused)] +enum DebugSubsectionKind { + // Native + Symbols = 0xf1, + Lines = 0xf2, + StringTable = 0xf3, + FileChecksums = 0xf4, + FrameData = 0xf5, + InlineeLines = 0xf6, + CrossScopeImports = 0xf7, + CrossScopeExports = 0xf8, + + // .NET + ILLines = 0xf9, + FuncMDTokenMap = 0xfa, + TypeMDTokenMap = 0xfb, + MergedAssemblyInput = 0xfc, + + CoffSymbolRva = 0xfd, +} + +impl DebugSubsectionKind { + fn parse(value: u32) -> Result> { + if (0xf1..=0xfd).contains(&value) { + Ok(Some(unsafe { std::mem::transmute(value) })) + } else if value == constants::DEBUG_S_IGNORE { + Ok(None) + } else { + Err(Error::UnimplementedDebugSubsection(value)) + } + } +} + +#[derive(Clone, Copy, Debug)] +struct DebugSubsectionHeader { + /// The kind of this subsection. + kind: u32, + /// The length of this subsection in bytes, following the header. + len: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for DebugSubsectionHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + kind: this.gread_with(&mut offset, le)?, + len: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl DebugSubsectionHeader { + fn kind(self) -> Result> { + DebugSubsectionKind::parse(self.kind) + } + + fn len(self) -> usize { + self.len as usize + } +} + +#[derive(Clone, Copy, Debug)] +struct DebugSubsection<'a> { + pub kind: DebugSubsectionKind, + pub data: &'a [u8], +} + +#[derive(Clone, Debug, Default)] +struct DebugSubsectionIterator<'a> { + buf: ParseBuffer<'a>, +} + +impl<'a> DebugSubsectionIterator<'a> { + fn new(data: &'a [u8]) -> Self { + Self { + buf: ParseBuffer::from(data), + } + } +} + +impl<'a> FallibleIterator for DebugSubsectionIterator<'a> { + type Item = DebugSubsection<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + while !self.buf.is_empty() { + let header = self.buf.parse::()?; + let data = self.buf.take(header.len())?; + let kind = match header.kind()? { + Some(kind) => kind, + None => continue, + }; + + return Ok(Some(DebugSubsection { kind, data })); + } + + Ok(None) + } +} + +#[derive(Clone, Copy, Debug, Default)] +struct DebugInlineeLinesHeader { + /// The signature of the inlinees + signature: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for DebugInlineeLinesHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + signature: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl DebugInlineeLinesHeader { + pub fn has_extra_files(self) -> bool { + self.signature == constants::CV_INLINEE_SOURCE_LINE_SIGNATURE_EX + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct InlineeSourceLine<'a> { + pub inlinee: IdIndex, + pub file_id: FileIndex, + pub line: u32, + extra_files: &'a [u8], +} + +impl<'a> InlineeSourceLine<'a> { + // TODO: Implement extra files iterator when needed. +} + +impl<'a> TryFromCtx<'a, DebugInlineeLinesHeader> for InlineeSourceLine<'a> { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], header: DebugInlineeLinesHeader) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + let inlinee = buf.parse()?; + let file_id = buf.parse()?; + let line = buf.parse()?; + + let extra_files = if header.has_extra_files() { + let file_count = buf.parse::()? as usize; + buf.take(file_count * std::mem::size_of::())? + } else { + &[] + }; + + let source_line = Self { + inlinee, + file_id, + line, + extra_files, + }; + + Ok((source_line, buf.pos())) + } +} + +#[derive(Debug, Clone, Default)] +struct DebugInlineeLinesIterator<'a> { + header: DebugInlineeLinesHeader, + buf: ParseBuffer<'a>, +} + +impl<'a> FallibleIterator for DebugInlineeLinesIterator<'a> { + type Item = InlineeSourceLine<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + Ok(None) + } else { + Ok(Some(self.buf.parse_with(self.header)?)) + } + } +} + +#[derive(Clone, Debug, Default)] +struct DebugInlineeLinesSubsection<'a> { + header: DebugInlineeLinesHeader, + data: &'a [u8], +} + +impl<'a> DebugInlineeLinesSubsection<'a> { + fn parse(data: &'a [u8]) -> Result { + let mut buf = ParseBuffer::from(data); + let header = buf.parse::()?; + + Ok(Self { + header, + data: &data[buf.pos()..], + }) + } + + /// Iterate through all inlinees. + fn lines(&self) -> DebugInlineeLinesIterator<'a> { + DebugInlineeLinesIterator { + header: self.header, + buf: ParseBuffer::from(self.data), + } + } +} + +#[derive(Clone, Copy, Debug, Default)] +struct DebugLinesHeader { + /// Section offset of this line contribution. + offset: PdbInternalSectionOffset, + /// See LineFlags enumeration. + flags: u16, + /// Code size of this line contribution. + code_size: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for DebugLinesHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + offset: this.gread_with(&mut offset, le)?, + flags: this.gread_with(&mut offset, le)?, + code_size: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl DebugLinesHeader { + fn has_columns(self) -> bool { + self.flags & constants::CV_LINES_HAVE_COLUMNS != 0 + } +} + +#[derive(Clone, Copy, Debug)] +struct DebugLinesSubsection<'a> { + header: DebugLinesHeader, + data: &'a [u8], +} + +impl<'a> DebugLinesSubsection<'a> { + fn parse(data: &'a [u8]) -> Result { + let mut buf = ParseBuffer::from(data); + let header = buf.parse()?; + let data = &data[buf.pos()..]; + Ok(Self { header, data }) + } + + fn blocks(&self) -> DebugLinesBlockIterator<'a> { + DebugLinesBlockIterator { + header: self.header, + buf: ParseBuffer::from(self.data), + } + } +} + +/// Marker instructions for a line offset. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum LineMarkerKind { + /// A debugger should skip this address. + DoNotStepOnto, + /// A debugger should not step into this address. + DoNotStepInto, +} + +/// The raw line number entry in a PDB. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +struct LineNumberHeader { + /// Offset to start of code bytes for line number. + offset: u32, + /// Combined information on the start line, end line and entry type: + /// + /// ```ignore + /// unsigned long linenumStart:24; // line where statement/expression starts + /// unsigned long deltaLineEnd:7; // delta to line where statement ends (optional) + /// unsigned long fStatement :1; // true if a statement line number, else an expression + /// ``` + flags: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for LineNumberHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + offset: this.gread_with(&mut offset, le)?, + flags: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +/// A mapping of code section offsets to source line numbers. +#[derive(Clone, Debug)] +struct LineNumberEntry { + /// Delta offset to the start of this line contribution (debug lines subsection). + pub offset: u32, + /// Start line number of the statement or expression. + pub start_line: u32, + /// End line number of the statement or expression. + pub end_line: u32, + /// The type of code construct this line entry refers to. + pub kind: LineInfoKind, +} + +/// Marker for debugging purposes. +#[derive(Clone, Debug)] +struct LineMarkerEntry { + /// Delta offset to the start of this line contribution (debug lines subsection). + #[allow(dead_code)] // reason = "unused until TODO in LineIterator is resolved" + pub offset: u32, + /// The marker kind, hinting a debugger how to deal with code at this offset. + #[allow(dead_code)] // reason = "debugger instructions are not exposed" + pub kind: LineMarkerKind, +} + +/// A parsed line entry. +#[derive(Clone, Debug)] +enum LineEntry { + /// Declares a source line number. + Number(LineNumberEntry), + /// Declares a debugging marker. + Marker(LineMarkerEntry), +} + +impl LineNumberHeader { + /// Parse this line number header into a line entry. + pub fn parse(self) -> LineEntry { + // The compiler generates special line numbers to hint the debugger. Separate these out so + // that they are not confused with actual line number entries. + let start_line = self.flags & 0x00ff_ffff; + let marker = match start_line { + 0xfeefee => Some(LineMarkerKind::DoNotStepOnto), + 0xf00f00 => Some(LineMarkerKind::DoNotStepInto), + _ => None, + }; + + if let Some(kind) = marker { + return LineEntry::Marker(LineMarkerEntry { + offset: self.offset, + kind, + }); + } + + // It has been observed in some PDBs that this does not store a delta to start_line but + // actually just the truncated value of `end_line`. Therefore, prefer to use `end_line` and + // compute the deta from `end_line` and `start_line`, if needed. + let line_delta = self.flags & 0x7f00_0000 >> 24; + + // The line_delta contains the lower 7 bits of the end line number. We take all higher bits + // from the start line and OR them with the lower delta bits. This combines to the full + // original end line number. + let high_start = start_line & !0x7f; + let mut end_line = high_start | line_delta; + + // If the end line number is smaller than the start line, we have to assume an overflow. + // The end line will most likely be within 128 lines from the start line. Thus, we account + // for the overflow by adding 1 to the 8th bit. + if end_line < start_line { + end_line += 1 << 7; + } + + let kind = if self.flags & 0x8000_0000 != 0 { + LineInfoKind::Statement + } else { + LineInfoKind::Expression + }; + + LineEntry::Number(LineNumberEntry { + offset: self.offset, + start_line, + end_line, + kind, + }) + } +} + +#[derive(Clone, Debug, Default)] +struct DebugLinesIterator<'a> { + block: DebugLinesBlockHeader, + buf: ParseBuffer<'a>, +} + +impl FallibleIterator for DebugLinesIterator<'_> { + type Item = LineEntry; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + self.buf.parse().map(LineNumberHeader::parse).map(Some) + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +struct ColumnNumberEntry { + start_column: u16, + end_column: u16, +} + +impl<'t> TryFromCtx<'t, Endian> for ColumnNumberEntry { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + start_column: this.gread_with(&mut offset, le)?, + end_column: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +#[derive(Clone, Debug, Default)] +struct DebugColumnsIterator<'a> { + buf: ParseBuffer<'a>, +} + +impl FallibleIterator for DebugColumnsIterator<'_> { + type Item = ColumnNumberEntry; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + self.buf.parse().map(Some) + } +} + +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +struct DebugLinesBlockHeader { + /// Offset of the file checksum in the file checksums debug subsection. + file_index: u32, + + /// Number of line entries in this block. + /// + /// If the debug lines subsection also contains column information (see `has_columns`), then the + /// same number of column entries will be present after the line entries. + num_lines: u32, + + /// Total byte size of this block, including following line and column entries. + block_size: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for DebugLinesBlockHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + file_index: this.gread_with(&mut offset, le)?, + num_lines: this.gread_with(&mut offset, le)?, + block_size: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl DebugLinesBlockHeader { + /// The byte size of all line and column records combined. + fn data_size(&self) -> usize { + self.block_size as usize - std::mem::size_of::() + } + + /// The byte size of all line number entries combined. + fn line_size(&self) -> usize { + self.num_lines as usize * std::mem::size_of::() + } + + /// The byte size of all column number entries combined. + fn column_size(&self, subsection: DebugLinesHeader) -> usize { + if subsection.has_columns() { + self.num_lines as usize * std::mem::size_of::() + } else { + 0 + } + } +} + +#[derive(Clone, Debug)] +struct DebugLinesBlock<'a> { + header: DebugLinesBlockHeader, + line_data: &'a [u8], + column_data: &'a [u8], +} + +impl<'a> DebugLinesBlock<'a> { + #[allow(unused)] + fn file_index(&self) -> FileIndex { + FileIndex(self.header.file_index) + } + + fn lines(&self) -> DebugLinesIterator<'a> { + DebugLinesIterator { + block: self.header, + buf: ParseBuffer::from(self.line_data), + } + } + + fn columns(&self) -> DebugColumnsIterator<'a> { + DebugColumnsIterator { + buf: ParseBuffer::from(self.column_data), + } + } +} + +#[derive(Clone, Debug, Default)] +struct DebugLinesBlockIterator<'a> { + header: DebugLinesHeader, + buf: ParseBuffer<'a>, +} + +impl<'a> FallibleIterator for DebugLinesBlockIterator<'a> { + type Item = DebugLinesBlock<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + // The header is followed by a variable-size chunk of data, specified by `data_size`. Load + // all of it at once to ensure we're not reading garbage in case there is more information + // we do not yet understand. + let header = self.buf.parse::()?; + let data = self.buf.take(header.data_size())?; + + // The first data is a set of line entries, optionally followed by column entries. Load both + // and discard eventual data that follows + let (line_data, data) = data.split_at(header.line_size()); + let (column_data, remainder) = data.split_at(header.column_size(self.header)); + + // In case the PDB format is extended with more information, we'd like to know here. + debug_assert!(remainder.is_empty()); + + Ok(Some(DebugLinesBlock { + header, + line_data, + column_data, + })) + } +} + +/// Possible representations of file checksums in the file checksums subsection. +#[repr(u8)] +#[allow(unused)] +#[derive(Clone, Copy, Debug, Eq, Ord, Hash, PartialEq, PartialOrd)] +enum FileChecksumKind { + None = 0, + Md5 = 1, + Sha1 = 2, + Sha256 = 3, +} + +impl FileChecksumKind { + /// Parses the checksum kind from its raw value. + fn parse(value: u8) -> Result { + if value <= 3 { + Ok(unsafe { std::mem::transmute(value) }) + } else { + Err(Error::UnimplementedFileChecksumKind(value)) + } + } +} + +/// Raw header of a single file checksum entry. +#[derive(Clone, Copy, Debug)] +struct FileChecksumHeader { + name_offset: u32, + checksum_size: u8, + checksum_kind: u8, +} + +impl<'t> TryFromCtx<'t, Endian> for FileChecksumHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + name_offset: this.gread_with(&mut offset, le)?, + checksum_size: this.gread_with(&mut offset, le)?, + checksum_kind: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +/// A file checksum entry. +#[derive(Clone, Debug)] +struct FileChecksumEntry<'a> { + /// Reference to the file name in the string table. + name: StringRef, + /// File checksum value. + checksum: FileChecksum<'a>, +} + +#[derive(Clone, Debug, Default)] +struct DebugFileChecksumsIterator<'a> { + buf: ParseBuffer<'a>, +} + +impl<'a> FallibleIterator for DebugFileChecksumsIterator<'a> { + type Item = FileChecksumEntry<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + let header = self.buf.parse::()?; + let checksum_data = self.buf.take(header.checksum_size as usize)?; + + let checksum = match FileChecksumKind::parse(header.checksum_kind)? { + FileChecksumKind::None => FileChecksum::None, + FileChecksumKind::Md5 => FileChecksum::Md5(checksum_data), + FileChecksumKind::Sha1 => FileChecksum::Sha1(checksum_data), + FileChecksumKind::Sha256 => FileChecksum::Sha256(checksum_data), + }; + + self.buf.align(4)?; + + Ok(Some(FileChecksumEntry { + name: StringRef(header.name_offset), + checksum, + })) + } +} + +#[derive(Clone, Debug, Default)] +struct DebugFileChecksumsSubsection<'a> { + data: &'a [u8], +} + +impl<'a> DebugFileChecksumsSubsection<'a> { + /// Creates a new file checksums subsection. + fn new(data: &'a [u8]) -> Self { + Self { data } + } + + /// Returns an iterator over all file checksum entries. + #[allow(unused)] + fn entries(&self) -> Result> { + self.entries_at_offset(FileIndex(0)) + } + + /// Returns an iterator over file checksum entries starting at the given offset. + fn entries_at_offset(&self, offset: FileIndex) -> Result> { + let mut buf = ParseBuffer::from(self.data); + buf.take(offset.0 as usize)?; + Ok(DebugFileChecksumsIterator { buf }) + } +} + +#[derive(Clone, Copy, Debug)] +struct CrossScopeImportModule<'a> { + name: ModuleRef, + /// unparsed in LE byteorder + imports: &'a [u32], +} + +impl CrossScopeImportModule<'_> { + /// Returns the local reference at the given offset. + /// + /// This function performs an "unsafe" conversion of the raw value into `Local`. It is + /// assumed that this function is only called from contexts where `I` can be statically + /// inferred. + fn get(self, import: usize) -> Option> + where + I: ItemIndex, + { + let value = self.imports.get(import)?; + let index = u32::from_le(*value).into(); + Some(Local(index)) + } +} + +#[derive(Clone, Debug, Default)] +struct CrossScopeImportModuleIter<'a> { + buf: ParseBuffer<'a>, +} + +impl<'a> FallibleIterator for CrossScopeImportModuleIter<'a> { + type Item = CrossScopeImportModule<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + let name = ModuleRef(self.buf.parse()?); + let count = self.buf.parse::()? as usize; + + let data = self.buf.take(count * mem::size_of::())?; + let imports = cast_aligned(data).ok_or(Error::InvalidStreamLength("CrossScopeImports"))?; + + Ok(Some(CrossScopeImportModule { name, imports })) + } +} + +#[derive(Clone, Copy, Debug, Default)] +struct DebugCrossScopeImportsSubsection<'a> { + data: &'a [u8], +} + +impl<'a> DebugCrossScopeImportsSubsection<'a> { + fn new(data: &'a [u8]) -> Self { + Self { data } + } + + fn modules(self) -> CrossScopeImportModuleIter<'a> { + let buf = ParseBuffer::from(self.data); + CrossScopeImportModuleIter { buf } + } +} + +/// Provides efficient access to imported types and IDs from other modules. +/// +/// This can be used to resolve cross module references. See [`ItemIndex::is_cross_module`] for more +/// information. +#[derive(Clone, Debug, Default)] +pub struct CrossModuleImports<'a> { + modules: Vec>, +} + +impl<'a> CrossModuleImports<'a> { + /// Creates `CrossModuleImports` from the imports debug subsection. + fn from_section(section: DebugCrossScopeImportsSubsection<'a>) -> Result { + let modules = section.modules().collect()?; + Ok(Self { modules }) + } + + /// Loads `CrossModuleImports` from the debug subsections data. + pub(crate) fn parse(data: &'a [u8]) -> Result { + let import_data = DebugSubsectionIterator::new(data) + .find(|sec| Ok(sec.kind == DebugSubsectionKind::CrossScopeImports))? + .map(|sec| sec.data); + + match import_data { + Some(d) => Self::from_section(DebugCrossScopeImportsSubsection::new(d)), + None => Ok(Self::default()), + } + } + + /// Resolves the referenced module and local index for the index. + /// + /// The given index **must** be a cross module reference. Use `ItemIndex::is_cross_module` to + /// check this before invoking this function. If successful, this function returns a reference + /// to the module that declares the type, as well as the local index of the type in that module. + /// + /// # Errors + /// + /// * `Error::NotACrossModuleRef` if the given index is already a global index and not a cross + /// module reference. + /// * `Error::CrossModuleRefNotFound` if the cross module reference points to a module or local + /// index that is not indexed by this import table. + pub fn resolve_import(&self, index: I) -> Result> + where + I: ItemIndex, + { + let raw_index = index.into(); + if !index.is_cross_module() { + return Err(Error::NotACrossModuleRef(raw_index)); + } + + let module_index = ((raw_index >> 20) & 0x7ff) as usize; + let import_index = (raw_index & 0x000f_ffff) as usize; + + let module = self + .modules + .get(module_index) + .ok_or(Error::CrossModuleRefNotFound(raw_index))?; + + let local_index = module + .get(import_index) + .ok_or(Error::CrossModuleRefNotFound(raw_index))?; + + Ok(CrossModuleRef(module.name, local_index)) + } +} + +/// Raw representation of `CrossModuleExport`. +/// +/// This type can directly be mapped onto a slice of binary data and exposes the underlying `local` +/// and `global` fields with correct endianness via getter methods. There are two ways to use this: +/// +/// 1. Binary search over a slice of exports to find the one matching a given local index +/// 2. Enumerate all for debugging purposes +#[repr(C)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +struct RawCrossScopeExport { + /// The local index within the module. + /// + /// This maps to `Local` in the public type signature. + local: u32, + + /// The index in the global type or id stream. + /// + /// This maps to `I: ItemIndex` in the public type signature. + global: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for RawCrossScopeExport { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + local: this.gread_with(&mut offset, le)?, + global: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl From for CrossModuleExport { + fn from(raw: RawCrossScopeExport) -> Self { + if (raw.local & 0x8000_0000) != 0 { + Self::Id(Local(IdIndex(raw.local)), IdIndex(raw.global)) + } else { + Self::Type(Local(TypeIndex(raw.local)), TypeIndex(raw.global)) + } + } +} + +struct RawCrossScopeExportsIter<'a> { + buf: ParseBuffer<'a>, +} + +impl FallibleIterator for RawCrossScopeExportsIter<'_> { + type Item = RawCrossScopeExport; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buf.is_empty() { + return Ok(None); + } + + self.buf.parse().map(Some) + } +} + +#[derive(Clone, Copy, Debug, Default)] +struct DebugCrossScopeExportsSubsection<'a> { + data: &'a [u8], +} + +impl<'a> DebugCrossScopeExportsSubsection<'a> { + /// Creates a new cross scope exports subsection. + fn parse(data: &'a [u8]) -> Result { + if cast_aligned::(data).is_none() { + return Err(Error::InvalidStreamLength( + "DebugCrossScopeExportsSubsection", + )); + } + + Ok(Self { data }) + } + + fn exports(self) -> RawCrossScopeExportsIter<'a> { + let buf = ParseBuffer::from(self.data); + RawCrossScopeExportsIter { buf } + } +} + +/// Iterator returned by [`CrossModuleExports::exports`]. +#[derive(Clone, Debug)] +pub struct CrossModuleExportIter<'a> { + exports: slice::Iter<'a, RawCrossScopeExport>, +} + +impl Default for CrossModuleExportIter<'_> { + fn default() -> Self { + Self { exports: [].iter() } + } +} + +impl<'a> FallibleIterator for CrossModuleExportIter<'a> { + type Item = CrossModuleExport; + type Error = Error; + + fn next(&mut self) -> Result> { + Ok(self.exports.next().map(|r| (*r).into())) + } +} + +/// A table of exports declared by this module. +/// +/// Other modules can import types and ids from this module by using [cross module +/// references](ItemIndex::is_cross_module). +#[derive(Clone, Debug, Default)] +pub struct CrossModuleExports { + raw_exports: Vec, +} + +impl CrossModuleExports { + fn from_section(section: DebugCrossScopeExportsSubsection<'_>) -> Result { + let raw_exports = section.exports().collect()?; + Ok(Self { raw_exports }) + } + + pub(crate) fn parse(data: &[u8]) -> Result { + let export_data = DebugSubsectionIterator::new(data) + .find(|sec| Ok(sec.kind == DebugSubsectionKind::CrossScopeExports))? + .map(|sec| sec.data); + + match export_data { + Some(d) => Self::from_section(DebugCrossScopeExportsSubsection::parse(d)?), + None => Ok(Self::default()), + } + } + + /// Returns the number of exported types or ids from this module. + #[inline] + pub fn len(&self) -> usize { + self.raw_exports.len() + } + + /// Returns `true` if this module does not export types or ids. + #[inline] + pub fn is_empty(&self) -> bool { + self.raw_exports.is_empty() + } + + /// Returns an iterator over all cross scope exports. + pub fn exports(&self) -> CrossModuleExportIter<'_> { + CrossModuleExportIter { + exports: self.raw_exports.iter(), + } + } + + /// Resolves the global index of the given cross module import's local index. + /// + /// The global index can be used to retrieve items from the + /// [`TypeInformation`](crate::TypeInformation) or [`IdInformation`](crate::IdInformation) + /// streams. If the given local index is not listed in the export list, this function returns + /// `Ok(None)`. + pub fn resolve_import(&self, local_index: Local) -> Result> + where + I: ItemIndex, + { + let local = local_index.0.into(); + let exports = &self.raw_exports; + + Ok(match exports.binary_search_by_key(&local, |r| r.local) { + Ok(i) => Some(I::from(exports[i].global)), + Err(_) => None, + }) + } +} + +#[derive(Clone)] +pub struct LineIterator<'a> { + /// Iterator over all subsections in the current module. + sections: std::slice::Iter<'a, DebugLinesSubsection<'a>>, + /// Iterator over all blocks in the current lines subsection. + blocks: DebugLinesBlockIterator<'a>, + /// Iterator over lines in the current block. + lines: DebugLinesIterator<'a>, + /// Iterator over optional columns in the current block. + columns: DebugColumnsIterator<'a>, + /// Previous line info before length can be inferred. + last_info: Option, +} + +impl<'a> FallibleIterator for LineIterator<'a> { + type Item = LineInfo; + type Error = Error; + + fn next(&mut self) -> Result> { + loop { + if let Some(entry) = self.lines.next()? { + // A column entry is only returned if the debug lines subsection contains column + // information. Otherwise, the columns iterator is empty. We can safely assume that + // the number of line entries and column entries returned from the two iterators is + // equivalent. If it were not, the creation of the block would already have failed. + let column_entry = self.columns.next()?; + + // The high-level line iterator is only interested in actual line entries. It might + // make sense to eventually fold markers at the same offset into the `LineInfo` + // record. + let line_entry = match entry { + LineEntry::Number(line_entry) => line_entry, + LineEntry::Marker(_) => continue, + }; + + let section_header = self.blocks.header; + let block_header = self.lines.block; + + let offset = section_header.offset + line_entry.offset; + + let line_info = LineInfo { + offset, + length: None, // Length is inferred in the next iteration. + file_index: FileIndex(block_header.file_index), + line_start: line_entry.start_line, + line_end: line_entry.end_line, + column_start: column_entry.map(|e| e.start_column.into()), + column_end: column_entry.map(|e| e.end_column.into()), + kind: line_entry.kind, + }; + + let mut last_info = match std::mem::replace(&mut self.last_info, Some(line_info)) { + Some(last_info) => last_info, + None => continue, + }; + + last_info.set_end(offset); + return Ok(Some(last_info)); + } + + if let Some(block) = self.blocks.next()? { + self.lines = block.lines(); + self.columns = block.columns(); + continue; + } + + // The current debug lines subsection ends. Fix up the length of the last line record + // using the code size of the lines section, before continuing iteration. This ensures + // the most accurate length of the line record, even if there are gaps between sections. + if let Some(ref mut last_line) = self.last_info { + let section_header = self.blocks.header; + last_line.set_end(section_header.offset + section_header.code_size); + } + + if let Some(lines_section) = self.sections.next() { + self.blocks = lines_section.blocks(); + continue; + } + + return Ok(self.last_info.take()); + } + } +} + +impl Default for LineIterator<'_> { + fn default() -> Self { + Self { + sections: [].iter(), + blocks: DebugLinesBlockIterator::default(), + lines: DebugLinesIterator::default(), + columns: DebugColumnsIterator::default(), + last_info: None, + } + } +} + +impl fmt::Debug for LineIterator<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LineIterator") + .field("sections", &self.sections.as_slice()) + .field("blocks", &self.blocks) + .field("lines", &self.lines) + .field("columns", &self.columns) + .field("last_info", &self.last_info) + .finish() + } +} + +/// An iterator over line information records in a module. +#[derive(Clone, Debug, Default)] +pub struct InlineeLineIterator<'a> { + annotations: BinaryAnnotationsIter<'a>, + file_index: FileIndex, + code_offset_base: u32, + code_offset: PdbInternalSectionOffset, + code_length: Option, + line: u32, + line_length: u32, + col_start: Option, + col_end: Option, + line_kind: LineInfoKind, + last_info: Option, +} + +impl<'a> InlineeLineIterator<'a> { + fn new( + parent_offset: PdbInternalSectionOffset, + inline_site: &InlineSiteSymbol<'a>, + inlinee_line: InlineeSourceLine<'a>, + ) -> Self { + Self { + annotations: inline_site.annotations.iter(), + file_index: inlinee_line.file_id, + code_offset_base: 0, + code_offset: parent_offset, + code_length: None, + line: inlinee_line.line, + line_length: 1, + col_start: None, + col_end: None, + line_kind: LineInfoKind::Statement, + last_info: None, + } + } +} + +impl<'a> FallibleIterator for InlineeLineIterator<'a> { + type Item = LineInfo; + type Error = Error; + + fn next(&mut self) -> Result> { + while let Some(op) = self.annotations.next()? { + match op { + BinaryAnnotation::CodeOffset(code_offset) => { + self.code_offset.offset = code_offset; + } + BinaryAnnotation::ChangeCodeOffsetBase(code_offset_base) => { + self.code_offset_base = code_offset_base; + } + BinaryAnnotation::ChangeCodeOffset(delta) => { + self.code_offset = self.code_offset.wrapping_add(delta); + } + BinaryAnnotation::ChangeCodeLength(code_length) => { + if let Some(ref mut last_info) = self.last_info { + if last_info.length.is_none() && last_info.kind == self.line_kind { + last_info.length = Some(code_length); + } + } + + self.code_offset = self.code_offset.wrapping_add(code_length); + } + BinaryAnnotation::ChangeFile(file_index) => { + // NOTE: There seems to be a bug in VS2015-VS2019 compilers that generates + // invalid binary annotations when file changes are involved. This can be + // triggered by #including files directly into inline functions. The + // `ChangeFile` annotations are generated in the wrong spot or missing + // completely. This renders information on the file effectively useless in a lot + // of cases. + self.file_index = file_index; + } + BinaryAnnotation::ChangeLineOffset(delta) => { + self.line = (i64::from(self.line) + i64::from(delta)) as u32; + } + BinaryAnnotation::ChangeLineEndDelta(line_length) => { + self.line_length = line_length; + } + BinaryAnnotation::ChangeRangeKind(kind) => { + self.line_kind = match kind { + 0 => LineInfoKind::Expression, + 1 => LineInfoKind::Statement, + _ => self.line_kind, + }; + } + BinaryAnnotation::ChangeColumnStart(col_start) => { + self.col_start = Some(col_start); + } + BinaryAnnotation::ChangeColumnEndDelta(delta) => { + self.col_end = self + .col_end + .map(|col_end| (i64::from(col_end) + i64::from(delta)) as u32) + } + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(code_delta, line_delta) => { + self.code_offset += code_delta; + self.line = (i64::from(self.line) + i64::from(line_delta)) as u32; + } + BinaryAnnotation::ChangeCodeLengthAndCodeOffset(code_length, code_delta) => { + self.code_length = Some(code_length); + self.code_offset += code_delta; + } + BinaryAnnotation::ChangeColumnEnd(col_end) => { + self.col_end = Some(col_end); + } + } + + if !op.emits_line_info() { + continue; + } + + let line_offset = self.code_offset + self.code_offset_base; + if let Some(ref mut last_info) = self.last_info { + if last_info.length.is_none() && last_info.kind == self.line_kind { + last_info.length = Some(line_offset.offset - last_info.offset.offset); + } + } + + let line_info = LineInfo { + kind: self.line_kind, + file_index: self.file_index, + offset: line_offset, + length: self.code_length, + line_start: self.line, + line_end: self.line + self.line_length, + column_start: self.col_start, + column_end: self.col_end, + }; + + // Code length resets with every line record. + self.code_length = None; + + // Finish the previous record and emit it. The current record is stored so that the + // length can be inferred from subsequent operators or the next line info. + if let Some(last_info) = std::mem::replace(&mut self.last_info, Some(line_info)) { + return Ok(Some(last_info)); + } + } + + Ok(self.last_info.take()) + } +} + +/// An inlined function that can evaluate to line information. +#[derive(Clone, Debug, Default)] +pub struct Inlinee<'a>(InlineeSourceLine<'a>); + +impl<'a> Inlinee<'a> { + /// The index of this inlinee in the `IdInformation` stream (IPI). + pub fn index(&self) -> IdIndex { + self.0.inlinee + } + + /// Returns an iterator over line records for an inline site. + /// + /// Note that line records are not guaranteed to be ordered by source code offset. If a + /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be + /// sorted manually. + pub fn lines( + &self, + parent_offset: PdbInternalSectionOffset, + inline_site: &InlineSiteSymbol<'a>, + ) -> InlineeLineIterator<'a> { + InlineeLineIterator::new(parent_offset, inline_site, self.0) + } +} + +/// An iterator over line information records in a module. +#[derive(Clone, Debug, Default)] +pub struct InlineeIterator<'a> { + inlinee_lines: DebugInlineeLinesIterator<'a>, +} + +impl<'a> InlineeIterator<'a> { + pub(crate) fn parse(data: &'a [u8]) -> Result { + let inlinee_data = DebugSubsectionIterator::new(data) + .find(|sec| Ok(sec.kind == DebugSubsectionKind::InlineeLines))? + .map(|sec| sec.data); + + let inlinee_lines = match inlinee_data { + Some(d) => DebugInlineeLinesSubsection::parse(d)?, + None => DebugInlineeLinesSubsection::default(), + }; + + Ok(Self { + inlinee_lines: inlinee_lines.lines(), + }) + } +} + +impl<'a> FallibleIterator for InlineeIterator<'a> { + type Item = Inlinee<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + match self.inlinee_lines.next() { + Ok(Some(inlinee_line)) => Ok(Some(Inlinee(inlinee_line))), + Ok(None) => Ok(None), + Err(error) => Err(error), + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct FileIterator<'a> { + checksums: DebugFileChecksumsIterator<'a>, +} + +impl<'a> FallibleIterator for FileIterator<'a> { + type Item = FileInfo<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + match self.checksums.next() { + Ok(Some(entry)) => Ok(Some(FileInfo { + name: entry.name, + checksum: entry.checksum, + })), + Ok(None) => Ok(None), + Err(error) => Err(error), + } + } +} + +pub struct LineProgram<'a> { + file_checksums: DebugFileChecksumsSubsection<'a>, + line_sections: Vec>, +} + +impl<'a> LineProgram<'a> { + pub(crate) fn parse(data: &'a [u8]) -> Result { + let mut file_checksums = DebugFileChecksumsSubsection::default(); + let mut line_sections = Vec::new(); + + let mut section_iter = DebugSubsectionIterator::new(data); + while let Some(sec) = section_iter.next()? { + match sec.kind { + DebugSubsectionKind::FileChecksums => { + file_checksums = DebugFileChecksumsSubsection::new(sec.data); + } + DebugSubsectionKind::Lines => { + line_sections.push(DebugLinesSubsection::parse(sec.data)?); + } + _ => {} + } + } + + line_sections.sort_unstable_by_key(Self::lines_key); + + Ok(Self { + file_checksums, + line_sections, + }) + } + + pub(crate) fn lines(&self) -> LineIterator<'_> { + LineIterator { + sections: self.line_sections.iter(), + blocks: DebugLinesBlockIterator::default(), + lines: DebugLinesIterator::default(), + columns: DebugColumnsIterator::default(), + last_info: None, + } + } + + pub(crate) fn lines_for_symbol(&self, offset: PdbInternalSectionOffset) -> LineIterator<'_> { + // Search for the lines subsection that covers the given offset. They are non-overlapping + // and not empty, so there will be at most one match. In most cases, there will be an exact + // match for each symbol. However, ASM sometimes yields line records outside of the stated + // symbol range `[offset, offset+len)`. In this case, search for the section covering the + // offset. + let key = Self::lines_offset_key(offset); + let index_result = self + .line_sections + .binary_search_by_key(&key, Self::lines_key); + + let section = match index_result { + Err(0) => return LineIterator::default(), + Err(i) => self.line_sections[i - 1], + Ok(i) => self.line_sections[i], + }; + + // In the `Err(i)` case, we might have chosen a lines subsection pointing into a different + // section. In this case, bail out. + if section.header.offset.section != offset.section { + return LineIterator::default(); + } + + LineIterator { + sections: [].iter(), + blocks: section.blocks(), + lines: DebugLinesIterator::default(), + columns: DebugColumnsIterator::default(), + last_info: None, + } + } + + pub(crate) fn files(&self) -> FileIterator<'a> { + FileIterator { + checksums: self.file_checksums.entries().unwrap_or_default(), + } + } + + pub(crate) fn get_file_info(&self, index: FileIndex) -> Result> { + // The file index actually contains the byte offset value into the file_checksums + // subsection. Therefore, treat it as the offset. + let mut entries = self.file_checksums.entries_at_offset(index)?; + let entry = entries + .next()? + .ok_or(Error::InvalidFileChecksumOffset(index.0))?; + + Ok(FileInfo { + name: entry.name, + checksum: entry.checksum, + }) + } + + fn lines_offset_key(offset: PdbInternalSectionOffset) -> (u16, u32) { + (offset.section, offset.offset) + } + + fn lines_key(lines: &DebugLinesSubsection<'_>) -> (u16, u32) { + Self::lines_offset_key(lines.header.offset) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::mem; + + use crate::symbol::BinaryAnnotations; + + #[test] + fn test_line_number_header() { + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::align_of::(), 4); + } + + #[test] + fn test_column_number_header() { + assert_eq!(mem::size_of::(), 4); + assert_eq!(mem::align_of::(), 2); + } + + #[test] + fn test_debug_lines_block_header() { + assert_eq!(mem::size_of::(), 12); + assert_eq!(mem::align_of::(), 4); + } + + #[test] + fn test_raw_cross_scope_export() { + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::align_of::(), 4); + } + + #[test] + fn test_iter_lines() { + let data = &[ + 244, 0, 0, 0, 24, 0, 0, 0, 169, 49, 0, 0, 16, 1, 115, 121, 2, 198, 45, 116, 88, 98, + 157, 13, 221, 82, 225, 34, 192, 51, 0, 0, 242, 0, 0, 0, 48, 0, 0, 0, 132, 160, 0, 0, 1, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 128, + 0, 0, 0, 0, 23, 0, 0, 128, 11, 0, 0, 0, 24, 0, 0, 128, + ]; + + let line_program = LineProgram::parse(data).expect("parse line program"); + let lines: Vec<_> = line_program.lines().collect().expect("collect lines"); + + let expected = [ + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xa084, + }, + length: Some(0), + file_index: FileIndex(0x0), + line_start: 22, + line_end: 22, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xa084, + }, + length: Some(11), + file_index: FileIndex(0x0), + line_start: 23, + line_end: 23, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xa08f, + }, + length: Some(1), + file_index: FileIndex(0x0), + line_start: 24, + line_end: 24, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + ]; + + assert_eq!(lines, expected); + } + + #[test] + fn test_lines_for_symbol() { + let data = &[ + 244, 0, 0, 0, 24, 0, 0, 0, 169, 49, 0, 0, 16, 1, 115, 121, 2, 198, 45, 116, 88, 98, + 157, 13, 221, 82, 225, 34, 192, 51, 0, 0, 242, 0, 0, 0, 48, 0, 0, 0, 132, 160, 0, 0, 1, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 128, + 0, 0, 0, 0, 23, 0, 0, 128, 11, 0, 0, 0, 24, 0, 0, 128, + ]; + + let offset = PdbInternalSectionOffset { + section: 0x0001, + offset: 0xa084, + }; + + let line_program = LineProgram::parse(data).expect("parse line program"); + let line = line_program + .lines_for_symbol(offset) + .next() + .expect("get line"); + + let expected = Some(LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xa084, + }, + length: Some(0), + file_index: FileIndex(0x0), + line_start: 22, + line_end: 22, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }); + + assert_eq!(expected, line); + } + + #[test] + fn test_lines_for_symbol_asm() { + // This test is similar to lines_for_symbol, but it tests with an offset that points beyond + // the beginning of a lines subsection. This happens when dealing with MASM. + + let data = &[ + 244, 0, 0, 0, 96, 0, 0, 0, 177, 44, 0, 0, 16, 1, 148, 43, 19, 100, 121, 95, 165, 113, + 45, 169, 112, 53, 233, 149, 174, 133, 0, 0, 248, 44, 0, 0, 16, 1, 54, 176, 28, 14, 163, + 149, 3, 189, 0, 215, 91, 24, 204, 45, 117, 241, 0, 0, 59, 45, 0, 0, 16, 1, 191, 40, + 129, 240, 15, 71, 114, 239, 184, 146, 206, 88, 119, 218, 136, 139, 0, 0, 126, 45, 0, 0, + 16, 1, 175, 252, 248, 34, 196, 152, 31, 107, 144, 61, 83, 41, 122, 95, 140, 123, 0, 0, + 242, 0, 0, 0, 96, 0, 0, 0, 112, 137, 0, 0, 1, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 84, 0, 0, 0, 16, 0, 0, 0, 45, 0, 0, 128, 16, 0, 0, 0, 47, 0, 0, 128, 23, 0, 0, 0, + 48, 0, 0, 128, 26, 0, 0, 0, 49, 0, 0, 128, 30, 0, 0, 0, 50, 0, 0, 128, 35, 0, 0, 0, 51, + 0, 0, 128, 38, 0, 0, 0, 52, 0, 0, 128, 40, 0, 0, 0, 62, 0, 0, 128, 44, 0, 0, 0, 66, 0, + 0, 128, + ]; + + let offset = PdbInternalSectionOffset { + section: 0x0001, + offset: 0x8990, // XXX: section and first line record at 0x0980 + }; + + let line_program = LineProgram::parse(data).expect("parse line program"); + let line = line_program + .lines_for_symbol(offset) + .next() + .expect("get line"); + + let expected = Some(LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x8980, + }, + length: Some(0), + file_index: FileIndex(0x0), + line_start: 45, + line_end: 45, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }); + + assert_eq!(expected, line); + } + + #[test] + fn test_parse_inlinee_lines() { + let data = &[ + 0, 0, 0, 0, 254, 18, 0, 0, 104, 1, 0, 0, 24, 0, 0, 0, 253, 18, 0, 0, 104, 1, 0, 0, 28, + 0, 0, 0, + ]; + + let inlinee_lines = DebugInlineeLinesSubsection::parse(data).expect("parse inlinee lines"); + assert!(!inlinee_lines.header.has_extra_files()); + + let lines: Vec<_> = inlinee_lines + .lines() + .collect() + .expect("collect inlinee lines"); + + let expected = [ + InlineeSourceLine { + inlinee: IdIndex(0x12FE), + file_id: FileIndex(0x168), + line: 24, + extra_files: &[], + }, + InlineeSourceLine { + inlinee: IdIndex(0x12FD), + file_id: FileIndex(0x168), + line: 28, + extra_files: &[], + }, + ]; + + assert_eq!(lines, expected); + } + + #[test] + fn test_parse_inlinee_lines_with_files() { + let data = &[ + 1, 0, 0, 0, 235, 102, 9, 0, 232, 37, 0, 0, 19, 0, 0, 0, 1, 0, 0, 0, 216, 26, 0, 0, 240, + 163, 7, 0, 176, 44, 0, 0, 120, 0, 0, 0, 1, 0, 0, 0, 120, 3, 0, 0, + ]; + + let inlinee_lines = DebugInlineeLinesSubsection::parse(data).expect("parse inlinee lines"); + assert!(inlinee_lines.header.has_extra_files()); + + let lines: Vec<_> = inlinee_lines + .lines() + .collect() + .expect("collect inlinee lines"); + + let expected = [ + InlineeSourceLine { + inlinee: IdIndex(0x966EB), + file_id: FileIndex(0x25e8), + line: 19, + extra_files: &[216, 26, 0, 0], + }, + InlineeSourceLine { + inlinee: IdIndex(0x7A3F0), + file_id: FileIndex(0x2cb0), + line: 120, + extra_files: &[120, 3, 0, 0], + }, + ]; + + assert_eq!(lines, expected) + } + + #[test] + fn test_inlinee_lines() { + // Obtained from a PDB compiling Breakpad's crash_generation_client.obj + + // S_GPROC32: [0001:00000120], Cb: 00000054 + // S_INLINESITE: Parent: 0000009C, End: 00000318, Inlinee: 0x1173 + // S_INLINESITE: Parent: 00000190, End: 000001EC, Inlinee: 0x1180 + // BinaryAnnotations: CodeLengthAndCodeOffset 2 3f CodeLengthAndCodeOffset 3 9 + let inline_site = InlineSiteSymbol { + parent: Some(SymbolIndex(0x190)), + end: SymbolIndex(0x1ec), + inlinee: IdIndex(0x1180), + invocations: None, + annotations: BinaryAnnotations::new(&[12, 2, 63, 12, 3, 9, 0, 0]), + }; + + // Inline site from corresponding DEBUG_S_INLINEELINES subsection: + let inlinee_line = InlineeSourceLine { + inlinee: IdIndex(0x1180), + file_id: FileIndex(0x270), + line: 341, + extra_files: &[], + }; + + // Parent offset from procedure root: + // S_GPROC32: [0001:00000120] + let parent_offset = PdbInternalSectionOffset { + offset: 0x120, + section: 0x1, + }; + + let iter = InlineeLineIterator::new(parent_offset, &inline_site, inlinee_line); + let lines: Vec<_> = iter.collect().expect("collect inlinee lines"); + + let expected = [ + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x015f, + }, + length: Some(2), + file_index: FileIndex(0x270), + line_start: 341, + line_end: 342, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x0168, + }, + length: Some(3), + file_index: FileIndex(0x270), + line_start: 341, + line_end: 342, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + ]; + + assert_eq!(lines, expected); + } + + #[test] + fn test_inlinee_lines_length() { + // Obtained from xul.pdb: + // https://symbols.mozilla.org/xul.pdb/5DCA9FFE1E8BC7FE4C4C44205044422E1/xul.pd_ + // + // 1. Rename to `xul.pdb.cab` and extract with `cabextract` + // 2. Get procedure at SymbolIndex(0x3e3c7f4) + // 3. Get inlinee at SymbolIndex(0x3e51b04) + + let inline_site = InlineSiteSymbol { + parent: Some(SymbolIndex(0x03e5_14dc)), + end: SymbolIndex(0x03e5_1bd0), + inlinee: IdIndex(0xeb476), + invocations: None, + annotations: BinaryAnnotations::new(&[6, 38, 3, 186, 32, 11, 71, 11, 36, 4, 5, 0]), + }; + + // Binary annotations: + // ChangeLineOffset(19), + // ChangeCodeOffset(14880), + // ChangeCodeOffsetAndLineOffset(7, 2), + // ChangeCodeOffsetAndLineOffset(4, 1), + // ChangeCodeLength(5), + + let inlinee_line = InlineeSourceLine { + inlinee: IdIndex(0xeb476), + file_id: FileIndex(0x590), + line: 499, + extra_files: &[], + }; + + let parent_offset = PdbInternalSectionOffset { + section: 0x1, + offset: 0x0453_f100, + }; + + let iter = InlineeLineIterator::new(parent_offset, &inline_site, inlinee_line); + let lines: Vec<_> = iter.collect().expect("collect inlinee lines"); + + let expected = [ + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x0454_2b20, + }, + length: Some(7), + file_index: FileIndex(0x590), + line_start: 518, + line_end: 519, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x0454_2b27, + }, + length: Some(4), + file_index: FileIndex(0x590), + line_start: 520, + line_end: 521, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + LineInfo { + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x0454_2b2b, + }, + length: Some(5), + file_index: FileIndex(0x590), + line_start: 521, + line_end: 522, + column_start: None, + column_end: None, + kind: LineInfoKind::Statement, + }, + ]; + + assert_eq!(lines, expected); + } + + #[repr(align(4))] + struct Align4(T); + + /// Aligned data for parsing cross module imports. + /// + /// When parsing them from the file, alignment is validated during ruintime using + /// `cast_aligned`. If alignment is validated, it throws an error. + const CROSS_MODULE_IMPORT_DATA: Align4<[u8; 76]> = Align4([ + // module 0 + 189, 44, 0, 0, // module name 2CBD + 14, 0, 0, 0, // 14 imports (all IDs, no Types) + 171, 19, 0, 128, // 800013AB + 37, 20, 0, 128, // 80001425 + 161, 19, 0, 128, // 800013A1 + 90, 20, 0, 128, // 8000145A + 159, 19, 0, 128, // 8000139F + 55, 20, 0, 128, // 80001437 + 109, 17, 0, 128, // 8000116D + 238, 17, 0, 128, // 800011EE + 246, 19, 0, 128, // 800013F6 + 69, 20, 0, 128, // 80001445 + 104, 19, 0, 128, // 80001368 + 148, 20, 0, 128, // 80001494 + 195, 20, 0, 128, // 800014C3 + 219, 20, 0, 128, // 800014DB + // module 1 + 21, 222, 0, 0, // module name DE15 + 1, 0, 0, 0, // 1 import (id) + 96, 22, 0, 128, // 80001660 + ]); + + #[test] + fn test_parse_cross_section_imports() { + let sec = DebugCrossScopeImportsSubsection::new(&CROSS_MODULE_IMPORT_DATA.0); + + let modules: Vec<_> = sec.modules().collect().expect("collect imports"); + assert_eq!(modules.len(), 2); + + let module = modules[0]; + assert_eq!(module.get(0), Some(Local(IdIndex(0x8000_13AB)))); + assert_eq!(module.get(13), Some(Local(IdIndex(0x8000_14DB)))); + assert_eq!(module.get::(14), None); + } + + #[test] + fn test_resolve_cross_module_import() { + let sec = DebugCrossScopeImportsSubsection::new(&CROSS_MODULE_IMPORT_DATA.0); + + let imports = CrossModuleImports::from_section(sec).expect("parse section"); + let cross_ref = imports + .resolve_import(IdIndex(0x8000_000A)) + .expect("resolve import"); + + let expected = CrossModuleRef( + // The module index is 0x000 = 1st module. + ModuleRef(StringRef(0x2CBD)), + // The import index is 0x0000A = 11th element. + Local(IdIndex(0x8000_1368)), + ); + + assert_eq!(cross_ref, expected); + } + + #[test] + fn test_resolve_cross_module_import2() { + let sec = DebugCrossScopeImportsSubsection::new(&CROSS_MODULE_IMPORT_DATA.0); + + let imports = CrossModuleImports::from_section(sec).expect("parse section"); + let cross_ref = imports + .resolve_import(IdIndex(0x8010_0000)) + .expect("resolve import"); + + let expected = CrossModuleRef( + // The module index is 0x001 = 2nd module. + ModuleRef(StringRef(0xDE15)), + // The import index is 0x00001 = 1st element. + Local(IdIndex(0x8000_1660)), + ); + + assert_eq!(cross_ref, expected); + } + + const CROSS_MODULE_EXPORT_DATA: Align4<[u8; 32]> = Align4([ + 31, 16, 0, 0, 12, 16, 0, 0, // 101F -> 100C + 32, 16, 0, 0, 79, 34, 0, 0, // 1020 -> 224F + 92, 17, 0, 128, 97, 17, 0, 0, // 8000115C -> 1161 + 109, 17, 0, 128, 98, 17, 0, 0, // 8000116D -> 1162 + ]); + + #[test] + fn test_iter_cross_module_exports() { + let section = DebugCrossScopeExportsSubsection::parse(&CROSS_MODULE_EXPORT_DATA.0) + .expect("parse exports"); + let exports = CrossModuleExports::from_section(section).expect("parse section"); + + let exports: Vec<_> = exports.exports().collect().expect("collect exports"); + + let expected = [ + CrossModuleExport::Type(Local(TypeIndex(0x101F)), TypeIndex(0x100C)), + CrossModuleExport::Type(Local(TypeIndex(0x1020)), TypeIndex(0x224F)), + CrossModuleExport::Id(Local(IdIndex(0x8000_115C)), IdIndex(0x1161)), + CrossModuleExport::Id(Local(IdIndex(0x8000_116D)), IdIndex(0x1162)), + ]; + + assert_eq!(exports, expected); + } + + #[test] + fn test_resolve_cross_module_ref() { + let section = DebugCrossScopeExportsSubsection::parse(&CROSS_MODULE_EXPORT_DATA.0) + .expect("parse exports"); + let exports = CrossModuleExports::from_section(section).expect("parse section"); + + let type_index = exports + .resolve_import(Local(TypeIndex(0x101F))) + .expect("resolve type"); + assert_eq!(type_index, Some(TypeIndex(0x100C))); + + let id_index = exports + .resolve_import(Local(IdIndex(0x8000_115C))) + .expect("resolve id"); + assert_eq!(id_index, Some(IdIndex(0x1161))); + + let missing_index = exports + .resolve_import(Local(TypeIndex(0xFEED))) + .expect("resolve missing"); + assert_eq!(missing_index, None); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/modi/constants.rs b/plugins/pdb-ng/vendor/pdb-rs/src/modi/constants.rs new file mode 100644 index 0000000000..834e3ae272 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/modi/constants.rs @@ -0,0 +1,19 @@ +//! Constants for all versions of the module info stream. +#![allow(unused)] + +/// First explicit signature. +pub const CV_SIGNATURE_C7: u32 = 1; +/// Signature indicating a C11 (VC 5.x) module info stream. Uses 32-bit types. +pub const CV_SIGNATURE_C11: u32 = 2; +/// Signature indicating a C13 (VC 7.x) module info stream. Uses zero terminated names. +pub const CV_SIGNATURE_C13: u32 = 4; + +/// Debug subsection kind for empty subsections. Should be skipped. +pub const DEBUG_S_IGNORE: u32 = 0x8000_0000; +/// Flag indicating that column information is present. +pub const CV_LINES_HAVE_COLUMNS: u16 = 0x1; + +/// Flag indicating the default format of `DEBUG_S_INLINEELINEINFO` +pub const CV_INLINEE_SOURCE_LINE_SIGNATURE: u32 = 0x0; +/// Flag indicating the extended format of `DEBUG_S_INLINEELINEINFO` +pub const CV_INLINEE_SOURCE_LINE_SIGNATURE_EX: u32 = 0x1; diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/modi/mod.rs b/plugins/pdb-ng/vendor/pdb-rs/src/modi/mod.rs new file mode 100644 index 0000000000..cdb2372bec --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/modi/mod.rs @@ -0,0 +1,358 @@ +use std::fmt; + +use crate::common::*; +use crate::dbi::Module; +use crate::msf::Stream; +use crate::symbol::SymbolIter; +use crate::FallibleIterator; + +mod c13; +mod constants; + +pub use c13::{ + CrossModuleExportIter, CrossModuleExports, CrossModuleImports, Inlinee, InlineeIterator, + InlineeLineIterator, +}; + +#[derive(Clone, Copy, Debug)] +enum LinesSize { + C11(usize), + C13(usize), +} + +/// This struct contains data about a single module from its module info stream. +/// +/// The module info stream is where private symbols and line info is stored. +pub struct ModuleInfo<'s> { + stream: Stream<'s>, + symbols_size: usize, + lines_size: LinesSize, +} + +impl<'s> ModuleInfo<'s> { + /// Parses a `ModuleInfo` from it's Module info stream data. + pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Self { + let info = module.info(); + + let lines_size = if info.lines_size > 0 { + LinesSize::C11(info.lines_size as usize) + } else { + LinesSize::C13(info.c13_lines_size as usize) + }; + + let symbols_size = info.symbols_size as usize; + ModuleInfo { + stream, + symbols_size, + lines_size, + } + } + + fn lines_data(&self, size: usize) -> &[u8] { + let start = self.symbols_size as usize; + &self.stream[start..start + size] + } + + /// Get an iterator over the all symbols in this module. + pub fn symbols(&self) -> Result> { + let mut buf = self.stream.parse_buffer(); + buf.truncate(self.symbols_size)?; + if self.symbols_size > 0 { + let sig = buf.parse_u32()?; + if sig != constants::CV_SIGNATURE_C13 { + return Err(Error::UnimplementedFeature( + "Unsupported symbol data format", + )); + } + } + Ok(SymbolIter::new(buf)) + } + + /// Get an iterator over symbols starting at the given index. + pub fn symbols_at(&self, index: SymbolIndex) -> Result> { + let mut iter = self.symbols()?; + iter.seek(index); + Ok(iter) + } + + /// Returns a line program that gives access to file and line information in this module. + pub fn line_program(&self) -> Result> { + let inner = match self.lines_size { + LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")), + LinesSize::C13(size) => { + LineProgramInner::C13(c13::LineProgram::parse(self.lines_data(size))?) + } + }; + + Ok(LineProgram { inner }) + } + + /// Returns an iterator over all inlinees in this module. + /// + /// Inlinees are not guaranteed to be sorted. When requiring random access by `ItemId`, collect + /// them into a mapping structure rather than reiterating multiple times. + pub fn inlinees(&self) -> Result> { + Ok(match self.lines_size { + // C11 does not contain inlinee information. + LinesSize::C11(_size) => Default::default(), + LinesSize::C13(size) => InlineeIterator::parse(self.lines_data(size))?, + }) + } + + /// Returns a table of exports declared by this module. + pub fn exports(&self) -> Result { + Ok(match self.lines_size { + // C11 does not have cross module exports. + LinesSize::C11(_size) => Default::default(), + LinesSize::C13(size) => CrossModuleExports::parse(self.lines_data(size))?, + }) + } + + /// Returns a table of imports of this module. + pub fn imports(&self) -> Result> { + Ok(match self.lines_size { + // C11 does not have cross module imports. + LinesSize::C11(_size) => Default::default(), + LinesSize::C13(size) => CrossModuleImports::parse(self.lines_data(size))?, + }) + } +} + +/// Checksum of a source file's contents. +#[derive(Clone, Debug)] +#[allow(missing_docs)] +pub enum FileChecksum<'a> { + None, + Md5(&'a [u8]), + Sha1(&'a [u8]), + Sha256(&'a [u8]), +} + +impl PartialEq for FileChecksum<'_> { + fn eq(&self, other: &Self) -> bool { + // Manual implementation to allow for None != None. + match (self, other) { + (&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs, + (&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs, + (&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs, + _ => false, + } + } +} + +/// Information record on a source file. +#[derive(Clone, Debug, PartialEq)] +pub struct FileInfo<'a> { + /// Reference to the file name in the [`StringTable`](crate::StringTable). + pub name: StringRef, + + /// Checksum of the file contents. + pub checksum: FileChecksum<'a>, +} + +/// The kind of source construct a line info is referring to. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum LineInfoKind { + /// A source code expression. + Expression, + /// A source code statement. + Statement, +} + +impl Default for LineInfoKind { + fn default() -> Self { + Self::Statement + } +} + +/// Mapping of a source code offset to a source file location. +/// +/// A line entry is always valid up to the subsequent entry. +#[derive(Clone, Debug, PartialEq)] +pub struct LineInfo { + /// Source code offset. + pub offset: PdbInternalSectionOffset, + /// The optional length of the code. + pub length: Option, + /// Index of the source file in this module. + pub file_index: FileIndex, + /// Line number of the start of the covered range. + pub line_start: u32, + /// Line number of the end of the covered range. + pub line_end: u32, + /// Column number of the start of the covered range. + /// + /// This value is only present if column information is provided by the PDB. Even then, it is + /// often zero. + pub column_start: Option, + /// Column number of the end of the covered range. + /// + /// This value is only present if column information is provided by the PDB. Even then, it is + /// often zero. + pub column_end: Option, + /// Kind of this line information. + pub kind: LineInfoKind, +} + +impl LineInfo { + pub(crate) fn set_end(&mut self, end_offset: PdbInternalSectionOffset) { + // This uses PartialOrd which only compares if the section is equal + debug_assert!(self.offset <= end_offset); + + if self.offset <= end_offset { + let length = end_offset.offset - self.offset.offset; + if self.length.map_or(true, |l| l > length) { + self.length = Some(length); + } + } + } +} + +enum LineProgramInner<'a> { + C13(c13::LineProgram<'a>), +} + +/// The `LineProgram` provides access to source line information for a module and its procedures. +pub struct LineProgram<'a> { + inner: LineProgramInner<'a>, +} + +impl<'a> LineProgram<'a> { + /// Returns an iterator over all line information records of this module. + /// + /// Note that line records are not guaranteed to be ordered by source code offset. If a + /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be + /// sorted manually. + pub fn lines(&self) -> LineIterator<'_> { + match self.inner { + LineProgramInner::C13(ref inner) => LineIterator { + inner: LineIteratorInner::C13(inner.lines()), + }, + } + } + + /// Returns an iterator over all file records of this module. + pub fn files(&self) -> FileIterator<'a> { + match self.inner { + LineProgramInner::C13(ref inner) => FileIterator { + inner: FileIteratorInner::C13(inner.files()), + }, + } + } + + /// Returns an iterator over line records for a symbol at the given section offset. + /// + /// This may return line records before the start offset of the symbol. When using ASM, + /// specifically MASM, symbol records may specify a range that is smaller than the actual + /// code generated for this function. `lines_for_symbol` returns all line records covering this + /// function, potentially exceeding this range. + /// + /// Note that line records are not guaranteed to be ordered by source code offset. If a + /// monotonic order by `PdbInternalSectionOffset` or `Rva` is required, the lines have to be + /// sorted manually. + pub fn lines_for_symbol(&self, offset: PdbInternalSectionOffset) -> LineIterator<'_> { + match self.inner { + LineProgramInner::C13(ref inner) => LineIterator { + inner: LineIteratorInner::C13(inner.lines_for_symbol(offset)), + }, + } + } + + /// Looks up file information for the specified file. + pub fn get_file_info(&self, offset: FileIndex) -> Result> { + match self.inner { + LineProgramInner::C13(ref inner) => inner.get_file_info(offset), + } + } +} + +#[derive(Clone, Debug)] +enum LineIteratorInner<'a> { + C13(c13::LineIterator<'a>), +} + +/// An iterator over line information records in a module. +#[derive(Clone, Debug)] +pub struct LineIterator<'a> { + inner: LineIteratorInner<'a>, +} + +impl Default for LineIterator<'_> { + fn default() -> Self { + LineIterator { + inner: LineIteratorInner::C13(Default::default()), + } + } +} + +impl<'a> FallibleIterator for LineIterator<'a> { + type Item = LineInfo; + type Error = Error; + + fn next(&mut self) -> Result> { + match self.inner { + LineIteratorInner::C13(ref mut inner) => inner.next(), + } + } +} + +#[derive(Clone, Debug)] +enum FileIteratorInner<'a> { + C13(c13::FileIterator<'a>), +} + +/// An iterator over file records in a module. +#[derive(Clone, Debug)] +pub struct FileIterator<'a> { + inner: FileIteratorInner<'a>, +} + +impl Default for FileIterator<'_> { + fn default() -> Self { + FileIterator { + inner: FileIteratorInner::C13(Default::default()), + } + } +} + +impl<'a> FallibleIterator for FileIterator<'a> { + type Item = FileInfo<'a>; + type Error = Error; + + fn next(&mut self) -> Result> { + match self.inner { + FileIteratorInner::C13(ref mut inner) => inner.next(), + } + } +} + +/// Named reference to a [`Module`]. +/// +/// The name stored in the [`StringTable`](crate::StringTable) corresponds to the name of the module +/// as returned by [`Module::module_name`]. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct ModuleRef(pub StringRef); + +impl fmt::Display for ModuleRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +/// Reference to a local type or id in another module. +/// +/// See [`ItemIndex::is_cross_module`] for more information. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct CrossModuleRef(pub ModuleRef, pub Local); + +/// A cross module export that can either be a `Type` or an `Id`. +/// +/// Other modules may reference this item using its local ID by declaring it in the cross module +/// imports subsection. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CrossModuleExport { + /// A cross module export of a [`Type`](crate::Type). + Type(Local, TypeIndex), + /// A cross module export of an [`Id`](crate::Id). + Id(Local, IdIndex), +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/msf/mod.rs b/plugins/pdb-ng/vendor/pdb-rs/src/msf/mod.rs new file mode 100644 index 0000000000..e00ca44463 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/msf/mod.rs @@ -0,0 +1,475 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::fmt; +use std::ops::Deref; + +use scroll::{ctx::TryFromCtx, Endian, Pread}; + +use crate::common::*; +use crate::source::*; + +mod page_list; +use self::page_list::PageList; + +type PageNumber = u32; + +#[derive(Debug, Copy, Clone)] +struct Header { + page_size: usize, + maximum_valid_page_number: PageNumber, +} + +impl Header { + fn pages_needed_to_store(&self, bytes: usize) -> usize { + (bytes + (self.page_size - 1)) / self.page_size + } + + fn validate_page_number(&self, page_number: u32) -> Result { + if page_number == 0 || page_number > self.maximum_valid_page_number { + Err(Error::PageReferenceOutOfRange(page_number)) + } else { + Ok(page_number as PageNumber) + } + } +} + +/// Represents a stream table at various stages of access +#[doc(hidden)] +#[derive(Debug)] +enum StreamTable<'s> { + /// The MSF header gives us the size of the table in bytes, and the list of pages (usually one) + /// where we can find the list of pages that contain the stream table. + HeaderOnly { + size_in_bytes: usize, + stream_table_location_location: PageList, + }, + + /// Given the HeaderOnly information, we can do an initial read to get the actual location of + /// the stream table as a PageList. + TableFound { stream_table_location: PageList }, + + // Given the table location, we can access the stream table itself + Available { + stream_table_view: Box>, + }, +} + +fn view<'s>(source: &mut dyn Source<'s>, page_list: &PageList) -> Result>> { + // view it + let view = source.view(page_list.source_slices())?; + + // double check our Source + // if the Source didn't return the requested bits, that's an implementation bug, so + // assert instead of returning an error + assert_eq!(view.as_slice().len(), page_list.len()); + + // done + Ok(view) +} + +mod big { + use super::*; + + pub const MAGIC: &[u8] = b"Microsoft C/C++ MSF 7.00\r\n\x1a\x44\x53\x00\x00\x00"; + + /// The PDB header as stored on disk. + /// + /// See the Microsoft code for reference: + #[repr(C)] + #[derive(Debug, Copy, Clone)] + struct RawHeader { + magic: [u8; 32], + page_size: u32, + free_page_map: u32, + pages_used: u32, + directory_size: u32, + _reserved: u32, + } + + impl<'t> TryFromCtx<'t, Endian> for RawHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + magic: { + let mut tmp = [0; 32]; + this.gread_inout_with(&mut offset, &mut tmp, le)?; + tmp + }, + page_size: this.gread_with(&mut offset, le)?, + free_page_map: this.gread_with(&mut offset, le)?, + pages_used: this.gread_with(&mut offset, le)?, + directory_size: this.gread_with(&mut offset, le)?, + _reserved: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } + } + + #[derive(Debug)] + pub struct BigMSF<'s, S> { + header: Header, + source: S, + stream_table: StreamTable<'s>, + } + + impl<'s, S: Source<'s>> BigMSF<'s, S> { + pub fn new(source: S, header_view: Box>) -> Result> { + let mut buf = ParseBuffer::from(header_view.as_slice()); + let header: RawHeader = buf.parse()?; + + if header.magic != MAGIC { + return Err(Error::UnrecognizedFileFormat); + } + + if header.page_size.count_ones() != 1 + || header.page_size < 0x100 + || header.page_size > (128 * 0x10000) + { + return Err(Error::InvalidPageSize(header.page_size)); + } + + let header_object = Header { + page_size: header.page_size as usize, + maximum_valid_page_number: header.pages_used, + }; + + // calculate how many pages are needed to store the stream table + let size_of_stream_table_in_pages = + header_object.pages_needed_to_store(header.directory_size as usize); + + // now: how many pages are needed to store the list of pages that store the stream table? + // each page entry is a u32, so multiply by four + let size_of_stream_table_page_list_in_pages = + header_object.pages_needed_to_store(size_of_stream_table_in_pages * 4); + + // read the list of stream table page list pages, which immediately follow the header + // yes, this is a stupid level of indirection + let mut stream_table_page_list_page_list = PageList::new(header_object.page_size); + for _ in 0..size_of_stream_table_page_list_in_pages { + let n = buf.parse_u32()?; + stream_table_page_list_page_list.push(header_object.validate_page_number(n)?); + } + + // truncate the stream table location location to the correct size + stream_table_page_list_page_list.truncate(size_of_stream_table_in_pages * 4); + + Ok(BigMSF { + header: header_object, + source, + stream_table: StreamTable::HeaderOnly { + size_in_bytes: header.directory_size as usize, + stream_table_location_location: stream_table_page_list_page_list, + }, + }) + } + + fn find_stream_table(&mut self) -> Result<()> { + let mut new_stream_table: Option> = None; + + if let StreamTable::HeaderOnly { + size_in_bytes, + ref stream_table_location_location, + } = self.stream_table + { + // the header indicated we need to read size_in_pages page numbers from the + // specified PageList. + + // ask to view the location location + let location_location = view(&mut self.source, stream_table_location_location)?; + + // build a PageList + let mut page_list = PageList::new(self.header.page_size); + let mut buf = ParseBuffer::from(location_location.as_slice()); + while !buf.is_empty() { + let n = buf.parse_u32()?; + page_list.push(self.header.validate_page_number(n)?); + } + + page_list.truncate(size_in_bytes); + + // remember what we learned + new_stream_table = Some(StreamTable::TableFound { + stream_table_location: page_list, + }); + } + + if let Some(st) = new_stream_table { + self.stream_table = st; + } + + Ok(()) + } + + fn make_stream_table_available(&mut self) -> Result<()> { + // do the initial read if we must + if let StreamTable::HeaderOnly { .. } = self.stream_table { + self.find_stream_table()?; + } + + // do we need to map the stream table itself? + let mut new_stream_table = None; + if let StreamTable::TableFound { + ref stream_table_location, + } = self.stream_table + { + // ask the source to view it + let stream_table_view = view(&mut self.source, stream_table_location)?; + new_stream_table = Some(StreamTable::Available { stream_table_view }); + } + + if let Some(st) = new_stream_table { + self.stream_table = st; + } + + // stream table is available + assert!(matches!(self.stream_table, StreamTable::Available { .. })); + + Ok(()) + } + + fn look_up_stream(&mut self, stream_number: u32) -> Result { + // ensure the stream table is available + self.make_stream_table_available()?; + + let header = self.header; + + // declare the things we're going to find + let bytes_in_stream: u32; + let page_list: PageList; + + if let StreamTable::Available { + ref stream_table_view, + } = self.stream_table + { + let stream_table_slice = stream_table_view.as_slice(); + let mut stream_table = ParseBuffer::from(stream_table_slice); + + // the stream table is structured as: + // stream_count + // 0..stream_count: size of stream in bytes (0xffffffff indicating "stream does not exist") + // stream 0: PageNumber + // stream 1: PageNumber, PageNumber + // stream 2: PageNumber, PageNumber, PageNumber, PageNumber, PageNumber + // stream 3: PageNumber, PageNumber, PageNumber, PageNumber + // (number of pages determined by number of bytes) + + let stream_count = stream_table.parse_u32()?; + + // check if we've already outworn our welcome + if stream_number >= stream_count { + return Err(Error::StreamNotFound(stream_number)); + } + + // we now have {stream_count} u32s describing the length of each stream + + // walk over the streams before the requested stream + // we need to pay attention to how big each one is, since their page numbers come + // before our page numbers in the stream table + let mut page_numbers_to_skip: usize = 0; + for _ in 0..stream_number { + let bytes = stream_table.parse_u32()?; + if bytes == u32::max_value() { + // stream is not present, ergo nothing to skip + } else { + page_numbers_to_skip += header.pages_needed_to_store(bytes as usize); + } + } + + // read our stream's size + bytes_in_stream = stream_table.parse_u32()?; + if bytes_in_stream == u32::max_value() { + return Err(Error::StreamNotFound(stream_number)); + } + let pages_in_stream = header.pages_needed_to_store(bytes_in_stream as usize); + + // skip the remaining streams' byte counts + let _ = stream_table.take((stream_count - stream_number - 1) as usize * 4)?; + + // skip the preceding streams' page numbers + let _ = stream_table.take((page_numbers_to_skip as usize) * 4)?; + + // we're now at the list of pages for our stream + // accumulate them into a PageList + let mut list = PageList::new(header.page_size); + for _ in 0..pages_in_stream { + let page_number = stream_table.parse_u32()?; + list.push(self.header.validate_page_number(page_number)?); + } + + // truncate to the size of the stream + list.truncate(bytes_in_stream as usize); + + page_list = list; + } else { + unreachable!(); + } + + // done! + Ok(page_list) + } + } + + impl<'s, S: Source<'s>> Msf<'s, S> for BigMSF<'s, S> { + fn get(&mut self, stream_number: u32, limit: Option) -> Result> { + // look up the stream + let mut page_list = self.look_up_stream(stream_number)?; + + // apply any limits we have + if let Some(limit) = limit { + page_list.truncate(limit); + } + + // now that we know where this stream lives, we can view it + let view = view(&mut self.source, &page_list)?; + + // pack it into a Stream + let stream = Stream { source_view: view }; + + Ok(stream) + } + } +} + +mod small { + pub const MAGIC: &[u8] = b"Microsoft C/C++ program database 2.00\r\n\x1a\x4a\x47"; + // TODO: implement SmallMSF +} + +/// Represents a single Stream within the multi-stream file. +#[derive(Debug)] +pub struct Stream<'s> { + source_view: Box>, +} + +impl<'s> Stream<'s> { + #[inline] + pub(crate) fn parse_buffer(&self) -> ParseBuffer<'_> { + let slice = self.source_view.as_slice(); + ParseBuffer::from(slice) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.source_view.as_slice() + } +} + +impl Deref for Stream<'_> { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &Self::Target { + self.as_slice() + } +} + +/// Provides access to a "multi-stream file", which is the container format used by PDBs. +pub trait Msf<'s, S>: fmt::Debug { + /// Accesses a stream by stream number, optionally restricted by a byte limit. + fn get(&mut self, stream_number: u32, limit: Option) -> Result>; +} + +fn header_matches(actual: &[u8], expected: &[u8]) -> bool { + actual.len() >= expected.len() && &actual[0..expected.len()] == expected +} + +pub fn open_msf<'s, S: Source<'s> + 's>(mut source: S) -> Result + 's>> { + // map the header + let mut header_location = PageList::new(4096); + header_location.push(0); + let header_view = match view(&mut source, &header_location) { + Ok(view) => view, + Err(e) => match e { + Error::IoError(x) => { + if x.kind() == std::io::ErrorKind::UnexpectedEof { + return Err(Error::UnrecognizedFileFormat); + } else { + return Err(Error::IoError(x)); + } + } + _ => return Err(e), + }, + }; + + // see if it's a BigMSF + if header_matches(header_view.as_slice(), big::MAGIC) { + // claimed! + let bigmsf = big::BigMSF::new(source, header_view)?; + return Ok(Box::new(bigmsf)); + } + + if header_matches(header_view.as_slice(), small::MAGIC) { + // sorry + return Err(Error::UnimplementedFeature("small MSF file format")); + } + + Err(Error::UnrecognizedFileFormat) +} + +#[cfg(test)] +mod tests { + mod header { + use crate::common::Error; + use crate::msf::open_msf; + use crate::msf::Header; + + #[test] + fn test_pages_needed_to_store() { + let h = Header { + page_size: 4096, + maximum_valid_page_number: 15, + }; + assert_eq!(h.pages_needed_to_store(0), 0); + assert_eq!(h.pages_needed_to_store(1), 1); + assert_eq!(h.pages_needed_to_store(1024), 1); + assert_eq!(h.pages_needed_to_store(2048), 1); + assert_eq!(h.pages_needed_to_store(4095), 1); + assert_eq!(h.pages_needed_to_store(4096), 1); + assert_eq!(h.pages_needed_to_store(4097), 2); + } + + #[test] + fn test_validate_page_number() { + let h = Header { + page_size: 4096, + maximum_valid_page_number: 15, + }; + assert!(matches!( + h.validate_page_number(0), + Err(Error::PageReferenceOutOfRange(0)) + )); + assert!(matches!(h.validate_page_number(1), Ok(1))); + assert!(matches!(h.validate_page_number(2), Ok(2))); + assert!(matches!(h.validate_page_number(14), Ok(14))); + assert!(matches!(h.validate_page_number(15), Ok(15))); + assert!(matches!( + h.validate_page_number(16), + Err(Error::PageReferenceOutOfRange(16)) + )); + assert!(matches!( + h.validate_page_number(17), + Err(Error::PageReferenceOutOfRange(17)) + )); + } + + #[test] + fn test_small_file_unrecognized_file_format() { + let small_file = std::io::Cursor::new(b"\x7FELF"); + + match open_msf(small_file) { + Ok(_) => panic!("4 byte file should not parse as msf"), + Err(e) => match e { + Error::UnrecognizedFileFormat => (), + _ => panic!("4 byte file should parse as unrecognized file format"), + }, + }; + } + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/msf/page_list.rs b/plugins/pdb-ng/vendor/pdb-rs/src/msf/page_list.rs new file mode 100644 index 0000000000..88570b62f2 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/msf/page_list.rs @@ -0,0 +1,289 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::msf::PageNumber; +use crate::source::SourceSlice; + +/// Represents a list of `PageNumbers`, which are likely (but not certainly) sequential, and which +/// will be presented as a slice of `SourceSlice`s. +#[derive(Debug)] +pub struct PageList { + page_size: usize, + source_slices: Vec, + last_page: Option, + truncated: bool, +} + +impl PageList { + /// Create a new PageList for a given page size. + pub fn new(page_size: usize) -> Self { + Self { + page_size, + source_slices: Vec::new(), + last_page: None, + truncated: false, + } + } + + /// Add a page to the PageList. If this page number is sequential with the previous page number, + /// it will be combined into the previous `SourceSlice` for efficiency. + pub fn push(&mut self, page: PageNumber) { + assert!(!self.truncated); + + let is_continuous = match self.last_page { + Some(n) => n.checked_add(1) == Some(page), + None => false, + }; + + if is_continuous { + // extend by one page + debug_assert!(!self.source_slices.is_empty()); + let last_slice = self.source_slices.last_mut().unwrap(); + last_slice.size += self.page_size; + } else { + self.source_slices.push(SourceSlice { + offset: (self.page_size as u64) * u64::from(page), + size: self.page_size, + }); + } + + self.last_page = Some(page); + } + + /// Truncate the `PageList` to request only a certain number of bytes, regardless of how many + /// pages were pushed. Truncatation is optional, but it must be last; `push()` may not be + /// called after `truncate()`. + pub fn truncate(&mut self, bytes: usize) { + let mut bytes = bytes; + let mut new_slices: Vec = Vec::new(); + + for slice in &self.source_slices { + let mut slice: SourceSlice = *slice; + if bytes > 0 { + // we need something from this slice + // restrict this slice to the number of bytes remaining + if slice.size > bytes { + slice.size = bytes; + } + + // keep it + new_slices.push(slice); + + // subtract the number of bytes in this slice + bytes -= slice.size; + } else { + // we're done + break; + } + } + + self.source_slices = new_slices; + self.truncated = true; + } + + /// Return the total length of this PageList. + pub fn len(&self) -> usize { + self.source_slices.iter().fold(0, |acc, s| acc + s.size) + } + + /// Return a slice of SourceSlices. + pub fn source_slices(&self) -> &[SourceSlice] { + self.source_slices.as_slice() + } +} + +#[cfg(test)] +mod tests { + use crate::msf::page_list::*; + use crate::source::SourceSlice; + + #[test] + fn test_push() { + let mut list = PageList::new(4096); + + // PageList should coalesce sequential pages + list.push(0); + list.push(1); + let expected = vec![SourceSlice { + offset: 0, + size: 8192, + }]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 8192); + + // PageList should handle nonsequential runs too + list.push(4); + list.push(5); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 8192, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 16384); + + // ...including nonsequential runs that go backwards + list.push(2); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 8192, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 20480); + + // ...and runs that repeat themselves + list.push(2); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 8192, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 24576); + } + + #[test] + fn test_truncate() { + let mut list = PageList::new(4096); + list.push(0); + list.push(1); + list.push(4); + list.push(5); + list.push(2); + list.push(2); + assert_eq!(list.len(), 24576); + + // truncation should do nothing when it's truncating more than is described + list.truncate(25000); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 8192, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 24576); + + // it's usually employed to reduce the size of the last slice... + list.truncate(24000); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 8192, + }, + SourceSlice { + offset: 8192, + size: 4096, + }, + SourceSlice { + offset: 8192, + size: 3520, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 24000); + + // ...but it should be able to lop off entire slices too + list.truncate(10000); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 1808, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 10000); + + // and again, it shouldn't do anything if we re-truncate to a larger size + list.truncate(12000); + let expected = vec![ + SourceSlice { + offset: 0, + size: 8192, + }, + SourceSlice { + offset: 16384, + size: 1808, + }, + ]; + assert_eq!(list.source_slices(), expected.as_slice()); + assert_eq!(list.len(), 10000); + + // finally, we should be able to truncate the entire PageList down to nothing + list.truncate(0); + assert_eq!(list.source_slices().len(), 0); + assert_eq!(list.len(), 0); + } + + #[test] + #[should_panic] + fn test_push_after_truncate() { + // push after truncate isn't permitted + let mut list = PageList::new(4096); + list.push(5); + list.truncate(2000); + // so far so good + + // bam! + list.push(6); + } + + #[test] + fn push_overflow() { + let mut list = PageList::new(4096); + list.push(u32::MAX); + list.push(u32::MAX); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/omap.rs b/plugins/pdb-ng/vendor/pdb-rs/src/omap.rs new file mode 100644 index 0000000000..a37c061d87 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/omap.rs @@ -0,0 +1,601 @@ +// Copyright 2018 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! Utilities for translating addresses between PDB offsets and _Relative Virtual Addresses_ (RVAs). + +use std::cmp::{self, Ordering}; +use std::fmt; +use std::iter::FusedIterator; +use std::mem; +use std::ops::Range; + +use crate::common::*; +use crate::msf::Stream; +use crate::pe::ImageSectionHeader; + +/// A address translation record from an `OMAPTable`. +/// +/// This record applies to the half-open interval [ `record.source_address`, +/// `next_record.source_address` ). +#[repr(C)] +#[derive(Clone, Copy, Eq, PartialEq)] +pub(crate) struct OMAPRecord { + source_address: u32, + target_address: u32, +} + +impl OMAPRecord { + /// Create a new OMAP record for the given mapping. + pub fn new(source_address: u32, target_address: u32) -> Self { + Self { + source_address: source_address.to_le(), + target_address: target_address.to_le(), + } + } + + /// Returns the address in the source space. + #[inline] + pub fn source_address(self) -> u32 { + u32::from_le(self.source_address) + } + + /// Returns the start of the mapped portion in the target address space. + #[inline] + pub fn target_address(self) -> u32 { + u32::from_le(self.target_address) + } + + /// Translate the given address into the target address space. + #[inline] + fn translate(self, address: u32) -> u32 { + // This method is only to be used internally by the OMAP iterator and lookups. The caller + // must verify that the record is valid to translate an address. + debug_assert!(self.source_address() <= address); + (address - self.source_address()) + self.target_address() + } +} + +impl fmt::Debug for OMAPRecord { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OMAPRecord") + .field( + "source_address", + &format_args!("{:#010x}", self.source_address()), + ) + .field( + "target_address", + &format_args!("{:#010x}", self.target_address()), + ) + .finish() + } +} + +impl PartialOrd for OMAPRecord { + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + self.source_address().partial_cmp(&other.source_address()) + } +} + +impl Ord for OMAPRecord { + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + self.source_address().cmp(&other.source_address()) + } +} + +/// PDBs can contain OMAP tables, which translate relative virtual addresses (RVAs) from one address +/// space into another. +/// +/// For more information on the pratical use of OMAPs, see the [module level documentation] and +/// [`AddressMap`]. A PDB can contain two OMAPs: +/// +/// - `omap_from_src`: A mapping from the original address space to the transformed address space +/// of an optimized binary. Use `PDB::omap_from_src` to obtain an instance of this OMAP. Also, +/// `PdbInternalRva::rva` performs this conversion in a safe manner. +/// - `omap_to_src`: A mapping from the transformed address space back into the original address +/// space of the unoptimized binary. Use `PDB::omap_to_src` to obtain an instace of this OMAP. +/// Also, `Rva::original_rva` performs this conversion in a safe manner. +/// +/// # Structure +/// +/// OMAP tables are dense arrays, sequentially storing `OMAPRecord` structs sorted by source +/// address. +/// +/// Each record applies to a range of addresses: i.e. record N indicates that addresses in the +/// half-open interval [ `record[n].source_address`, `record[n+1].source_address` ) were relocated +/// to a starting address of `record[n].target_address`. If `target_address` is zero, the `lookup()` +/// will return None, since this indicates a non-existent location in the target address space. +/// +/// Given that the table is sorted, lookups by source address can be efficiently serviced using a +/// binary search directly against the underlying data without secondary data structures. This is +/// not the most cache efficient data structure (especially given that half of each cache line is +/// storing target addresses), but given that OMAP tables are an uncommon PDBs feature, the obvious +/// binary search implementation seems appropriate. +/// +/// [module level documentation]: self +pub(crate) struct OMAPTable<'s> { + stream: Stream<'s>, +} + +impl<'s> OMAPTable<'s> { + pub(crate) fn parse(stream: Stream<'s>) -> Result { + match cast_aligned::(stream.as_slice()) { + Some(_) => Ok(OMAPTable { stream }), + None => Err(Error::InvalidStreamLength("OMAP")), + } + } + + /// Returns a direct view onto the records stored in this OMAP table. + #[inline] + pub fn records(&self) -> &[OMAPRecord] { + // alignment is checked during parsing, unwrap is safe. + cast_aligned(self.stream.as_slice()).unwrap() + } + + /// Look up `source_address` to yield a target address. + pub fn lookup(&self, source_address: u32) -> Option { + let records = self.records(); + + let index = match records.binary_search_by_key(&source_address, |r| r.source_address()) { + Ok(i) => i, + Err(0) => return None, + Err(i) => i - 1, + }; + + let record = records[index]; + + // As a special case, `target_address` can be zero, which indicates that the + // `source_address` does not exist in the target address space. + if record.target_address() == 0 { + return None; + } + + Some(record.translate(source_address)) + } + + /// Look up a the range `start..end` and iterate all mapped sub-ranges. + pub fn lookup_range(&self, range: Range) -> RangeIter<'_> { + let Range { start, end } = range; + if end <= start { + return RangeIter::empty(); + } + + let records = self.records(); + let (record, next) = match records.binary_search_by_key(&start, |r| r.source_address()) { + Ok(i) => (records[i], &records[i + 1..]), + // Insert a dummy record no indicate that the range before the first record is invalid. + // The range might still overlap with the first record however, so attempt regular + // iteration. + Err(0) => (OMAPRecord::new(0, 0), records), + Err(i) => (records[i - 1], &records[i..]), + }; + + RangeIter { + records: next.iter(), + record, + addr: start, + end, + } + } +} + +impl fmt::Debug for OMAPTable<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("OMAPTable").field(&self.records()).finish() + } +} + +/// An iterator over mapped target ranges in an OMAP. +pub(crate) struct RangeIter<'t> { + /// Iterator over subsequent OMAP records. + records: std::slice::Iter<'t, OMAPRecord>, + /// The record that spans the current start address. + record: OMAPRecord, + /// The start address of the current subrange. + addr: u32, + /// The final end address of the (last sub-)range. + end: u32, +} + +impl<'t> RangeIter<'t> { + /// Creates a `RangeIter` that does not yield any ranges. + pub fn empty() -> Self { + RangeIter { + records: [].iter(), + record: OMAPRecord::new(0, 0), + addr: 0, + end: 0, + } + } + + /// Creates a `RangeIter` that only yields the specified range. + pub fn identity(range: Range) -> Self { + // Declare the range `start..` as valid with an identity mapping. We cannot use `0..` here + // since the target must be a non-zero value to be recognized as valid mapping. Since there + // are no further records, a single subrange `start..end` will be considered. + RangeIter { + records: [].iter(), + record: OMAPRecord::new(range.start, range.start), + addr: range.start, + end: range.end, + } + } +} + +impl Default for RangeIter<'_> { + fn default() -> Self { + Self::empty() + } +} + +impl Iterator for RangeIter<'_> { + type Item = Range; + + fn next(&mut self) -> Option { + while self.addr < self.end { + // Pull the next record from the list. Since the current record is only valid up to the + // next one, this will determine the end of the current sub slice. If there are no more + // records, create an unmapped dummy record starting at the end of the source range. + let next_record = match self.records.next() { + Some(record) => *record, + None => OMAPRecord::new(self.end, 0), + }; + + // Calculate the bounds of the current subrange and write it back for the next + // iteration. Likewise, remember the next record as address translation base. + let subrange_end = cmp::min(next_record.source_address(), self.end); + let subrange_start = mem::replace(&mut self.addr, subrange_end); + let last_record = mem::replace(&mut self.record, next_record); + + // Check for the validity of this sub-range or skip it silently: + // 2. The sub range covered by the last OMAP record might be empty. This can be an + // artifact of a dummy record used when creating a new iterator. + // 3. A `target_address` of zero indicates an unmapped address range. + if subrange_start >= subrange_end || last_record.target_address() == 0 { + continue; + } + + let translated_start = last_record.translate(subrange_start); + let translated_end = last_record.translate(subrange_end); + return Some(translated_start..translated_end); + } + + None + } +} + +impl FusedIterator for RangeIter<'_> {} + +/// Iterator over [`Rva`] ranges returned by [`AddressMap::rva_ranges`]. +pub struct RvaRangeIter<'t>(RangeIter<'t>); + +impl Iterator for RvaRangeIter<'_> { + type Item = Range; + + fn next(&mut self) -> Option { + self.0.next().map(|range| Rva(range.start)..Rva(range.end)) + } +} + +impl FusedIterator for RvaRangeIter<'_> {} + +/// Iterator over [`PdbInternalRva`] ranges returned by [`AddressMap::internal_rva_ranges`]. +pub struct PdbInternalRvaRangeIter<'t>(RangeIter<'t>); + +impl Iterator for PdbInternalRvaRangeIter<'_> { + type Item = Range; + + fn next(&mut self) -> Option { + self.0 + .next() + .map(|range| PdbInternalRva(range.start)..PdbInternalRva(range.end)) + } +} + +impl FusedIterator for PdbInternalRvaRangeIter<'_> {} + +/// A mapping between addresses and offsets used in the PDB and PE file. +/// +/// To obtain an instace of this address map, call `PDB::address_map`. It will determine the correct +/// translation mode and read all internal state from the PDB. Then use the conversion methods on +/// the address and offset types to translate addresses. +/// +/// # Background +/// +/// Addresses in PDBs are stored as offsets into sections of the PE file. The `AddressMap` contains +/// the PE's section headers to translate between the offsets and virtual addresses relative to the +/// image base (RVAs). +/// +/// Additionally, Microsoft has been reordering the Windows system and application binaries to +/// optimize them for paging reduction, using a toolset reported to be derived from and/or built on +/// top of the [Vulcan research project]. Relatively little else is known about the tools or the +/// methods they use. Looking at Windows system binaries like `ntoskrnl.exe`, it is apparent that +/// their layout has been rearranged, and their respective symbol files contain _OMAP_ re-mapping +/// information. The [Microsoft Binary Technologies Projects] may be involved in this. +/// +/// The internals of this transformation are not well understood. According to [1997 reference +/// material]: +/// +/// > Yet another form of debug information is relatively new and undocumented, except for a few +/// > obscure references in `WINNT.H` and the Win32 SDK help. This type of information is known as +/// > OMAP. Apparently, as part of Microsoft's internal build procedure, small fragments of code in +/// > EXEs and DLLs are moved around to put the most commonly used code at the beginning of the code +/// > section. This presumably keeps the process memory working set as small as possible. However, +/// > when shifting around the blocks of code, the corresponding debug information isn't updated. +/// > Instead, OMAP information is created. It lets symbol table code translate between the original +/// > address in a symbol table and the modified address where the variable or line of code really +/// > exists in memory. +/// +/// # Usage +/// +/// To aid with translating addresses and offsets, this module exposes `AddressMap`, a helper that +/// contains all information to apply the correct translation of any kind of address or offset to +/// another. Due to the rearranging optimizations, there are four types involved: +/// +/// - [`Rva`]: A _Relative Virtual Address_ in the actual binary. This address directly corresponds +/// to instruction pointers seen in stack traces and symbol addresses reported by debuggers. +/// - [`PdbInternalRva`]: An RVA as it would have appeared before the optimization. These RVAs are +/// used in some places and can be converted to an `Rva` in the actual address space. +/// - [`SectionOffset`]: An offset into a section of the actual binary. A `section` member of _n_ +/// refers to section _n - 1_, which makes a section number of _0_ a null pointer. +/// - [`PdbInternalSectionOffset`]: An offset into a section of the original binary. These offsets +/// are used throughout the PDB and can be converted to either `SectionOffset`, or directly to +/// `Rva` in the actual address space. +/// +/// For binaries that have not been optimized that way, the `PdbInternal*` values are effectively +/// equal to their regular counterparts and the conversion between the two are no-ops. Address +/// translation still has to assume different address spaces, which is why there is no direct +/// conversion without an `AddressMap`. +/// +/// # Example +/// +/// ```rust +/// # use pdb::{Rva, FallibleIterator}; +/// # +/// # fn test() -> pdb::Result<()> { +/// # let source = std::fs::File::open("fixtures/self/foo.pdb")?; +/// let mut pdb = pdb::PDB::open(source)?; +/// +/// // Compute the address map once and reuse it +/// let address_map = pdb.address_map()?; +/// +/// # let symbol_table = pdb.global_symbols()?; +/// # let symbol = symbol_table.iter().next()?.unwrap(); +/// # match symbol.parse() { Ok(pdb::SymbolData::Public(pubsym)) => { +/// // Obtain some section offset, eg from a symbol, and convert it +/// match pubsym.offset.to_rva(&address_map) { +/// Some(rva) => { +/// println!("symbol is at {}", rva); +/// # assert_eq!(rva, Rva(26048)); +/// } +/// None => { +/// println!("symbol refers to eliminated code"); +/// # panic!("symbol should exist"); +/// } +/// } +/// # } _ => unreachable!() } +/// # Ok(()) +/// # } +/// # test().unwrap() +/// ``` +/// +/// [Vulcan research project]: https://research.microsoft.com/pubs/69850/tr-2001-50.pdf +/// [Microsoft Binary Technologies Projects]: https://microsoft.com/windows/cse/bit_projects.mspx +/// [1997 reference material]: https://www.microsoft.com/msj/0597/hood0597.aspx +#[derive(Debug, Default)] +pub struct AddressMap<'s> { + pub(crate) original_sections: Vec, + pub(crate) transformed_sections: Option>, + pub(crate) transformed_to_original: Option>, + pub(crate) original_to_transformed: Option>, +} + +impl<'s> AddressMap<'s> { + /// Resolves actual ranges in the executable's address space. + /// + /// The given internal address range might be split up into multiple ranges in the executable. + /// This iterator traverses all mapped ranges in the order of the PDB-internal mapping. All + /// empty or eliminated ranges are skipped. Thus, the iterator might be empty even for non-empty + /// ranges. + pub fn rva_ranges(&self, range: Range) -> RvaRangeIter<'_> { + RvaRangeIter(match self.original_to_transformed { + Some(ref omap) => omap.lookup_range(range.start.0..range.end.0), + None => RangeIter::identity(range.start.0..range.end.0), + }) + } + + /// Resolves actual ranges in the executable's address space. + /// + /// The given address range might correspond to multiple ranges in the PDB-internal address + /// space. This iterator traverses all mapped ranges in the order of the actual RVA mapping. + /// This iterator might be empty even for non-empty ranges if no corresponding original range + /// can be found. + pub fn internal_rva_ranges(&self, range: Range) -> PdbInternalRvaRangeIter<'_> { + PdbInternalRvaRangeIter(match self.transformed_to_original { + Some(ref omap) => omap.lookup_range(range.start.0..range.end.0), + None => RangeIter::identity(range.start.0..range.end.0), + }) + } +} + +fn get_section_offset(sections: &[ImageSectionHeader], address: u32) -> Option<(u16, u32)> { + // Section headers are sorted by virtual_address, so we only need to iterate until we exceed + // the desired address. Since the number of section headers is relatively low, a sequential + // search is the fastest option here. + let (index, section) = sections + .iter() + .take_while(|s| s.virtual_address <= address) + .enumerate() + .find(|(_, s)| address < s.virtual_address + s.size_of_raw_data)?; + + Some((index as u16 + 1, address - section.virtual_address)) +} + +fn get_virtual_address(sections: &[ImageSectionHeader], section: u16, offset: u32) -> Option { + (section as usize) + .checked_sub(1) + .and_then(|i| sections.get(i)) + .map(|section| section.virtual_address + offset) +} + +impl Rva { + /// Resolves a PDB-internal Relative Virtual Address. + /// + /// This address is not necessarily compatible with the executable's address space and should + /// therefore not be used for debugging purposes. + pub fn to_internal_rva(self, translator: &AddressMap<'_>) -> Option { + match translator.transformed_to_original { + Some(ref omap) => omap.lookup(self.0).map(PdbInternalRva), + None => Some(PdbInternalRva(self.0)), + } + } + + /// Resolves the section offset in the PE headers. + /// + /// This is an offset into PE section headers of the executable. To retrieve section offsets + /// used in the PDB, use [`to_internal_offset`](Self::to_internal_offset) instead. + pub fn to_section_offset(self, translator: &AddressMap<'_>) -> Option { + let (section, offset) = match translator.transformed_sections { + Some(ref sections) => get_section_offset(sections, self.0)?, + None => get_section_offset(&translator.original_sections, self.0)?, + }; + + Some(SectionOffset { section, offset }) + } + + /// Resolves the PDB internal section offset. + /// + /// This is the offset value used in the PDB file. To index into the actual PE section headers, + /// use [`to_section_offset`](Self::to_section_offset) instead. + pub fn to_internal_offset( + self, + translator: &AddressMap<'_>, + ) -> Option { + self.to_internal_rva(translator)? + .to_internal_offset(translator) + } +} + +impl PdbInternalRva { + /// Resolves an actual Relative Virtual Address in the executable's address space. + pub fn to_rva(self, translator: &AddressMap<'_>) -> Option { + match translator.original_to_transformed { + Some(ref omap) => omap.lookup(self.0).map(Rva), + None => Some(Rva(self.0)), + } + } + + /// Resolves the section offset in the PE headers. + /// + /// This is an offset into PE section headers of the executable. To retrieve section offsets + /// used in the PDB, use [`to_internal_offset`](Self::to_internal_offset) instead. + pub fn to_section_offset(self, translator: &AddressMap<'_>) -> Option { + self.to_rva(translator)?.to_section_offset(translator) + } + + /// Resolves the PDB internal section offset. + /// + /// This is the offset value used in the PDB file. To index into the actual PE section headers, + /// use [`to_section_offset`](Self::to_section_offset) instead. + pub fn to_internal_offset( + self, + translator: &AddressMap<'_>, + ) -> Option { + let (section, offset) = get_section_offset(&translator.original_sections, self.0)?; + Some(PdbInternalSectionOffset { section, offset }) + } +} + +impl SectionOffset { + /// Resolves an actual Relative Virtual Address in the executable's address space. + pub fn to_rva(self, translator: &AddressMap<'_>) -> Option { + let address = match translator.transformed_sections { + Some(ref sections) => get_virtual_address(sections, self.section, self.offset)?, + None => get_virtual_address(&translator.original_sections, self.section, self.offset)?, + }; + + Some(Rva(address)) + } + + /// Resolves a PDB-internal Relative Virtual Address. + /// + /// This address is not necessarily compatible with the executable's address space and should + /// therefore not be used for debugging purposes. + pub fn to_internal_rva(self, translator: &AddressMap<'_>) -> Option { + self.to_rva(translator)?.to_internal_rva(translator) + } + + /// Resolves the PDB internal section offset. + pub fn to_internal_offset( + self, + translator: &AddressMap<'_>, + ) -> Option { + if translator.transformed_sections.is_none() { + // Fast path to avoid section table lookups + let Self { section, offset } = self; + return Some(PdbInternalSectionOffset { section, offset }); + } + + self.to_internal_rva(translator)? + .to_internal_offset(translator) + } +} + +impl PdbInternalSectionOffset { + /// Resolves an actual Relative Virtual Address in the executable's address space. + pub fn to_rva(self, translator: &AddressMap<'_>) -> Option { + self.to_internal_rva(translator)?.to_rva(translator) + } + + /// Resolves a PDB-internal Relative Virtual Address. + /// + /// This address is not necessarily compatible with the executable's address space and should + /// therefore not be used for debugging purposes. + pub fn to_internal_rva(self, translator: &AddressMap<'_>) -> Option { + get_virtual_address(&translator.original_sections, self.section, self.offset) + .map(PdbInternalRva) + } + + /// Resolves the section offset in the PE headers. + pub fn to_section_offset(self, translator: &AddressMap<'_>) -> Option { + if translator.transformed_sections.is_none() { + // Fast path to avoid section table lookups + let Self { section, offset } = self; + return Some(SectionOffset { section, offset }); + } + + self.to_rva(translator)?.to_section_offset(translator) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::mem; + + #[test] + fn test_omap_record() { + assert_eq!(mem::size_of::(), 8); + assert_eq!(mem::align_of::(), 4); + } + + #[test] + fn test_get_virtual_address() { + let sections = vec![ImageSectionHeader { + virtual_address: 0x1000_0000, + ..Default::default() + }]; + + assert_eq!(get_virtual_address(§ions, 1, 0x1234), Some(0x1000_1234)); + assert_eq!(get_virtual_address(§ions, 2, 0x1234), None); + + // https://github.com/willglynn/pdb/issues/87 + assert_eq!(get_virtual_address(§ions, 0, 0x1234), None); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/pdb.rs b/plugins/pdb-ng/vendor/pdb-rs/src/pdb.rs new file mode 100644 index 0000000000..b92f67150e --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/pdb.rs @@ -0,0 +1,536 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::common::*; +use crate::dbi::{DBIExtraStreams, DBIHeader, DebugInformation, Module}; +use crate::framedata::FrameTable; +use crate::modi::ModuleInfo; +use crate::msf::{self, Msf, Stream}; +use crate::omap::{AddressMap, OMAPTable}; +use crate::pdbi::PDBInformation; +use crate::pe::ImageSectionHeader; +use crate::source::Source; +use crate::strings::StringTable; +use crate::symbol::SymbolTable; +use crate::tpi::{IdInformation, TypeInformation}; + +// Some streams have a fixed stream index. +// http://llvm.org/docs/PDB/index.html + +const PDB_STREAM: u32 = 1; +const TPI_STREAM: u32 = 2; +const DBI_STREAM: u32 = 3; +const IPI_STREAM: u32 = 4; + +/// `PDB` provides access to the data within a PDB file. +/// +/// A PDB file is internally a Multi-Stream File (MSF), composed of multiple independent +/// (and usually discontiguous) data streams on-disk. `PDB` provides lazy access to these data +/// structures, which means the `PDB` accessor methods usually cause disk accesses. +#[derive(Debug)] +pub struct PDB<'s, S> { + /// `msf` provides access to the underlying data streams + msf: Box + 's>, + + /// Memoize the `dbi::Header`, since it contains stream numbers we sometimes need + dbi_header: Option, + + /// Memoize the `dbi::DBIExtraStreams`, since it too contains stream numbers we sometimes need + dbi_extra_streams: Option, +} + +impl<'s, S: Source<'s> + 's> PDB<'s, S> { + /// Create a new `PDB` for a `Source`. + /// + /// `open()` accesses enough of the source file to find the MSF stream table. This usually + /// involves reading the header, a block near the end of the file, and finally the stream table + /// itself. It does not access or validate any of the contents of the rest of the PDB. + /// + /// # Errors + /// + /// * `Error::UnimplementedFeature` if the PDB file predates ~2002 + /// * `Error::UnrecognizedFileFormat` if the `Source` does not appear to be a PDB file + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange`, `Error::InvalidPageSize` if the PDB file seems corrupt + pub fn open(source: S) -> Result> { + Ok(PDB { + msf: msf::open_msf(source)?, + dbi_header: None, + dbi_extra_streams: None, + }) + } + + /// Retrieve the `PDBInformation` for this PDB. + /// + /// The `PDBInformation` object contains the GUID and age fields that can be used to verify + /// that a PDB file matches a binary, as well as the stream indicies of named PDB streams. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain the PDB information stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + pub fn pdb_information(&mut self) -> Result> { + let stream = self.msf.get(PDB_STREAM, None)?; + PDBInformation::parse(stream) + } + + /// Retrieve the `TypeInformation` for this PDB. + /// + /// The `TypeInformation` object owns a `SourceView` for the type information ("TPI") stream. + /// This is usually the single largest stream of the PDB file. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain the type information stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::InvalidTypeInformationHeader` if the type information stream header was not + /// understood + pub fn type_information(&mut self) -> Result> { + let stream = self.msf.get(TPI_STREAM, None)?; + TypeInformation::parse(stream) + } + + /// Retrieve the `IdInformation` for this PDB. + /// + /// The `IdInformation` object owns a `SourceView` for the type information ("IPI") stream. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain the id information stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::InvalidTypeInformationHeader` if the id information stream header was not + /// understood + pub fn id_information(&mut self) -> Result> { + let stream = self.msf.get(IPI_STREAM, None)?; + IdInformation::parse(stream) + } + + /// Retrieve the `DebugInformation` for this PDB. + /// + /// The `DebugInformation` object owns a `SourceView` for the debug information ("DBI") stream. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain a symbol records stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::UnimplementedFeature` if the debug information header predates ~1995 + pub fn debug_information(&mut self) -> Result> { + let stream = self.msf.get(DBI_STREAM, None)?; + let debug_info = DebugInformation::parse(stream)?; + + // Grab its header, since we need that for unrelated operations + self.dbi_header = Some(debug_info.header()); + Ok(debug_info) + } + + fn dbi_header(&mut self) -> Result { + // see if we've already got a header + if let Some(ref h) = self.dbi_header { + return Ok(*h); + } + + // get just the first little bit of the DBI stream + let stream = self.msf.get(DBI_STREAM, Some(1024))?; + let header = DBIHeader::parse(stream)?; + + self.dbi_header = Some(header); + Ok(header) + } + + /// Retrieve the global symbol table for this PDB. + /// + /// The `SymbolTable` object owns a `SourceView` for the symbol records stream. This is usually + /// the second-largest stream of the PDB file. + /// + /// The debug information stream indicates which stream is the symbol records stream, so + /// `global_symbols()` accesses the debug information stream to read the header unless + /// `debug_information()` was called first. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain a symbol records stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// + /// If `debug_information()` was not already called, `global_symbols()` will additionally read + /// the debug information header, in which case it can also return: + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain a debug information stream + /// * `Error::UnimplementedFeature` if the debug information header predates ~1995 + pub fn global_symbols(&mut self) -> Result> { + // the global symbol table is stored in a stream number described by the DBI header + // so, start by getting the DBI header + let dbi_header = self.dbi_header()?; + + // open the appropriate stream, assuming that it is always present. + let stream = self + .raw_stream(dbi_header.symbol_records_stream)? + .ok_or(Error::GlobalSymbolsNotFound)?; + + Ok(SymbolTable::new(stream)) + } + + /// Retrieve the module info stream for a specific `Module`. + /// + /// Some information for each module is stored in a separate stream per-module. `Module`s can be + /// retrieved from the `PDB` by first calling [`debug_information`](Self::debug_information) to + /// get the debug information stream, and then calling [`modules`](DebugInformation::modules) on + /// that. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain this module info stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::UnimplementedFeature` if the module information stream is an unsupported version + /// + /// # Example + /// + /// ``` + /// # use pdb::FallibleIterator; + /// # + /// # fn test() -> pdb::Result<()> { + /// let file = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = pdb::PDB::open(file)?; + /// let dbi = pdb.debug_information()?; + /// let mut modules = dbi.modules()?; + /// if let Some(module) = modules.next()? { + /// println!("module name: {}, object file name: {}", + /// module.module_name(), module.object_file_name()); + /// match pdb.module_info(&module)? { + /// Some(info) => println!("contains {} symbols", info.symbols()?.count()?), + /// None => println!("module information not available"), + /// } + /// } + /// + /// # Ok(()) + /// # } + /// ``` + pub fn module_info<'m>(&mut self, module: &Module<'m>) -> Result>> { + Ok(self + .raw_stream(module.info().stream)? + .map(|stream| ModuleInfo::parse(stream, module))) + } + + /// Retrieve the executable's section headers, as stored inside this PDB. + /// + /// The debug information stream indicates which stream contains the section headers, so + /// `sections()` accesses the debug information stream to read the header unless + /// `debug_information()` was called first. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain section headers + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::UnexpectedEof` if the section headers are truncated mid-record + /// + /// If `debug_information()` was not already called, `sections()` will additionally read + /// the debug information header, in which case it can also return: + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain a debug information stream + /// * `Error::UnimplementedFeature` if the debug information header predates ~1995 + pub fn sections(&mut self) -> Result>> { + let index = self.extra_streams()?.section_headers; + let stream = match self.raw_stream(index)? { + Some(stream) => stream, + None => return Ok(None), + }; + + let mut buf = stream.parse_buffer(); + let mut headers = Vec::with_capacity(buf.len() / 40); + while !buf.is_empty() { + headers.push(ImageSectionHeader::parse(&mut buf)?); + } + + Ok(Some(headers)) + } + + /// Retrieve the global frame data table. + /// + /// This table describes the stack frame layout for functions from all modules in the PDB. Not + /// every function in the image file must have FPO information defined for it. Those functions + /// that do not have FPO information are assumed to have normal stack frames. + /// + /// If this PDB does not contain frame data, the returned table is empty. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain the referenced streams + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// + /// # Example + /// + /// ```rust + /// # use pdb::{PDB, Rva, FallibleIterator}; + /// # + /// # fn test() -> pdb::Result<()> { + /// # let source = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = PDB::open(source)?; + /// + /// // Read the tables once and reuse them + /// let address_map = pdb.address_map()?; + /// let frame_table = pdb.frame_table()?; + /// let mut frames = frame_table.iter(); + /// + /// // Iterate frame data in internal RVA order + /// while let Some(frame) = frames.next()? { + /// println!("{:#?}", frame); + /// } + /// # Ok(()) + /// # } + /// # test().unwrap() + /// ``` + pub fn frame_table(&mut self) -> Result> { + let extra = self.extra_streams()?; + let old_stream = self.raw_stream(extra.fpo)?; + let new_stream = self.raw_stream(extra.framedata)?; + FrameTable::parse(old_stream, new_stream) + } + + pub(crate) fn original_sections(&mut self) -> Result>> { + let index = self.extra_streams()?.original_section_headers; + let stream = match self.raw_stream(index)? { + Some(stream) => stream, + None => return Ok(None), + }; + + let mut buf = stream.parse_buffer(); + let mut headers = Vec::with_capacity(buf.len() / 40); + while !buf.is_empty() { + headers.push(ImageSectionHeader::parse(&mut buf)?); + } + + Ok(Some(headers)) + } + + pub(crate) fn omap_from_src(&mut self) -> Result>> { + let index = self.extra_streams()?.omap_from_src; + match self.raw_stream(index)? { + Some(stream) => OMAPTable::parse(stream).map(Some), + None => Ok(None), + } + } + + pub(crate) fn omap_to_src(&mut self) -> Result>> { + let index = self.extra_streams()?.omap_to_src; + match self.raw_stream(index)? { + Some(stream) => OMAPTable::parse(stream).map(Some), + None => Ok(None), + } + } + + /// Build a map translating between different kinds of offsets and virtual addresses. + /// + /// For more information on address translation, see [`AddressMap`]. + /// + /// This reads `omap_from_src` and either `original_sections` or `sections` from this PDB and + /// chooses internally which strategy to use for resolving RVAs. Consider to reuse this instance + /// for multiple translations. + /// + /// # Errors + /// + /// * `Error::OmapNotFound` if an OMAP is required for translation but missing + /// * `Error::StreamNotFound` if the PDB somehow does not contain section headers + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::UnexpectedEof` if the section headers are truncated mid-record + /// + /// If `debug_information()` was not already called, `omap_table()` will additionally read the + /// debug information header, in which case it can also return: + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain a debug information stream + /// * `Error::UnimplementedFeature` if the debug information header predates ~1995 + /// + /// # Example + /// + /// ```rust + /// # use pdb::{Rva, FallibleIterator}; + /// # + /// # fn test() -> pdb::Result<()> { + /// # let source = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = pdb::PDB::open(source)?; + /// + /// // Compute the address map once and reuse it + /// let address_map = pdb.address_map()?; + /// + /// # let symbol_table = pdb.global_symbols()?; + /// # let symbol = symbol_table.iter().next()?.unwrap(); + /// # match symbol.parse() { Ok(pdb::SymbolData::Public(pubsym)) => { + /// // Obtain some section offset, eg from a symbol, and convert it + /// match pubsym.offset.to_rva(&address_map) { + /// Some(rva) => { + /// println!("symbol is at {}", rva); + /// # assert_eq!(rva, Rva(26048)); + /// } + /// None => { + /// println!("symbol refers to eliminated code"); + /// # panic!("symbol should exist"); + /// } + /// } + /// # } _ => unreachable!() } + /// # Ok(()) + /// # } + /// # test().unwrap() + /// ``` + pub fn address_map(&mut self) -> Result> { + let sections = self.sections()?.unwrap_or_default(); + Ok(match self.original_sections()? { + Some(original_sections) => { + let omap_from_src = self.omap_from_src()?.ok_or(Error::AddressMapNotFound)?; + let omap_to_src = self.omap_to_src()?.ok_or(Error::AddressMapNotFound)?; + + AddressMap { + original_sections, + transformed_sections: Some(sections), + original_to_transformed: Some(omap_from_src), + transformed_to_original: Some(omap_to_src), + } + } + None => AddressMap { + original_sections: sections, + transformed_sections: None, + original_to_transformed: None, + transformed_to_original: None, + }, + }) + } + + /// Retrieve the global string table of this PDB. + /// + /// Long strings, such as file names, are stored in a global deduplicated string table. They are + /// referred to by the [`StringRef`] type, which contains an offset into that table. Strings in + /// the table are stored as null-terminated C strings. Modern PDBs only store valid UTF-8 data + /// in the string table, but for older types a decoding might be necessary. + /// + /// The string table offers cheap zero-copy access to the underlying string data. It is + /// therefore cheap to build. + /// + /// # Example + /// + /// ``` + /// # use pdb::{FallibleIterator, StringRef, PDB}; + /// # + /// # fn test() -> pdb::Result<()> { + /// # let file = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = PDB::open(file)?; + /// let strings = pdb.string_table()?; + /// + /// // obtain a string ref somehow + /// # let string_ref = StringRef(0); + /// let raw_string = strings.get(string_ref)?; + /// println!("{}", raw_string.to_string()); + /// + /// // alternatively, use convenience methods + /// println!("{}", string_ref.to_string_lossy(&strings)?); + /// + /// # Ok(()) + /// # } + /// ``` + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB somehow does not contain section headers + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// * `Error::UnexpectedEof` if the string table ends prematurely + pub fn string_table(&mut self) -> Result> { + let stream = self.named_stream(b"/names")?; + StringTable::parse(stream) + } + + /// Retrieve a stream by its index to read its contents as bytes. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain this stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + /// + /// # Example + /// + /// ``` + /// # fn test() -> pdb::Result<()> { + /// let file = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = pdb::PDB::open(file)?; + /// // This is the index of the "mystream" stream that was added using pdbstr.exe. + /// let s = pdb.raw_stream(pdb::StreamIndex(208))?.expect("stream exists"); + /// assert_eq!(s.as_slice(), b"hello world\n"); + /// # Ok(()) + /// # } + /// ``` + pub fn raw_stream(&mut self, index: StreamIndex) -> Result>> { + match index.msf_number() { + Some(number) => self.msf.get(number, None).map(Some), + None => Ok(None), + } + } + + /// Retrieve a stream by its name, as declared in the PDB info stream. + /// + /// # Errors + /// + /// * `Error::StreamNameNotFound` if the PDB does not specify a stream with that name + /// * `Error::StreamNotFound` if the PDB does not contain the stream referred to + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + pub fn named_stream(&mut self, name: &[u8]) -> Result> { + let info = self.pdb_information()?; + let names = info.stream_names()?; + for named_stream in &names { + if named_stream.name.as_bytes() == name { + return self + .raw_stream(named_stream.stream_id)? + .ok_or(Error::StreamNameNotFound); + } + } + Err(Error::StreamNameNotFound) + } + + /// Loads the Optional Debug Header Stream, which contains offsets into extra streams. + /// + /// this stream is always returned, but its members are all optional depending on the data + /// present in the PDB. + /// + /// The optional header begins at offset 0 immediately after the EC Substream ends. + fn extra_streams(&mut self) -> Result { + if let Some(extra) = self.dbi_extra_streams { + return Ok(extra); + } + + // Parse and grab information on extra streams, since we might also need that + let debug_info = self.debug_information()?; + let extra = DBIExtraStreams::new(&debug_info)?; + self.dbi_extra_streams = Some(extra); + + Ok(extra) + } +} + +impl StreamIndex { + /// Load the raw data of this stream from the PDB. + /// + /// Returns `None` if this index is none. Otherwise, this will try to read the stream from the + /// PDB, which might fail if the stream is missing. + /// + /// # Errors + /// + /// * `Error::StreamNotFound` if the PDB does not contain this stream + /// * `Error::IoError` if returned by the `Source` + /// * `Error::PageReferenceOutOfRange` if the PDB file seems corrupt + pub fn get<'s, S>(self, pdb: &mut PDB<'s, S>) -> Result>> + where + S: Source<'s> + 's, + { + pdb.raw_stream(self) + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/pdbi.rs b/plugins/pdb-ng/vendor/pdb-rs/src/pdbi.rs new file mode 100644 index 0000000000..542842a343 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/pdbi.rs @@ -0,0 +1,186 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::convert::TryInto; +use std::mem; + +use uuid::Uuid; + +use crate::common::*; +use crate::dbi::HeaderVersion; +use crate::msf::*; + +/// A PDB info stream header parsed from a stream. +/// +/// The [PDB information stream] contains the GUID and age fields that can be used to +/// verify that a PDB file matches a specific binary, as well a list of named PDB streams +/// with their stream indices. +/// +/// [PDB information stream]: http://llvm.org/docs/PDB/PdbStream.html +#[derive(Debug)] +pub struct PDBInformation<'s> { + /// The version of the PDB format in use. + pub version: HeaderVersion, + /// A 32-bit timestamp. + pub signature: u32, + /// The number of times this PDB file has been written. + /// + /// This number is bumped by the linker and other tools every time the PDB is modified. It does + /// not necessarily correspond to the age declared in the image. Consider using + /// [`DebugInformation::age`](crate::DebugInformation::age) for a better match. + /// + /// This PDB matches an image, if the `guid` values match and the PDB age is equal or higher + /// than the image's age. + pub age: u32, + /// A `Uuid` generated when this PDB file was created that should uniquely identify it. + pub guid: Uuid, + /// The offset of the start of the stream name data within the stream. + pub names_offset: usize, + /// The size of the stream name data, in bytes. + pub names_size: usize, + stream: Stream<'s>, +} + +impl<'s> PDBInformation<'s> { + /// Parses a `PDBInformation` from raw stream data. + pub(crate) fn parse(stream: Stream<'s>) -> Result { + let (version, signature, age, guid, names_size, names_offset) = { + let mut buf = stream.parse_buffer(); + let version = From::from(buf.parse_u32()?); + let signature = buf.parse_u32()?; + let age = buf.parse_u32()?; + let guid = Uuid::from_fields( + buf.parse_u32()?, + buf.parse_u16()?, + buf.parse_u16()?, + buf.take(8)?.try_into().unwrap(), + ); + let names_size = buf.parse_u32()? as usize; + let names_offset = buf.pos(); + (version, signature, age, guid, names_size, names_offset) + }; + + Ok(PDBInformation { + version, + signature, + age, + guid, + names_size, + names_offset, + stream, + }) + } + + /// Get a `StreamNames` object that can be used to iterate over named streams contained + /// within the PDB file. + /// + /// This can be used to look up certain PDB streams by name. + /// + /// # Example + /// + /// ``` + /// # use pdb::FallibleIterator; + /// # + /// # fn test() -> pdb::Result<()> { + /// let file = std::fs::File::open("fixtures/self/foo.pdb")?; + /// let mut pdb = pdb::PDB::open(file)?; + /// let info = pdb.pdb_information()?; + /// let names = info.stream_names()?; + /// let mut v: Vec<_> = names.iter().map(|n| n.name.to_string()).collect(); + /// v.sort(); + /// assert_eq!(&v, &["mystream", "/LinkInfo", "/names", "/src/headerblock"]); + /// # Ok(()) + /// # } + /// ``` + pub fn stream_names(&self) -> Result> { + // The names map is part of the PDB info stream that provides a mapping from stream names to + // stream indicies. Its [format on disk](1) is somewhat complicated, consisting of a block of + // data comprising the names as null-terminated C strings, followed by a map of stream indices + // to the offset of their names within the names block. + // + // [The map itself](2) is stored as a 32-bit count of the number of entries, followed by a + // 32-bit value that gives the number of bytes taken up by the entries themselves, followed by + // two sets: one for names that are present in this PDB, and one for names that have been + // deleted, followed by the map entries, each of which is a pair of 32-bit values consisting of + // an offset into the names block and a stream ID. + // + // [The two sets](3) are each stored as a [bit array](4), which consists of a 32-bit count, and + // then that many 32-bit words containing the bits in the array. + // + // [1]: https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/include/nmtni.h#L76 + // [2]: https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/include/map.h#L474 + // [3]: https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/include/iset.h#L62 + // [4]: https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/include/array.h#L209 + + let mut names = vec![]; + let mut buf = self.stream.parse_buffer(); + + // Seek forward to the name map. + buf.take(self.names_offset + self.names_size)?; + let count = buf.parse_u32()?; + // We don't actually use most of these. + let _entries_size = buf.parse_u32()?; + let ok_words = buf.parse_u32()?; + let _ok_bits = buf.take(ok_words as usize * mem::size_of::())?; + let deleted_words = buf.parse_u32()?; + let _deleted_bits = buf.take(deleted_words as usize * mem::size_of::())?; + + // Skip over the header here. + let mut names_reader = self.stream.parse_buffer(); + names_reader.take(self.names_offset)?; + // And take just the name data. + let names_buf = names_reader.take(self.names_size)?; + for _ in 0..count { + let name_offset = buf.parse_u32()? as usize; + let stream_id = StreamIndex(buf.parse_u32()? as u16); + let name = ParseBuffer::from(&names_buf[name_offset..]).parse_cstring()?; + names.push(StreamName { name, stream_id }); + } + + Ok(StreamNames { names }) + } +} + +/// A named stream contained within the PDB file. +#[derive(Debug)] +pub struct StreamName<'n> { + /// The stream's name. + pub name: RawString<'n>, + /// The index of this stream. + pub stream_id: StreamIndex, +} + +/// A list of named streams contained within the PDB file. +/// +/// Call [`StreamNames::iter`] to iterate over the names. The iterator produces [`StreamName`] +/// objects. +#[derive(Debug)] +pub struct StreamNames<'s> { + /// The list of streams and their names. + names: Vec>, +} + +/// An iterator over [`StreamName`]s. +pub type NameIter<'a, 'n> = std::slice::Iter<'a, StreamName<'n>>; + +impl<'s> StreamNames<'s> { + /// Return an iterator over named streams and their stream indices. + #[inline] + pub fn iter(&self) -> NameIter<'_, 's> { + self.names.iter() + } +} + +impl<'a, 's> IntoIterator for &'a StreamNames<'s> { + type Item = &'a StreamName<'s>; + type IntoIter = NameIter<'a, 's>; + + #[inline] + fn into_iter(self) -> Self::IntoIter { + self.names.iter() + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/pe.rs b/plugins/pdb-ng/vendor/pdb-rs/src/pe.rs new file mode 100644 index 0000000000..d59cfc3c93 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/pe.rs @@ -0,0 +1,471 @@ +// Copyright 2018 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +//! Definitions for PE headers contained in PDBs. + +// PDBs contain PE section headers in one or two streams. `pdb::pe` is responsible for parsing them. + +use std::fmt; + +use scroll::ctx::TryFromCtx; +use scroll::Endian; + +use crate::common::*; + +/// The section should not be padded to the next boundary. This flag is +/// obsolete and is replaced by `IMAGE_SCN_ALIGN_1BYTES`. +const IMAGE_SCN_TYPE_NO_PAD: u32 = 0x00000008; +/// The section contains executable code. +const IMAGE_SCN_CNT_CODE: u32 = 0x00000020; +/// The section contains initialized data. +const IMAGE_SCN_CNT_INITIALIZED_DATA: u32 = 0x00000040; +/// The section contains uninitialized data. +const IMAGE_SCN_CNT_UNINITIALIZED_DATA: u32 = 0x00000080; +/// Reserved. +const IMAGE_SCN_LNK_OTHER: u32 = 0x00000100; +/// The section contains comments or other information. This is valid only for object files. +const IMAGE_SCN_LNK_INFO: u32 = 0x00000200; +/// The section will not become part of the image. This is valid only for object files. +const IMAGE_SCN_LNK_REMOVE: u32 = 0x00000800; +/// The section contains COMDAT data. This is valid only for object files. +const IMAGE_SCN_LNK_COMDAT: u32 = 0x00001000; +/// Reset speculative exceptions handling bits in the TLB entries for this section. +const IMAGE_SCN_NO_DEFER_SPEC_EXC: u32 = 0x00004000; +/// The section contains data referenced through the global pointer. +const IMAGE_SCN_GPREL: u32 = 0x00008000; +/// Reserved. +const IMAGE_SCN_MEM_PURGEABLE: u32 = 0x00020000; +/// Reserved. +const IMAGE_SCN_MEM_LOCKED: u32 = 0x00040000; +/// Reserved. +const IMAGE_SCN_MEM_PRELOAD: u32 = 0x00080000; +/// Align data on a 1-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_1BYTES: u32 = 0x00100000; +/// Align data on a 2-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_2BYTES: u32 = 0x00200000; +/// Align data on a 4-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_4BYTES: u32 = 0x00300000; +/// Align data on a 8-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_8BYTES: u32 = 0x00400000; +/// Align data on a 16-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_16BYTES: u32 = 0x00500000; +/// Align data on a 32-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_32BYTES: u32 = 0x00600000; +/// Align data on a 64-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_64BYTES: u32 = 0x00700000; +/// Align data on a 128-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_128BYTES: u32 = 0x00800000; +/// Align data on a 256-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_256BYTES: u32 = 0x00900000; +/// Align data on a 512-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_512BYTES: u32 = 0x00A00000; +/// Align data on a 1024-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_1024BYTES: u32 = 0x00B00000; +/// Align data on a 2048-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_2048BYTES: u32 = 0x00C00000; +/// Align data on a 4096-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_4096BYTES: u32 = 0x00D00000; +/// Align data on a 8192-byte boundary. This is valid only for object files. +const IMAGE_SCN_ALIGN_8192BYTES: u32 = 0x00E00000; +/// The section contains extended relocations. The count of relocations for the +/// section exceeds the 16 bits that is reserved for it in the section header. +/// If the `number_of_relocations` field in the section header is `0xffff`, the +/// actual relocation count is stored in the `virtual_address` field of the first +/// relocation. It is an error if `IMAGE_SCN_LNK_NRELOC_OVFL` is set and there +/// are fewer than `0xffff` relocations in the section. +const IMAGE_SCN_LNK_NRELOC_OVFL: u32 = 0x01000000; +/// The section can be discarded as needed. +const IMAGE_SCN_MEM_DISCARDABLE: u32 = 0x02000000; +/// The section cannot be cached. +const IMAGE_SCN_MEM_NOT_CACHED: u32 = 0x04000000; +/// The section cannot be paged. +const IMAGE_SCN_MEM_NOT_PAGED: u32 = 0x08000000; +/// The section can be shared in memory. +const IMAGE_SCN_MEM_SHARED: u32 = 0x10000000; +/// The section can be executed as code. +const IMAGE_SCN_MEM_EXECUTE: u32 = 0x20000000; +/// The section can be read. +const IMAGE_SCN_MEM_READ: u32 = 0x40000000; +/// The section can be written to. +const IMAGE_SCN_MEM_WRITE: u32 = 0x80000000; + +/// Characteristic flags of an [`ImageSectionHeader`]. +/// +/// These are defined by Microsoft as [`IMAGE_SCN_`] constants. +/// +/// [`IMAGE_SCN_`]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_section_header +#[derive(Clone, Copy, Eq, Default, PartialEq)] +pub struct SectionCharacteristics(pub u32); + +impl SectionCharacteristics { + /// The section contains executable code. + pub fn executable(self) -> bool { + (self.0 & IMAGE_SCN_CNT_CODE) > 0 + } + + /// The section contains initialized data. + pub fn initialized_data(self) -> bool { + (self.0 & IMAGE_SCN_CNT_INITIALIZED_DATA) > 0 + } + + /// The section contains uninitialized data. + pub fn uninitialized_data(self) -> bool { + (self.0 & IMAGE_SCN_CNT_UNINITIALIZED_DATA) > 0 + } + + /// Reserved. + pub fn other(self) -> bool { + (self.0 & IMAGE_SCN_LNK_OTHER) > 0 + } + + /// The section contains comments or other information. This is valid only for object files. + pub fn info(self) -> bool { + (self.0 & IMAGE_SCN_LNK_INFO) > 0 + } + + /// The section will not become part of the image. This is valid only for object files. + pub fn remove(self) -> bool { + (self.0 & IMAGE_SCN_LNK_REMOVE) > 0 + } + + /// The section contains COMDAT data. This is valid only for object files. + pub fn comdat(self) -> bool { + (self.0 & IMAGE_SCN_LNK_COMDAT) > 0 + } + + /// Reset speculative exceptions handling bits in the TLB entries for this section. + pub fn defer_speculative_exceptions(self) -> bool { + (self.0 & IMAGE_SCN_NO_DEFER_SPEC_EXC) > 0 + } + + /// The section contains data referenced through the global pointer. + pub fn global_pointer_relative(self) -> bool { + (self.0 & IMAGE_SCN_GPREL) > 0 + } + + /// Reserved. + pub fn purgeable(self) -> bool { + (self.0 & IMAGE_SCN_MEM_PURGEABLE) > 0 + } + + /// Reserved. + pub fn locked(self) -> bool { + (self.0 & IMAGE_SCN_MEM_LOCKED) > 0 + } + + /// Reserved. + pub fn preload(self) -> bool { + (self.0 & IMAGE_SCN_MEM_PRELOAD) > 0 + } + + /// Alignment for section data. + /// + /// This is valid only for object files. Returns `Some` if alignment is specified, and `None` if + /// no alignment is specified. An alignment of `Some(1)` means that the section should not be + /// padded to a boundary. + pub fn alignment(self) -> Option { + // Mask covering all align values and IMAGE_SCN_TYPE_NO_PAD. + match self.0 & 0x00F00008 { + self::IMAGE_SCN_ALIGN_1BYTES => Some(1), + self::IMAGE_SCN_ALIGN_2BYTES => Some(2), + self::IMAGE_SCN_ALIGN_4BYTES => Some(4), + self::IMAGE_SCN_ALIGN_8BYTES => Some(8), + self::IMAGE_SCN_ALIGN_16BYTES => Some(16), + self::IMAGE_SCN_ALIGN_32BYTES => Some(32), + self::IMAGE_SCN_ALIGN_64BYTES => Some(64), + self::IMAGE_SCN_ALIGN_128BYTES => Some(128), + self::IMAGE_SCN_ALIGN_256BYTES => Some(256), + self::IMAGE_SCN_ALIGN_512BYTES => Some(512), + self::IMAGE_SCN_ALIGN_1024BYTES => Some(1024), + self::IMAGE_SCN_ALIGN_2048BYTES => Some(2048), + self::IMAGE_SCN_ALIGN_4096BYTES => Some(4096), + self::IMAGE_SCN_ALIGN_8192BYTES => Some(8192), + self::IMAGE_SCN_TYPE_NO_PAD => Some(1), + _ => None, + } + } + + /// The section contains extended relocations. + /// + /// The count of relocations for the section exceeds the 16 bits that is reserved for it in the + /// section header. If the [`number_of_relocations`](ImageSectionHeader::number_of_relocations) + /// field in the section header is `0xffff`, the actual relocation count is stored in the + /// `virtual_address` field of the first relocation. It is an error if this flag is set and + /// there are fewer than `0xffff` relocations in the section. + pub fn lnk_nreloc_ovfl(self) -> bool { + (self.0 & IMAGE_SCN_LNK_NRELOC_OVFL) > 0 + } + + /// The section can be discarded as needed. + pub fn discardable(self) -> bool { + (self.0 & IMAGE_SCN_MEM_DISCARDABLE) > 0 + } + + /// The section cannot be cached. + pub fn not_cached(self) -> bool { + (self.0 & IMAGE_SCN_MEM_NOT_CACHED) > 0 + } + + /// The section cannot be paged. + pub fn not_paged(self) -> bool { + (self.0 & IMAGE_SCN_MEM_NOT_PAGED) > 0 + } + + /// The section can be shared in memory. + pub fn shared(self) -> bool { + (self.0 & IMAGE_SCN_MEM_SHARED) > 0 + } + + /// The section can be executed as code. + pub fn execute(self) -> bool { + (self.0 & IMAGE_SCN_MEM_EXECUTE) > 0 + } + + /// The section can be read. + pub fn read(self) -> bool { + (self.0 & IMAGE_SCN_MEM_READ) > 0 + } + + /// The section can be written to. + pub fn write(self) -> bool { + (self.0 & IMAGE_SCN_MEM_WRITE) > 0 + } +} + +impl fmt::Debug for SectionCharacteristics { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + f.debug_struct("ImageCharacteristics") + .field("executable", &self.executable()) + .field("initialized_data", &self.initialized_data()) + .field("uninitialized_data", &self.uninitialized_data()) + .field("info", &self.info()) + .field("remove", &self.remove()) + .field("comdat", &self.comdat()) + .field( + "defer_speculative_exceptions", + &self.defer_speculative_exceptions(), + ) + .field("global_pointer_relative", &self.global_pointer_relative()) + .field("purgeable", &self.purgeable()) + .field("locked", &self.locked()) + .field("preload", &self.preload()) + .field("alignment", &self.alignment()) + .field("lnk_nreloc_ovfl", &self.lnk_nreloc_ovfl()) + .field("discardable", &self.discardable()) + .field("not_cached", &self.not_cached()) + .field("not_paged", &self.not_paged()) + .field("shared", &self.shared()) + .field("execute", &self.execute()) + .field("read", &self.read()) + .field("write", &self.write()) + .finish() + } else { + f.debug_tuple("ImageCharacteristics") + .field(&format_args!("{:#x}", self.0)) + .finish() + } + } +} + +impl<'t> TryFromCtx<'t, Endian> for SectionCharacteristics { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let (value, size) = u32::try_from_ctx(this, le)?; + Ok((SectionCharacteristics(value), size)) + } +} + +/// A PE `IMAGE_SECTION_HEADER`, as described in [the Microsoft documentation](https://msdn.microsoft.com/en-us/library/windows/desktop/ms680341(v=vs.85).aspx). +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub struct ImageSectionHeader { + /// An 8-byte, null-padded UTF-8 string. There is no terminating null character if the string is + /// exactly eight characters long. For longer names, this member contains a forward slash (`/`) + /// followed by an ASCII representation of a decimal number that is an offset into the string + /// table. Executable images do not use a string table and do not support section names longer + /// than eight characters. + pub name: [u8; 8], + + /// The total size of the section when loaded into memory, in bytes. If this value is greater + /// than the [`size_of_raw_data`](Self::size_of_raw_data) member, the section is filled with + /// zeroes. This field is valid only for executable images and should be set to `0` for object + /// files. + /// + /// In object files, this field would be replaced with the physical file address. Such headers + /// are never embedded in PDBs. + pub virtual_size: u32, + + /// The address of the first byte of the section when loaded into memory, relative to the image + /// base. For object files, this is the address of the first byte before relocation is applied. + pub virtual_address: u32, + + /// The size of the initialized data on disk, in bytes. This value must be a multiple of the + /// `FileAlignment` member of the [`IMAGE_OPTIONAL_HEADER`] structure. If this value is less than + /// the [`virtual_size`](Self::virtual_size) member, the remainder of the section is filled with + /// zeroes. If the section contains only uninitialized data, the member is zero. + /// + /// [`IMAGE_OPTIONAL_HEADER`]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32 + pub size_of_raw_data: u32, + + /// A file pointer to the first page within the COFF file. This value must be a multiple of the + /// `FileAlignment` member of the [`IMAGE_OPTIONAL_HEADER`] structure. If a section contains only + /// uninitialized data, set this member is zero. + /// + /// [`IMAGE_OPTIONAL_HEADER`]: https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header32 + pub pointer_to_raw_data: u32, + + /// A file pointer to the beginning of the relocation entries for the section. If there are no + /// relocations, this value is zero. + pub pointer_to_relocations: u32, + + /// A file pointer to the beginning of the line-number entries for the section. If there are no + /// COFF line numbers, this value is zero. + pub pointer_to_line_numbers: u32, + + /// The number of relocation entries for the section. This value is zero for executable images. + /// + /// If the value is `0xffff`, the actual relocation count is stored in the `virtual_address` + /// field of the first relocation. It is an error if this flag is set and there are fewer than + /// `0xffff` relocations in the section. + pub number_of_relocations: u16, + + /// The number of line-number entries for the section. + pub number_of_line_numbers: u16, + + /// The characteristics of the image. + pub characteristics: SectionCharacteristics, +} + +impl ImageSectionHeader { + pub(crate) fn parse(parse_buffer: &mut ParseBuffer<'_>) -> Result { + let name_bytes = parse_buffer.take(8)?; + + Ok(Self { + name: [ + name_bytes[0], + name_bytes[1], + name_bytes[2], + name_bytes[3], + name_bytes[4], + name_bytes[5], + name_bytes[6], + name_bytes[7], + ], + virtual_size: parse_buffer.parse_u32()?, + virtual_address: parse_buffer.parse_u32()?, + size_of_raw_data: parse_buffer.parse_u32()?, + pointer_to_raw_data: parse_buffer.parse_u32()?, + pointer_to_relocations: parse_buffer.parse_u32()?, + pointer_to_line_numbers: parse_buffer.parse_u32()?, + number_of_relocations: parse_buffer.parse_u16()?, + number_of_line_numbers: parse_buffer.parse_u16()?, + characteristics: parse_buffer.parse()?, + }) + } + + /// Returns the name of the section. + pub fn name(&self) -> &str { + let end = self + .name + .iter() + .position(|ch| *ch == 0) + .unwrap_or(self.name.len()); + + // The spec guarantees that the name is a proper UTF-8 string. + // TODO: Look up long names from the string table. + std::str::from_utf8(&self.name[0..end]).unwrap_or("") + } +} + +impl fmt::Debug for ImageSectionHeader { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ImageSectionHeader") + .field("name()", &self.name()) + .field("virtual_size", &format_args!("{:#x}", self.virtual_size)) + .field( + "virtual_address", + &format_args!("{:#x}", self.virtual_address), + ) + .field("size_of_raw_data", &self.size_of_raw_data) + .field( + "pointer_to_raw_data", + &format_args!("{:#x}", self.pointer_to_raw_data), + ) + .field( + "pointer_to_relocations", + &format_args!("{:#x}", self.pointer_to_relocations), + ) + .field( + "pointer_to_line_numbers", + &format_args!("{:#x}", self.pointer_to_line_numbers), + ) + .field("number_of_relocations", &self.number_of_relocations) + .field("number_of_line_numbers", &self.number_of_line_numbers) + .field("characteristics", &self.characteristics) + .finish() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_section_characteristics() { + let bytes: Vec = vec![0x40, 0x00, 0x00, 0xC8]; + let mut parse_buffer = ParseBuffer::from(bytes.as_slice()); + let characteristics = parse_buffer + .parse::() + .expect("parse"); + + assert_eq!(characteristics, SectionCharacteristics(0xc800_0040)); + + assert!(characteristics.initialized_data()); + assert!(characteristics.not_paged()); + assert!(characteristics.read()); + assert!(characteristics.write()); + + assert_eq!(characteristics.alignment(), None); + } + + #[test] + fn test_section_characteristics_nopad() { + let characteristics = SectionCharacteristics(IMAGE_SCN_TYPE_NO_PAD); + assert_eq!(characteristics.alignment(), Some(1)); + } + + #[test] + fn test_section_characteristics_alignment() { + let characteristics = SectionCharacteristics(IMAGE_SCN_ALIGN_64BYTES); + assert_eq!(characteristics.alignment(), Some(64)); + } + + #[test] + fn test_image_section_header() { + let bytes: Vec = vec![ + 0x2E, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x48, 0x35, 0x09, 0x00, 0x00, 0xD0, + 0x1E, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xA2, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC8, + ]; + + let mut parse_buffer = ParseBuffer::from(bytes.as_slice()); + + let ish = ImageSectionHeader::parse(&mut parse_buffer).expect("parse"); + assert_eq!(&ish.name, b".data\0\0\0"); + assert_eq!(ish.name(), ".data"); + assert_eq!(ish.virtual_size, 0x93548); + assert_eq!(ish.virtual_address, 0x001e_d000); + assert_eq!(ish.size_of_raw_data, 0xfe00); + assert_eq!(ish.pointer_to_raw_data, 0x001e_a200); + assert_eq!(ish.pointer_to_relocations, 0); + assert_eq!(ish.pointer_to_line_numbers, 0); + assert_eq!(ish.number_of_relocations, 0); + assert_eq!(ish.number_of_line_numbers, 0); + assert_eq!(ish.characteristics, SectionCharacteristics(0xc800_0040)); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/register.rs b/plugins/pdb-ng/vendor/pdb-rs/src/register.rs new file mode 100644 index 0000000000..33cc3799fd --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/register.rs @@ -0,0 +1,9666 @@ +#![allow(unused, non_upper_case_globals, non_camel_case_types, missing_docs)] + +use crate::common::{Error, Result}; +use crate::CPUType; +use crate::Error::UnknownRegister; +use scroll::ctx::TryFromCtx; +use scroll::{Endian, LE}; +use std::convert::{TryFrom, TryInto}; +use std::fmt; + +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Register { + /// Register subset shared by all processor types, + All(AllRegister), + /// Register set for the Intel 80x86 and ix86 processor series (plus PCODE registers) + X86(X86Register), + /// Registers for the 68K processors + M68K(M68KRegister), + /// Register set for the MIPS 4000 + MIPS(MIPSRegister), + /// Register set for the ALPHA AXP + ALPHAAXP(ALPHAAXPRegister), + /// Register Set for Motorola/IBM PowerPC + PowerPC(PowerPCRegister), + /// JAVA VM registers + Java(JavaRegister), + /// Register set for the Hitachi SH(3) + HitachiSH(HitachiSHRegister), + /// Register set for the ARM processor + ARM(ARMRegister), + /// Register set for ARM64 + ARM64(ARM64Register), + /// Register set for Intel IA64 + IA64(IA64Register), + /// Register set for the TriCore processor + Tricore(TricoreRegister), + /// Register set for the AM33 and related processors + AM33(AM33Register), + /// Register set for the Mitsubishi M32R + MitsubishiM32R(MitsubishiM32RRegister), + /// Register set for the SuperH SHMedia processor including compact mode + SuperHSHMedia(SuperHSHMediaRegister), + /// AMD64 registers + AMD64(AMD64Register), + /// HLSL registers + HLSL(HLSLRegister), +} + +impl fmt::Display for Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Register::All(r) => write!(f, "All({})", r), + Register::X86(r) => write!(f, "X86({})", r), + Register::M68K(r) => write!(f, "M68K({})", r), + Register::MIPS(r) => write!(f, "MIPS({})", r), + Register::ALPHAAXP(r) => write!(f, "ALPHAAXP({})", r), + Register::PowerPC(r) => write!(f, "PowerPC({})", r), + Register::Java(r) => write!(f, "Java({})", r), + Register::HitachiSH(r) => write!(f, "HitachiSH({})", r), + Register::ARM(r) => write!(f, "ARM({})", r), + Register::ARM64(r) => write!(f, "ARM64({})", r), + Register::IA64(r) => write!(f, "IA64({})", r), + Register::Tricore(r) => write!(f, "Tricore({})", r), + Register::AM33(r) => write!(f, "AM33({})", r), + Register::MitsubishiM32R(r) => write!(f, "MitsubishiM32R({})", r), + Register::SuperHSHMedia(r) => write!(f, "SuperHSHMedia({})", r), + Register::AMD64(r) => write!(f, "AMD64({})", r), + Register::HLSL(r) => write!(f, "HLSL({})", r), + _ => Err(fmt::Error), + } + } +} + +impl Register { + pub fn new(value: crate::Register, cpu: crate::CPUType) -> Result { + match cpu { + CPUType::Intel8080 + | CPUType::Intel8086 + | CPUType::Intel80286 + | CPUType::Intel80386 + | CPUType::Intel80486 + | CPUType::Pentium + | CPUType::PentiumPro + | CPUType::Pentium3 => Ok(Self::X86(X86Register::try_from(value.0)?)), + CPUType::M68000 + | CPUType::M68010 + | CPUType::M68020 + | CPUType::M68030 + | CPUType::M68040 => Ok(Self::M68K(M68KRegister::try_from(value.0)?)), + CPUType::MIPS + | CPUType::MIPS16 + | CPUType::MIPS32 + | CPUType::MIPS64 + | CPUType::MIPSI + | CPUType::MIPSII + | CPUType::MIPSIII + | CPUType::MIPSIV + | CPUType::MIPSV => Ok(Self::MIPS(MIPSRegister::try_from(value.0)?)), + CPUType::Alpha + | CPUType::Alpha21164 + | CPUType::Alpha21164A + | CPUType::Alpha21264 + | CPUType::Alpha21364 => Ok(Self::ALPHAAXP(ALPHAAXPRegister::try_from(value.0)?)), + CPUType::PPC601 + | CPUType::PPC603 + | CPUType::PPC604 + | CPUType::PPC620 + | CPUType::PPCFP + | CPUType::PPCBE => Ok(Self::PowerPC(PowerPCRegister::try_from(value.0)?)), + CPUType::SH3 | CPUType::SH3E | CPUType::SH3DSP | CPUType::SH4 => { + Ok(Self::HitachiSH(HitachiSHRegister::try_from(value.0)?)) + } + CPUType::SHMedia => Ok(Self::SuperHSHMedia(SuperHSHMediaRegister::try_from( + value.0, + )?)), + CPUType::ARM3 + | CPUType::ARM4 + | CPUType::ARM4T + | CPUType::ARM5 + | CPUType::ARM5T + | CPUType::ARM6 + | CPUType::ARM_XMAC + | CPUType::ARM_WMMX + | CPUType::ARM7 => Ok(Self::ARM(ARMRegister::try_from(value.0)?)), + CPUType::ARM64 => Ok(Self::ARM64(ARM64Register::try_from(value.0)?)), + CPUType::Ia64 | CPUType::Ia64_2 => Ok(Self::IA64(IA64Register::try_from(value.0)?)), + CPUType::AM33 => Ok(Self::AM33(AM33Register::try_from(value.0)?)), + CPUType::M32R => Ok(Self::MitsubishiM32R(MitsubishiM32RRegister::try_from( + value.0, + )?)), + CPUType::TriCore => Ok(Self::Tricore(TricoreRegister::try_from(value.0)?)), + CPUType::X64 => Ok(Self::AMD64(AMD64Register::try_from(value.0)?)), + CPUType::D3D11_Shader => Ok(Self::HLSL(HLSLRegister::try_from(value.0)?)), + _ => Err(UnknownRegister(value.0)), + } + } +} + +/// Register subset shared by all processor types, +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum AllRegister { + Err = 30000, + TEB = 30001, + Timer = 30002, + Efad1 = 30003, + Efad2 = 30004, + Efad3 = 30005, + VFrame = 30006, + Handle = 30007, + Params = 30008, + Locals = 30009, + TID = 30010, + Env = 30011, + CmdLn = 30012, +} + +impl fmt::Display for AllRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Err => write!(f, "Err"), + Self::TEB => write!(f, "TEB"), + Self::Timer => write!(f, "Timer"), + Self::Efad1 => write!(f, "Efad1"), + Self::Efad2 => write!(f, "Efad2"), + Self::Efad3 => write!(f, "Efad3"), + Self::VFrame => write!(f, "VFrame"), + Self::Handle => write!(f, "Handle"), + Self::Params => write!(f, "Params"), + Self::Locals => write!(f, "Locals"), + Self::TID => write!(f, "TID"), + Self::Env => write!(f, "Env"), + Self::CmdLn => write!(f, "CmdLn"), + } + } +} + +impl TryFrom for AllRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 30000 => Ok(Self::Err), + 30001 => Ok(Self::TEB), + 30002 => Ok(Self::Timer), + 30003 => Ok(Self::Efad1), + 30004 => Ok(Self::Efad2), + 30005 => Ok(Self::Efad3), + 30006 => Ok(Self::VFrame), + 30007 => Ok(Self::Handle), + 30008 => Ok(Self::Params), + 30009 => Ok(Self::Locals), + 30010 => Ok(Self::TID), + 30011 => Ok(Self::Env), + 30012 => Ok(Self::CmdLn), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for AllRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the Intel 80x86 and ix86 processor series (plus PCODE registers) +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum X86Register { + AL = 1, + CL = 2, + DL = 3, + BL = 4, + AH = 5, + CH = 6, + DH = 7, + BH = 8, + AX = 9, + CX = 10, + DX = 11, + BX = 12, + SP = 13, + BP = 14, + SI = 15, + DI = 16, + EAX = 17, + ECX = 18, + EDX = 19, + EBX = 20, + ESP = 21, + EBP = 22, + ESI = 23, + EDI = 24, + ES = 25, + CS = 26, + SS = 27, + DS = 28, + FS = 29, + GS = 30, + IP = 31, + FLAGS = 32, + EIP = 33, + EFLAGS = 34, + TEMP = 40, // PCODE Temp + TEMPH = 41, // PCODE TempH + QUOTE = 42, // PCODE Quote + PCDR3 = 43, // PCODE reserved + PCDR4 = 44, // PCODE reserved + PCDR5 = 45, // PCODE reserved + PCDR6 = 46, // PCODE reserved + PCDR7 = 47, // PCODE reserved + CR0 = 80, // CR0 -- control registers + CR1 = 81, + CR2 = 82, + CR3 = 83, + CR4 = 84, // Pentium + DR0 = 90, // Debug register + DR1 = 91, + DR2 = 92, + DR3 = 93, + DR4 = 94, + DR5 = 95, + DR6 = 96, + DR7 = 97, + GDTR = 110, + GDTL = 111, + IDTR = 112, + IDTL = 113, + LDTR = 114, + TR = 115, + + PSEUDO1 = 116, + PSEUDO2 = 117, + PSEUDO3 = 118, + PSEUDO4 = 119, + PSEUDO5 = 120, + PSEUDO6 = 121, + PSEUDO7 = 122, + PSEUDO8 = 123, + PSEUDO9 = 124, + + ST0 = 128, + ST1 = 129, + ST2 = 130, + ST3 = 131, + ST4 = 132, + ST5 = 133, + ST6 = 134, + ST7 = 135, + CTRL = 136, + STAT = 137, + TAG = 138, + FPIP = 139, + FPCS = 140, + FPDO = 141, + FPDS = 142, + ISEM = 143, + FPEIP = 144, + FPEDO = 145, + + MM0 = 146, + MM1 = 147, + MM2 = 148, + MM3 = 149, + MM4 = 150, + MM5 = 151, + MM6 = 152, + MM7 = 153, + + XMM0 = 154, // KATMAI registers + XMM1 = 155, + XMM2 = 156, + XMM3 = 157, + XMM4 = 158, + XMM5 = 159, + XMM6 = 160, + XMM7 = 161, + + XMM00 = 162, // KATMAI sub-registers + XMM01 = 163, + XMM02 = 164, + XMM03 = 165, + XMM10 = 166, + XMM11 = 167, + XMM12 = 168, + XMM13 = 169, + XMM20 = 170, + XMM21 = 171, + XMM22 = 172, + XMM23 = 173, + XMM30 = 174, + XMM31 = 175, + XMM32 = 176, + XMM33 = 177, + XMM40 = 178, + XMM41 = 179, + XMM42 = 180, + XMM43 = 181, + XMM50 = 182, + XMM51 = 183, + XMM52 = 184, + XMM53 = 185, + XMM60 = 186, + XMM61 = 187, + XMM62 = 188, + XMM63 = 189, + XMM70 = 190, + XMM71 = 191, + XMM72 = 192, + XMM73 = 193, + + XMM0L = 194, + XMM1L = 195, + XMM2L = 196, + XMM3L = 197, + XMM4L = 198, + XMM5L = 199, + XMM6L = 200, + XMM7L = 201, + + XMM0H = 202, + XMM1H = 203, + XMM2H = 204, + XMM3H = 205, + XMM4H = 206, + XMM5H = 207, + XMM6H = 208, + XMM7H = 209, + + MXCSR = 211, // XMM status register + + EDXEAX = 212, // EDX:EAX pair + + EMM0L = 220, // XMM sub-registers (WNI integer) + EMM1L = 221, + EMM2L = 222, + EMM3L = 223, + EMM4L = 224, + EMM5L = 225, + EMM6L = 226, + EMM7L = 227, + + EMM0H = 228, + EMM1H = 229, + EMM2H = 230, + EMM3H = 231, + EMM4H = 232, + EMM5H = 233, + EMM6H = 234, + EMM7H = 235, + + // do not change the order of these regs, first one must be even too + MM00 = 236, + MM01 = 237, + MM10 = 238, + MM11 = 239, + MM20 = 240, + MM21 = 241, + MM30 = 242, + MM31 = 243, + MM40 = 244, + MM41 = 245, + MM50 = 246, + MM51 = 247, + MM60 = 248, + MM61 = 249, + MM70 = 250, + MM71 = 251, + + YMM0 = 252, // AVX registers + YMM1 = 253, + YMM2 = 254, + YMM3 = 255, + YMM4 = 256, + YMM5 = 257, + YMM6 = 258, + YMM7 = 259, + + YMM0H = 260, + YMM1H = 261, + YMM2H = 262, + YMM3H = 263, + YMM4H = 264, + YMM5H = 265, + YMM6H = 266, + YMM7H = 267, + + YMM0I0 = 268, // AVX integer registers + YMM0I1 = 269, + YMM0I2 = 270, + YMM0I3 = 271, + YMM1I0 = 272, + YMM1I1 = 273, + YMM1I2 = 274, + YMM1I3 = 275, + YMM2I0 = 276, + YMM2I1 = 277, + YMM2I2 = 278, + YMM2I3 = 279, + YMM3I0 = 280, + YMM3I1 = 281, + YMM3I2 = 282, + YMM3I3 = 283, + YMM4I0 = 284, + YMM4I1 = 285, + YMM4I2 = 286, + YMM4I3 = 287, + YMM5I0 = 288, + YMM5I1 = 289, + YMM5I2 = 290, + YMM5I3 = 291, + YMM6I0 = 292, + YMM6I1 = 293, + YMM6I2 = 294, + YMM6I3 = 295, + YMM7I0 = 296, + YMM7I1 = 297, + YMM7I2 = 298, + YMM7I3 = 299, + + YMM0F0 = 300, // AVX floating-point single precise registers + YMM0F1 = 301, + YMM0F2 = 302, + YMM0F3 = 303, + YMM0F4 = 304, + YMM0F5 = 305, + YMM0F6 = 306, + YMM0F7 = 307, + YMM1F0 = 308, + YMM1F1 = 309, + YMM1F2 = 310, + YMM1F3 = 311, + YMM1F4 = 312, + YMM1F5 = 313, + YMM1F6 = 314, + YMM1F7 = 315, + YMM2F0 = 316, + YMM2F1 = 317, + YMM2F2 = 318, + YMM2F3 = 319, + YMM2F4 = 320, + YMM2F5 = 321, + YMM2F6 = 322, + YMM2F7 = 323, + YMM3F0 = 324, + YMM3F1 = 325, + YMM3F2 = 326, + YMM3F3 = 327, + YMM3F4 = 328, + YMM3F5 = 329, + YMM3F6 = 330, + YMM3F7 = 331, + YMM4F0 = 332, + YMM4F1 = 333, + YMM4F2 = 334, + YMM4F3 = 335, + YMM4F4 = 336, + YMM4F5 = 337, + YMM4F6 = 338, + YMM4F7 = 339, + YMM5F0 = 340, + YMM5F1 = 341, + YMM5F2 = 342, + YMM5F3 = 343, + YMM5F4 = 344, + YMM5F5 = 345, + YMM5F6 = 346, + YMM5F7 = 347, + YMM6F0 = 348, + YMM6F1 = 349, + YMM6F2 = 350, + YMM6F3 = 351, + YMM6F4 = 352, + YMM6F5 = 353, + YMM6F6 = 354, + YMM6F7 = 355, + YMM7F0 = 356, + YMM7F1 = 357, + YMM7F2 = 358, + YMM7F3 = 359, + YMM7F4 = 360, + YMM7F5 = 361, + YMM7F6 = 362, + YMM7F7 = 363, + + YMM0D0 = 364, // AVX floating-point double precise registers + YMM0D1 = 365, + YMM0D2 = 366, + YMM0D3 = 367, + YMM1D0 = 368, + YMM1D1 = 369, + YMM1D2 = 370, + YMM1D3 = 371, + YMM2D0 = 372, + YMM2D1 = 373, + YMM2D2 = 374, + YMM2D3 = 375, + YMM3D0 = 376, + YMM3D1 = 377, + YMM3D2 = 378, + YMM3D3 = 379, + YMM4D0 = 380, + YMM4D1 = 381, + YMM4D2 = 382, + YMM4D3 = 383, + YMM5D0 = 384, + YMM5D1 = 385, + YMM5D2 = 386, + YMM5D3 = 387, + YMM6D0 = 388, + YMM6D1 = 389, + YMM6D2 = 390, + YMM6D3 = 391, + YMM7D0 = 392, + YMM7D1 = 393, + YMM7D2 = 394, + YMM7D3 = 395, + + BND0 = 396, + BND1 = 397, + BND2 = 398, + BND3 = 399, +} + +impl fmt::Display for X86Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AL => write!(f, "AL"), + Self::CL => write!(f, "CL"), + Self::DL => write!(f, "DL"), + Self::BL => write!(f, "BL"), + Self::AH => write!(f, "AH"), + Self::CH => write!(f, "CH"), + Self::DH => write!(f, "DH"), + Self::BH => write!(f, "BH"), + Self::AX => write!(f, "AX"), + Self::CX => write!(f, "CX"), + Self::DX => write!(f, "DX"), + Self::BX => write!(f, "BX"), + Self::SP => write!(f, "SP"), + Self::BP => write!(f, "BP"), + Self::SI => write!(f, "SI"), + Self::DI => write!(f, "DI"), + Self::EAX => write!(f, "EAX"), + Self::ECX => write!(f, "ECX"), + Self::EDX => write!(f, "EDX"), + Self::EBX => write!(f, "EBX"), + Self::ESP => write!(f, "ESP"), + Self::EBP => write!(f, "EBP"), + Self::ESI => write!(f, "ESI"), + Self::EDI => write!(f, "EDI"), + Self::ES => write!(f, "ES"), + Self::CS => write!(f, "CS"), + Self::SS => write!(f, "SS"), + Self::DS => write!(f, "DS"), + Self::FS => write!(f, "FS"), + Self::GS => write!(f, "GS"), + Self::IP => write!(f, "IP"), + Self::FLAGS => write!(f, "FLAGS"), + Self::EIP => write!(f, "EIP"), + Self::EFLAGS => write!(f, "EFLAGS"), + Self::TEMP => write!(f, "TEMP"), + Self::TEMPH => write!(f, "TEMPH"), + Self::QUOTE => write!(f, "QUOTE"), + Self::PCDR3 => write!(f, "PCDR3"), + Self::PCDR4 => write!(f, "PCDR4"), + Self::PCDR5 => write!(f, "PCDR5"), + Self::PCDR6 => write!(f, "PCDR6"), + Self::PCDR7 => write!(f, "PCDR7"), + Self::CR0 => write!(f, "CR0"), + Self::CR1 => write!(f, "CR1"), + Self::CR2 => write!(f, "CR2"), + Self::CR3 => write!(f, "CR3"), + Self::CR4 => write!(f, "CR4"), + Self::DR0 => write!(f, "DR0"), + Self::DR1 => write!(f, "DR1"), + Self::DR2 => write!(f, "DR2"), + Self::DR3 => write!(f, "DR3"), + Self::DR4 => write!(f, "DR4"), + Self::DR5 => write!(f, "DR5"), + Self::DR6 => write!(f, "DR6"), + Self::DR7 => write!(f, "DR7"), + Self::GDTR => write!(f, "GDTR"), + Self::GDTL => write!(f, "GDTL"), + Self::IDTR => write!(f, "IDTR"), + Self::IDTL => write!(f, "IDTL"), + Self::LDTR => write!(f, "LDTR"), + Self::TR => write!(f, "TR"), + Self::PSEUDO1 => write!(f, "PSEUDO1"), + Self::PSEUDO2 => write!(f, "PSEUDO2"), + Self::PSEUDO3 => write!(f, "PSEUDO3"), + Self::PSEUDO4 => write!(f, "PSEUDO4"), + Self::PSEUDO5 => write!(f, "PSEUDO5"), + Self::PSEUDO6 => write!(f, "PSEUDO6"), + Self::PSEUDO7 => write!(f, "PSEUDO7"), + Self::PSEUDO8 => write!(f, "PSEUDO8"), + Self::PSEUDO9 => write!(f, "PSEUDO9"), + Self::ST0 => write!(f, "ST0"), + Self::ST1 => write!(f, "ST1"), + Self::ST2 => write!(f, "ST2"), + Self::ST3 => write!(f, "ST3"), + Self::ST4 => write!(f, "ST4"), + Self::ST5 => write!(f, "ST5"), + Self::ST6 => write!(f, "ST6"), + Self::ST7 => write!(f, "ST7"), + Self::CTRL => write!(f, "CTRL"), + Self::STAT => write!(f, "STAT"), + Self::TAG => write!(f, "TAG"), + Self::FPIP => write!(f, "FPIP"), + Self::FPCS => write!(f, "FPCS"), + Self::FPDO => write!(f, "FPDO"), + Self::FPDS => write!(f, "FPDS"), + Self::ISEM => write!(f, "ISEM"), + Self::FPEIP => write!(f, "FPEIP"), + Self::FPEDO => write!(f, "FPEDO"), + Self::MM0 => write!(f, "MM0"), + Self::MM1 => write!(f, "MM1"), + Self::MM2 => write!(f, "MM2"), + Self::MM3 => write!(f, "MM3"), + Self::MM4 => write!(f, "MM4"), + Self::MM5 => write!(f, "MM5"), + Self::MM6 => write!(f, "MM6"), + Self::MM7 => write!(f, "MM7"), + Self::XMM0 => write!(f, "XMM0"), + Self::XMM1 => write!(f, "XMM1"), + Self::XMM2 => write!(f, "XMM2"), + Self::XMM3 => write!(f, "XMM3"), + Self::XMM4 => write!(f, "XMM4"), + Self::XMM5 => write!(f, "XMM5"), + Self::XMM6 => write!(f, "XMM6"), + Self::XMM7 => write!(f, "XMM7"), + Self::XMM00 => write!(f, "XMM00"), + Self::XMM01 => write!(f, "XMM01"), + Self::XMM02 => write!(f, "XMM02"), + Self::XMM03 => write!(f, "XMM03"), + Self::XMM10 => write!(f, "XMM10"), + Self::XMM11 => write!(f, "XMM11"), + Self::XMM12 => write!(f, "XMM12"), + Self::XMM13 => write!(f, "XMM13"), + Self::XMM20 => write!(f, "XMM20"), + Self::XMM21 => write!(f, "XMM21"), + Self::XMM22 => write!(f, "XMM22"), + Self::XMM23 => write!(f, "XMM23"), + Self::XMM30 => write!(f, "XMM30"), + Self::XMM31 => write!(f, "XMM31"), + Self::XMM32 => write!(f, "XMM32"), + Self::XMM33 => write!(f, "XMM33"), + Self::XMM40 => write!(f, "XMM40"), + Self::XMM41 => write!(f, "XMM41"), + Self::XMM42 => write!(f, "XMM42"), + Self::XMM43 => write!(f, "XMM43"), + Self::XMM50 => write!(f, "XMM50"), + Self::XMM51 => write!(f, "XMM51"), + Self::XMM52 => write!(f, "XMM52"), + Self::XMM53 => write!(f, "XMM53"), + Self::XMM60 => write!(f, "XMM60"), + Self::XMM61 => write!(f, "XMM61"), + Self::XMM62 => write!(f, "XMM62"), + Self::XMM63 => write!(f, "XMM63"), + Self::XMM70 => write!(f, "XMM70"), + Self::XMM71 => write!(f, "XMM71"), + Self::XMM72 => write!(f, "XMM72"), + Self::XMM73 => write!(f, "XMM73"), + Self::XMM0L => write!(f, "XMM0L"), + Self::XMM1L => write!(f, "XMM1L"), + Self::XMM2L => write!(f, "XMM2L"), + Self::XMM3L => write!(f, "XMM3L"), + Self::XMM4L => write!(f, "XMM4L"), + Self::XMM5L => write!(f, "XMM5L"), + Self::XMM6L => write!(f, "XMM6L"), + Self::XMM7L => write!(f, "XMM7L"), + Self::XMM0H => write!(f, "XMM0H"), + Self::XMM1H => write!(f, "XMM1H"), + Self::XMM2H => write!(f, "XMM2H"), + Self::XMM3H => write!(f, "XMM3H"), + Self::XMM4H => write!(f, "XMM4H"), + Self::XMM5H => write!(f, "XMM5H"), + Self::XMM6H => write!(f, "XMM6H"), + Self::XMM7H => write!(f, "XMM7H"), + Self::MXCSR => write!(f, "MXCSR"), + Self::EDXEAX => write!(f, "EDXEAX"), + Self::EMM0L => write!(f, "EMM0L"), + Self::EMM1L => write!(f, "EMM1L"), + Self::EMM2L => write!(f, "EMM2L"), + Self::EMM3L => write!(f, "EMM3L"), + Self::EMM4L => write!(f, "EMM4L"), + Self::EMM5L => write!(f, "EMM5L"), + Self::EMM6L => write!(f, "EMM6L"), + Self::EMM7L => write!(f, "EMM7L"), + Self::EMM0H => write!(f, "EMM0H"), + Self::EMM1H => write!(f, "EMM1H"), + Self::EMM2H => write!(f, "EMM2H"), + Self::EMM3H => write!(f, "EMM3H"), + Self::EMM4H => write!(f, "EMM4H"), + Self::EMM5H => write!(f, "EMM5H"), + Self::EMM6H => write!(f, "EMM6H"), + Self::EMM7H => write!(f, "EMM7H"), + Self::MM00 => write!(f, "MM00"), + Self::MM01 => write!(f, "MM01"), + Self::MM10 => write!(f, "MM10"), + Self::MM11 => write!(f, "MM11"), + Self::MM20 => write!(f, "MM20"), + Self::MM21 => write!(f, "MM21"), + Self::MM30 => write!(f, "MM30"), + Self::MM31 => write!(f, "MM31"), + Self::MM40 => write!(f, "MM40"), + Self::MM41 => write!(f, "MM41"), + Self::MM50 => write!(f, "MM50"), + Self::MM51 => write!(f, "MM51"), + Self::MM60 => write!(f, "MM60"), + Self::MM61 => write!(f, "MM61"), + Self::MM70 => write!(f, "MM70"), + Self::MM71 => write!(f, "MM71"), + Self::YMM0 => write!(f, "YMM0"), + Self::YMM1 => write!(f, "YMM1"), + Self::YMM2 => write!(f, "YMM2"), + Self::YMM3 => write!(f, "YMM3"), + Self::YMM4 => write!(f, "YMM4"), + Self::YMM5 => write!(f, "YMM5"), + Self::YMM6 => write!(f, "YMM6"), + Self::YMM7 => write!(f, "YMM7"), + Self::YMM0H => write!(f, "YMM0H"), + Self::YMM1H => write!(f, "YMM1H"), + Self::YMM2H => write!(f, "YMM2H"), + Self::YMM3H => write!(f, "YMM3H"), + Self::YMM4H => write!(f, "YMM4H"), + Self::YMM5H => write!(f, "YMM5H"), + Self::YMM6H => write!(f, "YMM6H"), + Self::YMM7H => write!(f, "YMM7H"), + Self::YMM0I0 => write!(f, "YMM0I0"), + Self::YMM0I1 => write!(f, "YMM0I1"), + Self::YMM0I2 => write!(f, "YMM0I2"), + Self::YMM0I3 => write!(f, "YMM0I3"), + Self::YMM1I0 => write!(f, "YMM1I0"), + Self::YMM1I1 => write!(f, "YMM1I1"), + Self::YMM1I2 => write!(f, "YMM1I2"), + Self::YMM1I3 => write!(f, "YMM1I3"), + Self::YMM2I0 => write!(f, "YMM2I0"), + Self::YMM2I1 => write!(f, "YMM2I1"), + Self::YMM2I2 => write!(f, "YMM2I2"), + Self::YMM2I3 => write!(f, "YMM2I3"), + Self::YMM3I0 => write!(f, "YMM3I0"), + Self::YMM3I1 => write!(f, "YMM3I1"), + Self::YMM3I2 => write!(f, "YMM3I2"), + Self::YMM3I3 => write!(f, "YMM3I3"), + Self::YMM4I0 => write!(f, "YMM4I0"), + Self::YMM4I1 => write!(f, "YMM4I1"), + Self::YMM4I2 => write!(f, "YMM4I2"), + Self::YMM4I3 => write!(f, "YMM4I3"), + Self::YMM5I0 => write!(f, "YMM5I0"), + Self::YMM5I1 => write!(f, "YMM5I1"), + Self::YMM5I2 => write!(f, "YMM5I2"), + Self::YMM5I3 => write!(f, "YMM5I3"), + Self::YMM6I0 => write!(f, "YMM6I0"), + Self::YMM6I1 => write!(f, "YMM6I1"), + Self::YMM6I2 => write!(f, "YMM6I2"), + Self::YMM6I3 => write!(f, "YMM6I3"), + Self::YMM7I0 => write!(f, "YMM7I0"), + Self::YMM7I1 => write!(f, "YMM7I1"), + Self::YMM7I2 => write!(f, "YMM7I2"), + Self::YMM7I3 => write!(f, "YMM7I3"), + Self::YMM0F0 => write!(f, "YMM0F0"), + Self::YMM0F1 => write!(f, "YMM0F1"), + Self::YMM0F2 => write!(f, "YMM0F2"), + Self::YMM0F3 => write!(f, "YMM0F3"), + Self::YMM0F4 => write!(f, "YMM0F4"), + Self::YMM0F5 => write!(f, "YMM0F5"), + Self::YMM0F6 => write!(f, "YMM0F6"), + Self::YMM0F7 => write!(f, "YMM0F7"), + Self::YMM1F0 => write!(f, "YMM1F0"), + Self::YMM1F1 => write!(f, "YMM1F1"), + Self::YMM1F2 => write!(f, "YMM1F2"), + Self::YMM1F3 => write!(f, "YMM1F3"), + Self::YMM1F4 => write!(f, "YMM1F4"), + Self::YMM1F5 => write!(f, "YMM1F5"), + Self::YMM1F6 => write!(f, "YMM1F6"), + Self::YMM1F7 => write!(f, "YMM1F7"), + Self::YMM2F0 => write!(f, "YMM2F0"), + Self::YMM2F1 => write!(f, "YMM2F1"), + Self::YMM2F2 => write!(f, "YMM2F2"), + Self::YMM2F3 => write!(f, "YMM2F3"), + Self::YMM2F4 => write!(f, "YMM2F4"), + Self::YMM2F5 => write!(f, "YMM2F5"), + Self::YMM2F6 => write!(f, "YMM2F6"), + Self::YMM2F7 => write!(f, "YMM2F7"), + Self::YMM3F0 => write!(f, "YMM3F0"), + Self::YMM3F1 => write!(f, "YMM3F1"), + Self::YMM3F2 => write!(f, "YMM3F2"), + Self::YMM3F3 => write!(f, "YMM3F3"), + Self::YMM3F4 => write!(f, "YMM3F4"), + Self::YMM3F5 => write!(f, "YMM3F5"), + Self::YMM3F6 => write!(f, "YMM3F6"), + Self::YMM3F7 => write!(f, "YMM3F7"), + Self::YMM4F0 => write!(f, "YMM4F0"), + Self::YMM4F1 => write!(f, "YMM4F1"), + Self::YMM4F2 => write!(f, "YMM4F2"), + Self::YMM4F3 => write!(f, "YMM4F3"), + Self::YMM4F4 => write!(f, "YMM4F4"), + Self::YMM4F5 => write!(f, "YMM4F5"), + Self::YMM4F6 => write!(f, "YMM4F6"), + Self::YMM4F7 => write!(f, "YMM4F7"), + Self::YMM5F0 => write!(f, "YMM5F0"), + Self::YMM5F1 => write!(f, "YMM5F1"), + Self::YMM5F2 => write!(f, "YMM5F2"), + Self::YMM5F3 => write!(f, "YMM5F3"), + Self::YMM5F4 => write!(f, "YMM5F4"), + Self::YMM5F5 => write!(f, "YMM5F5"), + Self::YMM5F6 => write!(f, "YMM5F6"), + Self::YMM5F7 => write!(f, "YMM5F7"), + Self::YMM6F0 => write!(f, "YMM6F0"), + Self::YMM6F1 => write!(f, "YMM6F1"), + Self::YMM6F2 => write!(f, "YMM6F2"), + Self::YMM6F3 => write!(f, "YMM6F3"), + Self::YMM6F4 => write!(f, "YMM6F4"), + Self::YMM6F5 => write!(f, "YMM6F5"), + Self::YMM6F6 => write!(f, "YMM6F6"), + Self::YMM6F7 => write!(f, "YMM6F7"), + Self::YMM7F0 => write!(f, "YMM7F0"), + Self::YMM7F1 => write!(f, "YMM7F1"), + Self::YMM7F2 => write!(f, "YMM7F2"), + Self::YMM7F3 => write!(f, "YMM7F3"), + Self::YMM7F4 => write!(f, "YMM7F4"), + Self::YMM7F5 => write!(f, "YMM7F5"), + Self::YMM7F6 => write!(f, "YMM7F6"), + Self::YMM7F7 => write!(f, "YMM7F7"), + Self::YMM0D0 => write!(f, "YMM0D0"), + Self::YMM0D1 => write!(f, "YMM0D1"), + Self::YMM0D2 => write!(f, "YMM0D2"), + Self::YMM0D3 => write!(f, "YMM0D3"), + Self::YMM1D0 => write!(f, "YMM1D0"), + Self::YMM1D1 => write!(f, "YMM1D1"), + Self::YMM1D2 => write!(f, "YMM1D2"), + Self::YMM1D3 => write!(f, "YMM1D3"), + Self::YMM2D0 => write!(f, "YMM2D0"), + Self::YMM2D1 => write!(f, "YMM2D1"), + Self::YMM2D2 => write!(f, "YMM2D2"), + Self::YMM2D3 => write!(f, "YMM2D3"), + Self::YMM3D0 => write!(f, "YMM3D0"), + Self::YMM3D1 => write!(f, "YMM3D1"), + Self::YMM3D2 => write!(f, "YMM3D2"), + Self::YMM3D3 => write!(f, "YMM3D3"), + Self::YMM4D0 => write!(f, "YMM4D0"), + Self::YMM4D1 => write!(f, "YMM4D1"), + Self::YMM4D2 => write!(f, "YMM4D2"), + Self::YMM4D3 => write!(f, "YMM4D3"), + Self::YMM5D0 => write!(f, "YMM5D0"), + Self::YMM5D1 => write!(f, "YMM5D1"), + Self::YMM5D2 => write!(f, "YMM5D2"), + Self::YMM5D3 => write!(f, "YMM5D3"), + Self::YMM6D0 => write!(f, "YMM6D0"), + Self::YMM6D1 => write!(f, "YMM6D1"), + Self::YMM6D2 => write!(f, "YMM6D2"), + Self::YMM6D3 => write!(f, "YMM6D3"), + Self::YMM7D0 => write!(f, "YMM7D0"), + Self::YMM7D1 => write!(f, "YMM7D1"), + Self::YMM7D2 => write!(f, "YMM7D2"), + Self::YMM7D3 => write!(f, "YMM7D3"), + Self::BND0 => write!(f, "BND0"), + Self::BND1 => write!(f, "BND1"), + Self::BND2 => write!(f, "BND2"), + Self::BND3 => write!(f, "BND3"), + } + } +} + +impl TryFrom for X86Register { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 1 => Ok(Self::AL), + 2 => Ok(Self::CL), + 3 => Ok(Self::DL), + 4 => Ok(Self::BL), + 5 => Ok(Self::AH), + 6 => Ok(Self::CH), + 7 => Ok(Self::DH), + 8 => Ok(Self::BH), + 9 => Ok(Self::AX), + 10 => Ok(Self::CX), + 11 => Ok(Self::DX), + 12 => Ok(Self::BX), + 13 => Ok(Self::SP), + 14 => Ok(Self::BP), + 15 => Ok(Self::SI), + 16 => Ok(Self::DI), + 17 => Ok(Self::EAX), + 18 => Ok(Self::ECX), + 19 => Ok(Self::EDX), + 20 => Ok(Self::EBX), + 21 => Ok(Self::ESP), + 22 => Ok(Self::EBP), + 23 => Ok(Self::ESI), + 24 => Ok(Self::EDI), + 25 => Ok(Self::ES), + 26 => Ok(Self::CS), + 27 => Ok(Self::SS), + 28 => Ok(Self::DS), + 29 => Ok(Self::FS), + 30 => Ok(Self::GS), + 31 => Ok(Self::IP), + 32 => Ok(Self::FLAGS), + 33 => Ok(Self::EIP), + 34 => Ok(Self::EFLAGS), + 40 => Ok(Self::TEMP), + 41 => Ok(Self::TEMPH), + 42 => Ok(Self::QUOTE), + 43 => Ok(Self::PCDR3), + 44 => Ok(Self::PCDR4), + 45 => Ok(Self::PCDR5), + 46 => Ok(Self::PCDR6), + 47 => Ok(Self::PCDR7), + 80 => Ok(Self::CR0), + 81 => Ok(Self::CR1), + 82 => Ok(Self::CR2), + 83 => Ok(Self::CR3), + 84 => Ok(Self::CR4), + 90 => Ok(Self::DR0), + 91 => Ok(Self::DR1), + 92 => Ok(Self::DR2), + 93 => Ok(Self::DR3), + 94 => Ok(Self::DR4), + 95 => Ok(Self::DR5), + 96 => Ok(Self::DR6), + 97 => Ok(Self::DR7), + 110 => Ok(Self::GDTR), + 111 => Ok(Self::GDTL), + 112 => Ok(Self::IDTR), + 113 => Ok(Self::IDTL), + 114 => Ok(Self::LDTR), + 115 => Ok(Self::TR), + 116 => Ok(Self::PSEUDO1), + 117 => Ok(Self::PSEUDO2), + 118 => Ok(Self::PSEUDO3), + 119 => Ok(Self::PSEUDO4), + 120 => Ok(Self::PSEUDO5), + 121 => Ok(Self::PSEUDO6), + 122 => Ok(Self::PSEUDO7), + 123 => Ok(Self::PSEUDO8), + 124 => Ok(Self::PSEUDO9), + 128 => Ok(Self::ST0), + 129 => Ok(Self::ST1), + 130 => Ok(Self::ST2), + 131 => Ok(Self::ST3), + 132 => Ok(Self::ST4), + 133 => Ok(Self::ST5), + 134 => Ok(Self::ST6), + 135 => Ok(Self::ST7), + 136 => Ok(Self::CTRL), + 137 => Ok(Self::STAT), + 138 => Ok(Self::TAG), + 139 => Ok(Self::FPIP), + 140 => Ok(Self::FPCS), + 141 => Ok(Self::FPDO), + 142 => Ok(Self::FPDS), + 143 => Ok(Self::ISEM), + 144 => Ok(Self::FPEIP), + 145 => Ok(Self::FPEDO), + 146 => Ok(Self::MM0), + 147 => Ok(Self::MM1), + 148 => Ok(Self::MM2), + 149 => Ok(Self::MM3), + 150 => Ok(Self::MM4), + 151 => Ok(Self::MM5), + 152 => Ok(Self::MM6), + 153 => Ok(Self::MM7), + 154 => Ok(Self::XMM0), + 155 => Ok(Self::XMM1), + 156 => Ok(Self::XMM2), + 157 => Ok(Self::XMM3), + 158 => Ok(Self::XMM4), + 159 => Ok(Self::XMM5), + 160 => Ok(Self::XMM6), + 161 => Ok(Self::XMM7), + 162 => Ok(Self::XMM00), + 163 => Ok(Self::XMM01), + 164 => Ok(Self::XMM02), + 165 => Ok(Self::XMM03), + 166 => Ok(Self::XMM10), + 167 => Ok(Self::XMM11), + 168 => Ok(Self::XMM12), + 169 => Ok(Self::XMM13), + 170 => Ok(Self::XMM20), + 171 => Ok(Self::XMM21), + 172 => Ok(Self::XMM22), + 173 => Ok(Self::XMM23), + 174 => Ok(Self::XMM30), + 175 => Ok(Self::XMM31), + 176 => Ok(Self::XMM32), + 177 => Ok(Self::XMM33), + 178 => Ok(Self::XMM40), + 179 => Ok(Self::XMM41), + 180 => Ok(Self::XMM42), + 181 => Ok(Self::XMM43), + 182 => Ok(Self::XMM50), + 183 => Ok(Self::XMM51), + 184 => Ok(Self::XMM52), + 185 => Ok(Self::XMM53), + 186 => Ok(Self::XMM60), + 187 => Ok(Self::XMM61), + 188 => Ok(Self::XMM62), + 189 => Ok(Self::XMM63), + 190 => Ok(Self::XMM70), + 191 => Ok(Self::XMM71), + 192 => Ok(Self::XMM72), + 193 => Ok(Self::XMM73), + 194 => Ok(Self::XMM0L), + 195 => Ok(Self::XMM1L), + 196 => Ok(Self::XMM2L), + 197 => Ok(Self::XMM3L), + 198 => Ok(Self::XMM4L), + 199 => Ok(Self::XMM5L), + 200 => Ok(Self::XMM6L), + 201 => Ok(Self::XMM7L), + 202 => Ok(Self::XMM0H), + 203 => Ok(Self::XMM1H), + 204 => Ok(Self::XMM2H), + 205 => Ok(Self::XMM3H), + 206 => Ok(Self::XMM4H), + 207 => Ok(Self::XMM5H), + 208 => Ok(Self::XMM6H), + 209 => Ok(Self::XMM7H), + 211 => Ok(Self::MXCSR), + 212 => Ok(Self::EDXEAX), + 220 => Ok(Self::EMM0L), + 221 => Ok(Self::EMM1L), + 222 => Ok(Self::EMM2L), + 223 => Ok(Self::EMM3L), + 224 => Ok(Self::EMM4L), + 225 => Ok(Self::EMM5L), + 226 => Ok(Self::EMM6L), + 227 => Ok(Self::EMM7L), + 228 => Ok(Self::EMM0H), + 229 => Ok(Self::EMM1H), + 230 => Ok(Self::EMM2H), + 231 => Ok(Self::EMM3H), + 232 => Ok(Self::EMM4H), + 233 => Ok(Self::EMM5H), + 234 => Ok(Self::EMM6H), + 235 => Ok(Self::EMM7H), + 236 => Ok(Self::MM00), + 237 => Ok(Self::MM01), + 238 => Ok(Self::MM10), + 239 => Ok(Self::MM11), + 240 => Ok(Self::MM20), + 241 => Ok(Self::MM21), + 242 => Ok(Self::MM30), + 243 => Ok(Self::MM31), + 244 => Ok(Self::MM40), + 245 => Ok(Self::MM41), + 246 => Ok(Self::MM50), + 247 => Ok(Self::MM51), + 248 => Ok(Self::MM60), + 249 => Ok(Self::MM61), + 250 => Ok(Self::MM70), + 251 => Ok(Self::MM71), + 252 => Ok(Self::YMM0), + 253 => Ok(Self::YMM1), + 254 => Ok(Self::YMM2), + 255 => Ok(Self::YMM3), + 256 => Ok(Self::YMM4), + 257 => Ok(Self::YMM5), + 258 => Ok(Self::YMM6), + 259 => Ok(Self::YMM7), + 260 => Ok(Self::YMM0H), + 261 => Ok(Self::YMM1H), + 262 => Ok(Self::YMM2H), + 263 => Ok(Self::YMM3H), + 264 => Ok(Self::YMM4H), + 265 => Ok(Self::YMM5H), + 266 => Ok(Self::YMM6H), + 267 => Ok(Self::YMM7H), + 268 => Ok(Self::YMM0I0), + 269 => Ok(Self::YMM0I1), + 270 => Ok(Self::YMM0I2), + 271 => Ok(Self::YMM0I3), + 272 => Ok(Self::YMM1I0), + 273 => Ok(Self::YMM1I1), + 274 => Ok(Self::YMM1I2), + 275 => Ok(Self::YMM1I3), + 276 => Ok(Self::YMM2I0), + 277 => Ok(Self::YMM2I1), + 278 => Ok(Self::YMM2I2), + 279 => Ok(Self::YMM2I3), + 280 => Ok(Self::YMM3I0), + 281 => Ok(Self::YMM3I1), + 282 => Ok(Self::YMM3I2), + 283 => Ok(Self::YMM3I3), + 284 => Ok(Self::YMM4I0), + 285 => Ok(Self::YMM4I1), + 286 => Ok(Self::YMM4I2), + 287 => Ok(Self::YMM4I3), + 288 => Ok(Self::YMM5I0), + 289 => Ok(Self::YMM5I1), + 290 => Ok(Self::YMM5I2), + 291 => Ok(Self::YMM5I3), + 292 => Ok(Self::YMM6I0), + 293 => Ok(Self::YMM6I1), + 294 => Ok(Self::YMM6I2), + 295 => Ok(Self::YMM6I3), + 296 => Ok(Self::YMM7I0), + 297 => Ok(Self::YMM7I1), + 298 => Ok(Self::YMM7I2), + 299 => Ok(Self::YMM7I3), + 300 => Ok(Self::YMM0F0), + 301 => Ok(Self::YMM0F1), + 302 => Ok(Self::YMM0F2), + 303 => Ok(Self::YMM0F3), + 304 => Ok(Self::YMM0F4), + 305 => Ok(Self::YMM0F5), + 306 => Ok(Self::YMM0F6), + 307 => Ok(Self::YMM0F7), + 308 => Ok(Self::YMM1F0), + 309 => Ok(Self::YMM1F1), + 310 => Ok(Self::YMM1F2), + 311 => Ok(Self::YMM1F3), + 312 => Ok(Self::YMM1F4), + 313 => Ok(Self::YMM1F5), + 314 => Ok(Self::YMM1F6), + 315 => Ok(Self::YMM1F7), + 316 => Ok(Self::YMM2F0), + 317 => Ok(Self::YMM2F1), + 318 => Ok(Self::YMM2F2), + 319 => Ok(Self::YMM2F3), + 320 => Ok(Self::YMM2F4), + 321 => Ok(Self::YMM2F5), + 322 => Ok(Self::YMM2F6), + 323 => Ok(Self::YMM2F7), + 324 => Ok(Self::YMM3F0), + 325 => Ok(Self::YMM3F1), + 326 => Ok(Self::YMM3F2), + 327 => Ok(Self::YMM3F3), + 328 => Ok(Self::YMM3F4), + 329 => Ok(Self::YMM3F5), + 330 => Ok(Self::YMM3F6), + 331 => Ok(Self::YMM3F7), + 332 => Ok(Self::YMM4F0), + 333 => Ok(Self::YMM4F1), + 334 => Ok(Self::YMM4F2), + 335 => Ok(Self::YMM4F3), + 336 => Ok(Self::YMM4F4), + 337 => Ok(Self::YMM4F5), + 338 => Ok(Self::YMM4F6), + 339 => Ok(Self::YMM4F7), + 340 => Ok(Self::YMM5F0), + 341 => Ok(Self::YMM5F1), + 342 => Ok(Self::YMM5F2), + 343 => Ok(Self::YMM5F3), + 344 => Ok(Self::YMM5F4), + 345 => Ok(Self::YMM5F5), + 346 => Ok(Self::YMM5F6), + 347 => Ok(Self::YMM5F7), + 348 => Ok(Self::YMM6F0), + 349 => Ok(Self::YMM6F1), + 350 => Ok(Self::YMM6F2), + 351 => Ok(Self::YMM6F3), + 352 => Ok(Self::YMM6F4), + 353 => Ok(Self::YMM6F5), + 354 => Ok(Self::YMM6F6), + 355 => Ok(Self::YMM6F7), + 356 => Ok(Self::YMM7F0), + 357 => Ok(Self::YMM7F1), + 358 => Ok(Self::YMM7F2), + 359 => Ok(Self::YMM7F3), + 360 => Ok(Self::YMM7F4), + 361 => Ok(Self::YMM7F5), + 362 => Ok(Self::YMM7F6), + 363 => Ok(Self::YMM7F7), + 364 => Ok(Self::YMM0D0), + 365 => Ok(Self::YMM0D1), + 366 => Ok(Self::YMM0D2), + 367 => Ok(Self::YMM0D3), + 368 => Ok(Self::YMM1D0), + 369 => Ok(Self::YMM1D1), + 370 => Ok(Self::YMM1D2), + 371 => Ok(Self::YMM1D3), + 372 => Ok(Self::YMM2D0), + 373 => Ok(Self::YMM2D1), + 374 => Ok(Self::YMM2D2), + 375 => Ok(Self::YMM2D3), + 376 => Ok(Self::YMM3D0), + 377 => Ok(Self::YMM3D1), + 378 => Ok(Self::YMM3D2), + 379 => Ok(Self::YMM3D3), + 380 => Ok(Self::YMM4D0), + 381 => Ok(Self::YMM4D1), + 382 => Ok(Self::YMM4D2), + 383 => Ok(Self::YMM4D3), + 384 => Ok(Self::YMM5D0), + 385 => Ok(Self::YMM5D1), + 386 => Ok(Self::YMM5D2), + 387 => Ok(Self::YMM5D3), + 388 => Ok(Self::YMM6D0), + 389 => Ok(Self::YMM6D1), + 390 => Ok(Self::YMM6D2), + 391 => Ok(Self::YMM6D3), + 392 => Ok(Self::YMM7D0), + 393 => Ok(Self::YMM7D1), + 394 => Ok(Self::YMM7D2), + 395 => Ok(Self::YMM7D3), + 396 => Ok(Self::BND0), + 397 => Ok(Self::BND1), + 398 => Ok(Self::BND2), + 399 => Ok(Self::BND3), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for X86Register { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Registers for the 68K processors +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum M68KRegister { + D0 = 0, + D1 = 1, + D2 = 2, + D3 = 3, + D4 = 4, + D5 = 5, + D6 = 6, + D7 = 7, + A0 = 8, + A1 = 9, + A2 = 10, + A3 = 11, + A4 = 12, + A5 = 13, + A6 = 14, + A7 = 15, + CCR = 16, + SR = 17, + USP = 18, + MSP = 19, + SFC = 20, + DFC = 21, + CACR = 22, + VBR = 23, + CAAR = 24, + ISP = 25, + PC = 26, + //reserved 27 + FPCR = 28, + FPSR = 29, + FPIAR = 30, + //reserved 31 + FP0 = 32, + FP1 = 33, + FP2 = 34, + FP3 = 35, + FP4 = 36, + FP5 = 37, + FP6 = 38, + FP7 = 39, + //reserved 40 + MMUSR030 = 41, + MMUSR = 42, + URP = 43, + DTT0 = 44, + DTT1 = 45, + ITT0 = 46, + ITT1 = 47, + //reserved 50 + PSR = 51, + PCSR = 52, + VAL = 53, + CRP = 54, + SRP = 55, + DRP = 56, + TC = 57, + AC = 58, + SCC = 59, + CAL = 60, + TT0 = 61, + TT1 = 62, + //reserved 63 + BAD0 = 64, + BAD1 = 65, + BAD2 = 66, + BAD3 = 67, + BAD4 = 68, + BAD5 = 69, + BAD6 = 70, + BAD7 = 71, + BAC0 = 72, + BAC1 = 73, + BAC2 = 74, + BAC3 = 75, + BAC4 = 76, + BAC5 = 77, + BAC6 = 78, + BAC7 = 79, +} + +impl fmt::Display for M68KRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::D0 => write!(f, "D0"), + Self::D1 => write!(f, "D1"), + Self::D2 => write!(f, "D2"), + Self::D3 => write!(f, "D3"), + Self::D4 => write!(f, "D4"), + Self::D5 => write!(f, "D5"), + Self::D6 => write!(f, "D6"), + Self::D7 => write!(f, "D7"), + Self::A0 => write!(f, "A0"), + Self::A1 => write!(f, "A1"), + Self::A2 => write!(f, "A2"), + Self::A3 => write!(f, "A3"), + Self::A4 => write!(f, "A4"), + Self::A5 => write!(f, "A5"), + Self::A6 => write!(f, "A6"), + Self::A7 => write!(f, "A7"), + Self::CCR => write!(f, "CCR"), + Self::SR => write!(f, "SR"), + Self::USP => write!(f, "USP"), + Self::MSP => write!(f, "MSP"), + Self::SFC => write!(f, "SFC"), + Self::DFC => write!(f, "DFC"), + Self::CACR => write!(f, "CACR"), + Self::VBR => write!(f, "VBR"), + Self::CAAR => write!(f, "CAAR"), + Self::ISP => write!(f, "ISP"), + Self::PC => write!(f, "PC"), + Self::FPCR => write!(f, "FPCR"), + Self::FPSR => write!(f, "FPSR"), + Self::FPIAR => write!(f, "FPIAR"), + Self::FP0 => write!(f, "FP0"), + Self::FP1 => write!(f, "FP1"), + Self::FP2 => write!(f, "FP2"), + Self::FP3 => write!(f, "FP3"), + Self::FP4 => write!(f, "FP4"), + Self::FP5 => write!(f, "FP5"), + Self::FP6 => write!(f, "FP6"), + Self::FP7 => write!(f, "FP7"), + Self::MMUSR030 => write!(f, "MMUSR030"), + Self::MMUSR => write!(f, "MMUSR"), + Self::URP => write!(f, "URP"), + Self::DTT0 => write!(f, "DTT0"), + Self::DTT1 => write!(f, "DTT1"), + Self::ITT0 => write!(f, "ITT0"), + Self::ITT1 => write!(f, "ITT1"), + Self::PSR => write!(f, "PSR"), + Self::PCSR => write!(f, "PCSR"), + Self::VAL => write!(f, "VAL"), + Self::CRP => write!(f, "CRP"), + Self::SRP => write!(f, "SRP"), + Self::DRP => write!(f, "DRP"), + Self::TC => write!(f, "TC"), + Self::AC => write!(f, "AC"), + Self::SCC => write!(f, "SCC"), + Self::CAL => write!(f, "CAL"), + Self::TT0 => write!(f, "TT0"), + Self::TT1 => write!(f, "TT1"), + Self::BAD0 => write!(f, "BAD0"), + Self::BAD1 => write!(f, "BAD1"), + Self::BAD2 => write!(f, "BAD2"), + Self::BAD3 => write!(f, "BAD3"), + Self::BAD4 => write!(f, "BAD4"), + Self::BAD5 => write!(f, "BAD5"), + Self::BAD6 => write!(f, "BAD6"), + Self::BAD7 => write!(f, "BAD7"), + Self::BAC0 => write!(f, "BAC0"), + Self::BAC1 => write!(f, "BAC1"), + Self::BAC2 => write!(f, "BAC2"), + Self::BAC3 => write!(f, "BAC3"), + Self::BAC4 => write!(f, "BAC4"), + Self::BAC5 => write!(f, "BAC5"), + Self::BAC6 => write!(f, "BAC6"), + Self::BAC7 => write!(f, "BAC7"), + } + } +} + +impl TryFrom for M68KRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::D0), + 1 => Ok(Self::D1), + 2 => Ok(Self::D2), + 3 => Ok(Self::D3), + 4 => Ok(Self::D4), + 5 => Ok(Self::D5), + 6 => Ok(Self::D6), + 7 => Ok(Self::D7), + 8 => Ok(Self::A0), + 9 => Ok(Self::A1), + 10 => Ok(Self::A2), + 11 => Ok(Self::A3), + 12 => Ok(Self::A4), + 13 => Ok(Self::A5), + 14 => Ok(Self::A6), + 15 => Ok(Self::A7), + 16 => Ok(Self::CCR), + 17 => Ok(Self::SR), + 18 => Ok(Self::USP), + 19 => Ok(Self::MSP), + 20 => Ok(Self::SFC), + 21 => Ok(Self::DFC), + 22 => Ok(Self::CACR), + 23 => Ok(Self::VBR), + 24 => Ok(Self::CAAR), + 25 => Ok(Self::ISP), + 26 => Ok(Self::PC), + 28 => Ok(Self::FPCR), + 29 => Ok(Self::FPSR), + 30 => Ok(Self::FPIAR), + 32 => Ok(Self::FP0), + 33 => Ok(Self::FP1), + 34 => Ok(Self::FP2), + 35 => Ok(Self::FP3), + 36 => Ok(Self::FP4), + 37 => Ok(Self::FP5), + 38 => Ok(Self::FP6), + 39 => Ok(Self::FP7), + 41 => Ok(Self::MMUSR030), + 42 => Ok(Self::MMUSR), + 43 => Ok(Self::URP), + 44 => Ok(Self::DTT0), + 45 => Ok(Self::DTT1), + 46 => Ok(Self::ITT0), + 47 => Ok(Self::ITT1), + 51 => Ok(Self::PSR), + 52 => Ok(Self::PCSR), + 53 => Ok(Self::VAL), + 54 => Ok(Self::CRP), + 55 => Ok(Self::SRP), + 56 => Ok(Self::DRP), + 57 => Ok(Self::TC), + 58 => Ok(Self::AC), + 59 => Ok(Self::SCC), + 60 => Ok(Self::CAL), + 61 => Ok(Self::TT0), + 62 => Ok(Self::TT1), + 64 => Ok(Self::BAD0), + 65 => Ok(Self::BAD1), + 66 => Ok(Self::BAD2), + 67 => Ok(Self::BAD3), + 68 => Ok(Self::BAD4), + 69 => Ok(Self::BAD5), + 70 => Ok(Self::BAD6), + 71 => Ok(Self::BAD7), + 72 => Ok(Self::BAC0), + 73 => Ok(Self::BAC1), + 74 => Ok(Self::BAC2), + 75 => Ok(Self::BAC3), + 76 => Ok(Self::BAC4), + 77 => Ok(Self::BAC5), + 78 => Ok(Self::BAC6), + 79 => Ok(Self::BAC7), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for M68KRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the MIPS 4000 +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum MIPSRegister { + IntZERO = 10, /* CPU REGISTER */ + IntAT = 11, + IntV0 = 12, + IntV1 = 13, + IntA0 = 14, + IntA1 = 15, + IntA2 = 16, + IntA3 = 17, + IntT0 = 18, + IntT1 = 19, + IntT2 = 20, + IntT3 = 21, + IntT4 = 22, + IntT5 = 23, + IntT6 = 24, + IntT7 = 25, + IntS0 = 26, + IntS1 = 27, + IntS2 = 28, + IntS3 = 29, + IntS4 = 30, + IntS5 = 31, + IntS6 = 32, + IntS7 = 33, + IntT8 = 34, + IntT9 = 35, + IntKT0 = 36, + IntKT1 = 37, + IntGP = 38, + IntSP = 39, + IntS8 = 40, + IntRA = 41, + IntLO = 42, + IntHI = 43, + + Fir = 50, + Psr = 51, + + FltF0 = 60, /* Floating point registers */ + FltF1 = 61, + FltF2 = 62, + FltF3 = 63, + FltF4 = 64, + FltF5 = 65, + FltF6 = 66, + FltF7 = 67, + FltF8 = 68, + FltF9 = 69, + FltF10 = 70, + FltF11 = 71, + FltF12 = 72, + FltF13 = 73, + FltF14 = 74, + FltF15 = 75, + FltF16 = 76, + FltF17 = 77, + FltF18 = 78, + FltF19 = 79, + FltF20 = 80, + FltF21 = 81, + FltF22 = 82, + FltF23 = 83, + FltF24 = 84, + FltF25 = 85, + FltF26 = 86, + FltF27 = 87, + FltF28 = 88, + FltF29 = 89, + FltF30 = 90, + FltF31 = 91, + FltFsr = 92, +} + +impl fmt::Display for MIPSRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::IntZERO => write!(f, "IntZERO"), + Self::IntAT => write!(f, "IntAT"), + Self::IntV0 => write!(f, "IntV0"), + Self::IntV1 => write!(f, "IntV1"), + Self::IntA0 => write!(f, "IntA0"), + Self::IntA1 => write!(f, "IntA1"), + Self::IntA2 => write!(f, "IntA2"), + Self::IntA3 => write!(f, "IntA3"), + Self::IntT0 => write!(f, "IntT0"), + Self::IntT1 => write!(f, "IntT1"), + Self::IntT2 => write!(f, "IntT2"), + Self::IntT3 => write!(f, "IntT3"), + Self::IntT4 => write!(f, "IntT4"), + Self::IntT5 => write!(f, "IntT5"), + Self::IntT6 => write!(f, "IntT6"), + Self::IntT7 => write!(f, "IntT7"), + Self::IntS0 => write!(f, "IntS0"), + Self::IntS1 => write!(f, "IntS1"), + Self::IntS2 => write!(f, "IntS2"), + Self::IntS3 => write!(f, "IntS3"), + Self::IntS4 => write!(f, "IntS4"), + Self::IntS5 => write!(f, "IntS5"), + Self::IntS6 => write!(f, "IntS6"), + Self::IntS7 => write!(f, "IntS7"), + Self::IntT8 => write!(f, "IntT8"), + Self::IntT9 => write!(f, "IntT9"), + Self::IntKT0 => write!(f, "IntKT0"), + Self::IntKT1 => write!(f, "IntKT1"), + Self::IntGP => write!(f, "IntGP"), + Self::IntSP => write!(f, "IntSP"), + Self::IntS8 => write!(f, "IntS8"), + Self::IntRA => write!(f, "IntRA"), + Self::IntLO => write!(f, "IntLO"), + Self::IntHI => write!(f, "IntHI"), + Self::Fir => write!(f, "Fir"), + Self::Psr => write!(f, "Psr"), + Self::FltF0 => write!(f, "FltF0"), + Self::FltF1 => write!(f, "FltF1"), + Self::FltF2 => write!(f, "FltF2"), + Self::FltF3 => write!(f, "FltF3"), + Self::FltF4 => write!(f, "FltF4"), + Self::FltF5 => write!(f, "FltF5"), + Self::FltF6 => write!(f, "FltF6"), + Self::FltF7 => write!(f, "FltF7"), + Self::FltF8 => write!(f, "FltF8"), + Self::FltF9 => write!(f, "FltF9"), + Self::FltF10 => write!(f, "FltF10"), + Self::FltF11 => write!(f, "FltF11"), + Self::FltF12 => write!(f, "FltF12"), + Self::FltF13 => write!(f, "FltF13"), + Self::FltF14 => write!(f, "FltF14"), + Self::FltF15 => write!(f, "FltF15"), + Self::FltF16 => write!(f, "FltF16"), + Self::FltF17 => write!(f, "FltF17"), + Self::FltF18 => write!(f, "FltF18"), + Self::FltF19 => write!(f, "FltF19"), + Self::FltF20 => write!(f, "FltF20"), + Self::FltF21 => write!(f, "FltF21"), + Self::FltF22 => write!(f, "FltF22"), + Self::FltF23 => write!(f, "FltF23"), + Self::FltF24 => write!(f, "FltF24"), + Self::FltF25 => write!(f, "FltF25"), + Self::FltF26 => write!(f, "FltF26"), + Self::FltF27 => write!(f, "FltF27"), + Self::FltF28 => write!(f, "FltF28"), + Self::FltF29 => write!(f, "FltF29"), + Self::FltF30 => write!(f, "FltF30"), + Self::FltF31 => write!(f, "FltF31"), + Self::FltFsr => write!(f, "FltFsr"), + } + } +} + +impl TryFrom for MIPSRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::IntZERO), + 11 => Ok(Self::IntAT), + 12 => Ok(Self::IntV0), + 13 => Ok(Self::IntV1), + 14 => Ok(Self::IntA0), + 15 => Ok(Self::IntA1), + 16 => Ok(Self::IntA2), + 17 => Ok(Self::IntA3), + 18 => Ok(Self::IntT0), + 19 => Ok(Self::IntT1), + 20 => Ok(Self::IntT2), + 21 => Ok(Self::IntT3), + 22 => Ok(Self::IntT4), + 23 => Ok(Self::IntT5), + 24 => Ok(Self::IntT6), + 25 => Ok(Self::IntT7), + 26 => Ok(Self::IntS0), + 27 => Ok(Self::IntS1), + 28 => Ok(Self::IntS2), + 29 => Ok(Self::IntS3), + 30 => Ok(Self::IntS4), + 31 => Ok(Self::IntS5), + 32 => Ok(Self::IntS6), + 33 => Ok(Self::IntS7), + 34 => Ok(Self::IntT8), + 35 => Ok(Self::IntT9), + 36 => Ok(Self::IntKT0), + 37 => Ok(Self::IntKT1), + 38 => Ok(Self::IntGP), + 39 => Ok(Self::IntSP), + 40 => Ok(Self::IntS8), + 41 => Ok(Self::IntRA), + 42 => Ok(Self::IntLO), + 43 => Ok(Self::IntHI), + 50 => Ok(Self::Fir), + 51 => Ok(Self::Psr), + 60 => Ok(Self::FltF0), + 61 => Ok(Self::FltF1), + 62 => Ok(Self::FltF2), + 63 => Ok(Self::FltF3), + 64 => Ok(Self::FltF4), + 65 => Ok(Self::FltF5), + 66 => Ok(Self::FltF6), + 67 => Ok(Self::FltF7), + 68 => Ok(Self::FltF8), + 69 => Ok(Self::FltF9), + 70 => Ok(Self::FltF10), + 71 => Ok(Self::FltF11), + 72 => Ok(Self::FltF12), + 73 => Ok(Self::FltF13), + 74 => Ok(Self::FltF14), + 75 => Ok(Self::FltF15), + 76 => Ok(Self::FltF16), + 77 => Ok(Self::FltF17), + 78 => Ok(Self::FltF18), + 79 => Ok(Self::FltF19), + 80 => Ok(Self::FltF20), + 81 => Ok(Self::FltF21), + 82 => Ok(Self::FltF22), + 83 => Ok(Self::FltF23), + 84 => Ok(Self::FltF24), + 85 => Ok(Self::FltF25), + 86 => Ok(Self::FltF26), + 87 => Ok(Self::FltF27), + 88 => Ok(Self::FltF28), + 89 => Ok(Self::FltF29), + 90 => Ok(Self::FltF30), + 91 => Ok(Self::FltF31), + 92 => Ok(Self::FltFsr), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for MIPSRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the ALPHA AXP +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ALPHAAXPRegister { + FltF0 = 10, // Floating point registers + FltF1 = 11, + FltF2 = 12, + FltF3 = 13, + FltF4 = 14, + FltF5 = 15, + FltF6 = 16, + FltF7 = 17, + FltF8 = 18, + FltF9 = 19, + FltF10 = 20, + FltF11 = 21, + FltF12 = 22, + FltF13 = 23, + FltF14 = 24, + FltF15 = 25, + FltF16 = 26, + FltF17 = 27, + FltF18 = 28, + FltF19 = 29, + FltF20 = 30, + FltF21 = 31, + FltF22 = 32, + FltF23 = 33, + FltF24 = 34, + FltF25 = 35, + FltF26 = 36, + FltF27 = 37, + FltF28 = 38, + FltF29 = 39, + FltF30 = 40, + FltF31 = 41, + + IntV0 = 42, // Integer registers + IntT0 = 43, + IntT1 = 44, + IntT2 = 45, + IntT3 = 46, + IntT4 = 47, + IntT5 = 48, + IntT6 = 49, + IntT7 = 50, + IntS0 = 51, + IntS1 = 52, + IntS2 = 53, + IntS3 = 54, + IntS4 = 55, + IntS5 = 56, + IntFP = 57, + IntA0 = 58, + IntA1 = 59, + IntA2 = 60, + IntA3 = 61, + IntA4 = 62, + IntA5 = 63, + IntT8 = 64, + IntT9 = 65, + IntT10 = 66, + IntT11 = 67, + IntRA = 68, + IntT12 = 69, + IntAT = 70, + IntGP = 71, + IntSP = 72, + IntZERO = 73, + + Fpcr = 74, // Control registers + Fir = 75, + Psr = 76, + FltFsr = 77, + SoftFpcr = 78, +} + +impl fmt::Display for ALPHAAXPRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::FltF0 => write!(f, "FltF0"), + Self::FltF1 => write!(f, "FltF1"), + Self::FltF2 => write!(f, "FltF2"), + Self::FltF3 => write!(f, "FltF3"), + Self::FltF4 => write!(f, "FltF4"), + Self::FltF5 => write!(f, "FltF5"), + Self::FltF6 => write!(f, "FltF6"), + Self::FltF7 => write!(f, "FltF7"), + Self::FltF8 => write!(f, "FltF8"), + Self::FltF9 => write!(f, "FltF9"), + Self::FltF10 => write!(f, "FltF10"), + Self::FltF11 => write!(f, "FltF11"), + Self::FltF12 => write!(f, "FltF12"), + Self::FltF13 => write!(f, "FltF13"), + Self::FltF14 => write!(f, "FltF14"), + Self::FltF15 => write!(f, "FltF15"), + Self::FltF16 => write!(f, "FltF16"), + Self::FltF17 => write!(f, "FltF17"), + Self::FltF18 => write!(f, "FltF18"), + Self::FltF19 => write!(f, "FltF19"), + Self::FltF20 => write!(f, "FltF20"), + Self::FltF21 => write!(f, "FltF21"), + Self::FltF22 => write!(f, "FltF22"), + Self::FltF23 => write!(f, "FltF23"), + Self::FltF24 => write!(f, "FltF24"), + Self::FltF25 => write!(f, "FltF25"), + Self::FltF26 => write!(f, "FltF26"), + Self::FltF27 => write!(f, "FltF27"), + Self::FltF28 => write!(f, "FltF28"), + Self::FltF29 => write!(f, "FltF29"), + Self::FltF30 => write!(f, "FltF30"), + Self::FltF31 => write!(f, "FltF31"), + Self::IntV0 => write!(f, "IntV0"), + Self::IntT0 => write!(f, "IntT0"), + Self::IntT1 => write!(f, "IntT1"), + Self::IntT2 => write!(f, "IntT2"), + Self::IntT3 => write!(f, "IntT3"), + Self::IntT4 => write!(f, "IntT4"), + Self::IntT5 => write!(f, "IntT5"), + Self::IntT6 => write!(f, "IntT6"), + Self::IntT7 => write!(f, "IntT7"), + Self::IntS0 => write!(f, "IntS0"), + Self::IntS1 => write!(f, "IntS1"), + Self::IntS2 => write!(f, "IntS2"), + Self::IntS3 => write!(f, "IntS3"), + Self::IntS4 => write!(f, "IntS4"), + Self::IntS5 => write!(f, "IntS5"), + Self::IntFP => write!(f, "IntFP"), + Self::IntA0 => write!(f, "IntA0"), + Self::IntA1 => write!(f, "IntA1"), + Self::IntA2 => write!(f, "IntA2"), + Self::IntA3 => write!(f, "IntA3"), + Self::IntA4 => write!(f, "IntA4"), + Self::IntA5 => write!(f, "IntA5"), + Self::IntT8 => write!(f, "IntT8"), + Self::IntT9 => write!(f, "IntT9"), + Self::IntT10 => write!(f, "IntT10"), + Self::IntT11 => write!(f, "IntT11"), + Self::IntRA => write!(f, "IntRA"), + Self::IntT12 => write!(f, "IntT12"), + Self::IntAT => write!(f, "IntAT"), + Self::IntGP => write!(f, "IntGP"), + Self::IntSP => write!(f, "IntSP"), + Self::IntZERO => write!(f, "IntZERO"), + Self::Fpcr => write!(f, "Fpcr"), + Self::Fir => write!(f, "Fir"), + Self::Psr => write!(f, "Psr"), + Self::FltFsr => write!(f, "FltFsr"), + Self::SoftFpcr => write!(f, "SoftFpcr"), + } + } +} + +impl TryFrom for ALPHAAXPRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::FltF0), + 11 => Ok(Self::FltF1), + 12 => Ok(Self::FltF2), + 13 => Ok(Self::FltF3), + 14 => Ok(Self::FltF4), + 15 => Ok(Self::FltF5), + 16 => Ok(Self::FltF6), + 17 => Ok(Self::FltF7), + 18 => Ok(Self::FltF8), + 19 => Ok(Self::FltF9), + 20 => Ok(Self::FltF10), + 21 => Ok(Self::FltF11), + 22 => Ok(Self::FltF12), + 23 => Ok(Self::FltF13), + 24 => Ok(Self::FltF14), + 25 => Ok(Self::FltF15), + 26 => Ok(Self::FltF16), + 27 => Ok(Self::FltF17), + 28 => Ok(Self::FltF18), + 29 => Ok(Self::FltF19), + 30 => Ok(Self::FltF20), + 31 => Ok(Self::FltF21), + 32 => Ok(Self::FltF22), + 33 => Ok(Self::FltF23), + 34 => Ok(Self::FltF24), + 35 => Ok(Self::FltF25), + 36 => Ok(Self::FltF26), + 37 => Ok(Self::FltF27), + 38 => Ok(Self::FltF28), + 39 => Ok(Self::FltF29), + 40 => Ok(Self::FltF30), + 41 => Ok(Self::FltF31), + 42 => Ok(Self::IntV0), + 43 => Ok(Self::IntT0), + 44 => Ok(Self::IntT1), + 45 => Ok(Self::IntT2), + 46 => Ok(Self::IntT3), + 47 => Ok(Self::IntT4), + 48 => Ok(Self::IntT5), + 49 => Ok(Self::IntT6), + 50 => Ok(Self::IntT7), + 51 => Ok(Self::IntS0), + 52 => Ok(Self::IntS1), + 53 => Ok(Self::IntS2), + 54 => Ok(Self::IntS3), + 55 => Ok(Self::IntS4), + 56 => Ok(Self::IntS5), + 57 => Ok(Self::IntFP), + 58 => Ok(Self::IntA0), + 59 => Ok(Self::IntA1), + 60 => Ok(Self::IntA2), + 61 => Ok(Self::IntA3), + 62 => Ok(Self::IntA4), + 63 => Ok(Self::IntA5), + 64 => Ok(Self::IntT8), + 65 => Ok(Self::IntT9), + 66 => Ok(Self::IntT10), + 67 => Ok(Self::IntT11), + 68 => Ok(Self::IntRA), + 69 => Ok(Self::IntT12), + 70 => Ok(Self::IntAT), + 71 => Ok(Self::IntGP), + 72 => Ok(Self::IntSP), + 73 => Ok(Self::IntZERO), + 74 => Ok(Self::Fpcr), + 75 => Ok(Self::Fir), + 76 => Ok(Self::Psr), + 77 => Ok(Self::FltFsr), + 78 => Ok(Self::SoftFpcr), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for ALPHAAXPRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register Set for Motorola/IBM PowerPC +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum PowerPCRegister { + /* + ** PowerPC General Registers ( User Level ) + */ + GPR0 = 1, + GPR1 = 2, + GPR2 = 3, + GPR3 = 4, + GPR4 = 5, + GPR5 = 6, + GPR6 = 7, + GPR7 = 8, + GPR8 = 9, + GPR9 = 10, + GPR10 = 11, + GPR11 = 12, + GPR12 = 13, + GPR13 = 14, + GPR14 = 15, + GPR15 = 16, + GPR16 = 17, + GPR17 = 18, + GPR18 = 19, + GPR19 = 20, + GPR20 = 21, + GPR21 = 22, + GPR22 = 23, + GPR23 = 24, + GPR24 = 25, + GPR25 = 26, + GPR26 = 27, + GPR27 = 28, + GPR28 = 29, + GPR29 = 30, + GPR30 = 31, + GPR31 = 32, + + /* + ** PowerPC Condition Register ( User Level ) + */ + CR = 33, + CR0 = 34, + CR1 = 35, + CR2 = 36, + CR3 = 37, + CR4 = 38, + CR5 = 39, + CR6 = 40, + CR7 = 41, + + /* + ** PowerPC Floating Point Registers ( User Level ) + */ + FPR0 = 42, + FPR1 = 43, + FPR2 = 44, + FPR3 = 45, + FPR4 = 46, + FPR5 = 47, + FPR6 = 48, + FPR7 = 49, + FPR8 = 50, + FPR9 = 51, + FPR10 = 52, + FPR11 = 53, + FPR12 = 54, + FPR13 = 55, + FPR14 = 56, + FPR15 = 57, + FPR16 = 58, + FPR17 = 59, + FPR18 = 60, + FPR19 = 61, + FPR20 = 62, + FPR21 = 63, + FPR22 = 64, + FPR23 = 65, + FPR24 = 66, + FPR25 = 67, + FPR26 = 68, + FPR27 = 69, + FPR28 = 70, + FPR29 = 71, + FPR30 = 72, + FPR31 = 73, + + /* + ** PowerPC Floating Point Status and Control Register ( User Level ) + */ + FPSCR = 74, + + /* + ** PowerPC Machine State Register ( Supervisor Level ) + */ + MSR = 75, + + /* + ** PowerPC Segment Registers ( Supervisor Level ) + */ + SR0 = 76, + SR1 = 77, + SR2 = 78, + SR3 = 79, + SR4 = 80, + SR5 = 81, + SR6 = 82, + SR7 = 83, + SR8 = 84, + SR9 = 85, + SR10 = 86, + SR11 = 87, + SR12 = 88, + SR13 = 89, + SR14 = 90, + SR15 = 91, + + /* + ** For all of the special purpose registers add 100 to the SPR# that the + ** Motorola/IBM documentation gives with the exception of any imaginary + ** registers. + */ + + /* + ** PowerPC Special Purpose Registers ( User Level ) + */ + PC = 99, // PC (imaginary register) + + MQ = 100, // MPC601 + XER = 101, + RTCU = 104, // MPC601 + RTCL = 105, // MPC601 + LR = 108, + CTR = 109, + + COMPARE = 110, // part of XER (internal to the debugger only) + COUNT = 111, // part of XER (internal to the debugger only) + + /* + ** PowerPC Special Purpose Registers ( Supervisor Level ) + */ + DSISR = 118, + DAR = 119, + DEC = 122, + SDR1 = 125, + SRR0 = 126, + SRR1 = 127, + SPRG0 = 372, + SPRG1 = 373, + SPRG2 = 374, + SPRG3 = 375, + ASR = 280, // 64-bit implementations only + EAR = 382, + PVR = 287, + BAT0U = 628, + BAT0L = 629, + BAT1U = 630, + BAT1L = 631, + BAT2U = 632, + BAT2L = 633, + BAT3U = 634, + BAT3L = 635, + DBAT0U = 636, + DBAT0L = 637, + DBAT1U = 638, + DBAT1L = 639, + DBAT2U = 640, + DBAT2L = 641, + DBAT3U = 642, + DBAT3L = 643, + + /* + ** PowerPC Special Purpose Registers Implementation Dependent ( Supervisor Level ) + */ + + /* + ** Doesn't appear that IBM/Motorola has finished defining these. + */ + PMR0 = 1044, // MPC620, + PMR1 = 1045, // MPC620, + PMR2 = 1046, // MPC620, + PMR3 = 1047, // MPC620, + PMR4 = 1048, // MPC620, + PMR5 = 1049, // MPC620, + PMR6 = 1050, // MPC620, + PMR7 = 1051, // MPC620, + PMR8 = 1052, // MPC620, + PMR9 = 1053, // MPC620, + PMR10 = 1054, // MPC620, + PMR11 = 1055, // MPC620, + PMR12 = 1056, // MPC620, + PMR13 = 1057, // MPC620, + PMR14 = 1058, // MPC620, + PMR15 = 1059, // MPC620, + + DMISS = 1076, // MPC603 + DCMP = 1077, // MPC603 + HASH1 = 1078, // MPC603 + HASH2 = 1079, // MPC603 + IMISS = 1080, // MPC603 + ICMP = 1081, // MPC603 + RPA = 1082, // MPC603 + + HID0 = 1108, // MPC601, MPC603, MPC620 + HID1 = 1109, // MPC601 + HID2 = 1110, // MPC601, MPC603, MPC620 ( IABR ) + HID3 = 1111, // Not Defined + HID4 = 1112, // Not Defined + HID5 = 1113, // MPC601, MPC604, MPC620 ( DABR ) + HID6 = 1114, // Not Defined + HID7 = 1115, // Not Defined + HID8 = 1116, // MPC620 ( BUSCSR ) + HID9 = 1117, // MPC620 ( L2CSR ) + HID10 = 1118, // Not Defined + HID11 = 1119, // Not Defined + HID12 = 1120, // Not Defined + HID13 = 1121, // MPC604 ( HCR ) + HID14 = 1122, // Not Defined + HID15 = 1123, // MPC601, MPC604, MPC620 ( PIR ) +} + +impl fmt::Display for PowerPCRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::GPR0 => write!(f, "GPR0"), + Self::GPR1 => write!(f, "GPR1"), + Self::GPR2 => write!(f, "GPR2"), + Self::GPR3 => write!(f, "GPR3"), + Self::GPR4 => write!(f, "GPR4"), + Self::GPR5 => write!(f, "GPR5"), + Self::GPR6 => write!(f, "GPR6"), + Self::GPR7 => write!(f, "GPR7"), + Self::GPR8 => write!(f, "GPR8"), + Self::GPR9 => write!(f, "GPR9"), + Self::GPR10 => write!(f, "GPR10"), + Self::GPR11 => write!(f, "GPR11"), + Self::GPR12 => write!(f, "GPR12"), + Self::GPR13 => write!(f, "GPR13"), + Self::GPR14 => write!(f, "GPR14"), + Self::GPR15 => write!(f, "GPR15"), + Self::GPR16 => write!(f, "GPR16"), + Self::GPR17 => write!(f, "GPR17"), + Self::GPR18 => write!(f, "GPR18"), + Self::GPR19 => write!(f, "GPR19"), + Self::GPR20 => write!(f, "GPR20"), + Self::GPR21 => write!(f, "GPR21"), + Self::GPR22 => write!(f, "GPR22"), + Self::GPR23 => write!(f, "GPR23"), + Self::GPR24 => write!(f, "GPR24"), + Self::GPR25 => write!(f, "GPR25"), + Self::GPR26 => write!(f, "GPR26"), + Self::GPR27 => write!(f, "GPR27"), + Self::GPR28 => write!(f, "GPR28"), + Self::GPR29 => write!(f, "GPR29"), + Self::GPR30 => write!(f, "GPR30"), + Self::GPR31 => write!(f, "GPR31"), + Self::CR => write!(f, "CR"), + Self::CR0 => write!(f, "CR0"), + Self::CR1 => write!(f, "CR1"), + Self::CR2 => write!(f, "CR2"), + Self::CR3 => write!(f, "CR3"), + Self::CR4 => write!(f, "CR4"), + Self::CR5 => write!(f, "CR5"), + Self::CR6 => write!(f, "CR6"), + Self::CR7 => write!(f, "CR7"), + Self::FPR0 => write!(f, "FPR0"), + Self::FPR1 => write!(f, "FPR1"), + Self::FPR2 => write!(f, "FPR2"), + Self::FPR3 => write!(f, "FPR3"), + Self::FPR4 => write!(f, "FPR4"), + Self::FPR5 => write!(f, "FPR5"), + Self::FPR6 => write!(f, "FPR6"), + Self::FPR7 => write!(f, "FPR7"), + Self::FPR8 => write!(f, "FPR8"), + Self::FPR9 => write!(f, "FPR9"), + Self::FPR10 => write!(f, "FPR10"), + Self::FPR11 => write!(f, "FPR11"), + Self::FPR12 => write!(f, "FPR12"), + Self::FPR13 => write!(f, "FPR13"), + Self::FPR14 => write!(f, "FPR14"), + Self::FPR15 => write!(f, "FPR15"), + Self::FPR16 => write!(f, "FPR16"), + Self::FPR17 => write!(f, "FPR17"), + Self::FPR18 => write!(f, "FPR18"), + Self::FPR19 => write!(f, "FPR19"), + Self::FPR20 => write!(f, "FPR20"), + Self::FPR21 => write!(f, "FPR21"), + Self::FPR22 => write!(f, "FPR22"), + Self::FPR23 => write!(f, "FPR23"), + Self::FPR24 => write!(f, "FPR24"), + Self::FPR25 => write!(f, "FPR25"), + Self::FPR26 => write!(f, "FPR26"), + Self::FPR27 => write!(f, "FPR27"), + Self::FPR28 => write!(f, "FPR28"), + Self::FPR29 => write!(f, "FPR29"), + Self::FPR30 => write!(f, "FPR30"), + Self::FPR31 => write!(f, "FPR31"), + Self::FPSCR => write!(f, "FPSCR"), + Self::MSR => write!(f, "MSR"), + Self::SR0 => write!(f, "SR0"), + Self::SR1 => write!(f, "SR1"), + Self::SR2 => write!(f, "SR2"), + Self::SR3 => write!(f, "SR3"), + Self::SR4 => write!(f, "SR4"), + Self::SR5 => write!(f, "SR5"), + Self::SR6 => write!(f, "SR6"), + Self::SR7 => write!(f, "SR7"), + Self::SR8 => write!(f, "SR8"), + Self::SR9 => write!(f, "SR9"), + Self::SR10 => write!(f, "SR10"), + Self::SR11 => write!(f, "SR11"), + Self::SR12 => write!(f, "SR12"), + Self::SR13 => write!(f, "SR13"), + Self::SR14 => write!(f, "SR14"), + Self::SR15 => write!(f, "SR15"), + Self::PC => write!(f, "PC"), + Self::MQ => write!(f, "MQ"), + Self::XER => write!(f, "XER"), + Self::RTCU => write!(f, "RTCU"), + Self::RTCL => write!(f, "RTCL"), + Self::LR => write!(f, "LR"), + Self::CTR => write!(f, "CTR"), + Self::COMPARE => write!(f, "COMPARE"), + Self::COUNT => write!(f, "COUNT"), + Self::DSISR => write!(f, "DSISR"), + Self::DAR => write!(f, "DAR"), + Self::DEC => write!(f, "DEC"), + Self::SDR1 => write!(f, "SDR1"), + Self::SRR0 => write!(f, "SRR0"), + Self::SRR1 => write!(f, "SRR1"), + Self::SPRG0 => write!(f, "SPRG0"), + Self::SPRG1 => write!(f, "SPRG1"), + Self::SPRG2 => write!(f, "SPRG2"), + Self::SPRG3 => write!(f, "SPRG3"), + Self::ASR => write!(f, "ASR"), + Self::EAR => write!(f, "EAR"), + Self::PVR => write!(f, "PVR"), + Self::BAT0U => write!(f, "BAT0U"), + Self::BAT0L => write!(f, "BAT0L"), + Self::BAT1U => write!(f, "BAT1U"), + Self::BAT1L => write!(f, "BAT1L"), + Self::BAT2U => write!(f, "BAT2U"), + Self::BAT2L => write!(f, "BAT2L"), + Self::BAT3U => write!(f, "BAT3U"), + Self::BAT3L => write!(f, "BAT3L"), + Self::DBAT0U => write!(f, "DBAT0U"), + Self::DBAT0L => write!(f, "DBAT0L"), + Self::DBAT1U => write!(f, "DBAT1U"), + Self::DBAT1L => write!(f, "DBAT1L"), + Self::DBAT2U => write!(f, "DBAT2U"), + Self::DBAT2L => write!(f, "DBAT2L"), + Self::DBAT3U => write!(f, "DBAT3U"), + Self::DBAT3L => write!(f, "DBAT3L"), + Self::PMR0 => write!(f, "PMR0"), + Self::PMR1 => write!(f, "PMR1"), + Self::PMR2 => write!(f, "PMR2"), + Self::PMR3 => write!(f, "PMR3"), + Self::PMR4 => write!(f, "PMR4"), + Self::PMR5 => write!(f, "PMR5"), + Self::PMR6 => write!(f, "PMR6"), + Self::PMR7 => write!(f, "PMR7"), + Self::PMR8 => write!(f, "PMR8"), + Self::PMR9 => write!(f, "PMR9"), + Self::PMR10 => write!(f, "PMR10"), + Self::PMR11 => write!(f, "PMR11"), + Self::PMR12 => write!(f, "PMR12"), + Self::PMR13 => write!(f, "PMR13"), + Self::PMR14 => write!(f, "PMR14"), + Self::PMR15 => write!(f, "PMR15"), + Self::DMISS => write!(f, "DMISS"), + Self::DCMP => write!(f, "DCMP"), + Self::HASH1 => write!(f, "HASH1"), + Self::HASH2 => write!(f, "HASH2"), + Self::IMISS => write!(f, "IMISS"), + Self::ICMP => write!(f, "ICMP"), + Self::RPA => write!(f, "RPA"), + Self::HID0 => write!(f, "HID0"), + Self::HID1 => write!(f, "HID1"), + Self::HID2 => write!(f, "HID2"), + Self::HID3 => write!(f, "HID3"), + Self::HID4 => write!(f, "HID4"), + Self::HID5 => write!(f, "HID5"), + Self::HID6 => write!(f, "HID6"), + Self::HID7 => write!(f, "HID7"), + Self::HID8 => write!(f, "HID8"), + Self::HID9 => write!(f, "HID9"), + Self::HID10 => write!(f, "HID10"), + Self::HID11 => write!(f, "HID11"), + Self::HID12 => write!(f, "HID12"), + Self::HID13 => write!(f, "HID13"), + Self::HID14 => write!(f, "HID14"), + Self::HID15 => write!(f, "HID15"), + } + } +} + +impl TryFrom for PowerPCRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 1 => Ok(Self::GPR0), + 2 => Ok(Self::GPR1), + 3 => Ok(Self::GPR2), + 4 => Ok(Self::GPR3), + 5 => Ok(Self::GPR4), + 6 => Ok(Self::GPR5), + 7 => Ok(Self::GPR6), + 8 => Ok(Self::GPR7), + 9 => Ok(Self::GPR8), + 10 => Ok(Self::GPR9), + 11 => Ok(Self::GPR10), + 12 => Ok(Self::GPR11), + 13 => Ok(Self::GPR12), + 14 => Ok(Self::GPR13), + 15 => Ok(Self::GPR14), + 16 => Ok(Self::GPR15), + 17 => Ok(Self::GPR16), + 18 => Ok(Self::GPR17), + 19 => Ok(Self::GPR18), + 20 => Ok(Self::GPR19), + 21 => Ok(Self::GPR20), + 22 => Ok(Self::GPR21), + 23 => Ok(Self::GPR22), + 24 => Ok(Self::GPR23), + 25 => Ok(Self::GPR24), + 26 => Ok(Self::GPR25), + 27 => Ok(Self::GPR26), + 28 => Ok(Self::GPR27), + 29 => Ok(Self::GPR28), + 30 => Ok(Self::GPR29), + 31 => Ok(Self::GPR30), + 32 => Ok(Self::GPR31), + 33 => Ok(Self::CR), + 34 => Ok(Self::CR0), + 35 => Ok(Self::CR1), + 36 => Ok(Self::CR2), + 37 => Ok(Self::CR3), + 38 => Ok(Self::CR4), + 39 => Ok(Self::CR5), + 40 => Ok(Self::CR6), + 41 => Ok(Self::CR7), + 42 => Ok(Self::FPR0), + 43 => Ok(Self::FPR1), + 44 => Ok(Self::FPR2), + 45 => Ok(Self::FPR3), + 46 => Ok(Self::FPR4), + 47 => Ok(Self::FPR5), + 48 => Ok(Self::FPR6), + 49 => Ok(Self::FPR7), + 50 => Ok(Self::FPR8), + 51 => Ok(Self::FPR9), + 52 => Ok(Self::FPR10), + 53 => Ok(Self::FPR11), + 54 => Ok(Self::FPR12), + 55 => Ok(Self::FPR13), + 56 => Ok(Self::FPR14), + 57 => Ok(Self::FPR15), + 58 => Ok(Self::FPR16), + 59 => Ok(Self::FPR17), + 60 => Ok(Self::FPR18), + 61 => Ok(Self::FPR19), + 62 => Ok(Self::FPR20), + 63 => Ok(Self::FPR21), + 64 => Ok(Self::FPR22), + 65 => Ok(Self::FPR23), + 66 => Ok(Self::FPR24), + 67 => Ok(Self::FPR25), + 68 => Ok(Self::FPR26), + 69 => Ok(Self::FPR27), + 70 => Ok(Self::FPR28), + 71 => Ok(Self::FPR29), + 72 => Ok(Self::FPR30), + 73 => Ok(Self::FPR31), + 74 => Ok(Self::FPSCR), + 75 => Ok(Self::MSR), + 76 => Ok(Self::SR0), + 77 => Ok(Self::SR1), + 78 => Ok(Self::SR2), + 79 => Ok(Self::SR3), + 80 => Ok(Self::SR4), + 81 => Ok(Self::SR5), + 82 => Ok(Self::SR6), + 83 => Ok(Self::SR7), + 84 => Ok(Self::SR8), + 85 => Ok(Self::SR9), + 86 => Ok(Self::SR10), + 87 => Ok(Self::SR11), + 88 => Ok(Self::SR12), + 89 => Ok(Self::SR13), + 90 => Ok(Self::SR14), + 91 => Ok(Self::SR15), + 99 => Ok(Self::PC), + 100 => Ok(Self::MQ), + 101 => Ok(Self::XER), + 104 => Ok(Self::RTCU), + 105 => Ok(Self::RTCL), + 108 => Ok(Self::LR), + 109 => Ok(Self::CTR), + 110 => Ok(Self::COMPARE), + 111 => Ok(Self::COUNT), + 118 => Ok(Self::DSISR), + 119 => Ok(Self::DAR), + 122 => Ok(Self::DEC), + 125 => Ok(Self::SDR1), + 126 => Ok(Self::SRR0), + 127 => Ok(Self::SRR1), + 372 => Ok(Self::SPRG0), + 373 => Ok(Self::SPRG1), + 374 => Ok(Self::SPRG2), + 375 => Ok(Self::SPRG3), + 280 => Ok(Self::ASR), + 382 => Ok(Self::EAR), + 287 => Ok(Self::PVR), + 628 => Ok(Self::BAT0U), + 629 => Ok(Self::BAT0L), + 630 => Ok(Self::BAT1U), + 631 => Ok(Self::BAT1L), + 632 => Ok(Self::BAT2U), + 633 => Ok(Self::BAT2L), + 634 => Ok(Self::BAT3U), + 635 => Ok(Self::BAT3L), + 636 => Ok(Self::DBAT0U), + 637 => Ok(Self::DBAT0L), + 638 => Ok(Self::DBAT1U), + 639 => Ok(Self::DBAT1L), + 640 => Ok(Self::DBAT2U), + 641 => Ok(Self::DBAT2L), + 642 => Ok(Self::DBAT3U), + 643 => Ok(Self::DBAT3L), + 1044 => Ok(Self::PMR0), + 1045 => Ok(Self::PMR1), + 1046 => Ok(Self::PMR2), + 1047 => Ok(Self::PMR3), + 1048 => Ok(Self::PMR4), + 1049 => Ok(Self::PMR5), + 1050 => Ok(Self::PMR6), + 1051 => Ok(Self::PMR7), + 1052 => Ok(Self::PMR8), + 1053 => Ok(Self::PMR9), + 1054 => Ok(Self::PMR10), + 1055 => Ok(Self::PMR11), + 1056 => Ok(Self::PMR12), + 1057 => Ok(Self::PMR13), + 1058 => Ok(Self::PMR14), + 1059 => Ok(Self::PMR15), + 1076 => Ok(Self::DMISS), + 1077 => Ok(Self::DCMP), + 1078 => Ok(Self::HASH1), + 1079 => Ok(Self::HASH2), + 1080 => Ok(Self::IMISS), + 1081 => Ok(Self::ICMP), + 1082 => Ok(Self::RPA), + 1108 => Ok(Self::HID0), + 1109 => Ok(Self::HID1), + 1110 => Ok(Self::HID2), + 1111 => Ok(Self::HID3), + 1112 => Ok(Self::HID4), + 1113 => Ok(Self::HID5), + 1114 => Ok(Self::HID6), + 1115 => Ok(Self::HID7), + 1116 => Ok(Self::HID8), + 1117 => Ok(Self::HID9), + 1118 => Ok(Self::HID10), + 1119 => Ok(Self::HID11), + 1120 => Ok(Self::HID12), + 1121 => Ok(Self::HID13), + 1122 => Ok(Self::HID14), + 1123 => Ok(Self::HID15), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for PowerPCRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// JAVA VM registers +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum JavaRegister { + PC = 1, +} + +impl fmt::Display for JavaRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::PC => write!(f, "PC"), + } + } +} + +impl TryFrom for JavaRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 1 => Ok(Self::PC), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for JavaRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the Hitachi SH(3) +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum HitachiSHRegister { + IntR0 = 10, // CPU REGISTER + IntR1 = 11, + IntR2 = 12, + IntR3 = 13, + IntR4 = 14, + IntR5 = 15, + IntR6 = 16, + IntR7 = 17, + IntR8 = 18, + IntR9 = 19, + IntR10 = 20, + IntR11 = 21, + IntR12 = 22, + IntR13 = 23, + IntFp = 24, + IntSp = 25, + Gbr = 38, + Pr = 39, + Mach = 40, + Macl = 41, + + Pc = 50, + Sr = 51, + + BarA = 60, + BasrA = 61, + BamrA = 62, + BbrA = 63, + BarB = 64, + BasrB = 65, + BamrB = 66, + BbrB = 67, + BdrB = 68, + BdmrB = 69, + Brcr = 70, + + // + // Additional registers for Hitachi SH processors + // + Fpscr = 75, // floating point status/control register + Fpul = 76, // floating point communication register + + FpR0 = 80, // Floating point registers + FpR1 = 81, + FpR2 = 82, + FpR3 = 83, + FpR4 = 84, + FpR5 = 85, + FpR6 = 86, + FpR7 = 87, + FpR8 = 88, + FpR9 = 89, + FpR10 = 90, + FpR11 = 91, + FpR12 = 92, + FpR13 = 93, + FpR14 = 94, + FpR15 = 95, + + XFpR0 = 96, + XFpR1 = 97, + XFpR2 = 98, + XFpR3 = 99, + XFpR4 = 100, + XFpR5 = 101, + XFpR6 = 102, + XFpR7 = 103, + XFpR8 = 104, + XFpR9 = 105, + XFpR10 = 106, + XFpR11 = 107, + XFpR12 = 108, + XFpR13 = 109, + XFpR14 = 110, + XFpR15 = 111, +} + +impl fmt::Display for HitachiSHRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::IntR0 => write!(f, "IntR0"), + Self::IntR1 => write!(f, "IntR1"), + Self::IntR2 => write!(f, "IntR2"), + Self::IntR3 => write!(f, "IntR3"), + Self::IntR4 => write!(f, "IntR4"), + Self::IntR5 => write!(f, "IntR5"), + Self::IntR6 => write!(f, "IntR6"), + Self::IntR7 => write!(f, "IntR7"), + Self::IntR8 => write!(f, "IntR8"), + Self::IntR9 => write!(f, "IntR9"), + Self::IntR10 => write!(f, "IntR10"), + Self::IntR11 => write!(f, "IntR11"), + Self::IntR12 => write!(f, "IntR12"), + Self::IntR13 => write!(f, "IntR13"), + Self::IntFp => write!(f, "IntFp"), + Self::IntSp => write!(f, "IntSp"), + Self::Gbr => write!(f, "Gbr"), + Self::Pr => write!(f, "Pr"), + Self::Mach => write!(f, "Mach"), + Self::Macl => write!(f, "Macl"), + Self::Pc => write!(f, "Pc"), + Self::Sr => write!(f, "Sr"), + Self::BarA => write!(f, "BarA"), + Self::BasrA => write!(f, "BasrA"), + Self::BamrA => write!(f, "BamrA"), + Self::BbrA => write!(f, "BbrA"), + Self::BarB => write!(f, "BarB"), + Self::BasrB => write!(f, "BasrB"), + Self::BamrB => write!(f, "BamrB"), + Self::BbrB => write!(f, "BbrB"), + Self::BdrB => write!(f, "BdrB"), + Self::BdmrB => write!(f, "BdmrB"), + Self::Brcr => write!(f, "Brcr"), + Self::Fpscr => write!(f, "Fpscr"), + Self::Fpul => write!(f, "Fpul"), + Self::FpR0 => write!(f, "FpR0"), + Self::FpR1 => write!(f, "FpR1"), + Self::FpR2 => write!(f, "FpR2"), + Self::FpR3 => write!(f, "FpR3"), + Self::FpR4 => write!(f, "FpR4"), + Self::FpR5 => write!(f, "FpR5"), + Self::FpR6 => write!(f, "FpR6"), + Self::FpR7 => write!(f, "FpR7"), + Self::FpR8 => write!(f, "FpR8"), + Self::FpR9 => write!(f, "FpR9"), + Self::FpR10 => write!(f, "FpR10"), + Self::FpR11 => write!(f, "FpR11"), + Self::FpR12 => write!(f, "FpR12"), + Self::FpR13 => write!(f, "FpR13"), + Self::FpR14 => write!(f, "FpR14"), + Self::FpR15 => write!(f, "FpR15"), + Self::XFpR0 => write!(f, "XFpR0"), + Self::XFpR1 => write!(f, "XFpR1"), + Self::XFpR2 => write!(f, "XFpR2"), + Self::XFpR3 => write!(f, "XFpR3"), + Self::XFpR4 => write!(f, "XFpR4"), + Self::XFpR5 => write!(f, "XFpR5"), + Self::XFpR6 => write!(f, "XFpR6"), + Self::XFpR7 => write!(f, "XFpR7"), + Self::XFpR8 => write!(f, "XFpR8"), + Self::XFpR9 => write!(f, "XFpR9"), + Self::XFpR10 => write!(f, "XFpR10"), + Self::XFpR11 => write!(f, "XFpR11"), + Self::XFpR12 => write!(f, "XFpR12"), + Self::XFpR13 => write!(f, "XFpR13"), + Self::XFpR14 => write!(f, "XFpR14"), + Self::XFpR15 => write!(f, "XFpR15"), + } + } +} + +impl TryFrom for HitachiSHRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::IntR0), + 11 => Ok(Self::IntR1), + 12 => Ok(Self::IntR2), + 13 => Ok(Self::IntR3), + 14 => Ok(Self::IntR4), + 15 => Ok(Self::IntR5), + 16 => Ok(Self::IntR6), + 17 => Ok(Self::IntR7), + 18 => Ok(Self::IntR8), + 19 => Ok(Self::IntR9), + 20 => Ok(Self::IntR10), + 21 => Ok(Self::IntR11), + 22 => Ok(Self::IntR12), + 23 => Ok(Self::IntR13), + 24 => Ok(Self::IntFp), + 25 => Ok(Self::IntSp), + 38 => Ok(Self::Gbr), + 39 => Ok(Self::Pr), + 40 => Ok(Self::Mach), + 41 => Ok(Self::Macl), + 50 => Ok(Self::Pc), + 51 => Ok(Self::Sr), + 60 => Ok(Self::BarA), + 61 => Ok(Self::BasrA), + 62 => Ok(Self::BamrA), + 63 => Ok(Self::BbrA), + 64 => Ok(Self::BarB), + 65 => Ok(Self::BasrB), + 66 => Ok(Self::BamrB), + 67 => Ok(Self::BbrB), + 68 => Ok(Self::BdrB), + 69 => Ok(Self::BdmrB), + 70 => Ok(Self::Brcr), + 75 => Ok(Self::Fpscr), + 76 => Ok(Self::Fpul), + 80 => Ok(Self::FpR0), + 81 => Ok(Self::FpR1), + 82 => Ok(Self::FpR2), + 83 => Ok(Self::FpR3), + 84 => Ok(Self::FpR4), + 85 => Ok(Self::FpR5), + 86 => Ok(Self::FpR6), + 87 => Ok(Self::FpR7), + 88 => Ok(Self::FpR8), + 89 => Ok(Self::FpR9), + 90 => Ok(Self::FpR10), + 91 => Ok(Self::FpR11), + 92 => Ok(Self::FpR12), + 93 => Ok(Self::FpR13), + 94 => Ok(Self::FpR14), + 95 => Ok(Self::FpR15), + 96 => Ok(Self::XFpR0), + 97 => Ok(Self::XFpR1), + 98 => Ok(Self::XFpR2), + 99 => Ok(Self::XFpR3), + 100 => Ok(Self::XFpR4), + 101 => Ok(Self::XFpR5), + 102 => Ok(Self::XFpR6), + 103 => Ok(Self::XFpR7), + 104 => Ok(Self::XFpR8), + 105 => Ok(Self::XFpR9), + 106 => Ok(Self::XFpR10), + 107 => Ok(Self::XFpR11), + 108 => Ok(Self::XFpR12), + 109 => Ok(Self::XFpR13), + 110 => Ok(Self::XFpR14), + 111 => Ok(Self::XFpR15), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for HitachiSHRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the ARM processor +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ARMRegister { + R0 = 10, + R1 = 11, + R2 = 12, + R3 = 13, + R4 = 14, + R5 = 15, + R6 = 16, + R7 = 17, + R8 = 18, + R9 = 19, + R10 = 20, + R11 = 21, // Frame pointer, if allocated + R12 = 22, + SP = 23, // Stack pointer + LR = 24, // Link Register + PC = 25, // Program counter + CPSR = 26, // Current program status register + + ACC0 = 27, // DSP co-processor 0 40 bit accumulator + + // + // Registers for ARM VFP10 support + // + FPSCR = 40, + FPEXC = 41, + + FS0 = 50, + FS1 = 51, + FS2 = 52, + FS3 = 53, + FS4 = 54, + FS5 = 55, + FS6 = 56, + FS7 = 57, + FS8 = 58, + FS9 = 59, + FS10 = 60, + FS11 = 61, + FS12 = 62, + FS13 = 63, + FS14 = 64, + FS15 = 65, + FS16 = 66, + FS17 = 67, + FS18 = 68, + FS19 = 69, + FS20 = 70, + FS21 = 71, + FS22 = 72, + FS23 = 73, + FS24 = 74, + FS25 = 75, + FS26 = 76, + FS27 = 77, + FS28 = 78, + FS29 = 79, + FS30 = 80, + FS31 = 81, + + // + // ARM VFP Floating Point Extra control registers + // + FPEXTRA0 = 90, + FPEXTRA1 = 91, + FPEXTRA2 = 92, + FPEXTRA3 = 93, + FPEXTRA4 = 94, + FPEXTRA5 = 95, + FPEXTRA6 = 96, + FPEXTRA7 = 97, + + // XSCALE Concan co-processor registers + WR0 = 128, + WR1 = 129, + WR2 = 130, + WR3 = 131, + WR4 = 132, + WR5 = 133, + WR6 = 134, + WR7 = 135, + WR8 = 136, + WR9 = 137, + WR10 = 138, + WR11 = 139, + WR12 = 140, + WR13 = 141, + WR14 = 142, + WR15 = 143, + + // XSCALE Concan co-processor control registers + WCID = 144, + WCON = 145, + WCSSF = 146, + WCASF = 147, + WC4 = 148, + WC5 = 149, + WC6 = 150, + WC7 = 151, + WCGR0 = 152, + WCGR1 = 153, + WCGR2 = 154, + WCGR3 = 155, + WC12 = 156, + WC13 = 157, + WC14 = 158, + WC15 = 159, + + // + // ARM VFPv3/Neon extended floating Point + // + FS32 = 200, + FS33 = 201, + FS34 = 202, + FS35 = 203, + FS36 = 204, + FS37 = 205, + FS38 = 206, + FS39 = 207, + FS40 = 208, + FS41 = 209, + FS42 = 210, + FS43 = 211, + FS44 = 212, + FS45 = 213, + FS46 = 214, + FS47 = 215, + FS48 = 216, + FS49 = 217, + FS50 = 218, + FS51 = 219, + FS52 = 220, + FS53 = 221, + FS54 = 222, + FS55 = 223, + FS56 = 224, + FS57 = 225, + FS58 = 226, + FS59 = 227, + FS60 = 228, + FS61 = 229, + FS62 = 230, + FS63 = 231, + + // ARM double-precision floating point + ND0 = 300, + ND1 = 301, + ND2 = 302, + ND3 = 303, + ND4 = 304, + ND5 = 305, + ND6 = 306, + ND7 = 307, + ND8 = 308, + ND9 = 309, + ND10 = 310, + ND11 = 311, + ND12 = 312, + ND13 = 313, + ND14 = 314, + ND15 = 315, + ND16 = 316, + ND17 = 317, + ND18 = 318, + ND19 = 319, + ND20 = 320, + ND21 = 321, + ND22 = 322, + ND23 = 323, + ND24 = 324, + ND25 = 325, + ND26 = 326, + ND27 = 327, + ND28 = 328, + ND29 = 329, + ND30 = 330, + ND31 = 331, + + // ARM extended precision floating point + NQ0 = 400, + NQ1 = 401, + NQ2 = 402, + NQ3 = 403, + NQ4 = 404, + NQ5 = 405, + NQ6 = 406, + NQ7 = 407, + NQ8 = 408, + NQ9 = 409, + NQ10 = 410, + NQ11 = 411, + NQ12 = 412, + NQ13 = 413, + NQ14 = 414, + NQ15 = 415, +} + +impl fmt::Display for ARMRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::R0 => write!(f, "R0"), + Self::R1 => write!(f, "R1"), + Self::R2 => write!(f, "R2"), + Self::R3 => write!(f, "R3"), + Self::R4 => write!(f, "R4"), + Self::R5 => write!(f, "R5"), + Self::R6 => write!(f, "R6"), + Self::R7 => write!(f, "R7"), + Self::R8 => write!(f, "R8"), + Self::R9 => write!(f, "R9"), + Self::R10 => write!(f, "R10"), + Self::R11 => write!(f, "R11"), + Self::R12 => write!(f, "R12"), + Self::SP => write!(f, "SP"), + Self::LR => write!(f, "LR"), + Self::PC => write!(f, "PC"), + Self::CPSR => write!(f, "CPSR"), + Self::ACC0 => write!(f, "ACC0"), + Self::FPSCR => write!(f, "FPSCR"), + Self::FPEXC => write!(f, "FPEXC"), + Self::FS0 => write!(f, "FS0"), + Self::FS1 => write!(f, "FS1"), + Self::FS2 => write!(f, "FS2"), + Self::FS3 => write!(f, "FS3"), + Self::FS4 => write!(f, "FS4"), + Self::FS5 => write!(f, "FS5"), + Self::FS6 => write!(f, "FS6"), + Self::FS7 => write!(f, "FS7"), + Self::FS8 => write!(f, "FS8"), + Self::FS9 => write!(f, "FS9"), + Self::FS10 => write!(f, "FS10"), + Self::FS11 => write!(f, "FS11"), + Self::FS12 => write!(f, "FS12"), + Self::FS13 => write!(f, "FS13"), + Self::FS14 => write!(f, "FS14"), + Self::FS15 => write!(f, "FS15"), + Self::FS16 => write!(f, "FS16"), + Self::FS17 => write!(f, "FS17"), + Self::FS18 => write!(f, "FS18"), + Self::FS19 => write!(f, "FS19"), + Self::FS20 => write!(f, "FS20"), + Self::FS21 => write!(f, "FS21"), + Self::FS22 => write!(f, "FS22"), + Self::FS23 => write!(f, "FS23"), + Self::FS24 => write!(f, "FS24"), + Self::FS25 => write!(f, "FS25"), + Self::FS26 => write!(f, "FS26"), + Self::FS27 => write!(f, "FS27"), + Self::FS28 => write!(f, "FS28"), + Self::FS29 => write!(f, "FS29"), + Self::FS30 => write!(f, "FS30"), + Self::FS31 => write!(f, "FS31"), + Self::FPEXTRA0 => write!(f, "FPEXTRA0"), + Self::FPEXTRA1 => write!(f, "FPEXTRA1"), + Self::FPEXTRA2 => write!(f, "FPEXTRA2"), + Self::FPEXTRA3 => write!(f, "FPEXTRA3"), + Self::FPEXTRA4 => write!(f, "FPEXTRA4"), + Self::FPEXTRA5 => write!(f, "FPEXTRA5"), + Self::FPEXTRA6 => write!(f, "FPEXTRA6"), + Self::FPEXTRA7 => write!(f, "FPEXTRA7"), + Self::WR0 => write!(f, "WR0"), + Self::WR1 => write!(f, "WR1"), + Self::WR2 => write!(f, "WR2"), + Self::WR3 => write!(f, "WR3"), + Self::WR4 => write!(f, "WR4"), + Self::WR5 => write!(f, "WR5"), + Self::WR6 => write!(f, "WR6"), + Self::WR7 => write!(f, "WR7"), + Self::WR8 => write!(f, "WR8"), + Self::WR9 => write!(f, "WR9"), + Self::WR10 => write!(f, "WR10"), + Self::WR11 => write!(f, "WR11"), + Self::WR12 => write!(f, "WR12"), + Self::WR13 => write!(f, "WR13"), + Self::WR14 => write!(f, "WR14"), + Self::WR15 => write!(f, "WR15"), + Self::WCID => write!(f, "WCID"), + Self::WCON => write!(f, "WCON"), + Self::WCSSF => write!(f, "WCSSF"), + Self::WCASF => write!(f, "WCASF"), + Self::WC4 => write!(f, "WC4"), + Self::WC5 => write!(f, "WC5"), + Self::WC6 => write!(f, "WC6"), + Self::WC7 => write!(f, "WC7"), + Self::WCGR0 => write!(f, "WCGR0"), + Self::WCGR1 => write!(f, "WCGR1"), + Self::WCGR2 => write!(f, "WCGR2"), + Self::WCGR3 => write!(f, "WCGR3"), + Self::WC12 => write!(f, "WC12"), + Self::WC13 => write!(f, "WC13"), + Self::WC14 => write!(f, "WC14"), + Self::WC15 => write!(f, "WC15"), + Self::FS32 => write!(f, "FS32"), + Self::FS33 => write!(f, "FS33"), + Self::FS34 => write!(f, "FS34"), + Self::FS35 => write!(f, "FS35"), + Self::FS36 => write!(f, "FS36"), + Self::FS37 => write!(f, "FS37"), + Self::FS38 => write!(f, "FS38"), + Self::FS39 => write!(f, "FS39"), + Self::FS40 => write!(f, "FS40"), + Self::FS41 => write!(f, "FS41"), + Self::FS42 => write!(f, "FS42"), + Self::FS43 => write!(f, "FS43"), + Self::FS44 => write!(f, "FS44"), + Self::FS45 => write!(f, "FS45"), + Self::FS46 => write!(f, "FS46"), + Self::FS47 => write!(f, "FS47"), + Self::FS48 => write!(f, "FS48"), + Self::FS49 => write!(f, "FS49"), + Self::FS50 => write!(f, "FS50"), + Self::FS51 => write!(f, "FS51"), + Self::FS52 => write!(f, "FS52"), + Self::FS53 => write!(f, "FS53"), + Self::FS54 => write!(f, "FS54"), + Self::FS55 => write!(f, "FS55"), + Self::FS56 => write!(f, "FS56"), + Self::FS57 => write!(f, "FS57"), + Self::FS58 => write!(f, "FS58"), + Self::FS59 => write!(f, "FS59"), + Self::FS60 => write!(f, "FS60"), + Self::FS61 => write!(f, "FS61"), + Self::FS62 => write!(f, "FS62"), + Self::FS63 => write!(f, "FS63"), + Self::ND0 => write!(f, "ND0"), + Self::ND1 => write!(f, "ND1"), + Self::ND2 => write!(f, "ND2"), + Self::ND3 => write!(f, "ND3"), + Self::ND4 => write!(f, "ND4"), + Self::ND5 => write!(f, "ND5"), + Self::ND6 => write!(f, "ND6"), + Self::ND7 => write!(f, "ND7"), + Self::ND8 => write!(f, "ND8"), + Self::ND9 => write!(f, "ND9"), + Self::ND10 => write!(f, "ND10"), + Self::ND11 => write!(f, "ND11"), + Self::ND12 => write!(f, "ND12"), + Self::ND13 => write!(f, "ND13"), + Self::ND14 => write!(f, "ND14"), + Self::ND15 => write!(f, "ND15"), + Self::ND16 => write!(f, "ND16"), + Self::ND17 => write!(f, "ND17"), + Self::ND18 => write!(f, "ND18"), + Self::ND19 => write!(f, "ND19"), + Self::ND20 => write!(f, "ND20"), + Self::ND21 => write!(f, "ND21"), + Self::ND22 => write!(f, "ND22"), + Self::ND23 => write!(f, "ND23"), + Self::ND24 => write!(f, "ND24"), + Self::ND25 => write!(f, "ND25"), + Self::ND26 => write!(f, "ND26"), + Self::ND27 => write!(f, "ND27"), + Self::ND28 => write!(f, "ND28"), + Self::ND29 => write!(f, "ND29"), + Self::ND30 => write!(f, "ND30"), + Self::ND31 => write!(f, "ND31"), + Self::NQ0 => write!(f, "NQ0"), + Self::NQ1 => write!(f, "NQ1"), + Self::NQ2 => write!(f, "NQ2"), + Self::NQ3 => write!(f, "NQ3"), + Self::NQ4 => write!(f, "NQ4"), + Self::NQ5 => write!(f, "NQ5"), + Self::NQ6 => write!(f, "NQ6"), + Self::NQ7 => write!(f, "NQ7"), + Self::NQ8 => write!(f, "NQ8"), + Self::NQ9 => write!(f, "NQ9"), + Self::NQ10 => write!(f, "NQ10"), + Self::NQ11 => write!(f, "NQ11"), + Self::NQ12 => write!(f, "NQ12"), + Self::NQ13 => write!(f, "NQ13"), + Self::NQ14 => write!(f, "NQ14"), + Self::NQ15 => write!(f, "NQ15"), + } + } +} + +impl TryFrom for ARMRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::R0), + 11 => Ok(Self::R1), + 12 => Ok(Self::R2), + 13 => Ok(Self::R3), + 14 => Ok(Self::R4), + 15 => Ok(Self::R5), + 16 => Ok(Self::R6), + 17 => Ok(Self::R7), + 18 => Ok(Self::R8), + 19 => Ok(Self::R9), + 20 => Ok(Self::R10), + 21 => Ok(Self::R11), + 22 => Ok(Self::R12), + 23 => Ok(Self::SP), + 24 => Ok(Self::LR), + 25 => Ok(Self::PC), + 26 => Ok(Self::CPSR), + 27 => Ok(Self::ACC0), + 40 => Ok(Self::FPSCR), + 41 => Ok(Self::FPEXC), + 50 => Ok(Self::FS0), + 51 => Ok(Self::FS1), + 52 => Ok(Self::FS2), + 53 => Ok(Self::FS3), + 54 => Ok(Self::FS4), + 55 => Ok(Self::FS5), + 56 => Ok(Self::FS6), + 57 => Ok(Self::FS7), + 58 => Ok(Self::FS8), + 59 => Ok(Self::FS9), + 60 => Ok(Self::FS10), + 61 => Ok(Self::FS11), + 62 => Ok(Self::FS12), + 63 => Ok(Self::FS13), + 64 => Ok(Self::FS14), + 65 => Ok(Self::FS15), + 66 => Ok(Self::FS16), + 67 => Ok(Self::FS17), + 68 => Ok(Self::FS18), + 69 => Ok(Self::FS19), + 70 => Ok(Self::FS20), + 71 => Ok(Self::FS21), + 72 => Ok(Self::FS22), + 73 => Ok(Self::FS23), + 74 => Ok(Self::FS24), + 75 => Ok(Self::FS25), + 76 => Ok(Self::FS26), + 77 => Ok(Self::FS27), + 78 => Ok(Self::FS28), + 79 => Ok(Self::FS29), + 80 => Ok(Self::FS30), + 81 => Ok(Self::FS31), + 90 => Ok(Self::FPEXTRA0), + 91 => Ok(Self::FPEXTRA1), + 92 => Ok(Self::FPEXTRA2), + 93 => Ok(Self::FPEXTRA3), + 94 => Ok(Self::FPEXTRA4), + 95 => Ok(Self::FPEXTRA5), + 96 => Ok(Self::FPEXTRA6), + 97 => Ok(Self::FPEXTRA7), + 128 => Ok(Self::WR0), + 129 => Ok(Self::WR1), + 130 => Ok(Self::WR2), + 131 => Ok(Self::WR3), + 132 => Ok(Self::WR4), + 133 => Ok(Self::WR5), + 134 => Ok(Self::WR6), + 135 => Ok(Self::WR7), + 136 => Ok(Self::WR8), + 137 => Ok(Self::WR9), + 138 => Ok(Self::WR10), + 139 => Ok(Self::WR11), + 140 => Ok(Self::WR12), + 141 => Ok(Self::WR13), + 142 => Ok(Self::WR14), + 143 => Ok(Self::WR15), + 144 => Ok(Self::WCID), + 145 => Ok(Self::WCON), + 146 => Ok(Self::WCSSF), + 147 => Ok(Self::WCASF), + 148 => Ok(Self::WC4), + 149 => Ok(Self::WC5), + 150 => Ok(Self::WC6), + 151 => Ok(Self::WC7), + 152 => Ok(Self::WCGR0), + 153 => Ok(Self::WCGR1), + 154 => Ok(Self::WCGR2), + 155 => Ok(Self::WCGR3), + 156 => Ok(Self::WC12), + 157 => Ok(Self::WC13), + 158 => Ok(Self::WC14), + 159 => Ok(Self::WC15), + 200 => Ok(Self::FS32), + 201 => Ok(Self::FS33), + 202 => Ok(Self::FS34), + 203 => Ok(Self::FS35), + 204 => Ok(Self::FS36), + 205 => Ok(Self::FS37), + 206 => Ok(Self::FS38), + 207 => Ok(Self::FS39), + 208 => Ok(Self::FS40), + 209 => Ok(Self::FS41), + 210 => Ok(Self::FS42), + 211 => Ok(Self::FS43), + 212 => Ok(Self::FS44), + 213 => Ok(Self::FS45), + 214 => Ok(Self::FS46), + 215 => Ok(Self::FS47), + 216 => Ok(Self::FS48), + 217 => Ok(Self::FS49), + 218 => Ok(Self::FS50), + 219 => Ok(Self::FS51), + 220 => Ok(Self::FS52), + 221 => Ok(Self::FS53), + 222 => Ok(Self::FS54), + 223 => Ok(Self::FS55), + 224 => Ok(Self::FS56), + 225 => Ok(Self::FS57), + 226 => Ok(Self::FS58), + 227 => Ok(Self::FS59), + 228 => Ok(Self::FS60), + 229 => Ok(Self::FS61), + 230 => Ok(Self::FS62), + 231 => Ok(Self::FS63), + 300 => Ok(Self::ND0), + 301 => Ok(Self::ND1), + 302 => Ok(Self::ND2), + 303 => Ok(Self::ND3), + 304 => Ok(Self::ND4), + 305 => Ok(Self::ND5), + 306 => Ok(Self::ND6), + 307 => Ok(Self::ND7), + 308 => Ok(Self::ND8), + 309 => Ok(Self::ND9), + 310 => Ok(Self::ND10), + 311 => Ok(Self::ND11), + 312 => Ok(Self::ND12), + 313 => Ok(Self::ND13), + 314 => Ok(Self::ND14), + 315 => Ok(Self::ND15), + 316 => Ok(Self::ND16), + 317 => Ok(Self::ND17), + 318 => Ok(Self::ND18), + 319 => Ok(Self::ND19), + 320 => Ok(Self::ND20), + 321 => Ok(Self::ND21), + 322 => Ok(Self::ND22), + 323 => Ok(Self::ND23), + 324 => Ok(Self::ND24), + 325 => Ok(Self::ND25), + 326 => Ok(Self::ND26), + 327 => Ok(Self::ND27), + 328 => Ok(Self::ND28), + 329 => Ok(Self::ND29), + 330 => Ok(Self::ND30), + 331 => Ok(Self::ND31), + 400 => Ok(Self::NQ0), + 401 => Ok(Self::NQ1), + 402 => Ok(Self::NQ2), + 403 => Ok(Self::NQ3), + 404 => Ok(Self::NQ4), + 405 => Ok(Self::NQ5), + 406 => Ok(Self::NQ6), + 407 => Ok(Self::NQ7), + 408 => Ok(Self::NQ8), + 409 => Ok(Self::NQ9), + 410 => Ok(Self::NQ10), + 411 => Ok(Self::NQ11), + 412 => Ok(Self::NQ12), + 413 => Ok(Self::NQ13), + 414 => Ok(Self::NQ14), + 415 => Ok(Self::NQ15), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for ARMRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for ARM64 +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ARM64Register { + // General purpose 32-bit integer registers + W0 = 10, + W1 = 11, + W2 = 12, + W3 = 13, + W4 = 14, + W5 = 15, + W6 = 16, + W7 = 17, + W8 = 18, + W9 = 19, + W10 = 20, + W11 = 21, + W12 = 22, + W13 = 23, + W14 = 24, + W15 = 25, + W16 = 26, + W17 = 27, + W18 = 28, + W19 = 29, + W20 = 30, + W21 = 31, + W22 = 32, + W23 = 33, + W24 = 34, + W25 = 35, + W26 = 36, + W27 = 37, + W28 = 38, + W29 = 39, + W30 = 40, + WZR = 41, + + // General purpose 64-bit integer registers + X0 = 50, + X1 = 51, + X2 = 52, + X3 = 53, + X4 = 54, + X5 = 55, + X6 = 56, + X7 = 57, + X8 = 58, + X9 = 59, + X10 = 60, + X11 = 61, + X12 = 62, + X13 = 63, + X14 = 64, + X15 = 65, + IP0 = 66, + IP1 = 67, + X18 = 68, + X19 = 69, + X20 = 70, + X21 = 71, + X22 = 72, + X23 = 73, + X24 = 74, + X25 = 75, + X26 = 76, + X27 = 77, + X28 = 78, + FP = 79, + LR = 80, + SP = 81, + ZR = 82, + + // statue register + NZCV = 90, + + // 32-bit floating point registers + S0 = 100, + S1 = 101, + S2 = 102, + S3 = 103, + S4 = 104, + S5 = 105, + S6 = 106, + S7 = 107, + S8 = 108, + S9 = 109, + S10 = 110, + S11 = 111, + S12 = 112, + S13 = 113, + S14 = 114, + S15 = 115, + S16 = 116, + S17 = 117, + S18 = 118, + S19 = 119, + S20 = 120, + S21 = 121, + S22 = 122, + S23 = 123, + S24 = 124, + S25 = 125, + S26 = 126, + S27 = 127, + S28 = 128, + S29 = 129, + S30 = 130, + S31 = 131, + + // 64-bit floating point registers + D0 = 140, + D1 = 141, + D2 = 142, + D3 = 143, + D4 = 144, + D5 = 145, + D6 = 146, + D7 = 147, + D8 = 148, + D9 = 149, + D10 = 150, + D11 = 151, + D12 = 152, + D13 = 153, + D14 = 154, + D15 = 155, + D16 = 156, + D17 = 157, + D18 = 158, + D19 = 159, + D20 = 160, + D21 = 161, + D22 = 162, + D23 = 163, + D24 = 164, + D25 = 165, + D26 = 166, + D27 = 167, + D28 = 168, + D29 = 169, + D30 = 170, + D31 = 171, + + // 128-bit SIMD registers + Q0 = 180, + Q1 = 181, + Q2 = 182, + Q3 = 183, + Q4 = 184, + Q5 = 185, + Q6 = 186, + Q7 = 187, + Q8 = 188, + Q9 = 189, + Q10 = 190, + Q11 = 191, + Q12 = 192, + Q13 = 193, + Q14 = 194, + Q15 = 195, + Q16 = 196, + Q17 = 197, + Q18 = 198, + Q19 = 199, + Q20 = 200, + Q21 = 201, + Q22 = 202, + Q23 = 203, + Q24 = 204, + Q25 = 205, + Q26 = 206, + Q27 = 207, + Q28 = 208, + Q29 = 209, + Q30 = 210, + Q31 = 211, + + // Floating point status register + FPSR = 220, +} + +impl fmt::Display for ARM64Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::W0 => write!(f, "W0"), + Self::W1 => write!(f, "W1"), + Self::W2 => write!(f, "W2"), + Self::W3 => write!(f, "W3"), + Self::W4 => write!(f, "W4"), + Self::W5 => write!(f, "W5"), + Self::W6 => write!(f, "W6"), + Self::W7 => write!(f, "W7"), + Self::W8 => write!(f, "W8"), + Self::W9 => write!(f, "W9"), + Self::W10 => write!(f, "W10"), + Self::W11 => write!(f, "W11"), + Self::W12 => write!(f, "W12"), + Self::W13 => write!(f, "W13"), + Self::W14 => write!(f, "W14"), + Self::W15 => write!(f, "W15"), + Self::W16 => write!(f, "W16"), + Self::W17 => write!(f, "W17"), + Self::W18 => write!(f, "W18"), + Self::W19 => write!(f, "W19"), + Self::W20 => write!(f, "W20"), + Self::W21 => write!(f, "W21"), + Self::W22 => write!(f, "W22"), + Self::W23 => write!(f, "W23"), + Self::W24 => write!(f, "W24"), + Self::W25 => write!(f, "W25"), + Self::W26 => write!(f, "W26"), + Self::W27 => write!(f, "W27"), + Self::W28 => write!(f, "W28"), + Self::W29 => write!(f, "W29"), + Self::W30 => write!(f, "W30"), + Self::WZR => write!(f, "WZR"), + Self::X0 => write!(f, "X0"), + Self::X1 => write!(f, "X1"), + Self::X2 => write!(f, "X2"), + Self::X3 => write!(f, "X3"), + Self::X4 => write!(f, "X4"), + Self::X5 => write!(f, "X5"), + Self::X6 => write!(f, "X6"), + Self::X7 => write!(f, "X7"), + Self::X8 => write!(f, "X8"), + Self::X9 => write!(f, "X9"), + Self::X10 => write!(f, "X10"), + Self::X11 => write!(f, "X11"), + Self::X12 => write!(f, "X12"), + Self::X13 => write!(f, "X13"), + Self::X14 => write!(f, "X14"), + Self::X15 => write!(f, "X15"), + Self::IP0 => write!(f, "IP0"), + Self::IP1 => write!(f, "IP1"), + Self::X18 => write!(f, "X18"), + Self::X19 => write!(f, "X19"), + Self::X20 => write!(f, "X20"), + Self::X21 => write!(f, "X21"), + Self::X22 => write!(f, "X22"), + Self::X23 => write!(f, "X23"), + Self::X24 => write!(f, "X24"), + Self::X25 => write!(f, "X25"), + Self::X26 => write!(f, "X26"), + Self::X27 => write!(f, "X27"), + Self::X28 => write!(f, "X28"), + Self::FP => write!(f, "FP"), + Self::LR => write!(f, "LR"), + Self::SP => write!(f, "SP"), + Self::ZR => write!(f, "ZR"), + Self::NZCV => write!(f, "NZCV"), + Self::S0 => write!(f, "S0"), + Self::S1 => write!(f, "S1"), + Self::S2 => write!(f, "S2"), + Self::S3 => write!(f, "S3"), + Self::S4 => write!(f, "S4"), + Self::S5 => write!(f, "S5"), + Self::S6 => write!(f, "S6"), + Self::S7 => write!(f, "S7"), + Self::S8 => write!(f, "S8"), + Self::S9 => write!(f, "S9"), + Self::S10 => write!(f, "S10"), + Self::S11 => write!(f, "S11"), + Self::S12 => write!(f, "S12"), + Self::S13 => write!(f, "S13"), + Self::S14 => write!(f, "S14"), + Self::S15 => write!(f, "S15"), + Self::S16 => write!(f, "S16"), + Self::S17 => write!(f, "S17"), + Self::S18 => write!(f, "S18"), + Self::S19 => write!(f, "S19"), + Self::S20 => write!(f, "S20"), + Self::S21 => write!(f, "S21"), + Self::S22 => write!(f, "S22"), + Self::S23 => write!(f, "S23"), + Self::S24 => write!(f, "S24"), + Self::S25 => write!(f, "S25"), + Self::S26 => write!(f, "S26"), + Self::S27 => write!(f, "S27"), + Self::S28 => write!(f, "S28"), + Self::S29 => write!(f, "S29"), + Self::S30 => write!(f, "S30"), + Self::S31 => write!(f, "S31"), + Self::D0 => write!(f, "D0"), + Self::D1 => write!(f, "D1"), + Self::D2 => write!(f, "D2"), + Self::D3 => write!(f, "D3"), + Self::D4 => write!(f, "D4"), + Self::D5 => write!(f, "D5"), + Self::D6 => write!(f, "D6"), + Self::D7 => write!(f, "D7"), + Self::D8 => write!(f, "D8"), + Self::D9 => write!(f, "D9"), + Self::D10 => write!(f, "D10"), + Self::D11 => write!(f, "D11"), + Self::D12 => write!(f, "D12"), + Self::D13 => write!(f, "D13"), + Self::D14 => write!(f, "D14"), + Self::D15 => write!(f, "D15"), + Self::D16 => write!(f, "D16"), + Self::D17 => write!(f, "D17"), + Self::D18 => write!(f, "D18"), + Self::D19 => write!(f, "D19"), + Self::D20 => write!(f, "D20"), + Self::D21 => write!(f, "D21"), + Self::D22 => write!(f, "D22"), + Self::D23 => write!(f, "D23"), + Self::D24 => write!(f, "D24"), + Self::D25 => write!(f, "D25"), + Self::D26 => write!(f, "D26"), + Self::D27 => write!(f, "D27"), + Self::D28 => write!(f, "D28"), + Self::D29 => write!(f, "D29"), + Self::D30 => write!(f, "D30"), + Self::D31 => write!(f, "D31"), + Self::Q0 => write!(f, "Q0"), + Self::Q1 => write!(f, "Q1"), + Self::Q2 => write!(f, "Q2"), + Self::Q3 => write!(f, "Q3"), + Self::Q4 => write!(f, "Q4"), + Self::Q5 => write!(f, "Q5"), + Self::Q6 => write!(f, "Q6"), + Self::Q7 => write!(f, "Q7"), + Self::Q8 => write!(f, "Q8"), + Self::Q9 => write!(f, "Q9"), + Self::Q10 => write!(f, "Q10"), + Self::Q11 => write!(f, "Q11"), + Self::Q12 => write!(f, "Q12"), + Self::Q13 => write!(f, "Q13"), + Self::Q14 => write!(f, "Q14"), + Self::Q15 => write!(f, "Q15"), + Self::Q16 => write!(f, "Q16"), + Self::Q17 => write!(f, "Q17"), + Self::Q18 => write!(f, "Q18"), + Self::Q19 => write!(f, "Q19"), + Self::Q20 => write!(f, "Q20"), + Self::Q21 => write!(f, "Q21"), + Self::Q22 => write!(f, "Q22"), + Self::Q23 => write!(f, "Q23"), + Self::Q24 => write!(f, "Q24"), + Self::Q25 => write!(f, "Q25"), + Self::Q26 => write!(f, "Q26"), + Self::Q27 => write!(f, "Q27"), + Self::Q28 => write!(f, "Q28"), + Self::Q29 => write!(f, "Q29"), + Self::Q30 => write!(f, "Q30"), + Self::Q31 => write!(f, "Q31"), + Self::FPSR => write!(f, "FPSR"), + } + } +} + +impl TryFrom for ARM64Register { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::W0), + 11 => Ok(Self::W1), + 12 => Ok(Self::W2), + 13 => Ok(Self::W3), + 14 => Ok(Self::W4), + 15 => Ok(Self::W5), + 16 => Ok(Self::W6), + 17 => Ok(Self::W7), + 18 => Ok(Self::W8), + 19 => Ok(Self::W9), + 20 => Ok(Self::W10), + 21 => Ok(Self::W11), + 22 => Ok(Self::W12), + 23 => Ok(Self::W13), + 24 => Ok(Self::W14), + 25 => Ok(Self::W15), + 26 => Ok(Self::W16), + 27 => Ok(Self::W17), + 28 => Ok(Self::W18), + 29 => Ok(Self::W19), + 30 => Ok(Self::W20), + 31 => Ok(Self::W21), + 32 => Ok(Self::W22), + 33 => Ok(Self::W23), + 34 => Ok(Self::W24), + 35 => Ok(Self::W25), + 36 => Ok(Self::W26), + 37 => Ok(Self::W27), + 38 => Ok(Self::W28), + 39 => Ok(Self::W29), + 40 => Ok(Self::W30), + 41 => Ok(Self::WZR), + 50 => Ok(Self::X0), + 51 => Ok(Self::X1), + 52 => Ok(Self::X2), + 53 => Ok(Self::X3), + 54 => Ok(Self::X4), + 55 => Ok(Self::X5), + 56 => Ok(Self::X6), + 57 => Ok(Self::X7), + 58 => Ok(Self::X8), + 59 => Ok(Self::X9), + 60 => Ok(Self::X10), + 61 => Ok(Self::X11), + 62 => Ok(Self::X12), + 63 => Ok(Self::X13), + 64 => Ok(Self::X14), + 65 => Ok(Self::X15), + 66 => Ok(Self::IP0), + 67 => Ok(Self::IP1), + 68 => Ok(Self::X18), + 69 => Ok(Self::X19), + 70 => Ok(Self::X20), + 71 => Ok(Self::X21), + 72 => Ok(Self::X22), + 73 => Ok(Self::X23), + 74 => Ok(Self::X24), + 75 => Ok(Self::X25), + 76 => Ok(Self::X26), + 77 => Ok(Self::X27), + 78 => Ok(Self::X28), + 79 => Ok(Self::FP), + 80 => Ok(Self::LR), + 81 => Ok(Self::SP), + 82 => Ok(Self::ZR), + 90 => Ok(Self::NZCV), + 100 => Ok(Self::S0), + 101 => Ok(Self::S1), + 102 => Ok(Self::S2), + 103 => Ok(Self::S3), + 104 => Ok(Self::S4), + 105 => Ok(Self::S5), + 106 => Ok(Self::S6), + 107 => Ok(Self::S7), + 108 => Ok(Self::S8), + 109 => Ok(Self::S9), + 110 => Ok(Self::S10), + 111 => Ok(Self::S11), + 112 => Ok(Self::S12), + 113 => Ok(Self::S13), + 114 => Ok(Self::S14), + 115 => Ok(Self::S15), + 116 => Ok(Self::S16), + 117 => Ok(Self::S17), + 118 => Ok(Self::S18), + 119 => Ok(Self::S19), + 120 => Ok(Self::S20), + 121 => Ok(Self::S21), + 122 => Ok(Self::S22), + 123 => Ok(Self::S23), + 124 => Ok(Self::S24), + 125 => Ok(Self::S25), + 126 => Ok(Self::S26), + 127 => Ok(Self::S27), + 128 => Ok(Self::S28), + 129 => Ok(Self::S29), + 130 => Ok(Self::S30), + 131 => Ok(Self::S31), + 140 => Ok(Self::D0), + 141 => Ok(Self::D1), + 142 => Ok(Self::D2), + 143 => Ok(Self::D3), + 144 => Ok(Self::D4), + 145 => Ok(Self::D5), + 146 => Ok(Self::D6), + 147 => Ok(Self::D7), + 148 => Ok(Self::D8), + 149 => Ok(Self::D9), + 150 => Ok(Self::D10), + 151 => Ok(Self::D11), + 152 => Ok(Self::D12), + 153 => Ok(Self::D13), + 154 => Ok(Self::D14), + 155 => Ok(Self::D15), + 156 => Ok(Self::D16), + 157 => Ok(Self::D17), + 158 => Ok(Self::D18), + 159 => Ok(Self::D19), + 160 => Ok(Self::D20), + 161 => Ok(Self::D21), + 162 => Ok(Self::D22), + 163 => Ok(Self::D23), + 164 => Ok(Self::D24), + 165 => Ok(Self::D25), + 166 => Ok(Self::D26), + 167 => Ok(Self::D27), + 168 => Ok(Self::D28), + 169 => Ok(Self::D29), + 170 => Ok(Self::D30), + 171 => Ok(Self::D31), + 180 => Ok(Self::Q0), + 181 => Ok(Self::Q1), + 182 => Ok(Self::Q2), + 183 => Ok(Self::Q3), + 184 => Ok(Self::Q4), + 185 => Ok(Self::Q5), + 186 => Ok(Self::Q6), + 187 => Ok(Self::Q7), + 188 => Ok(Self::Q8), + 189 => Ok(Self::Q9), + 190 => Ok(Self::Q10), + 191 => Ok(Self::Q11), + 192 => Ok(Self::Q12), + 193 => Ok(Self::Q13), + 194 => Ok(Self::Q14), + 195 => Ok(Self::Q15), + 196 => Ok(Self::Q16), + 197 => Ok(Self::Q17), + 198 => Ok(Self::Q18), + 199 => Ok(Self::Q19), + 200 => Ok(Self::Q20), + 201 => Ok(Self::Q21), + 202 => Ok(Self::Q22), + 203 => Ok(Self::Q23), + 204 => Ok(Self::Q24), + 205 => Ok(Self::Q25), + 206 => Ok(Self::Q26), + 207 => Ok(Self::Q27), + 208 => Ok(Self::Q28), + 209 => Ok(Self::Q29), + 210 => Ok(Self::Q30), + 211 => Ok(Self::Q31), + 220 => Ok(Self::FPSR), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for ARM64Register { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for Intel IA64 +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum IA64Register { + // Branch Registers + Br0 = 512, + Br1 = 513, + Br2 = 514, + Br3 = 515, + Br4 = 516, + Br5 = 517, + Br6 = 518, + Br7 = 519, + + // Predicate Registers + P0 = 704, + P1 = 705, + P2 = 706, + P3 = 707, + P4 = 708, + P5 = 709, + P6 = 710, + P7 = 711, + P8 = 712, + P9 = 713, + P10 = 714, + P11 = 715, + P12 = 716, + P13 = 717, + P14 = 718, + P15 = 719, + P16 = 720, + P17 = 721, + P18 = 722, + P19 = 723, + P20 = 724, + P21 = 725, + P22 = 726, + P23 = 727, + P24 = 728, + P25 = 729, + P26 = 730, + P27 = 731, + P28 = 732, + P29 = 733, + P30 = 734, + P31 = 735, + P32 = 736, + P33 = 737, + P34 = 738, + P35 = 739, + P36 = 740, + P37 = 741, + P38 = 742, + P39 = 743, + P40 = 744, + P41 = 745, + P42 = 746, + P43 = 747, + P44 = 748, + P45 = 749, + P46 = 750, + P47 = 751, + P48 = 752, + P49 = 753, + P50 = 754, + P51 = 755, + P52 = 756, + P53 = 757, + P54 = 758, + P55 = 759, + P56 = 760, + P57 = 761, + P58 = 762, + P59 = 763, + P60 = 764, + P61 = 765, + P62 = 766, + P63 = 767, + + Preds = 768, + + // Banked General Registers + IntH0 = 832, + IntH1 = 833, + IntH2 = 834, + IntH3 = 835, + IntH4 = 836, + IntH5 = 837, + IntH6 = 838, + IntH7 = 839, + IntH8 = 840, + IntH9 = 841, + IntH10 = 842, + IntH11 = 843, + IntH12 = 844, + IntH13 = 845, + IntH14 = 846, + IntH15 = 847, + + // Special Registers + Ip = 1016, + Umask = 1017, + Cfm = 1018, + Psr = 1019, + + // Banked General Registers + Nats = 1020, + Nats2 = 1021, + Nats3 = 1022, + + // General-Purpose Registers + + // Integer registers + IntR0 = 1024, + IntR1 = 1025, + IntR2 = 1026, + IntR3 = 1027, + IntR4 = 1028, + IntR5 = 1029, + IntR6 = 1030, + IntR7 = 1031, + IntR8 = 1032, + IntR9 = 1033, + IntR10 = 1034, + IntR11 = 1035, + IntR12 = 1036, + IntR13 = 1037, + IntR14 = 1038, + IntR15 = 1039, + IntR16 = 1040, + IntR17 = 1041, + IntR18 = 1042, + IntR19 = 1043, + IntR20 = 1044, + IntR21 = 1045, + IntR22 = 1046, + IntR23 = 1047, + IntR24 = 1048, + IntR25 = 1049, + IntR26 = 1050, + IntR27 = 1051, + IntR28 = 1052, + IntR29 = 1053, + IntR30 = 1054, + IntR31 = 1055, + + // Register Stack + IntR32 = 1056, + IntR33 = 1057, + IntR34 = 1058, + IntR35 = 1059, + IntR36 = 1060, + IntR37 = 1061, + IntR38 = 1062, + IntR39 = 1063, + IntR40 = 1064, + IntR41 = 1065, + IntR42 = 1066, + IntR43 = 1067, + IntR44 = 1068, + IntR45 = 1069, + IntR46 = 1070, + IntR47 = 1071, + IntR48 = 1072, + IntR49 = 1073, + IntR50 = 1074, + IntR51 = 1075, + IntR52 = 1076, + IntR53 = 1077, + IntR54 = 1078, + IntR55 = 1079, + IntR56 = 1080, + IntR57 = 1081, + IntR58 = 1082, + IntR59 = 1083, + IntR60 = 1084, + IntR61 = 1085, + IntR62 = 1086, + IntR63 = 1087, + IntR64 = 1088, + IntR65 = 1089, + IntR66 = 1090, + IntR67 = 1091, + IntR68 = 1092, + IntR69 = 1093, + IntR70 = 1094, + IntR71 = 1095, + IntR72 = 1096, + IntR73 = 1097, + IntR74 = 1098, + IntR75 = 1099, + IntR76 = 1100, + IntR77 = 1101, + IntR78 = 1102, + IntR79 = 1103, + IntR80 = 1104, + IntR81 = 1105, + IntR82 = 1106, + IntR83 = 1107, + IntR84 = 1108, + IntR85 = 1109, + IntR86 = 1110, + IntR87 = 1111, + IntR88 = 1112, + IntR89 = 1113, + IntR90 = 1114, + IntR91 = 1115, + IntR92 = 1116, + IntR93 = 1117, + IntR94 = 1118, + IntR95 = 1119, + IntR96 = 1120, + IntR97 = 1121, + IntR98 = 1122, + IntR99 = 1123, + IntR100 = 1124, + IntR101 = 1125, + IntR102 = 1126, + IntR103 = 1127, + IntR104 = 1128, + IntR105 = 1129, + IntR106 = 1130, + IntR107 = 1131, + IntR108 = 1132, + IntR109 = 1133, + IntR110 = 1134, + IntR111 = 1135, + IntR112 = 1136, + IntR113 = 1137, + IntR114 = 1138, + IntR115 = 1139, + IntR116 = 1140, + IntR117 = 1141, + IntR118 = 1142, + IntR119 = 1143, + IntR120 = 1144, + IntR121 = 1145, + IntR122 = 1146, + IntR123 = 1147, + IntR124 = 1148, + IntR125 = 1149, + IntR126 = 1150, + IntR127 = 1151, + + // Floating-Point Registers + + // Low Floating Point Registers + FltF0 = 2048, + FltF1 = 2049, + FltF2 = 2050, + FltF3 = 2051, + FltF4 = 2052, + FltF5 = 2053, + FltF6 = 2054, + FltF7 = 2055, + FltF8 = 2056, + FltF9 = 2057, + FltF10 = 2058, + FltF11 = 2059, + FltF12 = 2060, + FltF13 = 2061, + FltF14 = 2062, + FltF15 = 2063, + FltF16 = 2064, + FltF17 = 2065, + FltF18 = 2066, + FltF19 = 2067, + FltF20 = 2068, + FltF21 = 2069, + FltF22 = 2070, + FltF23 = 2071, + FltF24 = 2072, + FltF25 = 2073, + FltF26 = 2074, + FltF27 = 2075, + FltF28 = 2076, + FltF29 = 2077, + FltF30 = 2078, + FltF31 = 2079, + + // High Floating Point Registers + FltF32 = 2080, + FltF33 = 2081, + FltF34 = 2082, + FltF35 = 2083, + FltF36 = 2084, + FltF37 = 2085, + FltF38 = 2086, + FltF39 = 2087, + FltF40 = 2088, + FltF41 = 2089, + FltF42 = 2090, + FltF43 = 2091, + FltF44 = 2092, + FltF45 = 2093, + FltF46 = 2094, + FltF47 = 2095, + FltF48 = 2096, + FltF49 = 2097, + FltF50 = 2098, + FltF51 = 2099, + FltF52 = 2100, + FltF53 = 2101, + FltF54 = 2102, + FltF55 = 2103, + FltF56 = 2104, + FltF57 = 2105, + FltF58 = 2106, + FltF59 = 2107, + FltF60 = 2108, + FltF61 = 2109, + FltF62 = 2110, + FltF63 = 2111, + FltF64 = 2112, + FltF65 = 2113, + FltF66 = 2114, + FltF67 = 2115, + FltF68 = 2116, + FltF69 = 2117, + FltF70 = 2118, + FltF71 = 2119, + FltF72 = 2120, + FltF73 = 2121, + FltF74 = 2122, + FltF75 = 2123, + FltF76 = 2124, + FltF77 = 2125, + FltF78 = 2126, + FltF79 = 2127, + FltF80 = 2128, + FltF81 = 2129, + FltF82 = 2130, + FltF83 = 2131, + FltF84 = 2132, + FltF85 = 2133, + FltF86 = 2134, + FltF87 = 2135, + FltF88 = 2136, + FltF89 = 2137, + FltF90 = 2138, + FltF91 = 2139, + FltF92 = 2140, + FltF93 = 2141, + FltF94 = 2142, + FltF95 = 2143, + FltF96 = 2144, + FltF97 = 2145, + FltF98 = 2146, + FltF99 = 2147, + FltF100 = 2148, + FltF101 = 2149, + FltF102 = 2150, + FltF103 = 2151, + FltF104 = 2152, + FltF105 = 2153, + FltF106 = 2154, + FltF107 = 2155, + FltF108 = 2156, + FltF109 = 2157, + FltF110 = 2158, + FltF111 = 2159, + FltF112 = 2160, + FltF113 = 2161, + FltF114 = 2162, + FltF115 = 2163, + FltF116 = 2164, + FltF117 = 2165, + FltF118 = 2166, + FltF119 = 2167, + FltF120 = 2168, + FltF121 = 2169, + FltF122 = 2170, + FltF123 = 2171, + FltF124 = 2172, + FltF125 = 2173, + FltF126 = 2174, + FltF127 = 2175, + + // Application Registers + ApKR0 = 3072, + ApKR1 = 3073, + ApKR2 = 3074, + ApKR3 = 3075, + ApKR4 = 3076, + ApKR5 = 3077, + ApKR6 = 3078, + ApKR7 = 3079, + AR8 = 3080, + AR9 = 3081, + AR10 = 3082, + AR11 = 3083, + AR12 = 3084, + AR13 = 3085, + AR14 = 3086, + AR15 = 3087, + RsRSC = 3088, + RsBSP = 3089, + RsBSPSTORE = 3090, + RsRNAT = 3091, + AR20 = 3092, + StFCR = 3093, + AR22 = 3094, + AR23 = 3095, + EFLAG = 3096, + CSD = 3097, + SSD = 3098, + CFLG = 3099, + StFSR = 3100, + StFIR = 3101, + StFDR = 3102, + AR31 = 3103, + ApCCV = 3104, + AR33 = 3105, + AR34 = 3106, + AR35 = 3107, + ApUNAT = 3108, + AR37 = 3109, + AR38 = 3110, + AR39 = 3111, + StFPSR = 3112, + AR41 = 3113, + AR42 = 3114, + AR43 = 3115, + ApITC = 3116, + AR45 = 3117, + AR46 = 3118, + AR47 = 3119, + AR48 = 3120, + AR49 = 3121, + AR50 = 3122, + AR51 = 3123, + AR52 = 3124, + AR53 = 3125, + AR54 = 3126, + AR55 = 3127, + AR56 = 3128, + AR57 = 3129, + AR58 = 3130, + AR59 = 3131, + AR60 = 3132, + AR61 = 3133, + AR62 = 3134, + AR63 = 3135, + RsPFS = 3136, + ApLC = 3137, + ApEC = 3138, + AR67 = 3139, + AR68 = 3140, + AR69 = 3141, + AR70 = 3142, + AR71 = 3143, + AR72 = 3144, + AR73 = 3145, + AR74 = 3146, + AR75 = 3147, + AR76 = 3148, + AR77 = 3149, + AR78 = 3150, + AR79 = 3151, + AR80 = 3152, + AR81 = 3153, + AR82 = 3154, + AR83 = 3155, + AR84 = 3156, + AR85 = 3157, + AR86 = 3158, + AR87 = 3159, + AR88 = 3160, + AR89 = 3161, + AR90 = 3162, + AR91 = 3163, + AR92 = 3164, + AR93 = 3165, + AR94 = 3166, + AR95 = 3167, + AR96 = 3168, + AR97 = 3169, + AR98 = 3170, + AR99 = 3171, + AR100 = 3172, + AR101 = 3173, + AR102 = 3174, + AR103 = 3175, + AR104 = 3176, + AR105 = 3177, + AR106 = 3178, + AR107 = 3179, + AR108 = 3180, + AR109 = 3181, + AR110 = 3182, + AR111 = 3183, + AR112 = 3184, + AR113 = 3185, + AR114 = 3186, + AR115 = 3187, + AR116 = 3188, + AR117 = 3189, + AR118 = 3190, + AR119 = 3191, + AR120 = 3192, + AR121 = 3193, + AR122 = 3194, + AR123 = 3195, + AR124 = 3196, + AR125 = 3197, + AR126 = 3198, + AR127 = 3199, + + // CPUID Registers + CPUID0 = 3328, + CPUID1 = 3329, + CPUID2 = 3330, + CPUID3 = 3331, + CPUID4 = 3332, + + // Control Registers + ApDCR = 4096, + ApITM = 4097, + ApIVA = 4098, + CR3 = 4099, + CR4 = 4100, + CR5 = 4101, + CR6 = 4102, + CR7 = 4103, + ApPTA = 4104, + ApGPTA = 4105, + CR10 = 4106, + CR11 = 4107, + CR12 = 4108, + CR13 = 4109, + CR14 = 4110, + CR15 = 4111, + StIPSR = 4112, + StISR = 4113, + CR18 = 4114, + StIIP = 4115, + StIFA = 4116, + StITIR = 4117, + StIIPA = 4118, + StIFS = 4119, + StIIM = 4120, + StIHA = 4121, + CR26 = 4122, + CR27 = 4123, + CR28 = 4124, + CR29 = 4125, + CR30 = 4126, + CR31 = 4127, + CR32 = 4128, + CR33 = 4129, + CR34 = 4130, + CR35 = 4131, + CR36 = 4132, + CR37 = 4133, + CR38 = 4134, + CR39 = 4135, + CR40 = 4136, + CR41 = 4137, + CR42 = 4138, + CR43 = 4139, + CR44 = 4140, + CR45 = 4141, + CR46 = 4142, + CR47 = 4143, + CR48 = 4144, + CR49 = 4145, + CR50 = 4146, + CR51 = 4147, + CR52 = 4148, + CR53 = 4149, + CR54 = 4150, + CR55 = 4151, + CR56 = 4152, + CR57 = 4153, + CR58 = 4154, + CR59 = 4155, + CR60 = 4156, + CR61 = 4157, + CR62 = 4158, + CR63 = 4159, + SaLID = 4160, + SaIVR = 4161, + SaTPR = 4162, + SaEOI = 4163, + SaIRR0 = 4164, + SaIRR1 = 4165, + SaIRR2 = 4166, + SaIRR3 = 4167, + SaITV = 4168, + SaPMV = 4169, + SaCMCV = 4170, + CR75 = 4171, + CR76 = 4172, + CR77 = 4173, + CR78 = 4174, + CR79 = 4175, + SaLRR0 = 4176, + SaLRR1 = 4177, + CR82 = 4178, + CR83 = 4179, + CR84 = 4180, + CR85 = 4181, + CR86 = 4182, + CR87 = 4183, + CR88 = 4184, + CR89 = 4185, + CR90 = 4186, + CR91 = 4187, + CR92 = 4188, + CR93 = 4189, + CR94 = 4190, + CR95 = 4191, + CR96 = 4192, + CR97 = 4193, + CR98 = 4194, + CR99 = 4195, + CR100 = 4196, + CR101 = 4197, + CR102 = 4198, + CR103 = 4199, + CR104 = 4200, + CR105 = 4201, + CR106 = 4202, + CR107 = 4203, + CR108 = 4204, + CR109 = 4205, + CR110 = 4206, + CR111 = 4207, + CR112 = 4208, + CR113 = 4209, + CR114 = 4210, + CR115 = 4211, + CR116 = 4212, + CR117 = 4213, + CR118 = 4214, + CR119 = 4215, + CR120 = 4216, + CR121 = 4217, + CR122 = 4218, + CR123 = 4219, + CR124 = 4220, + CR125 = 4221, + CR126 = 4222, + CR127 = 4223, + + // Protection Key Registers + Pkr0 = 5120, + Pkr1 = 5121, + Pkr2 = 5122, + Pkr3 = 5123, + Pkr4 = 5124, + Pkr5 = 5125, + Pkr6 = 5126, + Pkr7 = 5127, + Pkr8 = 5128, + Pkr9 = 5129, + Pkr10 = 5130, + Pkr11 = 5131, + Pkr12 = 5132, + Pkr13 = 5133, + Pkr14 = 5134, + Pkr15 = 5135, + + // Region Registers + Rr0 = 6144, + Rr1 = 6145, + Rr2 = 6146, + Rr3 = 6147, + Rr4 = 6148, + Rr5 = 6149, + Rr6 = 6150, + Rr7 = 6151, + + // Performance Monitor Data Registers + PFD0 = 7168, + PFD1 = 7169, + PFD2 = 7170, + PFD3 = 7171, + PFD4 = 7172, + PFD5 = 7173, + PFD6 = 7174, + PFD7 = 7175, + PFD8 = 7176, + PFD9 = 7177, + PFD10 = 7178, + PFD11 = 7179, + PFD12 = 7180, + PFD13 = 7181, + PFD14 = 7182, + PFD15 = 7183, + PFD16 = 7184, + PFD17 = 7185, + + // Performance Monitor Config Registers + PFC0 = 7424, + PFC1 = 7425, + PFC2 = 7426, + PFC3 = 7427, + PFC4 = 7428, + PFC5 = 7429, + PFC6 = 7430, + PFC7 = 7431, + PFC8 = 7432, + PFC9 = 7433, + PFC10 = 7434, + PFC11 = 7435, + PFC12 = 7436, + PFC13 = 7437, + PFC14 = 7438, + PFC15 = 7439, + + // Instruction Translation Registers + TrI0 = 8192, + TrI1 = 8193, + TrI2 = 8194, + TrI3 = 8195, + TrI4 = 8196, + TrI5 = 8197, + TrI6 = 8198, + TrI7 = 8199, + + // Data Translation Registers + TrD0 = 8320, + TrD1 = 8321, + TrD2 = 8322, + TrD3 = 8323, + TrD4 = 8324, + TrD5 = 8325, + TrD6 = 8326, + TrD7 = 8327, + + // Instruction Breakpoint Registers + DbI0 = 8448, + DbI1 = 8449, + DbI2 = 8450, + DbI3 = 8451, + DbI4 = 8452, + DbI5 = 8453, + DbI6 = 8454, + DbI7 = 8455, + + // Data Breakpoint Registers + DbD0 = 8576, + DbD1 = 8577, + DbD2 = 8578, + DbD3 = 8579, + DbD4 = 8580, + DbD5 = 8581, + DbD6 = 8582, + DbD7 = 8583, +} + +impl fmt::Display for IA64Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Br0 => write!(f, "Br0"), + Self::Br1 => write!(f, "Br1"), + Self::Br2 => write!(f, "Br2"), + Self::Br3 => write!(f, "Br3"), + Self::Br4 => write!(f, "Br4"), + Self::Br5 => write!(f, "Br5"), + Self::Br6 => write!(f, "Br6"), + Self::Br7 => write!(f, "Br7"), + Self::P0 => write!(f, "P0"), + Self::P1 => write!(f, "P1"), + Self::P2 => write!(f, "P2"), + Self::P3 => write!(f, "P3"), + Self::P4 => write!(f, "P4"), + Self::P5 => write!(f, "P5"), + Self::P6 => write!(f, "P6"), + Self::P7 => write!(f, "P7"), + Self::P8 => write!(f, "P8"), + Self::P9 => write!(f, "P9"), + Self::P10 => write!(f, "P10"), + Self::P11 => write!(f, "P11"), + Self::P12 => write!(f, "P12"), + Self::P13 => write!(f, "P13"), + Self::P14 => write!(f, "P14"), + Self::P15 => write!(f, "P15"), + Self::P16 => write!(f, "P16"), + Self::P17 => write!(f, "P17"), + Self::P18 => write!(f, "P18"), + Self::P19 => write!(f, "P19"), + Self::P20 => write!(f, "P20"), + Self::P21 => write!(f, "P21"), + Self::P22 => write!(f, "P22"), + Self::P23 => write!(f, "P23"), + Self::P24 => write!(f, "P24"), + Self::P25 => write!(f, "P25"), + Self::P26 => write!(f, "P26"), + Self::P27 => write!(f, "P27"), + Self::P28 => write!(f, "P28"), + Self::P29 => write!(f, "P29"), + Self::P30 => write!(f, "P30"), + Self::P31 => write!(f, "P31"), + Self::P32 => write!(f, "P32"), + Self::P33 => write!(f, "P33"), + Self::P34 => write!(f, "P34"), + Self::P35 => write!(f, "P35"), + Self::P36 => write!(f, "P36"), + Self::P37 => write!(f, "P37"), + Self::P38 => write!(f, "P38"), + Self::P39 => write!(f, "P39"), + Self::P40 => write!(f, "P40"), + Self::P41 => write!(f, "P41"), + Self::P42 => write!(f, "P42"), + Self::P43 => write!(f, "P43"), + Self::P44 => write!(f, "P44"), + Self::P45 => write!(f, "P45"), + Self::P46 => write!(f, "P46"), + Self::P47 => write!(f, "P47"), + Self::P48 => write!(f, "P48"), + Self::P49 => write!(f, "P49"), + Self::P50 => write!(f, "P50"), + Self::P51 => write!(f, "P51"), + Self::P52 => write!(f, "P52"), + Self::P53 => write!(f, "P53"), + Self::P54 => write!(f, "P54"), + Self::P55 => write!(f, "P55"), + Self::P56 => write!(f, "P56"), + Self::P57 => write!(f, "P57"), + Self::P58 => write!(f, "P58"), + Self::P59 => write!(f, "P59"), + Self::P60 => write!(f, "P60"), + Self::P61 => write!(f, "P61"), + Self::P62 => write!(f, "P62"), + Self::P63 => write!(f, "P63"), + Self::Preds => write!(f, "Preds"), + Self::IntH0 => write!(f, "IntH0"), + Self::IntH1 => write!(f, "IntH1"), + Self::IntH2 => write!(f, "IntH2"), + Self::IntH3 => write!(f, "IntH3"), + Self::IntH4 => write!(f, "IntH4"), + Self::IntH5 => write!(f, "IntH5"), + Self::IntH6 => write!(f, "IntH6"), + Self::IntH7 => write!(f, "IntH7"), + Self::IntH8 => write!(f, "IntH8"), + Self::IntH9 => write!(f, "IntH9"), + Self::IntH10 => write!(f, "IntH10"), + Self::IntH11 => write!(f, "IntH11"), + Self::IntH12 => write!(f, "IntH12"), + Self::IntH13 => write!(f, "IntH13"), + Self::IntH14 => write!(f, "IntH14"), + Self::IntH15 => write!(f, "IntH15"), + Self::Ip => write!(f, "Ip"), + Self::Umask => write!(f, "Umask"), + Self::Cfm => write!(f, "Cfm"), + Self::Psr => write!(f, "Psr"), + Self::Nats => write!(f, "Nats"), + Self::Nats2 => write!(f, "Nats2"), + Self::Nats3 => write!(f, "Nats3"), + Self::IntR0 => write!(f, "IntR0"), + Self::IntR1 => write!(f, "IntR1"), + Self::IntR2 => write!(f, "IntR2"), + Self::IntR3 => write!(f, "IntR3"), + Self::IntR4 => write!(f, "IntR4"), + Self::IntR5 => write!(f, "IntR5"), + Self::IntR6 => write!(f, "IntR6"), + Self::IntR7 => write!(f, "IntR7"), + Self::IntR8 => write!(f, "IntR8"), + Self::IntR9 => write!(f, "IntR9"), + Self::IntR10 => write!(f, "IntR10"), + Self::IntR11 => write!(f, "IntR11"), + Self::IntR12 => write!(f, "IntR12"), + Self::IntR13 => write!(f, "IntR13"), + Self::IntR14 => write!(f, "IntR14"), + Self::IntR15 => write!(f, "IntR15"), + Self::IntR16 => write!(f, "IntR16"), + Self::IntR17 => write!(f, "IntR17"), + Self::IntR18 => write!(f, "IntR18"), + Self::IntR19 => write!(f, "IntR19"), + Self::IntR20 => write!(f, "IntR20"), + Self::IntR21 => write!(f, "IntR21"), + Self::IntR22 => write!(f, "IntR22"), + Self::IntR23 => write!(f, "IntR23"), + Self::IntR24 => write!(f, "IntR24"), + Self::IntR25 => write!(f, "IntR25"), + Self::IntR26 => write!(f, "IntR26"), + Self::IntR27 => write!(f, "IntR27"), + Self::IntR28 => write!(f, "IntR28"), + Self::IntR29 => write!(f, "IntR29"), + Self::IntR30 => write!(f, "IntR30"), + Self::IntR31 => write!(f, "IntR31"), + Self::IntR32 => write!(f, "IntR32"), + Self::IntR33 => write!(f, "IntR33"), + Self::IntR34 => write!(f, "IntR34"), + Self::IntR35 => write!(f, "IntR35"), + Self::IntR36 => write!(f, "IntR36"), + Self::IntR37 => write!(f, "IntR37"), + Self::IntR38 => write!(f, "IntR38"), + Self::IntR39 => write!(f, "IntR39"), + Self::IntR40 => write!(f, "IntR40"), + Self::IntR41 => write!(f, "IntR41"), + Self::IntR42 => write!(f, "IntR42"), + Self::IntR43 => write!(f, "IntR43"), + Self::IntR44 => write!(f, "IntR44"), + Self::IntR45 => write!(f, "IntR45"), + Self::IntR46 => write!(f, "IntR46"), + Self::IntR47 => write!(f, "IntR47"), + Self::IntR48 => write!(f, "IntR48"), + Self::IntR49 => write!(f, "IntR49"), + Self::IntR50 => write!(f, "IntR50"), + Self::IntR51 => write!(f, "IntR51"), + Self::IntR52 => write!(f, "IntR52"), + Self::IntR53 => write!(f, "IntR53"), + Self::IntR54 => write!(f, "IntR54"), + Self::IntR55 => write!(f, "IntR55"), + Self::IntR56 => write!(f, "IntR56"), + Self::IntR57 => write!(f, "IntR57"), + Self::IntR58 => write!(f, "IntR58"), + Self::IntR59 => write!(f, "IntR59"), + Self::IntR60 => write!(f, "IntR60"), + Self::IntR61 => write!(f, "IntR61"), + Self::IntR62 => write!(f, "IntR62"), + Self::IntR63 => write!(f, "IntR63"), + Self::IntR64 => write!(f, "IntR64"), + Self::IntR65 => write!(f, "IntR65"), + Self::IntR66 => write!(f, "IntR66"), + Self::IntR67 => write!(f, "IntR67"), + Self::IntR68 => write!(f, "IntR68"), + Self::IntR69 => write!(f, "IntR69"), + Self::IntR70 => write!(f, "IntR70"), + Self::IntR71 => write!(f, "IntR71"), + Self::IntR72 => write!(f, "IntR72"), + Self::IntR73 => write!(f, "IntR73"), + Self::IntR74 => write!(f, "IntR74"), + Self::IntR75 => write!(f, "IntR75"), + Self::IntR76 => write!(f, "IntR76"), + Self::IntR77 => write!(f, "IntR77"), + Self::IntR78 => write!(f, "IntR78"), + Self::IntR79 => write!(f, "IntR79"), + Self::IntR80 => write!(f, "IntR80"), + Self::IntR81 => write!(f, "IntR81"), + Self::IntR82 => write!(f, "IntR82"), + Self::IntR83 => write!(f, "IntR83"), + Self::IntR84 => write!(f, "IntR84"), + Self::IntR85 => write!(f, "IntR85"), + Self::IntR86 => write!(f, "IntR86"), + Self::IntR87 => write!(f, "IntR87"), + Self::IntR88 => write!(f, "IntR88"), + Self::IntR89 => write!(f, "IntR89"), + Self::IntR90 => write!(f, "IntR90"), + Self::IntR91 => write!(f, "IntR91"), + Self::IntR92 => write!(f, "IntR92"), + Self::IntR93 => write!(f, "IntR93"), + Self::IntR94 => write!(f, "IntR94"), + Self::IntR95 => write!(f, "IntR95"), + Self::IntR96 => write!(f, "IntR96"), + Self::IntR97 => write!(f, "IntR97"), + Self::IntR98 => write!(f, "IntR98"), + Self::IntR99 => write!(f, "IntR99"), + Self::IntR100 => write!(f, "IntR100"), + Self::IntR101 => write!(f, "IntR101"), + Self::IntR102 => write!(f, "IntR102"), + Self::IntR103 => write!(f, "IntR103"), + Self::IntR104 => write!(f, "IntR104"), + Self::IntR105 => write!(f, "IntR105"), + Self::IntR106 => write!(f, "IntR106"), + Self::IntR107 => write!(f, "IntR107"), + Self::IntR108 => write!(f, "IntR108"), + Self::IntR109 => write!(f, "IntR109"), + Self::IntR110 => write!(f, "IntR110"), + Self::IntR111 => write!(f, "IntR111"), + Self::IntR112 => write!(f, "IntR112"), + Self::IntR113 => write!(f, "IntR113"), + Self::IntR114 => write!(f, "IntR114"), + Self::IntR115 => write!(f, "IntR115"), + Self::IntR116 => write!(f, "IntR116"), + Self::IntR117 => write!(f, "IntR117"), + Self::IntR118 => write!(f, "IntR118"), + Self::IntR119 => write!(f, "IntR119"), + Self::IntR120 => write!(f, "IntR120"), + Self::IntR121 => write!(f, "IntR121"), + Self::IntR122 => write!(f, "IntR122"), + Self::IntR123 => write!(f, "IntR123"), + Self::IntR124 => write!(f, "IntR124"), + Self::IntR125 => write!(f, "IntR125"), + Self::IntR126 => write!(f, "IntR126"), + Self::IntR127 => write!(f, "IntR127"), + Self::FltF0 => write!(f, "FltF0"), + Self::FltF1 => write!(f, "FltF1"), + Self::FltF2 => write!(f, "FltF2"), + Self::FltF3 => write!(f, "FltF3"), + Self::FltF4 => write!(f, "FltF4"), + Self::FltF5 => write!(f, "FltF5"), + Self::FltF6 => write!(f, "FltF6"), + Self::FltF7 => write!(f, "FltF7"), + Self::FltF8 => write!(f, "FltF8"), + Self::FltF9 => write!(f, "FltF9"), + Self::FltF10 => write!(f, "FltF10"), + Self::FltF11 => write!(f, "FltF11"), + Self::FltF12 => write!(f, "FltF12"), + Self::FltF13 => write!(f, "FltF13"), + Self::FltF14 => write!(f, "FltF14"), + Self::FltF15 => write!(f, "FltF15"), + Self::FltF16 => write!(f, "FltF16"), + Self::FltF17 => write!(f, "FltF17"), + Self::FltF18 => write!(f, "FltF18"), + Self::FltF19 => write!(f, "FltF19"), + Self::FltF20 => write!(f, "FltF20"), + Self::FltF21 => write!(f, "FltF21"), + Self::FltF22 => write!(f, "FltF22"), + Self::FltF23 => write!(f, "FltF23"), + Self::FltF24 => write!(f, "FltF24"), + Self::FltF25 => write!(f, "FltF25"), + Self::FltF26 => write!(f, "FltF26"), + Self::FltF27 => write!(f, "FltF27"), + Self::FltF28 => write!(f, "FltF28"), + Self::FltF29 => write!(f, "FltF29"), + Self::FltF30 => write!(f, "FltF30"), + Self::FltF31 => write!(f, "FltF31"), + Self::FltF32 => write!(f, "FltF32"), + Self::FltF33 => write!(f, "FltF33"), + Self::FltF34 => write!(f, "FltF34"), + Self::FltF35 => write!(f, "FltF35"), + Self::FltF36 => write!(f, "FltF36"), + Self::FltF37 => write!(f, "FltF37"), + Self::FltF38 => write!(f, "FltF38"), + Self::FltF39 => write!(f, "FltF39"), + Self::FltF40 => write!(f, "FltF40"), + Self::FltF41 => write!(f, "FltF41"), + Self::FltF42 => write!(f, "FltF42"), + Self::FltF43 => write!(f, "FltF43"), + Self::FltF44 => write!(f, "FltF44"), + Self::FltF45 => write!(f, "FltF45"), + Self::FltF46 => write!(f, "FltF46"), + Self::FltF47 => write!(f, "FltF47"), + Self::FltF48 => write!(f, "FltF48"), + Self::FltF49 => write!(f, "FltF49"), + Self::FltF50 => write!(f, "FltF50"), + Self::FltF51 => write!(f, "FltF51"), + Self::FltF52 => write!(f, "FltF52"), + Self::FltF53 => write!(f, "FltF53"), + Self::FltF54 => write!(f, "FltF54"), + Self::FltF55 => write!(f, "FltF55"), + Self::FltF56 => write!(f, "FltF56"), + Self::FltF57 => write!(f, "FltF57"), + Self::FltF58 => write!(f, "FltF58"), + Self::FltF59 => write!(f, "FltF59"), + Self::FltF60 => write!(f, "FltF60"), + Self::FltF61 => write!(f, "FltF61"), + Self::FltF62 => write!(f, "FltF62"), + Self::FltF63 => write!(f, "FltF63"), + Self::FltF64 => write!(f, "FltF64"), + Self::FltF65 => write!(f, "FltF65"), + Self::FltF66 => write!(f, "FltF66"), + Self::FltF67 => write!(f, "FltF67"), + Self::FltF68 => write!(f, "FltF68"), + Self::FltF69 => write!(f, "FltF69"), + Self::FltF70 => write!(f, "FltF70"), + Self::FltF71 => write!(f, "FltF71"), + Self::FltF72 => write!(f, "FltF72"), + Self::FltF73 => write!(f, "FltF73"), + Self::FltF74 => write!(f, "FltF74"), + Self::FltF75 => write!(f, "FltF75"), + Self::FltF76 => write!(f, "FltF76"), + Self::FltF77 => write!(f, "FltF77"), + Self::FltF78 => write!(f, "FltF78"), + Self::FltF79 => write!(f, "FltF79"), + Self::FltF80 => write!(f, "FltF80"), + Self::FltF81 => write!(f, "FltF81"), + Self::FltF82 => write!(f, "FltF82"), + Self::FltF83 => write!(f, "FltF83"), + Self::FltF84 => write!(f, "FltF84"), + Self::FltF85 => write!(f, "FltF85"), + Self::FltF86 => write!(f, "FltF86"), + Self::FltF87 => write!(f, "FltF87"), + Self::FltF88 => write!(f, "FltF88"), + Self::FltF89 => write!(f, "FltF89"), + Self::FltF90 => write!(f, "FltF90"), + Self::FltF91 => write!(f, "FltF91"), + Self::FltF92 => write!(f, "FltF92"), + Self::FltF93 => write!(f, "FltF93"), + Self::FltF94 => write!(f, "FltF94"), + Self::FltF95 => write!(f, "FltF95"), + Self::FltF96 => write!(f, "FltF96"), + Self::FltF97 => write!(f, "FltF97"), + Self::FltF98 => write!(f, "FltF98"), + Self::FltF99 => write!(f, "FltF99"), + Self::FltF100 => write!(f, "FltF100"), + Self::FltF101 => write!(f, "FltF101"), + Self::FltF102 => write!(f, "FltF102"), + Self::FltF103 => write!(f, "FltF103"), + Self::FltF104 => write!(f, "FltF104"), + Self::FltF105 => write!(f, "FltF105"), + Self::FltF106 => write!(f, "FltF106"), + Self::FltF107 => write!(f, "FltF107"), + Self::FltF108 => write!(f, "FltF108"), + Self::FltF109 => write!(f, "FltF109"), + Self::FltF110 => write!(f, "FltF110"), + Self::FltF111 => write!(f, "FltF111"), + Self::FltF112 => write!(f, "FltF112"), + Self::FltF113 => write!(f, "FltF113"), + Self::FltF114 => write!(f, "FltF114"), + Self::FltF115 => write!(f, "FltF115"), + Self::FltF116 => write!(f, "FltF116"), + Self::FltF117 => write!(f, "FltF117"), + Self::FltF118 => write!(f, "FltF118"), + Self::FltF119 => write!(f, "FltF119"), + Self::FltF120 => write!(f, "FltF120"), + Self::FltF121 => write!(f, "FltF121"), + Self::FltF122 => write!(f, "FltF122"), + Self::FltF123 => write!(f, "FltF123"), + Self::FltF124 => write!(f, "FltF124"), + Self::FltF125 => write!(f, "FltF125"), + Self::FltF126 => write!(f, "FltF126"), + Self::FltF127 => write!(f, "FltF127"), + Self::ApKR0 => write!(f, "ApKR0"), + Self::ApKR1 => write!(f, "ApKR1"), + Self::ApKR2 => write!(f, "ApKR2"), + Self::ApKR3 => write!(f, "ApKR3"), + Self::ApKR4 => write!(f, "ApKR4"), + Self::ApKR5 => write!(f, "ApKR5"), + Self::ApKR6 => write!(f, "ApKR6"), + Self::ApKR7 => write!(f, "ApKR7"), + Self::AR8 => write!(f, "AR8"), + Self::AR9 => write!(f, "AR9"), + Self::AR10 => write!(f, "AR10"), + Self::AR11 => write!(f, "AR11"), + Self::AR12 => write!(f, "AR12"), + Self::AR13 => write!(f, "AR13"), + Self::AR14 => write!(f, "AR14"), + Self::AR15 => write!(f, "AR15"), + Self::RsRSC => write!(f, "RsRSC"), + Self::RsBSP => write!(f, "RsBSP"), + Self::RsBSPSTORE => write!(f, "RsBSPSTORE"), + Self::RsRNAT => write!(f, "RsRNAT"), + Self::AR20 => write!(f, "AR20"), + Self::StFCR => write!(f, "StFCR"), + Self::AR22 => write!(f, "AR22"), + Self::AR23 => write!(f, "AR23"), + Self::EFLAG => write!(f, "EFLAG"), + Self::CSD => write!(f, "CSD"), + Self::SSD => write!(f, "SSD"), + Self::CFLG => write!(f, "CFLG"), + Self::StFSR => write!(f, "StFSR"), + Self::StFIR => write!(f, "StFIR"), + Self::StFDR => write!(f, "StFDR"), + Self::AR31 => write!(f, "AR31"), + Self::ApCCV => write!(f, "ApCCV"), + Self::AR33 => write!(f, "AR33"), + Self::AR34 => write!(f, "AR34"), + Self::AR35 => write!(f, "AR35"), + Self::ApUNAT => write!(f, "ApUNAT"), + Self::AR37 => write!(f, "AR37"), + Self::AR38 => write!(f, "AR38"), + Self::AR39 => write!(f, "AR39"), + Self::StFPSR => write!(f, "StFPSR"), + Self::AR41 => write!(f, "AR41"), + Self::AR42 => write!(f, "AR42"), + Self::AR43 => write!(f, "AR43"), + Self::ApITC => write!(f, "ApITC"), + Self::AR45 => write!(f, "AR45"), + Self::AR46 => write!(f, "AR46"), + Self::AR47 => write!(f, "AR47"), + Self::AR48 => write!(f, "AR48"), + Self::AR49 => write!(f, "AR49"), + Self::AR50 => write!(f, "AR50"), + Self::AR51 => write!(f, "AR51"), + Self::AR52 => write!(f, "AR52"), + Self::AR53 => write!(f, "AR53"), + Self::AR54 => write!(f, "AR54"), + Self::AR55 => write!(f, "AR55"), + Self::AR56 => write!(f, "AR56"), + Self::AR57 => write!(f, "AR57"), + Self::AR58 => write!(f, "AR58"), + Self::AR59 => write!(f, "AR59"), + Self::AR60 => write!(f, "AR60"), + Self::AR61 => write!(f, "AR61"), + Self::AR62 => write!(f, "AR62"), + Self::AR63 => write!(f, "AR63"), + Self::RsPFS => write!(f, "RsPFS"), + Self::ApLC => write!(f, "ApLC"), + Self::ApEC => write!(f, "ApEC"), + Self::AR67 => write!(f, "AR67"), + Self::AR68 => write!(f, "AR68"), + Self::AR69 => write!(f, "AR69"), + Self::AR70 => write!(f, "AR70"), + Self::AR71 => write!(f, "AR71"), + Self::AR72 => write!(f, "AR72"), + Self::AR73 => write!(f, "AR73"), + Self::AR74 => write!(f, "AR74"), + Self::AR75 => write!(f, "AR75"), + Self::AR76 => write!(f, "AR76"), + Self::AR77 => write!(f, "AR77"), + Self::AR78 => write!(f, "AR78"), + Self::AR79 => write!(f, "AR79"), + Self::AR80 => write!(f, "AR80"), + Self::AR81 => write!(f, "AR81"), + Self::AR82 => write!(f, "AR82"), + Self::AR83 => write!(f, "AR83"), + Self::AR84 => write!(f, "AR84"), + Self::AR85 => write!(f, "AR85"), + Self::AR86 => write!(f, "AR86"), + Self::AR87 => write!(f, "AR87"), + Self::AR88 => write!(f, "AR88"), + Self::AR89 => write!(f, "AR89"), + Self::AR90 => write!(f, "AR90"), + Self::AR91 => write!(f, "AR91"), + Self::AR92 => write!(f, "AR92"), + Self::AR93 => write!(f, "AR93"), + Self::AR94 => write!(f, "AR94"), + Self::AR95 => write!(f, "AR95"), + Self::AR96 => write!(f, "AR96"), + Self::AR97 => write!(f, "AR97"), + Self::AR98 => write!(f, "AR98"), + Self::AR99 => write!(f, "AR99"), + Self::AR100 => write!(f, "AR100"), + Self::AR101 => write!(f, "AR101"), + Self::AR102 => write!(f, "AR102"), + Self::AR103 => write!(f, "AR103"), + Self::AR104 => write!(f, "AR104"), + Self::AR105 => write!(f, "AR105"), + Self::AR106 => write!(f, "AR106"), + Self::AR107 => write!(f, "AR107"), + Self::AR108 => write!(f, "AR108"), + Self::AR109 => write!(f, "AR109"), + Self::AR110 => write!(f, "AR110"), + Self::AR111 => write!(f, "AR111"), + Self::AR112 => write!(f, "AR112"), + Self::AR113 => write!(f, "AR113"), + Self::AR114 => write!(f, "AR114"), + Self::AR115 => write!(f, "AR115"), + Self::AR116 => write!(f, "AR116"), + Self::AR117 => write!(f, "AR117"), + Self::AR118 => write!(f, "AR118"), + Self::AR119 => write!(f, "AR119"), + Self::AR120 => write!(f, "AR120"), + Self::AR121 => write!(f, "AR121"), + Self::AR122 => write!(f, "AR122"), + Self::AR123 => write!(f, "AR123"), + Self::AR124 => write!(f, "AR124"), + Self::AR125 => write!(f, "AR125"), + Self::AR126 => write!(f, "AR126"), + Self::AR127 => write!(f, "AR127"), + Self::CPUID0 => write!(f, "CPUID0"), + Self::CPUID1 => write!(f, "CPUID1"), + Self::CPUID2 => write!(f, "CPUID2"), + Self::CPUID3 => write!(f, "CPUID3"), + Self::CPUID4 => write!(f, "CPUID4"), + Self::ApDCR => write!(f, "ApDCR"), + Self::ApITM => write!(f, "ApITM"), + Self::ApIVA => write!(f, "ApIVA"), + Self::CR3 => write!(f, "CR3"), + Self::CR4 => write!(f, "CR4"), + Self::CR5 => write!(f, "CR5"), + Self::CR6 => write!(f, "CR6"), + Self::CR7 => write!(f, "CR7"), + Self::ApPTA => write!(f, "ApPTA"), + Self::ApGPTA => write!(f, "ApGPTA"), + Self::CR10 => write!(f, "CR10"), + Self::CR11 => write!(f, "CR11"), + Self::CR12 => write!(f, "CR12"), + Self::CR13 => write!(f, "CR13"), + Self::CR14 => write!(f, "CR14"), + Self::CR15 => write!(f, "CR15"), + Self::StIPSR => write!(f, "StIPSR"), + Self::StISR => write!(f, "StISR"), + Self::CR18 => write!(f, "CR18"), + Self::StIIP => write!(f, "StIIP"), + Self::StIFA => write!(f, "StIFA"), + Self::StITIR => write!(f, "StITIR"), + Self::StIIPA => write!(f, "StIIPA"), + Self::StIFS => write!(f, "StIFS"), + Self::StIIM => write!(f, "StIIM"), + Self::StIHA => write!(f, "StIHA"), + Self::CR26 => write!(f, "CR26"), + Self::CR27 => write!(f, "CR27"), + Self::CR28 => write!(f, "CR28"), + Self::CR29 => write!(f, "CR29"), + Self::CR30 => write!(f, "CR30"), + Self::CR31 => write!(f, "CR31"), + Self::CR32 => write!(f, "CR32"), + Self::CR33 => write!(f, "CR33"), + Self::CR34 => write!(f, "CR34"), + Self::CR35 => write!(f, "CR35"), + Self::CR36 => write!(f, "CR36"), + Self::CR37 => write!(f, "CR37"), + Self::CR38 => write!(f, "CR38"), + Self::CR39 => write!(f, "CR39"), + Self::CR40 => write!(f, "CR40"), + Self::CR41 => write!(f, "CR41"), + Self::CR42 => write!(f, "CR42"), + Self::CR43 => write!(f, "CR43"), + Self::CR44 => write!(f, "CR44"), + Self::CR45 => write!(f, "CR45"), + Self::CR46 => write!(f, "CR46"), + Self::CR47 => write!(f, "CR47"), + Self::CR48 => write!(f, "CR48"), + Self::CR49 => write!(f, "CR49"), + Self::CR50 => write!(f, "CR50"), + Self::CR51 => write!(f, "CR51"), + Self::CR52 => write!(f, "CR52"), + Self::CR53 => write!(f, "CR53"), + Self::CR54 => write!(f, "CR54"), + Self::CR55 => write!(f, "CR55"), + Self::CR56 => write!(f, "CR56"), + Self::CR57 => write!(f, "CR57"), + Self::CR58 => write!(f, "CR58"), + Self::CR59 => write!(f, "CR59"), + Self::CR60 => write!(f, "CR60"), + Self::CR61 => write!(f, "CR61"), + Self::CR62 => write!(f, "CR62"), + Self::CR63 => write!(f, "CR63"), + Self::SaLID => write!(f, "SaLID"), + Self::SaIVR => write!(f, "SaIVR"), + Self::SaTPR => write!(f, "SaTPR"), + Self::SaEOI => write!(f, "SaEOI"), + Self::SaIRR0 => write!(f, "SaIRR0"), + Self::SaIRR1 => write!(f, "SaIRR1"), + Self::SaIRR2 => write!(f, "SaIRR2"), + Self::SaIRR3 => write!(f, "SaIRR3"), + Self::SaITV => write!(f, "SaITV"), + Self::SaPMV => write!(f, "SaPMV"), + Self::SaCMCV => write!(f, "SaCMCV"), + Self::CR75 => write!(f, "CR75"), + Self::CR76 => write!(f, "CR76"), + Self::CR77 => write!(f, "CR77"), + Self::CR78 => write!(f, "CR78"), + Self::CR79 => write!(f, "CR79"), + Self::SaLRR0 => write!(f, "SaLRR0"), + Self::SaLRR1 => write!(f, "SaLRR1"), + Self::CR82 => write!(f, "CR82"), + Self::CR83 => write!(f, "CR83"), + Self::CR84 => write!(f, "CR84"), + Self::CR85 => write!(f, "CR85"), + Self::CR86 => write!(f, "CR86"), + Self::CR87 => write!(f, "CR87"), + Self::CR88 => write!(f, "CR88"), + Self::CR89 => write!(f, "CR89"), + Self::CR90 => write!(f, "CR90"), + Self::CR91 => write!(f, "CR91"), + Self::CR92 => write!(f, "CR92"), + Self::CR93 => write!(f, "CR93"), + Self::CR94 => write!(f, "CR94"), + Self::CR95 => write!(f, "CR95"), + Self::CR96 => write!(f, "CR96"), + Self::CR97 => write!(f, "CR97"), + Self::CR98 => write!(f, "CR98"), + Self::CR99 => write!(f, "CR99"), + Self::CR100 => write!(f, "CR100"), + Self::CR101 => write!(f, "CR101"), + Self::CR102 => write!(f, "CR102"), + Self::CR103 => write!(f, "CR103"), + Self::CR104 => write!(f, "CR104"), + Self::CR105 => write!(f, "CR105"), + Self::CR106 => write!(f, "CR106"), + Self::CR107 => write!(f, "CR107"), + Self::CR108 => write!(f, "CR108"), + Self::CR109 => write!(f, "CR109"), + Self::CR110 => write!(f, "CR110"), + Self::CR111 => write!(f, "CR111"), + Self::CR112 => write!(f, "CR112"), + Self::CR113 => write!(f, "CR113"), + Self::CR114 => write!(f, "CR114"), + Self::CR115 => write!(f, "CR115"), + Self::CR116 => write!(f, "CR116"), + Self::CR117 => write!(f, "CR117"), + Self::CR118 => write!(f, "CR118"), + Self::CR119 => write!(f, "CR119"), + Self::CR120 => write!(f, "CR120"), + Self::CR121 => write!(f, "CR121"), + Self::CR122 => write!(f, "CR122"), + Self::CR123 => write!(f, "CR123"), + Self::CR124 => write!(f, "CR124"), + Self::CR125 => write!(f, "CR125"), + Self::CR126 => write!(f, "CR126"), + Self::CR127 => write!(f, "CR127"), + Self::Pkr0 => write!(f, "Pkr0"), + Self::Pkr1 => write!(f, "Pkr1"), + Self::Pkr2 => write!(f, "Pkr2"), + Self::Pkr3 => write!(f, "Pkr3"), + Self::Pkr4 => write!(f, "Pkr4"), + Self::Pkr5 => write!(f, "Pkr5"), + Self::Pkr6 => write!(f, "Pkr6"), + Self::Pkr7 => write!(f, "Pkr7"), + Self::Pkr8 => write!(f, "Pkr8"), + Self::Pkr9 => write!(f, "Pkr9"), + Self::Pkr10 => write!(f, "Pkr10"), + Self::Pkr11 => write!(f, "Pkr11"), + Self::Pkr12 => write!(f, "Pkr12"), + Self::Pkr13 => write!(f, "Pkr13"), + Self::Pkr14 => write!(f, "Pkr14"), + Self::Pkr15 => write!(f, "Pkr15"), + Self::Rr0 => write!(f, "Rr0"), + Self::Rr1 => write!(f, "Rr1"), + Self::Rr2 => write!(f, "Rr2"), + Self::Rr3 => write!(f, "Rr3"), + Self::Rr4 => write!(f, "Rr4"), + Self::Rr5 => write!(f, "Rr5"), + Self::Rr6 => write!(f, "Rr6"), + Self::Rr7 => write!(f, "Rr7"), + Self::PFD0 => write!(f, "PFD0"), + Self::PFD1 => write!(f, "PFD1"), + Self::PFD2 => write!(f, "PFD2"), + Self::PFD3 => write!(f, "PFD3"), + Self::PFD4 => write!(f, "PFD4"), + Self::PFD5 => write!(f, "PFD5"), + Self::PFD6 => write!(f, "PFD6"), + Self::PFD7 => write!(f, "PFD7"), + Self::PFD8 => write!(f, "PFD8"), + Self::PFD9 => write!(f, "PFD9"), + Self::PFD10 => write!(f, "PFD10"), + Self::PFD11 => write!(f, "PFD11"), + Self::PFD12 => write!(f, "PFD12"), + Self::PFD13 => write!(f, "PFD13"), + Self::PFD14 => write!(f, "PFD14"), + Self::PFD15 => write!(f, "PFD15"), + Self::PFD16 => write!(f, "PFD16"), + Self::PFD17 => write!(f, "PFD17"), + Self::PFC0 => write!(f, "PFC0"), + Self::PFC1 => write!(f, "PFC1"), + Self::PFC2 => write!(f, "PFC2"), + Self::PFC3 => write!(f, "PFC3"), + Self::PFC4 => write!(f, "PFC4"), + Self::PFC5 => write!(f, "PFC5"), + Self::PFC6 => write!(f, "PFC6"), + Self::PFC7 => write!(f, "PFC7"), + Self::PFC8 => write!(f, "PFC8"), + Self::PFC9 => write!(f, "PFC9"), + Self::PFC10 => write!(f, "PFC10"), + Self::PFC11 => write!(f, "PFC11"), + Self::PFC12 => write!(f, "PFC12"), + Self::PFC13 => write!(f, "PFC13"), + Self::PFC14 => write!(f, "PFC14"), + Self::PFC15 => write!(f, "PFC15"), + Self::TrI0 => write!(f, "TrI0"), + Self::TrI1 => write!(f, "TrI1"), + Self::TrI2 => write!(f, "TrI2"), + Self::TrI3 => write!(f, "TrI3"), + Self::TrI4 => write!(f, "TrI4"), + Self::TrI5 => write!(f, "TrI5"), + Self::TrI6 => write!(f, "TrI6"), + Self::TrI7 => write!(f, "TrI7"), + Self::TrD0 => write!(f, "TrD0"), + Self::TrD1 => write!(f, "TrD1"), + Self::TrD2 => write!(f, "TrD2"), + Self::TrD3 => write!(f, "TrD3"), + Self::TrD4 => write!(f, "TrD4"), + Self::TrD5 => write!(f, "TrD5"), + Self::TrD6 => write!(f, "TrD6"), + Self::TrD7 => write!(f, "TrD7"), + Self::DbI0 => write!(f, "DbI0"), + Self::DbI1 => write!(f, "DbI1"), + Self::DbI2 => write!(f, "DbI2"), + Self::DbI3 => write!(f, "DbI3"), + Self::DbI4 => write!(f, "DbI4"), + Self::DbI5 => write!(f, "DbI5"), + Self::DbI6 => write!(f, "DbI6"), + Self::DbI7 => write!(f, "DbI7"), + Self::DbD0 => write!(f, "DbD0"), + Self::DbD1 => write!(f, "DbD1"), + Self::DbD2 => write!(f, "DbD2"), + Self::DbD3 => write!(f, "DbD3"), + Self::DbD4 => write!(f, "DbD4"), + Self::DbD5 => write!(f, "DbD5"), + Self::DbD6 => write!(f, "DbD6"), + Self::DbD7 => write!(f, "DbD7"), + } + } +} + +impl TryFrom for IA64Register { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 512 => Ok(Self::Br0), + 513 => Ok(Self::Br1), + 514 => Ok(Self::Br2), + 515 => Ok(Self::Br3), + 516 => Ok(Self::Br4), + 517 => Ok(Self::Br5), + 518 => Ok(Self::Br6), + 519 => Ok(Self::Br7), + 704 => Ok(Self::P0), + 705 => Ok(Self::P1), + 706 => Ok(Self::P2), + 707 => Ok(Self::P3), + 708 => Ok(Self::P4), + 709 => Ok(Self::P5), + 710 => Ok(Self::P6), + 711 => Ok(Self::P7), + 712 => Ok(Self::P8), + 713 => Ok(Self::P9), + 714 => Ok(Self::P10), + 715 => Ok(Self::P11), + 716 => Ok(Self::P12), + 717 => Ok(Self::P13), + 718 => Ok(Self::P14), + 719 => Ok(Self::P15), + 720 => Ok(Self::P16), + 721 => Ok(Self::P17), + 722 => Ok(Self::P18), + 723 => Ok(Self::P19), + 724 => Ok(Self::P20), + 725 => Ok(Self::P21), + 726 => Ok(Self::P22), + 727 => Ok(Self::P23), + 728 => Ok(Self::P24), + 729 => Ok(Self::P25), + 730 => Ok(Self::P26), + 731 => Ok(Self::P27), + 732 => Ok(Self::P28), + 733 => Ok(Self::P29), + 734 => Ok(Self::P30), + 735 => Ok(Self::P31), + 736 => Ok(Self::P32), + 737 => Ok(Self::P33), + 738 => Ok(Self::P34), + 739 => Ok(Self::P35), + 740 => Ok(Self::P36), + 741 => Ok(Self::P37), + 742 => Ok(Self::P38), + 743 => Ok(Self::P39), + 744 => Ok(Self::P40), + 745 => Ok(Self::P41), + 746 => Ok(Self::P42), + 747 => Ok(Self::P43), + 748 => Ok(Self::P44), + 749 => Ok(Self::P45), + 750 => Ok(Self::P46), + 751 => Ok(Self::P47), + 752 => Ok(Self::P48), + 753 => Ok(Self::P49), + 754 => Ok(Self::P50), + 755 => Ok(Self::P51), + 756 => Ok(Self::P52), + 757 => Ok(Self::P53), + 758 => Ok(Self::P54), + 759 => Ok(Self::P55), + 760 => Ok(Self::P56), + 761 => Ok(Self::P57), + 762 => Ok(Self::P58), + 763 => Ok(Self::P59), + 764 => Ok(Self::P60), + 765 => Ok(Self::P61), + 766 => Ok(Self::P62), + 767 => Ok(Self::P63), + 768 => Ok(Self::Preds), + 832 => Ok(Self::IntH0), + 833 => Ok(Self::IntH1), + 834 => Ok(Self::IntH2), + 835 => Ok(Self::IntH3), + 836 => Ok(Self::IntH4), + 837 => Ok(Self::IntH5), + 838 => Ok(Self::IntH6), + 839 => Ok(Self::IntH7), + 840 => Ok(Self::IntH8), + 841 => Ok(Self::IntH9), + 842 => Ok(Self::IntH10), + 843 => Ok(Self::IntH11), + 844 => Ok(Self::IntH12), + 845 => Ok(Self::IntH13), + 846 => Ok(Self::IntH14), + 847 => Ok(Self::IntH15), + 1016 => Ok(Self::Ip), + 1017 => Ok(Self::Umask), + 1018 => Ok(Self::Cfm), + 1019 => Ok(Self::Psr), + 1020 => Ok(Self::Nats), + 1021 => Ok(Self::Nats2), + 1022 => Ok(Self::Nats3), + 1024 => Ok(Self::IntR0), + 1025 => Ok(Self::IntR1), + 1026 => Ok(Self::IntR2), + 1027 => Ok(Self::IntR3), + 1028 => Ok(Self::IntR4), + 1029 => Ok(Self::IntR5), + 1030 => Ok(Self::IntR6), + 1031 => Ok(Self::IntR7), + 1032 => Ok(Self::IntR8), + 1033 => Ok(Self::IntR9), + 1034 => Ok(Self::IntR10), + 1035 => Ok(Self::IntR11), + 1036 => Ok(Self::IntR12), + 1037 => Ok(Self::IntR13), + 1038 => Ok(Self::IntR14), + 1039 => Ok(Self::IntR15), + 1040 => Ok(Self::IntR16), + 1041 => Ok(Self::IntR17), + 1042 => Ok(Self::IntR18), + 1043 => Ok(Self::IntR19), + 1044 => Ok(Self::IntR20), + 1045 => Ok(Self::IntR21), + 1046 => Ok(Self::IntR22), + 1047 => Ok(Self::IntR23), + 1048 => Ok(Self::IntR24), + 1049 => Ok(Self::IntR25), + 1050 => Ok(Self::IntR26), + 1051 => Ok(Self::IntR27), + 1052 => Ok(Self::IntR28), + 1053 => Ok(Self::IntR29), + 1054 => Ok(Self::IntR30), + 1055 => Ok(Self::IntR31), + 1056 => Ok(Self::IntR32), + 1057 => Ok(Self::IntR33), + 1058 => Ok(Self::IntR34), + 1059 => Ok(Self::IntR35), + 1060 => Ok(Self::IntR36), + 1061 => Ok(Self::IntR37), + 1062 => Ok(Self::IntR38), + 1063 => Ok(Self::IntR39), + 1064 => Ok(Self::IntR40), + 1065 => Ok(Self::IntR41), + 1066 => Ok(Self::IntR42), + 1067 => Ok(Self::IntR43), + 1068 => Ok(Self::IntR44), + 1069 => Ok(Self::IntR45), + 1070 => Ok(Self::IntR46), + 1071 => Ok(Self::IntR47), + 1072 => Ok(Self::IntR48), + 1073 => Ok(Self::IntR49), + 1074 => Ok(Self::IntR50), + 1075 => Ok(Self::IntR51), + 1076 => Ok(Self::IntR52), + 1077 => Ok(Self::IntR53), + 1078 => Ok(Self::IntR54), + 1079 => Ok(Self::IntR55), + 1080 => Ok(Self::IntR56), + 1081 => Ok(Self::IntR57), + 1082 => Ok(Self::IntR58), + 1083 => Ok(Self::IntR59), + 1084 => Ok(Self::IntR60), + 1085 => Ok(Self::IntR61), + 1086 => Ok(Self::IntR62), + 1087 => Ok(Self::IntR63), + 1088 => Ok(Self::IntR64), + 1089 => Ok(Self::IntR65), + 1090 => Ok(Self::IntR66), + 1091 => Ok(Self::IntR67), + 1092 => Ok(Self::IntR68), + 1093 => Ok(Self::IntR69), + 1094 => Ok(Self::IntR70), + 1095 => Ok(Self::IntR71), + 1096 => Ok(Self::IntR72), + 1097 => Ok(Self::IntR73), + 1098 => Ok(Self::IntR74), + 1099 => Ok(Self::IntR75), + 1100 => Ok(Self::IntR76), + 1101 => Ok(Self::IntR77), + 1102 => Ok(Self::IntR78), + 1103 => Ok(Self::IntR79), + 1104 => Ok(Self::IntR80), + 1105 => Ok(Self::IntR81), + 1106 => Ok(Self::IntR82), + 1107 => Ok(Self::IntR83), + 1108 => Ok(Self::IntR84), + 1109 => Ok(Self::IntR85), + 1110 => Ok(Self::IntR86), + 1111 => Ok(Self::IntR87), + 1112 => Ok(Self::IntR88), + 1113 => Ok(Self::IntR89), + 1114 => Ok(Self::IntR90), + 1115 => Ok(Self::IntR91), + 1116 => Ok(Self::IntR92), + 1117 => Ok(Self::IntR93), + 1118 => Ok(Self::IntR94), + 1119 => Ok(Self::IntR95), + 1120 => Ok(Self::IntR96), + 1121 => Ok(Self::IntR97), + 1122 => Ok(Self::IntR98), + 1123 => Ok(Self::IntR99), + 1124 => Ok(Self::IntR100), + 1125 => Ok(Self::IntR101), + 1126 => Ok(Self::IntR102), + 1127 => Ok(Self::IntR103), + 1128 => Ok(Self::IntR104), + 1129 => Ok(Self::IntR105), + 1130 => Ok(Self::IntR106), + 1131 => Ok(Self::IntR107), + 1132 => Ok(Self::IntR108), + 1133 => Ok(Self::IntR109), + 1134 => Ok(Self::IntR110), + 1135 => Ok(Self::IntR111), + 1136 => Ok(Self::IntR112), + 1137 => Ok(Self::IntR113), + 1138 => Ok(Self::IntR114), + 1139 => Ok(Self::IntR115), + 1140 => Ok(Self::IntR116), + 1141 => Ok(Self::IntR117), + 1142 => Ok(Self::IntR118), + 1143 => Ok(Self::IntR119), + 1144 => Ok(Self::IntR120), + 1145 => Ok(Self::IntR121), + 1146 => Ok(Self::IntR122), + 1147 => Ok(Self::IntR123), + 1148 => Ok(Self::IntR124), + 1149 => Ok(Self::IntR125), + 1150 => Ok(Self::IntR126), + 1151 => Ok(Self::IntR127), + 2048 => Ok(Self::FltF0), + 2049 => Ok(Self::FltF1), + 2050 => Ok(Self::FltF2), + 2051 => Ok(Self::FltF3), + 2052 => Ok(Self::FltF4), + 2053 => Ok(Self::FltF5), + 2054 => Ok(Self::FltF6), + 2055 => Ok(Self::FltF7), + 2056 => Ok(Self::FltF8), + 2057 => Ok(Self::FltF9), + 2058 => Ok(Self::FltF10), + 2059 => Ok(Self::FltF11), + 2060 => Ok(Self::FltF12), + 2061 => Ok(Self::FltF13), + 2062 => Ok(Self::FltF14), + 2063 => Ok(Self::FltF15), + 2064 => Ok(Self::FltF16), + 2065 => Ok(Self::FltF17), + 2066 => Ok(Self::FltF18), + 2067 => Ok(Self::FltF19), + 2068 => Ok(Self::FltF20), + 2069 => Ok(Self::FltF21), + 2070 => Ok(Self::FltF22), + 2071 => Ok(Self::FltF23), + 2072 => Ok(Self::FltF24), + 2073 => Ok(Self::FltF25), + 2074 => Ok(Self::FltF26), + 2075 => Ok(Self::FltF27), + 2076 => Ok(Self::FltF28), + 2077 => Ok(Self::FltF29), + 2078 => Ok(Self::FltF30), + 2079 => Ok(Self::FltF31), + 2080 => Ok(Self::FltF32), + 2081 => Ok(Self::FltF33), + 2082 => Ok(Self::FltF34), + 2083 => Ok(Self::FltF35), + 2084 => Ok(Self::FltF36), + 2085 => Ok(Self::FltF37), + 2086 => Ok(Self::FltF38), + 2087 => Ok(Self::FltF39), + 2088 => Ok(Self::FltF40), + 2089 => Ok(Self::FltF41), + 2090 => Ok(Self::FltF42), + 2091 => Ok(Self::FltF43), + 2092 => Ok(Self::FltF44), + 2093 => Ok(Self::FltF45), + 2094 => Ok(Self::FltF46), + 2095 => Ok(Self::FltF47), + 2096 => Ok(Self::FltF48), + 2097 => Ok(Self::FltF49), + 2098 => Ok(Self::FltF50), + 2099 => Ok(Self::FltF51), + 2100 => Ok(Self::FltF52), + 2101 => Ok(Self::FltF53), + 2102 => Ok(Self::FltF54), + 2103 => Ok(Self::FltF55), + 2104 => Ok(Self::FltF56), + 2105 => Ok(Self::FltF57), + 2106 => Ok(Self::FltF58), + 2107 => Ok(Self::FltF59), + 2108 => Ok(Self::FltF60), + 2109 => Ok(Self::FltF61), + 2110 => Ok(Self::FltF62), + 2111 => Ok(Self::FltF63), + 2112 => Ok(Self::FltF64), + 2113 => Ok(Self::FltF65), + 2114 => Ok(Self::FltF66), + 2115 => Ok(Self::FltF67), + 2116 => Ok(Self::FltF68), + 2117 => Ok(Self::FltF69), + 2118 => Ok(Self::FltF70), + 2119 => Ok(Self::FltF71), + 2120 => Ok(Self::FltF72), + 2121 => Ok(Self::FltF73), + 2122 => Ok(Self::FltF74), + 2123 => Ok(Self::FltF75), + 2124 => Ok(Self::FltF76), + 2125 => Ok(Self::FltF77), + 2126 => Ok(Self::FltF78), + 2127 => Ok(Self::FltF79), + 2128 => Ok(Self::FltF80), + 2129 => Ok(Self::FltF81), + 2130 => Ok(Self::FltF82), + 2131 => Ok(Self::FltF83), + 2132 => Ok(Self::FltF84), + 2133 => Ok(Self::FltF85), + 2134 => Ok(Self::FltF86), + 2135 => Ok(Self::FltF87), + 2136 => Ok(Self::FltF88), + 2137 => Ok(Self::FltF89), + 2138 => Ok(Self::FltF90), + 2139 => Ok(Self::FltF91), + 2140 => Ok(Self::FltF92), + 2141 => Ok(Self::FltF93), + 2142 => Ok(Self::FltF94), + 2143 => Ok(Self::FltF95), + 2144 => Ok(Self::FltF96), + 2145 => Ok(Self::FltF97), + 2146 => Ok(Self::FltF98), + 2147 => Ok(Self::FltF99), + 2148 => Ok(Self::FltF100), + 2149 => Ok(Self::FltF101), + 2150 => Ok(Self::FltF102), + 2151 => Ok(Self::FltF103), + 2152 => Ok(Self::FltF104), + 2153 => Ok(Self::FltF105), + 2154 => Ok(Self::FltF106), + 2155 => Ok(Self::FltF107), + 2156 => Ok(Self::FltF108), + 2157 => Ok(Self::FltF109), + 2158 => Ok(Self::FltF110), + 2159 => Ok(Self::FltF111), + 2160 => Ok(Self::FltF112), + 2161 => Ok(Self::FltF113), + 2162 => Ok(Self::FltF114), + 2163 => Ok(Self::FltF115), + 2164 => Ok(Self::FltF116), + 2165 => Ok(Self::FltF117), + 2166 => Ok(Self::FltF118), + 2167 => Ok(Self::FltF119), + 2168 => Ok(Self::FltF120), + 2169 => Ok(Self::FltF121), + 2170 => Ok(Self::FltF122), + 2171 => Ok(Self::FltF123), + 2172 => Ok(Self::FltF124), + 2173 => Ok(Self::FltF125), + 2174 => Ok(Self::FltF126), + 2175 => Ok(Self::FltF127), + 3072 => Ok(Self::ApKR0), + 3073 => Ok(Self::ApKR1), + 3074 => Ok(Self::ApKR2), + 3075 => Ok(Self::ApKR3), + 3076 => Ok(Self::ApKR4), + 3077 => Ok(Self::ApKR5), + 3078 => Ok(Self::ApKR6), + 3079 => Ok(Self::ApKR7), + 3080 => Ok(Self::AR8), + 3081 => Ok(Self::AR9), + 3082 => Ok(Self::AR10), + 3083 => Ok(Self::AR11), + 3084 => Ok(Self::AR12), + 3085 => Ok(Self::AR13), + 3086 => Ok(Self::AR14), + 3087 => Ok(Self::AR15), + 3088 => Ok(Self::RsRSC), + 3089 => Ok(Self::RsBSP), + 3090 => Ok(Self::RsBSPSTORE), + 3091 => Ok(Self::RsRNAT), + 3092 => Ok(Self::AR20), + 3093 => Ok(Self::StFCR), + 3094 => Ok(Self::AR22), + 3095 => Ok(Self::AR23), + 3096 => Ok(Self::EFLAG), + 3097 => Ok(Self::CSD), + 3098 => Ok(Self::SSD), + 3099 => Ok(Self::CFLG), + 3100 => Ok(Self::StFSR), + 3101 => Ok(Self::StFIR), + 3102 => Ok(Self::StFDR), + 3103 => Ok(Self::AR31), + 3104 => Ok(Self::ApCCV), + 3105 => Ok(Self::AR33), + 3106 => Ok(Self::AR34), + 3107 => Ok(Self::AR35), + 3108 => Ok(Self::ApUNAT), + 3109 => Ok(Self::AR37), + 3110 => Ok(Self::AR38), + 3111 => Ok(Self::AR39), + 3112 => Ok(Self::StFPSR), + 3113 => Ok(Self::AR41), + 3114 => Ok(Self::AR42), + 3115 => Ok(Self::AR43), + 3116 => Ok(Self::ApITC), + 3117 => Ok(Self::AR45), + 3118 => Ok(Self::AR46), + 3119 => Ok(Self::AR47), + 3120 => Ok(Self::AR48), + 3121 => Ok(Self::AR49), + 3122 => Ok(Self::AR50), + 3123 => Ok(Self::AR51), + 3124 => Ok(Self::AR52), + 3125 => Ok(Self::AR53), + 3126 => Ok(Self::AR54), + 3127 => Ok(Self::AR55), + 3128 => Ok(Self::AR56), + 3129 => Ok(Self::AR57), + 3130 => Ok(Self::AR58), + 3131 => Ok(Self::AR59), + 3132 => Ok(Self::AR60), + 3133 => Ok(Self::AR61), + 3134 => Ok(Self::AR62), + 3135 => Ok(Self::AR63), + 3136 => Ok(Self::RsPFS), + 3137 => Ok(Self::ApLC), + 3138 => Ok(Self::ApEC), + 3139 => Ok(Self::AR67), + 3140 => Ok(Self::AR68), + 3141 => Ok(Self::AR69), + 3142 => Ok(Self::AR70), + 3143 => Ok(Self::AR71), + 3144 => Ok(Self::AR72), + 3145 => Ok(Self::AR73), + 3146 => Ok(Self::AR74), + 3147 => Ok(Self::AR75), + 3148 => Ok(Self::AR76), + 3149 => Ok(Self::AR77), + 3150 => Ok(Self::AR78), + 3151 => Ok(Self::AR79), + 3152 => Ok(Self::AR80), + 3153 => Ok(Self::AR81), + 3154 => Ok(Self::AR82), + 3155 => Ok(Self::AR83), + 3156 => Ok(Self::AR84), + 3157 => Ok(Self::AR85), + 3158 => Ok(Self::AR86), + 3159 => Ok(Self::AR87), + 3160 => Ok(Self::AR88), + 3161 => Ok(Self::AR89), + 3162 => Ok(Self::AR90), + 3163 => Ok(Self::AR91), + 3164 => Ok(Self::AR92), + 3165 => Ok(Self::AR93), + 3166 => Ok(Self::AR94), + 3167 => Ok(Self::AR95), + 3168 => Ok(Self::AR96), + 3169 => Ok(Self::AR97), + 3170 => Ok(Self::AR98), + 3171 => Ok(Self::AR99), + 3172 => Ok(Self::AR100), + 3173 => Ok(Self::AR101), + 3174 => Ok(Self::AR102), + 3175 => Ok(Self::AR103), + 3176 => Ok(Self::AR104), + 3177 => Ok(Self::AR105), + 3178 => Ok(Self::AR106), + 3179 => Ok(Self::AR107), + 3180 => Ok(Self::AR108), + 3181 => Ok(Self::AR109), + 3182 => Ok(Self::AR110), + 3183 => Ok(Self::AR111), + 3184 => Ok(Self::AR112), + 3185 => Ok(Self::AR113), + 3186 => Ok(Self::AR114), + 3187 => Ok(Self::AR115), + 3188 => Ok(Self::AR116), + 3189 => Ok(Self::AR117), + 3190 => Ok(Self::AR118), + 3191 => Ok(Self::AR119), + 3192 => Ok(Self::AR120), + 3193 => Ok(Self::AR121), + 3194 => Ok(Self::AR122), + 3195 => Ok(Self::AR123), + 3196 => Ok(Self::AR124), + 3197 => Ok(Self::AR125), + 3198 => Ok(Self::AR126), + 3199 => Ok(Self::AR127), + 3328 => Ok(Self::CPUID0), + 3329 => Ok(Self::CPUID1), + 3330 => Ok(Self::CPUID2), + 3331 => Ok(Self::CPUID3), + 3332 => Ok(Self::CPUID4), + 4096 => Ok(Self::ApDCR), + 4097 => Ok(Self::ApITM), + 4098 => Ok(Self::ApIVA), + 4099 => Ok(Self::CR3), + 4100 => Ok(Self::CR4), + 4101 => Ok(Self::CR5), + 4102 => Ok(Self::CR6), + 4103 => Ok(Self::CR7), + 4104 => Ok(Self::ApPTA), + 4105 => Ok(Self::ApGPTA), + 4106 => Ok(Self::CR10), + 4107 => Ok(Self::CR11), + 4108 => Ok(Self::CR12), + 4109 => Ok(Self::CR13), + 4110 => Ok(Self::CR14), + 4111 => Ok(Self::CR15), + 4112 => Ok(Self::StIPSR), + 4113 => Ok(Self::StISR), + 4114 => Ok(Self::CR18), + 4115 => Ok(Self::StIIP), + 4116 => Ok(Self::StIFA), + 4117 => Ok(Self::StITIR), + 4118 => Ok(Self::StIIPA), + 4119 => Ok(Self::StIFS), + 4120 => Ok(Self::StIIM), + 4121 => Ok(Self::StIHA), + 4122 => Ok(Self::CR26), + 4123 => Ok(Self::CR27), + 4124 => Ok(Self::CR28), + 4125 => Ok(Self::CR29), + 4126 => Ok(Self::CR30), + 4127 => Ok(Self::CR31), + 4128 => Ok(Self::CR32), + 4129 => Ok(Self::CR33), + 4130 => Ok(Self::CR34), + 4131 => Ok(Self::CR35), + 4132 => Ok(Self::CR36), + 4133 => Ok(Self::CR37), + 4134 => Ok(Self::CR38), + 4135 => Ok(Self::CR39), + 4136 => Ok(Self::CR40), + 4137 => Ok(Self::CR41), + 4138 => Ok(Self::CR42), + 4139 => Ok(Self::CR43), + 4140 => Ok(Self::CR44), + 4141 => Ok(Self::CR45), + 4142 => Ok(Self::CR46), + 4143 => Ok(Self::CR47), + 4144 => Ok(Self::CR48), + 4145 => Ok(Self::CR49), + 4146 => Ok(Self::CR50), + 4147 => Ok(Self::CR51), + 4148 => Ok(Self::CR52), + 4149 => Ok(Self::CR53), + 4150 => Ok(Self::CR54), + 4151 => Ok(Self::CR55), + 4152 => Ok(Self::CR56), + 4153 => Ok(Self::CR57), + 4154 => Ok(Self::CR58), + 4155 => Ok(Self::CR59), + 4156 => Ok(Self::CR60), + 4157 => Ok(Self::CR61), + 4158 => Ok(Self::CR62), + 4159 => Ok(Self::CR63), + 4160 => Ok(Self::SaLID), + 4161 => Ok(Self::SaIVR), + 4162 => Ok(Self::SaTPR), + 4163 => Ok(Self::SaEOI), + 4164 => Ok(Self::SaIRR0), + 4165 => Ok(Self::SaIRR1), + 4166 => Ok(Self::SaIRR2), + 4167 => Ok(Self::SaIRR3), + 4168 => Ok(Self::SaITV), + 4169 => Ok(Self::SaPMV), + 4170 => Ok(Self::SaCMCV), + 4171 => Ok(Self::CR75), + 4172 => Ok(Self::CR76), + 4173 => Ok(Self::CR77), + 4174 => Ok(Self::CR78), + 4175 => Ok(Self::CR79), + 4176 => Ok(Self::SaLRR0), + 4177 => Ok(Self::SaLRR1), + 4178 => Ok(Self::CR82), + 4179 => Ok(Self::CR83), + 4180 => Ok(Self::CR84), + 4181 => Ok(Self::CR85), + 4182 => Ok(Self::CR86), + 4183 => Ok(Self::CR87), + 4184 => Ok(Self::CR88), + 4185 => Ok(Self::CR89), + 4186 => Ok(Self::CR90), + 4187 => Ok(Self::CR91), + 4188 => Ok(Self::CR92), + 4189 => Ok(Self::CR93), + 4190 => Ok(Self::CR94), + 4191 => Ok(Self::CR95), + 4192 => Ok(Self::CR96), + 4193 => Ok(Self::CR97), + 4194 => Ok(Self::CR98), + 4195 => Ok(Self::CR99), + 4196 => Ok(Self::CR100), + 4197 => Ok(Self::CR101), + 4198 => Ok(Self::CR102), + 4199 => Ok(Self::CR103), + 4200 => Ok(Self::CR104), + 4201 => Ok(Self::CR105), + 4202 => Ok(Self::CR106), + 4203 => Ok(Self::CR107), + 4204 => Ok(Self::CR108), + 4205 => Ok(Self::CR109), + 4206 => Ok(Self::CR110), + 4207 => Ok(Self::CR111), + 4208 => Ok(Self::CR112), + 4209 => Ok(Self::CR113), + 4210 => Ok(Self::CR114), + 4211 => Ok(Self::CR115), + 4212 => Ok(Self::CR116), + 4213 => Ok(Self::CR117), + 4214 => Ok(Self::CR118), + 4215 => Ok(Self::CR119), + 4216 => Ok(Self::CR120), + 4217 => Ok(Self::CR121), + 4218 => Ok(Self::CR122), + 4219 => Ok(Self::CR123), + 4220 => Ok(Self::CR124), + 4221 => Ok(Self::CR125), + 4222 => Ok(Self::CR126), + 4223 => Ok(Self::CR127), + 5120 => Ok(Self::Pkr0), + 5121 => Ok(Self::Pkr1), + 5122 => Ok(Self::Pkr2), + 5123 => Ok(Self::Pkr3), + 5124 => Ok(Self::Pkr4), + 5125 => Ok(Self::Pkr5), + 5126 => Ok(Self::Pkr6), + 5127 => Ok(Self::Pkr7), + 5128 => Ok(Self::Pkr8), + 5129 => Ok(Self::Pkr9), + 5130 => Ok(Self::Pkr10), + 5131 => Ok(Self::Pkr11), + 5132 => Ok(Self::Pkr12), + 5133 => Ok(Self::Pkr13), + 5134 => Ok(Self::Pkr14), + 5135 => Ok(Self::Pkr15), + 6144 => Ok(Self::Rr0), + 6145 => Ok(Self::Rr1), + 6146 => Ok(Self::Rr2), + 6147 => Ok(Self::Rr3), + 6148 => Ok(Self::Rr4), + 6149 => Ok(Self::Rr5), + 6150 => Ok(Self::Rr6), + 6151 => Ok(Self::Rr7), + 7168 => Ok(Self::PFD0), + 7169 => Ok(Self::PFD1), + 7170 => Ok(Self::PFD2), + 7171 => Ok(Self::PFD3), + 7172 => Ok(Self::PFD4), + 7173 => Ok(Self::PFD5), + 7174 => Ok(Self::PFD6), + 7175 => Ok(Self::PFD7), + 7176 => Ok(Self::PFD8), + 7177 => Ok(Self::PFD9), + 7178 => Ok(Self::PFD10), + 7179 => Ok(Self::PFD11), + 7180 => Ok(Self::PFD12), + 7181 => Ok(Self::PFD13), + 7182 => Ok(Self::PFD14), + 7183 => Ok(Self::PFD15), + 7184 => Ok(Self::PFD16), + 7185 => Ok(Self::PFD17), + 7424 => Ok(Self::PFC0), + 7425 => Ok(Self::PFC1), + 7426 => Ok(Self::PFC2), + 7427 => Ok(Self::PFC3), + 7428 => Ok(Self::PFC4), + 7429 => Ok(Self::PFC5), + 7430 => Ok(Self::PFC6), + 7431 => Ok(Self::PFC7), + 7432 => Ok(Self::PFC8), + 7433 => Ok(Self::PFC9), + 7434 => Ok(Self::PFC10), + 7435 => Ok(Self::PFC11), + 7436 => Ok(Self::PFC12), + 7437 => Ok(Self::PFC13), + 7438 => Ok(Self::PFC14), + 7439 => Ok(Self::PFC15), + 8192 => Ok(Self::TrI0), + 8193 => Ok(Self::TrI1), + 8194 => Ok(Self::TrI2), + 8195 => Ok(Self::TrI3), + 8196 => Ok(Self::TrI4), + 8197 => Ok(Self::TrI5), + 8198 => Ok(Self::TrI6), + 8199 => Ok(Self::TrI7), + 8320 => Ok(Self::TrD0), + 8321 => Ok(Self::TrD1), + 8322 => Ok(Self::TrD2), + 8323 => Ok(Self::TrD3), + 8324 => Ok(Self::TrD4), + 8325 => Ok(Self::TrD5), + 8326 => Ok(Self::TrD6), + 8327 => Ok(Self::TrD7), + 8448 => Ok(Self::DbI0), + 8449 => Ok(Self::DbI1), + 8450 => Ok(Self::DbI2), + 8451 => Ok(Self::DbI3), + 8452 => Ok(Self::DbI4), + 8453 => Ok(Self::DbI5), + 8454 => Ok(Self::DbI6), + 8455 => Ok(Self::DbI7), + 8576 => Ok(Self::DbD0), + 8577 => Ok(Self::DbD1), + 8578 => Ok(Self::DbD2), + 8579 => Ok(Self::DbD3), + 8580 => Ok(Self::DbD4), + 8581 => Ok(Self::DbD5), + 8582 => Ok(Self::DbD6), + 8583 => Ok(Self::DbD7), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for IA64Register { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the TriCore processor +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum TricoreRegister { + // General Purpose Data Registers + D0 = 10, + D1 = 11, + D2 = 12, + D3 = 13, + D4 = 14, + D5 = 15, + D6 = 16, + D7 = 17, + D8 = 18, + D9 = 19, + D10 = 20, + D11 = 21, + D12 = 22, + D13 = 23, + D14 = 24, + D15 = 25, + + // General Purpose Address Registers + A0 = 26, + A1 = 27, + A2 = 28, + A3 = 29, + A4 = 30, + A5 = 31, + A6 = 32, + A7 = 33, + A8 = 34, + A9 = 35, + A10 = 36, + A11 = 37, + A12 = 38, + A13 = 39, + A14 = 40, + A15 = 41, + + // Extended (64-bit) data registers + E0 = 42, + E2 = 43, + E4 = 44, + E6 = 45, + E8 = 46, + E10 = 47, + E12 = 48, + E14 = 49, + + // Extended (64-bit) address registers + EA0 = 50, + EA2 = 51, + EA4 = 52, + EA6 = 53, + EA8 = 54, + EA10 = 55, + EA12 = 56, + EA14 = 57, + + PSW = 58, + PCXI = 59, + PC = 60, + FCX = 61, + LCX = 62, + ISP = 63, + ICR = 64, + BIV = 65, + BTV = 66, + SYSCON = 67, + DPRx_0 = 68, + DPRx_1 = 69, + DPRx_2 = 70, + DPRx_3 = 71, + // CPRx_0 = 68, + // CPRx_1 = 69, + // CPRx_2 = 70, + // CPRx_3 = 71, + // DPMx_0 = 68, + // DPMx_1 = 69, + // DPMx_2 = 70, + // DPMx_3 = 71, + // CPMx_0 = 68, + // CPMx_1 = 69, + // CPMx_2 = 70, + // CPMx_3 = 71, + DBGSSR = 72, + EXEVT = 73, + SWEVT = 74, + CREVT = 75, + TRnEVT = 76, + MMUCON = 77, + ASI = 78, + TVA = 79, + TPA = 80, + TPX = 81, + TFA = 82, +} + +impl fmt::Display for TricoreRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::D0 => write!(f, "D0"), + Self::D1 => write!(f, "D1"), + Self::D2 => write!(f, "D2"), + Self::D3 => write!(f, "D3"), + Self::D4 => write!(f, "D4"), + Self::D5 => write!(f, "D5"), + Self::D6 => write!(f, "D6"), + Self::D7 => write!(f, "D7"), + Self::D8 => write!(f, "D8"), + Self::D9 => write!(f, "D9"), + Self::D10 => write!(f, "D10"), + Self::D11 => write!(f, "D11"), + Self::D12 => write!(f, "D12"), + Self::D13 => write!(f, "D13"), + Self::D14 => write!(f, "D14"), + Self::D15 => write!(f, "D15"), + Self::A0 => write!(f, "A0"), + Self::A1 => write!(f, "A1"), + Self::A2 => write!(f, "A2"), + Self::A3 => write!(f, "A3"), + Self::A4 => write!(f, "A4"), + Self::A5 => write!(f, "A5"), + Self::A6 => write!(f, "A6"), + Self::A7 => write!(f, "A7"), + Self::A8 => write!(f, "A8"), + Self::A9 => write!(f, "A9"), + Self::A10 => write!(f, "A10"), + Self::A11 => write!(f, "A11"), + Self::A12 => write!(f, "A12"), + Self::A13 => write!(f, "A13"), + Self::A14 => write!(f, "A14"), + Self::A15 => write!(f, "A15"), + Self::E0 => write!(f, "E0"), + Self::E2 => write!(f, "E2"), + Self::E4 => write!(f, "E4"), + Self::E6 => write!(f, "E6"), + Self::E8 => write!(f, "E8"), + Self::E10 => write!(f, "E10"), + Self::E12 => write!(f, "E12"), + Self::E14 => write!(f, "E14"), + Self::EA0 => write!(f, "EA0"), + Self::EA2 => write!(f, "EA2"), + Self::EA4 => write!(f, "EA4"), + Self::EA6 => write!(f, "EA6"), + Self::EA8 => write!(f, "EA8"), + Self::EA10 => write!(f, "EA10"), + Self::EA12 => write!(f, "EA12"), + Self::EA14 => write!(f, "EA14"), + Self::PSW => write!(f, "PSW"), + Self::PCXI => write!(f, "PCXI"), + Self::PC => write!(f, "PC"), + Self::FCX => write!(f, "FCX"), + Self::LCX => write!(f, "LCX"), + Self::ISP => write!(f, "ISP"), + Self::ICR => write!(f, "ICR"), + Self::BIV => write!(f, "BIV"), + Self::BTV => write!(f, "BTV"), + Self::SYSCON => write!(f, "SYSCON"), + Self::DPRx_0 => write!(f, "DPRx_0"), + Self::DPRx_1 => write!(f, "DPRx_1"), + Self::DPRx_2 => write!(f, "DPRx_2"), + Self::DPRx_3 => write!(f, "DPRx_3"), + Self::DBGSSR => write!(f, "DBGSSR"), + Self::EXEVT => write!(f, "EXEVT"), + Self::SWEVT => write!(f, "SWEVT"), + Self::CREVT => write!(f, "CREVT"), + Self::TRnEVT => write!(f, "TRnEVT"), + Self::MMUCON => write!(f, "MMUCON"), + Self::ASI => write!(f, "ASI"), + Self::TVA => write!(f, "TVA"), + Self::TPA => write!(f, "TPA"), + Self::TPX => write!(f, "TPX"), + Self::TFA => write!(f, "TFA"), + } + } +} + +impl TryFrom for TricoreRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::D0), + 11 => Ok(Self::D1), + 12 => Ok(Self::D2), + 13 => Ok(Self::D3), + 14 => Ok(Self::D4), + 15 => Ok(Self::D5), + 16 => Ok(Self::D6), + 17 => Ok(Self::D7), + 18 => Ok(Self::D8), + 19 => Ok(Self::D9), + 20 => Ok(Self::D10), + 21 => Ok(Self::D11), + 22 => Ok(Self::D12), + 23 => Ok(Self::D13), + 24 => Ok(Self::D14), + 25 => Ok(Self::D15), + 26 => Ok(Self::A0), + 27 => Ok(Self::A1), + 28 => Ok(Self::A2), + 29 => Ok(Self::A3), + 30 => Ok(Self::A4), + 31 => Ok(Self::A5), + 32 => Ok(Self::A6), + 33 => Ok(Self::A7), + 34 => Ok(Self::A8), + 35 => Ok(Self::A9), + 36 => Ok(Self::A10), + 37 => Ok(Self::A11), + 38 => Ok(Self::A12), + 39 => Ok(Self::A13), + 40 => Ok(Self::A14), + 41 => Ok(Self::A15), + 42 => Ok(Self::E0), + 43 => Ok(Self::E2), + 44 => Ok(Self::E4), + 45 => Ok(Self::E6), + 46 => Ok(Self::E8), + 47 => Ok(Self::E10), + 48 => Ok(Self::E12), + 49 => Ok(Self::E14), + 50 => Ok(Self::EA0), + 51 => Ok(Self::EA2), + 52 => Ok(Self::EA4), + 53 => Ok(Self::EA6), + 54 => Ok(Self::EA8), + 55 => Ok(Self::EA10), + 56 => Ok(Self::EA12), + 57 => Ok(Self::EA14), + 58 => Ok(Self::PSW), + 59 => Ok(Self::PCXI), + 60 => Ok(Self::PC), + 61 => Ok(Self::FCX), + 62 => Ok(Self::LCX), + 63 => Ok(Self::ISP), + 64 => Ok(Self::ICR), + 65 => Ok(Self::BIV), + 66 => Ok(Self::BTV), + 67 => Ok(Self::SYSCON), + 68 => Ok(Self::DPRx_0), + 69 => Ok(Self::DPRx_1), + 70 => Ok(Self::DPRx_2), + 71 => Ok(Self::DPRx_3), + 72 => Ok(Self::DBGSSR), + 73 => Ok(Self::EXEVT), + 74 => Ok(Self::SWEVT), + 75 => Ok(Self::CREVT), + 76 => Ok(Self::TRnEVT), + 77 => Ok(Self::MMUCON), + 78 => Ok(Self::ASI), + 79 => Ok(Self::TVA), + 80 => Ok(Self::TPA), + 81 => Ok(Self::TPX), + 82 => Ok(Self::TFA), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for TricoreRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the AM33 and related processors +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum AM33Register { + // "Extended" (general purpose integer) registers + E0 = 10, + E1 = 11, + E2 = 12, + E3 = 13, + E4 = 14, + E5 = 15, + E6 = 16, + E7 = 17, + + // Address registers + A0 = 20, + A1 = 21, + A2 = 22, + A3 = 23, + + // Integer data registers + D0 = 30, + D1 = 31, + D2 = 32, + D3 = 33, + + // (Single-precision) floating-point registers + FS0 = 40, + FS1 = 41, + FS2 = 42, + FS3 = 43, + FS4 = 44, + FS5 = 45, + FS6 = 46, + FS7 = 47, + FS8 = 48, + FS9 = 49, + FS10 = 50, + FS11 = 51, + FS12 = 52, + FS13 = 53, + FS14 = 54, + FS15 = 55, + FS16 = 56, + FS17 = 57, + FS18 = 58, + FS19 = 59, + FS20 = 60, + FS21 = 61, + FS22 = 62, + FS23 = 63, + FS24 = 64, + FS25 = 65, + FS26 = 66, + FS27 = 67, + FS28 = 68, + FS29 = 69, + FS30 = 70, + FS31 = 71, + + // Special purpose registers + + // Stack pointer + SP = 80, + + // Program counter + PC = 81, + + // Multiply-divide/accumulate registers + MDR = 82, + MDRQ = 83, + MCRH = 84, + MCRL = 85, + MCVF = 86, + + // CPU status words + EPSW = 87, + FPCR = 88, + + // Loop buffer registers + LIR = 89, + LAR = 90, +} + +impl fmt::Display for AM33Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::E0 => write!(f, "E0"), + Self::E1 => write!(f, "E1"), + Self::E2 => write!(f, "E2"), + Self::E3 => write!(f, "E3"), + Self::E4 => write!(f, "E4"), + Self::E5 => write!(f, "E5"), + Self::E6 => write!(f, "E6"), + Self::E7 => write!(f, "E7"), + Self::A0 => write!(f, "A0"), + Self::A1 => write!(f, "A1"), + Self::A2 => write!(f, "A2"), + Self::A3 => write!(f, "A3"), + Self::D0 => write!(f, "D0"), + Self::D1 => write!(f, "D1"), + Self::D2 => write!(f, "D2"), + Self::D3 => write!(f, "D3"), + Self::FS0 => write!(f, "FS0"), + Self::FS1 => write!(f, "FS1"), + Self::FS2 => write!(f, "FS2"), + Self::FS3 => write!(f, "FS3"), + Self::FS4 => write!(f, "FS4"), + Self::FS5 => write!(f, "FS5"), + Self::FS6 => write!(f, "FS6"), + Self::FS7 => write!(f, "FS7"), + Self::FS8 => write!(f, "FS8"), + Self::FS9 => write!(f, "FS9"), + Self::FS10 => write!(f, "FS10"), + Self::FS11 => write!(f, "FS11"), + Self::FS12 => write!(f, "FS12"), + Self::FS13 => write!(f, "FS13"), + Self::FS14 => write!(f, "FS14"), + Self::FS15 => write!(f, "FS15"), + Self::FS16 => write!(f, "FS16"), + Self::FS17 => write!(f, "FS17"), + Self::FS18 => write!(f, "FS18"), + Self::FS19 => write!(f, "FS19"), + Self::FS20 => write!(f, "FS20"), + Self::FS21 => write!(f, "FS21"), + Self::FS22 => write!(f, "FS22"), + Self::FS23 => write!(f, "FS23"), + Self::FS24 => write!(f, "FS24"), + Self::FS25 => write!(f, "FS25"), + Self::FS26 => write!(f, "FS26"), + Self::FS27 => write!(f, "FS27"), + Self::FS28 => write!(f, "FS28"), + Self::FS29 => write!(f, "FS29"), + Self::FS30 => write!(f, "FS30"), + Self::FS31 => write!(f, "FS31"), + Self::SP => write!(f, "SP"), + Self::PC => write!(f, "PC"), + Self::MDR => write!(f, "MDR"), + Self::MDRQ => write!(f, "MDRQ"), + Self::MCRH => write!(f, "MCRH"), + Self::MCRL => write!(f, "MCRL"), + Self::MCVF => write!(f, "MCVF"), + Self::EPSW => write!(f, "EPSW"), + Self::FPCR => write!(f, "FPCR"), + Self::LIR => write!(f, "LIR"), + Self::LAR => write!(f, "LAR"), + } + } +} + +impl TryFrom for AM33Register { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::E0), + 11 => Ok(Self::E1), + 12 => Ok(Self::E2), + 13 => Ok(Self::E3), + 14 => Ok(Self::E4), + 15 => Ok(Self::E5), + 16 => Ok(Self::E6), + 17 => Ok(Self::E7), + 20 => Ok(Self::A0), + 21 => Ok(Self::A1), + 22 => Ok(Self::A2), + 23 => Ok(Self::A3), + 30 => Ok(Self::D0), + 31 => Ok(Self::D1), + 32 => Ok(Self::D2), + 33 => Ok(Self::D3), + 40 => Ok(Self::FS0), + 41 => Ok(Self::FS1), + 42 => Ok(Self::FS2), + 43 => Ok(Self::FS3), + 44 => Ok(Self::FS4), + 45 => Ok(Self::FS5), + 46 => Ok(Self::FS6), + 47 => Ok(Self::FS7), + 48 => Ok(Self::FS8), + 49 => Ok(Self::FS9), + 50 => Ok(Self::FS10), + 51 => Ok(Self::FS11), + 52 => Ok(Self::FS12), + 53 => Ok(Self::FS13), + 54 => Ok(Self::FS14), + 55 => Ok(Self::FS15), + 56 => Ok(Self::FS16), + 57 => Ok(Self::FS17), + 58 => Ok(Self::FS18), + 59 => Ok(Self::FS19), + 60 => Ok(Self::FS20), + 61 => Ok(Self::FS21), + 62 => Ok(Self::FS22), + 63 => Ok(Self::FS23), + 64 => Ok(Self::FS24), + 65 => Ok(Self::FS25), + 66 => Ok(Self::FS26), + 67 => Ok(Self::FS27), + 68 => Ok(Self::FS28), + 69 => Ok(Self::FS29), + 70 => Ok(Self::FS30), + 71 => Ok(Self::FS31), + 80 => Ok(Self::SP), + 81 => Ok(Self::PC), + 82 => Ok(Self::MDR), + 83 => Ok(Self::MDRQ), + 84 => Ok(Self::MCRH), + 85 => Ok(Self::MCRL), + 86 => Ok(Self::MCVF), + 87 => Ok(Self::EPSW), + 88 => Ok(Self::FPCR), + 89 => Ok(Self::LIR), + 90 => Ok(Self::LAR), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for AM33Register { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the Mitsubishi M32R +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum MitsubishiM32RRegister { + R0 = 10, + R1 = 11, + R2 = 12, + R3 = 13, + R4 = 14, + R5 = 15, + R6 = 16, + R7 = 17, + R8 = 18, + R9 = 19, + R10 = 20, + R11 = 21, + R12 = 22, // Gloabal Pointer, if used + R13 = 23, // Frame Pointer, if allocated + R14 = 24, // Link Register + R15 = 25, // Stack Pointer + PSW = 26, // Preocessor Status Register + CBR = 27, // Condition Bit Register + SPI = 28, // Interrupt Stack Pointer + SPU = 29, // User Stack Pointer + SPO = 30, // OS Stack Pointer + BPC = 31, // Backup Program Counter + ACHI = 32, // Accumulator High + ACLO = 33, // Accumulator Low + PC = 34, // Program Counter +} + +impl fmt::Display for MitsubishiM32RRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::R0 => write!(f, "R0"), + Self::R1 => write!(f, "R1"), + Self::R2 => write!(f, "R2"), + Self::R3 => write!(f, "R3"), + Self::R4 => write!(f, "R4"), + Self::R5 => write!(f, "R5"), + Self::R6 => write!(f, "R6"), + Self::R7 => write!(f, "R7"), + Self::R8 => write!(f, "R8"), + Self::R9 => write!(f, "R9"), + Self::R10 => write!(f, "R10"), + Self::R11 => write!(f, "R11"), + Self::R12 => write!(f, "R12"), + Self::R13 => write!(f, "R13"), + Self::R14 => write!(f, "R14"), + Self::R15 => write!(f, "R15"), + Self::PSW => write!(f, "PSW"), + Self::CBR => write!(f, "CBR"), + Self::SPI => write!(f, "SPI"), + Self::SPU => write!(f, "SPU"), + Self::SPO => write!(f, "SPO"), + Self::BPC => write!(f, "BPC"), + Self::ACHI => write!(f, "ACHI"), + Self::ACLO => write!(f, "ACLO"), + Self::PC => write!(f, "PC"), + } + } +} + +impl TryFrom for MitsubishiM32RRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::R0), + 11 => Ok(Self::R1), + 12 => Ok(Self::R2), + 13 => Ok(Self::R3), + 14 => Ok(Self::R4), + 15 => Ok(Self::R5), + 16 => Ok(Self::R6), + 17 => Ok(Self::R7), + 18 => Ok(Self::R8), + 19 => Ok(Self::R9), + 20 => Ok(Self::R10), + 21 => Ok(Self::R11), + 22 => Ok(Self::R12), + 23 => Ok(Self::R13), + 24 => Ok(Self::R14), + 25 => Ok(Self::R15), + 26 => Ok(Self::PSW), + 27 => Ok(Self::CBR), + 28 => Ok(Self::SPI), + 29 => Ok(Self::SPU), + 30 => Ok(Self::SPO), + 31 => Ok(Self::BPC), + 32 => Ok(Self::ACHI), + 33 => Ok(Self::ACLO), + 34 => Ok(Self::PC), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for MitsubishiM32RRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// Register set for the SuperH SHMedia processor including compact mode +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum SuperHSHMediaRegister { + // Integer - 64 bit general registers + R0 = 10, + R1 = 11, + R2 = 12, + R3 = 13, + R4 = 14, + R5 = 15, + R6 = 16, + R7 = 17, + R8 = 18, + R9 = 19, + R10 = 20, + R11 = 21, + R12 = 22, + R13 = 23, + R14 = 24, + R15 = 25, + R16 = 26, + R17 = 27, + R18 = 28, + R19 = 29, + R20 = 30, + R21 = 31, + R22 = 32, + R23 = 33, + R24 = 34, + R25 = 35, + R26 = 36, + R27 = 37, + R28 = 38, + R29 = 39, + R30 = 40, + R31 = 41, + R32 = 42, + R33 = 43, + R34 = 44, + R35 = 45, + R36 = 46, + R37 = 47, + R38 = 48, + R39 = 49, + R40 = 50, + R41 = 51, + R42 = 52, + R43 = 53, + R44 = 54, + R45 = 55, + R46 = 56, + R47 = 57, + R48 = 58, + R49 = 59, + R50 = 60, + R51 = 61, + R52 = 62, + R53 = 63, + R54 = 64, + R55 = 65, + R56 = 66, + R57 = 67, + R58 = 68, + R59 = 69, + R60 = 70, + R61 = 71, + R62 = 72, + R63 = 73, + + // Target Registers - 32 bit + TR0 = 74, + TR1 = 75, + TR2 = 76, + TR3 = 77, + TR4 = 78, + TR5 = 79, + TR6 = 80, + TR7 = 81, + TR8 = 82, // future-proof + TR9 = 83, // future-proof + TR10 = 84, // future-proof + TR11 = 85, // future-proof + TR12 = 86, // future-proof + TR13 = 87, // future-proof + TR14 = 88, // future-proof + TR15 = 89, // future-proof + + // Single - 32 bit fp registers + FR0 = 128, + FR1 = 129, + FR2 = 130, + FR3 = 131, + FR4 = 132, + FR5 = 133, + FR6 = 134, + FR7 = 135, + FR8 = 136, + FR9 = 137, + FR10 = 138, + FR11 = 139, + FR12 = 140, + FR13 = 141, + FR14 = 142, + FR15 = 143, + FR16 = 144, + FR17 = 145, + FR18 = 146, + FR19 = 147, + FR20 = 148, + FR21 = 149, + FR22 = 150, + FR23 = 151, + FR24 = 152, + FR25 = 153, + FR26 = 154, + FR27 = 155, + FR28 = 156, + FR29 = 157, + FR30 = 158, + FR31 = 159, + FR32 = 160, + FR33 = 161, + FR34 = 162, + FR35 = 163, + FR36 = 164, + FR37 = 165, + FR38 = 166, + FR39 = 167, + FR40 = 168, + FR41 = 169, + FR42 = 170, + FR43 = 171, + FR44 = 172, + FR45 = 173, + FR46 = 174, + FR47 = 175, + FR48 = 176, + FR49 = 177, + FR50 = 178, + FR51 = 179, + FR52 = 180, + FR53 = 181, + FR54 = 182, + FR55 = 183, + FR56 = 184, + FR57 = 185, + FR58 = 186, + FR59 = 187, + FR60 = 188, + FR61 = 189, + FR62 = 190, + FR63 = 191, + + // Double - 64 bit synonyms for 32bit fp register pairs + // subtract 128 to find first base single register + DR0 = 256, + DR2 = 258, + DR4 = 260, + DR6 = 262, + DR8 = 264, + DR10 = 266, + DR12 = 268, + DR14 = 270, + DR16 = 272, + DR18 = 274, + DR20 = 276, + DR22 = 278, + DR24 = 280, + DR26 = 282, + DR28 = 284, + DR30 = 286, + DR32 = 288, + DR34 = 290, + DR36 = 292, + DR38 = 294, + DR40 = 296, + DR42 = 298, + DR44 = 300, + DR46 = 302, + DR48 = 304, + DR50 = 306, + DR52 = 308, + DR54 = 310, + DR56 = 312, + DR58 = 314, + DR60 = 316, + DR62 = 318, + + // Vector - 128 bit synonyms for 32bit fp register quads + // subtract 384 to find first base single register + FV0 = 512, + FV4 = 516, + FV8 = 520, + FV12 = 524, + FV16 = 528, + FV20 = 532, + FV24 = 536, + FV28 = 540, + FV32 = 544, + FV36 = 548, + FV40 = 552, + FV44 = 556, + FV48 = 560, + FV52 = 564, + FV56 = 568, + FV60 = 572, + + // Matrix - 512 bit synonyms for 16 adjacent 32bit fp registers + // subtract 896 to find first base single register + MTRX0 = 1024, + MTRX16 = 1040, + MTRX32 = 1056, + MTRX48 = 1072, + + // Control - Implementation defined 64bit control registers + CR0 = 2000, + CR1 = 2001, + CR2 = 2002, + CR3 = 2003, + CR4 = 2004, + CR5 = 2005, + CR6 = 2006, + CR7 = 2007, + CR8 = 2008, + CR9 = 2009, + CR10 = 2010, + CR11 = 2011, + CR12 = 2012, + CR13 = 2013, + CR14 = 2014, + CR15 = 2015, + CR16 = 2016, + CR17 = 2017, + CR18 = 2018, + CR19 = 2019, + CR20 = 2020, + CR21 = 2021, + CR22 = 2022, + CR23 = 2023, + CR24 = 2024, + CR25 = 2025, + CR26 = 2026, + CR27 = 2027, + CR28 = 2028, + CR29 = 2029, + CR30 = 2030, + CR31 = 2031, + CR32 = 2032, + CR33 = 2033, + CR34 = 2034, + CR35 = 2035, + CR36 = 2036, + CR37 = 2037, + CR38 = 2038, + CR39 = 2039, + CR40 = 2040, + CR41 = 2041, + CR42 = 2042, + CR43 = 2043, + CR44 = 2044, + CR45 = 2045, + CR46 = 2046, + CR47 = 2047, + CR48 = 2048, + CR49 = 2049, + CR50 = 2050, + CR51 = 2051, + CR52 = 2052, + CR53 = 2053, + CR54 = 2054, + CR55 = 2055, + CR56 = 2056, + CR57 = 2057, + CR58 = 2058, + CR59 = 2059, + CR60 = 2060, + CR61 = 2061, + CR62 = 2062, + CR63 = 2063, + + FPSCR = 2064, + // Compact mode synonyms + // GBR = 26, + // MACL = 90, // synonym for lower 32bits of media R17 + // MACH = 91, // synonym for upper 32bits of media R17 + // PR = 28, + // T = 92, // synonym for lowest bit of media R19 + // FPUL = 160, + // PC = 93, + // SR = 2000, +} + +impl fmt::Display for SuperHSHMediaRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::R0 => write!(f, "R0"), + Self::R1 => write!(f, "R1"), + Self::R2 => write!(f, "R2"), + Self::R3 => write!(f, "R3"), + Self::R4 => write!(f, "R4"), + Self::R5 => write!(f, "R5"), + Self::R6 => write!(f, "R6"), + Self::R7 => write!(f, "R7"), + Self::R8 => write!(f, "R8"), + Self::R9 => write!(f, "R9"), + Self::R10 => write!(f, "R10"), + Self::R11 => write!(f, "R11"), + Self::R12 => write!(f, "R12"), + Self::R13 => write!(f, "R13"), + Self::R14 => write!(f, "R14"), + Self::R15 => write!(f, "R15"), + Self::R16 => write!(f, "R16"), + Self::R17 => write!(f, "R17"), + Self::R18 => write!(f, "R18"), + Self::R19 => write!(f, "R19"), + Self::R20 => write!(f, "R20"), + Self::R21 => write!(f, "R21"), + Self::R22 => write!(f, "R22"), + Self::R23 => write!(f, "R23"), + Self::R24 => write!(f, "R24"), + Self::R25 => write!(f, "R25"), + Self::R26 => write!(f, "R26"), + Self::R27 => write!(f, "R27"), + Self::R28 => write!(f, "R28"), + Self::R29 => write!(f, "R29"), + Self::R30 => write!(f, "R30"), + Self::R31 => write!(f, "R31"), + Self::R32 => write!(f, "R32"), + Self::R33 => write!(f, "R33"), + Self::R34 => write!(f, "R34"), + Self::R35 => write!(f, "R35"), + Self::R36 => write!(f, "R36"), + Self::R37 => write!(f, "R37"), + Self::R38 => write!(f, "R38"), + Self::R39 => write!(f, "R39"), + Self::R40 => write!(f, "R40"), + Self::R41 => write!(f, "R41"), + Self::R42 => write!(f, "R42"), + Self::R43 => write!(f, "R43"), + Self::R44 => write!(f, "R44"), + Self::R45 => write!(f, "R45"), + Self::R46 => write!(f, "R46"), + Self::R47 => write!(f, "R47"), + Self::R48 => write!(f, "R48"), + Self::R49 => write!(f, "R49"), + Self::R50 => write!(f, "R50"), + Self::R51 => write!(f, "R51"), + Self::R52 => write!(f, "R52"), + Self::R53 => write!(f, "R53"), + Self::R54 => write!(f, "R54"), + Self::R55 => write!(f, "R55"), + Self::R56 => write!(f, "R56"), + Self::R57 => write!(f, "R57"), + Self::R58 => write!(f, "R58"), + Self::R59 => write!(f, "R59"), + Self::R60 => write!(f, "R60"), + Self::R61 => write!(f, "R61"), + Self::R62 => write!(f, "R62"), + Self::R63 => write!(f, "R63"), + Self::TR0 => write!(f, "TR0"), + Self::TR1 => write!(f, "TR1"), + Self::TR2 => write!(f, "TR2"), + Self::TR3 => write!(f, "TR3"), + Self::TR4 => write!(f, "TR4"), + Self::TR5 => write!(f, "TR5"), + Self::TR6 => write!(f, "TR6"), + Self::TR7 => write!(f, "TR7"), + Self::TR8 => write!(f, "TR8"), + Self::TR9 => write!(f, "TR9"), + Self::TR10 => write!(f, "TR10"), + Self::TR11 => write!(f, "TR11"), + Self::TR12 => write!(f, "TR12"), + Self::TR13 => write!(f, "TR13"), + Self::TR14 => write!(f, "TR14"), + Self::TR15 => write!(f, "TR15"), + Self::FR0 => write!(f, "FR0"), + Self::FR1 => write!(f, "FR1"), + Self::FR2 => write!(f, "FR2"), + Self::FR3 => write!(f, "FR3"), + Self::FR4 => write!(f, "FR4"), + Self::FR5 => write!(f, "FR5"), + Self::FR6 => write!(f, "FR6"), + Self::FR7 => write!(f, "FR7"), + Self::FR8 => write!(f, "FR8"), + Self::FR9 => write!(f, "FR9"), + Self::FR10 => write!(f, "FR10"), + Self::FR11 => write!(f, "FR11"), + Self::FR12 => write!(f, "FR12"), + Self::FR13 => write!(f, "FR13"), + Self::FR14 => write!(f, "FR14"), + Self::FR15 => write!(f, "FR15"), + Self::FR16 => write!(f, "FR16"), + Self::FR17 => write!(f, "FR17"), + Self::FR18 => write!(f, "FR18"), + Self::FR19 => write!(f, "FR19"), + Self::FR20 => write!(f, "FR20"), + Self::FR21 => write!(f, "FR21"), + Self::FR22 => write!(f, "FR22"), + Self::FR23 => write!(f, "FR23"), + Self::FR24 => write!(f, "FR24"), + Self::FR25 => write!(f, "FR25"), + Self::FR26 => write!(f, "FR26"), + Self::FR27 => write!(f, "FR27"), + Self::FR28 => write!(f, "FR28"), + Self::FR29 => write!(f, "FR29"), + Self::FR30 => write!(f, "FR30"), + Self::FR31 => write!(f, "FR31"), + Self::FR32 => write!(f, "FR32"), + Self::FR33 => write!(f, "FR33"), + Self::FR34 => write!(f, "FR34"), + Self::FR35 => write!(f, "FR35"), + Self::FR36 => write!(f, "FR36"), + Self::FR37 => write!(f, "FR37"), + Self::FR38 => write!(f, "FR38"), + Self::FR39 => write!(f, "FR39"), + Self::FR40 => write!(f, "FR40"), + Self::FR41 => write!(f, "FR41"), + Self::FR42 => write!(f, "FR42"), + Self::FR43 => write!(f, "FR43"), + Self::FR44 => write!(f, "FR44"), + Self::FR45 => write!(f, "FR45"), + Self::FR46 => write!(f, "FR46"), + Self::FR47 => write!(f, "FR47"), + Self::FR48 => write!(f, "FR48"), + Self::FR49 => write!(f, "FR49"), + Self::FR50 => write!(f, "FR50"), + Self::FR51 => write!(f, "FR51"), + Self::FR52 => write!(f, "FR52"), + Self::FR53 => write!(f, "FR53"), + Self::FR54 => write!(f, "FR54"), + Self::FR55 => write!(f, "FR55"), + Self::FR56 => write!(f, "FR56"), + Self::FR57 => write!(f, "FR57"), + Self::FR58 => write!(f, "FR58"), + Self::FR59 => write!(f, "FR59"), + Self::FR60 => write!(f, "FR60"), + Self::FR61 => write!(f, "FR61"), + Self::FR62 => write!(f, "FR62"), + Self::FR63 => write!(f, "FR63"), + Self::DR0 => write!(f, "DR0"), + Self::DR2 => write!(f, "DR2"), + Self::DR4 => write!(f, "DR4"), + Self::DR6 => write!(f, "DR6"), + Self::DR8 => write!(f, "DR8"), + Self::DR10 => write!(f, "DR10"), + Self::DR12 => write!(f, "DR12"), + Self::DR14 => write!(f, "DR14"), + Self::DR16 => write!(f, "DR16"), + Self::DR18 => write!(f, "DR18"), + Self::DR20 => write!(f, "DR20"), + Self::DR22 => write!(f, "DR22"), + Self::DR24 => write!(f, "DR24"), + Self::DR26 => write!(f, "DR26"), + Self::DR28 => write!(f, "DR28"), + Self::DR30 => write!(f, "DR30"), + Self::DR32 => write!(f, "DR32"), + Self::DR34 => write!(f, "DR34"), + Self::DR36 => write!(f, "DR36"), + Self::DR38 => write!(f, "DR38"), + Self::DR40 => write!(f, "DR40"), + Self::DR42 => write!(f, "DR42"), + Self::DR44 => write!(f, "DR44"), + Self::DR46 => write!(f, "DR46"), + Self::DR48 => write!(f, "DR48"), + Self::DR50 => write!(f, "DR50"), + Self::DR52 => write!(f, "DR52"), + Self::DR54 => write!(f, "DR54"), + Self::DR56 => write!(f, "DR56"), + Self::DR58 => write!(f, "DR58"), + Self::DR60 => write!(f, "DR60"), + Self::DR62 => write!(f, "DR62"), + Self::FV0 => write!(f, "FV0"), + Self::FV4 => write!(f, "FV4"), + Self::FV8 => write!(f, "FV8"), + Self::FV12 => write!(f, "FV12"), + Self::FV16 => write!(f, "FV16"), + Self::FV20 => write!(f, "FV20"), + Self::FV24 => write!(f, "FV24"), + Self::FV28 => write!(f, "FV28"), + Self::FV32 => write!(f, "FV32"), + Self::FV36 => write!(f, "FV36"), + Self::FV40 => write!(f, "FV40"), + Self::FV44 => write!(f, "FV44"), + Self::FV48 => write!(f, "FV48"), + Self::FV52 => write!(f, "FV52"), + Self::FV56 => write!(f, "FV56"), + Self::FV60 => write!(f, "FV60"), + Self::MTRX0 => write!(f, "MTRX0"), + Self::MTRX16 => write!(f, "MTRX16"), + Self::MTRX32 => write!(f, "MTRX32"), + Self::MTRX48 => write!(f, "MTRX48"), + Self::CR0 => write!(f, "CR0"), + Self::CR1 => write!(f, "CR1"), + Self::CR2 => write!(f, "CR2"), + Self::CR3 => write!(f, "CR3"), + Self::CR4 => write!(f, "CR4"), + Self::CR5 => write!(f, "CR5"), + Self::CR6 => write!(f, "CR6"), + Self::CR7 => write!(f, "CR7"), + Self::CR8 => write!(f, "CR8"), + Self::CR9 => write!(f, "CR9"), + Self::CR10 => write!(f, "CR10"), + Self::CR11 => write!(f, "CR11"), + Self::CR12 => write!(f, "CR12"), + Self::CR13 => write!(f, "CR13"), + Self::CR14 => write!(f, "CR14"), + Self::CR15 => write!(f, "CR15"), + Self::CR16 => write!(f, "CR16"), + Self::CR17 => write!(f, "CR17"), + Self::CR18 => write!(f, "CR18"), + Self::CR19 => write!(f, "CR19"), + Self::CR20 => write!(f, "CR20"), + Self::CR21 => write!(f, "CR21"), + Self::CR22 => write!(f, "CR22"), + Self::CR23 => write!(f, "CR23"), + Self::CR24 => write!(f, "CR24"), + Self::CR25 => write!(f, "CR25"), + Self::CR26 => write!(f, "CR26"), + Self::CR27 => write!(f, "CR27"), + Self::CR28 => write!(f, "CR28"), + Self::CR29 => write!(f, "CR29"), + Self::CR30 => write!(f, "CR30"), + Self::CR31 => write!(f, "CR31"), + Self::CR32 => write!(f, "CR32"), + Self::CR33 => write!(f, "CR33"), + Self::CR34 => write!(f, "CR34"), + Self::CR35 => write!(f, "CR35"), + Self::CR36 => write!(f, "CR36"), + Self::CR37 => write!(f, "CR37"), + Self::CR38 => write!(f, "CR38"), + Self::CR39 => write!(f, "CR39"), + Self::CR40 => write!(f, "CR40"), + Self::CR41 => write!(f, "CR41"), + Self::CR42 => write!(f, "CR42"), + Self::CR43 => write!(f, "CR43"), + Self::CR44 => write!(f, "CR44"), + Self::CR45 => write!(f, "CR45"), + Self::CR46 => write!(f, "CR46"), + Self::CR47 => write!(f, "CR47"), + Self::CR48 => write!(f, "CR48"), + Self::CR49 => write!(f, "CR49"), + Self::CR50 => write!(f, "CR50"), + Self::CR51 => write!(f, "CR51"), + Self::CR52 => write!(f, "CR52"), + Self::CR53 => write!(f, "CR53"), + Self::CR54 => write!(f, "CR54"), + Self::CR55 => write!(f, "CR55"), + Self::CR56 => write!(f, "CR56"), + Self::CR57 => write!(f, "CR57"), + Self::CR58 => write!(f, "CR58"), + Self::CR59 => write!(f, "CR59"), + Self::CR60 => write!(f, "CR60"), + Self::CR61 => write!(f, "CR61"), + Self::CR62 => write!(f, "CR62"), + Self::CR63 => write!(f, "CR63"), + Self::FPSCR => write!(f, "FPSCR"), + } + } +} + +impl TryFrom for SuperHSHMediaRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 10 => Ok(Self::R0), + 11 => Ok(Self::R1), + 12 => Ok(Self::R2), + 13 => Ok(Self::R3), + 14 => Ok(Self::R4), + 15 => Ok(Self::R5), + 16 => Ok(Self::R6), + 17 => Ok(Self::R7), + 18 => Ok(Self::R8), + 19 => Ok(Self::R9), + 20 => Ok(Self::R10), + 21 => Ok(Self::R11), + 22 => Ok(Self::R12), + 23 => Ok(Self::R13), + 24 => Ok(Self::R14), + 25 => Ok(Self::R15), + 26 => Ok(Self::R16), + 27 => Ok(Self::R17), + 28 => Ok(Self::R18), + 29 => Ok(Self::R19), + 30 => Ok(Self::R20), + 31 => Ok(Self::R21), + 32 => Ok(Self::R22), + 33 => Ok(Self::R23), + 34 => Ok(Self::R24), + 35 => Ok(Self::R25), + 36 => Ok(Self::R26), + 37 => Ok(Self::R27), + 38 => Ok(Self::R28), + 39 => Ok(Self::R29), + 40 => Ok(Self::R30), + 41 => Ok(Self::R31), + 42 => Ok(Self::R32), + 43 => Ok(Self::R33), + 44 => Ok(Self::R34), + 45 => Ok(Self::R35), + 46 => Ok(Self::R36), + 47 => Ok(Self::R37), + 48 => Ok(Self::R38), + 49 => Ok(Self::R39), + 50 => Ok(Self::R40), + 51 => Ok(Self::R41), + 52 => Ok(Self::R42), + 53 => Ok(Self::R43), + 54 => Ok(Self::R44), + 55 => Ok(Self::R45), + 56 => Ok(Self::R46), + 57 => Ok(Self::R47), + 58 => Ok(Self::R48), + 59 => Ok(Self::R49), + 60 => Ok(Self::R50), + 61 => Ok(Self::R51), + 62 => Ok(Self::R52), + 63 => Ok(Self::R53), + 64 => Ok(Self::R54), + 65 => Ok(Self::R55), + 66 => Ok(Self::R56), + 67 => Ok(Self::R57), + 68 => Ok(Self::R58), + 69 => Ok(Self::R59), + 70 => Ok(Self::R60), + 71 => Ok(Self::R61), + 72 => Ok(Self::R62), + 73 => Ok(Self::R63), + 74 => Ok(Self::TR0), + 75 => Ok(Self::TR1), + 76 => Ok(Self::TR2), + 77 => Ok(Self::TR3), + 78 => Ok(Self::TR4), + 79 => Ok(Self::TR5), + 80 => Ok(Self::TR6), + 81 => Ok(Self::TR7), + 82 => Ok(Self::TR8), + 83 => Ok(Self::TR9), + 84 => Ok(Self::TR10), + 85 => Ok(Self::TR11), + 86 => Ok(Self::TR12), + 87 => Ok(Self::TR13), + 88 => Ok(Self::TR14), + 89 => Ok(Self::TR15), + 128 => Ok(Self::FR0), + 129 => Ok(Self::FR1), + 130 => Ok(Self::FR2), + 131 => Ok(Self::FR3), + 132 => Ok(Self::FR4), + 133 => Ok(Self::FR5), + 134 => Ok(Self::FR6), + 135 => Ok(Self::FR7), + 136 => Ok(Self::FR8), + 137 => Ok(Self::FR9), + 138 => Ok(Self::FR10), + 139 => Ok(Self::FR11), + 140 => Ok(Self::FR12), + 141 => Ok(Self::FR13), + 142 => Ok(Self::FR14), + 143 => Ok(Self::FR15), + 144 => Ok(Self::FR16), + 145 => Ok(Self::FR17), + 146 => Ok(Self::FR18), + 147 => Ok(Self::FR19), + 148 => Ok(Self::FR20), + 149 => Ok(Self::FR21), + 150 => Ok(Self::FR22), + 151 => Ok(Self::FR23), + 152 => Ok(Self::FR24), + 153 => Ok(Self::FR25), + 154 => Ok(Self::FR26), + 155 => Ok(Self::FR27), + 156 => Ok(Self::FR28), + 157 => Ok(Self::FR29), + 158 => Ok(Self::FR30), + 159 => Ok(Self::FR31), + 160 => Ok(Self::FR32), + 161 => Ok(Self::FR33), + 162 => Ok(Self::FR34), + 163 => Ok(Self::FR35), + 164 => Ok(Self::FR36), + 165 => Ok(Self::FR37), + 166 => Ok(Self::FR38), + 167 => Ok(Self::FR39), + 168 => Ok(Self::FR40), + 169 => Ok(Self::FR41), + 170 => Ok(Self::FR42), + 171 => Ok(Self::FR43), + 172 => Ok(Self::FR44), + 173 => Ok(Self::FR45), + 174 => Ok(Self::FR46), + 175 => Ok(Self::FR47), + 176 => Ok(Self::FR48), + 177 => Ok(Self::FR49), + 178 => Ok(Self::FR50), + 179 => Ok(Self::FR51), + 180 => Ok(Self::FR52), + 181 => Ok(Self::FR53), + 182 => Ok(Self::FR54), + 183 => Ok(Self::FR55), + 184 => Ok(Self::FR56), + 185 => Ok(Self::FR57), + 186 => Ok(Self::FR58), + 187 => Ok(Self::FR59), + 188 => Ok(Self::FR60), + 189 => Ok(Self::FR61), + 190 => Ok(Self::FR62), + 191 => Ok(Self::FR63), + 256 => Ok(Self::DR0), + 258 => Ok(Self::DR2), + 260 => Ok(Self::DR4), + 262 => Ok(Self::DR6), + 264 => Ok(Self::DR8), + 266 => Ok(Self::DR10), + 268 => Ok(Self::DR12), + 270 => Ok(Self::DR14), + 272 => Ok(Self::DR16), + 274 => Ok(Self::DR18), + 276 => Ok(Self::DR20), + 278 => Ok(Self::DR22), + 280 => Ok(Self::DR24), + 282 => Ok(Self::DR26), + 284 => Ok(Self::DR28), + 286 => Ok(Self::DR30), + 288 => Ok(Self::DR32), + 290 => Ok(Self::DR34), + 292 => Ok(Self::DR36), + 294 => Ok(Self::DR38), + 296 => Ok(Self::DR40), + 298 => Ok(Self::DR42), + 300 => Ok(Self::DR44), + 302 => Ok(Self::DR46), + 304 => Ok(Self::DR48), + 306 => Ok(Self::DR50), + 308 => Ok(Self::DR52), + 310 => Ok(Self::DR54), + 312 => Ok(Self::DR56), + 314 => Ok(Self::DR58), + 316 => Ok(Self::DR60), + 318 => Ok(Self::DR62), + 512 => Ok(Self::FV0), + 516 => Ok(Self::FV4), + 520 => Ok(Self::FV8), + 524 => Ok(Self::FV12), + 528 => Ok(Self::FV16), + 532 => Ok(Self::FV20), + 536 => Ok(Self::FV24), + 540 => Ok(Self::FV28), + 544 => Ok(Self::FV32), + 548 => Ok(Self::FV36), + 552 => Ok(Self::FV40), + 556 => Ok(Self::FV44), + 560 => Ok(Self::FV48), + 564 => Ok(Self::FV52), + 568 => Ok(Self::FV56), + 572 => Ok(Self::FV60), + 1024 => Ok(Self::MTRX0), + 1040 => Ok(Self::MTRX16), + 1056 => Ok(Self::MTRX32), + 1072 => Ok(Self::MTRX48), + 2000 => Ok(Self::CR0), + 2001 => Ok(Self::CR1), + 2002 => Ok(Self::CR2), + 2003 => Ok(Self::CR3), + 2004 => Ok(Self::CR4), + 2005 => Ok(Self::CR5), + 2006 => Ok(Self::CR6), + 2007 => Ok(Self::CR7), + 2008 => Ok(Self::CR8), + 2009 => Ok(Self::CR9), + 2010 => Ok(Self::CR10), + 2011 => Ok(Self::CR11), + 2012 => Ok(Self::CR12), + 2013 => Ok(Self::CR13), + 2014 => Ok(Self::CR14), + 2015 => Ok(Self::CR15), + 2016 => Ok(Self::CR16), + 2017 => Ok(Self::CR17), + 2018 => Ok(Self::CR18), + 2019 => Ok(Self::CR19), + 2020 => Ok(Self::CR20), + 2021 => Ok(Self::CR21), + 2022 => Ok(Self::CR22), + 2023 => Ok(Self::CR23), + 2024 => Ok(Self::CR24), + 2025 => Ok(Self::CR25), + 2026 => Ok(Self::CR26), + 2027 => Ok(Self::CR27), + 2028 => Ok(Self::CR28), + 2029 => Ok(Self::CR29), + 2030 => Ok(Self::CR30), + 2031 => Ok(Self::CR31), + 2032 => Ok(Self::CR32), + 2033 => Ok(Self::CR33), + 2034 => Ok(Self::CR34), + 2035 => Ok(Self::CR35), + 2036 => Ok(Self::CR36), + 2037 => Ok(Self::CR37), + 2038 => Ok(Self::CR38), + 2039 => Ok(Self::CR39), + 2040 => Ok(Self::CR40), + 2041 => Ok(Self::CR41), + 2042 => Ok(Self::CR42), + 2043 => Ok(Self::CR43), + 2044 => Ok(Self::CR44), + 2045 => Ok(Self::CR45), + 2046 => Ok(Self::CR46), + 2047 => Ok(Self::CR47), + 2048 => Ok(Self::CR48), + 2049 => Ok(Self::CR49), + 2050 => Ok(Self::CR50), + 2051 => Ok(Self::CR51), + 2052 => Ok(Self::CR52), + 2053 => Ok(Self::CR53), + 2054 => Ok(Self::CR54), + 2055 => Ok(Self::CR55), + 2056 => Ok(Self::CR56), + 2057 => Ok(Self::CR57), + 2058 => Ok(Self::CR58), + 2059 => Ok(Self::CR59), + 2060 => Ok(Self::CR60), + 2061 => Ok(Self::CR61), + 2062 => Ok(Self::CR62), + 2063 => Ok(Self::CR63), + 2064 => Ok(Self::FPSCR), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for SuperHSHMediaRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// AMD64 registers +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum AMD64Register { + AL = 1, + CL = 2, + DL = 3, + BL = 4, + AH = 5, + CH = 6, + DH = 7, + BH = 8, + AX = 9, + CX = 10, + DX = 11, + BX = 12, + SP = 13, + BP = 14, + SI = 15, + DI = 16, + EAX = 17, + ECX = 18, + EDX = 19, + EBX = 20, + ESP = 21, + EBP = 22, + ESI = 23, + EDI = 24, + ES = 25, + CS = 26, + SS = 27, + DS = 28, + FS = 29, + GS = 30, + FLAGS = 32, + RIP = 33, + EFLAGS = 34, + + // Control registers + CR0 = 80, + CR1 = 81, + CR2 = 82, + CR3 = 83, + CR4 = 84, + CR8 = 88, + + // Debug registers + DR0 = 90, + DR1 = 91, + DR2 = 92, + DR3 = 93, + DR4 = 94, + DR5 = 95, + DR6 = 96, + DR7 = 97, + DR8 = 98, + DR9 = 99, + DR10 = 100, + DR11 = 101, + DR12 = 102, + DR13 = 103, + DR14 = 104, + DR15 = 105, + + GDTR = 110, + GDTL = 111, + IDTR = 112, + IDTL = 113, + LDTR = 114, + TR = 115, + + ST0 = 128, + ST1 = 129, + ST2 = 130, + ST3 = 131, + ST4 = 132, + ST5 = 133, + ST6 = 134, + ST7 = 135, + CTRL = 136, + STAT = 137, + TAG = 138, + FPIP = 139, + FPCS = 140, + FPDO = 141, + FPDS = 142, + ISEM = 143, + FPEIP = 144, + FPEDO = 145, + + MM0 = 146, + MM1 = 147, + MM2 = 148, + MM3 = 149, + MM4 = 150, + MM5 = 151, + MM6 = 152, + MM7 = 153, + + XMM0 = 154, // KATMAI registers + XMM1 = 155, + XMM2 = 156, + XMM3 = 157, + XMM4 = 158, + XMM5 = 159, + XMM6 = 160, + XMM7 = 161, + + XMM0_0 = 162, // KATMAI sub-registers + XMM0_1 = 163, + XMM0_2 = 164, + XMM0_3 = 165, + XMM1_0 = 166, + XMM1_1 = 167, + XMM1_2 = 168, + XMM1_3 = 169, + XMM2_0 = 170, + XMM2_1 = 171, + XMM2_2 = 172, + XMM2_3 = 173, + XMM3_0 = 174, + XMM3_1 = 175, + XMM3_2 = 176, + XMM3_3 = 177, + XMM4_0 = 178, + XMM4_1 = 179, + XMM4_2 = 180, + XMM4_3 = 181, + XMM5_0 = 182, + XMM5_1 = 183, + XMM5_2 = 184, + XMM5_3 = 185, + XMM6_0 = 186, + XMM6_1 = 187, + XMM6_2 = 188, + XMM6_3 = 189, + XMM7_0 = 190, + XMM7_1 = 191, + XMM7_2 = 192, + XMM7_3 = 193, + + XMM0L = 194, + XMM1L = 195, + XMM2L = 196, + XMM3L = 197, + XMM4L = 198, + XMM5L = 199, + XMM6L = 200, + XMM7L = 201, + + XMM0H = 202, + XMM1H = 203, + XMM2H = 204, + XMM3H = 205, + XMM4H = 206, + XMM5H = 207, + XMM6H = 208, + XMM7H = 209, + + MXCSR = 211, // XMM status register + + EMM0L = 220, // XMM sub-registers (WNI integer) + EMM1L = 221, + EMM2L = 222, + EMM3L = 223, + EMM4L = 224, + EMM5L = 225, + EMM6L = 226, + EMM7L = 227, + + EMM0H = 228, + EMM1H = 229, + EMM2H = 230, + EMM3H = 231, + EMM4H = 232, + EMM5H = 233, + EMM6H = 234, + EMM7H = 235, + + // do not change the order of these regs, first one must be even too + MM00 = 236, + MM01 = 237, + MM10 = 238, + MM11 = 239, + MM20 = 240, + MM21 = 241, + MM30 = 242, + MM31 = 243, + MM40 = 244, + MM41 = 245, + MM50 = 246, + MM51 = 247, + MM60 = 248, + MM61 = 249, + MM70 = 250, + MM71 = 251, + + // Extended KATMAI registers + XMM8 = 252, // KATMAI registers + XMM9 = 253, + XMM10 = 254, + XMM11 = 255, + XMM12 = 256, + XMM13 = 257, + XMM14 = 258, + XMM15 = 259, + + XMM8_0 = 260, // KATMAI sub-registers + XMM8_1 = 261, + XMM8_2 = 262, + XMM8_3 = 263, + XMM9_0 = 264, + XMM9_1 = 265, + XMM9_2 = 266, + XMM9_3 = 267, + XMM10_0 = 268, + XMM10_1 = 269, + XMM10_2 = 270, + XMM10_3 = 271, + XMM11_0 = 272, + XMM11_1 = 273, + XMM11_2 = 274, + XMM11_3 = 275, + XMM12_0 = 276, + XMM12_1 = 277, + XMM12_2 = 278, + XMM12_3 = 279, + XMM13_0 = 280, + XMM13_1 = 281, + XMM13_2 = 282, + XMM13_3 = 283, + XMM14_0 = 284, + XMM14_1 = 285, + XMM14_2 = 286, + XMM14_3 = 287, + XMM15_0 = 288, + XMM15_1 = 289, + XMM15_2 = 290, + XMM15_3 = 291, + + XMM8L = 292, + XMM9L = 293, + XMM10L = 294, + XMM11L = 295, + XMM12L = 296, + XMM13L = 297, + XMM14L = 298, + XMM15L = 299, + + XMM8H = 300, + XMM9H = 301, + XMM10H = 302, + XMM11H = 303, + XMM12H = 304, + XMM13H = 305, + XMM14H = 306, + XMM15H = 307, + + EMM8L = 308, // XMM sub-registers (WNI integer) + EMM9L = 309, + EMM10L = 310, + EMM11L = 311, + EMM12L = 312, + EMM13L = 313, + EMM14L = 314, + EMM15L = 315, + + EMM8H = 316, + EMM9H = 317, + EMM10H = 318, + EMM11H = 319, + EMM12H = 320, + EMM13H = 321, + EMM14H = 322, + EMM15H = 323, + + // Low byte forms of some standard registers + SIL = 324, + DIL = 325, + BPL = 326, + SPL = 327, + + // 64-bit regular registers + RAX = 328, + RBX = 329, + RCX = 330, + RDX = 331, + RSI = 332, + RDI = 333, + RBP = 334, + RSP = 335, + + // 64-bit integer registers with 8-, 16-, and 32-bit forms (B, W, and D) + R8 = 336, + R9 = 337, + R10 = 338, + R11 = 339, + R12 = 340, + R13 = 341, + R14 = 342, + R15 = 343, + + R8B = 344, + R9B = 345, + R10B = 346, + R11B = 347, + R12B = 348, + R13B = 349, + R14B = 350, + R15B = 351, + + R8W = 352, + R9W = 353, + R10W = 354, + R11W = 355, + R12W = 356, + R13W = 357, + R14W = 358, + R15W = 359, + + R8D = 360, + R9D = 361, + R10D = 362, + R11D = 363, + R12D = 364, + R13D = 365, + R14D = 366, + R15D = 367, + + // AVX registers 256 bits + YMM0 = 368, + YMM1 = 369, + YMM2 = 370, + YMM3 = 371, + YMM4 = 372, + YMM5 = 373, + YMM6 = 374, + YMM7 = 375, + YMM8 = 376, + YMM9 = 377, + YMM10 = 378, + YMM11 = 379, + YMM12 = 380, + YMM13 = 381, + YMM14 = 382, + YMM15 = 383, + + // AVX registers upper 128 bits + YMM0H = 384, + YMM1H = 385, + YMM2H = 386, + YMM3H = 387, + YMM4H = 388, + YMM5H = 389, + YMM6H = 390, + YMM7H = 391, + YMM8H = 392, + YMM9H = 393, + YMM10H = 394, + YMM11H = 395, + YMM12H = 396, + YMM13H = 397, + YMM14H = 398, + YMM15H = 399, + + //Lower/upper 8 bytes of XMM registers. Unlike XMM, these + //values reprsesent the bit patterns of the registers as 64-bit integers, not + //the representation of these registers as a double. + XMM0IL = 400, + XMM1IL = 401, + XMM2IL = 402, + XMM3IL = 403, + XMM4IL = 404, + XMM5IL = 405, + XMM6IL = 406, + XMM7IL = 407, + XMM8IL = 408, + XMM9IL = 409, + XMM10IL = 410, + XMM11IL = 411, + XMM12IL = 412, + XMM13IL = 413, + XMM14IL = 414, + XMM15IL = 415, + + XMM0IH = 416, + XMM1IH = 417, + XMM2IH = 418, + XMM3IH = 419, + XMM4IH = 420, + XMM5IH = 421, + XMM6IH = 422, + XMM7IH = 423, + XMM8IH = 424, + XMM9IH = 425, + XMM10IH = 426, + XMM11IH = 427, + XMM12IH = 428, + XMM13IH = 429, + XMM14IH = 430, + XMM15IH = 431, + + YMM0I0 = 432, // AVX integer registers + YMM0I1 = 433, + YMM0I2 = 434, + YMM0I3 = 435, + YMM1I0 = 436, + YMM1I1 = 437, + YMM1I2 = 438, + YMM1I3 = 439, + YMM2I0 = 440, + YMM2I1 = 441, + YMM2I2 = 442, + YMM2I3 = 443, + YMM3I0 = 444, + YMM3I1 = 445, + YMM3I2 = 446, + YMM3I3 = 447, + YMM4I0 = 448, + YMM4I1 = 449, + YMM4I2 = 450, + YMM4I3 = 451, + YMM5I0 = 452, + YMM5I1 = 453, + YMM5I2 = 454, + YMM5I3 = 455, + YMM6I0 = 456, + YMM6I1 = 457, + YMM6I2 = 458, + YMM6I3 = 459, + YMM7I0 = 460, + YMM7I1 = 461, + YMM7I2 = 462, + YMM7I3 = 463, + YMM8I0 = 464, + YMM8I1 = 465, + YMM8I2 = 466, + YMM8I3 = 467, + YMM9I0 = 468, + YMM9I1 = 469, + YMM9I2 = 470, + YMM9I3 = 471, + YMM10I0 = 472, + YMM10I1 = 473, + YMM10I2 = 474, + YMM10I3 = 475, + YMM11I0 = 476, + YMM11I1 = 477, + YMM11I2 = 478, + YMM11I3 = 479, + YMM12I0 = 480, + YMM12I1 = 481, + YMM12I2 = 482, + YMM12I3 = 483, + YMM13I0 = 484, + YMM13I1 = 485, + YMM13I2 = 486, + YMM13I3 = 487, + YMM14I0 = 488, + YMM14I1 = 489, + YMM14I2 = 490, + YMM14I3 = 491, + YMM15I0 = 492, + YMM15I1 = 493, + YMM15I2 = 494, + YMM15I3 = 495, + + YMM0F0 = 496, // AVX floating-point single precise registers + YMM0F1 = 497, + YMM0F2 = 498, + YMM0F3 = 499, + YMM0F4 = 500, + YMM0F5 = 501, + YMM0F6 = 502, + YMM0F7 = 503, + YMM1F0 = 504, + YMM1F1 = 505, + YMM1F2 = 506, + YMM1F3 = 507, + YMM1F4 = 508, + YMM1F5 = 509, + YMM1F6 = 510, + YMM1F7 = 511, + YMM2F0 = 512, + YMM2F1 = 513, + YMM2F2 = 514, + YMM2F3 = 515, + YMM2F4 = 516, + YMM2F5 = 517, + YMM2F6 = 518, + YMM2F7 = 519, + YMM3F0 = 520, + YMM3F1 = 521, + YMM3F2 = 522, + YMM3F3 = 523, + YMM3F4 = 524, + YMM3F5 = 525, + YMM3F6 = 526, + YMM3F7 = 527, + YMM4F0 = 528, + YMM4F1 = 529, + YMM4F2 = 530, + YMM4F3 = 531, + YMM4F4 = 532, + YMM4F5 = 533, + YMM4F6 = 534, + YMM4F7 = 535, + YMM5F0 = 536, + YMM5F1 = 537, + YMM5F2 = 538, + YMM5F3 = 539, + YMM5F4 = 540, + YMM5F5 = 541, + YMM5F6 = 542, + YMM5F7 = 543, + YMM6F0 = 544, + YMM6F1 = 545, + YMM6F2 = 546, + YMM6F3 = 547, + YMM6F4 = 548, + YMM6F5 = 549, + YMM6F6 = 550, + YMM6F7 = 551, + YMM7F0 = 552, + YMM7F1 = 553, + YMM7F2 = 554, + YMM7F3 = 555, + YMM7F4 = 556, + YMM7F5 = 557, + YMM7F6 = 558, + YMM7F7 = 559, + YMM8F0 = 560, + YMM8F1 = 561, + YMM8F2 = 562, + YMM8F3 = 563, + YMM8F4 = 564, + YMM8F5 = 565, + YMM8F6 = 566, + YMM8F7 = 567, + YMM9F0 = 568, + YMM9F1 = 569, + YMM9F2 = 570, + YMM9F3 = 571, + YMM9F4 = 572, + YMM9F5 = 573, + YMM9F6 = 574, + YMM9F7 = 575, + YMM10F0 = 576, + YMM10F1 = 577, + YMM10F2 = 578, + YMM10F3 = 579, + YMM10F4 = 580, + YMM10F5 = 581, + YMM10F6 = 582, + YMM10F7 = 583, + YMM11F0 = 584, + YMM11F1 = 585, + YMM11F2 = 586, + YMM11F3 = 587, + YMM11F4 = 588, + YMM11F5 = 589, + YMM11F6 = 590, + YMM11F7 = 591, + YMM12F0 = 592, + YMM12F1 = 593, + YMM12F2 = 594, + YMM12F3 = 595, + YMM12F4 = 596, + YMM12F5 = 597, + YMM12F6 = 598, + YMM12F7 = 599, + YMM13F0 = 600, + YMM13F1 = 601, + YMM13F2 = 602, + YMM13F3 = 603, + YMM13F4 = 604, + YMM13F5 = 605, + YMM13F6 = 606, + YMM13F7 = 607, + YMM14F0 = 608, + YMM14F1 = 609, + YMM14F2 = 610, + YMM14F3 = 611, + YMM14F4 = 612, + YMM14F5 = 613, + YMM14F6 = 614, + YMM14F7 = 615, + YMM15F0 = 616, + YMM15F1 = 617, + YMM15F2 = 618, + YMM15F3 = 619, + YMM15F4 = 620, + YMM15F5 = 621, + YMM15F6 = 622, + YMM15F7 = 623, + + YMM0D0 = 624, // AVX floating-point double precise registers + YMM0D1 = 625, + YMM0D2 = 626, + YMM0D3 = 627, + YMM1D0 = 628, + YMM1D1 = 629, + YMM1D2 = 630, + YMM1D3 = 631, + YMM2D0 = 632, + YMM2D1 = 633, + YMM2D2 = 634, + YMM2D3 = 635, + YMM3D0 = 636, + YMM3D1 = 637, + YMM3D2 = 638, + YMM3D3 = 639, + YMM4D0 = 640, + YMM4D1 = 641, + YMM4D2 = 642, + YMM4D3 = 643, + YMM5D0 = 644, + YMM5D1 = 645, + YMM5D2 = 646, + YMM5D3 = 647, + YMM6D0 = 648, + YMM6D1 = 649, + YMM6D2 = 650, + YMM6D3 = 651, + YMM7D0 = 652, + YMM7D1 = 653, + YMM7D2 = 654, + YMM7D3 = 655, + YMM8D0 = 656, + YMM8D1 = 657, + YMM8D2 = 658, + YMM8D3 = 659, + YMM9D0 = 660, + YMM9D1 = 661, + YMM9D2 = 662, + YMM9D3 = 663, + YMM10D0 = 664, + YMM10D1 = 665, + YMM10D2 = 666, + YMM10D3 = 667, + YMM11D0 = 668, + YMM11D1 = 669, + YMM11D2 = 670, + YMM11D3 = 671, + YMM12D0 = 672, + YMM12D1 = 673, + YMM12D2 = 674, + YMM12D3 = 675, + YMM13D0 = 676, + YMM13D1 = 677, + YMM13D2 = 678, + YMM13D3 = 679, + YMM14D0 = 680, + YMM14D1 = 681, + YMM14D2 = 682, + YMM14D3 = 683, + YMM15D0 = 684, + YMM15D1 = 685, + YMM15D2 = 686, + YMM15D3 = 687, +} + +impl fmt::Display for AMD64Register { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::AL => write!(f, "AL"), + Self::CL => write!(f, "CL"), + Self::DL => write!(f, "DL"), + Self::BL => write!(f, "BL"), + Self::AH => write!(f, "AH"), + Self::CH => write!(f, "CH"), + Self::DH => write!(f, "DH"), + Self::BH => write!(f, "BH"), + Self::AX => write!(f, "AX"), + Self::CX => write!(f, "CX"), + Self::DX => write!(f, "DX"), + Self::BX => write!(f, "BX"), + Self::SP => write!(f, "SP"), + Self::BP => write!(f, "BP"), + Self::SI => write!(f, "SI"), + Self::DI => write!(f, "DI"), + Self::EAX => write!(f, "EAX"), + Self::ECX => write!(f, "ECX"), + Self::EDX => write!(f, "EDX"), + Self::EBX => write!(f, "EBX"), + Self::ESP => write!(f, "ESP"), + Self::EBP => write!(f, "EBP"), + Self::ESI => write!(f, "ESI"), + Self::EDI => write!(f, "EDI"), + Self::ES => write!(f, "ES"), + Self::CS => write!(f, "CS"), + Self::SS => write!(f, "SS"), + Self::DS => write!(f, "DS"), + Self::FS => write!(f, "FS"), + Self::GS => write!(f, "GS"), + Self::FLAGS => write!(f, "FLAGS"), + Self::RIP => write!(f, "RIP"), + Self::EFLAGS => write!(f, "EFLAGS"), + Self::CR0 => write!(f, "CR0"), + Self::CR1 => write!(f, "CR1"), + Self::CR2 => write!(f, "CR2"), + Self::CR3 => write!(f, "CR3"), + Self::CR4 => write!(f, "CR4"), + Self::CR8 => write!(f, "CR8"), + Self::DR0 => write!(f, "DR0"), + Self::DR1 => write!(f, "DR1"), + Self::DR2 => write!(f, "DR2"), + Self::DR3 => write!(f, "DR3"), + Self::DR4 => write!(f, "DR4"), + Self::DR5 => write!(f, "DR5"), + Self::DR6 => write!(f, "DR6"), + Self::DR7 => write!(f, "DR7"), + Self::DR8 => write!(f, "DR8"), + Self::DR9 => write!(f, "DR9"), + Self::DR10 => write!(f, "DR10"), + Self::DR11 => write!(f, "DR11"), + Self::DR12 => write!(f, "DR12"), + Self::DR13 => write!(f, "DR13"), + Self::DR14 => write!(f, "DR14"), + Self::DR15 => write!(f, "DR15"), + Self::GDTR => write!(f, "GDTR"), + Self::GDTL => write!(f, "GDTL"), + Self::IDTR => write!(f, "IDTR"), + Self::IDTL => write!(f, "IDTL"), + Self::LDTR => write!(f, "LDTR"), + Self::TR => write!(f, "TR"), + Self::ST0 => write!(f, "ST0"), + Self::ST1 => write!(f, "ST1"), + Self::ST2 => write!(f, "ST2"), + Self::ST3 => write!(f, "ST3"), + Self::ST4 => write!(f, "ST4"), + Self::ST5 => write!(f, "ST5"), + Self::ST6 => write!(f, "ST6"), + Self::ST7 => write!(f, "ST7"), + Self::CTRL => write!(f, "CTRL"), + Self::STAT => write!(f, "STAT"), + Self::TAG => write!(f, "TAG"), + Self::FPIP => write!(f, "FPIP"), + Self::FPCS => write!(f, "FPCS"), + Self::FPDO => write!(f, "FPDO"), + Self::FPDS => write!(f, "FPDS"), + Self::ISEM => write!(f, "ISEM"), + Self::FPEIP => write!(f, "FPEIP"), + Self::FPEDO => write!(f, "FPEDO"), + Self::MM0 => write!(f, "MM0"), + Self::MM1 => write!(f, "MM1"), + Self::MM2 => write!(f, "MM2"), + Self::MM3 => write!(f, "MM3"), + Self::MM4 => write!(f, "MM4"), + Self::MM5 => write!(f, "MM5"), + Self::MM6 => write!(f, "MM6"), + Self::MM7 => write!(f, "MM7"), + Self::XMM0 => write!(f, "XMM0"), + Self::XMM1 => write!(f, "XMM1"), + Self::XMM2 => write!(f, "XMM2"), + Self::XMM3 => write!(f, "XMM3"), + Self::XMM4 => write!(f, "XMM4"), + Self::XMM5 => write!(f, "XMM5"), + Self::XMM6 => write!(f, "XMM6"), + Self::XMM7 => write!(f, "XMM7"), + Self::XMM0_0 => write!(f, "XMM0_0"), + Self::XMM0_1 => write!(f, "XMM0_1"), + Self::XMM0_2 => write!(f, "XMM0_2"), + Self::XMM0_3 => write!(f, "XMM0_3"), + Self::XMM1_0 => write!(f, "XMM1_0"), + Self::XMM1_1 => write!(f, "XMM1_1"), + Self::XMM1_2 => write!(f, "XMM1_2"), + Self::XMM1_3 => write!(f, "XMM1_3"), + Self::XMM2_0 => write!(f, "XMM2_0"), + Self::XMM2_1 => write!(f, "XMM2_1"), + Self::XMM2_2 => write!(f, "XMM2_2"), + Self::XMM2_3 => write!(f, "XMM2_3"), + Self::XMM3_0 => write!(f, "XMM3_0"), + Self::XMM3_1 => write!(f, "XMM3_1"), + Self::XMM3_2 => write!(f, "XMM3_2"), + Self::XMM3_3 => write!(f, "XMM3_3"), + Self::XMM4_0 => write!(f, "XMM4_0"), + Self::XMM4_1 => write!(f, "XMM4_1"), + Self::XMM4_2 => write!(f, "XMM4_2"), + Self::XMM4_3 => write!(f, "XMM4_3"), + Self::XMM5_0 => write!(f, "XMM5_0"), + Self::XMM5_1 => write!(f, "XMM5_1"), + Self::XMM5_2 => write!(f, "XMM5_2"), + Self::XMM5_3 => write!(f, "XMM5_3"), + Self::XMM6_0 => write!(f, "XMM6_0"), + Self::XMM6_1 => write!(f, "XMM6_1"), + Self::XMM6_2 => write!(f, "XMM6_2"), + Self::XMM6_3 => write!(f, "XMM6_3"), + Self::XMM7_0 => write!(f, "XMM7_0"), + Self::XMM7_1 => write!(f, "XMM7_1"), + Self::XMM7_2 => write!(f, "XMM7_2"), + Self::XMM7_3 => write!(f, "XMM7_3"), + Self::XMM0L => write!(f, "XMM0L"), + Self::XMM1L => write!(f, "XMM1L"), + Self::XMM2L => write!(f, "XMM2L"), + Self::XMM3L => write!(f, "XMM3L"), + Self::XMM4L => write!(f, "XMM4L"), + Self::XMM5L => write!(f, "XMM5L"), + Self::XMM6L => write!(f, "XMM6L"), + Self::XMM7L => write!(f, "XMM7L"), + Self::XMM0H => write!(f, "XMM0H"), + Self::XMM1H => write!(f, "XMM1H"), + Self::XMM2H => write!(f, "XMM2H"), + Self::XMM3H => write!(f, "XMM3H"), + Self::XMM4H => write!(f, "XMM4H"), + Self::XMM5H => write!(f, "XMM5H"), + Self::XMM6H => write!(f, "XMM6H"), + Self::XMM7H => write!(f, "XMM7H"), + Self::MXCSR => write!(f, "MXCSR"), + Self::EMM0L => write!(f, "EMM0L"), + Self::EMM1L => write!(f, "EMM1L"), + Self::EMM2L => write!(f, "EMM2L"), + Self::EMM3L => write!(f, "EMM3L"), + Self::EMM4L => write!(f, "EMM4L"), + Self::EMM5L => write!(f, "EMM5L"), + Self::EMM6L => write!(f, "EMM6L"), + Self::EMM7L => write!(f, "EMM7L"), + Self::EMM0H => write!(f, "EMM0H"), + Self::EMM1H => write!(f, "EMM1H"), + Self::EMM2H => write!(f, "EMM2H"), + Self::EMM3H => write!(f, "EMM3H"), + Self::EMM4H => write!(f, "EMM4H"), + Self::EMM5H => write!(f, "EMM5H"), + Self::EMM6H => write!(f, "EMM6H"), + Self::EMM7H => write!(f, "EMM7H"), + Self::MM00 => write!(f, "MM00"), + Self::MM01 => write!(f, "MM01"), + Self::MM10 => write!(f, "MM10"), + Self::MM11 => write!(f, "MM11"), + Self::MM20 => write!(f, "MM20"), + Self::MM21 => write!(f, "MM21"), + Self::MM30 => write!(f, "MM30"), + Self::MM31 => write!(f, "MM31"), + Self::MM40 => write!(f, "MM40"), + Self::MM41 => write!(f, "MM41"), + Self::MM50 => write!(f, "MM50"), + Self::MM51 => write!(f, "MM51"), + Self::MM60 => write!(f, "MM60"), + Self::MM61 => write!(f, "MM61"), + Self::MM70 => write!(f, "MM70"), + Self::MM71 => write!(f, "MM71"), + Self::XMM8 => write!(f, "XMM8"), + Self::XMM9 => write!(f, "XMM9"), + Self::XMM10 => write!(f, "XMM10"), + Self::XMM11 => write!(f, "XMM11"), + Self::XMM12 => write!(f, "XMM12"), + Self::XMM13 => write!(f, "XMM13"), + Self::XMM14 => write!(f, "XMM14"), + Self::XMM15 => write!(f, "XMM15"), + Self::XMM8_0 => write!(f, "XMM8_0"), + Self::XMM8_1 => write!(f, "XMM8_1"), + Self::XMM8_2 => write!(f, "XMM8_2"), + Self::XMM8_3 => write!(f, "XMM8_3"), + Self::XMM9_0 => write!(f, "XMM9_0"), + Self::XMM9_1 => write!(f, "XMM9_1"), + Self::XMM9_2 => write!(f, "XMM9_2"), + Self::XMM9_3 => write!(f, "XMM9_3"), + Self::XMM10_0 => write!(f, "XMM10_0"), + Self::XMM10_1 => write!(f, "XMM10_1"), + Self::XMM10_2 => write!(f, "XMM10_2"), + Self::XMM10_3 => write!(f, "XMM10_3"), + Self::XMM11_0 => write!(f, "XMM11_0"), + Self::XMM11_1 => write!(f, "XMM11_1"), + Self::XMM11_2 => write!(f, "XMM11_2"), + Self::XMM11_3 => write!(f, "XMM11_3"), + Self::XMM12_0 => write!(f, "XMM12_0"), + Self::XMM12_1 => write!(f, "XMM12_1"), + Self::XMM12_2 => write!(f, "XMM12_2"), + Self::XMM12_3 => write!(f, "XMM12_3"), + Self::XMM13_0 => write!(f, "XMM13_0"), + Self::XMM13_1 => write!(f, "XMM13_1"), + Self::XMM13_2 => write!(f, "XMM13_2"), + Self::XMM13_3 => write!(f, "XMM13_3"), + Self::XMM14_0 => write!(f, "XMM14_0"), + Self::XMM14_1 => write!(f, "XMM14_1"), + Self::XMM14_2 => write!(f, "XMM14_2"), + Self::XMM14_3 => write!(f, "XMM14_3"), + Self::XMM15_0 => write!(f, "XMM15_0"), + Self::XMM15_1 => write!(f, "XMM15_1"), + Self::XMM15_2 => write!(f, "XMM15_2"), + Self::XMM15_3 => write!(f, "XMM15_3"), + Self::XMM8L => write!(f, "XMM8L"), + Self::XMM9L => write!(f, "XMM9L"), + Self::XMM10L => write!(f, "XMM10L"), + Self::XMM11L => write!(f, "XMM11L"), + Self::XMM12L => write!(f, "XMM12L"), + Self::XMM13L => write!(f, "XMM13L"), + Self::XMM14L => write!(f, "XMM14L"), + Self::XMM15L => write!(f, "XMM15L"), + Self::XMM8H => write!(f, "XMM8H"), + Self::XMM9H => write!(f, "XMM9H"), + Self::XMM10H => write!(f, "XMM10H"), + Self::XMM11H => write!(f, "XMM11H"), + Self::XMM12H => write!(f, "XMM12H"), + Self::XMM13H => write!(f, "XMM13H"), + Self::XMM14H => write!(f, "XMM14H"), + Self::XMM15H => write!(f, "XMM15H"), + Self::EMM8L => write!(f, "EMM8L"), + Self::EMM9L => write!(f, "EMM9L"), + Self::EMM10L => write!(f, "EMM10L"), + Self::EMM11L => write!(f, "EMM11L"), + Self::EMM12L => write!(f, "EMM12L"), + Self::EMM13L => write!(f, "EMM13L"), + Self::EMM14L => write!(f, "EMM14L"), + Self::EMM15L => write!(f, "EMM15L"), + Self::EMM8H => write!(f, "EMM8H"), + Self::EMM9H => write!(f, "EMM9H"), + Self::EMM10H => write!(f, "EMM10H"), + Self::EMM11H => write!(f, "EMM11H"), + Self::EMM12H => write!(f, "EMM12H"), + Self::EMM13H => write!(f, "EMM13H"), + Self::EMM14H => write!(f, "EMM14H"), + Self::EMM15H => write!(f, "EMM15H"), + Self::SIL => write!(f, "SIL"), + Self::DIL => write!(f, "DIL"), + Self::BPL => write!(f, "BPL"), + Self::SPL => write!(f, "SPL"), + Self::RAX => write!(f, "RAX"), + Self::RBX => write!(f, "RBX"), + Self::RCX => write!(f, "RCX"), + Self::RDX => write!(f, "RDX"), + Self::RSI => write!(f, "RSI"), + Self::RDI => write!(f, "RDI"), + Self::RBP => write!(f, "RBP"), + Self::RSP => write!(f, "RSP"), + Self::R8 => write!(f, "R8"), + Self::R9 => write!(f, "R9"), + Self::R10 => write!(f, "R10"), + Self::R11 => write!(f, "R11"), + Self::R12 => write!(f, "R12"), + Self::R13 => write!(f, "R13"), + Self::R14 => write!(f, "R14"), + Self::R15 => write!(f, "R15"), + Self::R8B => write!(f, "R8B"), + Self::R9B => write!(f, "R9B"), + Self::R10B => write!(f, "R10B"), + Self::R11B => write!(f, "R11B"), + Self::R12B => write!(f, "R12B"), + Self::R13B => write!(f, "R13B"), + Self::R14B => write!(f, "R14B"), + Self::R15B => write!(f, "R15B"), + Self::R8W => write!(f, "R8W"), + Self::R9W => write!(f, "R9W"), + Self::R10W => write!(f, "R10W"), + Self::R11W => write!(f, "R11W"), + Self::R12W => write!(f, "R12W"), + Self::R13W => write!(f, "R13W"), + Self::R14W => write!(f, "R14W"), + Self::R15W => write!(f, "R15W"), + Self::R8D => write!(f, "R8D"), + Self::R9D => write!(f, "R9D"), + Self::R10D => write!(f, "R10D"), + Self::R11D => write!(f, "R11D"), + Self::R12D => write!(f, "R12D"), + Self::R13D => write!(f, "R13D"), + Self::R14D => write!(f, "R14D"), + Self::R15D => write!(f, "R15D"), + Self::YMM0 => write!(f, "YMM0"), + Self::YMM1 => write!(f, "YMM1"), + Self::YMM2 => write!(f, "YMM2"), + Self::YMM3 => write!(f, "YMM3"), + Self::YMM4 => write!(f, "YMM4"), + Self::YMM5 => write!(f, "YMM5"), + Self::YMM6 => write!(f, "YMM6"), + Self::YMM7 => write!(f, "YMM7"), + Self::YMM8 => write!(f, "YMM8"), + Self::YMM9 => write!(f, "YMM9"), + Self::YMM10 => write!(f, "YMM10"), + Self::YMM11 => write!(f, "YMM11"), + Self::YMM12 => write!(f, "YMM12"), + Self::YMM13 => write!(f, "YMM13"), + Self::YMM14 => write!(f, "YMM14"), + Self::YMM15 => write!(f, "YMM15"), + Self::YMM0H => write!(f, "YMM0H"), + Self::YMM1H => write!(f, "YMM1H"), + Self::YMM2H => write!(f, "YMM2H"), + Self::YMM3H => write!(f, "YMM3H"), + Self::YMM4H => write!(f, "YMM4H"), + Self::YMM5H => write!(f, "YMM5H"), + Self::YMM6H => write!(f, "YMM6H"), + Self::YMM7H => write!(f, "YMM7H"), + Self::YMM8H => write!(f, "YMM8H"), + Self::YMM9H => write!(f, "YMM9H"), + Self::YMM10H => write!(f, "YMM10H"), + Self::YMM11H => write!(f, "YMM11H"), + Self::YMM12H => write!(f, "YMM12H"), + Self::YMM13H => write!(f, "YMM13H"), + Self::YMM14H => write!(f, "YMM14H"), + Self::YMM15H => write!(f, "YMM15H"), + Self::XMM0IL => write!(f, "XMM0IL"), + Self::XMM1IL => write!(f, "XMM1IL"), + Self::XMM2IL => write!(f, "XMM2IL"), + Self::XMM3IL => write!(f, "XMM3IL"), + Self::XMM4IL => write!(f, "XMM4IL"), + Self::XMM5IL => write!(f, "XMM5IL"), + Self::XMM6IL => write!(f, "XMM6IL"), + Self::XMM7IL => write!(f, "XMM7IL"), + Self::XMM8IL => write!(f, "XMM8IL"), + Self::XMM9IL => write!(f, "XMM9IL"), + Self::XMM10IL => write!(f, "XMM10IL"), + Self::XMM11IL => write!(f, "XMM11IL"), + Self::XMM12IL => write!(f, "XMM12IL"), + Self::XMM13IL => write!(f, "XMM13IL"), + Self::XMM14IL => write!(f, "XMM14IL"), + Self::XMM15IL => write!(f, "XMM15IL"), + Self::XMM0IH => write!(f, "XMM0IH"), + Self::XMM1IH => write!(f, "XMM1IH"), + Self::XMM2IH => write!(f, "XMM2IH"), + Self::XMM3IH => write!(f, "XMM3IH"), + Self::XMM4IH => write!(f, "XMM4IH"), + Self::XMM5IH => write!(f, "XMM5IH"), + Self::XMM6IH => write!(f, "XMM6IH"), + Self::XMM7IH => write!(f, "XMM7IH"), + Self::XMM8IH => write!(f, "XMM8IH"), + Self::XMM9IH => write!(f, "XMM9IH"), + Self::XMM10IH => write!(f, "XMM10IH"), + Self::XMM11IH => write!(f, "XMM11IH"), + Self::XMM12IH => write!(f, "XMM12IH"), + Self::XMM13IH => write!(f, "XMM13IH"), + Self::XMM14IH => write!(f, "XMM14IH"), + Self::XMM15IH => write!(f, "XMM15IH"), + Self::YMM0I0 => write!(f, "YMM0I0"), + Self::YMM0I1 => write!(f, "YMM0I1"), + Self::YMM0I2 => write!(f, "YMM0I2"), + Self::YMM0I3 => write!(f, "YMM0I3"), + Self::YMM1I0 => write!(f, "YMM1I0"), + Self::YMM1I1 => write!(f, "YMM1I1"), + Self::YMM1I2 => write!(f, "YMM1I2"), + Self::YMM1I3 => write!(f, "YMM1I3"), + Self::YMM2I0 => write!(f, "YMM2I0"), + Self::YMM2I1 => write!(f, "YMM2I1"), + Self::YMM2I2 => write!(f, "YMM2I2"), + Self::YMM2I3 => write!(f, "YMM2I3"), + Self::YMM3I0 => write!(f, "YMM3I0"), + Self::YMM3I1 => write!(f, "YMM3I1"), + Self::YMM3I2 => write!(f, "YMM3I2"), + Self::YMM3I3 => write!(f, "YMM3I3"), + Self::YMM4I0 => write!(f, "YMM4I0"), + Self::YMM4I1 => write!(f, "YMM4I1"), + Self::YMM4I2 => write!(f, "YMM4I2"), + Self::YMM4I3 => write!(f, "YMM4I3"), + Self::YMM5I0 => write!(f, "YMM5I0"), + Self::YMM5I1 => write!(f, "YMM5I1"), + Self::YMM5I2 => write!(f, "YMM5I2"), + Self::YMM5I3 => write!(f, "YMM5I3"), + Self::YMM6I0 => write!(f, "YMM6I0"), + Self::YMM6I1 => write!(f, "YMM6I1"), + Self::YMM6I2 => write!(f, "YMM6I2"), + Self::YMM6I3 => write!(f, "YMM6I3"), + Self::YMM7I0 => write!(f, "YMM7I0"), + Self::YMM7I1 => write!(f, "YMM7I1"), + Self::YMM7I2 => write!(f, "YMM7I2"), + Self::YMM7I3 => write!(f, "YMM7I3"), + Self::YMM8I0 => write!(f, "YMM8I0"), + Self::YMM8I1 => write!(f, "YMM8I1"), + Self::YMM8I2 => write!(f, "YMM8I2"), + Self::YMM8I3 => write!(f, "YMM8I3"), + Self::YMM9I0 => write!(f, "YMM9I0"), + Self::YMM9I1 => write!(f, "YMM9I1"), + Self::YMM9I2 => write!(f, "YMM9I2"), + Self::YMM9I3 => write!(f, "YMM9I3"), + Self::YMM10I0 => write!(f, "YMM10I0"), + Self::YMM10I1 => write!(f, "YMM10I1"), + Self::YMM10I2 => write!(f, "YMM10I2"), + Self::YMM10I3 => write!(f, "YMM10I3"), + Self::YMM11I0 => write!(f, "YMM11I0"), + Self::YMM11I1 => write!(f, "YMM11I1"), + Self::YMM11I2 => write!(f, "YMM11I2"), + Self::YMM11I3 => write!(f, "YMM11I3"), + Self::YMM12I0 => write!(f, "YMM12I0"), + Self::YMM12I1 => write!(f, "YMM12I1"), + Self::YMM12I2 => write!(f, "YMM12I2"), + Self::YMM12I3 => write!(f, "YMM12I3"), + Self::YMM13I0 => write!(f, "YMM13I0"), + Self::YMM13I1 => write!(f, "YMM13I1"), + Self::YMM13I2 => write!(f, "YMM13I2"), + Self::YMM13I3 => write!(f, "YMM13I3"), + Self::YMM14I0 => write!(f, "YMM14I0"), + Self::YMM14I1 => write!(f, "YMM14I1"), + Self::YMM14I2 => write!(f, "YMM14I2"), + Self::YMM14I3 => write!(f, "YMM14I3"), + Self::YMM15I0 => write!(f, "YMM15I0"), + Self::YMM15I1 => write!(f, "YMM15I1"), + Self::YMM15I2 => write!(f, "YMM15I2"), + Self::YMM15I3 => write!(f, "YMM15I3"), + Self::YMM0F0 => write!(f, "YMM0F0"), + Self::YMM0F1 => write!(f, "YMM0F1"), + Self::YMM0F2 => write!(f, "YMM0F2"), + Self::YMM0F3 => write!(f, "YMM0F3"), + Self::YMM0F4 => write!(f, "YMM0F4"), + Self::YMM0F5 => write!(f, "YMM0F5"), + Self::YMM0F6 => write!(f, "YMM0F6"), + Self::YMM0F7 => write!(f, "YMM0F7"), + Self::YMM1F0 => write!(f, "YMM1F0"), + Self::YMM1F1 => write!(f, "YMM1F1"), + Self::YMM1F2 => write!(f, "YMM1F2"), + Self::YMM1F3 => write!(f, "YMM1F3"), + Self::YMM1F4 => write!(f, "YMM1F4"), + Self::YMM1F5 => write!(f, "YMM1F5"), + Self::YMM1F6 => write!(f, "YMM1F6"), + Self::YMM1F7 => write!(f, "YMM1F7"), + Self::YMM2F0 => write!(f, "YMM2F0"), + Self::YMM2F1 => write!(f, "YMM2F1"), + Self::YMM2F2 => write!(f, "YMM2F2"), + Self::YMM2F3 => write!(f, "YMM2F3"), + Self::YMM2F4 => write!(f, "YMM2F4"), + Self::YMM2F5 => write!(f, "YMM2F5"), + Self::YMM2F6 => write!(f, "YMM2F6"), + Self::YMM2F7 => write!(f, "YMM2F7"), + Self::YMM3F0 => write!(f, "YMM3F0"), + Self::YMM3F1 => write!(f, "YMM3F1"), + Self::YMM3F2 => write!(f, "YMM3F2"), + Self::YMM3F3 => write!(f, "YMM3F3"), + Self::YMM3F4 => write!(f, "YMM3F4"), + Self::YMM3F5 => write!(f, "YMM3F5"), + Self::YMM3F6 => write!(f, "YMM3F6"), + Self::YMM3F7 => write!(f, "YMM3F7"), + Self::YMM4F0 => write!(f, "YMM4F0"), + Self::YMM4F1 => write!(f, "YMM4F1"), + Self::YMM4F2 => write!(f, "YMM4F2"), + Self::YMM4F3 => write!(f, "YMM4F3"), + Self::YMM4F4 => write!(f, "YMM4F4"), + Self::YMM4F5 => write!(f, "YMM4F5"), + Self::YMM4F6 => write!(f, "YMM4F6"), + Self::YMM4F7 => write!(f, "YMM4F7"), + Self::YMM5F0 => write!(f, "YMM5F0"), + Self::YMM5F1 => write!(f, "YMM5F1"), + Self::YMM5F2 => write!(f, "YMM5F2"), + Self::YMM5F3 => write!(f, "YMM5F3"), + Self::YMM5F4 => write!(f, "YMM5F4"), + Self::YMM5F5 => write!(f, "YMM5F5"), + Self::YMM5F6 => write!(f, "YMM5F6"), + Self::YMM5F7 => write!(f, "YMM5F7"), + Self::YMM6F0 => write!(f, "YMM6F0"), + Self::YMM6F1 => write!(f, "YMM6F1"), + Self::YMM6F2 => write!(f, "YMM6F2"), + Self::YMM6F3 => write!(f, "YMM6F3"), + Self::YMM6F4 => write!(f, "YMM6F4"), + Self::YMM6F5 => write!(f, "YMM6F5"), + Self::YMM6F6 => write!(f, "YMM6F6"), + Self::YMM6F7 => write!(f, "YMM6F7"), + Self::YMM7F0 => write!(f, "YMM7F0"), + Self::YMM7F1 => write!(f, "YMM7F1"), + Self::YMM7F2 => write!(f, "YMM7F2"), + Self::YMM7F3 => write!(f, "YMM7F3"), + Self::YMM7F4 => write!(f, "YMM7F4"), + Self::YMM7F5 => write!(f, "YMM7F5"), + Self::YMM7F6 => write!(f, "YMM7F6"), + Self::YMM7F7 => write!(f, "YMM7F7"), + Self::YMM8F0 => write!(f, "YMM8F0"), + Self::YMM8F1 => write!(f, "YMM8F1"), + Self::YMM8F2 => write!(f, "YMM8F2"), + Self::YMM8F3 => write!(f, "YMM8F3"), + Self::YMM8F4 => write!(f, "YMM8F4"), + Self::YMM8F5 => write!(f, "YMM8F5"), + Self::YMM8F6 => write!(f, "YMM8F6"), + Self::YMM8F7 => write!(f, "YMM8F7"), + Self::YMM9F0 => write!(f, "YMM9F0"), + Self::YMM9F1 => write!(f, "YMM9F1"), + Self::YMM9F2 => write!(f, "YMM9F2"), + Self::YMM9F3 => write!(f, "YMM9F3"), + Self::YMM9F4 => write!(f, "YMM9F4"), + Self::YMM9F5 => write!(f, "YMM9F5"), + Self::YMM9F6 => write!(f, "YMM9F6"), + Self::YMM9F7 => write!(f, "YMM9F7"), + Self::YMM10F0 => write!(f, "YMM10F0"), + Self::YMM10F1 => write!(f, "YMM10F1"), + Self::YMM10F2 => write!(f, "YMM10F2"), + Self::YMM10F3 => write!(f, "YMM10F3"), + Self::YMM10F4 => write!(f, "YMM10F4"), + Self::YMM10F5 => write!(f, "YMM10F5"), + Self::YMM10F6 => write!(f, "YMM10F6"), + Self::YMM10F7 => write!(f, "YMM10F7"), + Self::YMM11F0 => write!(f, "YMM11F0"), + Self::YMM11F1 => write!(f, "YMM11F1"), + Self::YMM11F2 => write!(f, "YMM11F2"), + Self::YMM11F3 => write!(f, "YMM11F3"), + Self::YMM11F4 => write!(f, "YMM11F4"), + Self::YMM11F5 => write!(f, "YMM11F5"), + Self::YMM11F6 => write!(f, "YMM11F6"), + Self::YMM11F7 => write!(f, "YMM11F7"), + Self::YMM12F0 => write!(f, "YMM12F0"), + Self::YMM12F1 => write!(f, "YMM12F1"), + Self::YMM12F2 => write!(f, "YMM12F2"), + Self::YMM12F3 => write!(f, "YMM12F3"), + Self::YMM12F4 => write!(f, "YMM12F4"), + Self::YMM12F5 => write!(f, "YMM12F5"), + Self::YMM12F6 => write!(f, "YMM12F6"), + Self::YMM12F7 => write!(f, "YMM12F7"), + Self::YMM13F0 => write!(f, "YMM13F0"), + Self::YMM13F1 => write!(f, "YMM13F1"), + Self::YMM13F2 => write!(f, "YMM13F2"), + Self::YMM13F3 => write!(f, "YMM13F3"), + Self::YMM13F4 => write!(f, "YMM13F4"), + Self::YMM13F5 => write!(f, "YMM13F5"), + Self::YMM13F6 => write!(f, "YMM13F6"), + Self::YMM13F7 => write!(f, "YMM13F7"), + Self::YMM14F0 => write!(f, "YMM14F0"), + Self::YMM14F1 => write!(f, "YMM14F1"), + Self::YMM14F2 => write!(f, "YMM14F2"), + Self::YMM14F3 => write!(f, "YMM14F3"), + Self::YMM14F4 => write!(f, "YMM14F4"), + Self::YMM14F5 => write!(f, "YMM14F5"), + Self::YMM14F6 => write!(f, "YMM14F6"), + Self::YMM14F7 => write!(f, "YMM14F7"), + Self::YMM15F0 => write!(f, "YMM15F0"), + Self::YMM15F1 => write!(f, "YMM15F1"), + Self::YMM15F2 => write!(f, "YMM15F2"), + Self::YMM15F3 => write!(f, "YMM15F3"), + Self::YMM15F4 => write!(f, "YMM15F4"), + Self::YMM15F5 => write!(f, "YMM15F5"), + Self::YMM15F6 => write!(f, "YMM15F6"), + Self::YMM15F7 => write!(f, "YMM15F7"), + Self::YMM0D0 => write!(f, "YMM0D0"), + Self::YMM0D1 => write!(f, "YMM0D1"), + Self::YMM0D2 => write!(f, "YMM0D2"), + Self::YMM0D3 => write!(f, "YMM0D3"), + Self::YMM1D0 => write!(f, "YMM1D0"), + Self::YMM1D1 => write!(f, "YMM1D1"), + Self::YMM1D2 => write!(f, "YMM1D2"), + Self::YMM1D3 => write!(f, "YMM1D3"), + Self::YMM2D0 => write!(f, "YMM2D0"), + Self::YMM2D1 => write!(f, "YMM2D1"), + Self::YMM2D2 => write!(f, "YMM2D2"), + Self::YMM2D3 => write!(f, "YMM2D3"), + Self::YMM3D0 => write!(f, "YMM3D0"), + Self::YMM3D1 => write!(f, "YMM3D1"), + Self::YMM3D2 => write!(f, "YMM3D2"), + Self::YMM3D3 => write!(f, "YMM3D3"), + Self::YMM4D0 => write!(f, "YMM4D0"), + Self::YMM4D1 => write!(f, "YMM4D1"), + Self::YMM4D2 => write!(f, "YMM4D2"), + Self::YMM4D3 => write!(f, "YMM4D3"), + Self::YMM5D0 => write!(f, "YMM5D0"), + Self::YMM5D1 => write!(f, "YMM5D1"), + Self::YMM5D2 => write!(f, "YMM5D2"), + Self::YMM5D3 => write!(f, "YMM5D3"), + Self::YMM6D0 => write!(f, "YMM6D0"), + Self::YMM6D1 => write!(f, "YMM6D1"), + Self::YMM6D2 => write!(f, "YMM6D2"), + Self::YMM6D3 => write!(f, "YMM6D3"), + Self::YMM7D0 => write!(f, "YMM7D0"), + Self::YMM7D1 => write!(f, "YMM7D1"), + Self::YMM7D2 => write!(f, "YMM7D2"), + Self::YMM7D3 => write!(f, "YMM7D3"), + Self::YMM8D0 => write!(f, "YMM8D0"), + Self::YMM8D1 => write!(f, "YMM8D1"), + Self::YMM8D2 => write!(f, "YMM8D2"), + Self::YMM8D3 => write!(f, "YMM8D3"), + Self::YMM9D0 => write!(f, "YMM9D0"), + Self::YMM9D1 => write!(f, "YMM9D1"), + Self::YMM9D2 => write!(f, "YMM9D2"), + Self::YMM9D3 => write!(f, "YMM9D3"), + Self::YMM10D0 => write!(f, "YMM10D0"), + Self::YMM10D1 => write!(f, "YMM10D1"), + Self::YMM10D2 => write!(f, "YMM10D2"), + Self::YMM10D3 => write!(f, "YMM10D3"), + Self::YMM11D0 => write!(f, "YMM11D0"), + Self::YMM11D1 => write!(f, "YMM11D1"), + Self::YMM11D2 => write!(f, "YMM11D2"), + Self::YMM11D3 => write!(f, "YMM11D3"), + Self::YMM12D0 => write!(f, "YMM12D0"), + Self::YMM12D1 => write!(f, "YMM12D1"), + Self::YMM12D2 => write!(f, "YMM12D2"), + Self::YMM12D3 => write!(f, "YMM12D3"), + Self::YMM13D0 => write!(f, "YMM13D0"), + Self::YMM13D1 => write!(f, "YMM13D1"), + Self::YMM13D2 => write!(f, "YMM13D2"), + Self::YMM13D3 => write!(f, "YMM13D3"), + Self::YMM14D0 => write!(f, "YMM14D0"), + Self::YMM14D1 => write!(f, "YMM14D1"), + Self::YMM14D2 => write!(f, "YMM14D2"), + Self::YMM14D3 => write!(f, "YMM14D3"), + Self::YMM15D0 => write!(f, "YMM15D0"), + Self::YMM15D1 => write!(f, "YMM15D1"), + Self::YMM15D2 => write!(f, "YMM15D2"), + Self::YMM15D3 => write!(f, "YMM15D3"), + } + } +} + +impl TryFrom for AMD64Register { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 1 => Ok(Self::AL), + 2 => Ok(Self::CL), + 3 => Ok(Self::DL), + 4 => Ok(Self::BL), + 5 => Ok(Self::AH), + 6 => Ok(Self::CH), + 7 => Ok(Self::DH), + 8 => Ok(Self::BH), + 9 => Ok(Self::AX), + 10 => Ok(Self::CX), + 11 => Ok(Self::DX), + 12 => Ok(Self::BX), + 13 => Ok(Self::SP), + 14 => Ok(Self::BP), + 15 => Ok(Self::SI), + 16 => Ok(Self::DI), + 17 => Ok(Self::EAX), + 18 => Ok(Self::ECX), + 19 => Ok(Self::EDX), + 20 => Ok(Self::EBX), + 21 => Ok(Self::ESP), + 22 => Ok(Self::EBP), + 23 => Ok(Self::ESI), + 24 => Ok(Self::EDI), + 25 => Ok(Self::ES), + 26 => Ok(Self::CS), + 27 => Ok(Self::SS), + 28 => Ok(Self::DS), + 29 => Ok(Self::FS), + 30 => Ok(Self::GS), + 32 => Ok(Self::FLAGS), + 33 => Ok(Self::RIP), + 34 => Ok(Self::EFLAGS), + 80 => Ok(Self::CR0), + 81 => Ok(Self::CR1), + 82 => Ok(Self::CR2), + 83 => Ok(Self::CR3), + 84 => Ok(Self::CR4), + 88 => Ok(Self::CR8), + 90 => Ok(Self::DR0), + 91 => Ok(Self::DR1), + 92 => Ok(Self::DR2), + 93 => Ok(Self::DR3), + 94 => Ok(Self::DR4), + 95 => Ok(Self::DR5), + 96 => Ok(Self::DR6), + 97 => Ok(Self::DR7), + 98 => Ok(Self::DR8), + 99 => Ok(Self::DR9), + 100 => Ok(Self::DR10), + 101 => Ok(Self::DR11), + 102 => Ok(Self::DR12), + 103 => Ok(Self::DR13), + 104 => Ok(Self::DR14), + 105 => Ok(Self::DR15), + 110 => Ok(Self::GDTR), + 111 => Ok(Self::GDTL), + 112 => Ok(Self::IDTR), + 113 => Ok(Self::IDTL), + 114 => Ok(Self::LDTR), + 115 => Ok(Self::TR), + 128 => Ok(Self::ST0), + 129 => Ok(Self::ST1), + 130 => Ok(Self::ST2), + 131 => Ok(Self::ST3), + 132 => Ok(Self::ST4), + 133 => Ok(Self::ST5), + 134 => Ok(Self::ST6), + 135 => Ok(Self::ST7), + 136 => Ok(Self::CTRL), + 137 => Ok(Self::STAT), + 138 => Ok(Self::TAG), + 139 => Ok(Self::FPIP), + 140 => Ok(Self::FPCS), + 141 => Ok(Self::FPDO), + 142 => Ok(Self::FPDS), + 143 => Ok(Self::ISEM), + 144 => Ok(Self::FPEIP), + 145 => Ok(Self::FPEDO), + 146 => Ok(Self::MM0), + 147 => Ok(Self::MM1), + 148 => Ok(Self::MM2), + 149 => Ok(Self::MM3), + 150 => Ok(Self::MM4), + 151 => Ok(Self::MM5), + 152 => Ok(Self::MM6), + 153 => Ok(Self::MM7), + 154 => Ok(Self::XMM0), + 155 => Ok(Self::XMM1), + 156 => Ok(Self::XMM2), + 157 => Ok(Self::XMM3), + 158 => Ok(Self::XMM4), + 159 => Ok(Self::XMM5), + 160 => Ok(Self::XMM6), + 161 => Ok(Self::XMM7), + 162 => Ok(Self::XMM0_0), + 163 => Ok(Self::XMM0_1), + 164 => Ok(Self::XMM0_2), + 165 => Ok(Self::XMM0_3), + 166 => Ok(Self::XMM1_0), + 167 => Ok(Self::XMM1_1), + 168 => Ok(Self::XMM1_2), + 169 => Ok(Self::XMM1_3), + 170 => Ok(Self::XMM2_0), + 171 => Ok(Self::XMM2_1), + 172 => Ok(Self::XMM2_2), + 173 => Ok(Self::XMM2_3), + 174 => Ok(Self::XMM3_0), + 175 => Ok(Self::XMM3_1), + 176 => Ok(Self::XMM3_2), + 177 => Ok(Self::XMM3_3), + 178 => Ok(Self::XMM4_0), + 179 => Ok(Self::XMM4_1), + 180 => Ok(Self::XMM4_2), + 181 => Ok(Self::XMM4_3), + 182 => Ok(Self::XMM5_0), + 183 => Ok(Self::XMM5_1), + 184 => Ok(Self::XMM5_2), + 185 => Ok(Self::XMM5_3), + 186 => Ok(Self::XMM6_0), + 187 => Ok(Self::XMM6_1), + 188 => Ok(Self::XMM6_2), + 189 => Ok(Self::XMM6_3), + 190 => Ok(Self::XMM7_0), + 191 => Ok(Self::XMM7_1), + 192 => Ok(Self::XMM7_2), + 193 => Ok(Self::XMM7_3), + 194 => Ok(Self::XMM0L), + 195 => Ok(Self::XMM1L), + 196 => Ok(Self::XMM2L), + 197 => Ok(Self::XMM3L), + 198 => Ok(Self::XMM4L), + 199 => Ok(Self::XMM5L), + 200 => Ok(Self::XMM6L), + 201 => Ok(Self::XMM7L), + 202 => Ok(Self::XMM0H), + 203 => Ok(Self::XMM1H), + 204 => Ok(Self::XMM2H), + 205 => Ok(Self::XMM3H), + 206 => Ok(Self::XMM4H), + 207 => Ok(Self::XMM5H), + 208 => Ok(Self::XMM6H), + 209 => Ok(Self::XMM7H), + 211 => Ok(Self::MXCSR), + 220 => Ok(Self::EMM0L), + 221 => Ok(Self::EMM1L), + 222 => Ok(Self::EMM2L), + 223 => Ok(Self::EMM3L), + 224 => Ok(Self::EMM4L), + 225 => Ok(Self::EMM5L), + 226 => Ok(Self::EMM6L), + 227 => Ok(Self::EMM7L), + 228 => Ok(Self::EMM0H), + 229 => Ok(Self::EMM1H), + 230 => Ok(Self::EMM2H), + 231 => Ok(Self::EMM3H), + 232 => Ok(Self::EMM4H), + 233 => Ok(Self::EMM5H), + 234 => Ok(Self::EMM6H), + 235 => Ok(Self::EMM7H), + 236 => Ok(Self::MM00), + 237 => Ok(Self::MM01), + 238 => Ok(Self::MM10), + 239 => Ok(Self::MM11), + 240 => Ok(Self::MM20), + 241 => Ok(Self::MM21), + 242 => Ok(Self::MM30), + 243 => Ok(Self::MM31), + 244 => Ok(Self::MM40), + 245 => Ok(Self::MM41), + 246 => Ok(Self::MM50), + 247 => Ok(Self::MM51), + 248 => Ok(Self::MM60), + 249 => Ok(Self::MM61), + 250 => Ok(Self::MM70), + 251 => Ok(Self::MM71), + 252 => Ok(Self::XMM8), + 253 => Ok(Self::XMM9), + 254 => Ok(Self::XMM10), + 255 => Ok(Self::XMM11), + 256 => Ok(Self::XMM12), + 257 => Ok(Self::XMM13), + 258 => Ok(Self::XMM14), + 259 => Ok(Self::XMM15), + 260 => Ok(Self::XMM8_0), + 261 => Ok(Self::XMM8_1), + 262 => Ok(Self::XMM8_2), + 263 => Ok(Self::XMM8_3), + 264 => Ok(Self::XMM9_0), + 265 => Ok(Self::XMM9_1), + 266 => Ok(Self::XMM9_2), + 267 => Ok(Self::XMM9_3), + 268 => Ok(Self::XMM10_0), + 269 => Ok(Self::XMM10_1), + 270 => Ok(Self::XMM10_2), + 271 => Ok(Self::XMM10_3), + 272 => Ok(Self::XMM11_0), + 273 => Ok(Self::XMM11_1), + 274 => Ok(Self::XMM11_2), + 275 => Ok(Self::XMM11_3), + 276 => Ok(Self::XMM12_0), + 277 => Ok(Self::XMM12_1), + 278 => Ok(Self::XMM12_2), + 279 => Ok(Self::XMM12_3), + 280 => Ok(Self::XMM13_0), + 281 => Ok(Self::XMM13_1), + 282 => Ok(Self::XMM13_2), + 283 => Ok(Self::XMM13_3), + 284 => Ok(Self::XMM14_0), + 285 => Ok(Self::XMM14_1), + 286 => Ok(Self::XMM14_2), + 287 => Ok(Self::XMM14_3), + 288 => Ok(Self::XMM15_0), + 289 => Ok(Self::XMM15_1), + 290 => Ok(Self::XMM15_2), + 291 => Ok(Self::XMM15_3), + 292 => Ok(Self::XMM8L), + 293 => Ok(Self::XMM9L), + 294 => Ok(Self::XMM10L), + 295 => Ok(Self::XMM11L), + 296 => Ok(Self::XMM12L), + 297 => Ok(Self::XMM13L), + 298 => Ok(Self::XMM14L), + 299 => Ok(Self::XMM15L), + 300 => Ok(Self::XMM8H), + 301 => Ok(Self::XMM9H), + 302 => Ok(Self::XMM10H), + 303 => Ok(Self::XMM11H), + 304 => Ok(Self::XMM12H), + 305 => Ok(Self::XMM13H), + 306 => Ok(Self::XMM14H), + 307 => Ok(Self::XMM15H), + 308 => Ok(Self::EMM8L), + 309 => Ok(Self::EMM9L), + 310 => Ok(Self::EMM10L), + 311 => Ok(Self::EMM11L), + 312 => Ok(Self::EMM12L), + 313 => Ok(Self::EMM13L), + 314 => Ok(Self::EMM14L), + 315 => Ok(Self::EMM15L), + 316 => Ok(Self::EMM8H), + 317 => Ok(Self::EMM9H), + 318 => Ok(Self::EMM10H), + 319 => Ok(Self::EMM11H), + 320 => Ok(Self::EMM12H), + 321 => Ok(Self::EMM13H), + 322 => Ok(Self::EMM14H), + 323 => Ok(Self::EMM15H), + 324 => Ok(Self::SIL), + 325 => Ok(Self::DIL), + 326 => Ok(Self::BPL), + 327 => Ok(Self::SPL), + 328 => Ok(Self::RAX), + 329 => Ok(Self::RBX), + 330 => Ok(Self::RCX), + 331 => Ok(Self::RDX), + 332 => Ok(Self::RSI), + 333 => Ok(Self::RDI), + 334 => Ok(Self::RBP), + 335 => Ok(Self::RSP), + 336 => Ok(Self::R8), + 337 => Ok(Self::R9), + 338 => Ok(Self::R10), + 339 => Ok(Self::R11), + 340 => Ok(Self::R12), + 341 => Ok(Self::R13), + 342 => Ok(Self::R14), + 343 => Ok(Self::R15), + 344 => Ok(Self::R8B), + 345 => Ok(Self::R9B), + 346 => Ok(Self::R10B), + 347 => Ok(Self::R11B), + 348 => Ok(Self::R12B), + 349 => Ok(Self::R13B), + 350 => Ok(Self::R14B), + 351 => Ok(Self::R15B), + 352 => Ok(Self::R8W), + 353 => Ok(Self::R9W), + 354 => Ok(Self::R10W), + 355 => Ok(Self::R11W), + 356 => Ok(Self::R12W), + 357 => Ok(Self::R13W), + 358 => Ok(Self::R14W), + 359 => Ok(Self::R15W), + 360 => Ok(Self::R8D), + 361 => Ok(Self::R9D), + 362 => Ok(Self::R10D), + 363 => Ok(Self::R11D), + 364 => Ok(Self::R12D), + 365 => Ok(Self::R13D), + 366 => Ok(Self::R14D), + 367 => Ok(Self::R15D), + 368 => Ok(Self::YMM0), + 369 => Ok(Self::YMM1), + 370 => Ok(Self::YMM2), + 371 => Ok(Self::YMM3), + 372 => Ok(Self::YMM4), + 373 => Ok(Self::YMM5), + 374 => Ok(Self::YMM6), + 375 => Ok(Self::YMM7), + 376 => Ok(Self::YMM8), + 377 => Ok(Self::YMM9), + 378 => Ok(Self::YMM10), + 379 => Ok(Self::YMM11), + 380 => Ok(Self::YMM12), + 381 => Ok(Self::YMM13), + 382 => Ok(Self::YMM14), + 383 => Ok(Self::YMM15), + 384 => Ok(Self::YMM0H), + 385 => Ok(Self::YMM1H), + 386 => Ok(Self::YMM2H), + 387 => Ok(Self::YMM3H), + 388 => Ok(Self::YMM4H), + 389 => Ok(Self::YMM5H), + 390 => Ok(Self::YMM6H), + 391 => Ok(Self::YMM7H), + 392 => Ok(Self::YMM8H), + 393 => Ok(Self::YMM9H), + 394 => Ok(Self::YMM10H), + 395 => Ok(Self::YMM11H), + 396 => Ok(Self::YMM12H), + 397 => Ok(Self::YMM13H), + 398 => Ok(Self::YMM14H), + 399 => Ok(Self::YMM15H), + 400 => Ok(Self::XMM0IL), + 401 => Ok(Self::XMM1IL), + 402 => Ok(Self::XMM2IL), + 403 => Ok(Self::XMM3IL), + 404 => Ok(Self::XMM4IL), + 405 => Ok(Self::XMM5IL), + 406 => Ok(Self::XMM6IL), + 407 => Ok(Self::XMM7IL), + 408 => Ok(Self::XMM8IL), + 409 => Ok(Self::XMM9IL), + 410 => Ok(Self::XMM10IL), + 411 => Ok(Self::XMM11IL), + 412 => Ok(Self::XMM12IL), + 413 => Ok(Self::XMM13IL), + 414 => Ok(Self::XMM14IL), + 415 => Ok(Self::XMM15IL), + 416 => Ok(Self::XMM0IH), + 417 => Ok(Self::XMM1IH), + 418 => Ok(Self::XMM2IH), + 419 => Ok(Self::XMM3IH), + 420 => Ok(Self::XMM4IH), + 421 => Ok(Self::XMM5IH), + 422 => Ok(Self::XMM6IH), + 423 => Ok(Self::XMM7IH), + 424 => Ok(Self::XMM8IH), + 425 => Ok(Self::XMM9IH), + 426 => Ok(Self::XMM10IH), + 427 => Ok(Self::XMM11IH), + 428 => Ok(Self::XMM12IH), + 429 => Ok(Self::XMM13IH), + 430 => Ok(Self::XMM14IH), + 431 => Ok(Self::XMM15IH), + 432 => Ok(Self::YMM0I0), + 433 => Ok(Self::YMM0I1), + 434 => Ok(Self::YMM0I2), + 435 => Ok(Self::YMM0I3), + 436 => Ok(Self::YMM1I0), + 437 => Ok(Self::YMM1I1), + 438 => Ok(Self::YMM1I2), + 439 => Ok(Self::YMM1I3), + 440 => Ok(Self::YMM2I0), + 441 => Ok(Self::YMM2I1), + 442 => Ok(Self::YMM2I2), + 443 => Ok(Self::YMM2I3), + 444 => Ok(Self::YMM3I0), + 445 => Ok(Self::YMM3I1), + 446 => Ok(Self::YMM3I2), + 447 => Ok(Self::YMM3I3), + 448 => Ok(Self::YMM4I0), + 449 => Ok(Self::YMM4I1), + 450 => Ok(Self::YMM4I2), + 451 => Ok(Self::YMM4I3), + 452 => Ok(Self::YMM5I0), + 453 => Ok(Self::YMM5I1), + 454 => Ok(Self::YMM5I2), + 455 => Ok(Self::YMM5I3), + 456 => Ok(Self::YMM6I0), + 457 => Ok(Self::YMM6I1), + 458 => Ok(Self::YMM6I2), + 459 => Ok(Self::YMM6I3), + 460 => Ok(Self::YMM7I0), + 461 => Ok(Self::YMM7I1), + 462 => Ok(Self::YMM7I2), + 463 => Ok(Self::YMM7I3), + 464 => Ok(Self::YMM8I0), + 465 => Ok(Self::YMM8I1), + 466 => Ok(Self::YMM8I2), + 467 => Ok(Self::YMM8I3), + 468 => Ok(Self::YMM9I0), + 469 => Ok(Self::YMM9I1), + 470 => Ok(Self::YMM9I2), + 471 => Ok(Self::YMM9I3), + 472 => Ok(Self::YMM10I0), + 473 => Ok(Self::YMM10I1), + 474 => Ok(Self::YMM10I2), + 475 => Ok(Self::YMM10I3), + 476 => Ok(Self::YMM11I0), + 477 => Ok(Self::YMM11I1), + 478 => Ok(Self::YMM11I2), + 479 => Ok(Self::YMM11I3), + 480 => Ok(Self::YMM12I0), + 481 => Ok(Self::YMM12I1), + 482 => Ok(Self::YMM12I2), + 483 => Ok(Self::YMM12I3), + 484 => Ok(Self::YMM13I0), + 485 => Ok(Self::YMM13I1), + 486 => Ok(Self::YMM13I2), + 487 => Ok(Self::YMM13I3), + 488 => Ok(Self::YMM14I0), + 489 => Ok(Self::YMM14I1), + 490 => Ok(Self::YMM14I2), + 491 => Ok(Self::YMM14I3), + 492 => Ok(Self::YMM15I0), + 493 => Ok(Self::YMM15I1), + 494 => Ok(Self::YMM15I2), + 495 => Ok(Self::YMM15I3), + 496 => Ok(Self::YMM0F0), + 497 => Ok(Self::YMM0F1), + 498 => Ok(Self::YMM0F2), + 499 => Ok(Self::YMM0F3), + 500 => Ok(Self::YMM0F4), + 501 => Ok(Self::YMM0F5), + 502 => Ok(Self::YMM0F6), + 503 => Ok(Self::YMM0F7), + 504 => Ok(Self::YMM1F0), + 505 => Ok(Self::YMM1F1), + 506 => Ok(Self::YMM1F2), + 507 => Ok(Self::YMM1F3), + 508 => Ok(Self::YMM1F4), + 509 => Ok(Self::YMM1F5), + 510 => Ok(Self::YMM1F6), + 511 => Ok(Self::YMM1F7), + 512 => Ok(Self::YMM2F0), + 513 => Ok(Self::YMM2F1), + 514 => Ok(Self::YMM2F2), + 515 => Ok(Self::YMM2F3), + 516 => Ok(Self::YMM2F4), + 517 => Ok(Self::YMM2F5), + 518 => Ok(Self::YMM2F6), + 519 => Ok(Self::YMM2F7), + 520 => Ok(Self::YMM3F0), + 521 => Ok(Self::YMM3F1), + 522 => Ok(Self::YMM3F2), + 523 => Ok(Self::YMM3F3), + 524 => Ok(Self::YMM3F4), + 525 => Ok(Self::YMM3F5), + 526 => Ok(Self::YMM3F6), + 527 => Ok(Self::YMM3F7), + 528 => Ok(Self::YMM4F0), + 529 => Ok(Self::YMM4F1), + 530 => Ok(Self::YMM4F2), + 531 => Ok(Self::YMM4F3), + 532 => Ok(Self::YMM4F4), + 533 => Ok(Self::YMM4F5), + 534 => Ok(Self::YMM4F6), + 535 => Ok(Self::YMM4F7), + 536 => Ok(Self::YMM5F0), + 537 => Ok(Self::YMM5F1), + 538 => Ok(Self::YMM5F2), + 539 => Ok(Self::YMM5F3), + 540 => Ok(Self::YMM5F4), + 541 => Ok(Self::YMM5F5), + 542 => Ok(Self::YMM5F6), + 543 => Ok(Self::YMM5F7), + 544 => Ok(Self::YMM6F0), + 545 => Ok(Self::YMM6F1), + 546 => Ok(Self::YMM6F2), + 547 => Ok(Self::YMM6F3), + 548 => Ok(Self::YMM6F4), + 549 => Ok(Self::YMM6F5), + 550 => Ok(Self::YMM6F6), + 551 => Ok(Self::YMM6F7), + 552 => Ok(Self::YMM7F0), + 553 => Ok(Self::YMM7F1), + 554 => Ok(Self::YMM7F2), + 555 => Ok(Self::YMM7F3), + 556 => Ok(Self::YMM7F4), + 557 => Ok(Self::YMM7F5), + 558 => Ok(Self::YMM7F6), + 559 => Ok(Self::YMM7F7), + 560 => Ok(Self::YMM8F0), + 561 => Ok(Self::YMM8F1), + 562 => Ok(Self::YMM8F2), + 563 => Ok(Self::YMM8F3), + 564 => Ok(Self::YMM8F4), + 565 => Ok(Self::YMM8F5), + 566 => Ok(Self::YMM8F6), + 567 => Ok(Self::YMM8F7), + 568 => Ok(Self::YMM9F0), + 569 => Ok(Self::YMM9F1), + 570 => Ok(Self::YMM9F2), + 571 => Ok(Self::YMM9F3), + 572 => Ok(Self::YMM9F4), + 573 => Ok(Self::YMM9F5), + 574 => Ok(Self::YMM9F6), + 575 => Ok(Self::YMM9F7), + 576 => Ok(Self::YMM10F0), + 577 => Ok(Self::YMM10F1), + 578 => Ok(Self::YMM10F2), + 579 => Ok(Self::YMM10F3), + 580 => Ok(Self::YMM10F4), + 581 => Ok(Self::YMM10F5), + 582 => Ok(Self::YMM10F6), + 583 => Ok(Self::YMM10F7), + 584 => Ok(Self::YMM11F0), + 585 => Ok(Self::YMM11F1), + 586 => Ok(Self::YMM11F2), + 587 => Ok(Self::YMM11F3), + 588 => Ok(Self::YMM11F4), + 589 => Ok(Self::YMM11F5), + 590 => Ok(Self::YMM11F6), + 591 => Ok(Self::YMM11F7), + 592 => Ok(Self::YMM12F0), + 593 => Ok(Self::YMM12F1), + 594 => Ok(Self::YMM12F2), + 595 => Ok(Self::YMM12F3), + 596 => Ok(Self::YMM12F4), + 597 => Ok(Self::YMM12F5), + 598 => Ok(Self::YMM12F6), + 599 => Ok(Self::YMM12F7), + 600 => Ok(Self::YMM13F0), + 601 => Ok(Self::YMM13F1), + 602 => Ok(Self::YMM13F2), + 603 => Ok(Self::YMM13F3), + 604 => Ok(Self::YMM13F4), + 605 => Ok(Self::YMM13F5), + 606 => Ok(Self::YMM13F6), + 607 => Ok(Self::YMM13F7), + 608 => Ok(Self::YMM14F0), + 609 => Ok(Self::YMM14F1), + 610 => Ok(Self::YMM14F2), + 611 => Ok(Self::YMM14F3), + 612 => Ok(Self::YMM14F4), + 613 => Ok(Self::YMM14F5), + 614 => Ok(Self::YMM14F6), + 615 => Ok(Self::YMM14F7), + 616 => Ok(Self::YMM15F0), + 617 => Ok(Self::YMM15F1), + 618 => Ok(Self::YMM15F2), + 619 => Ok(Self::YMM15F3), + 620 => Ok(Self::YMM15F4), + 621 => Ok(Self::YMM15F5), + 622 => Ok(Self::YMM15F6), + 623 => Ok(Self::YMM15F7), + 624 => Ok(Self::YMM0D0), + 625 => Ok(Self::YMM0D1), + 626 => Ok(Self::YMM0D2), + 627 => Ok(Self::YMM0D3), + 628 => Ok(Self::YMM1D0), + 629 => Ok(Self::YMM1D1), + 630 => Ok(Self::YMM1D2), + 631 => Ok(Self::YMM1D3), + 632 => Ok(Self::YMM2D0), + 633 => Ok(Self::YMM2D1), + 634 => Ok(Self::YMM2D2), + 635 => Ok(Self::YMM2D3), + 636 => Ok(Self::YMM3D0), + 637 => Ok(Self::YMM3D1), + 638 => Ok(Self::YMM3D2), + 639 => Ok(Self::YMM3D3), + 640 => Ok(Self::YMM4D0), + 641 => Ok(Self::YMM4D1), + 642 => Ok(Self::YMM4D2), + 643 => Ok(Self::YMM4D3), + 644 => Ok(Self::YMM5D0), + 645 => Ok(Self::YMM5D1), + 646 => Ok(Self::YMM5D2), + 647 => Ok(Self::YMM5D3), + 648 => Ok(Self::YMM6D0), + 649 => Ok(Self::YMM6D1), + 650 => Ok(Self::YMM6D2), + 651 => Ok(Self::YMM6D3), + 652 => Ok(Self::YMM7D0), + 653 => Ok(Self::YMM7D1), + 654 => Ok(Self::YMM7D2), + 655 => Ok(Self::YMM7D3), + 656 => Ok(Self::YMM8D0), + 657 => Ok(Self::YMM8D1), + 658 => Ok(Self::YMM8D2), + 659 => Ok(Self::YMM8D3), + 660 => Ok(Self::YMM9D0), + 661 => Ok(Self::YMM9D1), + 662 => Ok(Self::YMM9D2), + 663 => Ok(Self::YMM9D3), + 664 => Ok(Self::YMM10D0), + 665 => Ok(Self::YMM10D1), + 666 => Ok(Self::YMM10D2), + 667 => Ok(Self::YMM10D3), + 668 => Ok(Self::YMM11D0), + 669 => Ok(Self::YMM11D1), + 670 => Ok(Self::YMM11D2), + 671 => Ok(Self::YMM11D3), + 672 => Ok(Self::YMM12D0), + 673 => Ok(Self::YMM12D1), + 674 => Ok(Self::YMM12D2), + 675 => Ok(Self::YMM12D3), + 676 => Ok(Self::YMM13D0), + 677 => Ok(Self::YMM13D1), + 678 => Ok(Self::YMM13D2), + 679 => Ok(Self::YMM13D3), + 680 => Ok(Self::YMM14D0), + 681 => Ok(Self::YMM14D1), + 682 => Ok(Self::YMM14D2), + 683 => Ok(Self::YMM14D3), + 684 => Ok(Self::YMM15D0), + 685 => Ok(Self::YMM15D1), + 686 => Ok(Self::YMM15D2), + 687 => Ok(Self::YMM15D3), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for AMD64Register { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} + +/// HLSL registers +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum HLSLRegister { + TEMP = 0, + INPUT = 1, + OUTPUT = 2, + INDEXABLE_TEMP = 3, + IMMEDIATE32 = 4, + IMMEDIATE64 = 5, + SAMPLER = 6, + RESOURCE = 7, + CONSTANT_BUFFER = 8, + IMMEDIATE_CONSTANT_BUFFER = 9, + LABEL = 10, + INPUT_PRIMITIVEID = 11, + OUTPUT_DEPTH = 12, + NULL = 13, + RASTERIZER = 14, + OUTPUT_COVERAGE_MASK = 15, + STREAM = 16, + FUNCTION_BODY = 17, + FUNCTION_TABLE = 18, + INTERFACE = 19, + FUNCTION_INPUT = 20, + FUNCTION_OUTPUT = 21, + OUTPUT_CONTROL_POINT_ID = 22, + INPUT_FORK_INSTANCE_ID = 23, + INPUT_JOIN_INSTANCE_ID = 24, + INPUT_CONTROL_POINT = 25, + OUTPUT_CONTROL_POINT = 26, + INPUT_PATCH_CONSTANT = 27, + INPUT_DOMAIN_POINT = 28, + THIS_POINTER = 29, + UNORDERED_ACCESS_VIEW = 30, + THREAD_GROUP_SHARED_MEMORY = 31, + INPUT_THREAD_ID = 32, + INPUT_THREAD_GROUP_ID = 33, + INPUT_THREAD_ID_IN_GROUP = 34, + INPUT_COVERAGE_MASK = 35, + INPUT_THREAD_ID_IN_GROUP_FLATTENED = 36, + INPUT_GS_INSTANCE_ID = 37, + OUTPUT_DEPTH_GREATER_EQUAL = 38, + OUTPUT_DEPTH_LESS_EQUAL = 39, + CYCLE_COUNTER = 40, +} + +impl fmt::Display for HLSLRegister { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::TEMP => write!(f, "TEMP"), + Self::INPUT => write!(f, "INPUT"), + Self::OUTPUT => write!(f, "OUTPUT"), + Self::INDEXABLE_TEMP => write!(f, "INDEXABLE_TEMP"), + Self::IMMEDIATE32 => write!(f, "IMMEDIATE32"), + Self::IMMEDIATE64 => write!(f, "IMMEDIATE64"), + Self::SAMPLER => write!(f, "SAMPLER"), + Self::RESOURCE => write!(f, "RESOURCE"), + Self::CONSTANT_BUFFER => write!(f, "CONSTANT_BUFFER"), + Self::IMMEDIATE_CONSTANT_BUFFER => write!(f, "IMMEDIATE_CONSTANT_BUFFER"), + Self::LABEL => write!(f, "LABEL"), + Self::INPUT_PRIMITIVEID => write!(f, "INPUT_PRIMITIVEID"), + Self::OUTPUT_DEPTH => write!(f, "OUTPUT_DEPTH"), + Self::NULL => write!(f, "NULL"), + Self::RASTERIZER => write!(f, "RASTERIZER"), + Self::OUTPUT_COVERAGE_MASK => write!(f, "OUTPUT_COVERAGE_MASK"), + Self::STREAM => write!(f, "STREAM"), + Self::FUNCTION_BODY => write!(f, "FUNCTION_BODY"), + Self::FUNCTION_TABLE => write!(f, "FUNCTION_TABLE"), + Self::INTERFACE => write!(f, "INTERFACE"), + Self::FUNCTION_INPUT => write!(f, "FUNCTION_INPUT"), + Self::FUNCTION_OUTPUT => write!(f, "FUNCTION_OUTPUT"), + Self::OUTPUT_CONTROL_POINT_ID => write!(f, "OUTPUT_CONTROL_POINT_ID"), + Self::INPUT_FORK_INSTANCE_ID => write!(f, "INPUT_FORK_INSTANCE_ID"), + Self::INPUT_JOIN_INSTANCE_ID => write!(f, "INPUT_JOIN_INSTANCE_ID"), + Self::INPUT_CONTROL_POINT => write!(f, "INPUT_CONTROL_POINT"), + Self::OUTPUT_CONTROL_POINT => write!(f, "OUTPUT_CONTROL_POINT"), + Self::INPUT_PATCH_CONSTANT => write!(f, "INPUT_PATCH_CONSTANT"), + Self::INPUT_DOMAIN_POINT => write!(f, "INPUT_DOMAIN_POINT"), + Self::THIS_POINTER => write!(f, "THIS_POINTER"), + Self::UNORDERED_ACCESS_VIEW => write!(f, "UNORDERED_ACCESS_VIEW"), + Self::THREAD_GROUP_SHARED_MEMORY => write!(f, "THREAD_GROUP_SHARED_MEMORY"), + Self::INPUT_THREAD_ID => write!(f, "INPUT_THREAD_ID"), + Self::INPUT_THREAD_GROUP_ID => write!(f, "INPUT_THREAD_GROUP_ID"), + Self::INPUT_THREAD_ID_IN_GROUP => write!(f, "INPUT_THREAD_ID_IN_GROUP"), + Self::INPUT_COVERAGE_MASK => write!(f, "INPUT_COVERAGE_MASK"), + Self::INPUT_THREAD_ID_IN_GROUP_FLATTENED => { + write!(f, "INPUT_THREAD_ID_IN_GROUP_FLATTENED") + } + Self::INPUT_GS_INSTANCE_ID => write!(f, "INPUT_GS_INSTANCE_ID"), + Self::OUTPUT_DEPTH_GREATER_EQUAL => write!(f, "OUTPUT_DEPTH_GREATER_EQUAL"), + Self::OUTPUT_DEPTH_LESS_EQUAL => write!(f, "OUTPUT_DEPTH_LESS_EQUAL"), + Self::CYCLE_COUNTER => write!(f, "CYCLE_COUNTER"), + } + } +} + +impl TryFrom for HLSLRegister { + type Error = Error; + + fn try_from(value: u16) -> Result { + match value { + 0 => Ok(Self::TEMP), + 1 => Ok(Self::INPUT), + 2 => Ok(Self::OUTPUT), + 3 => Ok(Self::INDEXABLE_TEMP), + 4 => Ok(Self::IMMEDIATE32), + 5 => Ok(Self::IMMEDIATE64), + 6 => Ok(Self::SAMPLER), + 7 => Ok(Self::RESOURCE), + 8 => Ok(Self::CONSTANT_BUFFER), + 9 => Ok(Self::IMMEDIATE_CONSTANT_BUFFER), + 10 => Ok(Self::LABEL), + 11 => Ok(Self::INPUT_PRIMITIVEID), + 12 => Ok(Self::OUTPUT_DEPTH), + 13 => Ok(Self::NULL), + 14 => Ok(Self::RASTERIZER), + 15 => Ok(Self::OUTPUT_COVERAGE_MASK), + 16 => Ok(Self::STREAM), + 17 => Ok(Self::FUNCTION_BODY), + 18 => Ok(Self::FUNCTION_TABLE), + 19 => Ok(Self::INTERFACE), + 20 => Ok(Self::FUNCTION_INPUT), + 21 => Ok(Self::FUNCTION_OUTPUT), + 22 => Ok(Self::OUTPUT_CONTROL_POINT_ID), + 23 => Ok(Self::INPUT_FORK_INSTANCE_ID), + 24 => Ok(Self::INPUT_JOIN_INSTANCE_ID), + 25 => Ok(Self::INPUT_CONTROL_POINT), + 26 => Ok(Self::OUTPUT_CONTROL_POINT), + 27 => Ok(Self::INPUT_PATCH_CONSTANT), + 28 => Ok(Self::INPUT_DOMAIN_POINT), + 29 => Ok(Self::THIS_POINTER), + 30 => Ok(Self::UNORDERED_ACCESS_VIEW), + 31 => Ok(Self::THREAD_GROUP_SHARED_MEMORY), + 32 => Ok(Self::INPUT_THREAD_ID), + 33 => Ok(Self::INPUT_THREAD_GROUP_ID), + 34 => Ok(Self::INPUT_THREAD_ID_IN_GROUP), + 35 => Ok(Self::INPUT_COVERAGE_MASK), + 36 => Ok(Self::INPUT_THREAD_ID_IN_GROUP_FLATTENED), + 37 => Ok(Self::INPUT_GS_INSTANCE_ID), + 38 => Ok(Self::OUTPUT_DEPTH_GREATER_EQUAL), + 39 => Ok(Self::OUTPUT_DEPTH_LESS_EQUAL), + 40 => Ok(Self::CYCLE_COUNTER), + _ => Err(UnknownRegister(value)), + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for HLSLRegister { + type Error = Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> Result<(Self, usize)> { + let (v, l) = u16::try_from_ctx(this, le)?; + Ok((v.try_into()?, l)) + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/source.rs b/plugins/pdb-ng/vendor/pdb-rs/src/source.rs new file mode 100644 index 0000000000..69dae13e78 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/source.rs @@ -0,0 +1,202 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::fmt; +use std::io; + +/// Represents an offset + size of the source file. +/// +/// The multi-stream file implementation (used by `pdb::PDB`) determines which byte ranges it needs +/// to satisfy its requests, and it describes those requests as a `&[SourceSlice]`. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub struct SourceSlice { + /// Offset into the source file. + pub offset: u64, + /// Size of the slice. + pub size: usize, +} + +/// The `pdb` crate accesses PDB files via the `pdb::Source` trait. +/// +/// This library is written with zero-copy in mind. `Source`s provide [`SourceView`]s which need not +/// outlive their parent, supporting implementations of e.g. memory mapped files. +/// +/// PDB files are "multi-stream files" (MSF) under the hood. MSFs have various layers of +/// indirection, but ultimately the MSF code asks a `Source` to view a series of +/// [`{ offset, size }` records](SourceSlice), which the `Source` provides as a +/// contiguous `&[u8]`. +/// +/// # Default +/// +/// There is a default `Source` implementation for `std::io::Read` + `std::io::Seek` + +/// `std::fmt::Debug`, allowing a `std::fs::File` to be treated as `pdb::Source`. This +/// implementation provides views by allocating a buffer, seeking, and reading the contents into +/// that buffer. +/// +/// # Alignment +/// +/// The requested offsets will always be aligned to the MSF's page size, which is always a power of +/// two and is usually (but not always) 4096 bytes. The requested sizes will also be multiples of +/// the page size, except for the size of the final `SourceSlice`, which may be smaller. +/// +/// PDB files are specified as always being a multiple of the page size, so `Source` implementations +/// are free to e.g. map whole pages and return a sub-slice of the requested length. +/// +pub trait Source<'s>: fmt::Debug { + /// Provides a contiguous view of the source file composed of the requested position(s). + /// + /// Note that the SourceView's as_slice() method cannot fail, so `view()` is the time to raise + /// IO errors. + fn view(&mut self, slices: &[SourceSlice]) -> Result>, io::Error>; +} + +/// An owned, droppable, read-only view of the source file which can be referenced as a byte slice. +pub trait SourceView<'s>: fmt::Debug { + /// Returns a view to the raw data. + fn as_slice(&self) -> &[u8]; +} + +#[derive(Clone)] +struct ReadView { + bytes: Vec, +} + +impl fmt::Debug for ReadView { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ReadView({} bytes)", self.bytes.len()) + } +} + +impl SourceView<'_> for ReadView { + fn as_slice(&self) -> &[u8] { + self.bytes.as_slice() + } +} + +impl<'s, T> Source<'s> for T +where + T: io::Read + io::Seek + fmt::Debug + 's, +{ + fn view(&mut self, slices: &[SourceSlice]) -> Result>, io::Error> { + let len = slices.iter().fold(0, |acc, s| acc + s.size); + + let mut v = ReadView { + bytes: Vec::with_capacity(len), + }; + v.bytes.resize(len, 0); + + { + let bytes = v.bytes.as_mut_slice(); + let mut output_offset: usize = 0; + for slice in slices { + self.seek(io::SeekFrom::Start(slice.offset))?; + self.read_exact(&mut bytes[output_offset..(output_offset + slice.size)])?; + output_offset += slice.size; + } + } + + Ok(Box::new(v)) + } +} + +#[cfg(test)] +mod tests { + mod read_view { + use crate::source::*; + use std::io::Cursor; + use std::io::ErrorKind; + + #[test] + fn test_basic_reading() { + let mut data = vec![0; 4096]; + data[42] = 42; + + let mut source: Box> = Box::new(Cursor::new(data.as_slice())); + + let source_slices = vec![SourceSlice { + offset: 40, + size: 4, + }]; + let view = source + .view(source_slices.as_slice()) + .expect("viewing must succeed"); + assert_eq!(&[0u8, 0, 42, 0], view.as_slice()); + } + + #[test] + fn test_discontinuous_reading() { + let mut data = vec![0; 4096]; + data[42] = 42; + data[88] = 88; + + let mut source: Box> = Box::new(Cursor::new(data.as_slice())); + + let source_slices = vec![ + SourceSlice { + offset: 88, + size: 1, + }, + SourceSlice { + offset: 40, + size: 4, + }, + ]; + let view = source + .view(source_slices.as_slice()) + .expect("viewing must succeed"); + assert_eq!(&[88u8, 0, 0, 42, 0], view.as_slice()); + } + + #[test] + fn test_duplicate_reading() { + let mut data = vec![0; 4096]; + data[42] = 42; + data[88] = 88; + + let mut source: Box> = Box::new(Cursor::new(data.as_slice())); + + let source_slices = vec![ + SourceSlice { + offset: 88, + size: 1, + }, + SourceSlice { + offset: 40, + size: 4, + }, + SourceSlice { + offset: 88, + size: 1, + }, + ]; + let view = source + .view(source_slices.as_slice()) + .expect("viewing must succeed"); + assert_eq!(&[88u8, 0, 0, 42, 0, 88], view.as_slice()); + } + + #[test] + fn test_eof_reading() { + let data = vec![0; 4096]; + + let mut source: Box> = Box::new(Cursor::new(data.as_slice())); + + // one byte is readable, but we asked for two + let source_slices = vec![SourceSlice { + offset: 4095, + size: 2, + }]; + let r = source.view(source_slices.as_slice()); + match r { + Ok(_) => panic!("should have failed"), + Err(e) => { + assert_eq!(ErrorKind::UnexpectedEof, e.kind()); + } + } + } + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/strings.rs b/plugins/pdb-ng/vendor/pdb-rs/src/strings.rs new file mode 100644 index 0000000000..2a110448ae --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/strings.rs @@ -0,0 +1,170 @@ +use std::borrow::Cow; + +use scroll::{ctx::TryFromCtx, Endian, Pread}; + +use crate::common::*; +use crate::msf::Stream; + +/// Magic bytes identifying the string name table. +/// +/// This value is declared as `NMT::verHdr` in `nmt.h`. +const PDB_NMT_HDR: u32 = 0xEFFE_EFFE; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum StringTableHashVersion { + /// Default hash method used for reverse string lookups. + /// + /// The hash function has originally been defined in `LHashPbCb`. + LongHash = 1, + + /// Revised hash method used for reverse string lookups. + /// + /// The hash function has originally been defined in `LHashPbCbV2`. + LongHashV2 = 2, +} + +impl StringTableHashVersion { + fn parse_u32(value: u32) -> Result { + match value { + 1 => Ok(Self::LongHash), + 2 => Ok(Self::LongHashV2), + _ => Err(Error::UnimplementedFeature( + "unknown string table hash version", + )), + } + } +} + +/// Raw header of the string table stream. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +struct StringTableHeader { + /// Magic bytes of the string table. + magic: u32, + /// Version of the hash table after the names. + hash_version: u32, + /// The size of all names in bytes. + names_size: u32, +} + +impl<'t> TryFromCtx<'t, Endian> for StringTableHeader { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let mut offset = 0; + let data = Self { + magic: this.gread_with(&mut offset, le)?, + hash_version: this.gread_with(&mut offset, le)?, + names_size: this.gread_with(&mut offset, le)?, + }; + Ok((data, offset)) + } +} + +impl StringTableHeader { + /// Start index of the names buffer in the string table stream. + fn names_start(self) -> usize { + std::mem::size_of::() + } + + /// End index of the names buffer in the string table stream. + fn names_end(self) -> usize { + self.names_start() + self.names_size as usize + } +} + +/// The global string table of a PDB. +/// +/// The string table is a two-way mapping from offset to string and back. It can be used to resolve +/// [`StringRef`] offsets to their string values. Sometimes, it is also referred to as "Name table". +/// The mapping from string to offset has not been implemented yet. +/// +/// Use [`PDB::string_table`](crate::PDB::string_table) to obtain an instance. +#[derive(Debug)] +pub struct StringTable<'s> { + header: StringTableHeader, + #[allow(dead_code)] // reason = "reverse-lookups through hash table not implemented" + hash_version: StringTableHashVersion, + stream: Stream<'s>, +} + +impl<'s> StringTable<'s> { + pub(crate) fn parse(stream: Stream<'s>) -> Result { + let mut buf = stream.parse_buffer(); + let header = buf.parse::()?; + + if header.magic != PDB_NMT_HDR { + return Err(Error::UnimplementedFeature( + "invalid string table signature", + )); + } + + // The string table should at least contain all names as C-strings. Their combined size is + // declared in the `names_size` header field. + if buf.len() < header.names_end() { + return Err(Error::UnexpectedEof); + } + + let hash_version = StringTableHashVersion::parse_u32(header.hash_version)?; + + // After the name buffer, the stream contains a closed hash table for reverse mapping. From + // the original header file (`nmi.h`): + // + // Strings are mapped into name indices using a closed hash table of NIs. + // To find a string, we hash it and probe into the table, and compare the + // string against each successive ni's name until we hit or find an empty + // hash table entry. + + Ok(StringTable { + header, + hash_version, + stream, + }) + } +} + +impl<'s> StringTable<'s> { + /// Resolves a string value from this string table. + /// + /// Errors if the offset is out of bounds, otherwise returns the raw binary string value. + pub fn get(&self, offset: StringRef) -> Result> { + if offset.0 >= self.header.names_size { + return Err(Error::UnexpectedEof); + } + + let string_offset = self.header.names_start() + offset.0 as usize; + let data = &self.stream.as_slice()[string_offset..self.header.names_end()]; + ParseBuffer::from(data).parse_cstring() + } +} + +impl StringRef { + /// Resolves the raw string value of this reference. + /// + /// This method errors if the offset is out of bounds of the string table. Use + /// [`PDB::string_table`](crate::PDB::string_table) to obtain an instance of the string table. + pub fn to_raw_string<'s>(self, strings: &'s StringTable<'_>) -> Result> { + strings.get(self) + } + + /// Resolves and decodes the UTF-8 string value of this reference. + /// + /// This method errors if the offset is out of bounds of the string table. Use + /// [`PDB::string_table`](crate::PDB::string_table) to obtain an instance of the string table. + pub fn to_string_lossy<'s>(self, strings: &'s StringTable<'_>) -> Result> { + strings.get(self).map(|r| r.to_string()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use std::mem; + + #[test] + fn test_string_table_header() { + assert_eq!(mem::size_of::(), 12); + assert_eq!(mem::align_of::(), 4); + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/symbol/annotations.rs b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/annotations.rs new file mode 100644 index 0000000000..508db4d415 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/annotations.rs @@ -0,0 +1,312 @@ +use crate::common::*; +use crate::FallibleIterator; + +/// These values correspond to the BinaryAnnotationOpcode enum from the +/// cvinfo.h +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum BinaryAnnotationOpcode { + /// Link time pdb contains PADDINGs. + /// + /// These are represented with the 0 opcode which is in some PDB + /// implementation called "invalid". + Eof = 0, + /// param : start offset + CodeOffset = 1, + /// param : nth separated code chunk (main code chunk == 0) + ChangeCodeOffsetBase = 2, + /// param : delta of offset + ChangeCodeOffset = 3, + /// param : length of code, default next start + ChangeCodeLength = 4, + /// param : fileId + ChangeFile = 5, + /// param : line offset (signed) + ChangeLineOffset = 6, + /// param : how many lines, default 1 + ChangeLineEndDelta = 7, + /// param : either 1 (default, for statement) + /// or 0 (for expression) + ChangeRangeKind = 8, + /// param : start column number, 0 means no column info + ChangeColumnStart = 9, + /// param : end column number delta (signed) + ChangeColumnEndDelta = 10, + /// param : ((sourceDelta << 4) | CodeDelta) + ChangeCodeOffsetAndLineOffset = 11, + /// param : codeLength, codeOffset + ChangeCodeLengthAndCodeOffset = 12, + /// param : end column number + ChangeColumnEnd = 13, +} + +impl BinaryAnnotationOpcode { + fn parse(value: u32) -> Result { + Ok(match value { + 0 => Self::Eof, + 1 => Self::CodeOffset, + 2 => Self::ChangeCodeOffsetBase, + 3 => Self::ChangeCodeOffset, + 4 => Self::ChangeCodeLength, + 5 => Self::ChangeFile, + 6 => Self::ChangeLineOffset, + 7 => Self::ChangeLineEndDelta, + 8 => Self::ChangeRangeKind, + 9 => Self::ChangeColumnStart, + 10 => Self::ChangeColumnEndDelta, + 11 => Self::ChangeCodeOffsetAndLineOffset, + 12 => Self::ChangeCodeLengthAndCodeOffset, + 13 => Self::ChangeColumnEnd, + _ => return Err(Error::UnknownBinaryAnnotation(value)), + }) + } +} + +/// Represents a parsed `BinaryAnnotation`. +/// +/// Binary annotations are used by `S_INLINESITE` to encode opcodes for how to +/// evaluate the state changes for inline information. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BinaryAnnotation { + /// Sets the code offset to the given absolute value. + CodeOffset(u32), + /// Sets the base for all code offsets to the given absolute value. All following code offsets + /// are relative to this base value. + ChangeCodeOffsetBase(u32), + /// **Emitting**. Advances the code offset by the given value. + /// + /// This annotation emits a line record. The length of the covered code block can be established + /// by a following `ChangeCodeLength` annotation, or by the offset of the next emitted record. + ChangeCodeOffset(u32), + /// Adjusts the code length of the previously emitted line record. The code length resets with + /// every line record. + ChangeCodeLength(u32), + /// Sets the file index of following line records. + ChangeFile(FileIndex), + /// Advances the line number by the given value. + ChangeLineOffset(i32), + /// Sets the number of source lines covered by following line records. Defaults to `1`. + ChangeLineEndDelta(u32), + /// Sets the kind of the line record. Defaults to `Statement`. + ChangeRangeKind(u32), + /// Sets the start column number. Defaults to `None`. + ChangeColumnStart(u32), + /// Advances the end column number by the given value. + ChangeColumnEndDelta(i32), + /// **Emitting**. Advances the code offset and the line number by the given values. + /// + /// This annotation emits a line record. The length of the covered code block can be established + /// by a following `ChangeCodeLength` annotation, or by the offset of the next emitted record. + ChangeCodeOffsetAndLineOffset(u32, i32), + /// **Emitting**. Sets the code length and advances the code offset by the given value. + /// + /// This annotation emits a line record that is valid for the given code length. This is usually + /// issued as one of the last annotations, as there is no subsequent line record to derive the + /// code length from. + ChangeCodeLengthAndCodeOffset(u32, u32), + /// Sets the end column number. + ChangeColumnEnd(u32), +} + +impl BinaryAnnotation { + /// Does this annotation emit a line info? + pub fn emits_line_info(self) -> bool { + matches!( + self, + BinaryAnnotation::ChangeCodeOffset(..) + | BinaryAnnotation::ChangeCodeOffsetAndLineOffset(..) + | BinaryAnnotation::ChangeCodeLengthAndCodeOffset(..) + ) + } +} + +/// An iterator over binary annotations used by `S_INLINESITE`. +#[derive(Clone, Debug, Default)] +pub struct BinaryAnnotationsIter<'t> { + buffer: ParseBuffer<'t>, +} + +impl<'t> BinaryAnnotationsIter<'t> { + /// Parse a compact version of an unsigned integer. + /// + /// This implements `CVUncompressData`, which can decode numbers no larger than 0x1FFFFFFF. It + /// seems that values compressed this way are only used for binary annotations at this point. + fn uncompress_next(&mut self) -> Result { + let b1 = u32::from(self.buffer.parse::()?); + if (b1 & 0x80) == 0x00 { + let value = b1; + return Ok(value); + } + + let b2 = u32::from(self.buffer.parse::()?); + if (b1 & 0xc0) == 0x80 { + let value = (b1 & 0x3f) << 8 | b2; + return Ok(value); + } + + let b3 = u32::from(self.buffer.parse::()?); + let b4 = u32::from(self.buffer.parse::()?); + if (b1 & 0xe0) == 0xc0 { + let value = ((b1 & 0x1f) << 24) | (b2 << 16) | (b3 << 8) | b4; + return Ok(value); + } + + Err(Error::InvalidCompressedAnnotation) + } +} + +/// Resembles `DecodeSignedInt32`. +fn decode_signed_operand(value: u32) -> i32 { + if value & 1 != 0 { + -((value >> 1) as i32) + } else { + (value >> 1) as i32 + } +} + +impl<'t> FallibleIterator for BinaryAnnotationsIter<'t> { + type Item = BinaryAnnotation; + type Error = Error; + + fn next(&mut self) -> Result> { + if self.buffer.is_empty() { + return Ok(None); + } + + let op = self.uncompress_next()?; + let annotation = match BinaryAnnotationOpcode::parse(op)? { + BinaryAnnotationOpcode::Eof => { + // This makes the end of the stream + self.buffer = ParseBuffer::default(); + return Ok(None); + } + BinaryAnnotationOpcode::CodeOffset => { + BinaryAnnotation::CodeOffset(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeCodeOffsetBase => { + BinaryAnnotation::ChangeCodeOffsetBase(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeCodeOffset => { + BinaryAnnotation::ChangeCodeOffset(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeCodeLength => { + BinaryAnnotation::ChangeCodeLength(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeFile => { + BinaryAnnotation::ChangeFile(FileIndex(self.uncompress_next()?)) + } + BinaryAnnotationOpcode::ChangeLineOffset => { + BinaryAnnotation::ChangeLineOffset(decode_signed_operand(self.uncompress_next()?)) + } + BinaryAnnotationOpcode::ChangeLineEndDelta => { + BinaryAnnotation::ChangeLineEndDelta(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeRangeKind => { + BinaryAnnotation::ChangeRangeKind(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeColumnStart => { + BinaryAnnotation::ChangeColumnStart(self.uncompress_next()?) + } + BinaryAnnotationOpcode::ChangeColumnEndDelta => BinaryAnnotation::ChangeColumnEndDelta( + decode_signed_operand(self.uncompress_next()?), + ), + BinaryAnnotationOpcode::ChangeCodeOffsetAndLineOffset => { + let operand = self.uncompress_next()?; + BinaryAnnotation::ChangeCodeOffsetAndLineOffset( + operand & 0xf, + decode_signed_operand(operand >> 4), + ) + } + BinaryAnnotationOpcode::ChangeCodeLengthAndCodeOffset => { + BinaryAnnotation::ChangeCodeLengthAndCodeOffset( + self.uncompress_next()?, + self.uncompress_next()?, + ) + } + BinaryAnnotationOpcode::ChangeColumnEnd => { + BinaryAnnotation::ChangeColumnEnd(self.uncompress_next()?) + } + }; + + Ok(Some(annotation)) + } +} + +/// Binary annotations of a symbol. +/// +/// The binary annotation mechanism supports recording a list of annotations in an instruction +/// stream. The X64 unwind code and the DWARF standard have a similar design. +/// +/// Binary annotations are primarily used as line programs for inline function calls. +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct BinaryAnnotations<'t> { + data: &'t [u8], +} + +impl<'t> BinaryAnnotations<'t> { + /// Creates a new instance of binary annotations. + pub(crate) fn new(data: &'t [u8]) -> Self { + BinaryAnnotations { data } + } + + /// Iterates through binary annotations. + pub fn iter(&self) -> BinaryAnnotationsIter<'t> { + BinaryAnnotationsIter { + buffer: ParseBuffer::from(self.data), + } + } +} + +#[test] +fn test_binary_annotation_iter() { + let inp = b"\x0b\x03\x06\n\x03\x08\x06\x06\x03-\x06\x08\x03\x07\x0br\x06\x06\x0c\x03\x07\x06\x0f\x0c\x06\x05\x00\x00"; + let annotations = BinaryAnnotations::new(inp) + .iter() + .collect::>() + .unwrap(); + + assert_eq!( + annotations, + vec![ + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(3, 0), + BinaryAnnotation::ChangeLineOffset(5), + BinaryAnnotation::ChangeCodeOffset(8), + BinaryAnnotation::ChangeLineOffset(3), + BinaryAnnotation::ChangeCodeOffset(45), + BinaryAnnotation::ChangeLineOffset(4), + BinaryAnnotation::ChangeCodeOffset(7), + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(2, -3), + BinaryAnnotation::ChangeLineOffset(3), + BinaryAnnotation::ChangeCodeLengthAndCodeOffset(3, 7), + BinaryAnnotation::ChangeLineOffset(-7), + BinaryAnnotation::ChangeCodeLengthAndCodeOffset(6, 5) + ] + ); + + let inp = b"\x03P\x06\x0e\x03\x0c\x06\x04\x032\x06\x06\x03T\x0b#\x0b\\\x0bC\x0b/\x06\x04\x0c-\t\x03;\x06\x1d\x0c\x05\x06\x00\x00"; + let annotations = BinaryAnnotations::new(inp) + .iter() + .collect::>() + .unwrap(); + + assert_eq!( + annotations, + vec![ + BinaryAnnotation::ChangeCodeOffset(80), + BinaryAnnotation::ChangeLineOffset(7), + BinaryAnnotation::ChangeCodeOffset(12), + BinaryAnnotation::ChangeLineOffset(2), + BinaryAnnotation::ChangeCodeOffset(50), + BinaryAnnotation::ChangeLineOffset(3), + BinaryAnnotation::ChangeCodeOffset(84), + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(3, 1), + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(12, -2), + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(3, 2), + BinaryAnnotation::ChangeCodeOffsetAndLineOffset(15, 1), + BinaryAnnotation::ChangeLineOffset(2), + BinaryAnnotation::ChangeCodeLengthAndCodeOffset(45, 9), + BinaryAnnotation::ChangeCodeOffset(59), + BinaryAnnotation::ChangeLineOffset(-14), + BinaryAnnotation::ChangeCodeLengthAndCodeOffset(5, 6), + ] + ); +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/symbol/constants.rs b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/constants.rs new file mode 100644 index 0000000000..1d017ceeb6 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/constants.rs @@ -0,0 +1,608 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +// A list of known symbol kinds. +// from: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2735 + +#![allow(unused, non_upper_case_globals, non_camel_case_types)] + +use std::fmt; + +use scroll::{ctx::TryFromCtx, Endian}; + +pub const S_COMPILE: u16 = 0x0001; // Compile flags symbol +pub const S_REGISTER_16t: u16 = 0x0002; // Register variable +pub const S_CONSTANT_16t: u16 = 0x0003; // constant symbol +pub const S_UDT_16t: u16 = 0x0004; // User defined type +pub const S_SSEARCH: u16 = 0x0005; // Start Search +pub const S_END: u16 = 0x0006; // Block procedure "with" or thunk end +pub const S_SKIP: u16 = 0x0007; // Reserve symbol space in $$Symbols table +pub const S_CVRESERVE: u16 = 0x0008; // Reserved symbol for CV internal use +pub const S_OBJNAME_ST: u16 = 0x0009; // path to object file name +pub const S_ENDARG: u16 = 0x000a; // end of argument/return list +pub const S_COBOLUDT_16t: u16 = 0x000b; // special UDT for cobol that does not symbol pack +pub const S_MANYREG_16t: u16 = 0x000c; // multiple register variable +pub const S_RETURN: u16 = 0x000d; // return description symbol +pub const S_ENTRYTHIS: u16 = 0x000e; // description of this pointer on entry + +pub const S_BPREL16: u16 = 0x0100; // BP-relative +pub const S_LDATA16: u16 = 0x0101; // Module-local symbol +pub const S_GDATA16: u16 = 0x0102; // Global data symbol +pub const S_PUB16: u16 = 0x0103; // a public symbol +pub const S_LPROC16: u16 = 0x0104; // Local procedure start +pub const S_GPROC16: u16 = 0x0105; // Global procedure start +pub const S_THUNK16: u16 = 0x0106; // Thunk Start +pub const S_BLOCK16: u16 = 0x0107; // block start +pub const S_WITH16: u16 = 0x0108; // with start +pub const S_LABEL16: u16 = 0x0109; // code label +pub const S_CEXMODEL16: u16 = 0x010a; // change execution model +pub const S_VFTABLE16: u16 = 0x010b; // address of virtual function table +pub const S_REGREL16: u16 = 0x010c; // register relative address + +pub const S_BPREL32_16t: u16 = 0x0200; // BP-relative +pub const S_LDATA32_16t: u16 = 0x0201; // Module-local symbol +pub const S_GDATA32_16t: u16 = 0x0202; // Global data symbol +pub const S_PUB32_16t: u16 = 0x0203; // a public symbol (CV internal reserved) +pub const S_LPROC32_16t: u16 = 0x0204; // Local procedure start +pub const S_GPROC32_16t: u16 = 0x0205; // Global procedure start +pub const S_THUNK32_ST: u16 = 0x0206; // Thunk Start +pub const S_BLOCK32_ST: u16 = 0x0207; // block start +pub const S_WITH32_ST: u16 = 0x0208; // with start +pub const S_LABEL32_ST: u16 = 0x0209; // code label +pub const S_CEXMODEL32: u16 = 0x020a; // change execution model +pub const S_VFTABLE32_16t: u16 = 0x020b; // address of virtual function table +pub const S_REGREL32_16t: u16 = 0x020c; // register relative address +pub const S_LTHREAD32_16t: u16 = 0x020d; // local thread storage +pub const S_GTHREAD32_16t: u16 = 0x020e; // global thread storage +pub const S_SLINK32: u16 = 0x020f; // static link for MIPS EH implementation + +pub const S_LPROCMIPS_16t: u16 = 0x0300; // Local procedure start +pub const S_GPROCMIPS_16t: u16 = 0x0301; // Global procedure start + +// if these ref symbols have names following then the names are in ST format +pub const S_PROCREF_ST: u16 = 0x0400; // Reference to a procedure +pub const S_DATAREF_ST: u16 = 0x0401; // Reference to data +pub const S_ALIGN: u16 = 0x0402; // Used for page alignment of symbols + +pub const S_LPROCREF_ST: u16 = 0x0403; // Local Reference to a procedure +pub const S_OEM: u16 = 0x0404; // OEM defined symbol + +// sym records with 32-bit types embedded instead of 16-bit +// all have 0x1000 bit set for easy identification +// only do the 32-bit target versions since we don't really +// care about 16-bit ones anymore. +pub const S_TI16_MAX: u16 = 0x1000; + +pub const S_REGISTER_ST: u16 = 0x1001; // Register variable +pub const S_CONSTANT_ST: u16 = 0x1002; // constant symbol +pub const S_UDT_ST: u16 = 0x1003; // User defined type +pub const S_COBOLUDT_ST: u16 = 0x1004; // special UDT for cobol that does not symbol pack +pub const S_MANYREG_ST: u16 = 0x1005; // multiple register variable +pub const S_BPREL32_ST: u16 = 0x1006; // BP-relative +pub const S_LDATA32_ST: u16 = 0x1007; // Module-local symbol +pub const S_GDATA32_ST: u16 = 0x1008; // Global data symbol +pub const S_PUB32_ST: u16 = 0x1009; // a public symbol (CV internal reserved) +pub const S_LPROC32_ST: u16 = 0x100a; // Local procedure start +pub const S_GPROC32_ST: u16 = 0x100b; // Global procedure start +pub const S_VFTABLE32: u16 = 0x100c; // address of virtual function table +pub const S_REGREL32_ST: u16 = 0x100d; // register relative address +pub const S_LTHREAD32_ST: u16 = 0x100e; // local thread storage +pub const S_GTHREAD32_ST: u16 = 0x100f; // global thread storage + +pub const S_LPROCMIPS_ST: u16 = 0x1010; // Local procedure start +pub const S_GPROCMIPS_ST: u16 = 0x1011; // Global procedure start + +pub const S_FRAMEPROC: u16 = 0x1012; // extra frame and proc information +pub const S_COMPILE2_ST: u16 = 0x1013; // extended compile flags and info + +// new symbols necessary for 16-bit enumerates of IA64 registers +// and IA64 specific symbols + +pub const S_MANYREG2_ST: u16 = 0x1014; // multiple register variable +pub const S_LPROCIA64_ST: u16 = 0x1015; // Local procedure start (IA64) +pub const S_GPROCIA64_ST: u16 = 0x1016; // Global procedure start (IA64) + +// Local symbols for IL +pub const S_LOCALSLOT_ST: u16 = 0x1017; // local IL sym with field for local slot index +pub const S_PARAMSLOT_ST: u16 = 0x1018; // local IL sym with field for parameter slot index + +pub const S_ANNOTATION: u16 = 0x1019; // Annotation string literals + +// symbols to support managed code debugging +pub const S_GMANPROC_ST: u16 = 0x101a; // Global proc +pub const S_LMANPROC_ST: u16 = 0x101b; // Local proc +pub const S_RESERVED1: u16 = 0x101c; // reserved +pub const S_RESERVED2: u16 = 0x101d; // reserved +pub const S_RESERVED3: u16 = 0x101e; // reserved +pub const S_RESERVED4: u16 = 0x101f; // reserved +pub const S_LMANDATA_ST: u16 = 0x1020; +pub const S_GMANDATA_ST: u16 = 0x1021; +pub const S_MANFRAMEREL_ST: u16 = 0x1022; +pub const S_MANREGISTER_ST: u16 = 0x1023; +pub const S_MANSLOT_ST: u16 = 0x1024; +pub const S_MANMANYREG_ST: u16 = 0x1025; +pub const S_MANREGREL_ST: u16 = 0x1026; +pub const S_MANMANYREG2_ST: u16 = 0x1027; +pub const S_MANTYPREF: u16 = 0x1028; // Index for type referenced by name from metadata +pub const S_UNAMESPACE_ST: u16 = 0x1029; // Using namespace + +// Symbols w/ SZ name fields. All name fields contain utf8 encoded strings. +pub const S_ST_MAX: u16 = 0x1100; // starting point for SZ name symbols + +pub const S_OBJNAME: u16 = 0x1101; // path to object file name +pub const S_THUNK32: u16 = 0x1102; // Thunk Start +pub const S_BLOCK32: u16 = 0x1103; // block start +pub const S_WITH32: u16 = 0x1104; // with start +pub const S_LABEL32: u16 = 0x1105; // code label +pub const S_REGISTER: u16 = 0x1106; // Register variable +pub const S_CONSTANT: u16 = 0x1107; // constant symbol +pub const S_UDT: u16 = 0x1108; // User defined type +pub const S_COBOLUDT: u16 = 0x1109; // special UDT for cobol that does not symbol pack +pub const S_MANYREG: u16 = 0x110a; // multiple register variable +pub const S_BPREL32: u16 = 0x110b; // BP-relative +pub const S_LDATA32: u16 = 0x110c; // Module-local symbol +pub const S_GDATA32: u16 = 0x110d; // Global data symbol +pub const S_PUB32: u16 = 0x110e; // a public symbol (CV internal reserved) +pub const S_LPROC32: u16 = 0x110f; // Local procedure start +pub const S_GPROC32: u16 = 0x1110; // Global procedure start +pub const S_REGREL32: u16 = 0x1111; // register relative address +pub const S_LTHREAD32: u16 = 0x1112; // local thread storage +pub const S_GTHREAD32: u16 = 0x1113; // global thread storage + +pub const S_LPROCMIPS: u16 = 0x1114; // Local procedure start +pub const S_GPROCMIPS: u16 = 0x1115; // Global procedure start +pub const S_COMPILE2: u16 = 0x1116; // extended compile flags and info +pub const S_MANYREG2: u16 = 0x1117; // multiple register variable +pub const S_LPROCIA64: u16 = 0x1118; // Local procedure start (IA64) +pub const S_GPROCIA64: u16 = 0x1119; // Global procedure start (IA64) +pub const S_LOCALSLOT: u16 = 0x111a; // local IL sym with field for local slot index +pub const S_PARAMSLOT: u16 = 0x111b; // local IL sym with field for parameter slot index + +// symbols to support managed code debugging +pub const S_LMANDATA: u16 = 0x111c; +pub const S_GMANDATA: u16 = 0x111d; +pub const S_MANFRAMEREL: u16 = 0x111e; +pub const S_MANREGISTER: u16 = 0x111f; +pub const S_MANSLOT: u16 = 0x1120; +pub const S_MANMANYREG: u16 = 0x1121; +pub const S_MANREGREL: u16 = 0x1122; +pub const S_MANMANYREG2: u16 = 0x1123; +pub const S_UNAMESPACE: u16 = 0x1124; // Using namespace + +// ref symbols with name fields +pub const S_PROCREF: u16 = 0x1125; // Reference to a procedure +pub const S_DATAREF: u16 = 0x1126; // Reference to data +pub const S_LPROCREF: u16 = 0x1127; // Local Reference to a procedure +pub const S_ANNOTATIONREF: u16 = 0x1128; // Reference to an S_ANNOTATION symbol +pub const S_TOKENREF: u16 = 0x1129; // Reference to one of the many MANPROCSYM's + +// continuation of managed symbols +pub const S_GMANPROC: u16 = 0x112a; // Global proc +pub const S_LMANPROC: u16 = 0x112b; // Local proc + +// short light-weight thunks +pub const S_TRAMPOLINE: u16 = 0x112c; // trampoline thunks +pub const S_MANCONSTANT: u16 = 0x112d; // constants with metadata type info + +// native attributed local/parms +pub const S_ATTR_FRAMEREL: u16 = 0x112e; // relative to virtual frame ptr +pub const S_ATTR_REGISTER: u16 = 0x112f; // stored in a register +pub const S_ATTR_REGREL: u16 = 0x1130; // relative to register (alternate frame ptr) +pub const S_ATTR_MANYREG: u16 = 0x1131; // stored in >1 register + +// Separated code (from the compiler) support +pub const S_SEPCODE: u16 = 0x1132; + +pub const S_LOCAL_2005: u16 = 0x1133; // defines a local symbol in optimized code +pub const S_DEFRANGE_2005: u16 = 0x1134; // defines a single range of addresses in which symbol can be evaluated +pub const S_DEFRANGE2_2005: u16 = 0x1135; // defines ranges of addresses in which symbol can be evaluated + +pub const S_SECTION: u16 = 0x1136; // A COFF section in a PE executable +pub const S_COFFGROUP: u16 = 0x1137; // A COFF group +pub const S_EXPORT: u16 = 0x1138; // A export + +pub const S_CALLSITEINFO: u16 = 0x1139; // Indirect call site information +pub const S_FRAMECOOKIE: u16 = 0x113a; // Security cookie information + +pub const S_DISCARDED: u16 = 0x113b; // Discarded by LINK /OPT:REF (experimental see richards) + +pub const S_COMPILE3: u16 = 0x113c; // Replacement for S_COMPILE2 +pub const S_ENVBLOCK: u16 = 0x113d; // Environment block split off from S_COMPILE2 + +pub const S_LOCAL: u16 = 0x113e; // defines a local symbol in optimized code +pub const S_DEFRANGE: u16 = 0x113f; // defines a single range of addresses in which symbol can be evaluated +pub const S_DEFRANGE_SUBFIELD: u16 = 0x1140; // ranges for a subfield + +pub const S_DEFRANGE_REGISTER: u16 = 0x1141; // ranges for en-registered symbol +pub const S_DEFRANGE_FRAMEPOINTER_REL: u16 = 0x1142; // range for stack symbol. +pub const S_DEFRANGE_SUBFIELD_REGISTER: u16 = 0x1143; // ranges for en-registered field of symbol +pub const S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: u16 = 0x1144; // range for stack symbol span valid full scope of function body gap might apply. +pub const S_DEFRANGE_REGISTER_REL: u16 = 0x1145; // range for symbol address as register + offset. + +// S_PROC symbols that reference ID instead of type +pub const S_LPROC32_ID: u16 = 0x1146; +pub const S_GPROC32_ID: u16 = 0x1147; +pub const S_LPROCMIPS_ID: u16 = 0x1148; +pub const S_GPROCMIPS_ID: u16 = 0x1149; +pub const S_LPROCIA64_ID: u16 = 0x114a; +pub const S_GPROCIA64_ID: u16 = 0x114b; + +pub const S_BUILDINFO: u16 = 0x114c; // build information. +pub const S_INLINESITE: u16 = 0x114d; // inlined function callsite. +pub const S_INLINESITE_END: u16 = 0x114e; +pub const S_PROC_ID_END: u16 = 0x114f; + +pub const S_DEFRANGE_HLSL: u16 = 0x1150; +pub const S_GDATA_HLSL: u16 = 0x1151; +pub const S_LDATA_HLSL: u16 = 0x1152; + +pub const S_FILESTATIC: u16 = 0x1153; + +pub const S_LOCAL_DPC_GROUPSHARED: u16 = 0x1154; // DPC groupshared variable +pub const S_LPROC32_DPC: u16 = 0x1155; // DPC local procedure start +pub const S_LPROC32_DPC_ID: u16 = 0x1156; +pub const S_DEFRANGE_DPC_PTR_TAG: u16 = 0x1157; // DPC pointer tag definition range +pub const S_DPC_SYM_TAG_MAP: u16 = 0x1158; // DPC pointer tag value to symbol record map + +pub const S_ARMSWITCHTABLE: u16 = 0x1159; +pub const S_CALLEES: u16 = 0x115a; +pub const S_CALLERS: u16 = 0x115b; +pub const S_POGODATA: u16 = 0x115c; +pub const S_INLINESITE2: u16 = 0x115d; // extended inline site information + +pub const S_HEAPALLOCSITE: u16 = 0x115e; // heap allocation site + +pub const S_MOD_TYPEREF: u16 = 0x115f; // only generated at link time + +pub const S_REF_MINIPDB: u16 = 0x1160; // only generated at link time for mini PDB +pub const S_PDBMAP: u16 = 0x1161; // only generated at link time for mini PDB + +pub const S_GDATA_HLSL32: u16 = 0x1162; +pub const S_LDATA_HLSL32: u16 = 0x1163; + +pub const S_GDATA_HLSL32_EX: u16 = 0x1164; +pub const S_LDATA_HLSL32_EX: u16 = 0x1165; + +pub const S_FASTLINK: u16 = 0x1167; // generated at link time for /DEBUG:FASTLINK +pub const S_INLINEES: u16 = 0x1168; + +pub const S_HOTPATCHFUNC: u16 = 0x1169; + +pub const S_BPREL32_INDIR: u16 = 0x1170; +pub const S_REGREL32_INDIR: u16 = 0x1171; + +pub const S_GPROC32EX: u16 = 0x1172; +pub const S_LPROC32EX: u16 = 0x1173; +pub const S_GPROC32EX_ID: u16 = 0x1174; +pub const S_LPROC32EX_ID: u16 = 0x1175; + +pub const S_STATICLOCAL: u16 = 0x1176; + +pub const S_DEFRANGE_REGISTER_REL_INDIR: u16 = 0x1177; + +pub const S_RECTYPE_MAX: u16 = 0x1178; +pub const S_RECTYPE_PAD: u16 = 0x1278; + +/// These values correspond to the CV_CPU_TYPE_e enumeration, and are documented +/// [on MSDN](https://msdn.microsoft.com/en-us/library/b2fc64ek.aspx). +#[non_exhaustive] +#[allow(missing_docs)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CPUType { + Intel8080 = 0x0, + Intel8086 = 0x1, + Intel80286 = 0x2, + Intel80386 = 0x3, + Intel80486 = 0x4, + Pentium = 0x5, + PentiumPro = 0x6, + Pentium3 = 0x7, + MIPS = 0x10, + MIPS16 = 0x11, + MIPS32 = 0x12, + MIPS64 = 0x13, + MIPSI = 0x14, + MIPSII = 0x15, + MIPSIII = 0x16, + MIPSIV = 0x17, + MIPSV = 0x18, + M68000 = 0x20, + M68010 = 0x21, + M68020 = 0x22, + M68030 = 0x23, + M68040 = 0x24, + Alpha = 0x30, + Alpha21164 = 0x31, + Alpha21164A = 0x32, + Alpha21264 = 0x33, + Alpha21364 = 0x34, + PPC601 = 0x40, + PPC603 = 0x41, + PPC604 = 0x42, + PPC620 = 0x43, + PPCFP = 0x44, + PPCBE = 0x45, + SH3 = 0x50, + SH3E = 0x51, + SH3DSP = 0x52, + SH4 = 0x53, + SHMedia = 0x54, + ARM3 = 0x60, + ARM4 = 0x61, + ARM4T = 0x62, + ARM5 = 0x63, + ARM5T = 0x64, + ARM6 = 0x65, + ARM_XMAC = 0x66, + ARM_WMMX = 0x67, + ARM7 = 0x68, + ARM64 = 0x69, + Omni = 0x70, + Ia64 = 0x80, + Ia64_2 = 0x81, + CEE = 0x90, + AM33 = 0xa0, + M32R = 0xb0, + TriCore = 0xc0, + X64 = 0xd0, + EBC = 0xe0, + Thumb = 0xf0, + ARMNT = 0xf4, + D3D11_Shader = 0x100, +} + +impl fmt::Display for CPUType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Intel8080 => write!(f, "Intel8080"), + Self::Intel8086 => write!(f, "Intel8086"), + Self::Intel80286 => write!(f, "Intel80286"), + Self::Intel80386 => write!(f, "Intel80386"), + Self::Intel80486 => write!(f, "Intel80486"), + Self::Pentium => write!(f, "Pentium"), + Self::PentiumPro => write!(f, "PentiumPro"), + Self::Pentium3 => write!(f, "Pentium3"), + Self::MIPS => write!(f, "MIPS"), + Self::MIPS16 => write!(f, "MIPS16"), + Self::MIPS32 => write!(f, "MIPS32"), + Self::MIPS64 => write!(f, "MIPS64"), + Self::MIPSI => write!(f, "MIPSI"), + Self::MIPSII => write!(f, "MIPSII"), + Self::MIPSIII => write!(f, "MIPSIII"), + Self::MIPSIV => write!(f, "MIPSIV"), + Self::MIPSV => write!(f, "MIPSV"), + Self::M68000 => write!(f, "M68000"), + Self::M68010 => write!(f, "M68010"), + Self::M68020 => write!(f, "M68020"), + Self::M68030 => write!(f, "M68030"), + Self::M68040 => write!(f, "M68040"), + Self::Alpha => write!(f, "Alpha"), + Self::Alpha21164 => write!(f, "Alpha21164"), + Self::Alpha21164A => write!(f, "Alpha21164A"), + Self::Alpha21264 => write!(f, "Alpha21264"), + Self::Alpha21364 => write!(f, "Alpha21364"), + Self::PPC601 => write!(f, "PPC601"), + Self::PPC603 => write!(f, "PPC603"), + Self::PPC604 => write!(f, "PPC604"), + Self::PPC620 => write!(f, "PPC620"), + Self::PPCFP => write!(f, "PPCFP"), + Self::PPCBE => write!(f, "PPCBE"), + Self::SH3 => write!(f, "SH3"), + Self::SH3E => write!(f, "SH3E"), + Self::SH3DSP => write!(f, "SH3DSP"), + Self::SH4 => write!(f, "SH4"), + Self::SHMedia => write!(f, "SHMedia"), + Self::ARM3 => write!(f, "ARM3"), + Self::ARM4 => write!(f, "ARM4"), + Self::ARM4T => write!(f, "ARM4T"), + Self::ARM5 => write!(f, "ARM5"), + Self::ARM5T => write!(f, "ARM5T"), + Self::ARM6 => write!(f, "ARM6"), + Self::ARM_XMAC => write!(f, "ARM_XMAC"), + Self::ARM_WMMX => write!(f, "ARM_WMMX"), + Self::ARM7 => write!(f, "ARM7"), + Self::ARM64 => write!(f, "ARM64"), + Self::Omni => write!(f, "Omni"), + Self::Ia64 => write!(f, "Ia64"), + Self::Ia64_2 => write!(f, "Ia64_2"), + Self::CEE => write!(f, "CEE"), + Self::AM33 => write!(f, "AM33"), + Self::M32R => write!(f, "M32R"), + Self::TriCore => write!(f, "TriCore"), + Self::X64 => write!(f, "X64"), + Self::EBC => write!(f, "EBC"), + Self::Thumb => write!(f, "Thumb"), + Self::ARMNT => write!(f, "ARMNT"), + Self::D3D11_Shader => write!(f, "D3D11_Shader"), + } + } +} + +impl From for CPUType { + fn from(value: u16) -> Self { + match value { + 0x0 => Self::Intel8080, + 0x1 => Self::Intel8086, + 0x2 => Self::Intel80286, + 0x3 => Self::Intel80386, + 0x4 => Self::Intel80486, + 0x5 => Self::Pentium, + 0x6 => Self::PentiumPro, + 0x7 => Self::Pentium3, + 0x10 => Self::MIPS, + 0x11 => Self::MIPS16, + 0x12 => Self::MIPS32, + 0x13 => Self::MIPS64, + 0x14 => Self::MIPSI, + 0x15 => Self::MIPSII, + 0x16 => Self::MIPSIII, + 0x17 => Self::MIPSIV, + 0x18 => Self::MIPSV, + 0x20 => Self::M68000, + 0x21 => Self::M68010, + 0x22 => Self::M68020, + 0x23 => Self::M68030, + 0x24 => Self::M68040, + 0x30 => Self::Alpha, + 0x31 => Self::Alpha21164, + 0x32 => Self::Alpha21164A, + 0x33 => Self::Alpha21264, + 0x34 => Self::Alpha21364, + 0x40 => Self::PPC601, + 0x41 => Self::PPC603, + 0x42 => Self::PPC604, + 0x43 => Self::PPC620, + 0x44 => Self::PPCFP, + 0x45 => Self::PPCBE, + 0x50 => Self::SH3, + 0x51 => Self::SH3E, + 0x52 => Self::SH3DSP, + 0x53 => Self::SH4, + 0x54 => Self::SHMedia, + 0x60 => Self::ARM3, + 0x61 => Self::ARM4, + 0x62 => Self::ARM4T, + 0x63 => Self::ARM5, + 0x64 => Self::ARM5T, + 0x65 => Self::ARM6, + 0x66 => Self::ARM_XMAC, + 0x67 => Self::ARM_WMMX, + 0x68 => Self::ARM7, + 0x69 => Self::ARM64, + 0x70 => Self::Omni, + 0x80 => Self::Ia64, + 0x81 => Self::Ia64_2, + 0x90 => Self::CEE, + 0xa0 => Self::AM33, + 0xb0 => Self::M32R, + 0xc0 => Self::TriCore, + 0xd0 => Self::X64, + 0xe0 => Self::EBC, + 0xf0 => Self::Thumb, + 0xf4 => Self::ARMNT, + 0x100 => Self::D3D11_Shader, + _ => Self::Intel8080, // This enum doesn't have an unknown value, so we just force it to Intel8080 since it's 0x0. + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for CPUType { + type Error = scroll::Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> scroll::Result<(Self, usize)> { + u16::try_from_ctx(this, le).map(|(v, l)| (v.into(), l)) + } +} + +/// These values correspond to the CV_CFL_LANG enumeration, and are documented +/// [on MSDN](https://msdn.microsoft.com/en-us/library/bw3aekw6.aspx). +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum SourceLanguage { + /// Application language is C. + C = 0x00, + /// Application language is C++. + Cpp = 0x01, + /// Application language is FORTRAN. + Fortran = 0x02, + /// Application language is Microsoft Macro Assembler. + Masm = 0x03, + /// Application language is Pascal. + Pascal = 0x04, + /// Application language is BASIC. + Basic = 0x05, + /// Application language is COBOL. + Cobol = 0x06, + /// Application is a linker-generated module. + Link = 0x07, + /// Application is a resource module converted with CVTRES tool. + Cvtres = 0x08, + /// Application is a POGO optimized module generated with CVTPGD tool. + Cvtpgd = 0x09, + /// Application language is C#. + CSharp = 0x0a, + /// Application language is Visual Basic. + VB = 0x0b, + /// Application language is intermediate language assembly (that is, Common Language Runtime + /// (CLR) assembly). + ILAsm = 0x0c, + /// Application language is Java. + Java = 0x0d, + /// Application language is Jscript. + JScript = 0x0e, + /// Application language is an unknown Microsoft Intermediate Language (MSIL), possibly a result + /// of using the [/LTCG (Link-time Code + /// Generation)](https://docs.microsoft.com/en-us/cpp/build/reference/ltcg-link-time-code-generation) + /// switch. + MSIL = 0x0f, + /// Application language is High Level Shader Language. + HLSL = 0x10, + + /// The DMD compiler emits 'D' for the CV source language. Microsoft doesn't + /// have an enumerator for it yet. + D = 0x44, +} + +impl fmt::Display for SourceLanguage { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::C => write!(f, "C"), + Self::Cpp => write!(f, "Cpp"), + Self::Fortran => write!(f, "Fortran"), + Self::Masm => write!(f, "Masm"), + Self::Pascal => write!(f, "Pascal"), + Self::Basic => write!(f, "Basic"), + Self::Cobol => write!(f, "Cobol"), + Self::Link => write!(f, "Link"), + Self::Cvtres => write!(f, "Cvtres"), + Self::Cvtpgd => write!(f, "Cvtpgd"), + Self::CSharp => write!(f, "CSharp"), + Self::VB => write!(f, "VB"), + Self::ILAsm => write!(f, "ILAsm"), + Self::Java => write!(f, "Java"), + Self::JScript => write!(f, "JScript"), + Self::MSIL => write!(f, "MSIL"), + Self::HLSL => write!(f, "HLSL"), + Self::D => write!(f, "D"), + } + } +} + +impl From for SourceLanguage { + fn from(value: u8) -> Self { + match value { + 0x00 => Self::C, + 0x01 => Self::Cpp, + 0x02 => Self::Fortran, + 0x03 => Self::Masm, + 0x04 => Self::Pascal, + 0x05 => Self::Basic, + 0x06 => Self::Cobol, + 0x07 => Self::Link, + 0x08 => Self::Cvtres, + 0x09 => Self::Cvtpgd, + 0x0a => Self::CSharp, + 0x0b => Self::VB, + 0x0c => Self::ILAsm, + 0x0d => Self::Java, + 0x0e => Self::JScript, + 0x0f => Self::MSIL, + 0x10 => Self::HLSL, + 0x44 => Self::D, + _ => Self::Masm, // There is no unknown, so we just force to Masm as the default. + } + } +} + +impl<'a> TryFromCtx<'a, Endian> for SourceLanguage { + type Error = scroll::Error; + + fn try_from_ctx(this: &'a [u8], le: Endian) -> scroll::Result<(Self, usize)> { + u8::try_from_ctx(this, le).map(|(v, l)| (v.into(), l)) + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/symbol/mod.rs b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/mod.rs new file mode 100644 index 0000000000..94ee5e289f --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/symbol/mod.rs @@ -0,0 +1,3071 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::fmt; + +use scroll::{ctx::TryFromCtx, Endian, Pread, LE}; + +use crate::common::*; +use crate::msf::*; +use crate::FallibleIterator; + +mod annotations; +mod constants; + +use self::constants::*; +pub use self::constants::{CPUType, SourceLanguage}; + +pub use self::annotations::*; + +/// The raw type discriminator for `Symbols`. +pub type SymbolKind = u16; + +/// Represents a symbol from the symbol table. +/// +/// A `Symbol` is represented internally as a `&[u8]`, and in general the bytes inside are not +/// inspected in any way before calling any of the accessor methods. +/// +/// To avoid copying, `Symbol`s exist as references to data owned by the parent `SymbolTable`. +/// Therefore, a `Symbol` may not outlive its parent `SymbolTable`. +#[derive(Copy, Clone, PartialEq)] +pub struct Symbol<'t> { + index: SymbolIndex, + data: &'t [u8], +} + +impl<'t> Symbol<'t> { + /// The index of this symbol in the containing symbol stream. + #[inline] + pub fn index(&self) -> SymbolIndex { + self.index + } + + /// Returns the kind of symbol identified by this Symbol. + #[inline] + pub fn raw_kind(&self) -> SymbolKind { + debug_assert!(self.data.len() >= 2); + self.data.pread_with(0, LE).unwrap_or_default() + } + + /// Returns the raw bytes of this symbol record, including the symbol type and extra data, but + /// not including the preceding symbol length indicator. + #[inline] + pub fn raw_bytes(&self) -> &'t [u8] { + self.data + } + + /// Parse the symbol into the `SymbolData` it contains. + #[inline] + pub fn parse(&self) -> Result> { + self.raw_bytes().pread_with(0, ()) + } + + /// Returns whether this symbol starts a scope. + /// + /// If `true`, this symbol has a `parent` and an `end` field, which contains the offset of the + /// corrsponding end symbol. + pub fn starts_scope(&self) -> bool { + matches!( + self.raw_kind(), + S_GPROC16 + | S_GPROC32 + | S_GPROC32_ST + | S_GPROCMIPS + | S_GPROCMIPS_ST + | S_GPROCIA64 + | S_GPROCIA64_ST + | S_LPROC16 + | S_LPROC32 + | S_LPROC32_ST + | S_LPROC32_DPC + | S_LPROCMIPS + | S_LPROCMIPS_ST + | S_LPROCIA64 + | S_LPROCIA64_ST + | S_LPROC32_DPC_ID + | S_GPROC32_ID + | S_GPROCMIPS_ID + | S_GPROCIA64_ID + | S_BLOCK16 + | S_BLOCK32 + | S_BLOCK32_ST + | S_WITH16 + | S_WITH32 + | S_WITH32_ST + | S_THUNK16 + | S_THUNK32 + | S_THUNK32_ST + | S_SEPCODE + | S_GMANPROC + | S_GMANPROC_ST + | S_LMANPROC + | S_LMANPROC_ST + | S_INLINESITE + | S_INLINESITE2 + ) + } + + /// Returns whether this symbol declares the end of a scope. + pub fn ends_scope(&self) -> bool { + matches!(self.raw_kind(), S_END | S_PROC_ID_END | S_INLINESITE_END) + } +} + +impl<'t> fmt::Debug for Symbol<'t> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Symbol{{ kind: 0x{:x} [{} bytes] }}", + self.raw_kind(), + self.data.len() + ) + } +} + +fn parse_symbol_name<'t>(buf: &mut ParseBuffer<'t>, kind: SymbolKind) -> Result> { + if kind < S_ST_MAX { + // Pascal-style name + buf.parse_u8_pascal_string() + } else { + // NUL-terminated name + buf.parse_cstring() + } +} + +fn parse_optional_name<'t>( + buf: &mut ParseBuffer<'t>, + kind: SymbolKind, +) -> Result>> { + if kind < S_ST_MAX { + // ST variants do not specify a name + Ok(None) + } else { + // NUL-terminated name + buf.parse_cstring().map(Some) + } +} + +fn parse_optional_index(buf: &mut ParseBuffer<'_>) -> Result> { + Ok(match buf.parse()? { + SymbolIndex(0) => None, + index => Some(index), + }) +} + +// data types are defined at: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3038 +// constants defined at: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2735 +// decoding reference: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/cvdump/dumpsym7.cpp#L264 + +/// Information parsed from a [`Symbol`] record. +#[non_exhaustive] +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum SymbolData<'t> { + /// End of a scope, such as a procedure. + ScopeEnd, + /// Name of the object file of this module. + ObjName(ObjNameSymbol<'t>), + /// A Register variable. + RegisterVariable(RegisterVariableSymbol<'t>), + /// A constant value. + Constant(ConstantSymbol<'t>), + /// A user defined type. + UserDefinedType(UserDefinedTypeSymbol<'t>), + /// A Register variable spanning multiple registers. + MultiRegisterVariable(MultiRegisterVariableSymbol<'t>), + /// Static data, such as a global variable. + Data(DataSymbol<'t>), + /// A public symbol with a mangled name. + Public(PublicSymbol<'t>), + /// A procedure, such as a function or method. + Procedure(ProcedureSymbol<'t>), + /// A thread local variable. + ThreadStorage(ThreadStorageSymbol<'t>), + /// Flags used to compile a module. + CompileFlags(CompileFlagsSymbol<'t>), + /// A using namespace directive. + UsingNamespace(UsingNamespaceSymbol<'t>), + /// Reference to a [`ProcedureSymbol`]. + ProcedureReference(ProcedureReferenceSymbol<'t>), + /// Reference to an imported variable. + DataReference(DataReferenceSymbol<'t>), + /// Reference to an annotation. + AnnotationReference(AnnotationReferenceSymbol<'t>), + /// Trampoline thunk. + Trampoline(TrampolineSymbol), + /// An exported symbol. + Export(ExportSymbol<'t>), + /// A local symbol in optimized code. + Local(LocalSymbol<'t>), + /// Reference to build information. + BuildInfo(BuildInfoSymbol), + /// The callsite of an inlined function. + InlineSite(InlineSiteSymbol<'t>), + /// End of an inline callsite. + InlineSiteEnd, + /// End of a procedure. + ProcedureEnd, + /// A label. + Label(LabelSymbol<'t>), + /// A block. + Block(BlockSymbol<'t>), + /// Data allocated relative to a register. + RegisterRelative(RegisterRelativeSymbol<'t>), + /// A thunk. + Thunk(ThunkSymbol<'t>), + /// A block of separated code. + SeparatedCode(SeparatedCodeSymbol), + /// A live range of a variable. + DefRange(DefRangeSymbol), + /// A live range of a sub field of a variable. + DefRangeSubField(DefRangeSubFieldSymbol), + /// A live range of a register variable. + DefRangeRegister(DefRangeRegisterSymbol), + /// A live range of a frame pointer-relative variable. + DefRangeFramePointerRelative(DefRangeFramePointerRelativeSymbol), + /// A frame-pointer variable which is valid in the full scope of the function. + DefRangeFramePointerRelativeFullScope(DefRangeFramePointerRelativeFullScopeSymbol), + /// A live range of a sub field of a register variable. + DefRangeSubFieldRegister(DefRangeSubFieldRegisterSymbol), + /// A live range of a variable related to a register. + DefRangeRegisterRelative(DefRangeRegisterRelativeSymbol), + /// A base pointer-relative variable. + BasePointerRelative(BasePointerRelativeSymbol<'t>), + /// Extra frame and proc information. + FrameProcedure(FrameProcedureSymbol), + /// Indirect call site information. + CallSiteInfo(CallSiteInfoSymbol), +} + +impl<'t> SymbolData<'t> { + /// Returns the name of this symbol if it has one. + pub fn name(&self) -> Option> { + match self { + Self::ScopeEnd => None, + Self::ObjName(data) => Some(data.name), + Self::RegisterVariable(_) => None, + Self::Constant(data) => Some(data.name), + Self::UserDefinedType(data) => Some(data.name), + Self::MultiRegisterVariable(_) => None, + Self::Data(data) => Some(data.name), + Self::Public(data) => Some(data.name), + Self::Procedure(data) => Some(data.name), + Self::ThreadStorage(data) => Some(data.name), + Self::CompileFlags(_) => None, + Self::UsingNamespace(data) => Some(data.name), + Self::ProcedureReference(data) => data.name, + Self::DataReference(data) => data.name, + Self::AnnotationReference(data) => Some(data.name), + Self::Trampoline(_) => None, + Self::Export(data) => Some(data.name), + Self::Local(data) => Some(data.name), + Self::InlineSite(_) => None, + Self::BuildInfo(_) => None, + Self::InlineSiteEnd => None, + Self::ProcedureEnd => None, + Self::Label(data) => Some(data.name), + Self::Block(data) => Some(data.name), + Self::RegisterRelative(data) => Some(data.name), + Self::Thunk(data) => Some(data.name), + Self::SeparatedCode(_) => None, + Self::DefRange(_) => None, + Self::DefRangeSubField(_) => None, + Self::DefRangeRegister(_) => None, + Self::DefRangeFramePointerRelative(_) => None, + Self::DefRangeFramePointerRelativeFullScope(_) => None, + Self::DefRangeSubFieldRegister(_) => None, + Self::DefRangeRegisterRelative(_) => None, + Self::BasePointerRelative(data) => Some(data.name), + Self::FrameProcedure(_) => None, + Self::CallSiteInfo(_) => None, + } + } +} + +impl<'t> TryFromCtx<'t> for SymbolData<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _ctx: ()) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + let kind = buf.parse()?; + + let symbol = match kind { + S_END => SymbolData::ScopeEnd, + S_OBJNAME | S_OBJNAME_ST => SymbolData::ObjName(buf.parse_with(kind)?), + S_REGISTER | S_REGISTER_ST => SymbolData::RegisterVariable(buf.parse_with(kind)?), + S_CONSTANT | S_CONSTANT_ST | S_MANCONSTANT => { + SymbolData::Constant(buf.parse_with(kind)?) + } + S_UDT | S_UDT_ST | S_COBOLUDT | S_COBOLUDT_ST => { + SymbolData::UserDefinedType(buf.parse_with(kind)?) + } + S_MANYREG | S_MANYREG_ST | S_MANYREG2 | S_MANYREG2_ST => { + SymbolData::MultiRegisterVariable(buf.parse_with(kind)?) + } + S_LDATA32 | S_LDATA32_ST | S_GDATA32 | S_GDATA32_ST | S_LMANDATA | S_LMANDATA_ST + | S_GMANDATA | S_GMANDATA_ST => SymbolData::Data(buf.parse_with(kind)?), + S_PUB32 | S_PUB32_ST => SymbolData::Public(buf.parse_with(kind)?), + S_LPROC32 | S_LPROC32_ST | S_GPROC32 | S_GPROC32_ST | S_LPROC32_ID | S_GPROC32_ID + | S_LPROC32_DPC | S_LPROC32_DPC_ID => SymbolData::Procedure(buf.parse_with(kind)?), + S_LTHREAD32 | S_LTHREAD32_ST | S_GTHREAD32 | S_GTHREAD32_ST => { + SymbolData::ThreadStorage(buf.parse_with(kind)?) + } + S_COMPILE2 | S_COMPILE2_ST | S_COMPILE3 => { + SymbolData::CompileFlags(buf.parse_with(kind)?) + } + S_UNAMESPACE | S_UNAMESPACE_ST => SymbolData::UsingNamespace(buf.parse_with(kind)?), + S_PROCREF | S_PROCREF_ST | S_LPROCREF | S_LPROCREF_ST => { + SymbolData::ProcedureReference(buf.parse_with(kind)?) + } + S_TRAMPOLINE => Self::Trampoline(buf.parse_with(kind)?), + S_DATAREF | S_DATAREF_ST => SymbolData::DataReference(buf.parse_with(kind)?), + S_ANNOTATIONREF => SymbolData::AnnotationReference(buf.parse_with(kind)?), + S_EXPORT => SymbolData::Export(buf.parse_with(kind)?), + S_LOCAL => SymbolData::Local(buf.parse_with(kind)?), + S_BUILDINFO => SymbolData::BuildInfo(buf.parse_with(kind)?), + S_INLINESITE | S_INLINESITE2 => SymbolData::InlineSite(buf.parse_with(kind)?), + S_INLINESITE_END => SymbolData::InlineSiteEnd, + S_PROC_ID_END => SymbolData::ProcedureEnd, + S_LABEL32 | S_LABEL32_ST => SymbolData::Label(buf.parse_with(kind)?), + S_BLOCK32 | S_BLOCK32_ST => SymbolData::Block(buf.parse_with(kind)?), + S_REGREL32 => SymbolData::RegisterRelative(buf.parse_with(kind)?), + S_THUNK32 | S_THUNK32_ST => SymbolData::Thunk(buf.parse_with(kind)?), + S_SEPCODE => SymbolData::SeparatedCode(buf.parse_with(kind)?), + S_DEFRANGE => SymbolData::DefRange(buf.parse_with(kind)?), + S_DEFRANGE_SUBFIELD => SymbolData::DefRangeSubField(buf.parse_with(kind)?), + S_DEFRANGE_REGISTER => SymbolData::DefRangeRegister(buf.parse_with(kind)?), + S_DEFRANGE_FRAMEPOINTER_REL => { + SymbolData::DefRangeFramePointerRelative(buf.parse_with(kind)?) + } + S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE => { + SymbolData::DefRangeFramePointerRelativeFullScope(buf.parse_with(kind)?) + } + S_DEFRANGE_SUBFIELD_REGISTER => { + SymbolData::DefRangeSubFieldRegister(buf.parse_with(kind)?) + } + S_DEFRANGE_REGISTER_REL => SymbolData::DefRangeRegisterRelative(buf.parse_with(kind)?), + S_BPREL32 | S_BPREL32_ST | S_BPREL32_16t => { + SymbolData::BasePointerRelative(buf.parse_with(kind)?) + } + S_FRAMEPROC => SymbolData::FrameProcedure(buf.parse_with(kind)?), + S_CALLSITEINFO => SymbolData::CallSiteInfo(buf.parse_with(kind)?), + other => return Err(Error::UnimplementedSymbolKind(other)), + }; + + Ok((symbol, buf.pos())) + } +} + +/// A Register variable. +/// +/// Symbol kind `S_REGISTER`, or `S_REGISTER_ST` +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RegisterVariableSymbol<'t> { + /// Identifier of the variable type. + pub type_index: TypeIndex, + /// The register this variable is stored in. + pub register: Register, + /// Name of the variable. + pub name: RawString<'t>, + /// Parameter slot + pub slot: Option, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for RegisterVariableSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let type_index: TypeIndex = buf.parse()?; + let register: Register = buf.parse()?; + let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?; + + let slot: Option = if (this.len() as i64 - name.len() as i64 - 8i64) >= 6 { + if this[name.len() + 0xb] == 0x24 { + Some(ParseBuffer::from(&this[(name.len() + 0xc)..]).parse()?) + } else { + None + } + } else { + None + }; + + Ok(( + Self { + type_index, + register, + name, + slot, + }, + buf.pos(), + )) + } +} + +/// A Register variable spanning multiple registers. +/// +/// Symbol kind `S_MANYREG`, `S_MANYREG_ST`, `S_MANYREG2`, or `S_MANYREG2_ST`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MultiRegisterVariableSymbol<'t> { + /// Identifier of the variable type. + pub type_index: TypeIndex, + /// Most significant register first. + pub registers: Vec<(Register, RawString<'t>)>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for MultiRegisterVariableSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let type_index = buf.parse()?; + let count = match kind { + S_MANYREG2 | S_MANYREG2_ST => buf.parse::()?, + _ => u16::from(buf.parse::()?), + }; + + let mut registers = Vec::with_capacity(count as usize); + for _ in 0..count { + registers.push((buf.parse()?, parse_symbol_name(&mut buf, kind)?)); + } + + let symbol = MultiRegisterVariableSymbol { + type_index, + registers, + }; + + Ok((symbol, buf.pos())) + } +} + +// CV_PUBSYMFLAGS_e +const CVPSF_CODE: u32 = 0x1; +const CVPSF_FUNCTION: u32 = 0x2; +const CVPSF_MANAGED: u32 = 0x4; +const CVPSF_MSIL: u32 = 0x8; + +/// A public symbol with a mangled name. +/// +/// Symbol kind `S_PUB32`, or `S_PUB32_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct PublicSymbol<'t> { + /// The public symbol refers to executable code. + pub code: bool, + /// The public symbol is a function. + pub function: bool, + /// The symbol is in managed code (native or IL). + pub managed: bool, + /// The symbol is managed IL code. + pub msil: bool, + /// Start offset of the symbol. + pub offset: PdbInternalSectionOffset, + /// Mangled name of the symbol. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for PublicSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let flags = buf.parse::()?; + let symbol = PublicSymbol { + code: flags & CVPSF_CODE != 0, + function: flags & CVPSF_FUNCTION != 0, + managed: flags & CVPSF_MANAGED != 0, + msil: flags & CVPSF_MSIL != 0, + offset: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// Static data, such as a global variable. +/// +/// Symbol kinds: +/// - `S_LDATA32` and `S_LDATA32_ST` for local unmanaged data +/// - `S_GDATA32` and `S_GDATA32_ST` for global unmanaged data +/// - `S_LMANDATA32` and `S_LMANDATA32_ST` for local managed data +/// - `S_GMANDATA32` and `S_GMANDATA32_ST` for global managed data +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct DataSymbol<'t> { + /// Whether this data is global or local. + pub global: bool, + /// Whether this data is managed or unmanaged. + pub managed: bool, + /// Type identifier of the type of data. + pub type_index: TypeIndex, + /// Code offset of the start of the data region. + pub offset: PdbInternalSectionOffset, + /// Name of the data variable. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for DataSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = DataSymbol { + global: matches!(kind, S_GDATA32 | S_GDATA32_ST | S_GMANDATA | S_GMANDATA_ST), + managed: matches!( + kind, + S_LMANDATA | S_LMANDATA_ST | S_GMANDATA | S_GMANDATA_ST + ), + type_index: buf.parse()?, + offset: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// Reference to an imported procedure. +/// +/// Symbol kind `S_PROCREF`, `S_PROCREF_ST`, `S_LPROCREF`, or `S_LPROCREF_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ProcedureReferenceSymbol<'t> { + /// Whether the referenced procedure is global or local. + pub global: bool, + /// SUC of the name. + pub sum_name: u32, + /// Symbol index of the referenced [`ProcedureSymbol`]. + /// + /// Note that this symbol might be located in a different module. + pub symbol_index: SymbolIndex, + /// Index of the module in [`DebugInformation::modules`](crate::DebugInformation::modules) + /// containing the actual symbol. + pub module: Option, + /// Name of the procedure reference. + pub name: Option>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureReferenceSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ProcedureReferenceSymbol { + global: matches!(kind, S_PROCREF | S_PROCREF_ST), + sum_name: buf.parse()?, + symbol_index: buf.parse()?, + module: buf.parse::()?.checked_sub(1).map(usize::from), + name: parse_optional_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// Reference to an imported variable. +/// +/// Symbol kind `S_DATAREF`, or `S_DATAREF_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct DataReferenceSymbol<'t> { + /// SUC of the name. + pub sum_name: u32, + /// Symbol index of the referenced [`DataSymbol`]. + /// + /// Note that this symbol might be located in a different module. + pub symbol_index: SymbolIndex, + /// Index of the module in [`DebugInformation::modules`](crate::DebugInformation::modules) + /// containing the actual symbol. + pub module: Option, + /// Name of the data reference. + pub name: Option>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for DataReferenceSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = DataReferenceSymbol { + sum_name: buf.parse()?, + symbol_index: buf.parse()?, + module: buf.parse::()?.checked_sub(1).map(usize::from), + name: parse_optional_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// Reference to an annotation. +/// +/// Symbol kind `S_ANNOTATIONREF`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct AnnotationReferenceSymbol<'t> { + /// SUC of the name. + pub sum_name: u32, + /// Symbol index of the referenced symbol. + /// + /// Note that this symbol might be located in a different module. + pub symbol_index: SymbolIndex, + /// Index of the module in [`DebugInformation::modules`](crate::DebugInformation::modules) + /// containing the actual symbol. + pub module: Option, + /// Name of the annotation reference. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for AnnotationReferenceSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = AnnotationReferenceSymbol { + sum_name: buf.parse()?, + symbol_index: buf.parse()?, + module: buf.parse::()?.checked_sub(1).map(usize::from), + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// Subtype of [`TrampolineSymbol`]. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TrampolineType { + /// An incremental thunk. + Incremental, + /// Branch island thunk. + BranchIsland, + /// An unknown thunk type. + Unknown, +} + +/// Trampoline thunk. +/// +/// Symbol kind `S_TRAMPOLINE`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct TrampolineSymbol { + /// Trampoline symbol subtype. + pub tramp_type: TrampolineType, + /// Code size of the thunk. + pub size: u16, + /// Code offset of the thunk. + pub thunk: PdbInternalSectionOffset, + /// Code offset of the thunk target. + pub target: PdbInternalSectionOffset, +} + +impl TryFromCtx<'_, SymbolKind> for TrampolineSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let tramp_type = match buf.parse::()? { + 0x00 => TrampolineType::Incremental, + 0x01 => TrampolineType::BranchIsland, + _ => TrampolineType::Unknown, + }; + + let size = buf.parse()?; + let thunk_offset = buf.parse()?; + let target_offset = buf.parse()?; + let thunk_section = buf.parse()?; + let target_section = buf.parse()?; + + let symbol = Self { + tramp_type, + size, + thunk: PdbInternalSectionOffset::new(thunk_section, thunk_offset), + target: PdbInternalSectionOffset::new(target_section, target_offset), + }; + + Ok((symbol, buf.pos())) + } +} + +/// A constant value. +/// +/// Symbol kind `S_CONSTANT`, or `S_CONSTANT_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ConstantSymbol<'t> { + /// Whether this constant has metadata type information. + pub managed: bool, + /// The type of this constant or metadata token. + pub type_index: TypeIndex, + /// The value of this constant. + pub value: Variant, + /// Name of the constant. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ConstantSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ConstantSymbol { + managed: kind == S_MANCONSTANT, + type_index: buf.parse()?, + value: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A user defined type. +/// +/// Symbol kind `S_UDT`, or `S_UDT_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct UserDefinedTypeSymbol<'t> { + /// Identifier of the type. + pub type_index: TypeIndex, + /// Name of the type. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for UserDefinedTypeSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = UserDefinedTypeSymbol { + type_index: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A thread local variable. +/// +/// Symbol kinds: +/// - `S_LTHREAD32`, `S_LTHREAD32_ST` for local thread storage. +/// - `S_GTHREAD32`, or `S_GTHREAD32_ST` for global thread storage. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ThreadStorageSymbol<'t> { + /// Whether this is a global or local thread storage. + pub global: bool, + /// Identifier of the stored type. + pub type_index: TypeIndex, + /// Code offset of the thread local. + pub offset: PdbInternalSectionOffset, + /// Name of the thread local. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ThreadStorageSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ThreadStorageSymbol { + global: matches!(kind, S_GTHREAD32 | S_GTHREAD32_ST), + type_index: buf.parse()?, + offset: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +// CV_PROCFLAGS: +const CV_PFLAG_NOFPO: u8 = 0x01; +const CV_PFLAG_INT: u8 = 0x02; +const CV_PFLAG_FAR: u8 = 0x04; +const CV_PFLAG_NEVER: u8 = 0x08; +const CV_PFLAG_NOTREACHED: u8 = 0x10; +const CV_PFLAG_CUST_CALL: u8 = 0x20; +const CV_PFLAG_NOINLINE: u8 = 0x40; +const CV_PFLAG_OPTDBGINFO: u8 = 0x80; + +/// Flags of a [`ProcedureSymbol`]. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ProcedureFlags { + /// Frame pointer is present (not omitted). + pub nofpo: bool, + /// Interrupt return. + pub int: bool, + /// Far return. + pub far: bool, + /// Procedure does not return. + pub never: bool, + /// Procedure is never called. + pub notreached: bool, + /// Custom calling convention. + pub cust_call: bool, + /// Marked as `noinline`. + pub noinline: bool, + /// Debug information for optimized code is present. + pub optdbginfo: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for ProcedureFlags { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let (value, size) = u8::try_from_ctx(this, le)?; + + let flags = Self { + nofpo: value & CV_PFLAG_NOFPO != 0, + int: value & CV_PFLAG_INT != 0, + far: value & CV_PFLAG_FAR != 0, + never: value & CV_PFLAG_NEVER != 0, + notreached: value & CV_PFLAG_NOTREACHED != 0, + cust_call: value & CV_PFLAG_CUST_CALL != 0, + noinline: value & CV_PFLAG_NOINLINE != 0, + optdbginfo: value & CV_PFLAG_OPTDBGINFO != 0, + }; + + Ok((flags, size)) + } +} + +/// A procedure, such as a function or method. +/// +/// Symbol kinds: +/// - `S_GPROC32`, `S_GPROC32_ST` for global procedures +/// - `S_LPROC32`, `S_LPROC32_ST` for local procedures +/// - `S_LPROC32_DPC` for DPC procedures +/// - `S_GPROC32_ID`, `S_LPROC32_ID`, `S_LPROC32_DPC_ID` for procedures referencing types from the +/// ID stream rather than the Type stream. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ProcedureSymbol<'t> { + /// Whether this is a global or local procedure. + pub global: bool, + /// Indicates Deferred Procedure Calls (DPC). + pub dpc: bool, + /// The parent scope that this procedure is nested in. + pub parent: Option, + /// The end symbol of this procedure. + pub end: SymbolIndex, + /// The next procedure symbol. + pub next: Option, + /// The length of the code block covered by this procedure. + pub len: u32, + /// Start offset of the procedure's body code, which marks the end of the prologue. + pub dbg_start_offset: u32, + /// End offset of the procedure's body code, which marks the start of the epilogue. + pub dbg_end_offset: u32, + /// Identifier of the procedure type. + /// + /// The type contains the complete signature, including parameters, modifiers and the return + /// type. + pub type_index: TypeIndex, + /// Code offset of the start of this procedure. + pub offset: PdbInternalSectionOffset, + /// Detailed flags of this procedure. + pub flags: ProcedureFlags, + /// The full, demangled name of the procedure. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ProcedureSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ProcedureSymbol { + global: matches!(kind, S_GPROC32 | S_GPROC32_ST | S_GPROC32_ID), + dpc: matches!(kind, S_LPROC32_DPC | S_LPROC32_DPC_ID), + parent: parse_optional_index(&mut buf)?, + end: buf.parse()?, + next: parse_optional_index(&mut buf)?, + len: buf.parse()?, + dbg_start_offset: buf.parse()?, + dbg_end_offset: buf.parse()?, + type_index: buf.parse()?, + offset: buf.parse()?, + flags: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// The callsite of an inlined function. +/// +/// Symbol kind `S_INLINESITE`, or `S_INLINESITE2`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct InlineSiteSymbol<'t> { + /// Index of the parent function. + /// + /// This might either be a [`ProcedureSymbol`] or another `InlineSiteSymbol`. + pub parent: Option, + /// The end symbol of this callsite. + pub end: SymbolIndex, + /// Identifier of the type describing the inline function. + pub inlinee: IdIndex, + /// The total number of invocations of the inline function. + pub invocations: Option, + /// Binary annotations containing the line program of this call site. + pub annotations: BinaryAnnotations<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for InlineSiteSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = InlineSiteSymbol { + parent: parse_optional_index(&mut buf)?, + end: buf.parse()?, + inlinee: buf.parse()?, + invocations: match kind { + S_INLINESITE2 => Some(buf.parse()?), + _ => None, + }, + annotations: BinaryAnnotations::new(buf.take(buf.len())?), + }; + + Ok((symbol, buf.pos())) + } +} + +/// Reference to build information. +/// +/// Symbol kind `S_BUILDINFO`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct BuildInfoSymbol { + /// Index of the build information record. + pub id: IdIndex, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for BuildInfoSymbol { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = Self { id: buf.parse()? }; + + Ok((symbol, buf.pos())) + } +} + +/// Name of the object file of this module. +/// +/// Symbol kind `S_OBJNAME`, or `S_OBJNAME_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ObjNameSymbol<'t> { + /// Signature. + pub signature: u32, + /// Path to the object file. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ObjNameSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ObjNameSymbol { + signature: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A version number refered to by `CompileFlagsSymbol`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CompilerVersion { + /// The major version number. + pub major: u16, + /// The minor version number. + pub minor: u16, + /// The build (patch) version number. + pub build: u16, + /// The QFE (quick fix engineering) number. + pub qfe: Option, +} + +impl<'t> TryFromCtx<'t, bool> for CompilerVersion { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], has_qfe: bool) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let version = Self { + major: buf.parse()?, + minor: buf.parse()?, + build: buf.parse()?, + qfe: if has_qfe { Some(buf.parse()?) } else { None }, + }; + + Ok((version, buf.pos())) + } +} + +/// Compile flags declared in `CompileFlagsSymbol`. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CompileFlags { + /// Compiled for edit and continue. + pub edit_and_continue: bool, + /// Compiled without debugging info. + pub no_debug_info: bool, + /// Compiled with `LTCG`. + pub link_time_codegen: bool, + /// Compiled with `/bzalign`. + pub no_data_align: bool, + /// Managed code or data is present. + pub managed: bool, + /// Compiled with `/GS`. + pub security_checks: bool, + /// Compiled with `/hotpatch`. + pub hot_patch: bool, + /// Compiled with `CvtCIL`. + pub cvtcil: bool, + /// This is a MSIL .NET Module. + pub msil_module: bool, + /// Compiled with `/sdl`. + pub sdl: bool, + /// Compiled with `/ltcg:pgo` or `pgo:`. + pub pgo: bool, + /// This is a .exp module. + pub exp_module: bool, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlags { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let is_compile3 = kind == S_COMPILE3; + + let raw = this.pread_with::(0, LE)?; + this.pread::(2)?; // unused + + let flags = Self { + edit_and_continue: raw & 1 != 0, + no_debug_info: (raw >> 1) & 1 != 0, + link_time_codegen: (raw >> 2) & 1 != 0, + no_data_align: (raw >> 3) & 1 != 0, + managed: (raw >> 4) & 1 != 0, + security_checks: (raw >> 5) & 1 != 0, + hot_patch: (raw >> 6) & 1 != 0, + cvtcil: (raw >> 7) & 1 != 0, + msil_module: (raw >> 8) & 1 != 0, + sdl: (raw >> 9) & 1 != 0 && is_compile3, + pgo: (raw >> 10) & 1 != 0 && is_compile3, + exp_module: (raw >> 11) & 1 != 0 && is_compile3, + }; + + Ok((flags, 3)) + } +} + +/// Flags used to compile a module. +/// +/// Symbol kind `S_COMPILE2`, `S_COMPILE2_ST`, or `S_COMPILE3`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CompileFlagsSymbol<'t> { + /// The source code language. + pub language: SourceLanguage, + /// Compiler flags. + pub flags: CompileFlags, + /// Machine type of the compilation target. + pub cpu_type: CPUType, + /// Version of the compiler frontend. + pub frontend_version: CompilerVersion, + /// Version of the compiler backend. + pub backend_version: CompilerVersion, + /// Display name of the compiler. + pub version_string: RawString<'t>, + // TODO: Command block for S_COMPILE2? +} + +impl<'t> TryFromCtx<'t, SymbolKind> for CompileFlagsSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let has_qfe = kind == S_COMPILE3; + let symbol = CompileFlagsSymbol { + language: buf.parse()?, + flags: buf.parse_with(kind)?, + cpu_type: buf.parse()?, + frontend_version: buf.parse_with(has_qfe)?, + backend_version: buf.parse_with(has_qfe)?, + version_string: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A using namespace directive. +/// +/// Symbol kind `S_UNAMESPACE`, or `S_UNAMESPACE_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct UsingNamespaceSymbol<'t> { + /// The name of the imported namespace. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for UsingNamespaceSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = UsingNamespaceSymbol { + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +// CV_LVARFLAGS: +const CV_LVARFLAG_ISPARAM: u16 = 0x01; +const CV_LVARFLAG_ADDRTAKEN: u16 = 0x02; +const CV_LVARFLAG_COMPGENX: u16 = 0x04; +const CV_LVARFLAG_ISAGGREGATE: u16 = 0x08; +const CV_LVARFLAG_ISALIASED: u16 = 0x10; +const CV_LVARFLAG_ISALIAS: u16 = 0x20; +const CV_LVARFLAG_ISRETVALUE: u16 = 0x40; +const CV_LVARFLAG_ISOPTIMIZEDOUT: u16 = 0x80; +const CV_LVARFLAG_ISENREG_GLOB: u16 = 0x100; +const CV_LVARFLAG_ISENREG_STAT: u16 = 0x200; + +/// Flags for a [`LocalSymbol`]. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct LocalVariableFlags { + /// Variable is a parameter. + pub isparam: bool, + /// Address is taken. + pub addrtaken: bool, + /// Variable is compiler generated. + pub compgenx: bool, + /// The symbol is splitted in temporaries, which are treated by compiler as independent + /// entities. + pub isaggregate: bool, + /// Variable has multiple simultaneous lifetimes. + pub isaliased: bool, + /// Represents one of the multiple simultaneous lifetimes. + pub isalias: bool, + /// Represents a function return value. + pub isretvalue: bool, + /// Variable has no lifetimes. + pub isoptimizedout: bool, + /// Variable is an enregistered global. + pub isenreg_glob: bool, + /// Variable is an enregistered static. + pub isenreg_stat: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for LocalVariableFlags { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let (value, size) = u16::try_from_ctx(this, le)?; + + let flags = Self { + isparam: value & CV_LVARFLAG_ISPARAM != 0, + addrtaken: value & CV_LVARFLAG_ADDRTAKEN != 0, + compgenx: value & CV_LVARFLAG_COMPGENX != 0, + isaggregate: value & CV_LVARFLAG_ISAGGREGATE != 0, + isaliased: value & CV_LVARFLAG_ISALIASED != 0, + isalias: value & CV_LVARFLAG_ISALIAS != 0, + isretvalue: value & CV_LVARFLAG_ISRETVALUE != 0, + isoptimizedout: value & CV_LVARFLAG_ISOPTIMIZEDOUT != 0, + isenreg_glob: value & CV_LVARFLAG_ISENREG_GLOB != 0, + isenreg_stat: value & CV_LVARFLAG_ISENREG_STAT != 0, + }; + + Ok((flags, size)) + } +} + +/// A local symbol in optimized code. +/// +/// Symbol kind `S_LOCAL`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct LocalSymbol<'t> { + /// The type of the symbol. + pub type_index: TypeIndex, + /// Flags for this symbol. + pub flags: LocalVariableFlags, + /// Name of the symbol. + pub name: RawString<'t>, + /// Parameter slot + pub slot: Option, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for LocalSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let type_index: TypeIndex = buf.parse()?; + let flags: LocalVariableFlags = buf.parse()?; + let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?; + + let slot: Option = if (this.len() as i64 - name.len() as i64 - 8i64) >= 6 { + if this[name.len() + 0xb] == 0x24 { + Some(ParseBuffer::from(&this[(name.len() + 0xc)..]).parse()?) + } else { + None + } + } else { + None + }; + + Ok(( + Self { + type_index, + flags, + name, + slot, + }, + buf.pos(), + )) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4456 +/// Flags of an [`ExportSymbol`]. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ExportSymbolFlags { + /// An exported constant. + pub constant: bool, + /// Exported data (e.g. a static variable). + pub data: bool, + /// A private symbol. + pub private: bool, + /// A symbol with no name. + pub no_name: bool, + /// Ordinal was explicitly assigned. + pub ordinal: bool, + /// This is a forwarder. + pub forwarder: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for ExportSymbolFlags { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let (value, size) = u16::try_from_ctx(this, le)?; + + let flags = Self { + constant: value & 0x01 != 0, + data: value & 0x02 != 0, + private: value & 0x04 != 0, + no_name: value & 0x08 != 0, + ordinal: value & 0x10 != 0, + forwarder: value & 0x20 != 0, + }; + + Ok((flags, size)) + } +} + +/// An exported symbol. +/// +/// Symbol kind `S_EXPORT`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ExportSymbol<'t> { + /// Ordinal of the symbol. + pub ordinal: u16, + /// Flags declaring the type of the exported symbol. + pub flags: ExportSymbolFlags, + /// The name of the exported symbol. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ExportSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = ExportSymbol { + ordinal: buf.parse()?, + flags: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A label symbol. +/// +/// Symbol kind `S_LABEL32`, `S_LABEL16`, or `S_LABEL32_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct LabelSymbol<'t> { + /// Code offset of the start of this label. + pub offset: PdbInternalSectionOffset, + /// Detailed flags of this label. + pub flags: ProcedureFlags, + /// Name of the symbol. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for LabelSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = LabelSymbol { + offset: buf.parse()?, + flags: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A block symbol. +/// +/// Symbol kind `S_BLOCK32`, or `S_BLOCK32_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct BlockSymbol<'t> { + /// The parent scope that this block is nested in. + pub parent: SymbolIndex, + /// The end symbol of this block. + pub end: SymbolIndex, + /// The length of the block. + pub len: u32, + /// Code offset of the start of this label. + pub offset: PdbInternalSectionOffset, + /// The block name. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for BlockSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = BlockSymbol { + parent: buf.parse()?, + end: buf.parse()?, + len: buf.parse()?, + offset: buf.parse()?, + name: parse_symbol_name(&mut buf, kind)?, + }; + + Ok((symbol, buf.pos())) + } +} + +/// A register relative symbol. +/// +/// The address of the variable is the value in the register + offset (e.g. %EBP + 8). +/// +/// Symbol kind `S_REGREL32`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RegisterRelativeSymbol<'t> { + /// The variable offset. + pub offset: i32, + /// The type of the variable. + pub type_index: TypeIndex, + /// The register this variable address is relative to. + pub register: Register, + /// The variable name. + pub name: RawString<'t>, + /// Parameter slot + pub slot: Option, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for RegisterRelativeSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let offset: i32 = buf.parse()?; + let type_index: TypeIndex = buf.parse()?; + let register: Register = buf.parse()?; + let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?; + + let slot: Option = if (this.len() as i64 - name.len() as i64 - 0xci64) >= 6 { + if this[name.len() + 0xf] == 0x24 { + Some(ParseBuffer::from(&this[(name.len() + 0x10)..]).parse()?) + } else { + None + } + } else { + None + }; + + Ok(( + Self { + offset, + type_index, + register, + name, + slot, + }, + buf.pos(), + )) + } +} + +/// Thunk adjustor +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ThunkAdjustor<'t> { + delta: u16, + target: RawString<'t>, +} + +/// A thunk kind +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ThunkKind<'t> { + /// Standard thunk + NoType, + /// "this" adjustor thunk with delta and target + Adjustor(ThunkAdjustor<'t>), + /// Virtual call thunk with table entry + VCall(u16), + /// pcode thunk + PCode, + /// thunk which loads the address to jump to via unknown means... + Load, + /// Unknown with ordinal value + Unknown(u8), +} + +/// A thunk symbol. +/// +/// Symbol kind `S_THUNK32`, or `S_THUNK32_ST`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ThunkSymbol<'t> { + /// The parent scope that this thunk is nested in. + pub parent: Option, + /// The end symbol of this thunk. + pub end: SymbolIndex, + /// The next symbol. + pub next: Option, + /// Code offset of the start of this label. + pub offset: PdbInternalSectionOffset, + /// The length of the thunk. + pub len: u16, + /// The kind of the thunk. + pub kind: ThunkKind<'t>, + /// The thunk name. + pub name: RawString<'t>, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for ThunkSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let parent = parse_optional_index(&mut buf)?; + let end = buf.parse()?; + let next = parse_optional_index(&mut buf)?; + let offset = buf.parse()?; + let len = buf.parse()?; + let ord = buf.parse::()?; + let name = parse_symbol_name(&mut buf, kind)?; + + let kind = match ord { + 0 => ThunkKind::NoType, + 1 => ThunkKind::Adjustor(ThunkAdjustor { + delta: buf.parse::()?, + target: buf.parse_cstring()?, + }), + 2 => ThunkKind::VCall(buf.parse::()?), + 3 => ThunkKind::PCode, + 4 => ThunkKind::Load, + ord => ThunkKind::Unknown(ord), + }; + + let symbol = ThunkSymbol { + parent, + end, + next, + offset, + len, + kind, + name, + }; + + Ok((symbol, buf.pos())) + } +} + +// CV_SEPCODEFLAGS: +const CV_SEPCODEFLAG_IS_LEXICAL_SCOPE: u32 = 0x01; +const CV_SEPCODEFLAG_RETURNS_TO_PARENT: u32 = 0x02; + +/// Flags for a [`SeparatedCodeSymbol`]. +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SeparatedCodeFlags { + /// S_SEPCODE doubles as lexical scope. + pub islexicalscope: bool, + /// code frag returns to parent. + pub returnstoparent: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for SeparatedCodeFlags { + type Error = scroll::Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> scroll::Result<(Self, usize)> { + let (value, size) = u32::try_from_ctx(this, le)?; + + let flags = Self { + islexicalscope: value & CV_SEPCODEFLAG_IS_LEXICAL_SCOPE != 0, + returnstoparent: value & CV_SEPCODEFLAG_RETURNS_TO_PARENT != 0, + }; + + Ok((flags, size)) + } +} + +/// A separated code symbol. +/// +/// Symbol kind `S_SEPCODE`. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SeparatedCodeSymbol { + /// The parent scope that this block is nested in. + pub parent: SymbolIndex, + /// The end symbol of this block. + pub end: SymbolIndex, + /// The length of the block. + pub len: u32, + /// Flags for this symbol + pub flags: SeparatedCodeFlags, + /// Code offset of the start of the separated code. + pub offset: PdbInternalSectionOffset, + /// Parent offset. + pub parent_offset: PdbInternalSectionOffset, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for SeparatedCodeSymbol { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let parent = buf.parse()?; + let end = buf.parse()?; + let len = buf.parse()?; + let flags = buf.parse()?; + let offset = buf.parse()?; + let parent_offset = buf.parse()?; + let section = buf.parse()?; + let parent_section = buf.parse()?; + + let symbol = Self { + parent, + end, + len, + flags, + offset: PdbInternalSectionOffset { offset, section }, + parent_offset: PdbInternalSectionOffset { + offset: parent_offset, + section: parent_section, + }, + }; + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3102 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct AddressRange { + pub offset: PdbInternalSectionOffset, + pub cb_range: u16, +} + +impl<'t> TryFromCtx<'t, Endian> for AddressRange { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _le: Endian) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let range = Self { + offset: buf.parse()?, + cb_range: buf.parse()?, + }; + + Ok((range, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3111 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct AddressGap { + /// Relative offset from the beginning of the live range + pub gap_start_offset: u16, + /// Length of the gap + pub cb_range: u16, +} + +impl<'t> TryFromCtx<'t, Endian> for AddressGap { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _: Endian) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let range = Self { + gap_start_offset: buf.parse()?, + cb_range: buf.parse()?, + }; + + Ok((range, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4209 +/// A live range of sub field of variable +/// +/// Symbol kind `S_DEFRANGE`. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeSymbol { + /// DIA program to evaluate the value of the symbol + pub program: u32, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 16 /* sizeof(DEFRANGESYM) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + let mut symbol = Self { + program: buf.parse()?, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3102 +/// A live range of sub field of variable. like locala.i +/// +/// Symbol kind `S_DEFRANGE_SUBFIELD` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeSubFieldSymbol { + /// DIA program to evaluate the value of the symbol + pub program: u32, + /// Offset in parent variable. + pub parent_offset: u32, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeSubFieldSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 20 /* sizeof(DEFRANGESYMSUBFIELD) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + let mut symbol = Self { + program: buf.parse()?, + parent_offset: buf.parse()?, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4231 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct RangeFlags { + /// May have no user name on one of control flow path. + pub maybe: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for RangeFlags { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> std::result::Result<(Self, usize), Self::Error> { + let (value, size) = u16::try_from_ctx(this, le)?; + + let flags = Self { + maybe: value & 0x01 != 0, + }; + + Ok((flags, size)) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4236 +/// A live range of en-registed variable +/// +/// Symbol type `S_DEFRANGE_REGISTER` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeRegisterSymbol { + /// Register to hold the value of the symbol + pub register: Register, + /// Attribute of the register range. + pub flags: RangeFlags, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeRegisterSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 16 /* sizeof(DEFRANGESYM) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + let mut symbol = Self { + register: buf.parse()?, + flags: buf.parse()?, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4245 +/// A live range of frame variable +/// +/// Symbol type `S_DEFRANGE_FRAMEPOINTER_REL` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeFramePointerRelativeSymbol { + /// offset to frame pointer + pub offset: i32, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeFramePointerRelativeSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 16 /* sizeof(DEFRANGESYM) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + let mut symbol = Self { + offset: buf.parse()?, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4255 +/// A frame variable valid in all function scope +/// +/// Symbol type `S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE` +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct DefRangeFramePointerRelativeFullScopeSymbol { + /// offset to frame pointer + pub offset: i32, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeFramePointerRelativeFullScopeSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = Self { + offset: buf.parse()?, + }; + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4264 +/// A live range of sub field of variable. like locala.i +/// +/// Symbol type `S_DEFRANGE_SUBFIELD_REGISTER` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeSubFieldRegisterSymbol { + /// Register to hold the value of the symbol + pub register: Register, + /// Attribute of the register range. + pub flags: RangeFlags, + /// Offset in parent variable. + pub offset: u32, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeSubFieldRegisterSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 20 /* sizeof(DEFRANGESYMSUBFIELD) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + + let register: Register = buf.parse()?; + let flags: RangeFlags = buf.parse()?; + let offset_padding: u32 = buf.parse()?; + let offset = offset_padding & 0xFFFu32; + + let mut symbol = Self { + register, + flags, + offset, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4279 +/// A live range of variable related to a register. +/// +/// Symbol type `S_DEFRANGE_REGISTER_REL` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DefRangeRegisterRelativeSymbol { + /// Register to hold the base pointer of the symbol + pub base_register: Register, + /// Spilled member for s.i. + pub spilled_udt_member: u16, + /// Offset in parent variable. + pub offset_parent: u16, + /// offset to register + pub offset_base_pointer: i32, + /// Range of addresses where this program is valid + pub range: AddressRange, + /// The value is not available in following gaps + pub gaps: Vec, +} + +impl TryFromCtx<'_, SymbolKind> for DefRangeRegisterRelativeSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4313 + let gap_count = ( + buf.len() + 4 /* sizeof(reclen) + buf offset */ + - 20 /* sizeof(DEFRANGESYMSUBFIELD) */ + ) / 4 /* sizeof(CV_LVAR_ADDR_GAP) */; + + let base_register: Register = buf.parse()?; + let bitfield: u16 = buf.parse()?; + let spilled_udt_member = bitfield & 0x1; + let offset_parent = (bitfield >> 4) & 0xFFF; + + let mut symbol = Self { + base_register, + spilled_udt_member, + offset_parent, + offset_base_pointer: buf.parse()?, + range: buf.parse()?, + gaps: vec![], + }; + for _ in 0..gap_count { + symbol.gaps.push(buf.parse()?); + } + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L3573 +/// BP-Relative variable +/// +/// Symbol type `S_BPREL32`, `S_BPREL32_ST`, `S_BPREL16`, `S_BPREL32_16t` +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BasePointerRelativeSymbol<'t> { + /// BP-relative offset + pub offset: i32, + /// Type index or Metadata token + pub type_index: TypeIndex, + /// Length-prefixed name + pub name: RawString<'t>, + /// Parameter slot + pub slot: Option, +} + +impl<'t> TryFromCtx<'t, SymbolKind> for BasePointerRelativeSymbol<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let offset: i32 = buf.parse()?; + let type_index = match kind { + S_BPREL32 | S_BPREL32_ST => buf.parse()?, + S_BPREL32_16t => TypeIndex::from(buf.parse::()? as u32), + _ => return Err(Error::UnimplementedSymbolKind(kind)), + }; + let name: RawString<'t> = parse_symbol_name(&mut buf, kind)?; + + let slot: Option = if (this.len() as i64 - name.len() as i64 - 0xai64) >= 6 { + if this[name.len() + 0xd] == 0x24 { + Some(ParseBuffer::from(&this[(name.len() + 0xe)..]).parse()?) + } else { + None + } + } else { + None + }; + + Ok(( + Self { + offset, + type_index, + name, + slot, + }, + buf.pos(), + )) + } +} + +/// Frame procedure flags declared in `FrameProcedureSymbol` +#[non_exhaustive] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FrameProcedureFlags { + /// function uses `_alloca()` + has_alloca: bool, + /// function uses `setjmp()` + has_setjmp: bool, + /// function uses `longjmp()` + has_longjmp: bool, + /// function uses inline asm + has_inline_asm: bool, + /// function has EH states + has_eh: bool, + /// function was speced as inline + inline_spec: bool, + /// function has `SEH` + has_seh: bool, + /// function is `__declspec(naked)` + naked: bool, + /// function has buffer security check introduced by `/GS`. + security_checks: bool, + /// function compiled with `/EHa` + async_eh: bool, + /// function has `/GS` buffer checks, but stack ordering couldn't be done + gs_no_stack_ordering: bool, + /// function was inlined within another function + was_inlined: bool, + /// function is `__declspec(strict_gs_check)` + gs_check: bool, + /// function is `__declspec(safebuffers)` + safe_buffers: bool, + /// record function's local pointer explicitly. + encoded_local_base_pointer: u8, + /// record function's parameter pointer explicitly. + encoded_param_base_pointer: u8, + /// function was compiled with `PGO/PGU` + pogo_on: bool, + /// Do we have valid Pogo counts? + valid_counts: bool, + /// Did we optimize for speed? + opt_speed: bool, + /// function contains CFG checks (and no write checks) + guard_cf: bool, + /// function contains CFW checks and/or instrumentation + guard_cfw: bool, +} + +impl<'t> TryFromCtx<'t, Endian> for FrameProcedureFlags { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], le: Endian) -> Result<(Self, usize)> { + let raw = this.pread_with::(0, le)?; + let flags = Self { + has_alloca: raw & 1 != 0, + has_setjmp: (raw >> 1) & 1 != 0, + has_longjmp: (raw >> 2) & 1 != 0, + has_inline_asm: (raw >> 3) & 1 != 0, + has_eh: (raw >> 4) & 1 != 0, + inline_spec: (raw >> 5) & 1 != 0, + has_seh: (raw >> 6) & 1 != 0, + naked: (raw >> 7) & 1 != 0, + security_checks: (raw >> 8) & 1 != 0, + async_eh: (raw >> 9) & 1 != 0, + gs_no_stack_ordering: (raw >> 10) & 1 != 0, + was_inlined: (raw >> 11) & 1 != 0, + gs_check: (raw >> 12) & 1 != 0, + safe_buffers: (raw >> 13) & 1 != 0, + encoded_local_base_pointer: (raw >> 14) as u8 & 3, + encoded_param_base_pointer: (raw >> 16) as u8 & 3, + pogo_on: (raw >> 18) & 1 != 0, + valid_counts: (raw >> 19) & 1 != 0, + opt_speed: (raw >> 20) & 1 != 0, + guard_cf: (raw >> 21) & 1 != 0, + guard_cfw: (raw >> 22) & 1 != 0, + }; + + Ok((flags, 4)) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4069 +/// Extra frame and proc information +/// +/// Symbol type `S_FRAMEPROC` +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FrameProcedureSymbol { + /// count of bytes of total frame of procedure + pub frame_byte_count: u32, + /// count of bytes of padding in the frame + pub padding_byte_count: u32, + /// offset (relative to frame pointer) to where padding starts + pub offset_padding: u32, + /// count of bytes of callee save registers + pub callee_save_registers_byte_count: u32, + /// offset of exception handler + pub exception_handler_offset: PdbInternalSectionOffset, + pub flags: FrameProcedureFlags, +} + +impl TryFromCtx<'_, SymbolKind> for FrameProcedureSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let symbol = FrameProcedureSymbol { + frame_byte_count: buf.parse()?, + padding_byte_count: buf.parse()?, + offset_padding: buf.parse()?, + callee_save_registers_byte_count: buf.parse()?, + exception_handler_offset: buf.parse()?, + flags: buf.parse_with(LE)?, + }; + + Ok((symbol, buf.pos())) + } +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L4491 +/// Indirect call site information +/// +/// Symbol type `S_CALLSITEINFO` +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct CallSiteInfoSymbol { + /// offset of call site + pub offset: PdbInternalSectionOffset, + /// type index describing function signature + pub type_index: TypeIndex, +} + +impl TryFromCtx<'_, SymbolKind> for CallSiteInfoSymbol { + type Error = Error; + + fn try_from_ctx(this: &'_ [u8], _kind: SymbolKind) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + + let offset: PdbInternalSectionOffset = buf.parse()?; + let _padding = buf.parse::()?; + let type_index: TypeIndex = buf.parse()?; + let symbol = Self { offset, type_index }; + + Ok((symbol, buf.pos())) + } +} + +/// PDB symbol tables contain names, locations, and metadata about functions, global/static data, +/// constants, data types, and more. +/// +/// The `SymbolTable` holds a `SourceView` referencing the symbol table inside the PDB file. All the +/// data structures returned by a `SymbolTable` refer to that buffer. +/// +/// # Example +/// +/// ``` +/// # use pdb::FallibleIterator; +/// # +/// # fn test() -> pdb::Result { +/// let file = std::fs::File::open("fixtures/self/foo.pdb")?; +/// let mut pdb = pdb::PDB::open(file)?; +/// +/// let symbol_table = pdb.global_symbols()?; +/// let address_map = pdb.address_map()?; +/// +/// # let mut count: usize = 0; +/// let mut symbols = symbol_table.iter(); +/// while let Some(symbol) = symbols.next()? { +/// match symbol.parse() { +/// Ok(pdb::SymbolData::Public(data)) if data.function => { +/// // we found the location of a function! +/// let rva = data.offset.to_rva(&address_map).unwrap_or_default(); +/// println!("{} is {}", rva, data.name); +/// # count += 1; +/// } +/// _ => {} +/// } +/// } +/// +/// # Ok(count) +/// # } +/// # assert!(test().expect("test") > 2000); +/// ``` +#[derive(Debug)] +pub struct SymbolTable<'s> { + stream: Stream<'s>, +} + +impl<'s> SymbolTable<'s> { + /// Parses a symbol table from raw stream data. + pub(crate) fn new(stream: Stream<'s>) -> Self { + SymbolTable { stream } + } + + /// Returns an iterator that can traverse the symbol table in sequential order. + pub fn iter(&self) -> SymbolIter<'_> { + SymbolIter::new(self.stream.parse_buffer()) + } + + /// Returns an iterator over symbols starting at the given index. + pub fn iter_at(&self, index: SymbolIndex) -> SymbolIter<'_> { + let mut iter = self.iter(); + iter.seek(index); + iter + } +} + +/// A `SymbolIter` iterates over a `SymbolTable`, producing `Symbol`s. +/// +/// Symbol tables are represented internally as a series of records, each of which have a length, a +/// type, and a type-specific field layout. Iteration performance is therefore similar to a linked +/// list. +#[derive(Debug)] +pub struct SymbolIter<'t> { + buf: ParseBuffer<'t>, +} + +impl<'t> SymbolIter<'t> { + pub(crate) fn new(buf: ParseBuffer<'t>) -> SymbolIter<'t> { + SymbolIter { buf } + } + + /// Move the iterator to the symbol referred to by `index`. + /// + /// This can be used to jump to the sibiling or parent of a symbol record. + pub fn seek(&mut self, index: SymbolIndex) { + self.buf.seek(index.0 as usize); + } + + /// Skip to the symbol referred to by `index`, returning the symbol. + /// + /// This can be used to jump to the sibiling or parent of a symbol record. Iteration continues + /// after that symbol. + /// + /// Note that the symbol may be located **before** the originating symbol, for instance when + /// jumping to the parent symbol. Take care not to enter an endless loop in this case. + pub fn skip_to(&mut self, index: SymbolIndex) -> Result>> { + self.seek(index); + self.next() + } +} + +impl<'t> FallibleIterator for SymbolIter<'t> { + type Item = Symbol<'t>; + type Error = Error; + + fn next(&mut self) -> Result> { + while !self.buf.is_empty() { + let index = SymbolIndex(self.buf.pos() as u32); + + // read the length of the next symbol + let symbol_length = self.buf.parse::()? as usize; + if symbol_length < 2 { + // this can't be correct + return Err(Error::SymbolTooShort); + } + + // grab the symbol itself + let data = self.buf.take(symbol_length)?; + let symbol = Symbol { index, data }; + + // skip over padding in the symbol table + match symbol.raw_kind() { + S_ALIGN | S_SKIP => continue, + _ => return Ok(Some(symbol)), + } + } + + Ok(None) + } +} + +#[cfg(test)] +mod tests { + mod parsing { + use crate::symbol::*; + + #[test] + fn kind_0006() { + let data = &[6, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x0006); + assert_eq!(symbol.parse().expect("parse"), SymbolData::ScopeEnd); + } + + #[test] + fn kind_1101() { + let data = &[1, 17, 0, 0, 0, 0, 42, 32, 67, 73, 76, 32, 42, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1101); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::ObjName(ObjNameSymbol { + signature: 0, + name: "* CIL *".into(), + }) + ); + } + + #[test] + fn kind_1102() { + let data = &[ + 2, 17, 0, 0, 0, 0, 108, 22, 0, 0, 0, 0, 0, 0, 140, 11, 0, 0, 1, 0, 9, 0, 3, 91, + 116, 104, 117, 110, 107, 93, 58, 68, 101, 114, 105, 118, 101, 100, 58, 58, 70, 117, + 110, 99, 49, 96, 97, 100, 106, 117, 115, 116, 111, 114, 123, 56, 125, 39, 0, 0, 0, + 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1102); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Thunk(ThunkSymbol { + parent: None, + end: SymbolIndex(0x166c), + next: None, + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xb8c + }, + len: 9, + kind: ThunkKind::PCode, + name: "[thunk]:Derived::Func1`adjustor{8}'".into() + }) + ); + } + + #[test] + fn kind_1105() { + let data = &[ + 5, 17, 224, 95, 151, 0, 1, 0, 0, 100, 97, 118, 49, 100, 95, 119, 95, 97, 118, 103, + 95, 115, 115, 115, 101, 51, 0, 0, 0, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1105); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Label(LabelSymbol { + offset: PdbInternalSectionOffset { + offset: 0x0097_5fe0, + section: 1 + }, + flags: ProcedureFlags { + nofpo: false, + int: false, + far: false, + never: false, + notreached: false, + cust_call: false, + noinline: false, + optdbginfo: false + }, + name: "dav1d_w_avg_ssse3".into(), + }) + ); + } + + #[test] + fn kind_1106() { + let data = &[6, 17, 120, 34, 0, 0, 18, 0, 116, 104, 105, 115, 0, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1106); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::RegisterVariable(RegisterVariableSymbol { + type_index: TypeIndex(8824), + register: Register(18), + slot: None, + name: "this".into(), + }) + ); + } + + #[test] + fn kind_110e() { + let data = &[ + 14, 17, 2, 0, 0, 0, 192, 85, 0, 0, 1, 0, 95, 95, 108, 111, 99, 97, 108, 95, 115, + 116, 100, 105, 111, 95, 112, 114, 105, 110, 116, 102, 95, 111, 112, 116, 105, 111, + 110, 115, 0, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x110e); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Public(PublicSymbol { + code: false, + function: true, + managed: false, + msil: false, + offset: PdbInternalSectionOffset { + offset: 21952, + section: 1 + }, + name: "__local_stdio_printf_options".into(), + }) + ); + } + + #[test] + fn kind_1111() { + let data = &[ + 17, 17, 12, 0, 0, 0, 48, 16, 0, 0, 22, 0, 109, 97, 120, 105, 109, 117, 109, 95, 99, + 111, 117, 110, 116, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1111); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::RegisterRelative(RegisterRelativeSymbol { + offset: 12, + type_index: TypeIndex(0x1030), + register: Register(22), + slot: None, + name: "maximum_count".into(), + }) + ); + } + + #[test] + fn kind_1124() { + let data = &[36, 17, 115, 116, 100, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1124); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::UsingNamespace(UsingNamespaceSymbol { name: "std".into() }) + ); + } + + #[test] + fn kind_1125() { + let data = &[ + 37, 17, 0, 0, 0, 0, 108, 0, 0, 0, 1, 0, 66, 97, 122, 58, 58, 102, 95, 112, 117, 98, + 108, 105, 99, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1125); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::ProcedureReference(ProcedureReferenceSymbol { + global: true, + sum_name: 0, + symbol_index: SymbolIndex(108), + module: Some(0), + name: Some("Baz::f_public".into()), + }) + ); + } + + #[test] + fn kind_1108() { + let data = &[8, 17, 112, 6, 0, 0, 118, 97, 95, 108, 105, 115, 116, 0]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1108); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::UserDefinedType(UserDefinedTypeSymbol { + type_index: TypeIndex(1648), + name: "va_list".into(), + }) + ); + } + + #[test] + fn kind_1107() { + let data = &[ + 7, 17, 201, 18, 0, 0, 1, 0, 95, 95, 73, 83, 65, 95, 65, 86, 65, 73, 76, 65, 66, 76, + 69, 95, 83, 83, 69, 50, 0, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1107); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Constant(ConstantSymbol { + managed: false, + type_index: TypeIndex(4809), + value: Variant::U16(1), + name: "__ISA_AVAILABLE_SSE2".into(), + }) + ); + } + + #[test] + fn kind_110d() { + let data = &[ + 13, 17, 116, 0, 0, 0, 16, 0, 0, 0, 3, 0, 95, 95, 105, 115, 97, 95, 97, 118, 97, + 105, 108, 97, 98, 108, 101, 0, 0, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x110d); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Data(DataSymbol { + global: true, + managed: false, + type_index: TypeIndex(116), + offset: PdbInternalSectionOffset { + offset: 16, + section: 3 + }, + name: "__isa_available".into(), + }) + ); + } + + #[test] + fn kind_110c() { + let data = &[ + 12, 17, 32, 0, 0, 0, 240, 36, 1, 0, 2, 0, 36, 120, 100, 97, 116, 97, 115, 121, 109, + 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x110c); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Data(DataSymbol { + global: false, + managed: false, + type_index: TypeIndex(32), + offset: PdbInternalSectionOffset { + offset: 74992, + section: 2 + }, + name: "$xdatasym".into(), + }) + ); + } + + #[test] + fn kind_1127() { + let data = &[ + 39, 17, 0, 0, 0, 0, 128, 4, 0, 0, 182, 0, 99, 97, 112, 116, 117, 114, 101, 95, 99, + 117, 114, 114, 101, 110, 116, 95, 99, 111, 110, 116, 101, 120, 116, 0, 0, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1127); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::ProcedureReference(ProcedureReferenceSymbol { + global: false, + sum_name: 0, + symbol_index: SymbolIndex(1152), + module: Some(181), + name: Some("capture_current_context".into()), + }) + ); + } + + #[test] + fn kind_112c() { + let data = &[44, 17, 0, 0, 5, 0, 5, 0, 0, 0, 32, 124, 0, 0, 2, 0, 2, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + + assert_eq!(symbol.raw_kind(), 0x112c); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Trampoline(TrampolineSymbol { + tramp_type: TrampolineType::Incremental, + size: 0x5, + thunk: PdbInternalSectionOffset { + offset: 0x5, + section: 0x2 + }, + target: PdbInternalSectionOffset { + offset: 0x7c20, + section: 0x2 + }, + }) + ); + } + + #[test] + fn kind_1110() { + let data = &[ + 16, 17, 0, 0, 0, 0, 48, 2, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 7, + 16, 0, 0, 64, 85, 0, 0, 1, 0, 0, 66, 97, 122, 58, 58, 102, 95, 112, 114, 111, 116, + 101, 99, 116, 101, 100, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1110); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Procedure(ProcedureSymbol { + global: true, + dpc: false, + parent: None, + end: SymbolIndex(560), + next: None, + len: 6, + dbg_start_offset: 5, + dbg_end_offset: 5, + type_index: TypeIndex(4103), + offset: PdbInternalSectionOffset { + offset: 21824, + section: 1 + }, + flags: ProcedureFlags { + nofpo: false, + int: false, + far: false, + never: false, + notreached: false, + cust_call: false, + noinline: false, + optdbginfo: false + }, + name: "Baz::f_protected".into(), + }) + ); + } + + #[test] + fn kind_1103() { + let data = &[ + 3, 17, 244, 149, 9, 0, 40, 151, 9, 0, 135, 1, 0, 0, 108, 191, 184, 2, 1, 0, 0, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1103); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Block(BlockSymbol { + parent: SymbolIndex(0x0009_95f4), + end: SymbolIndex(0x0009_9728), + len: 391, + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x02b8_bf6c + }, + name: "".into(), + }) + ); + } + + #[test] + fn kind_110f() { + let data = &[ + 15, 17, 0, 0, 0, 0, 156, 1, 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, 4, 0, 0, 0, 9, 0, 0, 0, + 128, 16, 0, 0, 196, 87, 0, 0, 1, 0, 128, 95, 95, 115, 99, 114, 116, 95, 99, 111, + 109, 109, 111, 110, 95, 109, 97, 105, 110, 0, 0, 0, + ]; + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x110f); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Procedure(ProcedureSymbol { + global: false, + dpc: false, + parent: None, + end: SymbolIndex(412), + next: None, + len: 18, + dbg_start_offset: 4, + dbg_end_offset: 9, + type_index: TypeIndex(4224), + offset: PdbInternalSectionOffset { + offset: 22468, + section: 1 + }, + flags: ProcedureFlags { + nofpo: false, + int: false, + far: false, + never: false, + notreached: false, + cust_call: false, + noinline: false, + optdbginfo: true + }, + name: "__scrt_common_main".into(), + }) + ); + } + + #[test] + fn kind_1116() { + let data = &[ + 22, 17, 7, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 14, 0, 10, 0, 115, 98, 77, 105, 99, + 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 76, 73, 78, 75, 0, 0, 0, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1116); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::CompileFlags(CompileFlagsSymbol { + language: SourceLanguage::Link, + flags: CompileFlags { + edit_and_continue: false, + no_debug_info: false, + link_time_codegen: false, + no_data_align: false, + managed: false, + security_checks: false, + hot_patch: false, + cvtcil: false, + msil_module: false, + sdl: false, + pgo: false, + exp_module: false, + }, + cpu_type: CPUType::Intel80386, + frontend_version: CompilerVersion { + major: 0, + minor: 0, + build: 0, + qfe: None, + }, + backend_version: CompilerVersion { + major: 14, + minor: 10, + build: 25203, + qfe: None, + }, + version_string: "Microsoft (R) LINK".into(), + }) + ); + } + + #[test] + fn kind_1132() { + let data = &[ + 50, 17, 0, 0, 0, 0, 108, 0, 0, 0, 88, 0, 0, 0, 0, 0, 0, 0, 196, 252, 10, 0, 56, 67, + 0, 0, 1, 0, 1, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1132); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::SeparatedCode(SeparatedCodeSymbol { + parent: SymbolIndex(0x0), + end: SymbolIndex(0x6c), + len: 88, + flags: SeparatedCodeFlags { + islexicalscope: false, + returnstoparent: false + }, + offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0xafcc4 + }, + parent_offset: PdbInternalSectionOffset { + section: 0x1, + offset: 0x4338 + } + }) + ); + } + + #[test] + fn kind_113c() { + let data = &[ + 60, 17, 1, 36, 2, 0, 7, 0, 19, 0, 13, 0, 6, 102, 0, 0, 19, 0, 13, 0, 6, 102, 0, 0, + 77, 105, 99, 114, 111, 115, 111, 102, 116, 32, 40, 82, 41, 32, 79, 112, 116, 105, + 109, 105, 122, 105, 110, 103, 32, 67, 111, 109, 112, 105, 108, 101, 114, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x113c); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::CompileFlags(CompileFlagsSymbol { + language: SourceLanguage::Cpp, + flags: CompileFlags { + edit_and_continue: false, + no_debug_info: false, + link_time_codegen: true, + no_data_align: false, + managed: false, + security_checks: true, + hot_patch: false, + cvtcil: false, + msil_module: false, + sdl: true, + pgo: false, + exp_module: false, + }, + cpu_type: CPUType::Pentium3, + frontend_version: CompilerVersion { + major: 19, + minor: 13, + build: 26118, + qfe: Some(0), + }, + backend_version: CompilerVersion { + major: 19, + minor: 13, + build: 26118, + qfe: Some(0), + }, + version_string: "Microsoft (R) Optimizing Compiler".into(), + }) + ); + } + + #[test] + fn kind_113e() { + let data = &[62, 17, 193, 19, 0, 0, 1, 0, 116, 104, 105, 115, 0, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x113e); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::Local(LocalSymbol { + type_index: TypeIndex(5057), + flags: LocalVariableFlags { + isparam: true, + addrtaken: false, + compgenx: false, + isaggregate: false, + isaliased: false, + isalias: false, + isretvalue: false, + isoptimizedout: false, + isenreg_glob: false, + isenreg_stat: false, + }, + slot: None, + name: "this".into(), + }) + ); + } + + #[test] + fn kind_114c() { + let data = &[76, 17, 95, 17, 0, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x114c); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::BuildInfo(BuildInfoSymbol { + id: IdIndex(0x115F) + }) + ); + } + + #[test] + fn kind_114d() { + let data = &[ + 77, 17, 144, 1, 0, 0, 208, 1, 0, 0, 121, 17, 0, 0, 12, 6, 3, 0, + ]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x114d); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::InlineSite(InlineSiteSymbol { + parent: Some(SymbolIndex(0x0190)), + end: SymbolIndex(0x01d0), + inlinee: IdIndex(4473), + invocations: None, + annotations: BinaryAnnotations::new(&[12, 6, 3, 0]), + }) + ); + } + + #[test] + fn kind_114e() { + let data = &[78, 17]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x114e); + assert_eq!(symbol.parse().expect("parse"), SymbolData::InlineSiteEnd); + } + + #[test] + fn kind_1141() { + let data = &[65, 17, 17, 0, 0, 0, 70, 40, 0, 0, 1, 0, 66, 0, 44, 0, 19, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1141); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::DefRangeRegister(DefRangeRegisterSymbol { + register: Register(17), + flags: RangeFlags { maybe: false }, + range: AddressRange { + offset: PdbInternalSectionOffset { + offset: 0x2846, + section: 1, + }, + cb_range: 0x42, + }, + gaps: vec![AddressGap { + gap_start_offset: 0x2c, + cb_range: 0x13 + }] + }) + ); + + let data = &[65, 17, 19, 0, 1, 0, 156, 41, 0, 0, 1, 0, 2, 0]; + + let symbol = Symbol { + data, + index: SymbolIndex(0), + }; + assert_eq!(symbol.raw_kind(), 0x1141); + assert_eq!( + symbol.parse().expect("parse"), + SymbolData::DefRangeRegister(DefRangeRegisterSymbol { + register: Register(0x13), + flags: RangeFlags { maybe: true }, + range: AddressRange { + offset: PdbInternalSectionOffset { + offset: 0x299c, + section: 1, + }, + cb_range: 2, + }, + gaps: vec![] + }) + ); + } + } + + mod iterator { + use crate::symbol::*; + + fn create_iter() -> SymbolIter<'static> { + let data = &[ + 0x00, 0x00, 0x00, 0x00, // module signature (padding) + 0x02, 0x00, 0x4e, 0x11, // S_INLINESITE_END + 0x02, 0x00, 0x06, 0x00, // S_END + ]; + + let mut buf = ParseBuffer::from(&data[..]); + buf.seek(4); // skip the module signature + SymbolIter::new(buf) + } + + #[test] + fn test_iter() { + let symbols: Vec<_> = create_iter().collect().expect("collect"); + + let expected = [ + Symbol { + index: SymbolIndex(0x4), + data: &[0x4e, 0x11], // S_INLINESITE_END + }, + Symbol { + index: SymbolIndex(0x8), + data: &[0x06, 0x00], // S_END + }, + ]; + + assert_eq!(symbols, expected); + } + + #[test] + fn test_seek() { + let mut symbols = create_iter(); + symbols.seek(SymbolIndex(0x8)); + + let symbol = symbols.next().expect("get symbol"); + let expected = Symbol { + index: SymbolIndex(0x8), + data: &[0x06, 0x00], // S_END + }; + + assert_eq!(symbol, Some(expected)); + } + + #[test] + fn test_skip_to() { + let mut symbols = create_iter(); + let symbol = symbols.skip_to(SymbolIndex(0x8)).expect("get symbol"); + + let expected = Symbol { + index: SymbolIndex(0x8), + data: &[0x06, 0x00], // S_END + }; + + assert_eq!(symbol, Some(expected)); + } + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/constants.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/constants.rs new file mode 100644 index 0000000000..5821813d66 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/constants.rs @@ -0,0 +1,228 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +#![allow(unused, non_upper_case_globals)] + +// TODO: special types +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L328 + +// A list of known type kinds: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L772 + +// leaf indices starting records but referenced from symbol records + +pub const LF_MODIFIER_16t: u16 = 0x0001; +pub const LF_POINTER_16t: u16 = 0x0002; +pub const LF_ARRAY_16t: u16 = 0x0003; +pub const LF_CLASS_16t: u16 = 0x0004; +pub const LF_STRUCTURE_16t: u16 = 0x0005; +pub const LF_UNION_16t: u16 = 0x0006; +pub const LF_ENUM_16t: u16 = 0x0007; +pub const LF_PROCEDURE_16t: u16 = 0x0008; +pub const LF_MFUNCTION_16t: u16 = 0x0009; +pub const LF_VTSHAPE: u16 = 0x000a; +pub const LF_COBOL0_16t: u16 = 0x000b; +pub const LF_COBOL1: u16 = 0x000c; +pub const LF_BARRAY_16t: u16 = 0x000d; +pub const LF_LABEL: u16 = 0x000e; +pub const LF_NULL: u16 = 0x000f; +pub const LF_NOTTRAN: u16 = 0x0010; +pub const LF_DIMARRAY_16t: u16 = 0x0011; +pub const LF_VFTPATH_16t: u16 = 0x0012; +pub const LF_PRECOMP_16t: u16 = 0x0013; // not referenced from symbol +pub const LF_ENDPRECOMP: u16 = 0x0014; // not referenced from symbol +pub const LF_OEM_16t: u16 = 0x0015; // oem definable type string +pub const LF_TYPESERVER_ST: u16 = 0x0016; // not referenced from symbol + +// leaf indices starting records but referenced only from type records + +pub const LF_SKIP_16t: u16 = 0x0200; +pub const LF_ARGLIST_16t: u16 = 0x0201; +pub const LF_DEFARG_16t: u16 = 0x0202; +pub const LF_LIST: u16 = 0x0203; +pub const LF_FIELDLIST_16t: u16 = 0x0204; +pub const LF_DERIVED_16t: u16 = 0x0205; +pub const LF_BITFIELD_16t: u16 = 0x0206; +pub const LF_METHODLIST_16t: u16 = 0x0207; +pub const LF_DIMCONU_16t: u16 = 0x0208; +pub const LF_DIMCONLU_16t: u16 = 0x0209; +pub const LF_DIMVARU_16t: u16 = 0x020a; +pub const LF_DIMVARLU_16t: u16 = 0x020b; +pub const LF_REFSYM: u16 = 0x020c; + +pub const LF_BCLASS_16t: u16 = 0x0400; +pub const LF_VBCLASS_16t: u16 = 0x0401; +pub const LF_IVBCLASS_16t: u16 = 0x0402; +pub const LF_ENUMERATE_ST: u16 = 0x0403; +pub const LF_FRIENDFCN_16t: u16 = 0x0404; +pub const LF_INDEX_16t: u16 = 0x0405; +pub const LF_MEMBER_16t: u16 = 0x0406; +pub const LF_STMEMBER_16t: u16 = 0x0407; +pub const LF_METHOD_16t: u16 = 0x0408; +pub const LF_NESTTYPE_16t: u16 = 0x0409; +pub const LF_VFUNCTAB_16t: u16 = 0x040a; +pub const LF_FRIENDCLS_16t: u16 = 0x040b; +pub const LF_ONEMETHOD_16t: u16 = 0x040c; +pub const LF_VFUNCOFF_16t: u16 = 0x040d; + +// 32-bit type index versions of leaves all have the 0x1000 bit set +// +pub const LF_TI16_MAX: u16 = 0x1000; + +pub const LF_MODIFIER: u16 = 0x1001; +pub const LF_POINTER: u16 = 0x1002; +pub const LF_ARRAY_ST: u16 = 0x1003; +pub const LF_CLASS_ST: u16 = 0x1004; +pub const LF_STRUCTURE_ST: u16 = 0x1005; +pub const LF_UNION_ST: u16 = 0x1006; +pub const LF_ENUM_ST: u16 = 0x1007; +pub const LF_PROCEDURE: u16 = 0x1008; +pub const LF_MFUNCTION: u16 = 0x1009; +pub const LF_COBOL0: u16 = 0x100a; +pub const LF_BARRAY: u16 = 0x100b; +pub const LF_DIMARRAY_ST: u16 = 0x100c; +pub const LF_VFTPATH: u16 = 0x100d; +pub const LF_PRECOMP_ST: u16 = 0x100e; // not referenced from symbol +pub const LF_OEM: u16 = 0x100f; // oem definable type string +pub const LF_ALIAS_ST: u16 = 0x1010; // alias (typedef) type +pub const LF_OEM2: u16 = 0x1011; // oem definable type string + +// leaf indices starting records but referenced only from type records + +pub const LF_SKIP: u16 = 0x1200; +pub const LF_ARGLIST: u16 = 0x1201; +pub const LF_DEFARG_ST: u16 = 0x1202; +pub const LF_FIELDLIST: u16 = 0x1203; +pub const LF_DERIVED: u16 = 0x1204; +pub const LF_BITFIELD: u16 = 0x1205; +pub const LF_METHODLIST: u16 = 0x1206; +pub const LF_DIMCONU: u16 = 0x1207; +pub const LF_DIMCONLU: u16 = 0x1208; +pub const LF_DIMVARU: u16 = 0x1209; +pub const LF_DIMVARLU: u16 = 0x120a; + +pub const LF_BCLASS: u16 = 0x1400; +pub const LF_VBCLASS: u16 = 0x1401; +pub const LF_IVBCLASS: u16 = 0x1402; +pub const LF_FRIENDFCN_ST: u16 = 0x1403; +pub const LF_INDEX: u16 = 0x1404; +pub const LF_MEMBER_ST: u16 = 0x1405; +pub const LF_STMEMBER_ST: u16 = 0x1406; +pub const LF_METHOD_ST: u16 = 0x1407; +pub const LF_NESTTYPE_ST: u16 = 0x1408; +pub const LF_VFUNCTAB: u16 = 0x1409; +pub const LF_FRIENDCLS: u16 = 0x140a; +pub const LF_ONEMETHOD_ST: u16 = 0x140b; +pub const LF_VFUNCOFF: u16 = 0x140c; +pub const LF_NESTTYPEEX_ST: u16 = 0x140d; +pub const LF_MEMBERMODIFY_ST: u16 = 0x140e; +pub const LF_MANAGED_ST: u16 = 0x140f; + +// Types w/ SZ names + +pub const LF_ST_MAX: u16 = 0x1500; + +pub const LF_TYPESERVER: u16 = 0x1501; // not referenced from symbol +pub const LF_ENUMERATE: u16 = 0x1502; +pub const LF_ARRAY: u16 = 0x1503; +pub const LF_CLASS: u16 = 0x1504; +pub const LF_STRUCTURE: u16 = 0x1505; +pub const LF_UNION: u16 = 0x1506; +pub const LF_ENUM: u16 = 0x1507; +pub const LF_DIMARRAY: u16 = 0x1508; +pub const LF_PRECOMP: u16 = 0x1509; // not referenced from symbol +pub const LF_ALIAS: u16 = 0x150a; // alias (typedef) type +pub const LF_DEFARG: u16 = 0x150b; +pub const LF_FRIENDFCN: u16 = 0x150c; +pub const LF_MEMBER: u16 = 0x150d; +pub const LF_STMEMBER: u16 = 0x150e; +pub const LF_METHOD: u16 = 0x150f; +pub const LF_NESTTYPE: u16 = 0x1510; +pub const LF_ONEMETHOD: u16 = 0x1511; +pub const LF_NESTTYPEEX: u16 = 0x1512; +pub const LF_MEMBERMODIFY: u16 = 0x1513; +pub const LF_MANAGED: u16 = 0x1514; +pub const LF_TYPESERVER2: u16 = 0x1515; + +pub const LF_STRIDED_ARRAY: u16 = 0x1516; // same as LF_ARRAY but with stride between adjacent elements +pub const LF_HLSL: u16 = 0x1517; +pub const LF_MODIFIER_EX: u16 = 0x1518; +pub const LF_INTERFACE: u16 = 0x1519; +pub const LF_BINTERFACE: u16 = 0x151a; +pub const LF_VECTOR: u16 = 0x151b; +pub const LF_MATRIX: u16 = 0x151c; + +pub const LF_VFTABLE: u16 = 0x151d; // a virtual function table +pub const LF_ENDOFLEAFRECORD: u16 = LF_VFTABLE; + +pub const LF_TYPE_LAST: u16 = LF_ENDOFLEAFRECORD + 1; // one greater than the last type record +pub const LF_TYPE_MAX: u16 = LF_TYPE_LAST - 1; + +pub const LF_FUNC_ID: u16 = 0x1601; // global func ID +pub const LF_MFUNC_ID: u16 = 0x1602; // member func ID +pub const LF_BUILDINFO: u16 = 0x1603; // build info: tool version command line src/pdb file +pub const LF_SUBSTR_LIST: u16 = 0x1604; // similar to LF_ARGLIST for list of sub strings +pub const LF_STRING_ID: u16 = 0x1605; // string ID + +pub const LF_UDT_SRC_LINE: u16 = 0x1606; // source and line on where an UDT is defined + // only generated by compiler + +pub const LF_UDT_MOD_SRC_LINE: u16 = 0x1607; // module source and line on where an UDT is defined + // only generated by linker + +pub const LF_CLASS2: u16 = 0x1608; +pub const LF_STRUCTURE2: u16 = 0x1609; +pub const LF_UNION2: u16 = 0x160a; +pub const LF_INTERFACE2: u16 = 0x160b; + +pub const LF_ID_LAST: u16 = LF_UDT_MOD_SRC_LINE + 1; // one greater than the last ID record +pub const LF_ID_MAX: u16 = LF_ID_LAST - 1; + +pub const LF_NUMERIC: u16 = 0x8000; +pub const LF_CHAR: u16 = 0x8000; +pub const LF_SHORT: u16 = 0x8001; +pub const LF_USHORT: u16 = 0x8002; +pub const LF_LONG: u16 = 0x8003; +pub const LF_ULONG: u16 = 0x8004; +pub const LF_REAL32: u16 = 0x8005; +pub const LF_REAL64: u16 = 0x8006; +pub const LF_REAL80: u16 = 0x8007; +pub const LF_REAL128: u16 = 0x8008; +pub const LF_QUADWORD: u16 = 0x8009; +pub const LF_UQUADWORD: u16 = 0x800a; +pub const LF_REAL48: u16 = 0x800b; +pub const LF_COMPLEX32: u16 = 0x800c; +pub const LF_COMPLEX64: u16 = 0x800d; +pub const LF_COMPLEX80: u16 = 0x800e; +pub const LF_COMPLEX128: u16 = 0x800f; +pub const LF_VARSTRING: u16 = 0x8010; + +pub const LF_OCTWORD: u16 = 0x8017; +pub const LF_UOCTWORD: u16 = 0x8018; + +pub const LF_DECIMAL: u16 = 0x8019; +pub const LF_DATE: u16 = 0x801a; +pub const LF_UTF8STRING: u16 = 0x801b; + +pub const LF_REAL16: u16 = 0x801c; + +pub const LF_PAD0: u16 = 0xf0; +pub const LF_PAD1: u16 = 0xf1; +pub const LF_PAD2: u16 = 0xf2; +pub const LF_PAD3: u16 = 0xf3; +pub const LF_PAD4: u16 = 0xf4; +pub const LF_PAD5: u16 = 0xf5; +pub const LF_PAD6: u16 = 0xf6; +pub const LF_PAD7: u16 = 0xf7; +pub const LF_PAD8: u16 = 0xf8; +pub const LF_PAD9: u16 = 0xf9; +pub const LF_PAD10: u16 = 0xfa; +pub const LF_PAD11: u16 = 0xfb; +pub const LF_PAD12: u16 = 0xfc; +pub const LF_PAD13: u16 = 0xfd; +pub const LF_PAD14: u16 = 0xfe; +pub const LF_PAD15: u16 = 0xff; diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/data.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/data.rs new file mode 100644 index 0000000000..0af7a54c46 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/data.rs @@ -0,0 +1,1231 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +#![allow(missing_docs)] + +use crate::common::*; +use crate::tpi::constants::*; +use crate::tpi::primitive::*; + +const TYPE_RECORD_RECURSION_LIMIT: usize = 32; + +/// Encapsulates parsed data about a `Type`. +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum TypeData<'t> { + Primitive(PrimitiveType), + Class(ClassType<'t>), + Member(MemberType<'t>), + MemberFunction(MemberFunctionType), + OverloadedMethod(OverloadedMethodType<'t>), + Method(MethodType<'t>), + StaticMember(StaticMemberType<'t>), + Nested(NestedType<'t>), + BaseClass(BaseClassType), + VirtualBaseClass(VirtualBaseClassType), + VirtualFunctionTable(VirtualFunctionTableType<'t>), + VirtualTableShape(VirtualTableShapeType), + VirtualFunctionTablePointer(VirtualFunctionTablePointerType), + Procedure(ProcedureType), + Pointer(PointerType), + Modifier(ModifierType), + Enumeration(EnumerationType<'t>), + Enumerate(EnumerateType<'t>), + Array(ArrayType), + Union(UnionType<'t>), + Bitfield(BitfieldType), + FieldList(FieldList<'t>), + ArgumentList(ArgumentList), + MethodList(MethodList), +} + +impl<'t> TypeData<'t> { + /// Return the name of this TypeData, if any + pub fn name(&self) -> Option> { + let name = match self { + Self::Class(ClassType { ref name, .. }) + | Self::Member(MemberType { ref name, .. }) + | Self::OverloadedMethod(OverloadedMethodType { ref name, .. }) + | Self::StaticMember(StaticMemberType { ref name, .. }) + | Self::Nested(NestedType { ref name, .. }) + | Self::Enumeration(EnumerationType { ref name, .. }) + | Self::Enumerate(EnumerateType { ref name, .. }) + | Self::Union(UnionType { ref name, .. }) => name, + _ => return None, + }; + + Some(*name) + } +} + +/// Parse a type out of a `ParseBuffer`. +pub(crate) fn parse_type_data<'t>(buf: &mut ParseBuffer<'t>) -> Result> { + parse_type_data_with_depth(buf, 0) +} + +fn parse_type_data_with_depth<'t>( + buf: &mut ParseBuffer<'t>, + recursion_depth: usize, +) -> Result> { + let leaf = buf.parse_u16()?; + + match leaf { + // Basic types + // ----------- + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631-L1642 + LF_CLASS | LF_CLASS_ST | LF_STRUCTURE | LF_STRUCTURE_ST | LF_INTERFACE => { + let mut class = ClassType { + kind: match leaf { + LF_CLASS | LF_CLASS_ST => ClassKind::Class, + LF_STRUCTURE | LF_STRUCTURE_ST => ClassKind::Struct, + LF_INTERFACE => ClassKind::Interface, + _ => unreachable!(), + }, + count: buf.parse_u16()?, + properties: TypeProperties(buf.parse_u16()?), + fields: parse_optional_type_index(buf)?, + derived_from: parse_optional_type_index(buf)?, + vtable_shape: parse_optional_type_index(buf)?, + size: parse_unsigned(buf)?, + name: parse_string(leaf, buf)?, + unique_name: None, + }; + + if class.properties.has_unique_name() { + class.unique_name = Some(parse_string(leaf, buf)?); + } + + Ok(TypeData::Class(class)) + } + + // https://github.com/microsoft/microsoft-pdb/issues/50#issuecomment-737890766 + LF_CLASS2 | LF_STRUCTURE2 | LF_INTERFACE2 => { + let mut class = ClassType { + kind: match leaf { + LF_CLASS2 => ClassKind::Class, + LF_STRUCTURE2 => ClassKind::Struct, + LF_INTERFACE2 => ClassKind::Interface, + _ => unreachable!(), + }, + properties: TypeProperties(buf.parse_u32()? as u16), + fields: parse_optional_type_index(buf)?, + derived_from: parse_optional_type_index(buf)?, + vtable_shape: parse_optional_type_index(buf)?, + count: buf.parse_u16()?, + size: parse_unsigned(buf)?, + name: parse_string(leaf, buf)?, + unique_name: None, + }; + + if class.properties.has_unique_name() { + class.unique_name = Some(parse_string(leaf, buf)?); + } + + Ok(TypeData::Class(class)) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2580-L2586 + LF_MEMBER | LF_MEMBER_ST => Ok(TypeData::Member(MemberType { + attributes: FieldAttributes(buf.parse_u16()?), + field_type: buf.parse()?, + offset: parse_unsigned(buf)?, + name: parse_string(leaf, buf)?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2699-L2714 + LF_NESTTYPE | LF_NESTTYPE_ST | LF_NESTTYPEEX | LF_NESTTYPEEX_ST => { + // These structs differ in their use of the first 16 bits + let raw_attr = match leaf { + LF_NESTTYPEEX | LF_NESTTYPEEX_ST => buf.parse_u16()?, + _ => { + // discard padding + buf.parse_u16()?; + // assume zero + 0 + } + }; + + Ok(TypeData::Nested(NestedType { + attributes: FieldAttributes(raw_attr), + nested_type: buf.parse()?, + name: parse_string(leaf, buf)?, + })) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1801-L1811 + LF_MFUNCTION => Ok(TypeData::MemberFunction(MemberFunctionType { + return_type: buf.parse()?, + class_type: buf.parse()?, + this_pointer_type: parse_optional_type_index(buf)?, + attributes: FunctionAttributes(buf.parse_u16()?), + parameter_count: buf.parse_u16()?, + argument_list: buf.parse()?, + this_adjustment: buf.parse_u32()?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2650-L2655 + LF_METHOD | LF_METHOD_ST => Ok(TypeData::OverloadedMethod(OverloadedMethodType { + count: buf.parse_u16()?, + method_list: buf.parse()?, + name: parse_string(leaf, buf)?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2671-L2678 + LF_ONEMETHOD | LF_ONEMETHOD_ST => { + let attr = FieldAttributes(buf.parse_u16()?); + Ok(TypeData::Method(MethodType { + attributes: attr, + method_type: buf.parse()?, + vtable_offset: if attr.is_intro_virtual() { + Some(buf.parse_u32()? as u32) + } else { + // yes, this is variable length + None + }, + name: parse_string(leaf, buf)?, + })) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2499-L2505 + LF_BCLASS | LF_BINTERFACE => Ok(TypeData::BaseClass(BaseClassType { + kind: match leaf { + LF_BCLASS => ClassKind::Class, + LF_BINTERFACE => ClassKind::Interface, + _ => unreachable!(), + }, + attributes: FieldAttributes(buf.parse_u16()?), + base_class: buf.parse()?, + offset: parse_unsigned(buf)? as u32, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2615-L2619 + LF_VFUNCTAB => { + // padding is supposed to be zero always, but… let's not check + buf.parse_u16()?; + Ok(TypeData::VirtualFunctionTablePointer( + VirtualFunctionTablePointerType { + table: buf.parse()?, + }, + )) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2599-L2604 + LF_STMEMBER | LF_STMEMBER_ST => Ok(TypeData::StaticMember(StaticMemberType { + attributes: FieldAttributes(buf.parse_u16()?), + field_type: buf.parse()?, + name: parse_string(leaf, buf)?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1469-L1506 + LF_POINTER => { + let underlying_type = buf.parse()?; + let attributes = PointerAttributes(buf.parse()?); + + let containing_class = if attributes.pointer_to_member() { + Some(buf.parse()?) + } else { + None + }; + + Ok(TypeData::Pointer(PointerType { + underlying_type, + attributes, + containing_class, + })) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1775-L1782 + LF_PROCEDURE => Ok(TypeData::Procedure(ProcedureType { + return_type: parse_optional_type_index(buf)?, + attributes: FunctionAttributes(buf.parse_u16()?), + parameter_count: buf.parse_u16()?, + argument_list: buf.parse()?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1460-L1464 + LF_MODIFIER => { + let type_index = buf.parse()?; + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1090-L1095 + let flags = buf.parse_u16()?; + + Ok(TypeData::Modifier(ModifierType { + underlying_type: type_index, + constant: (flags & 0x01) != 0, + volatile: (flags & 0x02) != 0, + unaligned: (flags & 0x04) != 0, + })) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1752-L1759 + LF_ENUM | LF_ENUM_ST => { + let mut enumeration = EnumerationType { + count: buf.parse_u16()?, + properties: TypeProperties(buf.parse_u16()?), + underlying_type: buf.parse()?, + fields: buf.parse()?, + name: parse_string(leaf, buf)?, + unique_name: None, + }; + + if enumeration.properties.has_unique_name() { + enumeration.unique_name = Some(parse_string(leaf, buf)?); + } + + Ok(TypeData::Enumeration(enumeration)) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2683-L2688 + LF_ENUMERATE | LF_ENUMERATE_ST => Ok(TypeData::Enumerate(EnumerateType { + attributes: FieldAttributes(buf.parse_u16()?), + value: buf.parse()?, + name: parse_string(leaf, buf)?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1564-L1579 + LF_ARRAY | LF_ARRAY_ST | LF_STRIDED_ARRAY => { + let element_type = buf.parse()?; + let indexing_type = buf.parse()?; + let stride: Option = if leaf == LF_STRIDED_ARRAY { + Some(buf.parse_u32()?) + } else { + None + }; + + let mut dimensions: Vec = Vec::new(); + + loop { + let dim = parse_unsigned(buf)?; + if dim > u64::from(u32::max_value()) { + return Err(Error::UnimplementedFeature("u64 array sizes")); + } + dimensions.push(dim as u32); + + if buf.is_empty() { + // shouldn't run out here + return Err(Error::UnexpectedEof); + } + + if buf.peek_u8()? == 0x00 { + // end of dimensions + buf.parse_u8()?; + break; + } + } + + // eat any padding + parse_padding(buf)?; + + //println!("array: {:x}", buf); + //println!("dimensions: {:?}", dimensions); + + // Vector35/binaryninja-api#6076: NativeAOT PDBs have extra data here + // of unknown purpose + //assert!(buf.is_empty()); + + Ok(TypeData::Array(ArrayType { + element_type, + indexing_type, + stride, + dimensions, + })) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1657-L1664 + LF_UNION | LF_UNION_ST => { + let mut union = UnionType { + count: buf.parse_u16()?, + properties: TypeProperties(buf.parse_u16()?), + fields: buf.parse()?, + size: parse_unsigned(buf)?, + name: parse_string(leaf, buf)?, + unique_name: None, + }; + + if union.properties.has_unique_name() { + union.unique_name = Some(parse_string(leaf, buf)?); + } + + Ok(TypeData::Union(union)) + } + + // https://github.com/microsoft/microsoft-pdb/issues/50#issuecomment-737890766 + LF_UNION2 => { + let mut union = UnionType { + properties: TypeProperties(buf.parse_u32()? as u16), + fields: buf.parse()?, + count: buf.parse_u16()?, + size: parse_unsigned(buf)?, + name: parse_string(leaf, buf)?, + unique_name: None, + }; + + if union.properties.has_unique_name() { + union.unique_name = Some(parse_string(leaf, buf)?); + } + + Ok(TypeData::Union(union)) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2164-L2170 + LF_BITFIELD => Ok(TypeData::Bitfield(BitfieldType { + underlying_type: buf.parse()?, + length: buf.parse_u8()?, + position: buf.parse_u8()?, + })), + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1819-L1823 + LF_VTSHAPE => { + let mut vtshape = VirtualTableShapeType { + descriptors: vec![], + }; + let count = buf.parse_u16()? as usize; + // These are packed 4-bit values + for _ in 0..((count + 1) / 2) { + let desc: u8 = buf.parse()?; + vtshape.descriptors.push(desc & 0xF); + if vtshape.descriptors.len() < count { + vtshape.descriptors.push(desc >> 4); + } + } + Ok(TypeData::VirtualTableShape(vtshape)) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1825-L1837 + LF_VFTABLE => { + let mut vftable = VirtualFunctionTableType { + owner: buf.parse()?, + base: buf.parse()?, + object_offset: parse_unsigned(buf)? as u32, + names: vec![], + }; + + let names_length = parse_unsigned(buf)? as usize; + + let mut len = 0; + while len < names_length { + let s = buf.parse_cstring()?; + len += s.len() + 1; + vftable.names.push(s); + } + + Ok(TypeData::VirtualFunctionTable(vftable)) + } + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2521-L2528 + LF_VBCLASS | LF_IVBCLASS => Ok(TypeData::VirtualBaseClass(VirtualBaseClassType { + direct: leaf == LF_VBCLASS, + attributes: FieldAttributes(buf.parse_u16()?), + base_class: buf.parse()?, + base_pointer: buf.parse()?, + base_pointer_offset: parse_unsigned(buf)? as u32, + virtual_base_offset: parse_unsigned(buf)? as u32, + })), + + // List types + // ---------- + + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2112-L2115 + LF_FIELDLIST => { + let mut fields: Vec> = Vec::new(); + let mut continuation: Option = None; + + while !buf.is_empty() { + match buf.peek_u16()? { + LF_INDEX => { + // continuation record + // eat the leaf value + buf.parse_u16()?; + + // parse the TypeIndex where we continue + continuation = Some(buf.parse()?); + } + _ => { + let next_depth = next_type_data_depth(recursion_depth)?; + fields.push(parse_type_data_with_depth(buf, next_depth)?); + } + } + + // consume any padding + parse_padding(buf)?; + } + + Ok(TypeData::FieldList(FieldList { + fields, + continuation, + })) + } + + LF_ARGLIST => { + let count = buf.parse_u32()?; + let mut arglist: Vec = Vec::with_capacity(count as usize); + for _ in 0..count { + arglist.push(buf.parse()?); + } + Ok(TypeData::ArgumentList(ArgumentList { arguments: arglist })) + } + + LF_METHODLIST => { + let mut methods: Vec = Vec::new(); + + while !buf.is_empty() { + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L2131-L2136 + let attr = FieldAttributes(buf.parse_u16()?); + buf.parse_u16()?; // padding + + methods.push(MethodListEntry { + attributes: attr, + method_type: buf.parse()?, + vtable_offset: if attr.is_intro_virtual() { + Some(buf.parse_u32()?) + } else { + None + }, + }); + } + + Ok(TypeData::MethodList(MethodList { methods })) + } + + _ => Err(Error::UnimplementedTypeKind(leaf)), + } +} + +#[inline] +fn next_type_data_depth(recursion_depth: usize) -> Result { + match recursion_depth.checked_add(1) { + Some(next_depth) if next_depth <= TYPE_RECORD_RECURSION_LIMIT => Ok(next_depth), + _ => Err(Error::TypeRecordRecursionLimit( + "LF_FIELDLIST", + TYPE_RECORD_RECURSION_LIMIT, + )), + } +} + +#[inline] +fn parse_optional_type_index(buf: &mut ParseBuffer<'_>) -> Result> { + let index = buf.parse()?; + if index == TypeIndex(0) || index == TypeIndex(0xffff) { + Ok(None) + } else { + Ok(Some(index)) + } +} + +#[inline] +fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result> { + if leaf > LF_ST_MAX { + buf.parse_cstring() + } else { + buf.parse_u8_pascal_string() + } +} + +#[inline] +fn parse_padding(buf: &mut ParseBuffer<'_>) -> Result<()> { + while !buf.is_empty() && buf.peek_u8()? >= 0xf0 { + let padding = buf.parse_u8()?; + if padding > 0xf0 { + // low four bits indicate amount of padding + // (don't ask me what 0xf0 means, then) + buf.take((padding & 0x0f) as usize - 1)?; + } + } + Ok(()) +} + +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/pdbdump/pdbdump.cpp#L2417-L2456 +fn parse_unsigned(buf: &mut ParseBuffer<'_>) -> Result { + let leaf = buf.parse_u16()?; + if leaf < LF_NUMERIC { + // the u16 directly encodes a value + return Ok(u64::from(leaf)); + } + + match leaf { + LF_CHAR => Ok(u64::from(buf.parse_u8()?)), + LF_USHORT => Ok(u64::from(buf.parse_u16()?)), + LF_ULONG => Ok(u64::from(buf.parse_u32()?)), + LF_UQUADWORD => Ok(buf.parse_u64()?), + _ => { + if cfg!(debug_assertions) { + unreachable!(); + } else { + Err(Error::UnexpectedNumericPrefix(leaf)) + } + } + } +} + +/* +typedef struct CV_prop_t { +unsigned short packed :1; // true if structure is packed +unsigned short ctor :1; // true if constructors or destructors present +unsigned short ovlops :1; // true if overloaded operators present +unsigned short isnested :1; // true if this is a nested class +unsigned short cnested :1; // true if this class contains nested types +unsigned short opassign :1; // true if overloaded assignment (=) +unsigned short opcast :1; // true if casting methods +unsigned short fwdref :1; // true if forward reference (incomplete defn) +unsigned short scoped :1; // scoped definition +unsigned short hasuniquename :1; // true if there is a decorated name following the regular name +unsigned short sealed :1; // true if class cannot be used as a base class +unsigned short hfa :2; // CV_HFA_e +unsigned short intrinsic :1; // true if class is an intrinsic type (e.g. __m128d) +unsigned short mocom :2; // CV_MOCOM_UDT_e +} CV_prop_t; +*/ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TypeProperties(u16); +impl TypeProperties { + /// Indicates if a type is packed via `#pragma pack` or similar. + pub fn packed(self) -> bool { + self.0 & 0x0001 != 0 + } + + /// Indicates if a type has constructors or destructors. + pub fn constructors(self) -> bool { + self.0 & 0x0002 != 0 + } + + /// Indicates if a type has any overloaded operators. + pub fn overloaded_operators(self) -> bool { + self.0 & 0x0004 != 0 + } + + /// Indicates if a type is a nested type, e.g. a `union` defined inside a `class`. + pub fn is_nested_type(self) -> bool { + self.0 & 0x0008 != 0 + } + + /// Indicates if a type contains nested types. + pub fn contains_nested_types(self) -> bool { + self.0 & 0x0010 != 0 + } + + /// Indicates if a class has overloaded the assignment operator. + pub fn overloaded_assignment(self) -> bool { + self.0 & 0x0020 != 0 + } + pub fn overloaded_casting(self) -> bool { + self.0 & 0x0040 != 0 + } + + /// Indicates if a type is a forward reference, i.e. an incomplete Type that serves as a + /// placeholder until a complete Type can be built. This is necessary for e.g. self-referential + /// data structures, but other more common declaration/definition idioms can cause forward + /// references too. + pub fn forward_reference(self) -> bool { + self.0 & 0x0080 != 0 + } + + pub fn scoped_definition(self) -> bool { + self.0 & 0x0100 != 0 + } + pub fn has_unique_name(self) -> bool { + self.0 & 0x0200 != 0 + } + pub fn sealed(self) -> bool { + self.0 & 0x0400 != 0 + } + pub fn hfa(self) -> u8 { + ((self.0 & 0x1800) >> 11) as u8 + } + pub fn intrinsic_type(self) -> bool { + self.0 & 0x1000 != 0 + } + pub fn mocom(self) -> u8 { + ((self.0 & 0x6000) >> 14) as u8 + } +} + +/* +typedef struct CV_fldattr_t { + unsigned short access :2; // access protection CV_access_t + unsigned short mprop :3; // method properties CV_methodprop_t + unsigned short pseudo :1; // compiler generated fcn and does not exist + unsigned short noinherit :1; // true if class cannot be inherited + unsigned short noconstruct :1; // true if class cannot be constructed + unsigned short compgenx :1; // compiler generated fcn and does exist + unsigned short sealed :1; // true if method cannot be overridden + unsigned short unused :6; // unused +} CV_fldattr_t; + +typedef enum CV_methodprop_e { + CV_MTvanilla = 0x00, + CV_MTvirtual = 0x01, + CV_MTstatic = 0x02, + CV_MTfriend = 0x03, + CV_MTintro = 0x04, + CV_MTpurevirt = 0x05, + CV_MTpureintro = 0x06 +} CV_methodprop_e; + +*/ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct FieldAttributes(u16); +impl FieldAttributes { + #[inline] + pub fn access(self) -> u8 { + (self.0 & 0x0003) as u8 + } + #[inline] + fn method_properties(self) -> u8 { + ((self.0 & 0x001c) >> 2) as u8 + } + + #[inline] + pub fn is_static(self) -> bool { + self.method_properties() == 0x02 + } + + #[inline] + pub fn is_virtual(self) -> bool { + self.method_properties() == 0x01 + } + + #[inline] + pub fn is_pure_virtual(self) -> bool { + self.method_properties() == 0x05 + } + + #[inline] + pub fn is_intro_virtual(self) -> bool { + matches!(self.method_properties(), 0x04 | 0x06) + } + + // TODO +} + +#[allow(unused)] +#[repr(u8)] +enum Access { + None = 0x00, + Private = 0x01, + Protected = 0x02, + Public = 0x03, +} + +// CV_call_t and CV_funcattr_t are always found back to back +// Treat them as a combined u16 +/* +typedef struct CV_funcattr_t { + unsigned char cxxreturnudt :1; // true if C++ style ReturnUDT + unsigned char ctor :1; // true if func is an instance constructor + unsigned char ctorvbase :1; // true if func is an instance constructor of a class with virtual bases + unsigned char unused :5; // unused +} CV_funcattr_t; +*/ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct FunctionAttributes(u16); +impl FunctionAttributes { + pub fn calling_convention(self) -> u8 { + (self.0 & 0xff) as u8 + } + pub fn cxx_return_udt(self) -> bool { + (self.0 & 0x0100) > 0 + } + pub fn is_constructor(self) -> bool { + (self.0 & 0x0200) > 0 + } + pub fn is_constructor_with_virtual_bases(self) -> bool { + (self.0 & 0x0400) > 0 + } +} + +/// The kind of a `PointerType`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PointerKind { + /// 16 bit pointer. + Near16, + /// 16:16 far pointer. + Far16, + /// 16:16 huge pointer. + Huge16, + /// Based on segment. + BaseSeg, + /// Based on value of base. + BaseVal, + /// Based on segment value of base. + BaseSegVal, + /// Based on address of base. + BaseAddr, + /// Based on segment address of base. + BaseSegAddr, + /// Based on type. + BaseType, + /// Based on self. + BaseSelf, + /// 32-bit pointer. + Near32, + /// 48-bit 16:32 pointer. + Far32, + /// 64-bit pointer. + Ptr64, +} + +/// The mode of a `PointerType`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PointerMode { + /// A regular pointer. + Pointer, + /// L-Value reference. + LValueReference, + /// Pointer to data member. + Member, + /// Pointer to member function. + MemberFunction, + /// R-Value reference. + RValueReference, +} + +/* +struct lfPointerAttr { + unsigned long ptrtype :5; // ordinal specifying pointer type (CV_ptrtype_e) + unsigned long ptrmode :3; // ordinal specifying pointer mode (CV_ptrmode_e) + unsigned long isflat32 :1; // true if 0:32 pointer + unsigned long isvolatile :1; // TRUE if volatile pointer + unsigned long isconst :1; // TRUE if const pointer + unsigned long isunaligned :1; // TRUE if unaligned pointer + unsigned long isrestrict :1; // TRUE if restricted pointer (allow agressive opts) + unsigned long size :6; // size of pointer (in bytes) + unsigned long ismocom :1; // TRUE if it is a MoCOM pointer (^ or %) + unsigned long islref :1; // TRUE if it is this pointer of member function with & ref-qualifier + unsigned long isrref :1; // TRUE if it is this pointer of member function with && ref-qualifier + unsigned long unused :10;// pad out to 32-bits for following cv_typ_t's +} attr; +*/ + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PointerAttributes(u32); + +impl PointerAttributes { + /// Indicates the type of pointer. + pub fn pointer_kind(self) -> PointerKind { + match self.0 & 0x1f { + 0x00 => PointerKind::Near16, + 0x01 => PointerKind::Far16, + 0x02 => PointerKind::Huge16, + 0x03 => PointerKind::BaseSeg, + 0x04 => PointerKind::BaseVal, + 0x05 => PointerKind::BaseSegVal, + 0x06 => PointerKind::BaseAddr, + 0x07 => PointerKind::BaseSegAddr, + 0x08 => PointerKind::BaseType, + 0x09 => PointerKind::BaseSelf, + 0x0a => PointerKind::Near32, + 0x0b => PointerKind::Far32, + 0x0c => PointerKind::Ptr64, + _ => unreachable!(), + } + } + + /// Returns the mode of this pointer. + pub fn pointer_mode(self) -> PointerMode { + match (self.0 >> 5) & 0x7 { + 0x00 => PointerMode::Pointer, + 0x01 => PointerMode::LValueReference, + 0x02 => PointerMode::Member, + 0x03 => PointerMode::MemberFunction, + 0x04 => PointerMode::RValueReference, + _ => unreachable!(), + } + } + + /// Returns `true` if this points to a member (either data or function). + pub fn pointer_to_member(self) -> bool { + matches!( + self.pointer_mode(), + PointerMode::Member | PointerMode::MemberFunction + ) + } + + /// Returns `true` if this is a flat `0:32` pointer. + pub fn is_flat_32(self) -> bool { + (self.0 & 0x100) != 0 + } + + /// Returns `true` if this pointer is `volatile`. + pub fn is_volatile(self) -> bool { + (self.0 & 0x200) != 0 + } + + /// Returns `true` if this pointer is `const`. + pub fn is_const(self) -> bool { + (self.0 & 0x400) != 0 + } + + /// Returns `true` if this pointer is unaligned. + pub fn is_unaligned(self) -> bool { + (self.0 & 0x800) != 0 + } + + /// Returns `true` if this pointer is restricted (allow aggressive opts). + pub fn is_restrict(self) -> bool { + (self.0 & 0x1000) != 0 + } + + /// Is this a C++ reference, as opposed to a C pointer? + pub fn is_reference(self) -> bool { + matches!( + self.pointer_mode(), + PointerMode::LValueReference | PointerMode::RValueReference + ) + } + + /// The size of the pointer in bytes. + pub fn size(self) -> u8 { + let size = ((self.0 >> 13) & 0x3f) as u8; + if size != 0 { + return size; + } + + match self.pointer_kind() { + PointerKind::Near32 | PointerKind::Far32 => 4, + PointerKind::Ptr64 => 8, + _ => 0, + } + } + + /// Returns `true` if this is a MoCOM pointer (`^` or `%`). + pub fn is_mocom(self) -> bool { + (self.0 & 0x40000) != 0 + } +} + +/* +typedef enum CV_VTS_desc_e { + CV_VTS_near = 0x00, + CV_VTS_far = 0x01, + CV_VTS_thin = 0x02, + CV_VTS_outer = 0x03, + CV_VTS_meta = 0x04, + CV_VTS_near32 = 0x05, + CV_VTS_far32 = 0x06, + CV_VTS_unused = 0x07 +} CV_VTS_desc_e; + */ +#[allow(unused)] +#[repr(u8)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum VirtualTableShapeDescriptor { + Near = 0x00, + Far = 0x01, + Thin = 0x02, + Outer = 0x03, + Meta = 0x04, + Near32 = 0x05, + Far32 = 0x06, + Unused = 0x07, +} + +/// The information parsed from a type record with kind +/// `LF_CLASS`, `LF_CLASS_ST`, `LF_STRUCTURE`, `LF_STRUCTURE_ST` or `LF_INTERFACE`. +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L1631 +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ClassType<'t> { + pub kind: ClassKind, + + /// Count of number of elements in this class + pub count: u16, + pub properties: TypeProperties, + + /// Type index which describes the fields of this class + pub fields: Option, + + /// Type index which describes the class from which this class is derived, if any + pub derived_from: Option, + + /// Type index which describes the shape of the vtable for this class, if any + pub vtable_shape: Option, + + pub size: u64, + + /// Display name of the class including type parameters. + pub name: RawString<'t>, + + /// Mangled name, if present. + pub unique_name: Option>, +} + +/// Used by `ClassType` to distinguish class-like concepts. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ClassKind { + Class, + Struct, + Interface, +} + +/// The information parsed from a type record with kind `LF_MEMBER` or `LF_MEMBER_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MemberType<'t> { + pub attributes: FieldAttributes, + pub field_type: TypeIndex, + pub offset: u64, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind `LF_MFUNCTION`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct MemberFunctionType { + pub return_type: TypeIndex, + pub class_type: TypeIndex, + pub this_pointer_type: Option, + pub attributes: FunctionAttributes, + pub parameter_count: u16, + pub argument_list: TypeIndex, + pub this_adjustment: u32, +} + +/// The information parsed from a type record with kind `LF_METHOD` or `LF_METHOD_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct OverloadedMethodType<'t> { + pub count: u16, + pub method_list: TypeIndex, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind `LF_ONEMETHOD` or `LF_ONEMETHOD_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MethodType<'t> { + pub attributes: FieldAttributes, + pub method_type: TypeIndex, + pub vtable_offset: Option, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind `LF_STMEMBER` or `LF_STMEMBER_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StaticMemberType<'t> { + pub attributes: FieldAttributes, + pub field_type: TypeIndex, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind +/// `LF_NESTTYPE`, `LF_NESTTYPE_ST`, `LF_NESTTYPEEX`, or `LF_NESTTYPEEX_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NestedType<'t> { + pub attributes: FieldAttributes, + pub nested_type: TypeIndex, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind `LF_BCLASS` or `LF_BINTERFACE`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct BaseClassType { + pub kind: ClassKind, + pub attributes: FieldAttributes, + pub base_class: TypeIndex, + + /// Describes the offset of the base class within the class + pub offset: u32, +} + +/// The information parsed from a type record with kind `LF_VBCLASS` or `LF_IVBCLASS`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct VirtualBaseClassType { + pub direct: bool, + pub attributes: FieldAttributes, + pub base_class: TypeIndex, + pub base_pointer: TypeIndex, + + pub base_pointer_offset: u32, + pub virtual_base_offset: u32, +} + +/// The information parsed from a type record with kind `LF_VFUNCTAB`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct VirtualFunctionTablePointerType { + pub table: TypeIndex, +} + +/// The information parsed from a type record with kind `LF_VTSHAPE`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VirtualTableShapeType { + pub descriptors: Vec, +} + +/// The information parsed from a type record with kind `LF_VFTABLE`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct VirtualFunctionTableType<'t> { + pub owner: TypeIndex, + pub base: TypeIndex, + pub object_offset: u32, + pub names: Vec>, +} + +/// The information parsed from a type record with kind `LF_PROCEDURE`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ProcedureType { + pub return_type: Option, + pub attributes: FunctionAttributes, + pub parameter_count: u16, + pub argument_list: TypeIndex, +} + +/// The information parsed from a type record with kind `LF_POINTER`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct PointerType { + pub underlying_type: TypeIndex, + pub attributes: PointerAttributes, + pub containing_class: Option, +} + +/// The information parsed from a type record with kind `LF_MODIFIER`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct ModifierType { + pub underlying_type: TypeIndex, + pub constant: bool, + pub volatile: bool, + pub unaligned: bool, +} + +/// The information parsed from a type record with kind `LF_ENUM` or `LF_ENUM_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumerationType<'t> { + pub count: u16, + pub properties: TypeProperties, + pub underlying_type: TypeIndex, + pub fields: TypeIndex, + pub name: RawString<'t>, + pub unique_name: Option>, +} + +/// The information parsed from a type record with kind `LF_ENUMERATE` or `LF_ENUMERATE_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct EnumerateType<'t> { + pub attributes: FieldAttributes, + pub value: Variant, + pub name: RawString<'t>, +} + +/// The information parsed from a type record with kind +/// `LF_ARRAY`, `LF_ARRAY_ST` or `LF_STRIDED_ARRAY`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ArrayType { + pub element_type: TypeIndex, + pub indexing_type: TypeIndex, + pub stride: Option, + + /// Contains array dimensions as specified in the PDB. This is not what you expect: + /// + /// * Dimensions are specified in terms of byte sizes, not element counts. + /// * Multidimensional arrays aggregate the lower dimensions into the sizes of the higher + /// dimensions. + /// + /// Thus a `float[4][4]` has `dimensions: [16, 64]`. Determining array dimensions in terms + /// of element counts requires determining the size of the `element_type` and iteratively + /// dividing. + pub dimensions: Vec, +} + +/// The information parsed from a type record with kind `LF_UNION` or `LF_UNION_ST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UnionType<'t> { + pub count: u16, + pub properties: TypeProperties, + pub fields: TypeIndex, + pub size: u64, + pub name: RawString<'t>, + pub unique_name: Option>, +} + +/// The information parsed from a type record with kind `LF_BITFIELD`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct BitfieldType { + pub underlying_type: TypeIndex, + pub length: u8, + pub position: u8, +} + +/// The information parsed from a type record with kind `LF_FIELDLIST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct FieldList<'t> { + pub fields: Vec>, + + /// Sometimes fields can't all fit in a single FieldList, in which case the FieldList + /// refers to another FieldList in a chain. + pub continuation: Option, +} + +/// The information parsed from a type record with kind `LF_ARGLIST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ArgumentList { + pub arguments: Vec, +} + +/// The information parsed from a type record with kind `LF_METHODLIST`. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MethodList { + pub methods: Vec, +} + +/// An entry in a `MethodList`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct MethodListEntry { + pub attributes: FieldAttributes, + pub method_type: TypeIndex, + pub vtable_offset: Option, +} + +/* +// arrays: +ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x40\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\xa0\xdc\x0b\x00\x23\x00\x00\x00\x50\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\xa9\x12\x00\x00\x23\x00\x00\x00\x50\x02\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\xac\x12\x00\x00\x23\x00\x00\x00\x6c\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x80\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x75\x00\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x70\x0e\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x04\x02\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x31\x14\x00\x00\x23\x00\x00\x00\x0e\x03\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x77\x13\x00\x00\x23\x00\x00\x00\x02\x80\xbd\xda\x00\xf3\xf2\xf1").as_bytes(), +ParseBuf::from("\x03\x15\xb7\x16\x00\x00\x23\x00\x00\x00\x28\x00\x00\xf1").as_bytes(), +ParseBuf::from("\x03\x15\x14\x10\x00\x00\x23\x00\x00\x00\x55\x00\x00\xf1").as_bytes(), +*/ + +#[test] +fn kind_1609() { + let data = &[ + 9, 22, 0, 2, 0, 0, 22, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 0, 72, 95, 115, 105, 122, + 101, 0, 46, 63, 65, 85, 72, 95, 115, 105, 122, 101, 64, 64, 0, + ][..]; + + assert_eq!( + parse_type_data(&mut ParseBuffer::from(data)).expect("parse"), + TypeData::Class(ClassType { + kind: ClassKind::Struct, + count: 2, + properties: TypeProperties(512), + fields: Some(TypeIndex(0x1016)), + derived_from: None, + vtable_shape: None, + size: 6, + name: RawString::from("H_size"), + unique_name: Some(RawString::from(".?AUH_size@@")), + }) + ); +} + +#[test] +fn fieldlist_recursion_limit() { + let mut data = Vec::new(); + for _ in 0..=(TYPE_RECORD_RECURSION_LIMIT + 1) { + data.extend_from_slice(&LF_FIELDLIST.to_le_bytes()); + } + + let err = parse_type_data(&mut ParseBuffer::from(data.as_slice())).unwrap_err(); + match err { + Error::TypeRecordRecursionLimit(kind, limit) => { + assert_eq!(kind, "LF_FIELDLIST"); + assert_eq!(limit, TYPE_RECORD_RECURSION_LIMIT); + } + other => panic!("unexpected error: {:?}", other), + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/header.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/header.rs new file mode 100644 index 0000000000..28a0a56d46 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/header.rs @@ -0,0 +1,120 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::common::*; + +// OFFCB: +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct Slice { + pub offset: i32, // technically a "long", but... 32 bits for life? + pub size: u32, +} + +// HDR: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/dbi/tpi.h#L45 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct Header { + pub version: u32, + pub header_size: u32, + pub minimum_index: u32, + pub maximum_index: u32, + pub gprec_size: u32, + pub tpi_hash_stream: u16, + pub tpi_hash_pad_stream: u16, + pub hash_key_size: u32, + pub hash_bucket_size: u32, + pub hash_values: Slice, + pub ti_off: Slice, + pub hash_adj: Slice, // "offcb of hash head list, maps (hashval,ti), where ti is the head of the hashval chain." +} + +impl Header { + pub(crate) fn empty() -> Self { + let empty_slice = Slice { offset: 0, size: 0 }; + + Self { + version: 0, + header_size: 0, + minimum_index: 0, + maximum_index: 0, + gprec_size: 0, + tpi_hash_stream: 0, + tpi_hash_pad_stream: 0, + hash_key_size: 0, + hash_bucket_size: 0, + hash_values: empty_slice, + ti_off: empty_slice, + hash_adj: empty_slice, + } + } + + pub(crate) fn parse(buf: &mut ParseBuffer<'_>) -> Result { + debug_assert!(buf.pos() == 0); + + if buf.is_empty() { + // Special case when the buffer is completely empty. This indicates a missing TPI or IPI + // stream. In this case, `ItemInformation` acts like an empty shell that never resolves + // any types. + return Ok(Self::empty()); + } + + let header = Self { + version: buf.parse()?, + header_size: buf.parse()?, + minimum_index: buf.parse()?, + maximum_index: buf.parse()?, + gprec_size: buf.parse()?, + tpi_hash_stream: buf.parse()?, + tpi_hash_pad_stream: buf.parse()?, + hash_key_size: buf.parse()?, + hash_bucket_size: buf.parse()?, + hash_values: Slice { + offset: buf.parse()?, + size: buf.parse()?, + }, + ti_off: Slice { + offset: buf.parse()?, + size: buf.parse()?, + }, + hash_adj: Slice { + offset: buf.parse()?, + size: buf.parse()?, + }, + }; + + // we read 56 bytes + // make sure that's okay + let bytes_read = buf.pos() as u32; + if header.header_size < bytes_read { + return Err(Error::InvalidTypeInformationHeader( + "header size is impossibly small", + )); + } else if header.header_size > 1024 { + return Err(Error::InvalidTypeInformationHeader( + "header size is unreasonably large", + )); + } + + // consume anything else the header says belongs to the header + buf.take((header.header_size - bytes_read) as usize)?; + + // do some final validations + if header.minimum_index < 4096 { + return Err(Error::InvalidTypeInformationHeader( + "minimum type index is < 4096", + )); + } + if header.maximum_index < header.minimum_index { + return Err(Error::InvalidTypeInformationHeader( + "maximum type index is < minimum type index", + )); + } + + // success + Ok(header) + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/id.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/id.rs new file mode 100644 index 0000000000..a70036dcfd --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/id.rs @@ -0,0 +1,184 @@ +use scroll::ctx::TryFromCtx; + +use crate::common::*; +use crate::tpi::constants::*; + +#[inline] +fn parse_optional_id_index(buf: &mut ParseBuffer<'_>) -> Result> { + Ok(match buf.parse()? { + IdIndex(0) => None, + index => Some(index), + }) +} + +#[inline] +fn parse_string<'t>(leaf: u16, buf: &mut ParseBuffer<'t>) -> Result> { + if leaf > LF_ST_MAX { + buf.parse_cstring() + } else { + buf.parse_u8_pascal_string() + } +} + +/// Encapsulates parsed data about an `Id`. +#[non_exhaustive] +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IdData<'t> { + /// Global function, usually inlined. + Function(FunctionId<'t>), + /// Member function, usually inlined. + MemberFunction(MemberFunctionId<'t>), + /// Tool, version and command line build information. + BuildInfo(BuildInfoId), + /// A list of substrings. + StringList(StringListId), + /// A string. + String(StringId<'t>), + /// Source and line of the definition of a User Defined Type (UDT). + UserDefinedTypeSource(UserDefinedTypeSourceId), +} + +impl<'t> IdData<'t> {} + +impl<'t> TryFromCtx<'t, scroll::Endian> for IdData<'t> { + type Error = Error; + + fn try_from_ctx(this: &'t [u8], _ctx: scroll::Endian) -> Result<(Self, usize)> { + let mut buf = ParseBuffer::from(this); + let leaf = buf.parse_u16()?; + + let data = match leaf { + LF_FUNC_ID => IdData::Function(FunctionId { + scope: parse_optional_id_index(&mut buf)?, + function_type: buf.parse()?, + name: parse_string(leaf, &mut buf)?, + }), + LF_MFUNC_ID => IdData::MemberFunction(MemberFunctionId { + parent: buf.parse()?, + function_type: buf.parse()?, + name: parse_string(leaf, &mut buf)?, + }), + LF_BUILDINFO => IdData::BuildInfo({ + let count = buf.parse::()?; + let mut arguments = Vec::with_capacity(count as usize); + for _ in 0..count { + arguments.push(buf.parse()?); + } + BuildInfoId { arguments } + }), + LF_SUBSTR_LIST => IdData::StringList({ + let count = buf.parse::()?; + let mut substrings = Vec::with_capacity(count as usize); + for _ in 0..count { + substrings.push(buf.parse()?); + } + StringListId { substrings } + }), + LF_STRING_ID => IdData::String(StringId { + substrings: parse_optional_id_index(&mut buf)?, + name: parse_string(leaf, &mut buf)?, + }), + LF_UDT_SRC_LINE | LF_UDT_MOD_SRC_LINE => { + let udt = buf.parse()?; + let file_id = buf.parse()?; + let line = buf.parse()?; + + let source_file = if leaf == self::LF_UDT_SRC_LINE { + UserDefinedTypeSourceFileRef::Local(IdIndex(file_id)) + } else { + UserDefinedTypeSourceFileRef::Remote(buf.parse()?, StringRef(file_id)) + }; + + IdData::UserDefinedTypeSource(UserDefinedTypeSourceId { + udt, + source_file, + line, + }) + } + _ => return Err(Error::UnimplementedTypeKind(leaf)), + }; + + Ok((data, buf.pos())) + } +} + +/// Global function, usually inlined. +/// +/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct FunctionId<'t> { + /// Parent scope of this id. + pub scope: Option, + /// Index of the function type declaration. + pub function_type: TypeIndex, + /// Name of the function. + pub name: RawString<'t>, +} + +/// Member function, usually inlined. +/// +/// This Id is usually referenced by [`InlineSiteSymbol`](crate::InlineSiteSymbol). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct MemberFunctionId<'t> { + /// Index of the parent type. + pub parent: TypeIndex, + /// Index of the member function type declaration. + pub function_type: TypeIndex, + /// Name of the member function. + pub name: RawString<'t>, +} + +/// Tool, version and command line build information. +/// +/// This Id is usually referenced by [`BuildInfoSymbol`](crate::BuildInfoSymbol). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BuildInfoId { + /// Indexes of build arguments. + pub arguments: Vec, +} + +/// A list of substrings. +/// +/// This Id is usually referenced by [`StringId`]. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StringListId { + /// The list of substrings. + pub substrings: Vec, +} + +/// A string. +/// +/// This Id is usually referenced by [`FunctionId`] and contains the full namespace of a function. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StringId<'t> { + /// Index of the list of substrings. + pub substrings: Option, + /// The string. + pub name: RawString<'t>, +} + +/// A reference to the source file name of a [`UserDefinedTypeSourceId`]. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum UserDefinedTypeSourceFileRef { + /// Index of the source file name in the [`IdInformation`](crate::IdInformation) of the same module. + /// + /// The index should resolve to a [`IdData::String`]. + Local(IdIndex), + /// Reference into the [`StringTable`](crate::StringTable) of another module that contributes + /// this UDT definition. + /// + /// Use [`DebugInformation::modules`](crate::DebugInformation::modules) to resolve the + /// corresponding module. + Remote(u16, StringRef), +} + +/// Source and line of the definition of a User Defined Type (UDT). +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct UserDefinedTypeSourceId { + /// Index of the UDT's type definition. + pub udt: TypeIndex, + /// Reference to the source file name. + pub source_file: UserDefinedTypeSourceFileRef, + /// Line number in the source file. + pub line: u32, +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/mod.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/mod.rs new file mode 100644 index 0000000000..859f0ce798 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/mod.rs @@ -0,0 +1,552 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use std::fmt; +use std::marker::PhantomData; +use std::result; + +use crate::common::*; +use crate::msf::Stream; +use crate::FallibleIterator; + +pub(crate) mod constants; +mod data; +mod header; +mod id; +mod primitive; + +use self::header::*; +use self::primitive::type_data_for_primitive; + +pub use self::data::*; +pub use self::id::*; +pub use self::primitive::{Indirection, PrimitiveKind, PrimitiveType}; + +/// Zero-copy access to a PDB type or id stream. +/// +/// PDBs store two kinds of related streams with an identical internal structure: +/// +/// - [`TypeInformation`] (TPI stream) contains information on primitive types, classes and +/// procedures, including their return type and arguments. Its contents are identified by +/// [`TypeIndex`]. +/// - [`IdInformation`] (IPI stream) is a stricter version of the above stream that contains inline +/// functions, build infos and source references. Its contents are identified by [`IdIndex`]. +/// +/// Items in these streams are stored by their index in ascending order. Symbols declared in +/// [`ModuleInfo`](crate::ModuleInfo) can refer to items in both streams, as well as items to other +/// items with one exception: `Type`s cannot refer to `Id`s. Also, the PDB format requires that +/// items refer only to types with lower indexes. Thus, the stream of items forms a directed acyclic +/// graph. +/// +/// Both streams can iterate by their index using [`ItemInformation::iter`]. Additionally, +/// [`ItemFinder`] is a secondary data structure to provide efficient backtracking for random +/// access. +/// +/// There are type definitions for both streams: +/// +/// - `ItemInformation`: [`TypeInformation`] and [`IdInformation`] +/// - [`ItemFinder`]: [`TypeFinder`] and [`IdFinder`] +/// - [`ItemIndex`]: [`TypeIndex`] and [`IdIndex`] +/// - [`ItemIter`]: [`TypeIter`] and [`IdIter`] +/// - [`Item`]: [`Type`] and [`Id`] +/// +/// # Examples +/// +/// Iterating over the types while building a `TypeFinder`: +/// +/// ``` +/// # use pdb::FallibleIterator; +/// # +/// # fn test() -> pdb::Result { +/// # let file = std::fs::File::open("fixtures/self/foo.pdb")?; +/// # let mut pdb = pdb::PDB::open(file)?; +/// +/// let type_information = pdb.type_information()?; +/// let mut type_finder = type_information.finder(); +/// +/// # let expected_count = type_information.len(); +/// # let mut count: usize = 0; +/// let mut iter = type_information.iter(); +/// while let Some(typ) = iter.next()? { +/// // build the type finder as we go +/// type_finder.update(&iter); +/// +/// // parse the type record +/// match typ.parse() { +/// Ok(pdb::TypeData::Class(pdb::ClassType {name, properties, fields: Some(fields), ..})) => { +/// // this Type describes a class-like type with fields +/// println!("type {} is a class named {}", typ.index(), name); +/// +/// // `fields` is a TypeIndex which refers to a FieldList +/// // To find information about the fields, find and parse that Type +/// match type_finder.find(fields)?.parse()? { +/// pdb::TypeData::FieldList(list) => { +/// // `fields` is a Vec +/// for field in list.fields { +/// if let pdb::TypeData::Member(member) = field { +/// // follow `member.field_type` as desired +/// println!(" - field {} at offset {:x}", member.name, member.offset); +/// } else { +/// // handle member functions, nested types, etc. +/// } +/// } +/// +/// if let Some(more_fields) = list.continuation { +/// // A FieldList can be split across multiple records +/// // TODO: follow `more_fields` and handle the next FieldList +/// } +/// } +/// _ => { } +/// } +/// +/// }, +/// Ok(_) => { +/// // ignore everything that's not a class-like type +/// }, +/// Err(pdb::Error::UnimplementedTypeKind(_)) => { +/// // found an unhandled type record +/// // this probably isn't fatal in most use cases +/// }, +/// Err(e) => { +/// // other error, probably is worth failing +/// return Err(e); +/// } +/// } +/// # count += 1; +/// } +/// +/// # assert_eq!(expected_count, count); +/// # Ok(count) +/// # } +/// # assert!(test().expect("test") > 8000); +/// ``` +#[derive(Debug)] +pub struct ItemInformation<'s, I> { + stream: Stream<'s>, + header: Header, + _ph: PhantomData<&'s I>, +} + +impl<'s, I> ItemInformation<'s, I> +where + I: ItemIndex, +{ + /// Parses `TypeInformation` from raw stream data. + pub(crate) fn parse(stream: Stream<'s>) -> Result { + let mut buf = stream.parse_buffer(); + let header = Header::parse(&mut buf)?; + let _ph = PhantomData; + Ok(Self { + stream, + header, + _ph, + }) + } + + /// Returns an iterator that can traverse the type table in sequential order. + pub fn iter(&self) -> ItemIter<'_, I> { + // get a parse buffer + let mut buf = self.stream.parse_buffer(); + + // drop the header + // this can't fail; we've already read this once + buf.take(self.header.header_size as usize) + .expect("dropping TPI header"); + + ItemIter { + buf, + index: self.header.minimum_index, + _ph: PhantomData, + } + } + + /// Returns the number of items contained in this `ItemInformation`. + /// + /// Note that in the case of the type stream ([`TypeInformation`]) primitive types are not + /// stored in the PDB file. The number of distinct types reachable via this table will be higher + /// than `len()`. + pub fn len(&self) -> usize { + (self.header.maximum_index - self.header.minimum_index) as usize + } + + /// Returns whether this `ItemInformation` contains any data. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns an `ItemFinder` with a default time-space tradeoff useful for access by + /// [`ItemIndex`]. + /// + /// The `ItemFinder` is initially empty and must be populated by iterating. See the struct-level + /// docs for an example. + pub fn finder(&self) -> ItemFinder<'_, I> { + ItemFinder::new(self, 3) + } +} + +/// This buffer is used when a `Type` refers to a primitive type. It doesn't contain anything +/// type-specific, but it does parse as `raw_type() == 0xffff`, which is a reserved value. Seems +/// like a reasonable thing to do. +const PRIMITIVE_TYPE: &[u8] = b"\xff\xff"; + +/// Represents an entry in the type or id stream. +/// +/// An `Item` has been minimally processed and may not be correctly formed or even understood by +/// this library. To avoid copying, `Items`s exist as references to data owned by the parent +/// `ItemInformation`. Therefore, an `Item` may not outlive its parent. +/// +/// The data held by items can be parsed: +/// +/// - [`Type::parse`](Self::parse) returns [`TypeData`]. +/// - [`Id::parse`](Self::parse) returns [`IdData`]. +/// +/// Depending on the stream, this can either be a [`Type`] or [`Id`]. +#[derive(Copy, Clone, PartialEq)] +pub struct Item<'t, I> { + index: I, + data: &'t [u8], +} + +impl<'t, I> Item<'t, I> +where + I: ItemIndex, +{ + /// Returns this item's index. + /// + /// Depending on the stream, either a [`TypeIndex`] or [`IdIndex`]. + pub fn index(&self) -> I { + self.index + } + + /// Returns the the binary data length in the on-disk format. + /// + /// Items are prefixed by a 16-bit length number, which is not included in this length. + pub fn len(&self) -> usize { + self.data.len() + } + + /// Returns whether this items's data is empty. + /// + /// Items are prefixed by a 16-bit length number, which is not included in this operation. + pub fn is_empty(&self) -> bool { + self.data.is_empty() + } + + /// Returns the identifier of the kind of data stored by this this `Item`. + /// + /// As a special case, if this is a primitive [`Type`], this function will return `0xffff`. + #[inline] + pub fn raw_kind(&self) -> u16 { + debug_assert!(self.data.len() >= 2); + + // assemble a little-endian u16 + u16::from(self.data[0]) | (u16::from(self.data[1]) << 8) + } +} + +impl<'t, I> fmt::Debug for Item<'t, I> +where + I: ItemIndex, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Type{{ kind: 0x{:04x} [{} bytes] }}", + self.raw_kind(), + self.data.len() + ) + } +} + +/// In-memory index for efficient random-access to [`Item`]s by index. +/// +/// `ItemFinder` can be obtained via [`ItemInformation::finder`]. It starts out empty and must be +/// populated by calling [`ItemFinder::update`] while iterating. There are two typedefs for easier +/// use: +/// +/// - [`TypeFinder`] for finding [`Type`]s in a [`TypeInformation`](crate::TypeInformation) (TPI stream). +/// - [`IdFinder`] for finding [`Id`]s in a [`IdInformation`](crate::IdInformation) (IPI stream). +/// +/// `ItemFinder` allocates all the memory it needs when it is first created. The footprint is +/// directly proportional to the total number of types; see [`ItemInformation::len`]. +/// +/// # Time/space trade-off +/// +/// The naïve approach is to store the position of each `Item` as they are covered in the stream. +/// The cost is memory: namely one `u32` per `Item`. +/// +/// Compare this approach to an `ItemFinder` that stores the position of every Nth item. Memory +/// requirements would be reduced by a factor of N in exchange for requiring an average of (N-1)/2 +/// iterations per lookup. However, iteration is cheap sequential memory access, and spending less +/// memory on `ItemFinder` means more of the data can fit in the cache, so this is likely a good +/// trade-off for small-ish values of N. +/// +/// `ItemFinder` is parameterized by `shift` which controls this trade-off as powers of two: +/// +/// * If `shift` is 0, `ItemFinder` stores 4 bytes per `Item` and always performs direct lookups. +/// * If `shift` is 1, `ItemFinder` stores 2 bytes per `Item` and averages 0.5 iterations per +/// lookup. +/// * If `shift` is 2, `ItemFinder` stores 1 byte per `Item` and averages 1.5 iterations per +/// lookup. +/// * If `shift` is 3, `ItemFinder` stores 4 bits per `Item` and averages 3.5 iterations per +/// lookup. +/// * If `shift` is 4, `ItemFinder` stores 2 bits per `Item` and averages 7.5 iterations per +/// lookup. +/// * If `shift` is 5, `ItemFinder` stores 1 bit per `Item` and averages 15.5 iterations per +/// lookup. +/// +/// This list can continue but with rapidly diminishing returns. Iteration cost is proportional to +/// item size, which varies, but typical numbers from a large program are: +/// +/// * 24% of items are 12 bytes +/// * 34% of items are <= 16 bytes +/// * 84% of items are <= 32 bytes +/// +/// A `shift` of 2 or 3 is likely appropriate for most workloads. 500K items would require 1 MB or +/// 500 KB of memory respectively, and lookups -- though indirect -- would still usually need only +/// one or two 64-byte cache lines. +#[derive(Debug)] +pub struct ItemFinder<'t, I> { + buffer: ParseBuffer<'t>, + minimum_index: u32, + maximum_index: u32, + positions: Vec, + shift: u8, + _ph: PhantomData<&'t I>, +} + +impl<'t, I> ItemFinder<'t, I> +where + I: ItemIndex, +{ + fn new(info: &'t ItemInformation<'_, I>, shift: u8) -> Self { + // maximum index is the highest index + 1. + let count = info.header.maximum_index - info.header.minimum_index; + + let round_base = (1 << shift) - 1; + let shifted_count = ((count + round_base) & !round_base) >> shift; + let mut positions = Vec::with_capacity(shifted_count as usize); + + if shifted_count > 0 { + // add record zero, which is identical regardless of shift + positions.push(info.header.header_size); + } + + Self { + buffer: info.stream.parse_buffer(), + minimum_index: info.header.minimum_index, + maximum_index: info.header.maximum_index, + positions, + shift, + _ph: PhantomData, + } + } + + /// Given an index, find which position in the Vec we should jump to and how many times we + /// need to iterate to find the requested type. + /// + /// `shift` refers to the size of these bit shifts. + #[inline] + fn resolve(&self, type_index: u32) -> (usize, usize) { + let raw = type_index - self.minimum_index; + ( + (raw >> self.shift) as usize, + (raw & ((1 << self.shift) - 1)) as usize, + ) + } + + /// Returns the highest index which is currently served by this `ItemFinder`. + /// + /// When iterating through the stream, you shouldn't need to consider this. Items only ever + /// reference lower indexes. However, when loading items referenced by the symbols stream, this + /// can be useful to check whether iteration is required. + #[inline] + pub fn max_index(&self) -> I { + I::from(match self.positions.len() { + 0 => 0, // special case for an empty type index + len => (len << self.shift) as u32 + self.minimum_index - 1, + }) + } + + /// Update this `ItemFinder` based on the current position of a [`ItemIter`]. + /// + /// Do this each time you call `.next()`. See documentation of [`ItemInformation`] for an + /// example. + #[inline] + pub fn update(&mut self, iterator: &ItemIter<'t, I>) { + let (vec_index, iteration_count) = self.resolve(iterator.index); + if iteration_count == 0 && vec_index == self.positions.len() { + let pos = iterator.buf.pos(); + assert!(pos < u32::max_value() as usize); + self.positions.push(pos as u32); + } + } + + /// Find an `Item` by its index. + /// + /// # Errors + /// + /// * `Error::TypeNotFound(index)` if you ask for an item that doesn't exist. + /// * `Error::TypeNotIndexed(index, max_index)` if you ask for an item that is known to exist + /// but is not currently known by this `ItemFinder`. + pub fn find(&self, index: I) -> Result> { + let index: u32 = index.into(); + if index < self.minimum_index { + return Ok(Item { + index: I::from(index), + data: PRIMITIVE_TYPE, + }); + } else if index > self.maximum_index { + return Err(Error::TypeNotFound(index)); + } + + // figure out where we'd find this + let (vec_index, iteration_count) = self.resolve(index); + + if let Some(pos) = self.positions.get(vec_index) { + // hit + let mut buf = self.buffer.clone(); + + // jump forwards + buf.take(*pos as usize)?; + + // skip some records + for _ in 0..iteration_count { + let length = buf.parse_u16()?; + buf.take(length as usize)?; + } + + // read the type + let length = buf.parse_u16()?; + + Ok(Item { + index: I::from(index), + data: buf.take(length as usize)?, + }) + } else { + // miss + Err(Error::TypeNotIndexed(index, self.max_index().into())) + } + } +} + +/// An iterator over items in [`TypeInformation`](crate::TypeInformation) or +/// [`IdInformation`](crate::IdInformation). +/// +/// The TPI and IPI streams are represented internally as a series of records, each of which have a +/// length, a kind, and a type-specific field layout. Iteration performance is therefore similar to +/// a linked list. +#[derive(Debug)] +pub struct ItemIter<'t, I> { + buf: ParseBuffer<'t>, + index: u32, + _ph: PhantomData<&'t I>, +} + +impl<'t, I> FallibleIterator for ItemIter<'t, I> +where + I: ItemIndex, +{ + type Item = Item<'t, I>; + type Error = Error; + + fn next(&mut self) -> result::Result, Self::Error> { + // see if we're at EOF + if self.buf.is_empty() { + return Ok(None); + } + + // read the length of the next type + let length = self.buf.parse_u16()? as usize; + + // validate + if length < 2 { + // this can't be correct + return Err(Error::TypeTooShort); + } + + // grab the type itself + let type_buf = self.buf.take(length)?; + let index = self.index; + + self.index += 1; + + // Done + Ok(Some(Item { + index: I::from(index), + data: type_buf, + })) + } +} + +/// Zero-copy access to the PDB type stream (TPI). +/// +/// This stream exposes types, the variants of which are enumerated by [`TypeData`]. See +/// [`ItemInformation`] for more information on accessing types. +pub type TypeInformation<'s> = ItemInformation<'s, TypeIndex>; + +/// In-memory index for efficient random-access of [`Type`]s by index. +/// +/// `TypeFinder` can be obtained via [`TypeInformation::finder`](ItemInformation::finder). See +/// [`ItemFinder`] for more information. +pub type TypeFinder<'t> = ItemFinder<'t, TypeIndex>; + +/// An iterator over [`Type`]s returned by [`TypeInformation::iter`](ItemInformation::iter). +pub type TypeIter<'t> = ItemIter<'t, TypeIndex>; + +/// Information on a primitive type, class, or procedure. +pub type Type<'t> = Item<'t, TypeIndex>; + +impl<'t> Item<'t, TypeIndex> { + /// Parse this `Type` into `TypeData`. + /// + /// # Errors + /// + /// * `Error::UnimplementedTypeKind(kind)` if the type record isn't currently understood by this + /// library + /// * `Error::UnexpectedEof` if the type record is malformed + pub fn parse(&self) -> Result> { + if self.index < TypeIndex(0x1000) { + // Primitive type + type_data_for_primitive(self.index) + } else { + let mut buf = ParseBuffer::from(self.data); + parse_type_data(&mut buf) + } + } +} + +/// Zero-copy access to the PDB type stream (TPI). +/// +/// This stream exposes types, the variants of which are enumerated by [`IdData`]. See +/// [`ItemInformation`] for more information on accessing types. +pub type IdInformation<'s> = ItemInformation<'s, IdIndex>; + +/// In-memory index for efficient random-access of [`Id`]s by index. +/// +/// `IdFinder` can be obtained via [`IdInformation::finder`](ItemInformation::finder). See +/// [`ItemFinder`] for more information. +pub type IdFinder<'t> = ItemFinder<'t, IdIndex>; + +/// An iterator over [`Id`]s returned by [`IdInformation::iter`](ItemInformation::iter). +pub type IdIter<'t> = ItemIter<'t, IdIndex>; + +/// Information on an inline function, build infos or source references. +pub type Id<'t> = Item<'t, IdIndex>; + +impl<'t> Item<'t, IdIndex> { + /// Parse this `Id` into `IdData`. + /// + /// # Errors + /// + /// * `Error::UnimplementedTypeKind(kind)` if the id record isn't currently understood by this + /// library + /// * `Error::UnexpectedEof` if the id record is malformed + pub fn parse(&self) -> Result> { + ParseBuffer::from(self.data).parse() + } +} diff --git a/plugins/pdb-ng/vendor/pdb-rs/src/tpi/primitive.rs b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/primitive.rs new file mode 100644 index 0000000000..da45e565b4 --- /dev/null +++ b/plugins/pdb-ng/vendor/pdb-rs/src/tpi/primitive.rs @@ -0,0 +1,273 @@ +// Copyright 2017 pdb Developers +// +// Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be +// copied, modified, or distributed except according to those terms. + +use crate::common::*; +use crate::tpi::data::TypeData; + +// References for primitive types: +// +// cvinfo.h provides an enumeration: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L328-L750 +// +// pdbparse.cpp describes them as strings: +// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/pdbdump/pdbdump.cpp#L1896-L1974 +// +// The most obscure: MSDN Library October 2001 Disk 2 contains a \MSDN\specs.chm file which contains +// html\S66CD.HTM which actually documents the *format* of the primitive type descriptors rather +// than just listing them. TypeData::Primitive is designed to model the orthogonal information +// encoded into the bits of the TypeIndex rather than exploding the matrix like the reference +// implementations. + +/// Represents a primitive type like `void` or `char *`. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct PrimitiveType { + /// The kind of the primitive type. + pub kind: PrimitiveKind, + + /// Pointer indirection applied to the primitive type. + pub indirection: Option, +} + +/// A simple type. +#[non_exhaustive] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum PrimitiveKind { + /// Uncharacterized type (no type) + NoType, + + /// Void type + Void, + + /// Character (byte) + Char, + + /// Unsigned character + UChar, + + /// "Really a char" + RChar, + + /// Wide characters, i.e. 16 bits + WChar, + + /// "Really a 16-bit char" + RChar16, + + /// "Really a 32-bit char" + RChar32, + + /// Signed 8-bit integer + I8, + + /// Unsigned 8-bit integer + U8, + + /// Signed 16-bit integer + Short, + + /// Unsigned 16-bit integer + UShort, + + /// Signed 16-bit integer + I16, + + /// Unsigned 16-bit integer + U16, + + /// Signed 32-bit integer + Long, + + /// Unsigned 32-bit inteer + ULong, + + /// Signed 32-bit integer + I32, + + /// Unsigned 32-bit inteer + U32, + + /// Signed 64-bit integer + Quad, + + /// Unsigned 64-bit integer + UQuad, + + /// Signed 64-bit integer + I64, + + /// Unsigned 64-bit integer + U64, + + /// Signed 128-bit integer + Octa, + + /// Unsigned 128-bit integer + UOcta, + + /// Signed 128-bit integer + I128, + + /// Unsigned 128-bit integer + U128, + + /// 16-bit floating point + F16, + + /// 32-bit floating point + F32, + + /// 32-bit partial precision floating point + F32PP, + + /// 48-bit floating point + F48, + + /// 64-bit floating point + F64, + + /// 80-bit floating point + F80, + + /// 128-bit floating point + F128, + + /// 32-bit complex number + Complex32, + + /// 64-bit complex number + Complex64, + + /// 80-bit complex number + Complex80, + + /// 128-bit complex number + Complex128, + + /// 8-bit boolean value + Bool8, + + /// 16-bit boolean value + Bool16, + + /// 32-bit boolean value + Bool32, + + /// 16-bit boolean value + Bool64, + + /// Windows `HRESULT` error code. + /// + /// See: + HRESULT, +} + +/// Pointer mode of primitive types. +/// +/// This is partially overlapping with [`PointerKind`](crate::PointerKind) for regular pointer type +/// definitions. While `PointerKind` can specify many more pointer types, including relative +/// pointers, `Indirection` also contains a 128-bit variant. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Indirection { + /// 16-bit ("near") pointer. + Near16, + /// 16:16 far pointer. + Far16, + /// 16:16 huge pointer. + Huge16, + /// 32-bit pointer. + Near32, + /// 48-bit 16:32 pointer. + Far32, + /// 64-bit near pointer. + Near64, + /// 128-bit near pointer. + Near128, +} + +pub fn type_data_for_primitive(index: TypeIndex) -> Result> { + // https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/include/cvinfo.h#L326-L750 + + // primitives live under 0x1000, and we should never reach here for non-primitive indexes + assert!(index < TypeIndex(0x1000)); + + // indirection is stored in these bits + let indirection = match index.0 & 0xf00 { + 0x000 => None, + 0x100 => Some(Indirection::Near16), + 0x200 => Some(Indirection::Far16), + 0x300 => Some(Indirection::Huge16), + 0x400 => Some(Indirection::Near32), + 0x500 => Some(Indirection::Far32), + 0x600 => Some(Indirection::Near64), + 0x700 => Some(Indirection::Near128), + _ => { + return Err(Error::TypeNotFound(index.0)); + } + }; + + // primitive types are stored in the lowest octet + let kind = match index.0 & 0xff { + 0x00 => PrimitiveKind::NoType, + + 0x03 => PrimitiveKind::Void, + 0x08 => PrimitiveKind::HRESULT, + + 0x10 => PrimitiveKind::Char, + 0x20 => PrimitiveKind::UChar, + 0x68 => PrimitiveKind::I8, + 0x69 => PrimitiveKind::U8, + + 0x70 => PrimitiveKind::RChar, + 0x71 => PrimitiveKind::WChar, + 0x7a => PrimitiveKind::RChar16, + 0x7b => PrimitiveKind::RChar32, + + 0x11 => PrimitiveKind::Short, + 0x21 => PrimitiveKind::UShort, + 0x72 => PrimitiveKind::I16, + 0x73 => PrimitiveKind::U16, + + 0x12 => PrimitiveKind::Long, + 0x22 => PrimitiveKind::ULong, + 0x74 => PrimitiveKind::I32, + 0x75 => PrimitiveKind::U32, + + 0x13 => PrimitiveKind::Quad, + 0x23 => PrimitiveKind::UQuad, + 0x76 => PrimitiveKind::I64, + 0x77 => PrimitiveKind::U64, + + 0x14 => PrimitiveKind::Octa, + 0x24 => PrimitiveKind::UOcta, + 0x78 => PrimitiveKind::I128, + 0x79 => PrimitiveKind::U128, + + 0x46 => PrimitiveKind::F16, + 0x40 => PrimitiveKind::F32, + 0x45 => PrimitiveKind::F32PP, + 0x44 => PrimitiveKind::F48, + 0x41 => PrimitiveKind::F64, + 0x42 => PrimitiveKind::F80, + 0x43 => PrimitiveKind::F128, + + 0x50 => PrimitiveKind::Complex32, + 0x51 => PrimitiveKind::Complex64, + 0x52 => PrimitiveKind::Complex80, + 0x53 => PrimitiveKind::Complex128, + + 0x30 => PrimitiveKind::Bool8, + 0x31 => PrimitiveKind::Bool16, + 0x32 => PrimitiveKind::Bool32, + 0x33 => PrimitiveKind::Bool64, + + _ => { + return Err(Error::TypeNotFound(index.0)); + } + }; + + Ok(TypeData::Primitive(PrimitiveType { kind, indirection })) +}