Skip to content

Commit aa42d72

Browse files
committed
fix: unify CFA offset saturation
Use saturating addition consistently when merging CFA offsets in DW_OP_fbreg fast paths and EvaluationResult::merge_with_cfa. Add regression tests for both code paths.
1 parent bfd8a66 commit aa42d72

2 files changed

Lines changed: 66 additions & 4 deletions

File tree

ghostscope-dwarf/src/core/evaluation.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ impl EvaluationResult {
235235
// CFA gives us the frame base, add the frame_offset to get final location
236236
EvaluationResult::MemoryLocation(LocationResult::RegisterAddress {
237237
register,
238-
offset: Some(offset + frame_offset),
238+
offset: Some(offset.saturating_add(frame_offset)),
239239
size: None,
240240
})
241241
}
@@ -678,3 +678,28 @@ impl fmt::Display for ComputeStep {
678678
}
679679
}
680680
}
681+
682+
#[cfg(test)]
683+
mod tests {
684+
use super::{CfaResult, EvaluationResult, LocationResult};
685+
686+
#[test]
687+
fn merge_with_cfa_saturates_register_plus_offset() {
688+
let merged = EvaluationResult::Optimized.merge_with_cfa(
689+
CfaResult::RegisterPlusOffset {
690+
register: 7,
691+
offset: i64::MAX - 2,
692+
},
693+
10,
694+
);
695+
696+
assert_eq!(
697+
merged,
698+
EvaluationResult::MemoryLocation(LocationResult::RegisterAddress {
699+
register: 7,
700+
offset: Some(i64::MAX),
701+
size: None,
702+
})
703+
);
704+
}
705+
}

ghostscope-dwarf/src/parser/expression_evaluator.rs

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ impl ExpressionEvaluator {
685685
} => Ok(EvaluationResult::MemoryLocation(
686686
LocationResult::RegisterAddress {
687687
register,
688-
offset: Some(cfa_offset + offset),
688+
offset: Some(cfa_offset.saturating_add(*offset)),
689689
size: None,
690690
},
691691
)),
@@ -1604,15 +1604,15 @@ mod tests {
16041604
use super::ExpressionEvaluator;
16051605
use crate::binary::{dwarf_reader_from_arc, DwarfReader};
16061606
use crate::core::{
1607-
ComputeStep, DirectValueResult, EntryValueCase, EvaluationResult, LocationResult,
1607+
CfaResult, ComputeStep, DirectValueResult, EntryValueCase, EvaluationResult, LocationResult,
16081608
};
16091609
use crate::index::{BlockNode, CallSiteParameter, CallSiteRecord, FunctionBlocks};
16101610
use gimli::constants;
16111611
use gimli::write::{
16121612
Address, AttributeValue as WriteAttributeValue, Dwarf as WriteDwarf, EndianVec,
16131613
Expression as WriteExpression, LineProgram, Sections, Unit,
16141614
};
1615-
use gimli::{Format, LittleEndian, Register};
1615+
use gimli::{Format, LittleEndian, Register, RunTimeEndian};
16161616
use std::sync::Arc;
16171617

16181618
fn build_scanned_incoming_entry_value_fixture(
@@ -1956,6 +1956,43 @@ mod tests {
19561956
);
19571957
}
19581958

1959+
#[test]
1960+
fn single_fbreg_fast_path_saturates_cfa_offset_addition() {
1961+
let encoding = gimli::Encoding {
1962+
format: gimli::Format::Dwarf32,
1963+
version: 5,
1964+
address_size: 8,
1965+
};
1966+
let get_cfa = |_address| {
1967+
Ok(Some(CfaResult::RegisterPlusOffset {
1968+
register: 7,
1969+
offset: i64::MAX - 3,
1970+
}))
1971+
};
1972+
1973+
let result = ExpressionEvaluator::parse_expression_with_context(
1974+
&[0x91, 0x0a],
1975+
RunTimeEndian::Little,
1976+
encoding,
1977+
None,
1978+
0,
1979+
Some(&get_cfa),
1980+
None,
1981+
None,
1982+
0,
1983+
)
1984+
.expect("single DW_OP_fbreg should parse");
1985+
1986+
assert_eq!(
1987+
result,
1988+
EvaluationResult::MemoryLocation(LocationResult::RegisterAddress {
1989+
register: 7,
1990+
offset: Some(i64::MAX),
1991+
size: None,
1992+
})
1993+
);
1994+
}
1995+
19591996
#[test]
19601997
fn big_endian_dw_op_addr_preserves_absolute_address() {
19611998
let encoding = gimli::Encoding {

0 commit comments

Comments
 (0)