summaryrefslogtreecommitdiffstats
path: root/vendor/addr2line/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/addr2line/src/lib.rs')
-rw-r--r--vendor/addr2line/src/lib.rs246
1 files changed, 144 insertions, 102 deletions
diff --git a/vendor/addr2line/src/lib.rs b/vendor/addr2line/src/lib.rs
index b46a98393..3afa37f8f 100644
--- a/vendor/addr2line/src/lib.rs
+++ b/vendor/addr2line/src/lib.rs
@@ -181,6 +181,7 @@ impl<R: gimli::Reader> Context<R> {
ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists),
file_type: gimli::DwarfFileType::Main,
sup: None,
+ abbreviations_cache: gimli::AbbreviationsCache::new(),
})
}
@@ -404,6 +405,7 @@ impl<R: gimli::Reader> ResDwarf<R> {
};
let mut lang = None;
+ let mut have_unit_range = false;
{
let mut entries = dw_unit.entries_raw(None)?;
@@ -416,13 +418,18 @@ impl<R: gimli::Reader> ResDwarf<R> {
for spec in abbrev.attributes() {
let attr = entries.read_attribute(*spec)?;
match attr.name() {
- gimli::DW_AT_low_pc => {
- if let gimli::AttributeValue::Addr(val) = attr.value() {
- ranges.low_pc = Some(val);
+ gimli::DW_AT_low_pc => match attr.value() {
+ gimli::AttributeValue::Addr(val) => ranges.low_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.low_pc = Some(sections.address(&dw_unit, index)?);
}
- }
+ _ => {}
+ },
gimli::DW_AT_high_pc => match attr.value() {
gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
+ gimli::AttributeValue::DebugAddrIndex(index) => {
+ ranges.high_pc = Some(sections.address(&dw_unit, index)?);
+ }
gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
_ => {}
},
@@ -472,11 +479,12 @@ impl<R: gimli::Reader> ResDwarf<R> {
unit_id,
max_end: 0,
});
+ have_unit_range = true;
}
}
}
} else {
- ranges.for_each_range(&sections, &dw_unit, |range| {
+ have_unit_range |= ranges.for_each_range(&sections, &dw_unit, |range| {
unit_ranges.push(UnitRange {
range,
unit_id,
@@ -486,11 +494,34 @@ impl<R: gimli::Reader> ResDwarf<R> {
}
}
+ let lines = LazyCell::new();
+ if !have_unit_range {
+ // The unit did not declare any ranges.
+ // Try to get some ranges from the line program sequences.
+ if let Some(ref ilnp) = dw_unit.line_program {
+ if let Ok(lines) = lines
+ .borrow_with(|| Lines::parse(&dw_unit, ilnp.clone(), &*sections))
+ .as_ref()
+ {
+ for sequence in lines.sequences.iter() {
+ unit_ranges.push(UnitRange {
+ range: gimli::Range {
+ begin: sequence.start,
+ end: sequence.end,
+ },
+ unit_id,
+ max_end: 0,
+ })
+ }
+ }
+ }
+ }
+
res_units.push(ResUnit {
offset,
dw_unit,
lang,
- lines: LazyCell::new(),
+ lines,
funcs: LazyCell::new(),
});
}
@@ -531,6 +562,111 @@ struct Lines {
sequences: Box<[LineSequence]>,
}
+impl Lines {
+ fn parse<R: gimli::Reader>(
+ dw_unit: &gimli::Unit<R>,
+ ilnp: gimli::IncompleteLineProgram<R, R::Offset>,
+ sections: &gimli::Dwarf<R>,
+ ) -> Result<Self, Error> {
+ let mut sequences = Vec::new();
+ let mut sequence_rows = Vec::<LineRow>::new();
+ let mut rows = ilnp.rows();
+ while let Some((_, row)) = rows.next_row()? {
+ if row.end_sequence() {
+ if let Some(start) = sequence_rows.first().map(|x| x.address) {
+ let end = row.address();
+ let mut rows = Vec::new();
+ mem::swap(&mut rows, &mut sequence_rows);
+ sequences.push(LineSequence {
+ start,
+ end,
+ rows: rows.into_boxed_slice(),
+ });
+ }
+ continue;
+ }
+
+ let address = row.address();
+ let file_index = row.file_index();
+ let line = row.line().map(NonZeroU64::get).unwrap_or(0) as u32;
+ let column = match row.column() {
+ gimli::ColumnType::LeftEdge => 0,
+ gimli::ColumnType::Column(x) => x.get() as u32,
+ };
+
+ if let Some(last_row) = sequence_rows.last_mut() {
+ if last_row.address == address {
+ last_row.file_index = file_index;
+ last_row.line = line;
+ last_row.column = column;
+ continue;
+ }
+ }
+
+ sequence_rows.push(LineRow {
+ address,
+ file_index,
+ line,
+ column,
+ });
+ }
+ sequences.sort_by_key(|x| x.start);
+
+ let mut files = Vec::new();
+ let header = rows.header();
+ match header.file(0) {
+ Some(file) => files.push(render_file(dw_unit, file, header, sections)?),
+ None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index
+ }
+ let mut index = 1;
+ while let Some(file) = header.file(index) {
+ files.push(render_file(dw_unit, file, header, sections)?);
+ index += 1;
+ }
+
+ Ok(Self {
+ files: files.into_boxed_slice(),
+ sequences: sequences.into_boxed_slice(),
+ })
+ }
+}
+
+fn render_file<R: gimli::Reader>(
+ dw_unit: &gimli::Unit<R>,
+ file: &gimli::FileEntry<R, R::Offset>,
+ header: &gimli::LineProgramHeader<R, R::Offset>,
+ sections: &gimli::Dwarf<R>,
+) -> Result<String, gimli::Error> {
+ let mut path = if let Some(ref comp_dir) = dw_unit.comp_dir {
+ comp_dir.to_string_lossy()?.into_owned()
+ } else {
+ String::new()
+ };
+
+ // The directory index 0 is defined to correspond to the compilation unit directory.
+ if file.directory_index() != 0 {
+ if let Some(directory) = file.directory(header) {
+ path_push(
+ &mut path,
+ sections
+ .attr_string(dw_unit, directory)?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+ }
+ }
+
+ path_push(
+ &mut path,
+ sections
+ .attr_string(dw_unit, file.path_name())?
+ .to_string_lossy()?
+ .as_ref(),
+ );
+
+ Ok(path)
+}
+
struct LineSequence {
start: u64,
end: u64,
@@ -559,68 +695,7 @@ impl<R: gimli::Reader> ResUnit<R> {
None => return Ok(None),
};
self.lines
- .borrow_with(|| {
- let mut sequences = Vec::new();
- let mut sequence_rows = Vec::<LineRow>::new();
- let mut rows = ilnp.clone().rows();
- while let Some((_, row)) = rows.next_row()? {
- if row.end_sequence() {
- if let Some(start) = sequence_rows.first().map(|x| x.address) {
- let end = row.address();
- let mut rows = Vec::new();
- mem::swap(&mut rows, &mut sequence_rows);
- sequences.push(LineSequence {
- start,
- end,
- rows: rows.into_boxed_slice(),
- });
- }
- continue;
- }
-
- let address = row.address();
- let file_index = row.file_index();
- let line = row.line().map(NonZeroU64::get).unwrap_or(0) as u32;
- let column = match row.column() {
- gimli::ColumnType::LeftEdge => 0,
- gimli::ColumnType::Column(x) => x.get() as u32,
- };
-
- if let Some(last_row) = sequence_rows.last_mut() {
- if last_row.address == address {
- last_row.file_index = file_index;
- last_row.line = line;
- last_row.column = column;
- continue;
- }
- }
-
- sequence_rows.push(LineRow {
- address,
- file_index,
- line,
- column,
- });
- }
- sequences.sort_by_key(|x| x.start);
-
- let mut files = Vec::new();
- let header = ilnp.header();
- match header.file(0) {
- Some(file) => files.push(self.render_file(file, header, sections)?),
- None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index
- }
- let mut index = 1;
- while let Some(file) = header.file(index) {
- files.push(self.render_file(file, header, sections)?);
- index += 1;
- }
-
- Ok(Lines {
- files: files.into_boxed_slice(),
- sequences: sequences.into_boxed_slice(),
- })
- })
+ .borrow_with(|| Lines::parse(&self.dw_unit, ilnp.clone(), sections))
.as_ref()
.map(Some)
.map_err(Error::clone)
@@ -688,39 +763,6 @@ impl<R: gimli::Reader> ResUnit<R> {
let location = self.find_location(probe, &dwarf.sections)?;
Ok((function, location))
}
-
- fn render_file(
- &self,
- file: &gimli::FileEntry<R, R::Offset>,
- header: &gimli::LineProgramHeader<R, R::Offset>,
- sections: &gimli::Dwarf<R>,
- ) -> Result<String, gimli::Error> {
- let mut path = if let Some(ref comp_dir) = self.dw_unit.comp_dir {
- comp_dir.to_string_lossy()?.into_owned()
- } else {
- String::new()
- };
-
- if let Some(directory) = file.directory(header) {
- path_push(
- &mut path,
- sections
- .attr_string(&self.dw_unit, directory)?
- .to_string_lossy()?
- .as_ref(),
- );
- }
-
- path_push(
- &mut path,
- sections
- .attr_string(&self.dw_unit, file.path_name())?
- .to_string_lossy()?
- .as_ref(),
- );
-
- Ok(path)
- }
}
/// Iterator over `Location`s in a range of addresses, returned by `Context::find_location_range`.
@@ -928,7 +970,7 @@ fn path_push(path: &mut String, p: &str) {
'/'
};
- if !path.ends_with(dir_separator) {
+ if !path.is_empty() && !path.ends_with(dir_separator) {
path.push(dir_separator);
}
*path += p;