1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
use core::marker::PhantomData;
use crate::common::{DebugInfoOffset, Format};
use crate::read::{parse_debug_info_offset, Error, Reader, ReaderOffset, Result, UnitOffset};
// The various "Accelerated Access" sections (DWARF standard v4 Section 6.1) all have
// similar structures. They consist of a header with metadata and an offset into the
// .debug_info section for the entire compilation unit, and a series
// of following entries that list addresses (for .debug_aranges) or names
// (for .debug_pubnames and .debug_pubtypes) that are covered.
//
// Because these three tables all have similar structures, we abstract out some of
// the parsing mechanics.
pub trait LookupParser<R: Reader> {
/// The type of the produced header.
type Header;
/// The type of the produced entry.
type Entry;
/// Parse a header from `input`. Returns a tuple of `input` sliced to contain just the entries
/// corresponding to this header (without the header itself), and the parsed representation of
/// the header itself.
fn parse_header(input: &mut R) -> Result<(R, Self::Header)>;
/// Parse a single entry from `input`. Returns either a parsed representation of the entry
/// or None if `input` is exhausted.
fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>>;
}
#[derive(Clone, Debug)]
pub struct DebugLookup<R, Parser>
where
R: Reader,
Parser: LookupParser<R>,
{
input_buffer: R,
phantom: PhantomData<Parser>,
}
impl<R, Parser> From<R> for DebugLookup<R, Parser>
where
R: Reader,
Parser: LookupParser<R>,
{
fn from(input_buffer: R) -> Self {
DebugLookup {
input_buffer,
phantom: PhantomData,
}
}
}
impl<R, Parser> DebugLookup<R, Parser>
where
R: Reader,
Parser: LookupParser<R>,
{
pub fn items(&self) -> LookupEntryIter<R, Parser> {
LookupEntryIter {
current_set: None,
remaining_input: self.input_buffer.clone(),
}
}
pub fn reader(&self) -> &R {
&self.input_buffer
}
}
#[derive(Clone, Debug)]
pub struct LookupEntryIter<R, Parser>
where
R: Reader,
Parser: LookupParser<R>,
{
current_set: Option<(R, Parser::Header)>, // Only none at the very beginning and end.
remaining_input: R,
}
impl<R, Parser> LookupEntryIter<R, Parser>
where
R: Reader,
Parser: LookupParser<R>,
{
/// Advance the iterator and return the next entry.
///
/// Returns the newly parsed entry as `Ok(Some(Parser::Entry))`. Returns
/// `Ok(None)` when iteration is complete and all entries have already been
/// parsed and yielded. If an error occurs while parsing the next entry,
/// then this error is returned as `Err(e)`, and all subsequent calls return
/// `Ok(None)`.
///
/// Can be [used with `FallibleIterator`](./index.html#using-with-fallibleiterator).
pub fn next(&mut self) -> Result<Option<Parser::Entry>> {
loop {
if let Some((ref mut input, ref header)) = self.current_set {
if !input.is_empty() {
match Parser::parse_entry(input, header) {
Ok(Some(entry)) => return Ok(Some(entry)),
Ok(None) => {}
Err(e) => {
input.empty();
self.remaining_input.empty();
return Err(e);
}
}
}
}
if self.remaining_input.is_empty() {
self.current_set = None;
return Ok(None);
}
match Parser::parse_header(&mut self.remaining_input) {
Ok(set) => {
self.current_set = Some(set);
}
Err(e) => {
self.current_set = None;
self.remaining_input.empty();
return Err(e);
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PubStuffHeader<T = usize> {
format: Format,
length: T,
version: u16,
unit_offset: DebugInfoOffset<T>,
unit_length: T,
}
pub trait PubStuffEntry<R: Reader> {
fn new(
die_offset: UnitOffset<R::Offset>,
name: R,
unit_header_offset: DebugInfoOffset<R::Offset>,
) -> Self;
}
#[derive(Clone, Debug)]
pub struct PubStuffParser<R, Entry>
where
R: Reader,
Entry: PubStuffEntry<R>,
{
// This struct is never instantiated.
phantom: PhantomData<(R, Entry)>,
}
impl<R, Entry> LookupParser<R> for PubStuffParser<R, Entry>
where
R: Reader,
Entry: PubStuffEntry<R>,
{
type Header = PubStuffHeader<R::Offset>;
type Entry = Entry;
/// Parse an pubthings set header. Returns a tuple of the
/// pubthings to be parsed for this set, and the newly created PubThingHeader struct.
fn parse_header(input: &mut R) -> Result<(R, Self::Header)> {
let (length, format) = input.read_initial_length()?;
let mut rest = input.split(length)?;
let version = rest.read_u16()?;
if version != 2 {
return Err(Error::UnknownVersion(u64::from(version)));
}
let unit_offset = parse_debug_info_offset(&mut rest, format)?;
let unit_length = rest.read_length(format)?;
let header = PubStuffHeader {
format,
length,
version,
unit_offset,
unit_length,
};
Ok((rest, header))
}
/// Parse a single pubthing. Return `None` for the null pubthing, `Some` for an actual pubthing.
fn parse_entry(input: &mut R, header: &Self::Header) -> Result<Option<Self::Entry>> {
let offset = input.read_offset(header.format)?;
if offset.into_u64() == 0 {
input.empty();
Ok(None)
} else {
let name = input.read_null_terminated_slice()?;
Ok(Some(Self::Entry::new(
UnitOffset(offset),
name,
header.unit_offset,
)))
}
}
}