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