Skip to content

Commit

Permalink
Default the str_offsets_base, loclists_base, and rnglists_base attrib…
Browse files Browse the repository at this point in the history
…utes to just after the section header in DWARF 5 .dwos.

Of the four sections with corresponding base attributes (.debug_addr, .debug_str_offsets, .debug_loclists, and .debug_rnglists), only .debug_addr must be linked into the final executable in DWARF 5. The other three sections can be left behind in a .dwo file. In this case, a compiler (e.g. clang 11) can omit the base attribute value for the sections left behind in the .dwo because, since there is only one split CU represented in the .dwo, there is no ambiguity. However, gimli relies on these offsets to skip past the DWARF 5 section headers, so we need to change the default values here to point beyond the section header.

Note that the DW_AT_str_offsets_base attribute value may be present on the corresponding skeleton unit in the main DWARF file. This is controlling *only* for string attributes on that single DIE (for e.g. its DW_AT_comp_dir attribute). The only base value present on the skeleton unit in DWARF 5 that affects the split unit in the .dwo file is the DW_AT_addr_base value.
  • Loading branch information
khuey committed Jul 14, 2020
1 parent 3398bea commit cadf377
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 28 deletions.
17 changes: 17 additions & 0 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,3 +323,20 @@ impl SectionId {
/// split DWARF and linking a split compilation unit back together.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DwoId(pub u64);

/// The "type" of file with DWARF debugging information. This determines, among other things,
/// which files DWARF sections should be loaded from.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DwarfFileType {
/// A normal executable or object file.
Main,
/// A .dwo split DWARF file.
Dwo,
// TODO: Supplementary files, .dwps?
}

impl Default for DwarfFileType {
fn default() -> Self {
DwarfFileType::Main
}
}
40 changes: 16 additions & 24 deletions src/read/dwarf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use alloc::string::String;
use crate::common::{
DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase,
DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
DebugStrOffsetsIndex, DebugTypesOffset, Encoding, LocationListsOffset, RangeListsOffset,
SectionId, UnitSectionOffset,
DebugStrOffsetsIndex, DebugTypesOffset, DwarfFileType, Encoding, LocationListsOffset,
RangeListsOffset, SectionId, UnitSectionOffset,
};
use crate::constants;
use crate::read::{
Expand All @@ -15,23 +15,6 @@ use crate::read::{
ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset,
};

/// The "type" of file with DWARF debugging information. This determines, among other things,
/// which files DWARF sections should be loaded from.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DwarfFileType {
/// A normal executable or object file.
Main,
/// A .dwo split DWARF file.
Dwo,
// TODO: Supplementary files, .dwps?
}

impl Default for DwarfFileType {
fn default() -> Self {
DwarfFileType::Main
}
}

