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