From ac1ec743b2f8163e6b6bdc4c02362069e636ea38 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 12 Oct 2020 00:08:55 -0700 Subject: add documentation and bump to 0.1! --- Cargo.lock | 2 +- Cargo.toml | 5 +++-- LICENSE | 12 ++++++++++++ README.md | 36 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 LICENSE create mode 100644 README.md diff --git a/Cargo.lock b/Cargo.lock index b9f031d..1c059fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ [[package]] name = "yaxpeax-ia64" -version = "0.0.1" +version = "0.1.0" dependencies = [ "bitvec", "yaxpeax-arch", diff --git a/Cargo.toml b/Cargo.toml index c9ec03e..8431e5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "yaxpeax-ia64" -version = "0.0.1" +version = "0.1.0" authors = ["iximeow "] edition = "2018" license = "0BSD" repository = "http://git.iximeow.net/yaxpeax-ia64/" description = "ia64 decoder for the yaxpeax project" +readme = "README.md" [dependencies] yaxpeax-arch = { version = "0.0.4", default-features = false, features = [] } -bitvec = "*" +bitvec = "0.19" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7091f53 --- /dev/null +++ b/LICENSE @@ -0,0 +1,12 @@ +Copyright (c) 2020 iximeow + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cfa27d4 --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +## yaxpeax-ia64 + +ia64 decoder implemented as part of the yaxpeax project. + +`yaxpeax-ia64` implements traits provided by `yaxpeax-arch`, which are likely how you want to use this library from Rust. + +implementation is heavily derived from the manual [`itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf`](https://www.intel.com/content/dam/doc/manual/itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf), as of 2019-09-07. `sha256: 705d2fc04ab378568eddb6bac4ee6974b6224b8efb5f73606f964f4a86e22955`. + +bytes go in, instructions come out - from `test.rs`: +```rust +let decoder = yaxpeax_ia64::InstDecoder::default(); +let expected = "[MMI] ld1 r17=[r17];; nop.m 0x0; dep r14=r18,r14,0x0,0x8"; +let data = [0x0a, 0x88, 0x00, 0x22, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0xc0, 0x21, 0x71, 0xdc, 0x4f]; +let inst = decoder.decode(data[..].iter().cloned()).unwrap(); +assert_eq!(format!("{}", inst), expected); +``` + +the `InstructionBundle` impl for `Display` is somewhat opinionated in output format, it will write instructions all in one line. for more customized display formats (some kind of cool multi-column layout perhaps?), you'll want to whip something more clever up by using `InstructionBundle::instructions()` and handling instructions independently. + +### features + +* probably works +* almost-`#[no_std]` + +### probably works +the only decoding oracle i could find was the ia64 decoder in GNU `binutils`. i suspect it's correct, but between the size of the instruction set, details in immediate encoding, and user-mode-focused testing, there may be some misdecodes! a critical eye is warranted, though i expect `yaxpeax-ia64` to generally be correct or close to it. + +### almost-`#[no_std]` +`yaxpeax-ia64` does not reference `std::`, and theoretically `#[no_std]` is as simple as putting a `#![no_std]` in `lib.rs` and moving on. i don't expect to build or use `yaxpeax-ia64` in this configuration, so it is not enabled out of avoiding extra test permutations. + +if you would like to use `yaxpeax-ia64` in a `no-std` configuration: +* awesome! shouldn't be hard +* why? +* rust doesn't even target ia64 as a tier 3 platform, are you trying to get C bindings? that would be good to specify too + +### diff --git a/src/lib.rs b/src/lib.rs index 2df131e..c69083a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,10 @@ +//! `ia64` decoder implemented as part of th `yaxpeax` project. implements traits provided by +//! `yaxpeax-arch`. +//! +//! instruction set manual references are with respect to the docuemnt +//! [`itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf`](https://www.intel.com/content/dam/doc/manual/itanium-architecture-vol-1-2-3-4-reference-set-manual.pdf) +//! as of 2019-09-07. `sha256: 705d2fc04ab378568eddb6bac4ee6974b6224b8efb5f73606f964f4a86e22955` + use yaxpeax_arch::{Arch, AddressDiff, Decoder, LengthedInstruction}; use yaxpeax_arch::AddressBase; use bitvec::prelude::*; @@ -1034,6 +1041,37 @@ pub struct Instruction { dest_boundary: Option, operands: [Operand; 5], } +impl Instruction { + /// opcode for this instruction. + pub fn opcode(&self) -> Opcode { + self.opcode + } + /// for float instructions, `sf` may indicate which field in `FSPR` is used. + pub fn sf(&self) -> Option { + self.sf + } + /// predicate register this instruction is predicated on. `0` means this instruction is + /// unconditional. + pub fn predicate(&self) -> u8 { + self.predicate + } + /// index of the last operand that is written to (on the left-hand side of `=` when displayed) + /// in this instruction. `None` means no operand is written. (directly, anyway - post-increment + /// of register used to reference memory is still a write, and not tracked here.) + pub fn last_write_index(&self) -> Option { + self.dest_boundary + } + /// all operands used in this instruction. + pub fn operands(&self) -> &[Operand] { + for (i, op) in self.operands.iter().enumerate() { + if op == &Operand::None { + return &self.operands[..i]; + } + } + &self.operands[..] + } +} + impl fmt::Display for Instruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.predicate != 0 { @@ -1209,6 +1247,30 @@ pub struct InstructionBundle { bundle_tag: u8, instructions: [Instruction; 3], } +impl InstructionBundle { + /// retrieve the tag for this instruction bundle. `tag` can be used as an index into + /// `BUNDLE_TAGS` to look up the stop pattern or instruction types of each instruction in this + /// bundle. + pub fn bundle_tag(&self) -> u8 { + self.bundle_tag + } + + /// retrieve the instructions in this bundle. if this bundle contains an `LX` instruction, it + /// there will be two items (rather than three) in the returned slice. + pub fn instructions(&self) -> &[Instruction] { + let types = if let Some((types, _)) = BUNDLE_TAGS[self.bundle_tag as usize] { + types + } else { + // invalid bundle tag - might be a decoder bug? + return &[]; + }; + if types[2] == InstructionType::X { + &self.instructions[..2] + } else { + &self.instructions[..3] + } + } +} impl yaxpeax_arch::LengthedInstruction for InstructionBundle { type Unit = yaxpeax_arch::AddressDiff; fn len(&self) -> Self::Unit { AddressDiff::from_const(16) } -- cgit v1.1