Skip to content

Commit 6e25a48

Browse files
committed
read/cfi: minor CIE/FDE parsing optimisation
When asked to parse a CIE, we would fully parse any CIE or FDE at the offset, and then discard the result if it was an FDE. Similarly for parsing an FDE. Optimise this by doing the check of the CIE ID immediately. In practice this is unlikely to make any difference, because the entries will always be the expected type if the data is valid. Additionally, we had `Error::NotCieId`, `Error::NotCiePointer`, and `Error::NotFdePointer`, but `Error::NotCiePointer` was not used. However, `Error::NotCiePointer` is the more logical error for the situation where `Error::NotFdePointer` was used, so switch to it and delete `Error::NotFdePointer`. The git history shows that at some point we already did both of the above (which is why `NotCiePointer` existed), but they were lost along the way during refactoring. Also reorder some function parameters for consistency.
1 parent 574952e commit 6e25a48

File tree

2 files changed

+95
-54
lines changed

2 files changed

+95
-54
lines changed

src/read/cfi.rs

Lines changed: 95 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ pub trait UnwindSection<R: Reader>: Clone + Debug + _UnwindSectionPrivate<R> {
656656
let offset = UnwindOffset::into(offset);
657657
let input = &mut self.section().clone();
658658
input.skip(offset)?;
659-
CommonInformationEntry::parse(bases, self, input)
659+
CommonInformationEntry::parse(self, bases, input)
660660
}
661661

662662
/// Parse the `PartialFrameDescriptionEntry` at the given offset.
@@ -1011,7 +1011,7 @@ where
10111011
return Ok(None);
10121012
}
10131013

1014-
match parse_cfi_entry(self.bases, &self.section, &mut self.input) {
1014+
match parse_cfi_entry(&self.section, self.bases, &mut self.input) {
10151015
Ok(Some(entry)) => return Ok(Some(entry)),
10161016
Err(e) => {
10171017
self.input.empty();
@@ -1076,10 +1076,45 @@ where
10761076
}
10771077

10781078
fn parse_cfi_entry<'bases, Section, R>(
1079-
bases: &'bases BaseAddresses,
10801079
section: &Section,
1080+
bases: &'bases BaseAddresses,
10811081
input: &mut R,
10821082
) -> Result<Option<CieOrFde<'bases, Section, R>>>
1083+
where
1084+
R: Reader,
1085+
Section: UnwindSection<R>,
1086+
{
1087+
let Some(prefix) = parse_cfi_entry_prefix(section, input)? else {
1088+
return Ok(None);
1089+
};
1090+
1091+
if Section::is_cie(prefix.format, prefix.cie_id_or_offset) {
1092+
let cie = CommonInformationEntry::from_prefix(section, bases, prefix)?;
1093+
Ok(Some(CieOrFde::Cie(cie)))
1094+
} else {
1095+
let fde = PartialFrameDescriptionEntry::from_prefix(section, bases, prefix)?;
1096+
Ok(Some(CieOrFde::Fde(fde)))
1097+
}
1098+
}
1099+
1100+
/// The common prefix of a CIE or FDE.
1101+
#[derive(Clone, Debug, PartialEq, Eq)]
1102+
struct CfiEntryPrefix<R>
1103+
where
1104+
R: Reader,
1105+
{
1106+
offset: R::Offset,
1107+
length: R::Offset,
1108+
format: Format,
1109+
cie_offset_base: R::Offset,
1110+
cie_id_or_offset: u64,
1111+
rest: R,
1112+
}
1113+
1114+
fn parse_cfi_entry_prefix<Section, R>(
1115+
section: &Section,
1116+
input: &mut R,
1117+
) -> Result<Option<CfiEntryPrefix<R>>>
10831118
where
10841119
R: Reader,
10851120
Section: UnwindSection<R>,
@@ -1097,28 +1132,14 @@ where
10971132
CieOffsetEncoding::U64 => rest.read_u64()?,
10981133
};
10991134

