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