1 #![feature(test)]
2 
3 extern crate test;
4 
5 use gimli::{
6     AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine,
7     DebugLineOffset, DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges,
8     DebugRngLists, Encoding, EndianSlice, EntriesTreeNode, Expression, LittleEndian, LocationLists,
9     Operation, RangeLists, RangeListsOffset, Reader, ReaderOffset,
10 };
11 use std::env;
12 use std::fs::File;
13 use std::io::Read;
14 use std::path::PathBuf;
15 use std::rc::Rc;
16 
read_section(section: &str) -> Vec<u8>17 pub fn read_section(section: &str) -> Vec<u8> {
18     let mut path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into()));
19     path.push("./fixtures/self/");
20     path.push(section);
21 
22     assert!(path.is_file());
23     let mut file = File::open(path).unwrap();
24 
25     let mut buf = Vec::new();
26     file.read_to_end(&mut buf).unwrap();
27     buf
28 }
29 
30 #[bench]
bench_parsing_debug_abbrev(b: &mut test::Bencher)31 fn bench_parsing_debug_abbrev(b: &mut test::Bencher) {
32     let debug_info = read_section("debug_info");
33     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
34     let unit = debug_info
35         .units()
36         .next()
37         .expect("Should have at least one compilation unit")
38         .expect("And it should parse OK");
39 
40     let debug_abbrev = read_section("debug_abbrev");
41 
42     b.iter(|| {
43         let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
44         test::black_box(
45             unit.abbreviations(&debug_abbrev)
46                 .expect("Should parse abbreviations"),
47         );
48     });
49 }
50 
51 #[inline]
impl_bench_parsing_debug_info<R: Reader>( debug_info: DebugInfo<R>, debug_abbrev: DebugAbbrev<R>, )52 fn impl_bench_parsing_debug_info<R: Reader>(
53     debug_info: DebugInfo<R>,
54     debug_abbrev: DebugAbbrev<R>,
55 ) {
56     let mut iter = debug_info.units();
57     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
58         let abbrevs = unit
59             .abbreviations(&debug_abbrev)
60             .expect("Should parse abbreviations");
61 
62         let mut cursor = unit.entries(&abbrevs);
63         while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") {
64             let mut attrs = entry.attrs();
65             loop {
66                 match attrs.next() {
67                     Ok(Some(ref attr)) => {
68                         test::black_box(attr);
69                     }
70                     Ok(None) => break,
71                     e @ Err(_) => {
72                         e.expect("Should parse entry's attribute");
73                     }
74                 }
75             }
76         }
77     }
78 }
79 
80 #[bench]
bench_parsing_debug_info(b: &mut test::Bencher)81 fn bench_parsing_debug_info(b: &mut test::Bencher) {
82     let debug_info = read_section("debug_info");
83     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
84 
85     let debug_abbrev = read_section("debug_abbrev");
86     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
87 
88     b.iter(|| impl_bench_parsing_debug_info(debug_info, debug_abbrev));
89 }
90 
91 #[bench]
bench_parsing_debug_info_with_endian_rc_slice(b: &mut test::Bencher)92 fn bench_parsing_debug_info_with_endian_rc_slice(b: &mut test::Bencher) {
93     let debug_info = read_section("debug_info");
94     let debug_info = Rc::from(&debug_info[..]);
95     let debug_info = gimli::EndianRcSlice::new(debug_info, LittleEndian);
96     let debug_info = DebugInfo::from(debug_info);
97 
98     let debug_abbrev = read_section("debug_abbrev");
99     let debug_abbrev = Rc::from(&debug_abbrev[..]);
100     let debug_abbrev = gimli::EndianRcSlice::new(debug_abbrev, LittleEndian);
101     let debug_abbrev = DebugAbbrev::from(debug_abbrev);
102 
103     b.iter(|| impl_bench_parsing_debug_info(debug_info.clone(), debug_abbrev.clone()));
104 }
105 
106 #[bench]
bench_parsing_debug_info_tree(b: &mut test::Bencher)107 fn bench_parsing_debug_info_tree(b: &mut test::Bencher) {
108     let debug_abbrev = read_section("debug_abbrev");
109     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
110 
111     let debug_info = read_section("debug_info");
112 
113     b.iter(|| {
114         let debug_info = DebugInfo::new(&debug_info, LittleEndian);
115 
116         let mut iter = debug_info.units();
117         while let Some(unit) = iter.next().expect("Should parse compilation unit") {
118             let abbrevs = unit
119                 .abbreviations(&debug_abbrev)
120                 .expect("Should parse abbreviations");
121 
122             let mut tree = unit
123                 .entries_tree(&abbrevs, None)
124                 .expect("Should have entries tree");
125             let root = tree.root().expect("Should parse root entry");
126             parse_debug_info_tree(root);
127         }
128     });
129 }
130 
parse_debug_info_tree<R: Reader>(node: EntriesTreeNode<R>)131 fn parse_debug_info_tree<R: Reader>(node: EntriesTreeNode<R>) {
132     {
133         let mut attrs = node.entry().attrs();
134         loop {
135             match attrs.next() {
136                 Ok(Some(ref attr)) => {
137                     test::black_box(attr);
138                 }
139                 Ok(None) => break,
140                 e @ Err(_) => {
141                     e.expect("Should parse entry's attribute");
142                 }
143             }
144         }
145     }
146     let mut children = node.children();
147     while let Some(child) = children.next().expect("Should parse child entry") {
148         parse_debug_info_tree(child);
149     }
150 }
151 
152 #[bench]
bench_parsing_debug_info_raw(b: &mut test::Bencher)153 fn bench_parsing_debug_info_raw(b: &mut test::Bencher) {
154     let debug_abbrev = read_section("debug_abbrev");
155     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
156 
157     let debug_info = read_section("debug_info");
158 
159     b.iter(|| {
160         let debug_info = DebugInfo::new(&debug_info, LittleEndian);
161 
162         let mut iter = debug_info.units();
163         while let Some(unit) = iter.next().expect("Should parse compilation unit") {
164             let abbrevs = unit
165                 .abbreviations(&debug_abbrev)
166                 .expect("Should parse abbreviations");
167 
168             let mut raw = unit
169                 .entries_raw(&abbrevs, None)
170                 .expect("Should have entries");
171             while !raw.is_empty() {
172                 if let Some(abbrev) = raw
173                     .read_abbreviation()
174                     .expect("Should parse abbreviation code")
175                 {
176                     for spec in abbrev.attributes().iter().cloned() {
177                         match raw.read_attribute(spec) {
178                             Ok(ref attr) => {
179                                 test::black_box(attr);
180                             }
181                             e @ Err(_) => {
182                                 e.expect("Should parse attribute");
183                             }
184                         }
185                     }
186                 }
187             }
188         }
189     });
190 }
191 
192 #[bench]
bench_parsing_debug_aranges(b: &mut test::Bencher)193 fn bench_parsing_debug_aranges(b: &mut test::Bencher) {
194     let debug_aranges = read_section("debug_aranges");
195     let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian);
196 
197     b.iter(|| {
198         let mut headers = debug_aranges.headers();
199         while let Some(header) = headers.next().expect("Should parse arange header OK") {
200             let mut entries = header.entries();
201             while let Some(arange) = entries.next().expect("Should parse arange entry OK") {
202                 test::black_box(arange);
203             }
204         }
205     });
206 }
207 
208 #[bench]
bench_parsing_debug_pubnames(b: &mut test::Bencher)209 fn bench_parsing_debug_pubnames(b: &mut test::Bencher) {
210     let debug_pubnames = read_section("debug_pubnames");
211     let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian);
212 
213     b.iter(|| {
214         let mut pubnames = debug_pubnames.items();
215         while let Some(pubname) = pubnames.next().expect("Should parse pubname OK") {
216             test::black_box(pubname);
217         }
218     });
219 }
220 
221 #[bench]
bench_parsing_debug_pubtypes(b: &mut test::Bencher)222 fn bench_parsing_debug_pubtypes(b: &mut test::Bencher) {
223     let debug_pubtypes = read_section("debug_pubtypes");
224     let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian);
225 
226     b.iter(|| {
227         let mut pubtypes = debug_pubtypes.items();
228         while let Some(pubtype) = pubtypes.next().expect("Should parse pubtype OK") {
229             test::black_box(pubtype);
230         }
231     });
232 }
233 
234 // We happen to know that there is a line number program and header at
235 // offset 0 and that address size is 8 bytes. No need to parse DIEs to grab
236 // this info off of the compilation units.
237 const OFFSET: DebugLineOffset = DebugLineOffset(0);
238 const ADDRESS_SIZE: u8 = 8;
239 
240 #[bench]
bench_parsing_line_number_program_opcodes(b: &mut test::Bencher)241 fn bench_parsing_line_number_program_opcodes(b: &mut test::Bencher) {
242     let debug_line = read_section("debug_line");
243     let debug_line = DebugLine::new(&debug_line, LittleEndian);
244 
245     b.iter(|| {
246         let program = debug_line
247             .program(OFFSET, ADDRESS_SIZE, None, None)
248             .expect("Should parse line number program header");
249         let header = program.header();
250 
251         let mut instructions = header.instructions();
252         while let Some(instruction) = instructions
253             .next_instruction(header)
254             .expect("Should parse instruction")
255         {
256             test::black_box(instruction);
257         }
258     });
259 }
260 
261 #[bench]
bench_executing_line_number_programs(b: &mut test::Bencher)262 fn bench_executing_line_number_programs(b: &mut test::Bencher) {
263     let debug_line = read_section("debug_line");
264     let debug_line = DebugLine::new(&debug_line, LittleEndian);
265 
266     b.iter(|| {
267         let program = debug_line
268             .program(OFFSET, ADDRESS_SIZE, None, None)
269             .expect("Should parse line number program header");
270 
271         let mut rows = program.rows();
272         while let Some(row) = rows
273             .next_row()
274             .expect("Should parse and execute all rows in the line number program")
275         {
276             test::black_box(row);
277         }
278     });
279 }
280 
281 #[bench]
bench_parsing_debug_loc(b: &mut test::Bencher)282 fn bench_parsing_debug_loc(b: &mut test::Bencher) {
283     let debug_info = read_section("debug_info");
284     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
285 
286     let debug_abbrev = read_section("debug_abbrev");
287     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
288 
289     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
290     let debug_addr_base = DebugAddrBase(0);
291 
292     let debug_loc = read_section("debug_loc");
293     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
294     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
295     let loclists = LocationLists::new(debug_loc, debug_loclists);
296 
297     let mut offsets = Vec::new();
298 
299     let mut iter = debug_info.units();
300     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
301         let abbrevs = unit
302             .abbreviations(&debug_abbrev)
303             .expect("Should parse abbreviations");
304 
305         let mut cursor = unit.entries(&abbrevs);
306         cursor.next_dfs().expect("Should parse next dfs");
307 
308         let mut low_pc = 0;
309 
310         {
311             let unit_entry = cursor.current().expect("Should have a root entry");
312             let low_pc_attr = unit_entry
313                 .attr_value(gimli::DW_AT_low_pc)
314                 .expect("Should parse low_pc");
315             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
316                 low_pc = address;
317             }
318         }
319 
320         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
321             let entry = cursor.current().expect("Should have a current entry");
322             let mut attrs = entry.attrs();
323             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
324                 if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() {
325                     offsets.push((offset, unit.encoding(), low_pc));
326                 }
327             }
328         }
329     }
330 
331     b.iter(|| {
332         for &(offset, encoding, base_address) in &*offsets {
333             let mut locs = loclists
334                 .locations(offset, encoding, base_address, &debug_addr, debug_addr_base)
335                 .expect("Should parse locations OK");
336             while let Some(loc) = locs.next().expect("Should parse next location") {
337                 test::black_box(loc);
338             }
339         }
340     });
341 }
342 
343 #[bench]
bench_parsing_debug_ranges(b: &mut test::Bencher)344 fn bench_parsing_debug_ranges(b: &mut test::Bencher) {
345     let debug_info = read_section("debug_info");
346     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
347 
348     let debug_abbrev = read_section("debug_abbrev");
349     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
350 
351     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
352     let debug_addr_base = DebugAddrBase(0);
353 
354     let debug_ranges = read_section("debug_ranges");
355     let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian);
356     let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
357     let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
358 
359     let mut offsets = Vec::new();
360 
361     let mut iter = debug_info.units();
362     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
363         let abbrevs = unit
364             .abbreviations(&debug_abbrev)
365             .expect("Should parse abbreviations");
366 
367         let mut cursor = unit.entries(&abbrevs);
368         cursor.next_dfs().expect("Should parse next dfs");
369 
370         let mut low_pc = 0;
371 
372         {
373             let unit_entry = cursor.current().expect("Should have a root entry");
374             let low_pc_attr = unit_entry
375                 .attr_value(gimli::DW_AT_low_pc)
376                 .expect("Should parse low_pc");
377             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
378                 low_pc = address;
379             }
380         }
381 
382         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
383             let entry = cursor.current().expect("Should have a current entry");
384             let mut attrs = entry.attrs();
385             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
386                 if let gimli::AttributeValue::RangeListsRef(offset) = attr.value() {
387                     offsets.push((RangeListsOffset(offset.0), unit.encoding(), low_pc));
388                 }
389             }
390         }
391     }
392 
393     b.iter(|| {
394         for &(offset, encoding, base_address) in &*offsets {
395             let mut ranges = rnglists
396                 .ranges(offset, encoding, base_address, &debug_addr, debug_addr_base)
397                 .expect("Should parse ranges OK");
398             while let Some(range) = ranges.next().expect("Should parse next range") {
399                 test::black_box(range);
400             }
401         }
402     });
403 }
404 
debug_info_expressions<R: Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, ) -> Vec<(Expression<R>, Encoding)>405 fn debug_info_expressions<R: Reader>(
406     debug_info: &DebugInfo<R>,
407     debug_abbrev: &DebugAbbrev<R>,
408 ) -> Vec<(Expression<R>, Encoding)> {
409     let mut expressions = Vec::new();
410 
411     let mut iter = debug_info.units();
412     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
413         let abbrevs = unit
414             .abbreviations(debug_abbrev)
415             .expect("Should parse abbreviations");
416 
417         let mut cursor = unit.entries(&abbrevs);
418         while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") {
419             let mut attrs = entry.attrs();
420             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
421                 if let AttributeValue::Exprloc(expression) = attr.value() {
422                     expressions.push((expression, unit.encoding()));
423                 }
424             }
425         }
426     }
427 
428     expressions
429 }
430 
431 #[bench]
bench_parsing_debug_info_expressions(b: &mut test::Bencher)432 fn bench_parsing_debug_info_expressions(b: &mut test::Bencher) {
433     let debug_abbrev = read_section("debug_abbrev");
434     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
435 
436     let debug_info = read_section("debug_info");
437     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
438 
439     let expressions = debug_info_expressions(&debug_info, &debug_abbrev);
440 
441     b.iter(|| {
442         for &(expression, encoding) in &*expressions {
443             let mut pc = expression.0;
444             while !pc.is_empty() {
445                 Operation::parse(&mut pc, encoding).expect("Should parse operation");
446             }
447         }
448     });
449 }
450 
451 #[bench]
bench_evaluating_debug_info_expressions(b: &mut test::Bencher)452 fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) {
453     let debug_abbrev = read_section("debug_abbrev");
454     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
455 
456     let debug_info = read_section("debug_info");
457     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
458 
459     let expressions = debug_info_expressions(&debug_info, &debug_abbrev);
460 
461     b.iter(|| {
462         for &(expression, encoding) in &*expressions {
463             let mut eval = expression.evaluation(encoding);
464             eval.set_initial_value(0);
465             let result = eval.evaluate().expect("Should evaluate expression");
466             test::black_box(result);
467         }
468     });
469 }
470 
debug_loc_expressions<R: Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, debug_addr: &DebugAddr<R>, loclists: &LocationLists<R>, ) -> Vec<(Expression<R>, Encoding)>471 fn debug_loc_expressions<R: Reader>(
472     debug_info: &DebugInfo<R>,
473     debug_abbrev: &DebugAbbrev<R>,
474     debug_addr: &DebugAddr<R>,
475     loclists: &LocationLists<R>,
476 ) -> Vec<(Expression<R>, Encoding)> {
477     let debug_addr_base = DebugAddrBase(R::Offset::from_u8(0));
478 
479     let mut expressions = Vec::new();
480 
481     let mut iter = debug_info.units();
482     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
483         let abbrevs = unit
484             .abbreviations(debug_abbrev)
485             .expect("Should parse abbreviations");
486 
487         let mut cursor = unit.entries(&abbrevs);
488         cursor.next_dfs().expect("Should parse next dfs");
489 
490         let mut low_pc = 0;
491 
492         {
493             let unit_entry = cursor.current().expect("Should have a root entry");
494             let low_pc_attr = unit_entry
495                 .attr_value(gimli::DW_AT_low_pc)
496                 .expect("Should parse low_pc");
497             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
498                 low_pc = address;
499             }
500         }
501 
502         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
503             let entry = cursor.current().expect("Should have a current entry");
504             let mut attrs = entry.attrs();
505             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
506                 if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() {
507                     let mut locs = loclists
508                         .locations(offset, unit.encoding(), low_pc, debug_addr, debug_addr_base)
509                         .expect("Should parse locations OK");
510                     while let Some(loc) = locs.next().expect("Should parse next location") {
511                         expressions.push((loc.data, unit.encoding()));
512                     }
513                 }
514             }
515         }
516     }
517 
518     expressions
519 }
520 
521 #[bench]
bench_parsing_debug_loc_expressions(b: &mut test::Bencher)522 fn bench_parsing_debug_loc_expressions(b: &mut test::Bencher) {
523     let debug_info = read_section("debug_info");
524     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
525 
526     let debug_abbrev = read_section("debug_abbrev");
527     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
528 
529     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
530 
531     let debug_loc = read_section("debug_loc");
532     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
533     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
534     let loclists = LocationLists::new(debug_loc, debug_loclists);
535 
536     let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists);
537 
538     b.iter(|| {
539         for &(expression, encoding) in &*expressions {
540             let mut pc = expression.0;
541             while !pc.is_empty() {
542                 Operation::parse(&mut pc, encoding).expect("Should parse operation");
543             }
544         }
545     });
546 }
547 
548 #[bench]
bench_evaluating_debug_loc_expressions(b: &mut test::Bencher)549 fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) {
550     let debug_info = read_section("debug_info");
551     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
552 
553     let debug_abbrev = read_section("debug_abbrev");
554     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
555 
556     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
557 
558     let debug_loc = read_section("debug_loc");
559     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
560     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
561     let loclists = LocationLists::new(debug_loc, debug_loclists);
562 
563     let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists);
564 
565     b.iter(|| {
566         for &(expression, encoding) in &*expressions {
567             let mut eval = expression.evaluation(encoding);
568             eval.set_initial_value(0);
569             let result = eval.evaluate().expect("Should evaluate expression");
570             test::black_box(result);
571         }
572     });
573 }
574 
575 // See comment above `test_parse_self_eh_frame`.
576 #[cfg(target_pointer_width = "64")]
577 mod cfi {
578     use super::*;
579     use fallible_iterator::FallibleIterator;
580 
581     use gimli::{
582         BaseAddresses, CieOrFde, EhFrame, FrameDescriptionEntry, LittleEndian, UnwindContext,
583         UnwindSection,
584     };
585 
586     #[bench]
iterate_entries_and_do_not_parse_any_fde(b: &mut test::Bencher)587     fn iterate_entries_and_do_not_parse_any_fde(b: &mut test::Bencher) {
588         let eh_frame = read_section("eh_frame");
589         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
590 
591         let bases = BaseAddresses::default()
592             .set_eh_frame(0)
593             .set_got(0)
594             .set_text(0);
595 
596         b.iter(|| {
597             let mut entries = eh_frame.entries(&bases);
598             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
599                 test::black_box(entry);
600             }
601         });
602     }
603 
604     #[bench]
iterate_entries_and_parse_every_fde(b: &mut test::Bencher)605     fn iterate_entries_and_parse_every_fde(b: &mut test::Bencher) {
606         let eh_frame = read_section("eh_frame");
607         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
608 
609         let bases = BaseAddresses::default()
610             .set_eh_frame(0)
611             .set_got(0)
612             .set_text(0);
613 
614         b.iter(|| {
615             let mut entries = eh_frame.entries(&bases);
616             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
617                 match entry {
618                     CieOrFde::Cie(cie) => {
619                         test::black_box(cie);
620                     }
621                     CieOrFde::Fde(partial) => {
622                         let fde = partial
623                             .parse(EhFrame::cie_from_offset)
624                             .expect("Should be able to get CIE for FED");
625                         test::black_box(fde);
626                     }
627                 };
628             }
629         });
630     }
631 
632     #[bench]
iterate_entries_and_parse_every_fde_and_instructions(b: &mut test::Bencher)633     fn iterate_entries_and_parse_every_fde_and_instructions(b: &mut test::Bencher) {
634         let eh_frame = read_section("eh_frame");
635         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
636 
637         let bases = BaseAddresses::default()
638             .set_eh_frame(0)
639             .set_got(0)
640             .set_text(0);
641 
642         b.iter(|| {
643             let mut entries = eh_frame.entries(&bases);
644             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
645                 match entry {
646                     CieOrFde::Cie(cie) => {
647                         let mut instrs = cie.instructions(&eh_frame, &bases);
648                         while let Some(i) =
649                             instrs.next().expect("Can parse next CFI instruction OK")
650                         {
651                             test::black_box(i);
652                         }
653                     }
654                     CieOrFde::Fde(partial) => {
655                         let fde = partial
656                             .parse(EhFrame::cie_from_offset)
657                             .expect("Should be able to get CIE for FED");
658                         let mut instrs = fde.instructions(&eh_frame, &bases);
659                         while let Some(i) =
660                             instrs.next().expect("Can parse next CFI instruction OK")
661                         {
662                             test::black_box(i);
663                         }
664                     }
665                 };
666             }
667         });
668     }
669 
670     #[bench]
iterate_entries_evaluate_every_fde(b: &mut test::Bencher)671     fn iterate_entries_evaluate_every_fde(b: &mut test::Bencher) {
672         let eh_frame = read_section("eh_frame");
673         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
674 
675         let bases = BaseAddresses::default()
676             .set_eh_frame(0)
677             .set_got(0)
678             .set_text(0);
679 
680         let mut ctx = Box::new(UnwindContext::new());
681 
682         b.iter(|| {
683             let mut entries = eh_frame.entries(&bases);
684             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
685                 match entry {
686                     CieOrFde::Cie(_) => {}
687                     CieOrFde::Fde(partial) => {
688                         let fde = partial
689                             .parse(EhFrame::cie_from_offset)
690                             .expect("Should be able to get CIE for FED");
691                         let mut table = fde
692                             .rows(&eh_frame, &bases, &mut ctx)
693                             .expect("Should be able to initialize ctx");
694                         while let Some(row) =
695                             table.next_row().expect("Should get next unwind table row")
696                         {
697                             test::black_box(row);
698                         }
699                     }
700                 };
701             }
702         });
703     }
704 
instrs_len<R: Reader>( eh_frame: &EhFrame<R>, bases: &BaseAddresses, fde: &FrameDescriptionEntry<R>, ) -> usize705     fn instrs_len<R: Reader>(
706         eh_frame: &EhFrame<R>,
707         bases: &BaseAddresses,
708         fde: &FrameDescriptionEntry<R>,
709     ) -> usize {
710         fde.instructions(eh_frame, bases)
711             .fold(0, |count, _| Ok(count + 1))
712             .expect("fold over instructions OK")
713     }
714 
get_fde_with_longest_cfi_instructions<R: Reader>( eh_frame: &EhFrame<R>, bases: &BaseAddresses, ) -> FrameDescriptionEntry<R>715     fn get_fde_with_longest_cfi_instructions<R: Reader>(
716         eh_frame: &EhFrame<R>,
717         bases: &BaseAddresses,
718     ) -> FrameDescriptionEntry<R> {
719         let mut longest: Option<(usize, FrameDescriptionEntry<_>)> = None;
720 
721         let mut entries = eh_frame.entries(bases);
722         while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
723             match entry {
724                 CieOrFde::Cie(_) => {}
725                 CieOrFde::Fde(partial) => {
726                     let fde = partial
727                         .parse(EhFrame::cie_from_offset)
728                         .expect("Should be able to get CIE for FED");
729 
730                     let this_len = instrs_len(eh_frame, bases, &fde);
731 
732                     let found_new_longest = match longest {
733                         None => true,
734                         Some((longest_len, ref _fde)) => this_len > longest_len,
735                     };
736 
737                     if found_new_longest {
738                         longest = Some((this_len, fde));
739                     }
740                 }
741             };
742         }
743 
744         longest.expect("At least one FDE in .eh_frame").1
745     }
746 
747     #[bench]
parse_longest_fde_instructions(b: &mut test::Bencher)748     fn parse_longest_fde_instructions(b: &mut test::Bencher) {
749         let eh_frame = read_section("eh_frame");
750         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
751         let bases = BaseAddresses::default()
752             .set_eh_frame(0)
753             .set_got(0)
754             .set_text(0);
755         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
756 
757         b.iter(|| {
758             let mut instrs = fde.instructions(&eh_frame, &bases);
759             while let Some(i) = instrs.next().expect("Should parse instruction OK") {
760                 test::black_box(i);
761             }
762         });
763     }
764 
765     #[bench]
eval_longest_fde_instructions_new_ctx_everytime(b: &mut test::Bencher)766     fn eval_longest_fde_instructions_new_ctx_everytime(b: &mut test::Bencher) {
767         let eh_frame = read_section("eh_frame");
768         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
769         let bases = BaseAddresses::default()
770             .set_eh_frame(0)
771             .set_got(0)
772             .set_text(0);
773         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
774 
775         b.iter(|| {
776             let mut ctx = Box::new(UnwindContext::new());
777             let mut table = fde
778                 .rows(&eh_frame, &bases, &mut ctx)
779                 .expect("Should initialize the ctx OK");
780             while let Some(row) = table.next_row().expect("Should get next unwind table row") {
781                 test::black_box(row);
782             }
783         });
784     }
785 
786     #[bench]
eval_longest_fde_instructions_same_ctx(b: &mut test::Bencher)787     fn eval_longest_fde_instructions_same_ctx(b: &mut test::Bencher) {
788         let eh_frame = read_section("eh_frame");
789         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
790         let bases = BaseAddresses::default()
791             .set_eh_frame(0)
792             .set_got(0)
793             .set_text(0);
794         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
795 
796         let mut ctx = Box::new(UnwindContext::new());
797 
798         b.iter(|| {
799             let mut table = fde
800                 .rows(&eh_frame, &bases, &mut ctx)
801                 .expect("Should initialize the ctx OK");
802             while let Some(row) = table.next_row().expect("Should get next unwind table row") {
803                 test::black_box(row);
804             }
805         });
806     }
807 }
808