Skip to content

Commit 5bda6fa

Browse files
authored
Reduce the size of UnitSectionOffset (#825)
Change `UnitSectionOffset` from an enum to a simple newtype, and store a `SectionId` in `read::UnitHeader` instead. `UnitSectionOffset` is intended for code that may be handling either `.debug_info` or `.debug_types`. However, you will usually have a `UnitHeader` you can use to determine the section type. This significantly reduces the memory usage in the conversion code, where we need to store an offset for every entry in the section. This required some changes to the `UnitSectionOffset` methods. To make things more consistent, I also changed these methods to use `UnitHeader` instead of `Unit`, and added a `Deref` impl to `Unit`.
1 parent 8654b25 commit 5bda6fa

File tree

12 files changed

+305
-282
lines changed

12 files changed

+305
-282
lines changed

crates/examples/src/bin/convert.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -218,13 +218,9 @@ fn convert_attributes<R: gimli::Reader<Offset = usize>>(
218218
Ok(value) => unit.unit.get_mut(id).set(attr.name(), value),
219219
Err(e) => {
220220
// Invalid input DWARF has most often been seen for expressions.
221-
let unit_offset = match unit.from_unit.header.offset() {
222-
gimli::UnitSectionOffset::DebugInfoOffset(o) => o.0,
223-
gimli::UnitSectionOffset::DebugTypesOffset(o) => o.0,
224-
};
225221
eprintln!(
226222
"Warning: failed to convert attribute for DIE {:x}: {} = {:?}: {}",
227-
unit_offset + entry.offset.0,
223+
unit.from_unit.offset().0 + entry.offset.0,
228224
attr.name(),
229225
attr.raw_value(),
230226
e

crates/examples/src/bin/dwarf-validate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,11 @@ fn validate_info<W, R>(
156156
Ok(None) => break,
157157
Ok(Some(u)) => u,
158158
};
159-
last_offset = u.offset().as_debug_info_offset().unwrap().0 + u.length_including_self();
159+
last_offset = u.offset().0 + u.length_including_self();
160160
units.push(u);
161161
}
162162
let process_unit = |unit: UnitHeader<R>| -> UnitSummary {
163-
let unit_offset = unit.offset().as_debug_info_offset().unwrap();
163+
let unit_offset = unit.offset().to_debug_info_offset(&unit).unwrap();
164164
let mut ret = UnitSummary {
165165
internally_valid: false,
166166
offset: unit_offset,

crates/examples/src/bin/dwarfdump.rs

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![allow(clippy::needless_lifetimes)]
55

66
use fallible_iterator::FallibleIterator;
7-
use gimli::{Section, UnitHeader, UnitOffset, UnitSectionOffset, UnitType, UnwindSection};
7+
use gimli::{Section, UnitHeader, UnitOffset, UnitType, UnwindSection};
88
use object::{Object, ObjectSection};
99
use regex::bytes::Regex;
1010
use std::borrow::Cow;
@@ -1033,13 +1033,12 @@ where
10331033
}
10341034
};
10351035
let process_unit = |header: UnitHeader<R>, buf: &mut Vec<u8>| -> Result<()> {
1036-
let output_unit = dump_unit(buf, header, dwarf, dwo_parent_units, flags)?;
1037-
if !output_unit
1038-
|| !flags
1039-
.match_units
1040-
.as_ref()
1041-
.map(|r| r.is_match(buf))
1042-
.unwrap_or(true)
1036+
dump_unit(buf, header, dwarf, dwo_parent_units, flags)?;
1037+
if !flags
1038+
.match_units
1039+
.as_ref()
1040+
.map(|r| r.is_match(buf))
1041+
.unwrap_or(true)
10431042
{
10441043
buf.clear();
10451044
}
@@ -1071,32 +1070,28 @@ fn dump_unit<R: Reader, W: Write>(
10711070
dwarf: &gimli::Dwarf<R>,
10721071
dwo_parent_units: Option<&HashMap<gimli::DwoId, gimli::Unit<R>>>,
10731072
flags: &Flags,
1074-
) -> Result<bool> {
1075-
write!(w, "\nUNIT<")?;
1076-
let offset = match header.offset() {
1077-
UnitSectionOffset::DebugInfoOffset(o) => {
1078-
write!(w, ".debug_info+0x{:08x}", o.0)?;
1079-
if let Some(offset) = flags.info_offset {
1080-
if offset == o {
1081-
// If the offset points to the very start of the unit, we
1082-
// can process everything from here on normally.
1083-
None
1084-
} else if let Some(o) = offset.to_unit_offset(&header) {
1085-
Some(o)
1086-
} else {
1087-
// Skip this unit and erase what we already wrote.
1088-
return Ok(false);
1089-
}
1090-
} else {
1073+
) -> Result<()> {
1074+
let offset = if let Some(o) = header.offset().to_debug_info_offset(&header) {
1075+
if let Some(offset) = flags.info_offset {
1076+
if offset == o {
1077+
// If the offset points to the very start of the unit, we
1078+
// can process everything from here on normally.
10911079
None
1080+
} else if let Some(o) = offset.to_unit_offset(&header) {
1081+
Some(o)
1082+
} else {
1083+
// Skip this unit.
1084+
return Ok(());
10921085
}
1093-
}
1094-
UnitSectionOffset::DebugTypesOffset(o) => {
1095-
write!(w, ".debug_types+0x{:08x}", o.0)?;
1086+
} else {
10961087
None
10971088
}
1089+
} else {
1090+
None
10981091
};
1099-
writeln!(w, ">: length = 0x{:x}, format = {:?}, version = {}, address_size = {}, abbrev_offset = 0x{:x}",
1092+
writeln!(w, "\nUNIT<{}+0x{:08x}>: length = 0x{:x}, format = {:?}, version = {}, address_size = {}, abbrev_offset = 0x{:x}",
1093+
header.section().name(),
1094+
header.offset().0,
11001095
header.unit_length(),
11011096
header.format(),
11021097
header.version(),
@@ -1129,7 +1124,7 @@ fn dump_unit<R: Reader, W: Write>(
11291124
Ok(unit) => unit,
11301125
Err(err) => {
11311126
writeln_error(w, dwarf, err.into(), "Failed to parse unit root entry")?;
1132-
return Ok(true);
1127+
return Ok(());
11331128
}
11341129
};
11351130

@@ -1146,7 +1141,7 @@ fn dump_unit<R: Reader, W: Write>(
11461141
if let Err(err) = entries_result {
11471142
writeln_error(w, dwarf, err, "Failed to dump entries")?;
11481143
}
1149-
Ok(true)
1144+
Ok(())
11501145
}
11511146

11521147
fn spaces(buf: &mut String, len: usize) -> &str {
@@ -1167,11 +1162,7 @@ fn write_offset<R: Reader, W: Write>(
11671162
) -> Result<()> {
11681163
write!(w, "<0x{:08x}", offset.0)?;
11691164
if flags.goff {
1170-
let goff = match offset.to_unit_section_offset(unit) {
1171-
UnitSectionOffset::DebugInfoOffset(o) => o.0,
1172-
UnitSectionOffset::DebugTypesOffset(o) => o.0,
1173-
};
1174-
write!(w, " GOFF=0x{:08x}", goff)?;
1165+
write!(w, " GOFF=0x{:08x}", offset.to_unit_section_offset(unit).0)?;
11751166
}
11761167
write!(w, ">")?;
11771168
Ok(())
@@ -1377,16 +1368,13 @@ fn dump_attr_value<R: Reader, W: Write>(
13771368
writeln!(w, "{:#x}", address)?;
13781369
}
13791370
gimli::AttributeValue::UnitRef(offset) => {
1380-
write!(w, "0x{:08x}", offset.0)?;
1381-
match offset.to_unit_section_offset(&unit) {
1382-
UnitSectionOffset::DebugInfoOffset(goff) => {
1383-
write!(w, "<.debug_info+0x{:08x}>", goff.0)?;
1384-
}
1385-
UnitSectionOffset::DebugTypesOffset(goff) => {
1386-
write!(w, "<.debug_types+0x{:08x}>", goff.0)?;
1387-
}
1388-
}
1389-
writeln!(w)?;
1371+
writeln!(
1372+
w,
1373+
"0x{:08x}<{}+0x{:08x}>",
1374+
offset.0,
1375+
unit.section().name(),
1376+
offset.to_unit_section_offset(&unit).0,
1377+
)?;
13901378
}
13911379
gimli::AttributeValue::DebugInfoRef(offset) => {
13921380
writeln!(w, "<.debug_info+0x{:08x}>", offset.0)?;
@@ -1975,7 +1963,7 @@ fn dump_line<R: Reader, W: Write>(w: &mut W, dwarf: &gimli::Dwarf<R>) -> Result<
19751963
writeln!(
19761964
w,
19771965
"\n.debug_line: line number info for unit at .debug_info offset 0x{:08x}",
1978-
header.offset().as_debug_info_offset().unwrap().0
1966+
header.offset().0
19791967
)?;
19801968
let unit = match dwarf.unit(header) {
19811969
Ok(unit) => unit,

crates/examples/src/bin/simple.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,7 @@ fn dump_file(
130130
// Iterate over the compilation units.
131131
let mut iter = dwarf.units();
132132
while let Some(header) = iter.next()? {
133-
println!(
134-
"Unit at <.debug_info+0x{:x}>",
135-
header.offset().as_debug_info_offset().unwrap().0
136-
);
133+
println!("Unit at <.debug_info+0x{:x}>", header.offset().0);
137134
let unit = dwarf.unit(header)?;
138135
let unit_ref = unit.unit_ref(&dwarf);
139136
dump_unit(unit_ref)?;

crates/examples/src/bin/simple_line.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn dump_file(
4747
while let Some(header) = iter.next()? {
4848
println!(
4949
"Line number info for unit at <.debug_info+0x{:x}>",
50-
header.offset().as_debug_info_offset().unwrap().0
50+
header.offset().0
5151
);
5252
let unit = dwarf.unit(header)?;
5353
let unit = unit.unit_ref(&dwarf);

src/common.rs

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -212,45 +212,11 @@ impl<T> From<T> for EhFrameOffset<T> {
212212
}
213213

214214
/// An offset into the `.debug_info` or `.debug_types` sections.
215+
///
216+
/// This type does not store which section the offset applies to. You will need to either
217+
/// determine that from the context of its use, or store a [`SectionId`] along with it.
215218
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
216-
pub enum UnitSectionOffset<T = usize> {
217-
/// An offset into the `.debug_info` section.
218-
DebugInfoOffset(DebugInfoOffset<T>),
219-
/// An offset into the `.debug_types` section.
220-
DebugTypesOffset(DebugTypesOffset<T>),
221-
}
222-
223-
impl<T> From<DebugInfoOffset<T>> for UnitSectionOffset<T> {
224-
fn from(offset: DebugInfoOffset<T>) -> Self {
225-
UnitSectionOffset::DebugInfoOffset(offset)
226-
}
227-
}
228-
229-
impl<T> From<DebugTypesOffset<T>> for UnitSectionOffset<T> {
230-
fn from(offset: DebugTypesOffset<T>) -> Self {
231-
UnitSectionOffset::DebugTypesOffset(offset)
232-
}
233-
}
234-
235-
impl<T> UnitSectionOffset<T>
236-
where
237-
T: Clone,
238-
{
239-
/// Returns the `DebugInfoOffset` inside, or `None` otherwise.
240-
pub fn as_debug_info_offset(&self) -> Option<DebugInfoOffset<T>> {
241-
match self {
242-
UnitSectionOffset::DebugInfoOffset(offset) => Some(offset.clone()),
243-
UnitSectionOffset::DebugTypesOffset(_) => None,
244-
}
245-
}
246-
/// Returns the `DebugTypesOffset` inside, or `None` otherwise.
247-
pub fn as_debug_types_offset(&self) -> Option<DebugTypesOffset<T>> {
248-
match self {
249-
UnitSectionOffset::DebugInfoOffset(_) => None,
250-
UnitSectionOffset::DebugTypesOffset(offset) => Some(offset.clone()),
251-
}
252-
}
253-
}
219+
pub struct UnitSectionOffset<T = usize>(pub T);
254220

255221
/// An identifier for a DWARF section.
256222
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]

src/read/dwarf.rs

Lines changed: 12 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ use alloc::string::String;
22
use alloc::sync::Arc;
33

44
use crate::common::{
5-
DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase,
6-
DebugLocListsIndex, DebugMacinfoOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset,
7-
DebugStrOffsetsBase, DebugStrOffsetsIndex, DebugTypeSignature, DebugTypesOffset, DwarfFileType,
8-
DwoId, Encoding, LocationListsOffset, RangeListsOffset, RawRangeListsOffset, SectionId,
9-
UnitSectionOffset,
5+
DebugAddrBase, DebugAddrIndex, DebugLineStrOffset, DebugLocListsBase, DebugLocListsIndex,
6+
DebugMacinfoOffset, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
7+
DebugStrOffsetsIndex, DebugTypeSignature, DwarfFileType, DwoId, Encoding, LocationListsOffset,
8+
RangeListsOffset, RawRangeListsOffset, SectionId,
109
};
1110
use crate::read::{
1211
Abbreviations, AbbreviationsCache, AbbreviationsCacheStrategy, AttributeValue, DebugAbbrev,
@@ -1196,6 +1195,14 @@ where
11961195
pub dwo_id: Option<DwoId>,
11971196
}
11981197

1198+
impl<'a, R: Reader> core::ops::Deref for Unit<R> {
1199+
type Target = UnitHeader<R>;
1200+
1201+
fn deref(&self) -> &Self::Target {
1202+
&self.header
1203+
}
1204+
}
1205+
11991206
impl<R: Reader> Unit<R> {
12001207
/// Construct a new `Unit` from the given unit header.
12011208
#[inline]
@@ -1599,68 +1606,6 @@ impl<'a, R: Reader> UnitRef<'a, R> {
15991606
}
16001607
}
16011608

1602-
impl<T: ReaderOffset> UnitSectionOffset<T> {
1603-
/// Convert an offset to be relative to the start of the given unit,
1604-
/// instead of relative to the start of the section.
1605-
///
1606-
/// Returns `None` if the offset is not within the unit entries.
1607-
pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>>
1608-
where
1609-
R: Reader<Offset = T>,
1610-
{
1611-
let (offset, unit_offset) = match (self, unit.header.offset()) {
1612-
(
1613-
UnitSectionOffset::DebugInfoOffset(offset),
1614-
UnitSectionOffset::DebugInfoOffset(unit_offset),
1615-
) => (offset.0, unit_offset.0),
1616-
(
1617-
UnitSectionOffset::DebugTypesOffset(offset),
1618-
UnitSectionOffset::DebugTypesOffset(unit_offset),
1619-
) => (offset.0, unit_offset.0),
1620-
_ => return None,
1621-
};
1622-
let offset = match offset.checked_sub(unit_offset) {
1623-
Some(offset) => UnitOffset(offset),
1624-
None => return None,
1625-
};
1626-
if !unit.header.is_valid_offset(offset) {
1627-
return None;
1628-
}
1629-
Some(offset)
1630-
}
1631-
}
1632-
1633-
impl<T: ReaderOffset> UnitOffset<T> {
1634-
/// Return true if this offset is within the entries of the given unit.
1635-
///
1636-
/// This only checks that the offset is within the range of the data for unit entries,
1637-
/// not that there is a valid DIE at this offset.
1638-
pub fn is_in_bounds<R>(&self, unit: &Unit<R>) -> bool
1639-
where
1640-
R: Reader<Offset = T>,
1641-
{
1642-
unit.header.is_valid_offset(*self)
1643-
}
1644-
1645-
/// Convert an offset to be relative to the start of the .debug_info section,
1646-
/// instead of relative to the start of the given compilation unit.
1647-
///
1648-
/// Does not check that the offset is valid.
1649-
pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T>
1650-
where
1651-
R: Reader<Offset = T>,
1652-
{
1653-
match unit.header.offset() {
1654-
UnitSectionOffset::DebugInfoOffset(unit_offset) => {
1655-
DebugInfoOffset(unit_offset.0 + self.0).into()
1656-
}
1657-
UnitSectionOffset::DebugTypesOffset(unit_offset) => {
1658-
DebugTypesOffset(unit_offset.0 + self.0).into()
1659-
}
1660-
}
1661-
}
1662-
}
1663-
16641609
/// An iterator for the address ranges of a `DebuggingInformationEntry`.
16651610
///
16661611
/// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`.

0 commit comments

Comments
 (0)