Emulating load/restore register instructions in MIPS assembly profiler

I am working on assembly profiler for MIPS using EmulateInstruction.

I have set the ContextType to eContextPopRegisterOffStack in the function which emulates “ld ra,40(sp)”

(i.e. load/restore ra from stack) instruction.

0xffffffff802009a4 :

0xffffffff802009a4: 67bdffd0 daddiu sp,sp,-48

0xffffffff802009a8: ffbf0028 sd ra,40(sp) -----> store return address

0xffffffff802009ac: ffbe0020 sd s8,32(sp)

0xffffffff802009b0: 03a0f02d move s8,sp

<…end of prologue…>

<…some other instructions…>

<…start of epilogue…>

0xffffffff802009f4: 03c0e82d move sp,s8

0xffffffff802009f8: dfbf0028 ld ra,40(sp) ------> restore return address

0xffffffff802009fc: dfbe0020 ld s8,32(sp)

0xffffffff80200a00: 67bd0030 daddiu sp,sp,48

0xffffffff80200a04: 03e00008 jr ra

0xffffffff80200a08: 00000000 nop

With this setting, the unwinder fails when we try to unwind from 0xffffffff802009fc.

The call sequence is main()->foo()->bar() however, backtrace displays only current frame.

I am working on assembly profiler for MIPS using EmulateInstruction.

I have set the ContextType to eContextPopRegisterOffStack in the function which emulates “ld ra,40(sp)”
(i.e. load/restore ra from stack) instruction.

0xffffffff802009a4 <bar>:
0xffffffff802009a4: 67bdffd0 daddiu sp,sp,-48
0xffffffff802009a8: ffbf0028 sd ra,40(sp) -----> store return address
0xffffffff802009ac: ffbe0020 sd s8,32(sp)
0xffffffff802009b0: 03a0f02d move s8,sp
<..end of prologue...>
<..some other instructions...>
<..start of epilogue...>
0xffffffff802009f4: 03c0e82d move sp,s8
0xffffffff802009f8: dfbf0028 ld ra,40(sp) ------> restore return address
0xffffffff802009fc: dfbe0020 ld s8,32(sp)
0xffffffff80200a00: 67bd0030 daddiu sp,sp,48
0xffffffff80200a04: 03e00008 jr ra
0xffffffff80200a08: 00000000 nop

With this setting, the unwinder fails when we try to unwind from 0xffffffff802009fc.
The call sequence is main()->foo()->bar() however, backtrace displays only current frame.
----------------------------------------
(lldb) bt
* thread #1: tid = 0x0001, 0xffffffff802009fc a.out_64`bar(p=4) + 88 at a.c:30, stop reason = breakpoint 1.1
  * frame #0: 0xffffffff802009fc a.out_64`bar(p=4) + 88 at a.c:30
---------------------------------------

Below is a part of generated log:
--------------------------------------------------------------------------------------
th1/fr0 0xffffffff802009fc: CFA=sp+48 => fp=[CFA-16] ra= <same> pc=[CFA-8]

th1/fr0 CFA is 0xffffffff800fff60: Register sp (29) contents are 0xffffffff800fff30, offset is 48
th1/fr0 initialized frame current pc is 0xffffffff802009fc cfa is 0xffffffff800fff60 using EmulateInstructionMIPS64 UnwindPlan
th1/fr0 requested caller's saved PC but this UnwindPlan uses a RA reg; getting ra (31) instead
th1/fr0 supplying caller's saved ra (31)'s location using EmulateInstructionMIPS64 UnwindPlan
th1/fr0 could not supply caller's ra (31) location, IsSame
th1/fr1 could not get pc value
Frame 1 invalid RegisterContext for this frame, stopping stack walk
th1 Unwind of this thread is complete.
--------------------------------------------------------------------------------------

Here we just need to tell the unwinder that the register has been restored and take this register from live register context.
Which ContextType to use in such case?

It seems like this is what is being done in UnwindAssemblyInstEmulation::WriteRegister (...):

        case EmulateInstruction::eContextPopRegisterOffStack:
            {
                const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
                if (reg_num != LLDB_INVALID_REGNUM)
                {
                    m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
                    m_curr_row_modified = true;
                    m_curr_insn_restored_a_register = true;
                }
            }
            break;

1. There exists similar ContextType - eContextRegisterLoad, but it is unimplemented (just breaks out and does nothing) in UnwindAssemblyInstEmulation::WriteRegister().
   So will it be a good option to implement eContextRegisterLoad and set the register location to itself using SetRegisterLocationToRegister (reg_num, reg_num, true)
   OR
2. Add new ContextType say eContextRegisterRestore to EmulateInstruction class and implement it in UnwindAssemblyInstEmulation::WriteRegister().
   
Also, consider location of pc if we are restoring the return address register.
This is similar to how eContextPushRegisterOnStack handles return address register in UnwindAssemblyInstEmulation::WriteMemory().

If all goes well it seems like he code in UnwindAssemblyInstEmulation::WriteRegister() should be setting the register to be in the register itself. Can you step through this code and make sure we are happy with all of the register numbers?

Greg