@@ -311,6 +311,50 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
311311 uint32_t savedRegistersLocations =
312312 EXTRACT_BITS (compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
313313
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+
314358 uint64_t savedRegisters = registers.getRBP () - 8 * savedRegistersOffset;
315359 for (int i = 0 ; i < 5 ; ++i) {
316360 switch (savedRegistersLocations & 0x7 ) {
@@ -431,6 +475,118 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
431475 }
432476 }
433477 }
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+
434590 uint64_t savedRegisters = registers.getSP () + stackSize - 8 - 8 * regCount;
435591 for (uint32_t i = 0 ; i < regCount; ++i) {
436592 switch (registersSaved[i]) {
0 commit comments