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