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