1100-
if Section::is_cie(format, cie_id_or_offset) {
1101-
let cie = CommonInformationEntry::parse_rest(offset, length, format, bases, section, rest)?;
1102-
Ok(Some(CieOrFde::Cie(cie)))
1103-
} else {
1104-
let cie_offset = R::Offset::from_u64(cie_id_or_offset)?;
1105-
let cie_offset = match section.resolve_cie_offset(cie_offset_base, cie_offset) {
1106-
None => return Err(Error::OffsetOutOfBounds),
1107-
Some(cie_offset) => cie_offset,
1108-
};
1109-
1110-
let fde = PartialFrameDescriptionEntry {
1111-
offset,
1112-
length,
1113-
format,
1114-
cie_offset: cie_offset.into(),
1115-
rest,
1116-
section: section.clone(),
1117-
bases,
1118-
};
1119-
1120-
Ok(Some(CieOrFde::Fde(fde)))
1121-
}
1135+
Ok(Some(CfiEntryPrefix {
1136+
offset,
1137+
length,
1138+
format,
1139+
cie_offset_base,
1140+
cie_id_or_offset,
1141+
rest,
1142+
}))
11221143
}
11231144

11241145
/// We support the z-style augmentation [defined by `.eh_frame`][ehframe].
@@ -1313,25 +1334,25 @@ where
13131334

