#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
extern crate fallible_iterator;
extern crate gimli;
extern crate object;
use fallible_iterator::FallibleIterator;
use gimli::{CompilationUnitHeadersIter, DebugAbbrev, DebugInfo, DebugStr, EndianBuf, NativeEndian,
Reader};
use std::error;
use std::fmt;
use std::fs;
use std::io::{self, Read};
use std::path;
#[derive(Debug)]
pub enum Error {
Msg(String),
Io(io::Error),
Dwarf(gimli::Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Msg(ref s) => write!(f, "{}", s),
Error::Io(ref e) => write!(f, "{}", e),
Error::Dwarf(ref e) => write!(f, "{}", e),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::Msg(ref s) => s.as_str(),
Error::Io(ref e) => e.description(),
Error::Dwarf(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Msg(_) => None,
Error::Io(ref e) => Some(e),
Error::Dwarf(ref e) => Some(e),
}
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::Io(e)
}
}
impl From<gimli::Error> for Error {
fn from(e: gimli::Error) -> Error {
Error::Dwarf(e)
}
}
impl From<String> for Error {
fn from(s: String) -> Error {
Error::Msg(s)
}
}
impl<'a> From<&'a str> for Error {
fn from(s: &'a str) -> Error {
s.to_string().into()
}
}
pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Default, Debug)]
pub struct Options {
file: path::PathBuf,
}
impl Options {
pub fn new<P: AsRef<path::Path>>(path: P) -> Options {
Options {
file: path.as_ref().into(),
}
}
pub fn producers<F, T>(self, mut f: F) -> Result<T>
where
F: FnMut(&mut Producers) -> T,
{
let mut contents = vec![];
{
let mut file = fs::File::open(self.file)?;
file.read_to_end(&mut contents)?;
}
let file = object::File::parse(&contents[..])?;
let debug_info = file.get_section(".debug_info")
.ok_or_else(|| Error::from("missing .debug_info section"))?;
let debug_info = DebugInfo::new(debug_info, gimli::NativeEndian);
let debug_abbrev = file.get_section(".debug_abbrev")
.ok_or_else(|| Error::from("missing .debug_abbrev section"))?;
let debug_abbrev = DebugAbbrev::new(debug_abbrev, gimli::NativeEndian);
let debug_str = file.get_section(".debug_str")
.ok_or_else(|| Error::from("missing .debug_str section"))?;
let debug_str = DebugStr::new(debug_str, gimli::NativeEndian);
let headers = debug_info.units();
let mut producers = Producers {
debug_str,
debug_abbrev,
headers,
};
Ok(f(&mut producers))
}
}
#[derive(Debug)]
pub struct Producers<'a> {
debug_str: DebugStr<EndianBuf<'a, NativeEndian>>,
debug_abbrev: DebugAbbrev<EndianBuf<'a, NativeEndian>>,
headers: CompilationUnitHeadersIter<EndianBuf<'a, NativeEndian>>,
}
impl<'a> Producers<'a> {
pub fn next(&mut self) -> Result<Option<String>> {
loop {
let unit_header = match self.headers.next()? {
None => return Ok(None),
Some(h) => h,
};
let abbrevs = unit_header.abbreviations(&self.debug_abbrev)?;
let mut tree = unit_header.entries_tree(&abbrevs, None)?;
let root = tree.root()?;
let mut attrs = root.entry().attrs();
while let Some(attr) = attrs.next()? {
if let gimli::DW_AT_producer = attr.name() {
match attr.value() {
gimli::AttributeValue::DebugStrRef(offset) => {
return Ok(Some(self.debug_str.get_str(offset)?.to_string()?.into()));
}
gimli::AttributeValue::Block(data) => {
return Ok(Some(data.to_string()?.into()));
}
_ => continue,
}
}
}
}
}
}
impl<'a> FallibleIterator for Producers<'a> {
type Error = Error;
type Item = String;
fn next(&mut self) -> Result<Option<Self::Item>> {
Producers::next(self)
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}