/// All of the commonly used DWARF sections, and other common information.
#[derive(Debug, Default)]
pub struct Dwarf<R> {
Expand Down Expand Up @@ -541,17 +524,26 @@ impl<R: Reader> Unit<R> {
pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> {
let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?;
let mut unit = Unit {
header,
abbreviations,
name: None,
comp_dir: None,
low_pc: 0,
// Defaults to 0 for GNU extensions.
str_offsets_base: DebugStrOffsetsBase(R::Offset::from_u8(0)),
str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file(
header.encoding(),
dwarf.file_type,
),
// NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided.
addr_base: DebugAddrBase(R::Offset::from_u8(0)),
loclists_base: DebugLocListsBase(R::Offset::from_u8(0)),
rnglists_base: DebugRngListsBase(R::Offset::from_u8(0)),
loclists_base: DebugLocListsBase::default_for_encoding_and_file(
header.encoding(),
dwarf.file_type,
),
rnglists_base: DebugRngListsBase::default_for_encoding_and_file(
header.encoding(),
dwarf.file_type,
),
line_program: None,
header,
};
let mut name = None;
let mut comp_dir = None;
Expand Down
24 changes: 22 additions & 2 deletions src/read/loclists.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::common::{
DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, Encoding,
DebugAddrBase, DebugAddrIndex, DebugLocListsBase, DebugLocListsIndex, DwarfFileType, Encoding,
LocationListsOffset, SectionId,
};
use crate::constants;
Expand Down Expand Up @@ -100,9 +100,29 @@ impl<R> From<R> for DebugLocLists<R> {
}
}

#[allow(unused)]
pub(crate) type LocListsHeader = ListsHeader;

impl<Offset> DebugLocListsBase<Offset>
where
Offset: ReaderOffset,
{
/// Returns a `DebugLocListsBase` with the default value of DW_AT_loclists_base
/// for the given `Encoding` and `DwarfFileType`.
pub fn default_for_encoding_and_file(
encoding: Encoding,
file_type: DwarfFileType,
) -> DebugLocListsBase<Offset> {
if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
// In .dwo files, the compiler omits the DW_AT_loclists_base attribute (because there is
// only a single unit in the file) but we must skip past the header, which the attribute
// would normally do for us.
DebugLocListsBase(Offset::from_u8(LocListsHeader::size_for_encoding(encoding)))
} else {
DebugLocListsBase(Offset::from_u8(0))
}
}
}

/// The DWARF data found in `.debug_loc` and `.debug_loclists` sections.
#[derive(Debug, Default, Clone, Copy)]
pub struct LocationLists<R> {
Expand Down
23 changes: 22 additions & 1 deletion src/read/rnglists.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::common::{
DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, Encoding,
DebugAddrBase, DebugAddrIndex, DebugRngListsBase, DebugRngListsIndex, DwarfFileType, Encoding,
RangeListsOffset, SectionId,
};
use crate::constants;
Expand Down Expand Up @@ -104,6 +104,27 @@ impl<R> From<R> for DebugRngLists<R> {
#[allow(unused)]
pub(crate) type RngListsHeader = ListsHeader;

impl<Offset> DebugRngListsBase<Offset>
where
Offset: ReaderOffset,
{
/// Returns a `DebugRngListsBase` with the default value of DW_AT_rnglists_base
/// for the given `Encoding` and `DwarfFileType`.
pub fn default_for_encoding_and_file(
encoding: Encoding,
file_type: DwarfFileType,
) -> DebugRngListsBase<Offset> {
if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
// In .dwo files, the compiler omits the DW_AT_rnglists_base attribute (because there is
// only a single unit in the file) but we must skip past the header, which the attribute
// would normally do for us.
DebugRngListsBase(Offset::from_u8(RngListsHeader::size_for_encoding(encoding)))
} else {
DebugRngListsBase(Offset::from_u8(0))
}
}
}

/// The DWARF data found in `.debug_ranges` and `.debug_rnglists` sections.
#[derive(Debug, Default, Clone, Copy)]
pub struct RangeLists<R> {
Expand Down
27 changes: 26 additions & 1 deletion src/read/str.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::common::{
DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, SectionId,
DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsBase, DebugStrOffsetsIndex, DwarfFileType,
Encoding, SectionId,
};
use crate::endianity::Endianity;
use crate::read::{EndianSlice, Reader, ReaderOffset, Result, Section};
Expand Down Expand Up @@ -173,6 +174,30 @@ impl<R> From<R> for DebugStrOffsets<R> {
}
}

impl<Offset> DebugStrOffsetsBase<Offset>
where
Offset: ReaderOffset,
{
/// Returns a `DebugStrOffsetsBase` with the default value of DW_AT_str_offsets_base
/// for the given `Encoding` and `DwarfFileType`.
pub fn default_for_encoding_and_file(
encoding: Encoding,
file_type: DwarfFileType,
) -> DebugStrOffsetsBase<Offset> {
if encoding.version >= 5 && file_type == DwarfFileType::Dwo {
// In .dwo files, the compiler omits the DW_AT_str_offsets_base attribute (because there is
// only a single unit in the file) but we must skip past the header, which the attribute
// would normally do for us.
// initial_length_size + version + 2 bytes of padding.
DebugStrOffsetsBase(Offset::from_u8(
encoding.format.initial_length_size() + 2 + 2,
))
} else {
DebugStrOffsetsBase(Offset::from_u8(0))
}
}
}

/// The `DebugLineStr` struct represents the DWARF strings
/// found in the `.debug_line_str` section.
#[derive(Debug, Default, Clone, Copy)]
Expand Down

0 comments on commit cadf377

Please sign in to comment.