13141335
impl<R: Reader> CommonInformationEntry<R> {
13151336
fn parse<Section: UnwindSection<R>>(
1316-
bases: &BaseAddresses,
13171337
section: &Section,
1338+
bases: &BaseAddresses,
13181339
input: &mut R,
13191340
) -> Result<CommonInformationEntry<R>> {
1320-
match parse_cfi_entry(bases, section, input)? {
1321-
Some(CieOrFde::Cie(cie)) => Ok(cie),
1322-
Some(CieOrFde::Fde(_)) => Err(Error::NotCieId),
1323-
None => Err(Error::NoEntryAtGivenOffset),
1341+
let Some(prefix) = parse_cfi_entry_prefix(section, input)? else {
1342+
return Err(Error::NoEntryAtGivenOffset);
1343+
};
1344+
if !Section::is_cie(prefix.format, prefix.cie_id_or_offset) {
1345+
return Err(Error::NotCieId);
13241346
}
1347+
CommonInformationEntry::from_prefix(section, bases, prefix)
13251348
}
13261349

1327-
fn parse_rest<Section: UnwindSection<R>>(
1328-
offset: R::Offset,
1329-
length: R::Offset,
1330-
format: Format,
1331-
bases: &BaseAddresses,
1350+
fn from_prefix<Section: UnwindSection<R>>(
13321351
section: &Section,
1333-
mut rest: R,
1352+
bases: &BaseAddresses,
1353+
prefix: CfiEntryPrefix<R>,
13341354
) -> Result<CommonInformationEntry<R>> {
1355+
let mut rest = prefix.rest;
13351356
let version = rest.read_u8()?;
13361357

13371358
// Version 1 of `.debug_frame` corresponds to DWARF 2, and then for
@@ -1377,9 +1398,9 @@ impl<R: Reader> CommonInformationEntry<R> {
13771398
};
13781399

13791400
let entry = CommonInformationEntry {
1380-
offset,
1381-
length,
1382-
format,
1401+
offset: prefix.offset,
1402+
length: prefix.length,
1403+
format: prefix.format,
13831404
version,
13841405
augmentation,
13851406
address_size,
@@ -1544,11 +1565,36 @@ where
15441565
bases: &'bases BaseAddresses,
15451566
input: &mut R,
15461567
) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> {
1547-
match parse_cfi_entry(bases, section, input)? {
1548-
Some(CieOrFde::Cie(_)) => Err(Error::NotFdePointer),
1549-
Some(CieOrFde::Fde(partial)) => Ok(partial),
1550-
None => Err(Error::NoEntryAtGivenOffset),
1568+
let Some(prefix) = parse_cfi_entry_prefix(section, input)? else {
1569+
return Err(Error::NoEntryAtGivenOffset);
1570+
};
1571+
if Section::is_cie(prefix.format, prefix.cie_id_or_offset) {
1572+
return Err(Error::NotCiePointer);
15511573
}
1574+
Self::from_prefix(section, bases, prefix)
1575+
}
1576+
1577+
fn from_prefix(
1578+
section: &Section,
1579+
bases: &'bases BaseAddresses,
1580+
prefix: CfiEntryPrefix<R>,
1581+
) -> Result<PartialFrameDescriptionEntry<'bases, Section, R>> {
1582+
let cie_offset = R::Offset::from_u64(prefix.cie_id_or_offset)?;
1583+
let Some(cie_offset) = section.resolve_cie_offset(prefix.cie_offset_base, cie_offset)
1584+
else {
1585+
return Err(Error::OffsetOutOfBounds);
1586+
};
1587+
1588+
let fde = PartialFrameDescriptionEntry {
1589+
offset: prefix.offset,
1590+
length: prefix.length,
1591+
format: prefix.format,
1592+
cie_offset: cie_offset.into(),
1593+
rest: prefix.rest,
1594+
section: section.clone(),
1595+
bases,
1596+
};
1597+
Ok(fde)
15521598
}
15531599

15541600
/// Fully parse this FDE.
@@ -3778,7 +3824,7 @@ mod tests {
37783824
F: FnMut(&Section, &BaseAddresses, O) -> Result<CommonInformationEntry<R>>,
37793825
{
37803826
let bases = Default::default();
3781-
match parse_cfi_entry(&bases, &section, input) {
3827+
match parse_cfi_entry(&section, &bases, input) {
37823828
Ok(Some(CieOrFde::Fde(partial))) => partial.parse(get_cie),
37833829
Ok(_) => Err(Error::NoEntryAtGivenOffset),
37843830
Err(e) => Err(e),
@@ -3984,7 +4030,7 @@ mod tests {
39844030
debug_frame.set_address_size(address_size);
39854031
let input = &mut EndianSlice::new(&section, E::default());
39864032
let bases = Default::default();
3987-
let result = CommonInformationEntry::parse(&bases, &debug_frame, input);
4033+
let result = CommonInformationEntry::parse(&debug_frame, &bases, input);
39884034
let result = result.map(|cie| (*input, cie)).map_eof(&section);
39894035
assert_eq!(result, expected);
39904036
}
@@ -4177,8 +4223,8 @@ mod tests {
41774223
let bases = Default::default();
41784224
assert_eq!(
41794225
CommonInformationEntry::parse(
4180-
&bases,
41814226
&debug_frame,
4227+
&bases,
41824228
&mut EndianSlice::new(&contents, LittleEndian)
41834229
)
41844230
.map_eof(&contents),
@@ -4355,7 +4401,7 @@ mod tests {
43554401

43564402
let bases = Default::default();
43574403
assert_eq!(
4358-
parse_cfi_entry(&bases, &debug_frame, rest),
4404+
parse_cfi_entry(&debug_frame, &bases, rest),
43594405
Ok(Some(CieOrFde::Cie(cie)))
43604406
);
43614407
assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
@@ -4401,7 +4447,7 @@ mod tests {
44014447
let rest = &mut EndianSlice::new(&section, BigEndian);
44024448

44034449
let bases = Default::default();
4404-
match parse_cfi_entry(&bases, &debug_frame, rest) {
4450+
match parse_cfi_entry(&debug_frame, &bases, rest) {
44054451
Ok(Some(CieOrFde::Fde(partial))) => {
44064452
assert_eq!(*rest, EndianSlice::new(&expected_rest, BigEndian));
44074453

@@ -6740,7 +6786,7 @@ mod tests {
67406786
let input = &mut EndianSlice::new(&section[buf.len()..], LittleEndian);
67416787

67426788
let bases = Default::default();
6743-
match parse_cfi_entry(&bases, &eh_frame, input) {
6789+
match parse_cfi_entry(&eh_frame, &bases, input) {
67446790
Ok(Some(CieOrFde::Fde(partial))) => Ok(partial.cie_offset.0),
67456791
Err(e) => Err(e),
67466792
otherwise => panic!("Unexpected result: {:#?}", otherwise),

src/read/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,6 @@ pub enum Error {
318318
NotCieId,
319319
/// Expected to find a pointer to a CIE, but found the CIE ID instead.
320320
NotCiePointer,
321-
/// Expected to find a pointer to an FDE, but found a CIE instead.
322-
NotFdePointer,
323321
/// Invalid branch target for a DW_OP_bra or DW_OP_skip.
324322
BadBranchTarget(u64),
325323
/// DW_OP_push_object_address used but no address passed in.
@@ -504,9 +502,6 @@ impl Error {
504502
Error::BadUtf8 => "Found an invalid UTF-8 string.",
505503
Error::NotCieId => "Expected to find the CIE ID, but found something else.",
506504
Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.",
507-
Error::NotFdePointer => {
508-
"Expected to find an FDE pointer, but found a CIE pointer instead."
509-
}
510505
Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression",
511506
Error::InvalidPushObjectAddress => {
512507
"DW_OP_push_object_address used but no object address given"

0 commit comments

Comments
 (0)