Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update .debug_line read/write for DWARF 5 #366

Merged
merged 9 commits into from
Jan 29, 2019
97 changes: 73 additions & 24 deletions examples/dwarfdump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ where
let debug_addr = load_section(&arena, file, endian);
let debug_info = load_section(&arena, file, endian);
let debug_line = load_section(&arena, file, endian);
let debug_line_str = load_section(&arena, file, endian);
let debug_str = load_section(&arena, file, endian);
let debug_str_offsets = load_section(&arena, file, endian);
let debug_types = load_section(&arena, file, endian);
Expand All @@ -548,6 +549,7 @@ where
debug_addr,
debug_info,
debug_line,
debug_line_str,
debug_str,
debug_str_offsets,
debug_str_sup: no_reader.clone().into(),
Expand Down Expand Up @@ -975,8 +977,8 @@ struct Unit<R: Reader> {
encoding: gimli::Encoding,
base_address: u64,
line_program: Option<gimli::IncompleteLineProgram<R>>,
comp_dir: Option<R>,
comp_name: Option<R>,
comp_dir: Option<gimli::AttributeValue<R>>,
comp_name: Option<gimli::AttributeValue<R>>,
str_offsets_base: gimli::DebugStrOffsetsBase,
addr_base: gimli::DebugAddrBase,
loclists_base: gimli::DebugLocListsBase,
Expand Down Expand Up @@ -1046,12 +1048,8 @@ fn dump_entries<R: Reader, W: Write>(
Some(gimli::AttributeValue::Addr(address)) => address,
_ => 0,
};
unit.comp_dir = entry
.attr(gimli::DW_AT_comp_dir)?
.and_then(|attr| dwarf.attr_string(&attr));
unit.comp_name = entry
.attr(gimli::DW_AT_name)?
.and_then(|attr| dwarf.attr_string(&attr));
unit.comp_dir = entry.attr_value(gimli::DW_AT_comp_dir)?;
unit.comp_name = entry.attr_value(gimli::DW_AT_name)?;
unit.line_program = match entry.attr_value(gimli::DW_AT_stmt_list)? {
Some(gimli::AttributeValue::DebugLineRef(offset)) => dwarf
.debug_line
Expand Down Expand Up @@ -1281,6 +1279,13 @@ fn dump_attr_value<R: Reader, W: Write>(
writeln!(w, "<.debug_str+0x{:08x}>", offset.0)?;
}
}
gimli::AttributeValue::DebugLineStrRef(offset) => {
if let Ok(s) = dwarf.debug_line_str.get_str(offset) {
writeln!(w, "{}", s.to_string_lossy()?)?;
} else {
writeln!(w, "<.debug_line_str=0x{:08x}>", offset.0)?;
}
}
gimli::AttributeValue::String(s) => {
writeln!(w, "{}", s.to_string_lossy()?)?;
}
Expand Down Expand Up @@ -1322,7 +1327,7 @@ fn dump_attr_value<R: Reader, W: Write>(
}
gimli::AttributeValue::FileIndex(value) => {
write!(w, "0x{:08x}", value)?;
dump_file_index(w, value, unit)?;
dump_file_index(w, value, unit, dwarf)?;
writeln!(w)?;
}
}
Expand All @@ -1345,7 +1350,12 @@ fn dump_type_signature<Endian: gimli::Endianity, W: Write>(
Ok(())
}

fn dump_file_index<R: Reader, W: Write>(w: &mut W, file: u64, unit: &Unit<R>) -> Result<()> {
fn dump_file_index<R: Reader, W: Write>(
w: &mut W,
file: u64,
unit: &Unit<R>,
dwarf: &gimli::Dwarf<R, R::Endian>,
) -> Result<()> {
if file == 0 {
return Ok(());
}
Expand All @@ -1362,15 +1372,24 @@ fn dump_file_index<R: Reader, W: Write>(w: &mut W, file: u64, unit: &Unit<R>) ->
};
write!(w, " ")?;
if let Some(directory) = file.directory(header) {
let directory = dwarf.attr_string(directory)?;
let directory = directory.to_string_lossy()?;
if !directory.starts_with('/') {
if let Some(ref comp_dir) = unit.comp_dir {
write!(w, "{}/", comp_dir.to_string_lossy()?)?;
write!(
w,
"{}/",
dwarf.attr_string(comp_dir.clone())?.to_string_lossy()?
)?;
}
}
write!(w, "{}/", directory)?;
}
write!(w, "{}", file.path_name().to_string_lossy()?)?;
write!(
w,
"{}",
dwarf.attr_string(file.path_name())?.to_string_lossy()?
)?;
Ok(())
}

