Expand description

traits (and convenient impls) for decoders that also produce descriptions of parsed bit fields.

the design of this API is discussed in yaxpeax-arch documentation.

usage

AnnotatingDecoder::decode_with_annotation decodes an instruction much like crate::Decoder::decode_into, but also reports descriptions of bit fields to a provided DescriptionSink. VecSink is likely the DescriptionSink of interest to retain fields; decoders are not required to make any guarantees about the order of descriptions, either by the description’s associated FieldDescription::id, or with respect to the bits a FieldDescription is reported against. fields may be described by multiple FieldDescription with matching id and desc – this is to describe data in an instruction where non-contiguous bits are taken together for a single detail. for these cases, the various FieldDescription must compare equal, and users of yaxpeax-arch can rely on this equivalence for grouping bit ranges.

in a generic setting, there isn’t much to do with a FieldDescription other than display it. a typical use might look something like:

fn show_field_descriptions<A: Arch>(decoder: A::Decoder, buf: &[u8])
where
    A::Decoder: AnnotatingDecoder<A>,
    A::Instruction: fmt::Display, for<'data> U8Reader<'data>: Reader<A::Address, A::Word>,
{
    let mut inst = A::Instruction::default();
    let mut reader = U8Reader::new(buf);
    let mut sink: VecSink<<A::Decoder as AnnotatingDecoder<A>>::FieldDescription> = VecSink::new();

    decoder.decode_with_annotation(&mut inst, &mut reader, &mut sink).unwrap();

    println!("decoded instruction {}", inst);
    for (start, end, desc) in sink.records.iter() {
        println("  bits [{}, {}]: {}", start, end, desc);
    }
}

note that the range [start, end] for a reported span is inclusive. the end-th bit of a an instruction’s bit stream is described by the description.

implementation guidance

the typical implementation pattern is that an architecture’s Decoder implements crate::Decoder and AnnotatingDecoder, then callers are free to choose which style of decoding they want. NullSink has a blanket impl of DescriptionSink for all possible descriptions, and discards reported field descriptions. decode_with_annotation with annotations reported to a NullSink must be functionally identical to a call to Decoder::decode_into.

the important points:

  • AnnotatingDecoder is an optional implementation for decoders.
  • FieldDescription in general is oriented towards human-directed output, but implementations can be as precise as they want.
  • since bit/byte order varies from architecture to architecture, a field’s start and end are defined with some ordering from the corresponding decoder crate. crates should describe the bit ordering they select, and where possible, the bit ordering they describe should match relevant ISA mauals.
  • FieldDescription that return true for FieldDescription::is_separator are an exception to bit span inclusivity: for these descriptions, the bit range should be [b, b] where b is the last bit before the boundary being delimited. unlike other descriptions, is_separator descriptions describe the space between bits b and b+1.
  • if a description is to cover multiple bit fields, the reported FieldDescription must be identical on id and desc for all involved bit fields.

Structs

Traits

an interface to decode Arch::Instruction words from a reader of Arch::Words, with the decoder able to report descriptions of bits or fields in the instruction to a sink implementing DescriptionSink. the sink may be NullSink to discard provided data. decoding with a NullSink should behave identically to Decoder::decode_into. implementors are recommended to implement Decoder::decode_into as a call to AnnotatingDecoder::decode_with_annotation if implementing both traits.
implementors of DescriptionSink receive descriptions of an instruction’s disassembly process and relevant offsets in the bitstream being decoded. descriptions are archtecture-specific, and architectures are expected to be able to turn the bit-level start and width values into a meaningful description of bits in the original instruction stream.