blazesym/dwarf/location.rs
1// Based on gimli-rs/addr2line (https://github.com/gimli-rs/addr2line):
2// > Copyright (c) 2016-2018 The gimli Developers
3// >
4// > Permission is hereby granted, free of charge, to any
5// > person obtaining a copy of this software and associated
6// > documentation files (the "Software"), to deal in the
7// > Software without restriction, including without
8// > limitation the rights to use, copy, modify, merge,
9// > publish, distribute, sublicense, and/or sell copies of
10// > the Software, and to permit persons to whom the Software
11// > is furnished to do so, subject to the following
12// > conditions:
13// >
14// > The above copyright notice and this permission notice
15// > shall be included in all copies or substantial portions
16// > of the Software.
17// >
18// > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
19// > ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
20// > TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
21// > PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
22// > SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23// > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24// > OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
25// > IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26// > DEALINGS IN THE SOFTWARE.
27
28use std::cmp::Ordering;
29use std::ffi::OsStr;
30use std::path::Path;
31
32use super::lines::LineSequence;
33use super::lines::Lines;
34use super::unit::Unit;
35use super::units::Units;
36
37
38/// A source location.
39#[derive(Debug, PartialEq)]
40pub struct Location<'dwarf> {
41 /// The directory.
42 pub dir: &'dwarf Path,
43 /// The file name.
44 pub file: &'dwarf OsStr,
45 /// The line number.
46 pub line: Option<u32>,
47 /// The column number.
48 pub column: Option<u32>,
49}
50
51
52pub(super) struct LocationRangeUnitIter<'unit, 'dwarf> {
53 lines: &'unit Lines<'dwarf>,
54 seqs: &'unit [LineSequence],
55 seq_idx: usize,
56 row_idx: usize,
57 probe_high: u64,
58}
59
60impl<'unit, 'dwarf> LocationRangeUnitIter<'unit, 'dwarf> {
61 pub(super) fn new(
62 unit: &'unit Unit<'dwarf>,
63 units: &Units<'dwarf>,
64 probe_low: u64,
65 probe_high: u64,
66 ) -> Result<Option<Self>, gimli::Error> {
67 let unit_ref = units.unit_ref(unit.dw_unit());
68 let lines = unit.parse_lines(unit_ref)?;
69
70 if let Some(lines) = lines {
71 // Find index for probe_low.
72 let seq_idx = lines.sequences.binary_search_by(|sequence| {
73 if probe_low < sequence.start {
74 Ordering::Greater
75 } else if probe_low >= sequence.end {
76 Ordering::Less
77 } else {
78 Ordering::Equal
79 }
80 });
81 let seq_idx = match seq_idx {
82 Ok(x) => x,
83 Err(0) => 0, // probe below sequence, but range could overlap
84 Err(_) => lines.sequences.len(),
85 };
86
87 let row_idx = if let Some(seq) = lines.sequences.get(seq_idx) {
88 let idx = seq.rows.binary_search_by(|row| row.address.cmp(&probe_low));
89 match idx {
90 Ok(x) => x,
91 Err(0) => 0, // probe below sequence, but range could overlap
92 Err(x) => x - 1,
93 }
94 } else {
95 0
96 };
97
98 Ok(Some(Self {
99 lines,
100 seqs: &*lines.sequences,
101 seq_idx,
102 row_idx,
103 probe_high,
104 }))
105 } else {
106 Ok(None)
107 }
108 }
109}
110
111impl<'unit> Iterator for LocationRangeUnitIter<'unit, '_> {
112 type Item = (u64, u64, Location<'unit>);
113
114 fn next(&mut self) -> Option<(u64, u64, Location<'unit>)> {
115 while let Some(seq) = self.seqs.get(self.seq_idx) {
116 if seq.start >= self.probe_high {
117 break
118 }
119
120 match seq.rows.get(self.row_idx) {
121 Some(row) => {
122 if row.address >= self.probe_high {
123 break
124 }
125
126 // SANITY: We always have a file present for each
127 // `file_index`.
128 let (dir, file) = self.lines.files.get(row.file_index as usize).unwrap();
129 let nextaddr = seq
130 .rows
131 .get(self.row_idx + 1)
132 .map(|row| row.address)
133 .unwrap_or(seq.end);
134
135 let item = (
136 row.address,
137 nextaddr - row.address,
138 Location {
139 dir,
140 file,
141 line: if row.line != 0 { Some(row.line) } else { None },
142 column: if row.column != 0 {
143 Some(row.column)
144 } else {
145 None
146 },
147 },
148 );
149 self.row_idx += 1;
150
151 return Some(item)
152 }
153 None => {
154 self.seq_idx += 1;
155 self.row_idx = 0;
156 }
157 }
158 }
159 None
160 }
161}