1 #![cfg(all(feature = "read", feature = "std", feature = "endian-reader"))]
2
3 use gimli::{
4 AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine,
5 DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr,
6 Encoding, EndianSlice, Expression, LittleEndian, LocationLists, Operation, RangeLists,
7 RangeListsOffset, Reader,
8 };
9 use std::collections::hash_map::HashMap;
10 use std::env;
11 use std::fs::File;
12 use std::io::Read;
13 use std::path::PathBuf;
14 use std::rc::Rc;
15
read_section(section: &str) -> Vec<u8>16 fn read_section(section: &str) -> Vec<u8> {
17 let mut path = PathBuf::new();
18 if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") {
19 path.push(dir);
20 }
21 path.push("fixtures/self");
22 path.push(section);
23
24 println!("Reading section \"{}\" at path {:?}", section, path);
25 assert!(path.is_file());
26 let mut file = File::open(path).unwrap();
27
28 let mut buf = Vec::new();
29 file.read_to_end(&mut buf).unwrap();
30 buf
31 }
32
parse_expression<R: Reader>(expr: Expression<R>, encoding: Encoding)33 fn parse_expression<R: Reader>(expr: Expression<R>, encoding: Encoding) {
34 let mut pc = expr.0.clone();
35 while !pc.is_empty() {
36 Operation::parse(&mut pc, encoding).expect("Should parse operation");
37 }
38
39 // Also attempt to evaluate some of it.
40 let mut eval = expr.evaluation(encoding);
41 eval.set_initial_value(0);
42 eval.evaluate().expect("Should evaluate expression");
43 }
44
impl_parse_self_debug_info<R: gimli::Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, )45 fn impl_parse_self_debug_info<R: gimli::Reader>(
46 debug_info: &DebugInfo<R>,
47 debug_abbrev: &DebugAbbrev<R>,
48 ) {
49 let mut iter = debug_info.units();
50 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
51 let abbrevs = unit
52 .abbreviations(&debug_abbrev)
53 .expect("Should parse abbreviations");
54
55 let mut cursor = unit.entries(&abbrevs);
56
57 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
58 let entry = cursor.current().expect("Should have a current entry");
59
60 let mut attrs = entry.attrs();
61 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
62 if let AttributeValue::Exprloc(expression) = attr.value() {
63 parse_expression(expression, unit.encoding());
64 }
65 }
66 }
67 }
68 }
69
70 #[test]
test_parse_self_debug_info()71 fn test_parse_self_debug_info() {
72 let debug_info = read_section("debug_info");
73 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
74
75 let debug_abbrev = read_section("debug_abbrev");
76 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
77
78 impl_parse_self_debug_info(&debug_info, &debug_abbrev);
79 }
80
81 #[test]
test_parse_self_debug_info_with_endian_rc_slice()82 fn test_parse_self_debug_info_with_endian_rc_slice() {
83 let debug_info = read_section("debug_info");
84 let debug_info = Rc::from(&debug_info[..]);
85 let debug_info = gimli::EndianRcSlice::new(debug_info, LittleEndian);
86 let debug_info = DebugInfo::from(debug_info);
87
88 let debug_abbrev = read_section("debug_abbrev");
89 let debug_abbrev = Rc::from(&debug_abbrev[..]);
90 let debug_abbrev = gimli::EndianRcSlice::new(debug_abbrev, LittleEndian);
91 let debug_abbrev = DebugAbbrev::from(debug_abbrev);
92
93 impl_parse_self_debug_info(&debug_info, &debug_abbrev);
94 }
95
96 #[test]
test_parse_self_debug_line()97 fn test_parse_self_debug_line() {
98 let debug_info = read_section("debug_info");
99 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
100
101 let debug_abbrev = read_section("debug_abbrev");
102 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
103
104 let debug_line = read_section("debug_line");
105 let debug_line = DebugLine::new(&debug_line, LittleEndian);
106
107 let debug_str = read_section("debug_str");
108 let debug_str = DebugStr::new(&debug_str, LittleEndian);
109
110 let mut iter = debug_info.units();
111 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
112 let abbrevs = unit
113 .abbreviations(&debug_abbrev)
114 .expect("Should parse abbreviations");
115
116 let mut cursor = unit.entries(&abbrevs);
117 cursor.next_dfs().expect("Should parse next dfs");
118
119 let unit_entry = cursor.current().expect("Should have a root entry");
120
121 let comp_dir = unit_entry
122 .attr_value(gimli::DW_AT_comp_dir)
123 .expect("Should parse comp_dir attribute")
124 .and_then(|val| val.string_value(&debug_str));
125 let comp_name = unit_entry
126 .attr_value(gimli::DW_AT_name)
127 .expect("Should parse name attribute")
128 .and_then(|val| val.string_value(&debug_str));
129
130 if let Some(AttributeValue::DebugLineRef(offset)) = unit_entry
131 .attr_value(gimli::DW_AT_stmt_list)
132 .expect("Should parse stmt_list")
133 {
134 let program = debug_line
135 .program(offset, unit.address_size(), comp_dir, comp_name)
136 .expect("should parse line number program header");
137
138 let mut results = Vec::new();
139 let mut rows = program.rows();
140 while let Some((_, row)) = rows
141 .next_row()
142 .expect("Should parse and execute all rows in the line number program")
143 {
144 results.push(*row);
145 }
146 results.reverse();
147
148 let program = debug_line
149 .program(offset, unit.address_size(), comp_dir, comp_name)
150 .expect("should parse line number program header");
151 let (program, sequences) = program
152 .sequences()
153 .expect("should parse and execute the entire line number program");
154 assert!(!sequences.is_empty()); // Should be at least one sequence.
155 for sequence in sequences {
156 let mut rows = program.resume_from(&sequence);
157 while let Some((_, row)) = rows
158 .next_row()
159 .expect("Should parse and execute all rows after resuming")
160 {
161 let other_row = results.pop().unwrap();
162 assert!(row.address() >= sequence.start);
163 assert!(row.address() <= sequence.end);
164 assert_eq!(row.address(), other_row.address());
165 assert_eq!(row.line(), other_row.line());
166 }
167 }
168 assert!(results.is_empty());
169 }
170 }
171 }
172
173 #[test]
test_parse_self_debug_loc()174 fn test_parse_self_debug_loc() {
175 let debug_info = read_section("debug_info");
176 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
177
178 let debug_abbrev = read_section("debug_abbrev");
179 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
180
181 let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
182 let debug_addr_base = DebugAddrBase(0);
183
184 let debug_loc = read_section("debug_loc");
185 let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
186 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
187 let loclists = LocationLists::new(debug_loc, debug_loclists);
188
189 let mut iter = debug_info.units();
190 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
191 let abbrevs = unit
192 .abbreviations(&debug_abbrev)
193 .expect("Should parse abbreviations");
194
195 let mut cursor = unit.entries(&abbrevs);
196 cursor.next_dfs().expect("Should parse next dfs");
197
198 let mut low_pc = 0;
199
200 {
201 let unit_entry = cursor.current().expect("Should have a root entry");
202 let low_pc_attr = unit_entry
203 .attr_value(gimli::DW_AT_low_pc)
204 .expect("Should parse low_pc");
205 if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
206 low_pc = address;
207 }
208 }
209
210 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
211 let entry = cursor.current().expect("Should have a current entry");
212 let mut attrs = entry.attrs();
213 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
214 if let AttributeValue::LocationListsRef(offset) = attr.value() {
215 let mut locs = loclists
216 .locations(
217 offset,
218 unit.encoding(),
219 low_pc,
220 &debug_addr,
221 debug_addr_base,
222 )
223 .expect("Should parse locations OK");
224 while let Some(loc) = locs.next().expect("Should parse next location") {
225 assert!(loc.range.begin <= loc.range.end);
226 parse_expression(loc.data, unit.encoding());
227 }
228 }
229 }
230 }
231 }
232 }
233
234 #[test]
test_parse_self_debug_ranges()235 fn test_parse_self_debug_ranges() {
236 let debug_info = read_section("debug_info");
237 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
238
239 let debug_abbrev = read_section("debug_abbrev");
240 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
241
242 let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
243 let debug_addr_base = DebugAddrBase(0);
244
245 let debug_ranges = read_section("debug_ranges");
246 let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian);
247 let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
248 let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
249
250 let mut iter = debug_info.units();
251 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
252 let abbrevs = unit
253 .abbreviations(&debug_abbrev)
254 .expect("Should parse abbreviations");
255
256 let mut cursor = unit.entries(&abbrevs);
257 cursor.next_dfs().expect("Should parse next dfs");
258
259 let mut low_pc = 0;
260
261 {
262 let unit_entry = cursor.current().expect("Should have a root entry");
263 let low_pc_attr = unit_entry
264 .attr_value(gimli::DW_AT_low_pc)
265 .expect("Should parse low_pc");
266 if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
267 low_pc = address;
268 }
269 }
270
271 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
272 let entry = cursor.current().expect("Should have a current entry");
273 let mut attrs = entry.attrs();
274 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
275 if let AttributeValue::RangeListsRef(offset) = attr.value() {
276 let mut ranges = rnglists
277 .ranges(
278 RangeListsOffset(offset.0),
279 unit.encoding(),
280 low_pc,
281 &debug_addr,
282 debug_addr_base,
283 )
284 .expect("Should parse ranges OK");
285 while let Some(range) = ranges.next().expect("Should parse next range") {
286 assert!(range.begin <= range.end);
287 }
288 }
289 }
290 }
291 }
292 }
293
294 #[test]
test_parse_self_debug_aranges()295 fn test_parse_self_debug_aranges() {
296 let debug_aranges = read_section("debug_aranges");
297 let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian);
298
299 let mut headers = debug_aranges.headers();
300 while let Some(header) = headers.next().expect("Should parse arange header OK") {
301 let mut entries = header.entries();
302 while let Some(_) = entries.next().expect("Should parse arange entry OK") {
303 // Not really anything else we can check right now.
304 }
305 }
306 }
307
308 #[test]
test_parse_self_debug_pubnames()309 fn test_parse_self_debug_pubnames() {
310 let debug_info = read_section("debug_info");
311 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
312
313 let debug_abbrev = read_section("debug_abbrev");
314 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
315
316 let debug_pubnames = read_section("debug_pubnames");
317 let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian);
318
319 let mut units = HashMap::new();
320 let mut abbrevs = HashMap::new();
321 let mut pubnames = debug_pubnames.items();
322 while let Some(entry) = pubnames.next().expect("Should parse pubname OK") {
323 let unit_offset = entry.unit_header_offset();
324 let unit = units.entry(unit_offset).or_insert_with(|| {
325 debug_info
326 .header_from_offset(unit_offset)
327 .expect("Should parse unit header OK")
328 });
329 let abbrev_offset = unit.debug_abbrev_offset();
330 let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| {
331 debug_abbrev
332 .abbreviations(abbrev_offset)
333 .expect("Should parse abbreviations OK")
334 });
335 let mut cursor = unit
336 .entries_at_offset(abbrevs, entry.die_offset())
337 .expect("DIE offset should be valid");
338 assert!(cursor.next_dfs().expect("Should parse DIE").is_some());
339 }
340 }
341
342 #[test]
test_parse_self_debug_pubtypes()343 fn test_parse_self_debug_pubtypes() {
344 let debug_info = read_section("debug_info");
345 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
346
347 let debug_abbrev = read_section("debug_abbrev");
348 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
349
350 let debug_pubtypes = read_section("debug_pubtypes");
351 let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian);
352
353 let mut units = HashMap::new();
354 let mut abbrevs = HashMap::new();
355 let mut pubtypes = debug_pubtypes.items();
356 while let Some(entry) = pubtypes.next().expect("Should parse pubtype OK") {
357 let unit_offset = entry.unit_header_offset();
358 let unit = units.entry(unit_offset).or_insert_with(|| {
359 debug_info
360 .header_from_offset(unit_offset)
361 .expect("Should parse unit header OK")
362 });
363 let abbrev_offset = unit.debug_abbrev_offset();
364 let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| {
365 debug_abbrev
366 .abbreviations(abbrev_offset)
367 .expect("Should parse abbreviations OK")
368 });
369 let mut cursor = unit
370 .entries_at_offset(abbrevs, entry.die_offset())
371 .expect("DIE offset should be valid");
372 assert!(cursor.next_dfs().expect("Should parse DIE").is_some());
373 }
374 }
375
376 #[test]
test_parse_self_eh_frame()377 fn test_parse_self_eh_frame() {
378 use gimli::{BaseAddresses, CieOrFde, EhFrame, UnwindSection};
379
380 let eh_frame = read_section("eh_frame");
381 let mut eh_frame = EhFrame::new(&eh_frame, LittleEndian);
382 // The `.eh_frame` fixture data was created on a 64-bit machine.
383 eh_frame.set_address_size(8);
384
385 let bases = BaseAddresses::default()
386 .set_eh_frame(0)
387 .set_text(0)
388 .set_got(0);
389 let mut entries = eh_frame.entries(&bases);
390 while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
391 match entry {
392 CieOrFde::Cie(cie) => {
393 let mut instrs = cie.instructions(&eh_frame, &bases);
394 while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") {
395 // TODO FITZGEN
396 }
397 }
398 CieOrFde::Fde(partial) => {
399 let fde = partial
400 .parse(UnwindSection::cie_from_offset)
401 .expect("Should be able to get CIE for FDE");
402
403 let mut instrs = fde.instructions(&eh_frame, &bases);
404 while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") {
405 // TODO FITZGEN
406 }
407 }
408 }
409 }
410 }
411
412 #[test]
test_parse_self_eh_frame_hdr()413 fn test_parse_self_eh_frame_hdr() {
414 use gimli::{BaseAddresses, EhFrameHdr};
415
416 let eh_frame_hdr = read_section("eh_frame_hdr");
417 let eh_frame_hdr = EhFrameHdr::new(&eh_frame_hdr, LittleEndian);
418
419 let bases = BaseAddresses::default()
420 .set_eh_frame(0)
421 .set_eh_frame_hdr(0)
422 .set_text(0)
423 .set_got(0);
424
425 // `.eh_frame_hdr` was generated on a 64 bit machine.
426 let address_size = 8;
427
428 let _parsed_header = eh_frame_hdr
429 .parse(&bases, address_size)
430 .expect("we can parse the `.eh_frame_hdr` section OK");
431 }
432