summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2020-10-12 00:08:55 -0700
committeriximeow <me@iximeow.net>2020-10-12 00:08:55 -0700
commitac1ec743b2f8163e6b6bdc4c02362069e636ea38 (patch)
treeacf55f8531e168298f38fc3f0dbca1416e12ecea
parent15423d14e596c5489b5ac4513a30e7c265a635b6 (diff)
add documentation and bump to 0.1!
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml5
-rw-r--r--LICENSE12
-rw-r--r--README.md36
-rw-r--r--src/lib.rs62
5 files changed, 114 insertions, 3 deletions
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 <me@iximeow.net>"]
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<u8>,
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<u8> {
+ 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<u8> {
+ 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<u64>;
fn len(&self) -> Self::Unit { AddressDiff::from_const(16) }