@@ -311,6 +311,50 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
311
311
uint32_t savedRegistersLocations =
312
312
EXTRACT_BITS (compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
313
313
314
+ // If we have not stored EBP yet
315
+ if (functionStart == registers.getIP ()) {
316
+ uint64_t rsp = registers.getSP ();
317
+ // old esp is ebp less return address
318
+ registers.setSP (rsp+8 );
319
+ // pop return address into eip
320
+ registers.setIP (addressSpace.get64 (rsp));
321
+
322
+ return UNW_STEP_SUCCESS;
323
+ } else if (functionStart + 1 == registers.getIP ()) {
324
+ uint64_t rsp = registers.getSP ();
325
+ // old esp is ebp less return address
326
+ registers.setSP (rsp + 16 );
327
+ // pop return address into eip
328
+ registers.setIP (addressSpace.get64 (rsp + 8 ));
329
+
330
+ return UNW_STEP_SUCCESS;
331
+ }
332
+
333
+ // If we're about to return, we've already popped the base pointer
334
+ uint8_t b = addressSpace.get8 (registers.getIP ());
335
+
336
+ // This is a hack to detect VZEROUPPER but in between popq rbp and ret
337
+ // It's not pretty but it works
338
+ if (b == 0xC5 ) {
339
+ if ((b = addressSpace.get8 (registers.getIP () + 1 )) == 0xF8 &&
340
+ (b = addressSpace.get8 (registers.getIP () + 2 )) == 0x77 )
341
+ b = addressSpace.get8 (registers.getIP () + 3 );
342
+ else
343
+ goto skip_ret;
344
+ }
345
+
346
+ if (b == 0xC3 || b == 0xCB || b == 0xC2 || b == 0xCA ) {
347
+ uint64_t rbp = registers.getSP ();
348
+ // old esp is ebp less return address
349
+ registers.setSP (rbp + 16 );
350
+ // pop return address into eip
351
+ registers.setIP (addressSpace.get64 (rbp + 8 ));
352
+
353
+ return UNW_STEP_SUCCESS;
354
+ }
355
+
356
+ skip_ret:
357
+
314
358
uint64_t savedRegisters = registers.getRBP () - 8 * savedRegistersOffset;
315
359
for (int i = 0 ; i < 5 ; ++i) {
316
360
switch (savedRegistersLocations & 0x7 ) {
@@ -431,6 +475,118 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
431
475
}
432
476
}
433
477
}
478
+
479
+ // Note that the order of these registers is so that
480
+ // registersSaved[0] is the one that will be pushed onto the stack last.
481
+ // Thus, if we want to walk this from the top, we need to go in reverse.
482
+ assert (regCount <= 6 );
483
+
484
+ // check whether we are still in the prologue
485
+ uint64_t curAddr = functionStart;
486
+ if (regCount > 0 ) {
487
+ for (int8_t i = (int8_t )(regCount) - 1 ; i >= 0 ; --i) {
488
+ if (registers.getIP () == curAddr) {
489
+ // None of the registers have been modified yet, so we don't need to reload them
490
+ framelessUnwind (addressSpace, registers.getSP () + 8 * (regCount - (uint64_t )(i + 1 )), registers);
491
+ return UNW_STEP_SUCCESS;
492
+ } else {
493
+ assert (curAddr < registers.getIP ());
494
+ }
495
+
496
+
497
+ // pushq %rbp and pushq %rbx is 1 byte. Everything else 2
498
+ if ((UNWIND_X86_64_REG_RBP == registersSaved[i]) ||
499
+ (UNWIND_X86_64_REG_RBX == registersSaved[i]))
500
+ curAddr += 1 ;
501
+ else
502
+ curAddr += 2 ;
503
+ }
504
+ }
505
+ if (registers.getIP () == curAddr) {
506
+ // None of the registers have been modified yet, so we don't need to reload them
507
+ framelessUnwind (addressSpace, registers.getSP () + 8 *regCount, registers);
508
+ return UNW_STEP_SUCCESS;
509
+ } else {
510
+ assert (curAddr < registers.getIP ());
511
+ }
512
+
513
+
514
+ // And now for the epilogue
515
+ {
516
+ uint8_t i = 0 ;
517
+ uint64_t p = registers.getIP ();
518
+ uint8_t b = 0 ;
519
+
520
+ while (true ) {
521
+ b = addressSpace.get8 (p++);
522
+ // This is a hack to detect VZEROUPPER but in between the popq's and ret
523
+ // It's not pretty but it works
524
+ if (b == 0xC5 ) {
525
+ if ((b = addressSpace.get8 (p++)) == 0xF8 && (b = addressSpace.get8 (p++)) == 0x77 )
526
+ b = addressSpace.get8 (p++);
527
+ else
528
+ break ;
529
+ }
530
+ // popq %rbx popq %rbp
531
+ if (b == 0x5B || b == 0x5D ) {
532
+ i++;
533
+ } else if (b == 0x41 ) {
534
+ b = addressSpace.get8 (p++);
535
+ if (b == 0x5C || b == 0x5D || b == 0x5E || b == 0x5F )
536
+ i++;
537
+ else
538
+ break ;
539
+ } else if (b == 0xC3 || b == 0xCB || b == 0xC2 || b == 0xCA ) {
540
+ // i pop's haven't happened yet
541
+ uint64_t savedRegisters = registers.getSP () + 8 * i;
542
+ if (regCount > 0 ) {
543
+ for (int8_t j = (int8_t )(regCount) - 1 ; j >= (int8_t )(regCount) - i; --j) {
544
+ uint64_t addr = savedRegisters - 8 * (regCount - (uint64_t )(j));
545
+ switch (registersSaved[j]) {
546
+ case UNWIND_X86_64_REG_RBX:
547
+ registers.setRBX (addressSpace.get64 (addr));
548
+ break ;
549
+ case UNWIND_X86_64_REG_R12:
550
+ registers.setR12 (addressSpace.get64 (addr));
551
+ break ;
552
+ case UNWIND_X86_64_REG_R13:
553
+ registers.setR13 (addressSpace.get64 (addr));
554
+ break ;
555
+ case UNWIND_X86_64_REG_R14:
556
+ registers.setR14 (addressSpace.get64 (addr));
557
+ break ;
558
+ case UNWIND_X86_64_REG_R15:
559
+ registers.setR15 (addressSpace.get64 (addr));
560
+ break ;
561
+ case UNWIND_X86_64_REG_RBP:
562
+ registers.setRBP (addressSpace.get64 (addr));
563
+ break ;
564
+ default :
565
+ _LIBUNWIND_DEBUG_LOG (" bad register for frameless, encoding=%08X for "
566
+ " function starting at 0x%llX" ,
567
+ encoding, functionStart);
568
+ _LIBUNWIND_ABORT (" invalid compact unwind encoding" );
569
+ }
570
+ }
571
+ }
572
+ framelessUnwind (addressSpace, savedRegisters, registers);
573
+ return UNW_STEP_SUCCESS;
574
+ } else {
575
+ break ;
576
+ }
577
+ }
578
+ }
579
+
580
+ /*
581
+ 0x10fe2733a: 5b popq %rbx
582
+ 0x10fe2733b: 41 5c popq %r12
583
+ 0x10fe2733d: 41 5d popq %r13
584
+ 0x10fe2733f: 41 5e popq %r14
585
+ 0x10fe27341: 41 5f popq %r15
586
+ 0x10fe27343: 5d popq %rbp
587
+ */
588
+
589
+
434
590
uint64_t savedRegisters = registers.getSP () + stackSize - 8 - 8 * regCount;
435
591
for (uint32_t i = 0 ; i < regCount; ++i) {
436
592
switch (registersSaved[i]) {
0 commit comments