Skip to content

Commit a396d23

Browse files
committed
Handle DW_AT_ranges for functions
1 parent 3544e9d commit a396d23

File tree

7 files changed

+156
-97
lines changed

7 files changed

+156
-97
lines changed

main/src/print/file.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ pub fn bloat_index(file: &File, options: &Options) -> BloatIndex {
776776
let mut callers = HashMap::new();
777777
for (unit_index, unit) in file.units().iter().enumerate() {
778778
for (function_index, function) in unit.functions().iter().enumerate() {
779-
if let Some(range) = function.range() {
779+
if let Some(size) = function.size() {
780780
let mut name = Vec::new();
781781
print::function::print_ref(function, &mut name).unwrap();
782782
let mut source = Vec::new();
@@ -785,17 +785,19 @@ pub fn bloat_index(file: &File, options: &Options) -> BloatIndex {
785785
let mut function_total = function_totals
786786
.entry(id)
787787
.or_insert(FunctionTotal::default());
788-
function_total.size += range.size();
788+
function_total.size += size;
789789
function_total.functions.push((unit_index, function_index));
790790

791791
if let Some(code) = code.as_ref() {
792-
for call in code.calls(range) {
793-
let entry = callers.entry(call.to).or_insert(Vec::new());
794-
entry.push(Caller {
795-
unit_index,
796-
function_index,
797-
_address: call.from,
798-
});
792+
for range in function.ranges() {
793+
for call in code.calls(*range) {
794+
let entry = callers.entry(call.to).or_insert(Vec::new());
795+
entry.push(Caller {
796+
unit_index,
797+
function_index,
798+
_address: call.from,
799+
});
800+
}
799801
}
800802
}
801803
}
@@ -838,17 +840,18 @@ pub fn bloat(
838840
for (unit_index, function_index) in &function_total.functions {
839841
let unit = &file.units()[*unit_index];
840842
let function = &unit.functions()[*function_index];
841-
let range = function.range().unwrap();
843+
let address = function.address().unwrap();
844+
let size = function.size().unwrap();
842845
state.id(
843846
function.id(),
844847
|state| {
845848
state.line(|w, _hash| {
846-
write!(w, "{} ", range.size())?;
849+
write!(w, "{} ", size)?;
847850
print::unit::print_ref(unit, w)?;
848851
Ok(())
849852
})
850853
},
851-
|state| bloat_callers(state, file, index, range.begin),
854+
|state| bloat_callers(state, file, index, address),
852855
)?;
853856
}
854857
Ok(())

main/src/print/function.rs

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ fn print_source(f: &Function, w: &mut dyn ValuePrinter, unit: &Unit) -> Result<(
4848
print::source::print(f.source(), w, unit)
4949
}
5050

51-
fn print_address(f: &Function, w: &mut dyn ValuePrinter) -> Result<()> {
52-
if let Some(ref range) = f.range() {
51+
fn print_range(range: Option<&Range>, w: &mut dyn ValuePrinter) -> Result<()> {
52+
if let Some(range) = range {
5353
print::range::print_address(range, w)?;
5454
}
5555
Ok(())
@@ -100,7 +100,13 @@ impl<'input> PrintHeader for Function<'input> {
100100
if state.options().print_source {
101101
state.field("source", |w, _state| print_source(self, w, unit))?;
102102
}
103-
state.field("address", |w, _state| print_address(self, w))?;
103+
let ranges = self.ranges();
104+
if ranges.len() > 1 {
105+
state.field_collapsed("addresses", |state| state.list(&(), ranges))?;
106+
} else {
107+
let range = ranges.first();
108+
state.field("address", |w, _state| print_range(range, w))?;
109+
}
104110
state.field("size", |w, _state| print_size(self, w))?;
105111
state.field("inline", |w, _state| print_inline(self, w))?;
106112
state.field("declaration", |w, _state| print_declaration(self, w))?;
@@ -125,7 +131,7 @@ impl<'input> PrintHeader for Function<'input> {
125131
let calls = calls(self, state.code);
126132
state.field_collapsed("calls", |state| state.list(&(), &calls))?;
127133
}
128-
if state.options().print_function_instructions && self.range().is_some() {
134+
if state.options().print_function_instructions && !self.ranges().is_empty() {
129135
state.field_detail("code", "instructions", |state| {
130136
print_instructions(state, self, &details)
131137
})?;
@@ -164,7 +170,19 @@ impl<'input> PrintHeader for Function<'input> {
164170
}
165171
let flag = state.options().ignore_function_address;
166172
state.ignore_diff(flag, |state| {
167-
state.field("address", a, b, |w, _state, x| print_address(x, w))
173+
let ranges_a = a.ranges();
174+
let ranges_b = b.ranges();
175+
if ranges_a.len() > 1 || ranges_b.len() > 1 {
176+
state.field_collapsed("addresses", |state| {
177+
state.ord_list(&(), ranges_a, &(), ranges_b)
178+
})
179+
} else {
180+
let range_a = ranges_a.first();
181+
let range_b = ranges_b.first();
182+
state.field("address", range_a, range_b, |w, _state, range| {
183+
print_range(range, w)
184+
})
185+
}
168186
})?;
169187
let flag = state.options().ignore_function_size;
170188
state.ignore_diff(flag, |state| {
@@ -391,21 +409,24 @@ impl DiffList for Call {
391409
}
392410

393411
pub(crate) fn calls(f: &Function, code: Option<&Code>) -> Vec<Call> {
394-
if let (Some(code), Some(range)) = (code, f.range()) {
395-
return code.calls(range);
412+
let mut calls = Vec::new();
413+
if let Some(code) = code {
414+
for range in f.ranges() {
415+
calls.extend(code.calls(*range));
416+
}
396417
}
397-
Vec::new()
418+
calls
398419
}
399420

400421
pub(crate) fn print_instructions(
401422
state: &mut PrintState,
402423
f: &Function,
403424
details: &FunctionDetails,
404425
) -> Result<()> {
405-
let range = match f.range() {
406-
Some(x) => x,
407-
None => return Ok(()),
408-
};
426+
let ranges = f.ranges();
427+
if ranges.is_empty() {
428+
return Ok(());
429+
}
409430
let code = match state.code {
410431
Some(x) => x,
411432
None => return Ok(()),
@@ -414,37 +435,44 @@ pub(crate) fn print_instructions(
414435
Some(x) => x,
415436
None => return Ok(()),
416437
};
417-
let insns = match disassembler.instructions(code, range) {
418-
Some(x) => x,
419-
None => return Ok(()),
420-
};
421-
let cfis = f.cfi(state.hash());
422-
423-
let mut insns = insns.iter();
424-
let mut cfis = cfis.iter();
438+
for range in ranges.iter().copied() {
439+
state.instruction(None, "", |w, _hash| {
440+
write!(w, ".org 0x{:x}", range.begin)?;
441+
Ok(())
442+
})?;
425443

426-
let mut insn_next = insns.next();
427-
let mut cfi_next = cfis.next();
428-
loop {
429-
match (&insn_next, cfi_next) {
430-
(&Some(ref insn), Some(cfi)) => {
431-
if cfi.0.is_none() || cfi.0 <= insn.address() {
432-
print_cfi(state, cfi, range)?;
433-
cfi_next = cfis.next();
434-
} else {
444+
let insns = match disassembler.instructions(code, range) {
445+
Some(x) => x,
446+
None => return Ok(()),
447+
};
448+
let cfis = state.hash().file.cfi(range);
449+
450+
let mut insns = insns.iter();
451+
let mut cfis = cfis.iter();
452+
453+
let mut insn_next = insns.next();
454+
let mut cfi_next = cfis.next();
455+
loop {
456+
match (&insn_next, cfi_next) {
457+
(&Some(ref insn), Some(cfi)) => {
458+
if cfi.0.is_none() || cfi.0 <= insn.address() {
459+
print_cfi(state, cfi, range)?;
460+
cfi_next = cfis.next();
461+
} else {
462+
insn.print(state, code, &disassembler, details, range)?;
463+
insn_next = insns.next();
464+
}
465+
}
466+
(&Some(ref insn), None) => {
435467
insn.print(state, code, &disassembler, details, range)?;
436468
insn_next = insns.next();
437469
}
470+
(&None, Some(cfi)) => {
471+
print_cfi(state, cfi, range)?;
472+
cfi_next = cfis.next();
473+
}
474+
(&None, None) => break,
438475
}
439-
(&Some(ref insn), None) => {
440-
insn.print(state, code, &disassembler, details, range)?;
441-
insn_next = insns.next();
442-
}
443-
(&None, Some(cfi)) => {
444-
print_cfi(state, cfi, range)?;
445-
cfi_next = cfis.next();
446-
}
447-
(&None, None) => break,
448476
}
449477
}
450478
Ok(())

main/src/print/unit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ pub(crate) fn diff_body(state: &mut DiffState, unit_a: &Unit, unit_b: &Unit) ->
216216
if options.print_unit_address {
217217
let ranges_a = unit_a.ranges(state.hash_a());
218218
let ranges_b = unit_b.ranges(state.hash_b());
219-
if ranges_a.list().len() > 1 || ranges_a.list().len() > 1 {
219+
if ranges_a.list().len() > 1 || ranges_b.list().len() > 1 {
220220
state.field_collapsed("addresses", |state| {
221221
state.ord_list(&(), ranges_a.list(), &(), ranges_b.list())
222222
})?;

parser/src/file/dwarf.rs

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ where
347347
})
348348
}
349349

350-
pub(crate) fn get_cfi(&self, address: Address, size: Size) -> Vec<Cfi> {
351-
self.frame.get_cfi(address, size).unwrap_or_default()
350+
pub(crate) fn get_cfi(&self, range: Range) -> Vec<Cfi> {
351+
self.frame.get_cfi(range).unwrap_or_default()
352352
}
353353

354354
pub(crate) fn get_register_name(
@@ -2164,6 +2164,7 @@ where
21642164
source: Source::default(),
21652165
address: Address::none(),
21662166
size: Size::none(),
2167+
ranges: Vec::new(),
21672168
inline: false,
21682169
declaration: false,
21692170
parameters: Vec::new(),
@@ -2174,6 +2175,7 @@ where
21742175
let mut abstract_origin = false;
21752176
let mut high_pc = None;
21762177
let mut size = None;
2178+
let mut ranges = None;
21772179

21782180
let entry = node.entry();
21792181
let mut attrs = entry.attrs();
@@ -2216,6 +2218,11 @@ where
22162218
}
22172219
_ => {}
22182220
},
2221+
gimli::DW_AT_ranges => {
2222+
if let gimli::AttributeValue::RangeListsRef(val) = attr.value() {
2223+
ranges = Some(val);
2224+
}
2225+
}
22192226
gimli::DW_AT_type => {
22202227
if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
22212228
function.return_type = offset;
@@ -2259,13 +2266,36 @@ where
22592266
}
22602267
}
22612268

2262-
if let Some(address) = function.address() {
2269+
if let Some(offset) = ranges {
2270+
let offset = dwarf.read.ranges_offset_from_raw(&dwarf_unit, offset);
2271+
let mut ranges = dwarf.read.ranges(&dwarf_unit, offset)?;
2272+
let mut size = 0;
2273+
while let Some(range) = ranges.next()? {
2274+
if range.end > range.begin {
2275+
size += range.end - range.begin;
2276+
function.ranges.push(Range {
2277+
begin: range.begin,
2278+
end: range.end,
2279+
});
2280+
}
2281+
}
2282+
function.size = Size::new(size);
2283+
function.address = Address::new(function.ranges.first().map(|r| r.begin).unwrap_or(0));
2284+
} else if let Some(address) = function.address.get() {
22632285
if let Some(high_pc) = high_pc {
22642286
if high_pc > address {
22652287
function.size = Size::new(high_pc - address);
2288+
function.ranges.push(Range {
2289+
begin: address,
2290+
end: high_pc,
2291+
});
22662292
}
22672293
} else if let Some(size) = size {
22682294
function.size = Size::new(size);
2295+
function.ranges.push(Range {
2296+
begin: address,
2297+
end: address.wrapping_add(size),
2298+
});
22692299
}
22702300
}
22712301

@@ -3902,17 +3932,13 @@ impl<R: gimli::Reader<Offset = usize>> DwarfFrame<R> {
39023932
}
39033933
}
39043934

3905-
fn get_cfi(&self, address: Address, size: Size) -> Option<Vec<Cfi>> {
3935+
fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
39063936
let cfi = self
39073937
.eh_frame
3908-
.get_cfi(address, size)
3909-
.or_else(|| self.debug_frame.get_cfi(address, size));
3938+
.get_cfi(range)
3939+
.or_else(|| self.debug_frame.get_cfi(range));
39103940
if cfi.is_none() {
3911-
debug!(
3912-
"no FDE for 0x{:x}[0x{:x}]",
3913-
address.get().unwrap_or(0),
3914-
size.get().unwrap_or(0)
3915-
);
3941+
debug!("no FDE for 0x{:x}[0x{:x}]", range.begin, range.size());
39163942
}
39173943
cfi
39183944
}
@@ -3935,8 +3961,8 @@ impl<R: gimli::Reader<Offset = usize>> DebugFrameTable<R> {
39353961
}
39363962
}
39373963

3938-
fn get_cfi(&self, address: Address, size: Size) -> Option<Vec<Cfi>> {
3939-
get_cfi(&self.debug_frame, &self.bases, &self.fdes, address, size)
3964+
fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
3965+
get_cfi(&self.debug_frame, &self.bases, &self.fdes, range)
39403966
}
39413967
}
39423968

@@ -3956,8 +3982,8 @@ impl<R: gimli::Reader<Offset = usize>> EhFrameTable<R> {
39563982
}
39573983
}
39583984

3959-
fn get_cfi(&self, address: Address, size: Size) -> Option<Vec<Cfi>> {
3960-
get_cfi(&self.eh_frame, &self.bases, &self.fdes, address, size)
3985+
fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
3986+
get_cfi(&self.eh_frame, &self.bases, &self.fdes, range)
39613987
}
39623988
}
39633989

@@ -4019,14 +4045,13 @@ fn get_cfi<R: gimli::Reader, S: gimli::UnwindSection<R>>(
40194045
section: &S,
40204046
bases: &gimli::BaseAddresses,
40214047
fdes: &FdeOffsetTable,
4022-
address: Address,
4023-
size: Size,
4048+
range: Range,
40244049
) -> Option<Vec<Cfi>>
40254050
where
40264051
S::Offset: gimli::UnwindOffset,
40274052
{
4028-
let address = address.get()?;
4029-
let size = size.get()?;
4053+
let address = range.begin;
4054+
let size = range.size();
40304055
let fde_offset = S::Offset::from(fdes.find(address)?);
40314056
let fde = section
40324057
.fde_from_offset(bases, fde_offset, S::cie_from_offset)

0 commit comments

Comments
 (0)