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:
Tamas Berghammer
2015-06-24 11:27:32 +00:00
parent 1d2353d4f3
commit 44ff9ccede
10 changed files with 295 additions and 326 deletions

View File

@@ -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;

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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())

View File

@@ -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;

View File

@@ -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_

View File

@@ -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;

View File

@@ -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