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