Skip to main content

pcode_types/
lib.rs

1//! The vocabulary types shared between a p-code *producer* and a p-code
2//! *consumer*.
3//!
4//! A SLEIGH specification describes memory spaces, processor registers and
5//! user-defined p-code operations; an IR built from that specification refers
6//! to the same things. Both sides need to agree on how those are identified, so
7//! the definitions live here rather than in either crate — which lets the
8//! decoder and the IR depend on each other only through this vocabulary.
9//!
10//! These types appear directly in precompiled specification blobs, so their
11//! serialized form is part of the producer/consumer compatibility contract.
12//! A producer must version its blob format; serde alone does not provide a
13//! cross-version or cross-platform wire-format guarantee.
14//!
15//! # Example
16//!
17//! The vocabulary is plain data. A consumer names its spaces and registers,
18//! and a producer's varnodes refer to them by id.
19//!
20//! ```
21//! use jstd::registry::Registry;
22//! use pcode_types::{
23//!     Register, SpaceType,
24//!     space::{Space, SpaceId, SpaceStore},
25//! };
26//!
27//! struct MySpecification {
28//!     spaces: Registry<SpaceId, Space>,
29//! }
30//!
31//! impl SpaceStore for MySpecification {
32//!     fn spaces(&self) -> &Registry<SpaceId, Space> {
33//!         &self.spaces
34//!     }
35//! }
36//!
37//! let mut spaces = Registry::default();
38//! // A byte-addressed 64-bit RAM space, and the space registers live in.
39//! let ram = spaces.push(Space::new(Some("ram"), 1, 8));
40//! let register_space = spaces.push(Space::new(Some("register"), 1, 8));
41//! let spec = MySpecification { spaces };
42//!
43//! // `from_id` resolves against any `SpaceStore`, including your own context.
44//! let resolved = Space::from_id(&spec, ram);
45//! assert_eq!(resolved.name.as_deref(), Some("ram"));
46//! assert!(matches!(resolved.ty, SpaceType::Ram));
47//!
48//! // An 8-byte register at offset 0 of the register space.
49//! let rax = Register {
50//!     name: "RAX".into(),
51//!     space: register_space,
52//!     offset: 0,
53//!     size: 8,
54//! };
55//! assert_eq!(&*rax.name, "RAX");
56//! ```
57
58pub mod error;
59pub mod expression;
60pub mod instruction;
61pub mod register;
62pub mod space;
63pub mod statement;
64pub mod streaming;
65
66pub use error::{PcodeError, PcodeErrorTy, PcodeResult};
67pub use expression::{
68    BinaryOperator, Binop, Builtin, Expression, ExpressionTy, Ident, Load, LocalVarId,
69    LocalVarInterner, Range, RangeParam, SpaceRef as PcodeSpaceRef, UnaryOperator, Unop,
70    pretty_print_ident,
71};
72pub use instruction::{
73    BitRangeInfo, BodyWidths, InstructionPcode, LabelId, LocalSizes, Opcode, PcodeLowerError,
74    PcodeLoweringContext, PcodeOp, PcodePlan, PcodeSink, SymbolicWidth, Varnode, Width,
75    emit_instruction, infer_local_sizes, lower_instruction, lower_instruction_into,
76    plan_instruction, plan_instruction_with, resolve_body_widths,
77};
78pub use register::{Register, RegisterId, RegisterMutRef, RegisterRef};
79pub use space::{SPACE_CONST, Space, SpaceId, SpaceRef, SpaceStore, SpaceType};
80pub use statement::{Ast, AstNode, DelaySlotArg, LabelOrNode};
81
82use jstd::Identifier;
83
84/// A stable identifier for a user-defined p-code operation.
85///
86/// These are the `define pcodeop` names in a SLEIGH specification: operations
87/// with no p-code semantics, which a consumer must interpret itself.
88#[derive(Identifier)]
89pub struct PCodeOpId(usize);
90
91/// Identifier used by source-shaped p-code for a decoder field.
92#[derive(Identifier)]
93pub struct FieldId(usize);
94/// Identifier used by `build` statements for a decoder table.
95#[derive(Identifier)]
96pub struct TableId(usize);
97/// Identifier of a p-code macro definition.
98#[derive(Identifier)]
99pub struct PMacroId(usize);
100/// Identifier of a named register bit range.
101#[derive(Identifier)]
102pub struct BitRangeFieldId(usize);
103
104/// Backend-neutral, source-shaped p-code AST for one decoded instruction.
105#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
106pub struct PcodeAst {
107    /// Statements in execution order.
108    pub statements: Vec<Ast>,
109}
110
111impl PcodeAst {
112    /// Pretty-prints the statements using a producer-specific name resolver.
113    pub fn pretty_print(&self, resolver: &impl PcodeResolver) -> String {
114        self.statements
115            .iter()
116            .map(|statement| statement.pretty_print(resolver))
117            .collect::<Vec<_>>()
118            .join("\n")
119    }
120}
121
122/// Supplies names for formatting a p-code AST without coupling it to a
123/// particular producer such as SLEIGH.
124pub trait PcodeResolver {
125    /// Name of an identifier.
126    fn ident_name(&self, ident: &Ident) -> String;
127    /// Name of a field.
128    fn field_name(&self, id: FieldId) -> String;
129    /// Name of an address space.
130    fn space_name(&self, id: SpaceId) -> String;
131    /// Name of a user-defined operation.
132    fn pcode_op_name(&self, id: PCodeOpId) -> String;
133    /// Name of a macro.
134    fn macro_name(&self, id: PMacroId) -> String;
135}