test_assembler/
lib.rs

1// Copyright 2015 Ted Mielczarek. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3
4//! A set of types for building complex binary streams.
5//!
6//! For testing code that consumes binary data, it is necessary to
7//! be able to generate test inputs consisting of various valid and
8//! invalid permutations. The `Section` struct defined in this crate
9//! allows for easily building a stream of bytes in any desired
10//! endianness.
11//!
12//! This crate defines two useful structs: [`Section`] and
13//! [`Label`]. A `Section` is simply a stream of bytes which can
14//! be written to, and a `Label` is a placeholder for a value that can be
15//! computed based on other values, but can be written to a `Section` without
16//! knowing its value at that time.
17//!
18//! This crate is based on [Jim Blandy's fantastic C++ implementation][1] in Google Breakpad.
19//!
20//! [1]: https://chromium.googlesource.com/breakpad/breakpad/+/master/src/common/test_assembler.h
21//!
22//! # Examples
23//!
24//! `Section` provides many convenient methods for appending data of specific endianness and byte width. There are methods for appending 8, 16, 32, and 64-bit integers using the `Section`'s default  endianness, or explicitly using big or little-endian byte ordering. These methods all have shorthand names of the form:
25//!
26//! `[endianness][bits]`
27//!
28//! Where `endianness` is one of:
29//! * `D`: The `Section`'s default endianness
30//! * `L`: little-endian
31//! * `B`: big-endian
32//! And `bits` is any of 8, 16, 32, or 64 to write an integer from 1 to 8 bytes in length.
33//!
34//! So, for example, to write a little-endian 32-bit integer, call [`L32`](struct.Section.html#method.L32).
35//!
36//! The `Section` methods for appending data all consume and return the `Section`
37//! so that they can be chained:
38//!
39//! ```
40//! use test_assembler::Section;
41//!
42//! let mut section = Section::new();
43//! assert_eq!(section.D8(0xFF).L16(0xABCD).B32(0x12345678)
44//!             .get_contents().unwrap(),
45//!            &[0xFF, 0xCD, 0xAB, 0x12, 0x34, 0x56, 0x78]);
46//! ```
47//!
48//! `Label`s can be appended to a section as placeholders for values that
49//! are not yet known using the same methods:
50//!
51//! ```
52//! use test_assembler::*;
53//!
54//! let l = Label::new();
55//! let mut s = Section::with_endian(Endian::Little);
56//! s = s.D32(&l);
57//! // Now assign a value to l.
58//! l.set_const(0x12345678);
59//! assert_eq!(s.get_contents().unwrap(),
60//!            &[0x78, 0x56, 0x34, 0x12]);
61//! ```
62//!
63//! `Label`s can also be set to the current length of the `Section` by calling
64//! [`mark`][mark], which is useful for calculating an offset into the data:
65//!
66//! [mark]: struct.Section.html#method.mark
67//!
68//! ```
69//! use test_assembler::*;
70//!
71//! let l = Label::new();
72//! let s = Section::with_endian(Endian::Little);
73//! let start = s.start();
74//! s.append_repeated(0, 10)
75//!     .mark(&l)
76//!     .append_repeated(0, 10);
77//! assert_eq!(&l - &start, 10);
78//! ```
79
80#![allow(non_snake_case)]
81
82extern crate byteorder;
83
84#[cfg(doctest)]
85extern crate doc_comment;
86
87#[cfg(doctest)]
88doc_comment::doctest!("../README.md");
89
90use std::borrow::Borrow;
91use std::cell::RefCell;
92use std::fmt;
93use std::io::Cursor;
94use std::io::Seek;
95use std::io::SeekFrom;
96use std::io::Write;
97use std::ops::{Add, Deref, Sub};
98use std::rc::Rc;
99
100use byteorder::{BigEndian, LittleEndian, WriteBytesExt};
101
102/// Possible byte orders
103#[derive(Clone, Copy, Debug, PartialEq)]
104pub enum Endian {
105    Big,
106    Little,
107}
108
109/// The default endianness for this system.
110#[cfg(target_endian = "little")]
111pub const DEFAULT_ENDIAN: Endian = Endian::Little;
112
113/// The default endianness for this system.
114#[cfg(target_endian = "big")]
115pub const DEFAULT_ENDIAN: Endian = Endian::Big;
116
117/// Potential values of a `Binding`.
118enum BindingValue {
119    /// A known constant value.
120    Constant(u64),
121    /// Equal to some other binding plus a constant.
122    From(Rc<Binding>, i64),
123    /// Free to take on any value.
124    Unconstrained,
125}
126
127impl fmt::Debug for BindingValue {
128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129        match *self {
130            BindingValue::Constant(v) => write!(f, "Constant({})", v),
131            BindingValue::From(ref b, v) => write!(f, "From({:?}, {})", b, v),
132            BindingValue::Unconstrained => write!(f, "Unconstrained"),
133        }
134    }
135}
136
137/// A label's value, or if that is not yet known, how the value is related to other labels' values.
138struct Binding {
139    value: RefCell<BindingValue>,
140}
141
142impl fmt::Debug for Binding {
143    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144        write!(f, "Binding {{ {:?} }}", self.value.borrow())
145    }
146}
147
148/// These methods need to work with Rc<Binding>, so they go on a trait implemented for that type.
149trait BindingOffset {
150    /// Get the base `Binding` that this Binding references, as well
151    /// as the sum of all offsets along the chain.
152    fn get_base_and_offset(&self) -> (Rc<Binding>, i64);
153    /// Return the offset between two bindings, if they are related.
154    fn offset(&self, other: &Rc<Binding>) -> Option<i64>;
155}
156
157impl BindingOffset for Rc<Binding> {
158    fn get_base_and_offset(&self) -> (Rc<Binding>, i64) {
159        match *self.value.borrow().deref() {
160            BindingValue::From(ref b, offset) => {
161                let (base, base_offset) = b.get_base_and_offset();
162                (base, base_offset + offset)
163            }
164            // If it's not From another binding, just return self.
165            _ => (self.clone(), 0),
166        }
167    }
168
169    fn offset(&self, other: &Rc<Binding>) -> Option<i64> {
170        let (base, offset) = self.get_base_and_offset();
171        let (other_base, other_offset) = other.get_base_and_offset();
172        let base_ptr = base.deref() as *const Binding;
173        let other_base_ptr = other_base.deref() as *const Binding;
174        if base_ptr == other_base_ptr {
175            // If the two bindings have the same base, then the offset is
176            // the difference of their offsets.
177            Some(offset - other_offset)
178        } else {
179            // Otherwise they are unrelated.
180            None
181        }
182    }
183}
184
185impl Binding {
186    /// Create a new Binding with an unconstrained value.
187    pub fn unconstrained() -> Binding {
188        Binding {
189            value: RefCell::new(BindingValue::Unconstrained),
190        }
191    }
192    /// Create a new Binding whose value is taken from another Binding.
193    pub fn from(other: Rc<Binding>, offset: i64) -> Binding {
194        Binding {
195            value: RefCell::new(BindingValue::From(other, offset)),
196        }
197    }
198    /// Create a new Binding with a constant value.
199    pub fn constant(val: u64) -> Binding {
200        Binding {
201            value: RefCell::new(BindingValue::Constant(val)),
202        }
203    }
204
205    /// Set this `Binding`s value to `val`.
206    pub fn set_const(&self, val: u64) {
207        let mut v = self.value.borrow_mut();
208        *v = BindingValue::Constant(val);
209    }
210    /// Set this `Binding`s value equal to `other`.
211    pub fn set(&self, other: Rc<Binding>) {
212        let mut v = self.value.borrow_mut();
213        let (base, offset) = other.get_base_and_offset();
214        *v = BindingValue::From(base, offset);
215    }
216    /// Get the constant value of the `Binding`, if known.
217    pub fn value(&self) -> Option<u64> {
218        match *self.value.borrow() {
219            // If this Binding is a constant, this is easy.
220            BindingValue::Constant(c) => Some(c),
221            // If this Binding is based on another Binding, ask it for its
222            // value.
223            BindingValue::From(ref base, addend) => base.value().map(|v| v + addend as u64),
224            // If this Binding is unconstrained then its value is not known.
225            _ => None,
226        }
227    }
228}
229
230#[doc(hidden)]
231pub struct RealLabel {
232    binding: Rc<Binding>,
233}
234
235impl fmt::Debug for RealLabel {
236    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237        write!(f, "{:?}", self.binding)
238    }
239}
240
241/// Methods for creating a `Label` (or a `RealLabel`, but don't do that).
242pub trait LabelMaker {
243    /// Create an undefined label.
244    fn new() -> Self;
245    /// Create a label with a constant value `val`.
246    fn from_const(val: u64) -> Self;
247    /// Create a label whose value is equal to `other`.
248    fn from_label(other: &Self) -> Self;
249    /// Create a label whose value is equal to `other` plus `offset`.
250    fn from_label_offset(other: &Self, offset: i64) -> Self;
251}
252
253impl RealLabel {
254    /// Get the constant value of the `RealLabel`, if known.
255    pub fn value(&self) -> Option<u64> {
256        self.binding.value()
257    }
258    /// Get the relative offset from another label, if possible.
259    pub fn offset(&self, other: &RealLabel) -> Option<i64> {
260        // Let the Binding calculate the offset.
261        self.binding.offset(&other.binding)
262    }
263    /// Set this `RealLabel`s value to `val`.
264    pub fn set_const(&self, val: u64) {
265        self.binding.set_const(val);
266    }
267    /// Set this `RealLabel`s value equal to `other`.
268    pub fn set(&self, other: &RealLabel) {
269        //TODO: could use some sanity checks here?
270        self.binding.set(other.binding.clone())
271    }
272}
273
274impl LabelMaker for RealLabel {
275    fn new() -> RealLabel {
276        RealLabel {
277            binding: Rc::new(Binding::unconstrained()),
278        }
279    }
280    fn from_const(val: u64) -> RealLabel {
281        RealLabel {
282            binding: Rc::new(Binding::constant(val)),
283        }
284    }
285    fn from_label(other: &RealLabel) -> RealLabel {
286        RealLabel {
287            binding: other.binding.clone(),
288        }
289    }
290    fn from_label_offset(other: &RealLabel, offset: i64) -> RealLabel {
291        RealLabel {
292            binding: Rc::new(Binding::from(other.binding.clone(), offset)),
293        }
294    }
295}
296
297/// A `Label` represents a value not yet known that is stored in a `Section`.
298///
299/// As long as all the labels a section refers to are defined
300/// by the time its contents are retrieved as bytes, undefined
301/// labels can be used freely in that section's construction.
302/// A label can be in one of three states:
303///
304/// * undefined,
305/// * defined as the sum of some other label and a constant, or
306/// * a constant.
307///
308/// A label's value never changes, but it can accumulate constraints.
309/// Adding labels and integers is permitted, and yields a label.
310/// Subtracting a constant from a label is permitted, and also yields a
311/// label. Subtracting two labels that have some relationship to each
312/// other is permitted, and yields a constant.
313///
314/// A common usage of `Label` is to use [`Section::mark`] to make a `Label`
315/// contain an offset into the `Section` without having to hard-code it.
316/// The `Section` methods for inserting fixed-width integer values (such as
317/// [`Section::L32`]) all accept `&Label` for the purpose of writing a value
318/// that is not yet available.
319///
320/// # Examples
321///
322/// `Label`s can be set to point to other `Label`s, potentially with an offset.
323///
324/// ```
325/// use test_assembler::*;
326///
327/// let l1 = Label::new();
328/// // l2 is l1's value (which is currently undefined) + 10
329/// let l2 = &l1 + 10;
330/// // Now give l1 a value.
331/// l1.set_const(1);
332/// // l2's value is derived from l1.
333/// assert_eq!(l2.value().unwrap(), 11);
334/// ```
335#[derive(Clone)]
336pub struct Label(pub Rc<RealLabel>);
337
338impl fmt::Debug for Label {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        write!(f, "Label {{ {:?} }}", self.0)
341    }
342}
343
344impl Deref for Label {
345    type Target = RealLabel;
346
347    fn deref(&self) -> &RealLabel {
348        let &Label(ref inner) = self;
349        inner.deref()
350    }
351}
352
353impl LabelMaker for Label {
354    fn new() -> Label {
355        Label(Rc::new(RealLabel::new()))
356    }
357    fn from_const(val: u64) -> Label {
358        Label(Rc::new(RealLabel::from_const(val)))
359    }
360    fn from_label(other: &Label) -> Label {
361        let &Label(ref inner) = other;
362        Label(Rc::new(RealLabel::from_label(inner.borrow())))
363    }
364    fn from_label_offset(other: &Label, offset: i64) -> Label {
365        let &Label(ref inner) = other;
366        Label(Rc::new(RealLabel::from_label_offset(
367            inner.borrow(),
368            offset,
369        )))
370    }
371}
372
373/// Add a constant to a `Label`, producing a new `Label`.
374///
375/// The new `Label` references the existing `Label`.
376impl<'a> Add<i64> for &'a Label {
377    type Output = Label;
378
379    fn add(self, rhs: i64) -> Label {
380        Label::from_label_offset(self, rhs)
381    }
382}
383
384/// Subtract a constant from a `Label`, producing a new `Label`.
385///
386/// The new `Label` references the existing `Label`.
387impl<'a> Sub<i64> for &'a Label {
388    type Output = Label;
389
390    fn sub(self, rhs: i64) -> Label {
391        Label::from_label_offset(self, -rhs)
392    }
393}
394
395/// Subtract a `Label` from another `Label`, returning an `i64`.
396///
397/// If the labels are unrelated this will panic.
398impl<'a> Sub<&'a Label> for &'a Label {
399    type Output = i64;
400
401    fn sub(self, rhs: &'a Label) -> i64 {
402        self.offset(rhs).unwrap()
403    }
404}
405
406/// A marker trait for number types.
407pub trait Num {}
408
409impl Num for u8 {}
410impl Num for u16 {}
411impl Num for u32 {}
412impl Num for u64 {}
413
414/// An enum to hold `Label`s or `Num`s.
415pub enum LabelOrNum<T: Num> {
416    Label(Label),
417    Num(T),
418}
419
420/// A trait to allow passing numbers or Labels.
421pub trait ToLabelOrNum<'a, T: Num> {
422    fn to_labelornum(self) -> LabelOrNum<T>;
423}
424
425impl<'a, T: Num> ToLabelOrNum<'a, T> for Label {
426    fn to_labelornum(self) -> LabelOrNum<T> {
427        LabelOrNum::Label(self)
428    }
429}
430
431impl<'a, T: Num> ToLabelOrNum<'a, T> for &'a Label {
432    fn to_labelornum(self) -> LabelOrNum<T> {
433        LabelOrNum::Label(self.clone())
434    }
435}
436
437impl<'a, T: Num> ToLabelOrNum<'a, T> for T {
438    fn to_labelornum(self) -> LabelOrNum<T> {
439        LabelOrNum::Num(self)
440    }
441}
442
443/// A reference to a `Label` that has been appended to a `Section`.
444#[derive(Clone)]
445struct Reference {
446    /// The `Label` being referenced.
447    label: Label,
448    /// The offset of the reference within the `Section`.
449    offset: u64,
450    /// The endianness with which the `Label` should be stored.
451    endian: Endian,
452    /// The size with which the `Label` should be stored.
453    size: usize,
454}
455
456/// A section is a sequence of bytes, constructed by appending bytes to the end.
457///
458/// Sections have a convenient and flexible set of member
459/// functions for appending data in various formats: big-endian and
460/// little-endian signed and unsigned values of different sizes, and
461/// raw blocks of bytes.
462///
463/// There are methods for appending each of `u8`, `u16`, `u32`, and `u64`
464/// in each of big, little, or the `Section`'s default endianness.
465/// The method names are {D,L,B}{8,16,32,64} for each variant, so
466/// [`D16`][D16] writes a `u16` in the `Section`'s default endianness, and
467/// [`L64`][L64] writes a `u64` in little-endian byte order.
468///
469/// Each of these methods also accepts a [`Label`][Label] to write
470/// non-constant values.
471///
472/// See [the module-level documentation][module] for examples.
473///
474/// [module]: index.html
475/// [D16]: #method.D16
476/// [L64]: #method.L64
477/// [Label]: struct.Label.html
478pub struct Section {
479    /// The current endianness of the writer.
480    ///
481    /// This sets the behavior of the D<N> appending functions.
482    pub endian: Endian,
483    /// The contents of the section.
484    contents: Cursor<Vec<u8>>,
485    /// References to `Label`s that were added to this `Section`.
486    references: Vec<Reference>,
487    /// A label representing the start of this `Section`.
488    start: Label,
489    /// A label representing the final size of this `Section`.
490    final_size: Label,
491}
492
493impl Section {
494    /// Construct a `Section` with platform-default endianness.
495    pub fn new() -> Section {
496        Section::with_endian(DEFAULT_ENDIAN)
497    }
498
499    /// Construct a `Section` with `endian` endianness.
500    pub fn with_endian(endian: Endian) -> Section {
501        Section {
502            endian,
503            contents: Cursor::new(vec![]),
504            references: vec![],
505            start: Label::new(),
506            final_size: Label::new(),
507        }
508    }
509
510    /// Return the current size of the section.
511    pub fn size(&self) -> u64 {
512        self.contents.get_ref().len() as u64
513    }
514
515    /// Return a `Label` that will resolve to the final size of the section.
516    ///
517    /// This label is undefined until `get_contents` is called.
518    pub fn final_size(&self) -> Label {
519        self.final_size.clone()
520    }
521
522    /// Get the contents of this section as a slice of bytes.
523    ///
524    /// Consumes the section. If there were still undefined labels,
525    /// return `None`.
526    pub fn get_contents(self) -> Option<Vec<u8>> {
527        // Patch all labels into the section's contents.
528        let mut section = self;
529        section.final_size.set_const(section.size());
530        let references: Vec<Reference> = section.references.to_vec();
531        let mut ok = true;
532        section = references.iter().cloned().fold(section, |s, r| {
533            if let Some(val) = r.label.value() {
534                s.store_label_value(val, r.offset, r.endian, r.size)
535            } else {
536                ok = false;
537                s
538            }
539        });
540        if ok {
541            Some(section.contents.into_inner())
542        } else {
543            None
544        }
545    }
546
547    /// Return a label representing the start of the section.
548    ///
549    /// It is up to the user whether this label represents the section's
550    /// position in an object file, the section's address in memory, or
551    /// what have you; some applications may need both, in which case
552    /// this simple-minded interface won't be enough. This class only
553    /// provides a single start label, for use with the `here` and `mark`
554    /// methods.
555    pub fn start(&self) -> Label {
556        self.start.clone()
557    }
558
559    /// A label representing the point at which the next appended item will appear in the section, relative to `start`.
560    pub fn here(&self) -> Label {
561        &self.start + self.size() as i64
562    }
563
564    /// Set the value of `start` to `value`.
565    pub fn set_start_const(self, value: u64) -> Section {
566        self.start.set_const(value);
567        self
568    }
569
570    /// Set `label` to [`here`](#method.here), and return this section.
571    pub fn mark(self, label: &Label) -> Section {
572        label.set(&self.here());
573        self
574    }
575
576    /// Append `data` to the end of this section, and return this section.
577    pub fn append_bytes(mut self, data: &[u8]) -> Section {
578        self.contents.write_all(data).unwrap();
579        self
580    }
581
582    /// Append `section`'s contents to the end of this section.
583    ///
584    /// Any `Label`s that were appended to `section` will not be
585    /// resolved until this section is finalized.
586    /// Return this section.
587    pub fn append_section<S: Into<Section>>(mut self, section: S) -> Section {
588        let Section {
589            contents,
590            references,
591            final_size,
592            ..
593        } = section.into();
594        final_size.set_const(contents.get_ref().len() as u64);
595        let current = self.size();
596        self.contents.write_all(&contents.into_inner()).unwrap();
597        self.references.extend(references.into_iter().map(|mut r| {
598            r.offset += current;
599            r
600        }));
601        self
602    }
603
604    /// Append `count` copies of `byte` to the end of this section.
605    ///
606    /// Return this section.
607    pub fn append_repeated(mut self, byte: u8, count: usize) -> Section {
608        for _ in 0..count {
609            self.contents.write_u8(byte).unwrap();
610        }
611        self
612    }
613
614    /// Jump to the next location aligned on an `alignment`-byte boundary, relative to the start of the section.
615    ///
616    /// Fill the gap with zeroes. `alignment` must be a power of two.
617    /// Return this section.
618    pub fn align(self, alignment: u64) -> Section {
619        // `alignment` must be a power of two.
620        assert!(((alignment - 1) & alignment) == 0);
621        let new_size = (self.size() + alignment - 1) & !(alignment - 1);
622        let add = new_size - self.size();
623        self.append_repeated(0, add as usize)
624    }
625
626    fn store_label_value(mut self, val: u64, offset: u64, endian: Endian, size: usize) -> Section {
627        let current = self.size();
628        if offset != current {
629            self.contents.seek(SeekFrom::Start(offset)).unwrap();
630        }
631        match endian {
632            Endian::Little => match size {
633                1 => self.L8(val as u8),
634                2 => self.L16(val as u16),
635                4 => self.L32(val as u32),
636                8 => self.L64(val),
637                _ => unreachable!("Unhandled label size!"),
638            },
639            Endian::Big => match size {
640                1 => self.B8(val as u8),
641                2 => self.B16(val as u16),
642                4 => self.B32(val as u32),
643                8 => self.B64(val),
644                _ => unreachable!("Unhandled label size!"),
645            },
646        }
647    }
648
649    /// Append `label` to the Section with `endian` endianness, taking `size` bytes.
650    ///
651    /// Panics if `size` is not an intrinsic integer size: 1, 2, 4, 8 bytes.
652    fn append_label(mut self, label: &Label, endian: Endian, size: usize) -> Section {
653        let current = self.size();
654        // For labels with a known value, don't bother with a reference.
655        if let Some(val) = label.value() {
656            self.store_label_value(val, current, endian, size)
657        } else {
658            // label isn't yet known, need to store a reference.
659            self.references.push(Reference {
660                label: label.clone(),
661                offset: current,
662                endian,
663                size,
664            });
665            // Reserve space for the label.
666            self.append_repeated(0, size)
667        }
668    }
669
670    /// Append `byte` with the Section's default endianness.
671    ///
672    /// `byte` may be a `Label` or a `u8`.
673    /// Return this section.
674    pub fn D8<'a, T: ToLabelOrNum<'a, u8>>(mut self, byte: T) -> Section {
675        let endian = self.endian;
676        match byte.to_labelornum() {
677            LabelOrNum::Num(n) => {
678                self.contents.write_u8(n).unwrap();
679                self
680            }
681            LabelOrNum::Label(l) => self.append_label(&l, endian, 1),
682        }
683    }
684    /// Append `byte` as little-endian (identical to `D8`).
685    ///
686    /// Return this section.
687    pub fn L8<'a, T: ToLabelOrNum<'a, u8>>(self, byte: T) -> Section {
688        self.D8(byte)
689    }
690    /// Append `byte` as big-endian (identical to `D8`).
691    ///
692    /// Return this section.
693    pub fn B8<'a, T: ToLabelOrNum<'a, u8>>(self, byte: T) -> Section {
694        self.D8(byte)
695    }
696
697    /// Append `word` with the Section's default endianness.
698    ///
699    /// `word` may be a `Label` or a `u16`.
700    /// Return this section.
701    pub fn D16<'a, T: ToLabelOrNum<'a, u16>>(self, word: T) -> Section {
702        match self.endian {
703            Endian::Little => self.L16(word),
704            Endian::Big => self.B16(word),
705        }
706    }
707    /// Append `word` as little-endian.
708    ///
709    /// `word` may be a `Label` or a `u16`.
710    /// Return this section.
711    pub fn L16<'a, T: ToLabelOrNum<'a, u16>>(mut self, word: T) -> Section {
712        match word.to_labelornum() {
713            LabelOrNum::Num(n) => {
714                self.contents.write_u16::<LittleEndian>(n).unwrap();
715                self
716            }
717            LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 2),
718        }
719    }
720    /// Append `word` as big-endian.
721    ///
722    /// `word` may be a `Label` or a `u16`.
723    /// Return this section.
724    pub fn B16<'a, T: ToLabelOrNum<'a, u16>>(mut self, word: T) -> Section {
725        match word.to_labelornum() {
726            LabelOrNum::Num(n) => {
727                self.contents.write_u16::<BigEndian>(n).unwrap();
728                self
729            }
730            LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 2),
731        }
732    }
733
734    /// Append `dword` with the Section's default endianness.
735    ///
736    /// `dword` may be a `Label` or a `u32`.
737    /// Return this section.
738    pub fn D32<'a, T: ToLabelOrNum<'a, u32>>(self, dword: T) -> Section {
739        match self.endian {
740            Endian::Little => self.L32(dword),
741            Endian::Big => self.B32(dword),
742        }
743    }
744    /// Append `dword` as little-endian.
745    ///
746    /// `dword` may be a `Label` or a `u32`.
747    /// Return this section.
748    pub fn L32<'a, T: ToLabelOrNum<'a, u32>>(mut self, dword: T) -> Section {
749        match dword.to_labelornum() {
750            LabelOrNum::Num(n) => {
751                self.contents.write_u32::<LittleEndian>(n).unwrap();
752                self
753            }
754            LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 4),
755        }
756    }
757    /// Append `dword` as big-endian.
758    ///
759    /// `dword` may be a `Label` or a `u32`.
760    /// Return this section.
761    pub fn B32<'a, T: ToLabelOrNum<'a, u32>>(mut self, dword: T) -> Section {
762        match dword.to_labelornum() {
763            LabelOrNum::Num(n) => {
764                self.contents.write_u32::<BigEndian>(n).unwrap();
765                self
766            }
767            LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 4),
768        }
769    }
770
771    /// Append `qword` with the Section's default endianness.
772    ///
773    /// `qword` may be a `Label` or a `u32`.
774    /// Return this section.
775    pub fn D64<'a, T: ToLabelOrNum<'a, u64>>(self, qword: T) -> Section {
776        match self.endian {
777            Endian::Little => self.L64(qword),
778            Endian::Big => self.B64(qword),
779        }
780    }
781    /// Append `qword` as little-endian.
782    ///
783    /// `qword` may be a `Label` or a `u32`.
784    /// Return this section.
785    pub fn L64<'a, T: ToLabelOrNum<'a, u64>>(mut self, qword: T) -> Section {
786        match qword.to_labelornum() {
787            LabelOrNum::Num(n) => {
788                self.contents.write_u64::<LittleEndian>(n).unwrap();
789                self
790            }
791            LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 8),
792        }
793    }
794    /// Append `qword` as big-endian.
795    ///
796    /// `qword` may be a `Label` or a `u32`.
797    /// Return this section.
798    pub fn B64<'a, T: ToLabelOrNum<'a, u64>>(mut self, qword: T) -> Section {
799        match qword.to_labelornum() {
800            LabelOrNum::Num(n) => {
801                self.contents.write_u64::<BigEndian>(n).unwrap();
802                self
803            }
804            LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 8),
805        }
806    }
807}
808
809impl Default for Section {
810    fn default() -> Self {
811        Section::new()
812    }
813}
814
815#[test]
816fn binding_offset() {
817    let b_u = Rc::new(Binding::unconstrained());
818    let b_c = Rc::new(Binding::constant(1));
819    let b_f1 = Rc::new(Binding::from(b_u.clone(), 0));
820    // b_f1 is equal to b_u, so the offset should be zero.
821    assert_eq!(b_f1.offset(&b_u).unwrap(), 0);
822    // b_f1 and b_c are unrelated
823    assert!(b_f1.offset(&b_c).is_none());
824    // as are b_u and b_c.
825    assert!(b_u.offset(&b_c).is_none());
826    assert!(b_c.offset(&b_u).is_none());
827
828    let b_f2 = Rc::new(Binding::from(b_c.clone(), 10));
829    // b_f2 is a non-zero offset from b_c.
830    assert_eq!(b_f2.offset(&b_c).unwrap(), 10);
831    // We need to go deeper.
832    let b_f3 = Rc::new(Binding::from(b_f1.clone(), 10));
833    assert_eq!(b_f3.offset(&b_u).unwrap(), 10);
834    let b_f4 = Rc::new(Binding::from(b_f3.clone(), 10));
835    assert_eq!(b_f4.offset(&b_u).unwrap(), 20);
836    // Make another chain of bindings so we can test that the leaves of
837    // both chains compare properly.
838    // <INCEPTION HORN>
839    let b_f5 = Rc::new(Binding::from(b_u.clone(), 10));
840    let b_f6 = Rc::new(Binding::from(b_f5.clone(), 10));
841    assert_eq!(b_f6.offset(&b_f5).unwrap(), 10);
842    assert_eq!(b_f6.offset(&b_u).unwrap(), 20);
843    // Now for the kicker, b_f6 and b_f4 should be the same value, since
844    // they're both b_u + 20.
845    assert_eq!(b_f6.offset(&b_f4).unwrap(), 0);
846    // and some additional checks.
847    assert_eq!(b_f6.offset(&b_f3).unwrap(), 10);
848    assert_eq!(b_f3.offset(&b_f6).unwrap(), -10);
849}
850
851#[test]
852fn binding_value() {
853    let b_u = Rc::new(Binding::unconstrained());
854    let b_c = Rc::new(Binding::constant(1));
855    let b_f1 = Rc::new(Binding::from(b_u.clone(), 0));
856    assert!(b_u.value().is_none());
857    assert_eq!(b_c.value().unwrap(), 1);
858    assert!(b_f1.value().is_none());
859
860    let b_f2 = Rc::new(Binding::from(b_c.clone(), 10));
861    assert_eq!(b_f2.value().unwrap(), 11);
862    // We need to go deeper.
863    let b_f3 = Rc::new(Binding::from(b_f1.clone(), 10));
864    assert!(b_f3.value().is_none());
865    let b_f4 = Rc::new(Binding::from(b_f3.clone(), 10));
866    assert!(b_f4.value().is_none());
867
868    let b_f5 = Rc::new(Binding::from(b_f2.clone(), 10));
869    assert_eq!(b_f5.value().unwrap(), 21);
870}
871
872#[test]
873fn label_unconstrained() {
874    let l = Label::new();
875    assert!(l.value().is_none());
876}
877
878#[test]
879fn label_const() {
880    let l = Label::from_const(10);
881    assert_eq!(l.value().unwrap(), 10);
882}
883
884#[test]
885fn label_label() {
886    let l1 = Label::new();
887    let l2 = Label::from_label(&l1);
888    assert!(l2.value().is_none());
889    // The offset should work both ways.
890    assert_eq!(l2.offset(&l1).unwrap(), 0);
891    assert_eq!(l1.offset(&l2).unwrap(), 0);
892}
893
894#[test]
895fn label_label_offset() {
896    let l1 = Label::new();
897    let l2 = Label::from_label_offset(&l1, 10);
898    assert!(l2.value().is_none());
899    assert_eq!(l2.offset(&l1).unwrap(), 10);
900    assert_eq!(l1.offset(&l2).unwrap(), -10);
901
902    let l3 = Label::from_label_offset(&l2, 10);
903    assert_eq!(l3.offset(&l2).unwrap(), 10);
904    assert_eq!(l2.offset(&l3).unwrap(), -10);
905    assert_eq!(l3.offset(&l1).unwrap(), 20);
906    assert_eq!(l1.offset(&l3).unwrap(), -20);
907
908    let l4 = Label::from_label_offset(&l3, 10);
909    assert_eq!(l4.offset(&l1).unwrap(), 30);
910
911    // Check that chains of label offsets work properly.
912    let l5 = Label::from_label_offset(&l1, 10);
913    // l5 and l2 are both l1 + 10.
914    assert_eq!(l5.offset(&l2).unwrap(), 0);
915    assert_eq!(l5.offset(&l3).unwrap(), -10);
916    assert_eq!(l3.offset(&l5).unwrap(), 10);
917}
918
919#[test]
920fn label_offset_unrelated() {
921    let l1 = Label::new();
922    let l2 = Label::new();
923    assert!(l2.offset(&l1).is_none());
924    assert!(l1.offset(&l2).is_none());
925}
926
927#[test]
928fn label_add() {
929    let l1 = Label::new();
930    let l2 = &l1 + 10;
931    assert_eq!(l2.offset(&l1).unwrap(), 10);
932}
933
934#[test]
935fn label_sub() {
936    let l1 = Label::new();
937    let l2 = &l1 - 10;
938    assert_eq!(l2.offset(&l1).unwrap(), -10);
939}
940
941#[test]
942fn label_sub_label() {
943    let l1 = Label::new();
944    let l2 = &l1 + 10;
945    assert_eq!(&l2 - &l1, 10);
946}
947
948#[test]
949fn label_set_const() {
950    let l = Label::new();
951    let val = 0x12345678;
952    l.set_const(val);
953    assert_eq!(l.value().unwrap(), val);
954}
955
956#[test]
957fn label_set() {
958    let val = 0x12345678;
959    let l1 = Label::from_const(val);
960    let l2 = Label::new();
961    l2.set(&l1);
962    assert_eq!(l2.value().unwrap(), val);
963    // Check that setting the first value's label *after* the call to set works.
964    let l3 = Label::new();
965    let l4 = Label::new();
966    l4.set(&l3);
967    l3.set_const(val);
968    assert_eq!(l4.value().unwrap(), val);
969}
970
971#[test]
972fn section_construction() {
973    let s = Section::new();
974    assert_eq!(s.endian, DEFAULT_ENDIAN);
975
976    let s2 = Section::with_endian(Endian::Little);
977    assert_eq!(s2.endian, Endian::Little);
978}
979
980#[test]
981fn section_append_bytes() {
982    let s = Section::new();
983    let b1 = [0, 1, 2, 3, 4];
984    let b2 = [0xf, 0xe, 0xd, 0xc, 0xb];
985    assert_eq!(
986        s.append_bytes(&b1)
987            .append_bytes(&b2)
988            .get_contents()
989            .unwrap(),
990        &[0, 1, 2, 3, 4, 0xf, 0xe, 0xd, 0xc, 0xb]
991    );
992}
993
994#[test]
995fn section_final_size() {
996    let s = Section::new();
997    let size = s.final_size();
998    s.append_repeated(0, 20).get_contents().unwrap();
999    assert_eq!(size.value().unwrap(), 20);
1000}
1001
1002#[test]
1003fn section_append_section_simple() {
1004    assert_eq!(
1005        Section::new()
1006            .D8(0xab)
1007            .append_section(Section::new().D8(0xcd))
1008            .D8(0xef)
1009            .get_contents()
1010            .unwrap(),
1011        &[0xab, 0xcd, 0xef]
1012    );
1013}
1014
1015#[test]
1016fn section_append_section_labels() {
1017    let mut s = Section::new();
1018    let l1 = Label::from_const(0x12);
1019    let l2 = Label::new();
1020    s = s.D8(0xab);
1021    {
1022        s = s.append_section(Section::new().D8(0xcd).D8(&l1).D8(&l2));
1023    }
1024    s = s.D8(0xef);
1025    l2.set_const(0x34);
1026    assert_eq!(s.get_contents().unwrap(), &[0xab, 0xcd, 0x12, 0x34, 0xef]);
1027}
1028
1029#[test]
1030fn section_append_section_final_size() {
1031    let s = Section::new().D8(0xcd);
1032    assert_eq!(
1033        Section::new()
1034            .D8(0xab)
1035            .D8(s.final_size())
1036            .append_section(s)
1037            .D8(0xef)
1038            .get_contents()
1039            .unwrap(),
1040        &[0xab, 1, 0xcd, 0xef]
1041    );
1042}
1043
1044#[test]
1045fn section_append_repeated() {
1046    let s = Section::new();
1047    assert_eq!(
1048        s.append_repeated(0xff, 5).get_contents().unwrap(),
1049        &[0xff, 0xff, 0xff, 0xff, 0xff]
1050    );
1051}
1052
1053#[test]
1054fn section_align() {
1055    let s = Section::new();
1056    assert_eq!(
1057        s.D8(1).align(8).D8(1).get_contents().unwrap(),
1058        &[1, 0, 0, 0, 0, 0, 0, 0, 1]
1059    );
1060}
1061
1062#[test]
1063fn section_test_8() {
1064    let s = Section::new();
1065    assert_eq!(
1066        s.D8(0x12).L8(0x12).B8(0x12).get_contents().unwrap(),
1067        &[0x12, 0x12, 0x12]
1068    );
1069}
1070
1071#[test]
1072fn section_test_16() {
1073    let s = Section::with_endian(Endian::Little);
1074    assert_eq!(
1075        s.D16(0xABCD)
1076            .L16(0xABCD)
1077            .B16(0xABCD)
1078            .get_contents()
1079            .unwrap(),
1080        &[0xCD, 0xAB, 0xCD, 0xAB, 0xAB, 0xCD]
1081    );
1082}
1083
1084#[test]
1085fn section_test_32() {
1086    let s = Section::with_endian(Endian::Little);
1087    assert_eq!(
1088        s.D32(0xABCD1234)
1089            .L32(0xABCD1234)
1090            .B32(0xABCD1234)
1091            .get_contents()
1092            .unwrap(),
1093        &[0x34, 0x12, 0xCD, 0xAB, 0x34, 0x12, 0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34]
1094    );
1095}
1096
1097#[test]
1098fn section_test_64() {
1099    let s = Section::with_endian(Endian::Little);
1100    assert_eq!(
1101        s.D64(0x12345678ABCDEFFF)
1102            .L64(0x12345678ABCDEFFF)
1103            .B64(0x12345678ABCDEFFF)
1104            .get_contents()
1105            .unwrap(),
1106        &[
1107            0xFF, 0xEF, 0xCD, 0xAB, 0x78, 0x56, 0x34, 0x12, 0xFF, 0xEF, 0xCD, 0xAB, 0x78, 0x56,
1108            0x34, 0x12, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0xFF
1109        ]
1110    );
1111}
1112
1113#[test]
1114fn section_d8l_const_label() {
1115    let l = Label::from_const(10);
1116    let s = Section::with_endian(Endian::Little);
1117    assert_eq!(
1118        s.D8(&l).L8(&l).B8(&l).get_contents().unwrap(),
1119        &[10, 10, 10]
1120    );
1121}
1122
1123#[test]
1124fn section_d16l_const_label() {
1125    let l = Label::from_const(0xABCD);
1126    let s = Section::with_endian(Endian::Little);
1127    assert_eq!(
1128        s.D16(&l).L16(&l).B16(&l).get_contents().unwrap(),
1129        &[0xCD, 0xAB, 0xCD, 0xAB, 0xAB, 0xCD]
1130    );
1131}
1132
1133#[test]
1134fn section_d32l_const_label() {
1135    let l = Label::from_const(0xABCD1234);
1136    let s = Section::with_endian(Endian::Little);
1137    assert_eq!(
1138        s.D32(&l).L32(&l).B32(&l).get_contents().unwrap(),
1139        &[0x34, 0x12, 0xCD, 0xAB, 0x34, 0x12, 0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34]
1140    );
1141}
1142
1143#[test]
1144fn section_d64l_const_label() {
1145    let l = Label::from_const(0xABCD12345678F00D);
1146    let s = Section::with_endian(Endian::Little);
1147    assert_eq!(
1148        s.D64(&l).L64(&l).B64(&l).get_contents().unwrap(),
1149        &[
1150            0x0D, 0xF0, 0x78, 0x56, 0x34, 0x12, 0xCD, 0xAB, 0x0D, 0xF0, 0x78, 0x56, 0x34, 0x12,
1151            0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34, 0x56, 0x78, 0xF0, 0x0D
1152        ]
1153    );
1154}
1155
1156#[test]
1157fn section_get_contents_label_no_value() {
1158    // Trying to get_contents on a Section when a Label that was added
1159    // has no value should return None.
1160    let l = Label::new();
1161    let s = Section::with_endian(Endian::Little);
1162    assert!(s.D8(&l).get_contents().is_none());
1163}
1164
1165#[test]
1166fn section_label_assign_late() {
1167    let l = Label::new();
1168    let mut s = Section::with_endian(Endian::Little);
1169    s = s.D8(&l).L8(&l).B8(&l);
1170    // Now assign a value to l.
1171    l.set_const(10);
1172    assert_eq!(s.get_contents().unwrap(), &[10, 10, 10]);
1173}
1174
1175#[test]
1176fn section_start_here() {
1177    let mut s = Section::with_endian(Endian::Little);
1178    s = s.append_repeated(0, 10);
1179    let start = s.start();
1180    let mut here = s.here();
1181    assert_eq!(here.offset(&start).unwrap(), 10);
1182    s = s.append_repeated(0, 10);
1183    here = s.here();
1184    assert_eq!(here.offset(&start).unwrap(), 20);
1185}
1186
1187#[test]
1188fn section_start_mark() {
1189    let s = Section::with_endian(Endian::Little);
1190    let start = s.start();
1191    let marked = Label::new();
1192    s.append_repeated(0, 10)
1193        .mark(&marked)
1194        .append_repeated(0, 10);
1195    assert_eq!(marked.offset(&start).unwrap(), 10);
1196}
1197
1198#[test]
1199fn section_additional_methods_trait() {
1200    trait ExtraSection {
1201        fn add_a_thing(self) -> Section;
1202    }
1203
1204    impl ExtraSection for Section {
1205        fn add_a_thing(self) -> Section {
1206            self.B8(0x12).B16(0x3456).B32(0x7890abcd)
1207        }
1208    }
1209
1210    assert_eq!(
1211        Section::new()
1212            .D8(0)
1213            .add_a_thing()
1214            .D8(1)
1215            .get_contents()
1216            .unwrap(),
1217        &[0, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 1]
1218    );
1219}
1220
1221#[test]
1222fn test_simple_labels() {
1223    let start = Label::new();
1224    let end = Label::new();
1225
1226    let _section = Section::new().mark(&start).mark(&end);
1227
1228    assert_eq!(start.offset(&end), Some(0));
1229}
1230
1231#[test]
1232fn test_set_start_const() {
1233    let l = Label::new();
1234    Section::new()
1235        .set_start_const(0)
1236        .append_repeated(0, 10)
1237        .mark(&l)
1238        .get_contents()
1239        .unwrap();
1240    assert_eq!(l.value().unwrap(), 10);
1241}
1242
1243#[test]
1244fn section_bigendian_defaults() {
1245    let s = Section::with_endian(Endian::Big);
1246    assert_eq!(
1247        s.D8(0x12)
1248            .D16(0x1234)
1249            .D32(0x12345678)
1250            .D64(0x12345678ABCDEFFF)
1251            .get_contents()
1252            .unwrap(),
1253        &[
1254            0x12, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF,
1255            0xFF
1256        ]
1257    );
1258}