Skip to content

Commit

Permalink
Add read-no-alloc feature gate
Browse files Browse the repository at this point in the history
  • Loading branch information
nbdd0121 committed Oct 12, 2021
1 parent 9eed5f8 commit 425896b
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 81 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- run: cargo test --no-default-features
# Ensure gimli can be built without alloc.
- run: cargo check --no-default-features --feature read-no-alloc
- run: cargo test --no-default-features --features read
- run: cargo test --no-default-features --features read,fallible-iterator
- run: cargo test --no-default-features --features read,std
Expand Down
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ test-assembler = "0.1.3"
typed-arena = "2"

[features]
read = []
endian-reader = ["stable_deref_trait"]
read-no-alloc = []
read = ["read-no-alloc"]
endian-reader = ["read", "stable_deref_trait"]
write = ["indexmap"]
std = ["fallible-iterator/std", "stable_deref_trait/std"]
default = ["read", "write", "std", "fallible-iterator", "endian-reader"]
Expand Down
4 changes: 2 additions & 2 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ macro_rules! dw {
if let Some(s) = self.static_string() {
f.pad(s)
} else {
f.pad(&format!("Unknown {}: {}",
write!(f, "Unknown {}: {}",
stringify!($struct_name),
self.0))
self.0)
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/leb128.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
//! ```
const CONTINUATION_BIT: u8 = 1 << 7;
#[cfg(feature = "read")]
#[cfg(feature = "read-no-alloc")]
const SIGN_BIT: u8 = 1 << 6;

#[inline]
Expand All @@ -62,7 +62,7 @@ fn low_bits_of_u64(val: u64) -> u8 {

/// A module for reading signed and unsigned integers that have been LEB128
/// encoded.
#[cfg(feature = "read")]
#[cfg(feature = "read-no-alloc")]
pub mod read {
use super::{low_bits_of_byte, CONTINUATION_BIT, SIGN_BIT};
use crate::read::{Error, Reader, Result};
Expand Down
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#![no_std]

#[allow(unused_imports)]
#[cfg(any(feature = "read", feature = "write"))]
#[macro_use]
extern crate alloc;

Expand All @@ -62,10 +63,10 @@ pub use crate::endianity::{BigEndian, Endianity, LittleEndian, NativeEndian, Run

pub mod leb128;

#[cfg(feature = "read")]
#[cfg(feature = "read-no-alloc")]
pub mod read;
// For backwards compat.
#[cfg(feature = "read")]
#[cfg(feature = "read-no-alloc")]
pub use crate::read::*;

#[cfg(feature = "write")]
Expand Down
42 changes: 33 additions & 9 deletions src/read/cfi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "read")]
use alloc::vec::Vec;

use core::cmp::{Ord, Ordering};
Expand All @@ -10,9 +11,9 @@ use super::util::{ArrayLike, ArrayVec};
use crate::common::{DebugFrameOffset, EhFrameOffset, Encoding, Format, Register, SectionId};
use crate::constants::{self, DwEhPe};
use crate::endianity::Endianity;
use crate::read::{
EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, StoreOnHeap,
};
#[cfg(feature = "read")]
use crate::read::StoreOnHeap;
use crate::read::{EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section};

/// `DebugFrame` contains the `.debug_frame` section's frame unwinding
/// information required to unwind to and recover registers from older frames on
Expand Down Expand Up @@ -1738,8 +1739,10 @@ impl<R: Reader> FrameDescriptionEntry<R> {

/// Specification of what storage should be used for [`UnwindContext`].
///
/// Normally you would only need to use [`StoreOnHeap`], which places the stack
/// on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`].
#[cfg_attr(feature = "read", doc = "
Normally you would only need to use [`StoreOnHeap`], which places the stack
on the heap using [`Vec`]. This is the default storage type parameter for [`UnwindContext`].
")]
///
/// If you need to avoid [`UnwindContext`] from allocating memory, e.g. for signal safety,
/// you can provide you own storage specification:
Expand Down Expand Up @@ -1780,8 +1783,10 @@ pub trait UnwindContextStorage<R: Reader>: Sized {
type Stack: ArrayLike<Item = UnwindTableRow<R, Self>>;
}

#[cfg(feature = "read")]
const MAX_RULES: usize = 192;

#[cfg(feature = "read")]
impl<R: Reader> UnwindContextStorage<R> for StoreOnHeap {
type Rules = [(Register, RegisterRule<R>); MAX_RULES];
type Stack = Vec<UnwindTableRow<R, Self>>;
Expand Down Expand Up @@ -1814,7 +1819,11 @@ impl<R: Reader> UnwindContextStorage<R> for StoreOnHeap {
/// # }
/// ```
#[derive(Clone, PartialEq, Eq)]
pub struct UnwindContext<R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> {
pub struct UnwindContext<
R: Reader,
#[cfg(not(feature = "read"))] A: UnwindContextStorage<R>,
#[cfg(feature = "read")] A: UnwindContextStorage<R> = StoreOnHeap,
> {
// Stack of rows. The last row is the row currently being built by the
// program. There is always at least one row. The vast majority of CFI
// programs will only ever have one row on the stack.
Expand Down Expand Up @@ -1849,6 +1858,7 @@ impl<R: Reader, A: UnwindContextStorage<R>> Default for UnwindContext<R, A> {
}
}

#[cfg(feature = "read")]
impl<R: Reader> UnwindContext<R> {
/// Construct a new call frame unwinding context.
pub fn new() -> Self {
Expand Down Expand Up @@ -2036,7 +2046,13 @@ impl<R: Reader, A: UnwindContextStorage<R>> UnwindContext<R, A> {
/// > recording just the differences starting at the beginning address of each
/// > subroutine in the program.
#[derive(Debug)]
pub struct UnwindTable<'a, 'ctx, R: Reader, A: UnwindContextStorage<R> = StoreOnHeap> {
pub struct UnwindTable<
'a,
'ctx,
R: Reader,
#[cfg(not(feature = "read"))] A: UnwindContextStorage<R>,
#[cfg(feature = "read")] A: UnwindContextStorage<R> = StoreOnHeap,
> {
code_alignment_factor: Wrapping<u64>,
data_alignment_factor: Wrapping<i64>,
next_start_address: u64,
Expand Down Expand Up @@ -2347,7 +2363,11 @@ impl<'a, 'ctx, R: Reader, A: UnwindContextStorage<R>> UnwindTable<'a, 'ctx, R, A
// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-aarch64/dwarf-config.h#L32
// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-arm/dwarf-config.h#L31
// - https://github.com/libunwind/libunwind/blob/11fd461095ea98f4b3e3a361f5a8a558519363fa/include/tdep-mips/dwarf-config.h#L31
struct RegisterRuleMap<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> {
struct RegisterRuleMap<
R: Reader,
#[cfg(not(feature = "read"))] S: UnwindContextStorage<R>,
#[cfg(feature = "read")] S: UnwindContextStorage<R> = StoreOnHeap,
> {
rules: ArrayVec<S::Rules>,
}

Expand Down Expand Up @@ -2490,7 +2510,11 @@ impl<'iter, R: Reader> Iterator for RegisterRuleIter<'iter, R> {
/// A row in the virtual unwind table that describes how to find the values of
/// the registers in the *previous* frame for a range of PC addresses.
#[derive(PartialEq, Eq)]
pub struct UnwindTableRow<R: Reader, S: UnwindContextStorage<R> = StoreOnHeap> {
pub struct UnwindTableRow<
R: Reader,
#[cfg(not(feature = "read"))] S: UnwindContextStorage<R>,
#[cfg(feature = "read")] S: UnwindContextStorage<R> = StoreOnHeap,
> {
start_address: u64,
end_address: u64,
saved_args_size: u64,
Expand Down
11 changes: 11 additions & 0 deletions src/read/endian_slice.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Working with byte slices that have an associated endianity.
#[cfg(feature = "read")]
use alloc::borrow::Cow;
#[cfg(feature = "read")]
use alloc::string::String;
use core::ops::{Deref, Index, Range, RangeFrom, RangeTo};
use core::str;
Expand Down Expand Up @@ -82,6 +84,7 @@ where

/// Converts the slice to a string, including invalid characters,
/// using `String::from_utf8_lossy`.
#[cfg(feature = "read")]
#[inline]
pub fn to_string_lossy(&self) -> Cow<'input, str> {
String::from_utf8_lossy(self.slice)
Expand Down Expand Up @@ -284,11 +287,18 @@ where
Ok(EndianSlice::new(slice, self.endian))
}

#[cfg(not(feature = "read"))]
fn cannot_implement() -> super::reader::seal_if_no_alloc::Sealed {
super::reader::seal_if_no_alloc::Sealed
}

#[cfg(feature = "read")]
#[inline]
fn to_slice(&self) -> Result<Cow<[u8]>> {
Ok(self.slice.into())
}

#[cfg(feature = "read")]
#[inline]
fn to_string(&self) -> Result<Cow<str>> {
match str::from_utf8(self.slice) {
Expand All @@ -297,6 +307,7 @@ where
}
}

#[cfg(feature = "read")]
#[inline]
fn to_string_lossy(&self) -> Result<Cow<str>> {
Ok(String::from_utf8_lossy(self.slice))
Expand Down
6 changes: 6 additions & 0 deletions src/read/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ pub use self::addr::*;
mod cfi;
pub use self::cfi::*;

#[cfg(feature = "read")]
mod dwarf;
#[cfg(feature = "read")]
pub use self::dwarf::*;

mod endian_slice;
Expand All @@ -200,7 +202,9 @@ pub use self::endian_reader::*;
mod reader;
pub use self::reader::*;

#[cfg(feature = "read")]
mod abbrev;
#[cfg(feature = "read")]
pub use self::abbrev::*;

mod aranges;
Expand All @@ -209,7 +213,9 @@ pub use self::aranges::*;
mod index;
pub use self::index::*;

#[cfg(feature = "read")]
mod line;
#[cfg(feature = "read")]
pub use self::line::*;

mod lists;
Expand Down
48 changes: 29 additions & 19 deletions src/read/op.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
//! Functions for parsing and evaluating DWARF expressions.
#[cfg(feature = "read")]
use alloc::vec::Vec;
use core::mem;

use super::util::{ArrayLike, ArrayVec};
use crate::common::{DebugAddrIndex, DebugInfoOffset, Encoding, Register};
use crate::constants;
use crate::read::{Error, Reader, ReaderOffset, Result, StoreOnHeap, UnitOffset, Value, ValueType};
#[cfg(feature = "read")]
use crate::read::StoreOnHeap;
use crate::read::{Error, Reader, ReaderOffset, Result, UnitOffset, Value, ValueType};

/// A reference to a DIE, either relative to the current CU or
/// relative to the section.
Expand Down Expand Up @@ -938,6 +941,7 @@ impl<R: Reader> Expression<R> {
/// let mut eval = expression.evaluation(unit.encoding());
/// let mut result = eval.evaluate().unwrap();
/// ```
#[cfg(feature = "read")]
#[inline]
pub fn evaluation(self, encoding: Encoding) -> Evaluation<R> {
Evaluation::new(self.0, encoding)
Expand Down Expand Up @@ -982,8 +986,10 @@ impl<R: Reader> OperationIter<R> {

/// Specification of what storage should be used for [`Evaluation`].
///
/// Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results
/// on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`].
#[cfg_attr(feature = "read", doc = "
Normally you would only need to use [`StoreOnHeap`], which places the stacks and the results
on the heap using [`Vec`]. This is the default storage type parameter for [`Evaluation`].
")]
///
/// If you need to avoid [`Evaluation`] from allocating memory, e.g. for signal safety,
/// you can provide you own storage specification:
Expand Down Expand Up @@ -1030,6 +1036,7 @@ pub trait EvaluationStorage<R: Reader> {
type Result: ArrayLike<Item = Piece<R>>;
}

#[cfg(feature = "read")]
impl<R: Reader> EvaluationStorage<R> for StoreOnHeap {
type Stack = Vec<Value>;
type ExpressionStack = Vec<(R, R)>;
Expand Down Expand Up @@ -1082,7 +1089,11 @@ impl<R: Reader> EvaluationStorage<R> for StoreOnHeap {
/// println!("{:?}", result);
/// ```
#[derive(Debug)]
pub struct Evaluation<R: Reader, S: EvaluationStorage<R> = StoreOnHeap> {
pub struct Evaluation<
R: Reader,
#[cfg(not(feature = "read"))] S: EvaluationStorage<R>,
#[cfg(feature = "read")] S: EvaluationStorage<R> = StoreOnHeap,
> {
bytecode: R,
encoding: Encoding,
object_address: Option<u64>,
Expand All @@ -1108,6 +1119,7 @@ pub struct Evaluation<R: Reader, S: EvaluationStorage<R> = StoreOnHeap> {
result: ArrayVec<S::Result>,
}

#[cfg(feature = "read")]
impl<R: Reader> Evaluation<R> {
/// Create a new DWARF expression evaluator.
///
Expand All @@ -1116,6 +1128,19 @@ impl<R: Reader> Evaluation<R> {
pub fn new(bytecode: R, encoding: Encoding) -> Self {
Self::new_in(bytecode, encoding)
}

/// Get the result of this `Evaluation`.
///
/// # Panics
/// Panics if this `Evaluation` has not been driven to completion.
pub fn result(self) -> Vec<Piece<R>> {
match self.state {
EvaluationState::Complete => self.result.into_vec(),
_ => {
panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed")
}
}
}
}

impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> {
Expand Down Expand Up @@ -1956,21 +1981,6 @@ impl<R: Reader, S: EvaluationStorage<R>> Evaluation<R, S> {
}
}

impl<R: Reader> Evaluation<R, StoreOnHeap> {
/// Get the result of this `Evaluation`.
///
/// # Panics
/// Panics if this `Evaluation` has not been driven to completion.
pub fn result(self) -> Vec<Piece<R>> {
match self.state {
EvaluationState::Complete => self.result.into_vec(),
_ => {
panic!("Called `Evaluation::result` on an `Evaluation` that has not been completed")
}
}
}
}

#[cfg(test)]
// Tests require leb128::write.
#[cfg(feature = "write")]
Expand Down
Loading

0 comments on commit 425896b

Please sign in to comment.