summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2012-05-25 01:54:06 +0000
committerJason Molenda <jmolenda@apple.com>2012-05-25 01:54:06 +0000
commit6f5e8c2647d98d4f7ca3a44d87f235e0c032ba6a (patch)
tree412de9f0c3f6fd4d57657d754e751d748f4e3144 /lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
parent268f154f489f52954d719b23b49b18bc356cbebe (diff)
downloadbcm5719-llvm-6f5e8c2647d98d4f7ca3a44d87f235e0c032ba6a.tar.gz
bcm5719-llvm-6f5e8c2647d98d4f7ca3a44d87f235e0c032ba6a.zip
Add support for function with stack frame checks added by the compiler;
these functions will end in the sequence mov %rbp, %rsp ret call __stack_chk_fail instead of the usual mov, ret. The x86 assembly profiler only looked for functions ending in 'ret' and added the Unwind row describing how to set the CFA based on that -- the addition of the call insn (which is jumped to earlier in the function body) threw off that inspection. Resolves the need to "step" twice to get out of these functions when doing source-level stepping. <rdar://problem/11469705> llvm-svn: 157454
Diffstat (limited to 'lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp')
-rw-r--r--lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp85
1 files changed, 57 insertions, 28 deletions
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
index c0daaac2882..27e3622696d 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -676,40 +676,69 @@ loopnext:
}
// Now look at the byte at the end of the AddressRange for a limited attempt at describing the
- // epilogue. If this function is built -fomit-frame-pointer (so the CFA is defined in terms of the
- // stack pointer) we'd need to profile every instruction which causes rsp to change to backtrace
- // all the time. But assuming the CFA is in terms of rbp most of the time, this one additional Row
- // will be sufficient.
+ // epilogue. We're looking for the sequence
- if (m_func_bounds.GetByteSize() > 2)
+ // [ 0x5d ] mov %rbp, %rsp
+ // [ 0xc3 ] ret
+ // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
+
+ // 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.
+
+ 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());
+
+ if (m_func_bounds.GetByteSize() > 7)
{
- Address last_insn (m_func_bounds.GetBaseAddress());
- last_insn.SetOffset (last_insn.GetOffset() + m_func_bounds.GetByteSize() - 1);
- uint8_t bytebuf[1];
- if (target->ReadMemory (last_insn, prefer_file_cache, bytebuf, 1, error) != -1)
+ 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) != -1)
{
- if (bytebuf[0] == 0xc3) // ret aka retq
+ if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov, ret
{
- // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
- UnwindPlan::Row epi_row;
- UnwindPlan::Row::RegisterLocation epi_regloc;
-
- // When the ret instruction is about to be executed, here's our state
- epi_row.SetOffset (m_func_bounds.GetByteSize() - 1);
- 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);
-
- unwind_plan.AppendRow (epi_row);
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 6;
}
}
+ } 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) != -1)
+ {
+ if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ }
+ }
+
+ if (ret_insn_offset != LLDB_INVALID_ADDRESS)
+ {
+ // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
+ UnwindPlan::Row epi_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);
+
+ unwind_plan.AppendRow (epi_row);
}
unwind_plan.SetSourceName ("assembly insn profiling");
OpenPOWER on IntegriCloud