mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
Improve instruction emulation based stack unwinding on ARM
* Add and fix the emulation of several instruction. * Disable frame pointer usage on Android. * Specify return address register for the unwind plan instead of explict tracking the value of RA. * Replace prologue detection heuristics (unreliable in several cases) with a logic to follow the branch instructions and restore the CFI value based on them. The target address for a branch should have the same CFI as the source address (if they are in the same function). * Handle symbols in ELF files where the symbol size is not specified with calcualting their size based on the next symbol (already done in MachO files). * Fix architecture in FuncUnwinders with filling up the inforamtion missing from the object file with the architecture of the target. * Add code to read register wehn the value is set to "IsSame" as it meanse the value of a register in the parent frame is the same as the value in the current frame. Differential revision: http://reviews.llvm.org/D10447 llvm-svn: 240533
This commit is contained in:
@@ -50,7 +50,7 @@ public:
|
||||
GetUnwindPlanAtNonCallSite (Target& target, lldb_private::Thread& thread, int current_offset);
|
||||
|
||||
lldb::UnwindPlanSP
|
||||
GetUnwindPlanFastUnwind (lldb_private::Thread& Thread);
|
||||
GetUnwindPlanFastUnwind (Target& target, lldb_private::Thread& thread);
|
||||
|
||||
lldb::UnwindPlanSP
|
||||
GetUnwindPlanArchitectureDefault (lldb_private::Thread& thread);
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
private:
|
||||
|
||||
lldb::UnwindAssemblySP
|
||||
GetUnwindAssemblyProfiler ();
|
||||
GetUnwindAssemblyProfiler (Target& target);
|
||||
|
||||
UnwindTable& m_unwind_table;
|
||||
AddressRange m_range;
|
||||
|
||||
@@ -3775,7 +3775,7 @@ protected:
|
||||
{
|
||||
result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan is '%s'\n", callsite_unwind_plan->GetSourceName().AsCString());
|
||||
}
|
||||
UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
|
||||
UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*target, *thread.get());
|
||||
if (fast_unwind_plan.get())
|
||||
{
|
||||
result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString());
|
||||
|
||||
@@ -290,6 +290,9 @@ EmulateInstructionARM::GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t re
|
||||
uint32_t
|
||||
EmulateInstructionARM::GetFramePointerRegisterNumber () const
|
||||
{
|
||||
if (m_arch.GetTriple().getEnvironment() == llvm::Triple::Android)
|
||||
return LLDB_INVALID_REGNUM; // Don't use frame pointer on android
|
||||
|
||||
bool is_apple = false;
|
||||
if (m_arch.GetTriple().getVendor() == llvm::Triple::Apple)
|
||||
is_apple = true;
|
||||
@@ -1339,29 +1342,61 @@ EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding
|
||||
return false;
|
||||
uint32_t imm32; // the immediate operand
|
||||
uint32_t d;
|
||||
//bool setflags = false; // Add this back if/when support eEncodingT3 eEncodingA1
|
||||
switch (encoding)
|
||||
bool setflags;
|
||||
switch (encoding)
|
||||
{
|
||||
case eEncodingT1:
|
||||
// d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32);
|
||||
d = Bits32 (opcode, 10, 8);
|
||||
imm32 = (Bits32 (opcode, 7, 0) << 2);
|
||||
|
||||
setflags = false;
|
||||
break;
|
||||
|
||||
|
||||
case eEncodingT2:
|
||||
// d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
|
||||
d = 13;
|
||||
imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
|
||||
|
||||
imm32 = ThumbImm7Scaled (opcode); // imm32 = ZeroExtend(imm7:'00', 32)
|
||||
setflags = false;
|
||||
break;
|
||||
|
||||
|
||||
case eEncodingT3:
|
||||
// d = UInt(Rd); setflags = (S == "1"); imm32 = ThumbExpandImm(i:imm3:imm8);
|
||||
d = Bits32 (opcode, 11, 8);
|
||||
imm32 = ThumbExpandImm (opcode);
|
||||
setflags = Bit32 (opcode, 20);
|
||||
|
||||
// if Rd == "1111" && S == "1" then SEE CMN (immediate);
|
||||
if (d == 15 && setflags == 1)
|
||||
return false; // CMN (immediate) not yet supported
|
||||
|
||||
// if d == 15 && S == "0" then UNPREDICTABLE;
|
||||
if (d == 15 && setflags == 0)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case eEncodingT4:
|
||||
{
|
||||
// if Rn == '1111' then SEE ADR;
|
||||
// d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
|
||||
d = Bits32 (opcode, 11, 8);
|
||||
setflags = false;
|
||||
uint32_t i = Bit32 (opcode, 26);
|
||||
uint32_t imm3 = Bits32 (opcode, 14, 12);
|
||||
uint32_t imm8 = Bits32 (opcode, 7, 0);
|
||||
imm32 = (i << 11) | (imm3 << 8) | imm8;
|
||||
|
||||
// if d == 15 then UNPREDICTABLE;
|
||||
if (d == 15)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
addr_t sp_offset = imm32;
|
||||
addr_t addr = sp + sp_offset; // the adjusted stack pointer value
|
||||
|
||||
// (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
|
||||
AddWithCarryResult res = AddWithCarry (sp, imm32, 0);
|
||||
|
||||
EmulateInstruction::Context context;
|
||||
if (d == 13)
|
||||
context.type = EmulateInstruction::eContextAdjustStackPointer;
|
||||
@@ -1370,26 +1405,23 @@ EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding
|
||||
|
||||
RegisterInfo sp_reg;
|
||||
GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
|
||||
context.SetRegisterPlusOffset (sp_reg, sp_offset);
|
||||
|
||||
context.SetRegisterPlusOffset (sp_reg, res.result - sp);
|
||||
|
||||
if (d == 15)
|
||||
{
|
||||
if (!ALUWritePC (context, addr))
|
||||
if (!ALUWritePC (context, res.result))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr))
|
||||
// R[d] = result;
|
||||
// if setflags then
|
||||
// APSR.N = result<31>;
|
||||
// APSR.Z = IsZeroBit(result);
|
||||
// APSR.C = carry;
|
||||
// APSR.V = overflow;
|
||||
if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
|
||||
return false;
|
||||
|
||||
// Add this back if/when support eEncodingT3 eEncodingA1
|
||||
//if (setflags)
|
||||
//{
|
||||
// APSR.N = result<31>;
|
||||
// APSR.Z = IsZeroBit(result);
|
||||
// APSR.C = carry;
|
||||
// APSR.V = overflow;
|
||||
//}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -2318,13 +2350,16 @@ EmulateInstructionARM::EmulateB (const uint32_t opcode, const ARMEncoding encodi
|
||||
context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
|
||||
break;
|
||||
case eEncodingT2:
|
||||
imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
|
||||
imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1);
|
||||
target = pc + imm32;
|
||||
context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
|
||||
break;
|
||||
case eEncodingT3:
|
||||
// The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
|
||||
{
|
||||
if (Bits32(opcode, 25, 23) == 7)
|
||||
return false; // See Branches and miscellaneous control on page A6-235.
|
||||
|
||||
uint32_t S = Bit32(opcode, 26);
|
||||
uint32_t imm6 = Bits32(opcode, 21, 16);
|
||||
uint32_t J1 = Bit32(opcode, 13);
|
||||
@@ -2404,7 +2439,7 @@ EmulateInstructionARM::EmulateCB (const uint32_t opcode, const ARMEncoding encod
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (nonzero ^ (reg_val == 0))
|
||||
if (m_ignore_conditions || (nonzero ^ (reg_val == 0)))
|
||||
if (!BranchWritePC(context, target))
|
||||
return false;
|
||||
|
||||
@@ -2434,56 +2469,59 @@ EmulateInstructionARM::EmulateTB (const uint32_t opcode, const ARMEncoding encod
|
||||
|
||||
bool success = false;
|
||||
|
||||
uint32_t Rn; // the base register which contains the address of the table of branch lengths
|
||||
uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
|
||||
bool is_tbh; // true if table branch halfword
|
||||
switch (encoding) {
|
||||
case eEncodingT1:
|
||||
Rn = Bits32(opcode, 19, 16);
|
||||
Rm = Bits32(opcode, 3, 0);
|
||||
is_tbh = BitIsSet(opcode, 4);
|
||||
if (Rn == 13 || BadReg(Rm))
|
||||
if (ConditionPassed(opcode))
|
||||
{
|
||||
uint32_t Rn; // the base register which contains the address of the table of branch lengths
|
||||
uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
|
||||
bool is_tbh; // true if table branch halfword
|
||||
switch (encoding) {
|
||||
case eEncodingT1:
|
||||
Rn = Bits32(opcode, 19, 16);
|
||||
Rm = Bits32(opcode, 3, 0);
|
||||
is_tbh = BitIsSet(opcode, 4);
|
||||
if (Rn == 13 || BadReg(Rm))
|
||||
return false;
|
||||
if (InITBlock() && !LastInITBlock())
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
if (InITBlock() && !LastInITBlock())
|
||||
}
|
||||
|
||||
// Read the address of the table from the operand register Rn.
|
||||
// The PC can be used, in which case the table immediately follows this instruction.
|
||||
uint32_t base = ReadCoreReg(Rn, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// the table index
|
||||
uint32_t index = ReadCoreReg(Rm, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// the offsetted table address
|
||||
addr_t addr = base + (is_tbh ? index*2 : index);
|
||||
|
||||
// PC-relative offset to branch forward
|
||||
EmulateInstruction::Context context;
|
||||
context.type = EmulateInstruction::eContextTableBranchReadMemory;
|
||||
uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
const uint32_t pc = ReadCoreReg(PC_REG, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// target address
|
||||
addr_t target = pc + offset;
|
||||
context.type = EmulateInstruction::eContextRelativeBranchImmediate;
|
||||
context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
|
||||
|
||||
if (!BranchWritePC(context, target))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the address of the table from the operand register Rn.
|
||||
// The PC can be used, in which case the table immediately follows this instruction.
|
||||
uint32_t base = ReadCoreReg(Rm, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// the table index
|
||||
uint32_t index = ReadCoreReg(Rm, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// the offsetted table address
|
||||
addr_t addr = base + (is_tbh ? index*2 : index);
|
||||
|
||||
// PC-relative offset to branch forward
|
||||
EmulateInstruction::Context context;
|
||||
context.type = EmulateInstruction::eContextTableBranchReadMemory;
|
||||
uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
const uint32_t pc = ReadCoreReg(PC_REG, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
// target address
|
||||
addr_t target = pc + offset;
|
||||
context.type = EmulateInstruction::eContextRelativeBranchImmediate;
|
||||
context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
|
||||
|
||||
if (!BranchWritePC(context, target))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2498,14 +2536,14 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
|
||||
R[d] = result;
|
||||
if setflags then
|
||||
APSR.N = result<31>;
|
||||
APSR.Z = IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
APSR.N = result<31>;
|
||||
APSR.Z = IsZeroBit(result);
|
||||
APSR.C = carry;
|
||||
APSR.V = overflow;
|
||||
#endif
|
||||
|
||||
|
||||
bool success = false;
|
||||
|
||||
|
||||
if (ConditionPassed(opcode))
|
||||
{
|
||||
uint32_t d;
|
||||
@@ -2513,8 +2551,8 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
bool setflags;
|
||||
uint32_t imm32;
|
||||
uint32_t carry_out;
|
||||
|
||||
//EncodingSpecificOperations();
|
||||
|
||||
//EncodingSpecificOperations();
|
||||
switch (encoding)
|
||||
{
|
||||
case eEncodingT1:
|
||||
@@ -2523,7 +2561,7 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
n = Bits32 (opcode, 5, 3);
|
||||
setflags = !InITBlock();
|
||||
imm32 = Bits32 (opcode, 8,6);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case eEncodingT2:
|
||||
@@ -2532,28 +2570,30 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
n = Bits32 (opcode, 10, 8);
|
||||
setflags = !InITBlock();
|
||||
imm32 = Bits32 (opcode, 7, 0);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case eEncodingT3:
|
||||
// if Rd == '1111' && S == '1' then SEE CMN (immediate);
|
||||
// if Rn == '1101' then SEE ADD (SP plus immediate);
|
||||
// d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8);
|
||||
d = Bits32 (opcode, 11, 8);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
setflags = BitIsSet (opcode, 20);
|
||||
imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out);
|
||||
|
||||
|
||||
// if Rn == '1101' then SEE ADD (SP plus immediate);
|
||||
if (n == 13)
|
||||
return EmulateADDSPImm(opcode, eEncodingT3);
|
||||
|
||||
// if BadReg(d) || n == 15 then UNPREDICTABLE;
|
||||
if (BadReg (d) || (n == 15))
|
||||
return false;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
case eEncodingT4:
|
||||
{
|
||||
// if Rn == '1111' then SEE ADR;
|
||||
// if Rn == '1101' then SEE ADD (SP plus immediate);
|
||||
// d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
|
||||
d = Bits32 (opcode, 11, 8);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
@@ -2562,31 +2602,36 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
uint32_t imm3 = Bits32 (opcode, 14, 12);
|
||||
uint32_t imm8 = Bits32 (opcode, 7, 0);
|
||||
imm32 = (i << 11) | (imm3 << 8) | imm8;
|
||||
|
||||
|
||||
// if Rn == '1101' then SEE ADD (SP plus immediate);
|
||||
if (n == 13)
|
||||
return EmulateADDSPImm(opcode, eEncodingT4);
|
||||
|
||||
// if BadReg(d) then UNPREDICTABLE;
|
||||
if (BadReg (d))
|
||||
return false;
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
|
||||
//(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
|
||||
AddWithCarryResult res = AddWithCarry (Rn, imm32, 0);
|
||||
|
||||
|
||||
RegisterInfo reg_n;
|
||||
GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
|
||||
|
||||
|
||||
EmulateInstruction::Context context;
|
||||
context.type = eContextArithmetic;
|
||||
context.SetRegisterPlusOffset (reg_n, imm32);
|
||||
|
||||
|
||||
//R[d] = result;
|
||||
//if setflags then
|
||||
//APSR.N = result<31>;
|
||||
@@ -2595,7 +2640,7 @@ EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncod
|
||||
//APSR.V = overflow;
|
||||
if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2650,6 +2695,8 @@ EmulateInstructionARM::EmulateADDImmARM (const uint32_t opcode, const ARMEncodin
|
||||
EmulateInstruction::Context context;
|
||||
if (Rd == 13)
|
||||
context.type = EmulateInstruction::eContextAdjustStackPointer;
|
||||
else if (Rd == GetFramePointerRegisterNumber())
|
||||
context.type = EmulateInstruction::eContextSetFramePointer;
|
||||
else
|
||||
context.type = EmulateInstruction::eContextRegisterPlusOffset;
|
||||
|
||||
@@ -2968,6 +3015,13 @@ EmulateInstructionARM::EmulateCMPReg (const uint32_t opcode, const ARMEncoding e
|
||||
if (Rn == 15 || Rm == 15)
|
||||
return false;
|
||||
break;
|
||||
case eEncodingT3:
|
||||
Rn = Bits32(opcode, 19, 16);
|
||||
Rm = Bits32(opcode, 3, 0);
|
||||
shift_n = DecodeImmShiftThumb(opcode, shift_t);
|
||||
if (Rn == 15 || BadReg(Rm))
|
||||
return false;
|
||||
break;
|
||||
case eEncodingA1:
|
||||
Rn = Bits32(opcode, 19, 16);
|
||||
Rm = Bits32(opcode, 3, 0);
|
||||
@@ -4016,8 +4070,22 @@ EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncodi
|
||||
if (wback)
|
||||
{
|
||||
EmulateInstruction::Context ctx;
|
||||
ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
|
||||
ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
|
||||
if (Rn == 13)
|
||||
{
|
||||
ctx.type = eContextAdjustStackPointer;
|
||||
ctx.SetImmediateSigned((int32_t) (offset_addr - base));
|
||||
}
|
||||
else if (Rn == GetFramePointerRegisterNumber())
|
||||
{
|
||||
ctx.type = eContextSetFramePointer;
|
||||
ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
|
||||
ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
|
||||
}
|
||||
|
||||
|
||||
if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
|
||||
return false;
|
||||
@@ -6216,8 +6284,6 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
|
||||
break;
|
||||
|
||||
case eEncodingT2:
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
// t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
|
||||
t = Bits32 (opcode, 15, 12);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
@@ -6227,7 +6293,15 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
|
||||
index = true;
|
||||
add = true;
|
||||
wback = false;
|
||||
|
||||
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
if (t == 15)
|
||||
return false; // PLD is not implemented yet
|
||||
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
if (n == 15)
|
||||
return EmulateLDRBLiteral(opcode, eEncodingT1);
|
||||
|
||||
// if t == 13 then UNPREDICTABLE;
|
||||
if (t == 13)
|
||||
return false;
|
||||
@@ -6235,14 +6309,12 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
|
||||
break;
|
||||
|
||||
case eEncodingT3:
|
||||
// if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
// if P == '1' && U == '1' && W == '0' then SEE LDRBT;
|
||||
// if P == '0' && W == '0' then UNDEFINED;
|
||||
if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
|
||||
return false;
|
||||
|
||||
// t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
|
||||
// t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
|
||||
t = Bits32 (opcode, 15, 12);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
imm32 = Bits32 (opcode, 7, 0);
|
||||
@@ -6251,7 +6323,15 @@ EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEnc
|
||||
index = BitIsSet (opcode, 10);
|
||||
add = BitIsSet (opcode, 9);
|
||||
wback = BitIsSet (opcode, 8);
|
||||
|
||||
|
||||
// if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
|
||||
if (t == 15)
|
||||
return false; // PLD is not implemented yet
|
||||
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
if (n == 15)
|
||||
return EmulateLDRBLiteral(opcode, eEncodingT1);
|
||||
|
||||
// if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
|
||||
if (BadReg (t) || (wback && (n == t)))
|
||||
return false;
|
||||
@@ -6333,11 +6413,14 @@ EmulateInstructionARM::EmulateLDRBLiteral (const uint32_t opcode, const ARMEncod
|
||||
switch (encoding)
|
||||
{
|
||||
case eEncodingT1:
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
// t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
|
||||
t = Bits32 (opcode, 15, 12);
|
||||
imm32 = Bits32 (opcode, 11, 0);
|
||||
add = BitIsSet (opcode, 23);
|
||||
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
if (t == 15)
|
||||
return false; // PLD is not implemented yet
|
||||
|
||||
// if t == 13 then UNPREDICTABLE;
|
||||
if (t == 13)
|
||||
@@ -6438,8 +6521,6 @@ EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEnco
|
||||
break;
|
||||
|
||||
case eEncodingT2:
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
// t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
|
||||
t = Bits32 (opcode, 15, 12);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
@@ -6453,6 +6534,14 @@ EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEnco
|
||||
// (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
|
||||
shift_t = SRType_LSL;
|
||||
shift_n = Bits32 (opcode, 5, 4);
|
||||
|
||||
// if Rt == '1111' then SEE PLD;
|
||||
if (t == 15)
|
||||
return false; // PLD is not implemented yet
|
||||
|
||||
// if Rn == '1111' then SEE LDRB (literal);
|
||||
if (n == 15)
|
||||
return EmulateLDRBLiteral(opcode, eEncodingT1);
|
||||
|
||||
// if t == 13 || BadReg(m) then UNPREDICTABLE;
|
||||
if ((t == 13) || BadReg (m))
|
||||
@@ -9726,14 +9815,20 @@ EmulateInstructionARM::EmulateSUBReg (const uint32_t opcode, const ARMEncoding e
|
||||
break;
|
||||
|
||||
case eEncodingT2:
|
||||
// if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register);
|
||||
// if Rn == Ô1101Õ then SEE SUB (SP minus register);
|
||||
// d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
|
||||
// d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1");
|
||||
d = Bits32 (opcode, 11, 8);
|
||||
n = Bits32 (opcode, 19, 16);
|
||||
m = Bits32 (opcode, 3, 0);
|
||||
setflags = BitIsSet (opcode, 20);
|
||||
|
||||
// if Rd == "1111" && S == "1" then SEE CMP (register);
|
||||
if (d == 15 && setflags == 1)
|
||||
return EmulateCMPImm (opcode, eEncodingT3);
|
||||
|
||||
// if Rn == "1101" then SEE SUB (SP minus register);
|
||||
if (n == 13)
|
||||
return EmulateSUBSPReg (opcode, eEncodingT1);
|
||||
|
||||
// (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
|
||||
shift_n = DecodeImmShiftThumb (opcode, shift_t);
|
||||
|
||||
@@ -12740,6 +12835,7 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint
|
||||
{ 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
|
||||
// cmp (register) (Rn and Rm not both from r0-r7)
|
||||
{ 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
|
||||
{ 0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c>.w <Rn>, <Rm> {, <shift>}"},
|
||||
// asr (immediate)
|
||||
{ 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"},
|
||||
{ 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"},
|
||||
@@ -13673,15 +13769,11 @@ EmulateInstructionARM::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
|
||||
|
||||
// Our previous Call Frame Address is the stack pointer
|
||||
row->GetCFAValue().SetIsRegisterPlusOffset (dwarf_sp, 0);
|
||||
|
||||
// Our previous PC is in the LR
|
||||
row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true);
|
||||
unwind_plan.AppendRow (row);
|
||||
|
||||
// All other registers are the same.
|
||||
|
||||
unwind_plan.AppendRow (row);
|
||||
unwind_plan.SetSourceName ("EmulateInstructionARM");
|
||||
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
|
||||
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
|
||||
unwind_plan.SetReturnAddressRegister (dwarf_lr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -350,17 +350,12 @@ EmulateInstructionARM64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
|
||||
|
||||
// Our previous Call Frame Address is the stack pointer
|
||||
row->GetCFAValue().SetIsRegisterPlusOffset(arm64_dwarf::sp, 0);
|
||||
|
||||
// Our previous PC is in the LR
|
||||
row->SetRegisterLocationToRegister(arm64_dwarf::pc, arm64_dwarf::lr, can_replace);
|
||||
|
||||
unwind_plan.AppendRow (row);
|
||||
|
||||
// All other registers are the same.
|
||||
|
||||
unwind_plan.SetSourceName ("EmulateInstructionARM64");
|
||||
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
|
||||
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
|
||||
unwind_plan.SetReturnAddressRegister (arm64_dwarf::lr);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2020,11 +2020,12 @@ ObjectFileELF::ParseSymbols (Symtab *symtab,
|
||||
symbol_section_sp, // Section in which this symbol is defined or null.
|
||||
symbol_value, // Offset in section or symbol value.
|
||||
symbol.st_size), // Size in bytes of this symbol.
|
||||
true, // Size is valid
|
||||
has_suffix, // Contains linker annotations?
|
||||
flags); // Symbol flags.
|
||||
symbol.st_size != 0, // Size is valid if it is not 0
|
||||
has_suffix, // Contains linker annotations?
|
||||
flags); // Symbol flags.
|
||||
symtab->AddSymbol(dc_symbol);
|
||||
}
|
||||
symtab->CalculateSymbolSizes();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -692,7 +692,7 @@ RegisterContextLLDB::GetFastUnwindPlanForFrame ()
|
||||
if (m_frame_type == eTrapHandlerFrame || m_frame_type == eDebuggerFrame)
|
||||
return unwind_plan_sp;
|
||||
|
||||
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
|
||||
unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (*m_thread.CalculateTarget(), m_thread);
|
||||
if (unwind_plan_sp)
|
||||
{
|
||||
if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
|
||||
@@ -1403,16 +1403,13 @@ RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_privat
|
||||
|
||||
if (unwindplan_regloc.IsSame())
|
||||
{
|
||||
if (IsFrameZero ())
|
||||
{
|
||||
UnwindLogMsg ("could not supply caller's %s (%d) location, IsSame",
|
||||
regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
|
||||
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
|
||||
}
|
||||
else
|
||||
{
|
||||
return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
|
||||
}
|
||||
regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
|
||||
regloc.location.register_number = regnum.GetAsKind (eRegisterKindLLDB);
|
||||
m_registers[regnum.GetAsKind (eRegisterKindLLDB)] = regloc;
|
||||
UnwindLogMsg ("supplying caller's register %s (%d), saved in register %s (%d)",
|
||||
regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB),
|
||||
regnum.GetName(), regnum.GetAsKind (eRegisterKindLLDB));
|
||||
return UnwindLLDB::RegisterSearchResult::eRegisterFound;
|
||||
}
|
||||
|
||||
if (unwindplan_regloc.IsCFAPlusOffset())
|
||||
|
||||
@@ -96,7 +96,13 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
|
||||
if (num_instructions > 0)
|
||||
{
|
||||
Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
|
||||
const addr_t base_addr = inst->GetAddress().GetFileAddress();
|
||||
const lldb::addr_t base_addr = inst->GetAddress().GetFileAddress();
|
||||
|
||||
// Map for storing the unwind plan row and the value of the registers at a given offset.
|
||||
// When we see a forward branch we add a new entry to this map with the actual unwind plan
|
||||
// row and register context for the target address of the branch as the current data have
|
||||
// to be valid for the target address of the branch too if we are in the same function.
|
||||
std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>> saved_unwind_states;
|
||||
|
||||
// Make a copy of the current instruction Row and save it in m_curr_row
|
||||
// so we can add updates as we process the instructions.
|
||||
@@ -106,18 +112,8 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
|
||||
*newrow = *last_row.get();
|
||||
m_curr_row.reset(newrow);
|
||||
|
||||
// Once we've seen the initial prologue instructions complete, save a
|
||||
// copy of the CFI at that point into prologue_completed_row for possible
|
||||
// use later.
|
||||
int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update
|
||||
|
||||
bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
|
||||
|
||||
bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate
|
||||
|
||||
bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
|
||||
|
||||
UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
|
||||
// Add the initial state to the save list with offset 0.
|
||||
saved_unwind_states.insert({0, {last_row, m_register_values}});
|
||||
|
||||
// cache the pc register number (in whatever register numbering this UnwindPlan uses) for
|
||||
// quick reference during instruction parsing.
|
||||
@@ -140,10 +136,27 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
|
||||
for (size_t idx=0; idx<num_instructions; ++idx)
|
||||
{
|
||||
m_curr_row_modified = false;
|
||||
m_curr_insn_restored_a_register = false;
|
||||
m_forward_branch_offset = 0;
|
||||
|
||||
inst = inst_list.GetInstructionAtIndex (idx).get();
|
||||
if (inst)
|
||||
{
|
||||
lldb::addr_t current_offset = inst->GetAddress().GetFileAddress() - base_addr;
|
||||
auto it = saved_unwind_states.upper_bound(current_offset);
|
||||
assert(it != saved_unwind_states.begin() && "Unwind row for the function entry missing");
|
||||
--it; // Move it to the row corresponding to the current offset
|
||||
|
||||
// If the offset of m_curr_row don't match with the offset we see in saved_unwind_states
|
||||
// then we have to update m_curr_row and m_register_values based on the saved values. It
|
||||
// is happenning after we processed an epilogue and a return to caller instruction.
|
||||
if (it->second.first->GetOffset() != m_curr_row->GetOffset())
|
||||
{
|
||||
UnwindPlan::Row *newrow = new UnwindPlan::Row;
|
||||
*newrow = *it->second.first;
|
||||
m_curr_row.reset(newrow);
|
||||
m_register_values = it->second.second;;
|
||||
}
|
||||
|
||||
if (log && log->GetVerbose ())
|
||||
{
|
||||
StreamString strm;
|
||||
@@ -159,111 +172,30 @@ UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange&
|
||||
|
||||
m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
|
||||
|
||||
// If the current instruction is a branch forward then save the current CFI information
|
||||
// for the offset where we are branching.
|
||||
if (m_forward_branch_offset != 0 && range.ContainsFileAddress(inst->GetAddress().GetFileAddress() + m_forward_branch_offset))
|
||||
{
|
||||
auto newrow = std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
|
||||
newrow->SetOffset(current_offset + m_forward_branch_offset);
|
||||
saved_unwind_states.insert({current_offset + m_forward_branch_offset, {newrow, m_register_values}});
|
||||
unwind_plan.InsertRow(newrow);
|
||||
}
|
||||
|
||||
// Were there any changes to the CFI while evaluating this instruction?
|
||||
if (m_curr_row_modified)
|
||||
{
|
||||
reinstate_prologue_next_instruction = false;
|
||||
m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
|
||||
// Append the new row
|
||||
unwind_plan.AppendRow (m_curr_row);
|
||||
|
||||
// Allocate a new Row for m_curr_row, copy the current state into it
|
||||
UnwindPlan::Row *newrow = new UnwindPlan::Row;
|
||||
*newrow = *m_curr_row.get();
|
||||
m_curr_row.reset(newrow);
|
||||
|
||||
// If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
|
||||
// Set instructions_since_last_prologue_insn to a very high number so we don't append
|
||||
// any of these epilogue instructions to our prologue_complete row.
|
||||
if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
|
||||
instructions_since_last_prologue_insn = 0;
|
||||
else
|
||||
instructions_since_last_prologue_insn = 99;
|
||||
|
||||
UnwindPlan::Row::RegisterLocation pc_regloc;
|
||||
UnwindPlan::Row::RegisterLocation ra_regloc;
|
||||
|
||||
// While parsing the instructions of this function, if we've ever
|
||||
// seen the return address register (aka lr on arm) in a non-IsSame() state,
|
||||
// it has been saved on the stack. If it's ever back to IsSame(), we've
|
||||
// executed an epilogue.
|
||||
if (ra_reg_num != LLDB_INVALID_REGNUM
|
||||
&& m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
|
||||
&& !ra_regloc.IsSame())
|
||||
// Save the modified row if we don't already have a CFI row in the currennt address
|
||||
if (saved_unwind_states.count(current_offset + inst->GetOpcode().GetByteSize()) == 0)
|
||||
{
|
||||
return_address_register_has_been_saved = true;
|
||||
}
|
||||
m_curr_row->SetOffset (current_offset + inst->GetOpcode().GetByteSize());
|
||||
unwind_plan.InsertRow (m_curr_row);
|
||||
saved_unwind_states.insert({current_offset + inst->GetOpcode().GetByteSize(), {m_curr_row, m_register_values}});
|
||||
|
||||
// If the caller's pc is "same", we've just executed an epilogue and we return to the caller
|
||||
// after this instruction completes executing.
|
||||
// If there are any instructions past this, there must have been flow control over this
|
||||
// epilogue so we'll reinstate the original prologue setup instructions.
|
||||
if (prologue_completed_row.get()
|
||||
&& pc_reg_num != LLDB_INVALID_REGNUM
|
||||
&& m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
|
||||
&& pc_regloc.IsSame())
|
||||
{
|
||||
if (log && log->GetVerbose())
|
||||
log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
|
||||
reinstate_prologue_next_instruction = true;
|
||||
}
|
||||
else if (prologue_completed_row.get()
|
||||
&& return_address_register_has_been_saved
|
||||
&& ra_reg_num != LLDB_INVALID_REGNUM
|
||||
&& m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
|
||||
&& ra_regloc.IsSame())
|
||||
{
|
||||
if (log && log->GetVerbose())
|
||||
log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
|
||||
last_instruction_restored_return_addr_reg = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the previous instruction was a return-to-caller (epilogue), and we're still executing
|
||||
// instructions in this function, there must be a code path that jumps over that epilogue.
|
||||
// Also detect the case where we epilogue & branch imm to another function (tail-call opt)
|
||||
// instead of a normal pop lr-into-pc exit.
|
||||
// Reinstate the frame setup from the prologue.
|
||||
if (reinstate_prologue_next_instruction
|
||||
|| (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
|
||||
{
|
||||
if (log && log->GetVerbose())
|
||||
log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
|
||||
UnwindPlan::Row *newrow = new UnwindPlan::Row;
|
||||
*newrow = *prologue_completed_row.get();
|
||||
m_curr_row.reset(newrow);
|
||||
m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
|
||||
unwind_plan.AppendRow(m_curr_row);
|
||||
|
||||
newrow = new UnwindPlan::Row;
|
||||
*newrow = *m_curr_row.get();
|
||||
m_curr_row.reset(newrow);
|
||||
|
||||
reinstate_prologue_next_instruction = false;
|
||||
last_instruction_restored_return_addr_reg = false;
|
||||
m_curr_insn_is_branch_immediate = false;
|
||||
}
|
||||
|
||||
// clear both of these if either one wasn't set
|
||||
if (last_instruction_restored_return_addr_reg)
|
||||
{
|
||||
last_instruction_restored_return_addr_reg = false;
|
||||
}
|
||||
if (m_curr_insn_is_branch_immediate)
|
||||
{
|
||||
m_curr_insn_is_branch_immediate = false;
|
||||
}
|
||||
|
||||
// Stop updating the prologue instructions if we've seen 8 non-prologue instructions
|
||||
// in a row.
|
||||
if (instructions_since_last_prologue_insn++ < 8)
|
||||
{
|
||||
// Allocate a new Row for m_curr_row, copy the current state into it
|
||||
UnwindPlan::Row *newrow = new UnwindPlan::Row;
|
||||
*newrow = *m_curr_row.get();
|
||||
prologue_completed_row.reset(newrow);
|
||||
if (log && log->GetVerbose())
|
||||
log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
|
||||
m_curr_row.reset(newrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,8 +392,7 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
|
||||
context.Dump(strm, instruction);
|
||||
log->PutCString (strm.GetData());
|
||||
}
|
||||
|
||||
const bool can_replace = true;
|
||||
|
||||
const bool cant_replace = false;
|
||||
|
||||
switch (context.type)
|
||||
@@ -491,19 +422,12 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
|
||||
case EmulateInstruction::eContextPushRegisterOnStack:
|
||||
{
|
||||
uint32_t reg_num = LLDB_INVALID_REGNUM;
|
||||
bool is_return_address_reg = false;
|
||||
const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
|
||||
if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
|
||||
{
|
||||
reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
|
||||
if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
|
||||
is_return_address_reg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (!"unhandled case, add code to handle this!");
|
||||
}
|
||||
|
||||
|
||||
if (reg_num != LLDB_INVALID_REGNUM)
|
||||
{
|
||||
if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
|
||||
@@ -512,21 +436,6 @@ UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
|
||||
const int32_t offset = addr - m_initial_sp;
|
||||
m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
|
||||
m_curr_row_modified = true;
|
||||
if (is_return_address_reg)
|
||||
{
|
||||
// This push was pushing the return address register,
|
||||
// so this is also how we will unwind the PC...
|
||||
RegisterInfo pc_reg_info;
|
||||
if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
|
||||
{
|
||||
uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
|
||||
if (pc_reg_num != LLDB_INVALID_REGNUM)
|
||||
{
|
||||
m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
|
||||
m_curr_row_modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -598,7 +507,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
|
||||
log->PutCString(strm.GetData());
|
||||
}
|
||||
|
||||
const bool must_replace = true;
|
||||
SetRegisterValue (*reg_info, reg_value);
|
||||
|
||||
switch (context.type)
|
||||
@@ -610,7 +518,6 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
|
||||
case EmulateInstruction::eContextRegisterPlusOffset:
|
||||
case EmulateInstruction::eContextAdjustPC:
|
||||
case EmulateInstruction::eContextRegisterStore:
|
||||
case EmulateInstruction::eContextAbsoluteBranchRegister:
|
||||
case EmulateInstruction::eContextSupervisorCall:
|
||||
case EmulateInstruction::eContextTableBranchReadMemory:
|
||||
case EmulateInstruction::eContextWriteRegisterRandomBits:
|
||||
@@ -619,6 +526,7 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
|
||||
case EmulateInstruction::eContextAdvancePC:
|
||||
case EmulateInstruction::eContextReturnFromException:
|
||||
case EmulateInstruction::eContextPushRegisterOnStack:
|
||||
case EmulateInstruction::eContextRegisterLoad:
|
||||
// {
|
||||
// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
|
||||
// if (reg_num != LLDB_INVALID_REGNUM)
|
||||
@@ -633,40 +541,18 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
|
||||
// }
|
||||
break;
|
||||
|
||||
case EmulateInstruction::eContextRegisterLoad:
|
||||
{
|
||||
const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
|
||||
const uint32_t reg_num = reg_info->kinds[unwind_reg_kind];
|
||||
if (reg_num != LLDB_INVALID_REGNUM)
|
||||
{
|
||||
m_curr_row->SetRegisterLocationToRegister (reg_num, reg_num, must_replace);
|
||||
m_curr_row_modified = true;
|
||||
m_curr_insn_restored_a_register = true;
|
||||
|
||||
if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
|
||||
{
|
||||
// This load was restoring the return address register,
|
||||
// so this is also how we will unwind the PC...
|
||||
RegisterInfo pc_reg_info;
|
||||
if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
|
||||
{
|
||||
uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
|
||||
if (pc_reg_num != LLDB_INVALID_REGNUM)
|
||||
{
|
||||
m_curr_row->SetRegisterLocationToRegister (pc_reg_num, reg_num, must_replace);
|
||||
m_curr_row_modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EmulateInstruction::eContextAbsoluteBranchRegister:
|
||||
case EmulateInstruction::eContextRelativeBranchImmediate:
|
||||
{
|
||||
|
||||
if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediate &&
|
||||
context.info.ISAAndImmediate.unsigned_data32 > 0)
|
||||
{
|
||||
m_curr_insn_is_branch_immediate = true;
|
||||
m_forward_branch_offset = context.info.ISAAndImmediateSigned.signed_data32;
|
||||
}
|
||||
else if (context.info_type == EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
|
||||
context.info.ISAAndImmediateSigned.signed_data32 > 0)
|
||||
{
|
||||
m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -676,9 +562,8 @@ UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
|
||||
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->SetRegisterLocationToSame (reg_num, /*must_replace*/ false);
|
||||
m_curr_row_modified = true;
|
||||
m_curr_insn_restored_a_register = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -141,8 +141,7 @@ private:
|
||||
m_register_values (),
|
||||
m_pushed_regs(),
|
||||
m_curr_row_modified (false),
|
||||
m_curr_insn_is_branch_immediate (false),
|
||||
m_curr_insn_restored_a_register (false)
|
||||
m_forward_branch_offset (0)
|
||||
{
|
||||
if (m_inst_emulator_ap.get())
|
||||
{
|
||||
@@ -178,13 +177,11 @@ private:
|
||||
// While processing the instruction stream, we need to communicate some state change
|
||||
// information up to the higher level loop that makes decisions about how to push
|
||||
// the unwind instructions for the UnwindPlan we're constructing.
|
||||
|
||||
|
||||
// The instruction we're processing updated the UnwindPlan::Row contents
|
||||
bool m_curr_row_modified;
|
||||
// The instruction we're examining is a branch immediate instruction
|
||||
bool m_curr_insn_is_branch_immediate;
|
||||
// The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
|
||||
bool m_curr_insn_restored_a_register;
|
||||
// The instruction is branching forward with the given offset. 0 value means no branching.
|
||||
uint32_t m_forward_branch_offset;
|
||||
};
|
||||
|
||||
#endif // liblldb_UnwindAssemblyInstEmulation_h_
|
||||
|
||||
@@ -154,7 +154,7 @@ FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, in
|
||||
// Augment the eh_frame instructions with epilogue descriptions if necessary so the
|
||||
// UnwindPlan can be used at any instruction in the function.
|
||||
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
|
||||
if (assembly_profiler_sp)
|
||||
{
|
||||
if (!assembly_profiler_sp->AugmentUnwindPlanFromCallSite (m_range, thread, *m_unwind_plan_eh_frame_augmented_sp))
|
||||
@@ -179,7 +179,7 @@ FuncUnwinders::GetAssemblyUnwindPlan (Target &target, Thread &thread, int curren
|
||||
Mutex::Locker lock (m_mutex);
|
||||
m_tried_unwind_plan_assembly = true;
|
||||
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
|
||||
if (assembly_profiler_sp)
|
||||
{
|
||||
m_unwind_plan_assembly_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
@@ -204,7 +204,7 @@ FuncUnwinders::GetUnwindPlanAtNonCallSite (Target& target, Thread& thread, int c
|
||||
}
|
||||
|
||||
UnwindPlanSP
|
||||
FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
|
||||
FuncUnwinders::GetUnwindPlanFastUnwind (Target& target, Thread& thread)
|
||||
{
|
||||
if (m_unwind_plan_fast_sp.get() || m_tried_unwind_fast)
|
||||
return m_unwind_plan_fast_sp;
|
||||
@@ -212,7 +212,7 @@ FuncUnwinders::GetUnwindPlanFastUnwind (Thread& thread)
|
||||
Mutex::Locker locker (m_mutex);
|
||||
m_tried_unwind_fast = true;
|
||||
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
|
||||
if (assembly_profiler_sp)
|
||||
{
|
||||
m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
|
||||
@@ -287,7 +287,7 @@ FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
|
||||
|
||||
Mutex::Locker locker (m_mutex);
|
||||
ExecutionContext exe_ctx (target.shared_from_this(), false);
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler());
|
||||
UnwindAssemblySP assembly_profiler_sp (GetUnwindAssemblyProfiler(target));
|
||||
if (assembly_profiler_sp)
|
||||
assembly_profiler_sp->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
|
||||
return m_first_non_prologue_insn;
|
||||
@@ -300,12 +300,13 @@ FuncUnwinders::GetFunctionStartAddress () const
|
||||
}
|
||||
|
||||
lldb::UnwindAssemblySP
|
||||
FuncUnwinders::GetUnwindAssemblyProfiler ()
|
||||
FuncUnwinders::GetUnwindAssemblyProfiler (Target& target)
|
||||
{
|
||||
UnwindAssemblySP assembly_profiler_sp;
|
||||
ArchSpec arch;
|
||||
if (m_unwind_table.GetArchitecture (arch))
|
||||
{
|
||||
arch.MergeFrom (target.GetArchitecture ());
|
||||
assembly_profiler_sp = UnwindAssembly::FindPlugin (arch);
|
||||
}
|
||||
return assembly_profiler_sp;
|
||||
|
||||
@@ -343,11 +343,12 @@ UnwindPlan::InsertRow (const UnwindPlan::RowSP &row_sp)
|
||||
collection::iterator it = m_row_list.begin();
|
||||
while (it != m_row_list.end()) {
|
||||
RowSP row = *it;
|
||||
if (row->GetOffset() > row_sp->GetOffset())
|
||||
if (row->GetOffset() >= row_sp->GetOffset())
|
||||
break;
|
||||
it++;
|
||||
}
|
||||
m_row_list.insert(it, row_sp);
|
||||
if (it == m_row_list.end() || (*it)->GetOffset() != row_sp->GetOffset())
|
||||
m_row_list.insert(it, row_sp);
|
||||
}
|
||||
|
||||
UnwindPlan::RowSP
|
||||
|
||||
Reference in New Issue
Block a user