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, 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 aranges = debug_aranges.items();
199         while let Some(arange) = aranges.next().expect("Should parse arange OK") {
200             test::black_box(arange);
201         }
202     });
203 }
204 
205 #[bench]
bench_parsing_debug_pubnames(b: &mut test::Bencher)206 fn bench_parsing_debug_pubnames(b: &mut test::Bencher) {
207     let debug_pubnames = read_section("debug_pubnames");
208     let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian);
209 
210     b.iter(|| {
211         let mut pubnames = debug_pubnames.items();
212         while let Some(pubname) = pubnames.next().expect("Should parse pubname OK") {
213             test::black_box(pubname);
214         }
215     });
216 }
217 
218 #[bench]
bench_parsing_debug_pubtypes(b: &mut test::Bencher)219 fn bench_parsing_debug_pubtypes(b: &mut test::Bencher) {
220     let debug_pubtypes = read_section("debug_pubtypes");
221     let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian);
222 
223     b.iter(|| {
224         let mut pubtypes = debug_pubtypes.items();
225         while let Some(pubtype) = pubtypes.next().expect("Should parse pubtype OK") {
226             test::black_box(pubtype);
227         }
228     });
229 }
230 
231 // We happen to know that there is a line number program and header at
232 // offset 0 and that address size is 8 bytes. No need to parse DIEs to grab
233 // this info off of the compilation units.
234 const OFFSET: DebugLineOffset = DebugLineOffset(0);
235 const ADDRESS_SIZE: u8 = 8;
236 
237 #[bench]
bench_parsing_line_number_program_opcodes(b: &mut test::Bencher)238 fn bench_parsing_line_number_program_opcodes(b: &mut test::Bencher) {
239     let debug_line = read_section("debug_line");
240     let debug_line = DebugLine::new(&debug_line, LittleEndian);
241 
242     b.iter(|| {
243         let program = debug_line
244             .program(OFFSET, ADDRESS_SIZE, None, None)
245             .expect("Should parse line number program header");
246         let header = program.header();
247 
248         let mut instructions = header.instructions();
249         while let Some(instruction) = instructions
250             .next_instruction(header)
251             .expect("Should parse instruction")
252         {
253             test::black_box(instruction);
254         }
255     });
256 }
257 
258 #[bench]
bench_executing_line_number_programs(b: &mut test::Bencher)259 fn bench_executing_line_number_programs(b: &mut test::Bencher) {
260     let debug_line = read_section("debug_line");
261     let debug_line = DebugLine::new(&debug_line, LittleEndian);
262 
263     b.iter(|| {
264         let program = debug_line
265             .program(OFFSET, ADDRESS_SIZE, None, None)
266             .expect("Should parse line number program header");
267 
268         let mut rows = program.rows();
269         while let Some(row) = rows
270             .next_row()
271             .expect("Should parse and execute all rows in the line number program")
272         {
273             test::black_box(row);
274         }
275     });
276 }
277 
278 #[bench]
bench_parsing_debug_loc(b: &mut test::Bencher)279 fn bench_parsing_debug_loc(b: &mut test::Bencher) {
280     let debug_info = read_section("debug_info");
281     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
282 
283     let debug_abbrev = read_section("debug_abbrev");
284     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
285 
286     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
287     let debug_addr_base = DebugAddrBase(0);
288 
289     let debug_loc = read_section("debug_loc");
290     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
291     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
292     let loclists = LocationLists::new(debug_loc, debug_loclists);
293 
294     let mut offsets = Vec::new();
295 
296     let mut iter = debug_info.units();
297     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
298         let abbrevs = unit
299             .abbreviations(&debug_abbrev)
300             .expect("Should parse abbreviations");
301 
302         let mut cursor = unit.entries(&abbrevs);
303         cursor.next_dfs().expect("Should parse next dfs");
304 
305         let mut low_pc = 0;
306 
307         {
308             let unit_entry = cursor.current().expect("Should have a root entry");
309             let low_pc_attr = unit_entry
310                 .attr_value(gimli::DW_AT_low_pc)
311                 .expect("Should parse low_pc");
312             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
313                 low_pc = address;
314             }
315         }
316 
317         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
318             let entry = cursor.current().expect("Should have a current entry");
319             let mut attrs = entry.attrs();
320             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
321                 if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() {
322                     offsets.push((offset, unit.encoding(), low_pc));
323                 }
324             }
325         }
326     }
327 
328     b.iter(|| {
329         for &(offset, encoding, base_address) in &*offsets {
330             let mut locs = loclists
331                 .locations(offset, encoding, base_address, &debug_addr, debug_addr_base)
332                 .expect("Should parse locations OK");
333             while let Some(loc) = locs.next().expect("Should parse next location") {
334                 test::black_box(loc);
335             }
336         }
337     });
338 }
339 
340 #[bench]
bench_parsing_debug_ranges(b: &mut test::Bencher)341 fn bench_parsing_debug_ranges(b: &mut test::Bencher) {
342     let debug_info = read_section("debug_info");
343     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
344 
345     let debug_abbrev = read_section("debug_abbrev");
346     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
347 
348     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
349     let debug_addr_base = DebugAddrBase(0);
350 
351     let debug_ranges = read_section("debug_ranges");
352     let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian);
353     let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
354     let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
355 
356     let mut offsets = Vec::new();
357 
358     let mut iter = debug_info.units();
359     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
360         let abbrevs = unit
361             .abbreviations(&debug_abbrev)
362             .expect("Should parse abbreviations");
363 
364         let mut cursor = unit.entries(&abbrevs);
365         cursor.next_dfs().expect("Should parse next dfs");
366 
367         let mut low_pc = 0;
368 
369         {
370             let unit_entry = cursor.current().expect("Should have a root entry");
371             let low_pc_attr = unit_entry
372                 .attr_value(gimli::DW_AT_low_pc)
373                 .expect("Should parse low_pc");
374             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
375                 low_pc = address;
376             }
377         }
378 
379         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
380             let entry = cursor.current().expect("Should have a current entry");
381             let mut attrs = entry.attrs();
382             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
383                 if let gimli::AttributeValue::RangeListsRef(offset) = attr.value() {
384                     offsets.push((offset, unit.encoding(), low_pc));
385                 }
386             }
387         }
388     }
389 
390     b.iter(|| {
391         for &(offset, encoding, base_address) in &*offsets {
392             let mut ranges = rnglists
393                 .ranges(offset, encoding, base_address, &debug_addr, debug_addr_base)
394                 .expect("Should parse ranges OK");
395             while let Some(range) = ranges.next().expect("Should parse next range") {
396                 test::black_box(range);
397             }
398         }
399     });
400 }
401 
debug_info_expressions<R: Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, ) -> Vec<(Expression<R>, Encoding)>402 fn debug_info_expressions<R: Reader>(
403     debug_info: &DebugInfo<R>,
404     debug_abbrev: &DebugAbbrev<R>,
405 ) -> Vec<(Expression<R>, Encoding)> {
406     let mut expressions = Vec::new();
407 
408     let mut iter = debug_info.units();
409     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
410         let abbrevs = unit
411             .abbreviations(debug_abbrev)
412             .expect("Should parse abbreviations");
413 
414         let mut cursor = unit.entries(&abbrevs);
415         while let Some((_, entry)) = cursor.next_dfs().expect("Should parse next dfs") {
416             let mut attrs = entry.attrs();
417             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
418                 if let AttributeValue::Exprloc(expression) = attr.value() {
419                     expressions.push((expression, unit.encoding()));
420                 }
421             }
422         }
423     }
424 
425     expressions
426 }
427 
428 #[bench]
bench_parsing_debug_info_expressions(b: &mut test::Bencher)429 fn bench_parsing_debug_info_expressions(b: &mut test::Bencher) {
430     let debug_abbrev = read_section("debug_abbrev");
431     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
432 
433     let debug_info = read_section("debug_info");
434     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
435 
436     let expressions = debug_info_expressions(&debug_info, &debug_abbrev);
437 
438     b.iter(|| {
439         for &(expression, encoding) in &*expressions {
440             let mut pc = expression.0;
441             while !pc.is_empty() {
442                 Operation::parse(&mut pc, encoding).expect("Should parse operation");
443             }
444         }
445     });
446 }
447 
448 #[bench]
bench_evaluating_debug_info_expressions(b: &mut test::Bencher)449 fn bench_evaluating_debug_info_expressions(b: &mut test::Bencher) {
450     let debug_abbrev = read_section("debug_abbrev");
451     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
452 
453     let debug_info = read_section("debug_info");
454     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
455 
456     let expressions = debug_info_expressions(&debug_info, &debug_abbrev);
457 
458     b.iter(|| {
459         for &(expression, encoding) in &*expressions {
460             let mut eval = expression.evaluation(encoding);
461             eval.set_initial_value(0);
462             let result = eval.evaluate().expect("Should evaluate expression");
463             test::black_box(result);
464         }
465     });
466 }
467 
debug_loc_expressions<R: Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, debug_addr: &DebugAddr<R>, loclists: &LocationLists<R>, ) -> Vec<(Expression<R>, Encoding)>468 fn debug_loc_expressions<R: Reader>(
469     debug_info: &DebugInfo<R>,
470     debug_abbrev: &DebugAbbrev<R>,
471     debug_addr: &DebugAddr<R>,
472     loclists: &LocationLists<R>,
473 ) -> Vec<(Expression<R>, Encoding)> {
474     let debug_addr_base = DebugAddrBase(R::Offset::from_u8(0));
475 
476     let mut expressions = Vec::new();
477 
478     let mut iter = debug_info.units();
479     while let Some(unit) = iter.next().expect("Should parse compilation unit") {
480         let abbrevs = unit
481             .abbreviations(debug_abbrev)
482             .expect("Should parse abbreviations");
483 
484         let mut cursor = unit.entries(&abbrevs);
485         cursor.next_dfs().expect("Should parse next dfs");
486 
487         let mut low_pc = 0;
488 
489         {
490             let unit_entry = cursor.current().expect("Should have a root entry");
491             let low_pc_attr = unit_entry
492                 .attr_value(gimli::DW_AT_low_pc)
493                 .expect("Should parse low_pc");
494             if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
495                 low_pc = address;
496             }
497         }
498 
499         while cursor.next_dfs().expect("Should parse next dfs").is_some() {
500             let entry = cursor.current().expect("Should have a current entry");
501             let mut attrs = entry.attrs();
502             while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
503                 if let gimli::AttributeValue::LocationListsRef(offset) = attr.value() {
504                     let mut locs = loclists
505                         .locations(offset, unit.encoding(), low_pc, debug_addr, debug_addr_base)
506                         .expect("Should parse locations OK");
507                     while let Some(loc) = locs.next().expect("Should parse next location") {
508                         expressions.push((loc.data, unit.encoding()));
509                     }
510                 }
511             }
512         }
513     }
514 
515     expressions
516 }
517 
518 #[bench]
bench_parsing_debug_loc_expressions(b: &mut test::Bencher)519 fn bench_parsing_debug_loc_expressions(b: &mut test::Bencher) {
520     let debug_info = read_section("debug_info");
521     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
522 
523     let debug_abbrev = read_section("debug_abbrev");
524     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
525 
526     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
527 
528     let debug_loc = read_section("debug_loc");
529     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
530     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
531     let loclists = LocationLists::new(debug_loc, debug_loclists);
532 
533     let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists);
534 
535     b.iter(|| {
536         for &(expression, encoding) in &*expressions {
537             let mut pc = expression.0;
538             while !pc.is_empty() {
539                 Operation::parse(&mut pc, encoding).expect("Should parse operation");
540             }
541         }
542     });
543 }
544 
545 #[bench]
bench_evaluating_debug_loc_expressions(b: &mut test::Bencher)546 fn bench_evaluating_debug_loc_expressions(b: &mut test::Bencher) {
547     let debug_info = read_section("debug_info");
548     let debug_info = DebugInfo::new(&debug_info, LittleEndian);
549 
550     let debug_abbrev = read_section("debug_abbrev");
551     let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
552 
553     let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
554 
555     let debug_loc = read_section("debug_loc");
556     let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
557     let debug_loclists = DebugLocLists::new(&[], LittleEndian);
558     let loclists = LocationLists::new(debug_loc, debug_loclists);
559 
560     let expressions = debug_loc_expressions(&debug_info, &debug_abbrev, &debug_addr, &loclists);
561 
562     b.iter(|| {
563         for &(expression, encoding) in &*expressions {
564             let mut eval = expression.evaluation(encoding);
565             eval.set_initial_value(0);
566             let result = eval.evaluate().expect("Should evaluate expression");
567             test::black_box(result);
568         }
569     });
570 }
571 
572 // See comment above `test_parse_self_eh_frame`.
573 #[cfg(target_pointer_width = "64")]
574 mod cfi {
575     use super::*;
576     use fallible_iterator::FallibleIterator;
577 
578     use gimli::{
579         BaseAddresses, CieOrFde, EhFrame, FrameDescriptionEntry, LittleEndian,
580         UninitializedUnwindContext, UnwindSection,
581     };
582 
583     #[bench]
iterate_entries_and_do_not_parse_any_fde(b: &mut test::Bencher)584     fn iterate_entries_and_do_not_parse_any_fde(b: &mut test::Bencher) {
585         let eh_frame = read_section("eh_frame");
586         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
587 
588         let bases = BaseAddresses::default()
589             .set_eh_frame(0)
590             .set_got(0)
591             .set_text(0);
592 
593         b.iter(|| {
594             let mut entries = eh_frame.entries(&bases);
595             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
596                 test::black_box(entry);
597             }
598         });
599     }
600 
601     #[bench]
iterate_entries_and_parse_every_fde(b: &mut test::Bencher)602     fn iterate_entries_and_parse_every_fde(b: &mut test::Bencher) {
603         let eh_frame = read_section("eh_frame");
604         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
605 
606         let bases = BaseAddresses::default()
607             .set_eh_frame(0)
608             .set_got(0)
609             .set_text(0);
610 
611         b.iter(|| {
612             let mut entries = eh_frame.entries(&bases);
613             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
614                 match entry {
615                     CieOrFde::Cie(cie) => {
616                         test::black_box(cie);
617                     }
618                     CieOrFde::Fde(partial) => {
619                         let fde = partial
620                             .parse(EhFrame::cie_from_offset)
621                             .expect("Should be able to get CIE for FED");
622                         test::black_box(fde);
623                     }
624                 };
625             }
626         });
627     }
628 
629     #[bench]
iterate_entries_and_parse_every_fde_and_instructions(b: &mut test::Bencher)630     fn iterate_entries_and_parse_every_fde_and_instructions(b: &mut test::Bencher) {
631         let eh_frame = read_section("eh_frame");
632         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
633 
634         let bases = BaseAddresses::default()
635             .set_eh_frame(0)
636             .set_got(0)
637             .set_text(0);
638 
639         b.iter(|| {
640             let mut entries = eh_frame.entries(&bases);
641             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
642                 match entry {
643                     CieOrFde::Cie(cie) => {
644                         let mut instrs = cie.instructions(&eh_frame, &bases);
645                         while let Some(i) =
646                             instrs.next().expect("Can parse next CFI instruction OK")
647                         {
648                             test::black_box(i);
649                         }
650                     }
651                     CieOrFde::Fde(partial) => {
652                         let fde = partial
653                             .parse(EhFrame::cie_from_offset)
654                             .expect("Should be able to get CIE for FED");
655                         let mut instrs = fde.instructions(&eh_frame, &bases);
656                         while let Some(i) =
657                             instrs.next().expect("Can parse next CFI instruction OK")
658                         {
659                             test::black_box(i);
660                         }
661                     }
662                 };
663             }
664         });
665     }
666 
667     #[bench]
iterate_entries_evaluate_every_fde(b: &mut test::Bencher)668     fn iterate_entries_evaluate_every_fde(b: &mut test::Bencher) {
669         let eh_frame = read_section("eh_frame");
670         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
671 
672         let bases = BaseAddresses::default()
673             .set_eh_frame(0)
674             .set_got(0)
675             .set_text(0);
676 
677         let mut ctx = UninitializedUnwindContext::new();
678 
679         b.iter(|| {
680             let mut entries = eh_frame.entries(&bases);
681             while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
682                 match entry {
683                     CieOrFde::Cie(_) => {}
684                     CieOrFde::Fde(partial) => {
685                         let fde = partial
686                             .parse(EhFrame::cie_from_offset)
687                             .expect("Should be able to get CIE for FED");
688                         let mut table = fde
689                             .rows(&eh_frame, &bases, &mut ctx)
690                             .expect("Should be able to initialize ctx");
691                         while let Some(row) =
692                             table.next_row().expect("Should get next unwind table row")
693                         {
694                             test::black_box(row);
695                         }
696                     }
697                 };
698             }
699         });
700     }
701 
instrs_len<R: Reader>( eh_frame: &EhFrame<R>, bases: &BaseAddresses, fde: &FrameDescriptionEntry<R>, ) -> usize702     fn instrs_len<R: Reader>(
703         eh_frame: &EhFrame<R>,
704         bases: &BaseAddresses,
705         fde: &FrameDescriptionEntry<R>,
706     ) -> usize {
707         fde.instructions(eh_frame, bases)
708             .fold(0, |count, _| Ok(count + 1))
709             .expect("fold over instructions OK")
710     }
711 
get_fde_with_longest_cfi_instructions<R: Reader>( eh_frame: &EhFrame<R>, bases: &BaseAddresses, ) -> FrameDescriptionEntry<R>712     fn get_fde_with_longest_cfi_instructions<R: Reader>(
713         eh_frame: &EhFrame<R>,
714         bases: &BaseAddresses,
715     ) -> FrameDescriptionEntry<R> {
716         let mut longest: Option<(usize, FrameDescriptionEntry<_>)> = None;
717 
718         let mut entries = eh_frame.entries(bases);
719         while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
720             match entry {
721                 CieOrFde::Cie(_) => {}
722                 CieOrFde::Fde(partial) => {
723                     let fde = partial
724                         .parse(EhFrame::cie_from_offset)
725                         .expect("Should be able to get CIE for FED");
726 
727                     let this_len = instrs_len(eh_frame, bases, &fde);
728 
729                     let found_new_longest = match longest {
730                         None => true,
731                         Some((longest_len, ref _fde)) => this_len > longest_len,
732                     };
733 
734                     if found_new_longest {
735                         longest = Some((this_len, fde));
736                     }
737                 }
738             };
739         }
740 
741         longest.expect("At least one FDE in .eh_frame").1
742     }
743 
744     #[bench]
parse_longest_fde_instructions(b: &mut test::Bencher)745     fn parse_longest_fde_instructions(b: &mut test::Bencher) {
746         let eh_frame = read_section("eh_frame");
747         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
748         let bases = BaseAddresses::default()
749             .set_eh_frame(0)
750             .set_got(0)
751             .set_text(0);
752         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
753 
754         b.iter(|| {
755             let mut instrs = fde.instructions(&eh_frame, &bases);
756             while let Some(i) = instrs.next().expect("Should parse instruction OK") {
757                 test::black_box(i);
758             }
759         });
760     }
761 
762     #[bench]
eval_longest_fde_instructions_new_ctx_everytime(b: &mut test::Bencher)763     fn eval_longest_fde_instructions_new_ctx_everytime(b: &mut test::Bencher) {
764         let eh_frame = read_section("eh_frame");
765         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
766         let bases = BaseAddresses::default()
767             .set_eh_frame(0)
768             .set_got(0)
769             .set_text(0);
770         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
771 
772         b.iter(|| {
773             let mut ctx = UninitializedUnwindContext::new();
774             let mut table = fde
775                 .rows(&eh_frame, &bases, &mut ctx)
776                 .expect("Should initialize the ctx OK");
777             while let Some(row) = table.next_row().expect("Should get next unwind table row") {
778                 test::black_box(row);
779             }
780         });
781     }
782 
783     #[bench]
eval_longest_fde_instructions_same_ctx(b: &mut test::Bencher)784     fn eval_longest_fde_instructions_same_ctx(b: &mut test::Bencher) {
785         let eh_frame = read_section("eh_frame");
786         let eh_frame = EhFrame::new(&eh_frame, LittleEndian);
787         let bases = BaseAddresses::default()
788             .set_eh_frame(0)
789             .set_got(0)
790             .set_text(0);
791         let fde = get_fde_with_longest_cfi_instructions(&eh_frame, &bases);
792 
793         let mut ctx = UninitializedUnwindContext::new();
794 
795         b.iter(|| {
796             let mut table = fde
797                 .rows(&eh_frame, &bases, &mut ctx)
798                 .expect("Should initialize the ctx OK");
799             while let Some(row) = table.next_row().expect("Should get next unwind table row") {
800                 test::black_box(row);
801             }
802         });
803     }
804 }
805