Expand Down Expand Up @@ -1886,6 +1905,11 @@ fn dump_line_program<R: Reader, W: Write>(
"DWARF version: {}",
header.version()
)?;
writeln!(
w,
"Address size: {}",
header.address_size()
)?;
writeln!(
w,
"Prologue length: {}",
Expand Down Expand Up @@ -1930,27 +1954,48 @@ fn dump_line_program<R: Reader, W: Write>(
.iter()
.enumerate()
{
writeln!(w, " Opcode {} as {} args", i + 1, length)?;
writeln!(w, " Opcode {} has {} args", i + 1, length)?;
}

let base = if header.version() >= 5 { 0 } else { 1 };
writeln!(w)?;
writeln!(w, "The Directory Table:")?;
for (i, dir) in header.include_directories().iter().enumerate() {
writeln!(w, " {} {}", i + 1, dir.to_string_lossy()?)?;
writeln!(
w,
" {} {}",
base + i,
dwarf.attr_string(dir.clone())?.to_string_lossy()?
)?;
}

writeln!(w)?;
writeln!(w, "The File Name Table")?;
writeln!(w, " Entry\tDir\tTime\tSize\tName")?;
write!(w, " Entry\tDir\tTime\tSize")?;
if header.file_has_md5() {
write!(w, "\tMD5\t\t\t\t")?;
}
writeln!(w, "\tName")?;
for (i, file) in header.file_names().iter().enumerate() {
writeln!(
write!(
w,
" {}\t{}\t{}\t{}\t{}",
i + 1,
" {}\t{}\t{}\t{}",
base + i,
file.directory_index(),
file.last_modification(),
file.length(),
file.path_name().to_string_lossy()?
file.timestamp(),
file.size(),
)?;
if header.file_has_md5() {
let md5 = file.md5();
write!(w, "\t")?;
for i in 0..16 {
write!(w, "{:02X}", md5[i])?;
}
}
writeln!(
w,
"\t{}",
dwarf.attr_string(file.path_name())?.to_string_lossy()?
)?;
}

Expand Down Expand Up @@ -2002,11 +2047,15 @@ fn dump_line_program<R: Reader, W: Write>(
write!(
w,
" uri: \"{}/{}\"",
directory.to_string_lossy()?,
file.path_name().to_string_lossy()?
dwarf.attr_string(directory)?.to_string_lossy()?,
dwarf.attr_string(file.path_name())?.to_string_lossy()?
)?;
} else {
write!(w, " uri: \"{}\"", file.path_name().to_string_lossy()?)?;
write!(
w,
" uri: \"{}\"",
dwarf.attr_string(file.path_name())?.to_string_lossy()?
)?;
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ pub struct DebugInfoOffset<T = usize>(pub T);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugLineOffset<T = usize>(pub T);

/// An offset into the `.debug_line_str` section.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugLineStrOffset<T = usize>(pub T);

/// An offset into either the `.debug_loc` section or the `.debug_loclists` section,
/// depending on the version of the unit the offset was contained in.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down
2 changes: 1 addition & 1 deletion src/read/cfi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl<'a, R: Reader + 'a> EhHdrTable<'a, R> {
pub fn lookup(&self, address: u64, bases: &BaseAddresses) -> Result<Pointer> {
let size = match self.hdr.table_enc.format() {
constants::DW_EH_PE_uleb128 | constants::DW_EH_PE_sleb128 => {
return Err(Error::VariableLengthSearchTable)
return Err(Error::VariableLengthSearchTable);
}
constants::DW_EH_PE_sdata2 | constants::DW_EH_PE_udata2 => 2,
constants::DW_EH_PE_sdata4 | constants::DW_EH_PE_udata4 => 4,
Expand Down
47 changes: 27 additions & 20 deletions src/read/dwarf.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use constants;
use read::{
Abbreviations, Attribute, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter,
DebugAbbrev, DebugAddr, DebugInfo, DebugLine, DebugStr, DebugStrOffsets, DebugTypes, Error,
Abbreviations, AttributeValue, CompilationUnitHeader, CompilationUnitHeadersIter, DebugAbbrev,
DebugAddr, DebugInfo, DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, Error,
IncompleteLineProgram, LocationLists, RangeLists, Reader, Result, TypeUnitHeader,
TypeUnitHeadersIter,
};
Expand Down Expand Up @@ -30,6 +30,9 @@ where
/// The `.debug_line` section.
pub debug_line: DebugLine<R>,

/// The `.debug_line_str` section.
pub debug_line_str: DebugLineStr<R>,

/// The `.debug_str` section.
pub debug_str: DebugStr<R>,

Expand Down Expand Up @@ -104,30 +107,34 @@ where
Some(_) => return Err(Error::UnsupportedAttributeForm),
None => return Ok(None),
};
let comp_dir = root
.attr(constants::DW_AT_comp_dir)?
.and_then(|attr| self.attr_string(&attr));
let comp_name = root
.attr(constants::DW_AT_name)?
.and_then(|attr| self.attr_string(&attr));
let comp_dir = root.attr_value(constants::DW_AT_comp_dir)?;
let comp_name = root.attr_value(constants::DW_AT_name)?;
self.debug_line
.program(offset, unit.address_size(), comp_dir, comp_name)
.map(Option::Some)
}

/// Try to return an attribute's value as a string slice.
/// Try to return an attribute value as a string slice.
///
/// If the attribute value is one of:
///
/// - an inline `DW_FORM_string` string
/// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section
/// - a `DW_FORM_strp_sup` reference to an offset into a supplementary
/// object file
/// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str`
/// section
///
/// If the attribute's value is either an inline `DW_FORM_string` string,
/// or a `DW_FORM_strp` reference to an offset into the `.debug_str`
/// section, or a `DW_FORM_strp_sup` reference to an offset into a supplementary
/// object file, return the attribute's string value as `Some`. Other attribute
/// value forms are returned as `None`.
pub fn attr_string(&self, attr: &Attribute<R>) -> Option<R> {
match attr.value() {
AttributeValue::String(ref string) => Some(string.clone()),
AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset).ok(),
AttributeValue::DebugStrRefSup(offset) => self.debug_str_sup.get_str(offset).ok(),
_ => None,
/// then return the attribute's string value. Returns an error if the attribute
/// value does not have a string form, or if a string form has an invalid value.
// TODO: handle `DW_FORM_strx`, but that requires knowing the DebugStrOffsetsBase
pub fn attr_string(&self, attr: AttributeValue<R, R::Offset>) -> Result<R> {
match attr {
AttributeValue::String(string) => Ok(string),
AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset),
AttributeValue::DebugStrRefSup(offset) => self.debug_str_sup.get_str(offset),
AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset),
_ => Err(Error::ExpectedStringAttributeValue),
}
}
}
Expand Down
Loading