[Lldb-commits] [lldb] r225770 - Change the x86 assembly instruction unwind parser to
Jason Molenda
jmolenda at apple.com
Mon Jan 12 22:04:05 PST 2015
Author: jmolenda
Date: Tue Jan 13 00:04:04 2015
New Revision: 225770
URL: http://llvm.org/viewvc/llvm-project?rev=225770&view=rev
Log:
Change the x86 assembly instruction unwind parser to
step through the complete function looking for any epilogue
instructions. If we find an epilogue sequence, re-instate
the correct unwind instructions if there is more code past
that epilogue -- this will correctly handle an x86 function
with multiple epilogues in it.
NB there is still a bug with the "eh_frame augmented"
UnwindPlans and mid-function epilogues. Looking at that next.
<rdar://problem/18863406>
Modified:
lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
lldb/trunk/include/lldb/Symbol/UnwindPlan.h
lldb/trunk/source/Commands/CommandObjectTarget.cpp
lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
lldb/trunk/source/Symbol/UnwindPlan.cpp
Modified: lldb/trunk/include/lldb/Symbol/FuncUnwinders.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/FuncUnwinders.h?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h (original)
+++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h Tue Jan 13 00:04:04 2015
@@ -84,10 +84,11 @@ public:
Address
GetPersonalityRoutinePtrAddress (Target &target);
-private:
- lldb::UnwindAssemblySP
- GetUnwindAssemblyProfiler ();
+
+ // The following methods to retrieve specific unwind plans should rarely be used.
+ // Instead, clients should ask for the *behavior* they are looking for, using one
+ // of the above UnwindPlan retrieval methods.
lldb::UnwindPlanSP
GetAssemblyUnwindPlan (Target &target, Thread &thread, int current_offset);
@@ -102,13 +103,15 @@ private:
GetCompactUnwindUnwindPlan (Target &target, int current_offset);
lldb::UnwindPlanSP
- GetFastUnwindPlan (Target &target, int current_offset);
+ GetArchDefaultUnwindPlan (Thread &thread);
lldb::UnwindPlanSP
- GetArchDefaultUnwindPlan (Target &target, int current_offset);
+ GetArchDefaultAtFuncEntryUnwindPlan (Thread &thread);
- lldb::UnwindPlanSP
- GetArchDefaultAtFuncEntryUnwindPlan (Target &target, int current_offset);
+private:
+
+ lldb::UnwindAssemblySP
+ GetUnwindAssemblyProfiler ();
UnwindTable& m_unwind_table;
AddressRange m_range;
Modified: lldb/trunk/include/lldb/Symbol/UnwindPlan.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/UnwindPlan.h?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/UnwindPlan.h (original)
+++ lldb/trunk/include/lldb/Symbol/UnwindPlan.h Tue Jan 13 00:04:04 2015
@@ -257,7 +257,10 @@ public:
void
SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
-
+
+ void
+ RemoveRegisterInfo (uint32_t reg_num);
+
lldb::addr_t
GetOffset() const
{
Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Tue Jan 13 00:04:04 2015
@@ -3744,45 +3744,85 @@ protected:
if (func_unwinders_sp.get() == NULL)
continue;
- Address first_non_prologue_insn (func_unwinders_sp->GetFirstNonPrologueInsn(*target));
- if (first_non_prologue_insn.IsValid())
- {
- result.GetOutputStream().Printf("First non-prologue instruction is at address 0x%" PRIx64 " or offset %" PRId64 " into the function.\n", first_non_prologue_insn.GetLoadAddress(target), first_non_prologue_insn.GetLoadAddress(target) - start_addr);
- result.GetOutputStream().Printf ("\n");
- }
+ result.GetOutputStream().Printf("UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread.get(), -1);
if (non_callsite_unwind_plan.get())
{
- result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- non_callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("Asynchronous (not restricted to call-sites) UnwindPlan is '%s'\n", non_callsite_unwind_plan->GetSourceName().AsCString());
}
-
UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(*target, -1);
if (callsite_unwind_plan.get())
{
- result.GetOutputStream().Printf("Synchronous (restricted to call-sites) UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- callsite_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ 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());
+ if (fast_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan is '%s'\n", fast_unwind_plan->GetSourceName().AsCString());
+ }
+
+ result.GetOutputStream().Printf("\n");
- UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get());
- if (arch_default_unwind_plan.get())
+ UnwindPlanSP assembly_sp = func_unwinders_sp->GetAssemblyUnwindPlan(*target, *thread.get(), 0);
+ if (assembly_sp)
{
- result.GetOutputStream().Printf("Architecture default UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
- arch_default_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("Assembly language inspection UnwindPlan:\n");
+ assembly_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
}
+
- UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
- if (fast_unwind_plan.get())
+ UnwindPlanSP ehframe_sp = func_unwinders_sp->GetEHFrameUnwindPlan(*target, 0);
+ if (ehframe_sp)
{
- result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ result.GetOutputStream().Printf("eh_frame UnwindPlan:\n");
+ ehframe_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlanSP ehframe_augmented_sp = func_unwinders_sp->GetEHFrameAugmentedUnwindPlan(*target, *thread.get(), 0);
+ if (ehframe_augmented_sp)
+ {
+ result.GetOutputStream().Printf("eh_frame augmented UnwindPlan:\n");
+ ehframe_augmented_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlanSP compact_unwind_sp = func_unwinders_sp->GetCompactUnwindUnwindPlan(*target, 0);
+ if (compact_unwind_sp)
+ {
+ result.GetOutputStream().Printf("Compact unwind UnwindPlan:\n");
+ compact_unwind_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ if (fast_unwind_plan)
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan:\n");
fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
- result.GetOutputStream().Printf ("\n");
+ result.GetOutputStream().Printf("\n");
}
+ ABISP abi_sp = process->GetABI();
+ if (abi_sp)
+ {
+ UnwindPlan arch_default(lldb::eRegisterKindGeneric);
+ if (abi_sp->CreateDefaultUnwindPlan (arch_default))
+ {
+ result.GetOutputStream().Printf("Arch default UnwindPlan:\n");
+ arch_default.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+
+ UnwindPlan arch_entry(lldb::eRegisterKindGeneric);
+ if (abi_sp->CreateFunctionEntryUnwindPlan (arch_entry))
+ {
+ result.GetOutputStream().Printf("Arch default at entry point UnwindPlan:\n");
+ arch_entry.Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf("\n");
+ }
+ }
result.GetOutputStream().Printf ("\n");
}
Modified: lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp (original)
+++ lldb/trunk/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp Tue Jan 13 00:04:04 2015
@@ -319,7 +319,8 @@ AssemblyParse_x86::nonvolatile_reg_p (in
#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
// pushq %rbp [0x55]
-bool AssemblyParse_x86::push_rbp_pattern_p ()
+bool
+AssemblyParse_x86::push_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x55)
@@ -328,7 +329,8 @@ bool AssemblyParse_x86::push_rbp_pattern
}
// pushq $0 ; the first instruction in start() [0x6a 0x00]
-bool AssemblyParse_x86::push_0_pattern_p ()
+bool
+AssemblyParse_x86::push_0_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x6a && *(p + 1) == 0x0)
@@ -338,7 +340,8 @@ bool AssemblyParse_x86::push_0_pattern_p
// pushq $0
// pushl $0
-bool AssemblyParse_x86::push_imm_pattern_p ()
+bool
+AssemblyParse_x86::push_imm_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (*p == 0x68 || *p == 0x6a)
@@ -348,7 +351,8 @@ bool AssemblyParse_x86::push_imm_pattern
// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
-bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
+bool
+AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -361,7 +365,8 @@ bool AssemblyParse_x86::mov_rsp_rbp_patt
}
// subq $0x20, %rsp
-bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
+bool
+AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -382,7 +387,8 @@ bool AssemblyParse_x86::sub_rsp_pattern_
}
// addq $0x20, %rsp
-bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
+bool
+AssemblyParse_x86::add_rsp_pattern_p (int& amount)
{
uint8_t *p = m_cur_insn_bytes;
if (m_wordsize == 8 && *p == 0x48)
@@ -404,7 +410,8 @@ bool AssemblyParse_x86::add_rsp_pattern_
// pushq %rbx
// pushl %ebx
-bool AssemblyParse_x86::push_reg_p (int& regno)
+bool
+AssemblyParse_x86::push_reg_p (int& regno)
{
uint8_t *p = m_cur_insn_bytes;
int regno_prefix_bit = 0;
@@ -424,7 +431,8 @@ bool AssemblyParse_x86::push_reg_p (int&
// popq %rbx
// popl %ebx
-bool AssemblyParse_x86::pop_reg_p (int& regno)
+bool
+AssemblyParse_x86::pop_reg_p (int& regno)
{
uint8_t *p = m_cur_insn_bytes;
int regno_prefix_bit = 0;
@@ -444,14 +452,16 @@ bool AssemblyParse_x86::pop_reg_p (int&
// popq %rbp [0x5d]
// popl %ebp [0x5d]
-bool AssemblyParse_x86::pop_rbp_pattern_p ()
+bool
+AssemblyParse_x86::pop_rbp_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
return (*p == 0x5d);
}
// call $0 [0xe8 0x0 0x0 0x0 0x0]
-bool AssemblyParse_x86::call_next_insn_pattern_p ()
+bool
+AssemblyParse_x86::call_next_insn_pattern_p ()
{
uint8_t *p = m_cur_insn_bytes;
return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
@@ -469,7 +479,8 @@ bool AssemblyParse_x86::call_next_insn_p
// the actual location. The positive value returned for the offset
// is a convention used elsewhere for CFA offsets et al.
-bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
+bool
+AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
{
uint8_t *p = m_cur_insn_bytes;
int src_reg_prefix_bit = 0;
@@ -603,7 +614,6 @@ bool
AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
{
UnwindPlan::RowSP row(new UnwindPlan::Row);
- int non_prologue_insn_count = 0;
m_cur_insn = m_func_bounds.GetBaseAddress ();
int current_func_text_offset = 0;
int current_sp_bytes_offset_from_cfa = 0;
@@ -647,18 +657,29 @@ AssemblyParse_x86::get_non_call_site_unw
const bool prefer_file_cache = true;
+ // Once the prologue has completed we'll save a copy of the unwind instructions
+ // If there is an epilogue in the middle of the function, after that epilogue we'll reinstate
+ // the unwind setup -- we assume that some code path jumps over the mid-function epilogue
+
+ bool in_epilogue = false; // we're in the middle of an epilogue sequence
+ UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+ int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the epilogue started executed
+
Target *target = m_exe_ctx.GetTargetPtr();
- while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
{
int stack_offset, insn_len;
int machine_regno; // register numbers masked directly out of instructions
uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
+ bool row_updated = false;
+
if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
{
// An unrecognized/junk instruction
break;
}
+
if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
insn_len, error) == static_cast<size_t>(-1))
{
@@ -668,232 +689,170 @@ AssemblyParse_x86::get_non_call_site_unw
if (push_rbp_pattern_p ())
{
- row->SetOffset (current_func_text_offset + insn_len);
current_sp_bytes_offset_from_cfa += m_wordsize;
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
UnwindPlan::Row::RegisterLocation regloc;
regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ saved_registers[m_machine_fp_regnum] = true;
+ row_updated = true;
}
- if (mov_rsp_rbp_pattern_p ())
+ else if (mov_rsp_rbp_pattern_p ())
{
- row->SetOffset (current_func_text_offset + insn_len);
row->SetCFARegister (m_lldb_fp_regnum);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ row_updated = true;
}
// This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
// saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all --
// normally the saved pc value is already on the stack by the time the function starts executing.
- if (push_0_pattern_p ())
+ else if (push_0_pattern_p ())
{
- goto loopnext;
}
- if (push_reg_p (machine_regno))
+ else if (push_reg_p (machine_regno))
{
current_sp_bytes_offset_from_cfa += m_wordsize;
- bool need_to_push_row = false;
// the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
// we need to add a new row of instructions.
if (row->GetCFARegister() == m_lldb_sp_regnum)
{
- need_to_push_row = true;
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
}
// record where non-volatile (callee-saved, spilled) registers are saved on the stack
if (nonvolatile_reg_p (machine_regno)
&& machine_regno_to_lldb_regno (machine_regno, lldb_regno)
&& saved_registers[machine_regno] == false)
{
- need_to_push_row = true;
UnwindPlan::Row::RegisterLocation regloc;
regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
row->SetRegisterInfo (lldb_regno, regloc);
saved_registers[machine_regno] = true;
+ row_updated = true;
}
- if (need_to_push_row)
- {
- row->SetOffset (current_func_text_offset + insn_len);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- }
- goto loopnext;
}
- if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
+ else if (pop_reg_p (machine_regno))
{
- if (machine_regno_to_lldb_regno (machine_regno, lldb_regno) && saved_registers[machine_regno] == false)
- {
- saved_registers[machine_regno] = true;
+ current_sp_bytes_offset_from_cfa -= m_wordsize;
- row->SetOffset (current_func_text_offset + insn_len);
- UnwindPlan::Row::RegisterLocation regloc;
+ if (nonvolatile_reg_p (machine_regno)
+ && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+ && saved_registers[machine_regno] == true)
+ {
+ saved_registers[machine_regno] = false;
+ row->RemoveRegisterInfo (lldb_regno);
- // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
- // In the Row, we want to express this as the offset from the CFA. If the frame base
- // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
- // want to say that the value is stored at the CFA address - 96.
- regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
+ if (machine_regno == m_machine_fp_regnum)
+ {
+ row->SetCFARegister (m_lldb_sp_regnum);
+ }
- row->SetRegisterInfo (lldb_regno, regloc);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
- goto loopnext;
+ in_epilogue = true;
+ row_updated = true;
}
- }
- if (sub_rsp_pattern_p (stack_offset))
- {
- current_sp_bytes_offset_from_cfa += stack_offset;
+ // the POP instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
+ // we need to add a new row of instructions.
if (row->GetCFARegister() == m_lldb_sp_regnum)
{
- row->SetOffset (current_func_text_offset + insn_len);
row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
- unwind_plan.AppendRow (row);
- // Allocate a new Row, populate it with the existing Row contents.
- newrow = new UnwindPlan::Row;
- *newrow = *row.get();
- row.reset(newrow);
+ row_updated = true;
}
- goto loopnext;
}
- if (ret_pattern_p ())
+ else if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset)
+ && nonvolatile_reg_p (machine_regno)
+ && machine_regno_to_lldb_regno (machine_regno, lldb_regno)
+ && saved_registers[machine_regno] == false)
{
- // we know where the end of the function is; set the limit on the PlanValidAddressRange
- // in case our initial "high pc" value was overly large
- // int original_size = m_func_bounds.GetByteSize();
- // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
- // m_func_bounds.SetByteSize (calculated_size);
- // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
- break;
- }
-
- // FIXME recognize the i386 picbase setup instruction sequence,
- // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
- // 0x1f1b: popl %eax
- // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
-
- non_prologue_insn_count++;
-loopnext:
- m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
- current_func_text_offset += insn_len;
- }
+ saved_registers[machine_regno] = true;
- // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
- // epilogue. We're looking for the sequence
+ UnwindPlan::Row::RegisterLocation regloc;
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xc3 ] ret
+ // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
+ // In the Row, we want to express this as the offset from the CFA. If the frame base
+ // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
+ // want to say that the value is stored at the CFA address - 96.
+ regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
- // or
+ row->SetRegisterInfo (lldb_regno, regloc);
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function)
+ row_updated = true;
+ }
- // or
+ else if (sub_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa += stack_offset;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ }
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xc3 ] ret
- // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
+ else if (add_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa -= stack_offset;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ row_updated = true;
+ }
+ in_epilogue = true;
+ }
- // or
+ else if (ret_pattern_p () && prologue_completed_row.get())
+ {
+ // Reinstate the saved prologue setup for any instructions
+ // that come after the ret instruction
- // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
- // [ 0xc3 ] ret
- // [ 0x0f 0x1f 0x44 xx xx ] nopl (%rax,%rax) (aka nop)
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *prologue_completed_row.get();
+ row.reset (newrow);
+ current_sp_bytes_offset_from_cfa = prologue_completed_sp_bytes_offset_from_cfa;
- // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
- // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
- // (or the 'jmp' instruction in the second case)
+ in_epilogue = true;
+ row_updated = true;
+ }
- uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
- Address end_of_fun(m_func_bounds.GetBaseAddress());
- end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+ // FIXME recognize the i386 picbase setup instruction sequence,
+ // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
+ // 0x1f1b: popl %eax
+ // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
- if (m_func_bounds.GetByteSize() > 7)
- {
- uint8_t bytebuf[7];
- Address last_seven_bytes(end_of_fun);
- last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
- if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
- error) != static_cast<size_t>(-1))
+ if (row_updated)
{
- if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret
- {
- ret_insn_offset = m_func_bounds.GetByteSize() - 1;
- }
- else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp
- {
- // When the pc is sitting on the 'jmp' instruction, we have the same
- // unwind state as if it was sitting on a 'ret' instruction.
- ret_insn_offset = m_func_bounds.GetByteSize() - 5;
- }
- else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
+ if (current_func_text_offset + insn_len < m_func_bounds.GetByteSize())
{
- ret_insn_offset = m_func_bounds.GetByteSize() - 6;
- }
- else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3
- && bytebuf[2] == 0x0f && bytebuf[3] == 0x1f && bytebuf[4] == 0x44) // mov & ret & nop
- {
- ret_insn_offset = m_func_bounds.GetByteSize() - 6;
+ row->SetOffset (current_func_text_offset + insn_len);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
}
}
- }
- else if (m_func_bounds.GetByteSize() > 2)
- {
- uint8_t bytebuf[2];
- Address last_two_bytes(end_of_fun);
- last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
- if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
- error) != static_cast<size_t>(-1))
+
+ if (in_epilogue == false && row_updated)
{
- if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
- {
- ret_insn_offset = m_func_bounds.GetByteSize() - 1;
- }
+ // If we're not in an epilogue sequence, save the updated Row
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ prologue_completed_row.reset (newrow);
}
- }
- if (ret_insn_offset != LLDB_INVALID_ADDRESS)
- {
- // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
- UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
- UnwindPlan::Row::RegisterLocation epi_regloc;
-
- // When the ret instruction is about to be executed, here's our state
- epi_row->SetOffset (ret_insn_offset);
- epi_row->SetCFARegister (m_lldb_sp_regnum);
- epi_row->SetCFAOffset (m_wordsize);
-
- // caller's stack pointer value before the call insn is the CFA address
- epi_regloc.SetIsCFAPlusOffset (0);
- epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
-
- // saved instruction pointer can be found at CFA - wordsize
- epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
- epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+ // We may change the sp value without adding a new Row necessarily -- keep
+ // track of it either way.
+ if (in_epilogue == false)
+ {
+ prologue_completed_sp_bytes_offset_from_cfa = current_sp_bytes_offset_from_cfa;
+ }
- unwind_plan.AppendRow (epi_row);
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ current_func_text_offset += insn_len;
}
unwind_plan.SetSourceName ("assembly insn profiling");
Modified: lldb/trunk/source/Symbol/UnwindPlan.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/UnwindPlan.cpp?rev=225770&r1=225769&r2=225770&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/UnwindPlan.cpp (original)
+++ lldb/trunk/source/Symbol/UnwindPlan.cpp Tue Jan 13 00:04:04 2015
@@ -168,7 +168,7 @@ UnwindPlan::Row::Dump (Stream& s, const
if (base_addr != LLDB_INVALID_ADDRESS)
s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
else
- s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
+ s.Printf ("%4" PRId64 ": CFA=", GetOffset());
if (reg_info)
s.Printf ("%s", reg_info->name);
@@ -211,6 +211,16 @@ UnwindPlan::Row::GetRegisterInfo (uint32
}
void
+UnwindPlan::Row::RemoveRegisterInfo (uint32_t reg_num)
+{
+ collection::const_iterator pos = m_register_locations.find(reg_num);
+ if (pos != m_register_locations.end())
+ {
+ m_register_locations.erase(pos);
+ }
+}
+
+void
UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
{
m_register_locations[reg_num] = register_location;
More information about the lldb-commits
mailing list