diff options
author | Tamas Berghammer <tberghammer@google.com> | 2015-04-15 09:47:02 +0000 |
---|---|---|
committer | Tamas Berghammer <tberghammer@google.com> | 2015-04-15 09:47:02 +0000 |
commit | d8c338d42f81db3d2544e19b03e35b94661785a9 (patch) | |
tree | a3238e9ff4b9508bc43d44b972788a8ddc9ff0ce /lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp | |
parent | 63c8be9571df98df49d80cc760092de26106e82a (diff) | |
download | bcm5719-llvm-d8c338d42f81db3d2544e19b03e35b94661785a9.tar.gz bcm5719-llvm-d8c338d42f81db3d2544e19b03e35b94661785a9.zip |
Add single stepping logic for linux arm
Linux arm don't support hardware stepping (neither mismatch
breakpoints). This patch implement signle stepping with doing a software
emulation of the next instruction and then setting a temporary
breakpoint at the address where the thread will stop next.
Differential revision: http://reviews.llvm.org/D8976
llvm-svn: 234987
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 286e21afec5..f740669af77 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -24,6 +24,7 @@ // Other libraries and framework includes #include "lldb/Core/Debugger.h" +#include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Error.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -2375,6 +2376,19 @@ NativeProcessLinux::MonitorBreakpoint(lldb::pid_t pid, NativeThreadProtocolSP th if (log) log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", __FUNCTION__, pid, error.AsCString()); + + auto it = m_threads_stepping_with_breakpoint.find(pid); + if (it != m_threads_stepping_with_breakpoint.end()) + { + Error error = RemoveBreakpoint (it->second); + if (error.Fail()) + if (log) + log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " remove stepping breakpoint: %s", + __FUNCTION__, pid, error.AsCString()); + + m_threads_stepping_with_breakpoint.erase(it); + std::static_pointer_cast<NativeThreadLinux>(thread_sp)->SetStoppedByTrace(); + } } else if (log) @@ -3590,6 +3604,151 @@ NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo) return op.GetError(); } +#if defined(__arm__) + +namespace { + +struct EmulatorBaton +{ + NativeProcessLinux* m_process; + NativeRegisterContext* m_reg_context; + RegisterValue m_pc; + RegisterValue m_cpsr; + + EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) : + m_process(process), m_reg_context(reg_context) {} +}; + +} // anonymous namespace + +static size_t +ReadMemoryCallback (EmulateInstruction *instruction, + void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, + void *dst, + size_t length) +{ + EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton); + + lldb::addr_t bytes_read; + emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); + return bytes_read; +} + +static bool +ReadRegisterCallback (EmulateInstruction *instruction, + void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value) +{ + EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton); + + // The emulator only fill in the dwarf regsiter numbers (and in some case + // the generic register numbers). Get the full register info from the + // register context based on the dwarf register numbers. + const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo( + eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); + + Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); + return error.Success(); +} + +static bool +WriteRegisterCallback (EmulateInstruction *instruction, + void *baton, + const EmulateInstruction::Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value) +{ + EmulatorBaton* emulator_baton = static_cast<EmulatorBaton*>(baton); + + switch (reg_info->kinds[eRegisterKindGeneric]) + { + case LLDB_REGNUM_GENERIC_PC: + emulator_baton->m_pc = reg_value; + break; + case LLDB_REGNUM_GENERIC_FLAGS: + emulator_baton->m_cpsr = reg_value; + break; + } + + return true; +} + +static size_t WriteMemoryCallback (EmulateInstruction *instruction, + void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, + const void *dst, + size_t length) +{ + return length; +} + +Error +NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo) +{ + Error error; + NativeRegisterContextSP register_context_sp = GetThreadByID(tid)->GetRegisterContext(); + + std::unique_ptr<EmulateInstruction> emulator_ap( + EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, nullptr)); + + if (emulator_ap == nullptr) + return Error("Instrunction emulator not found!"); + + EmulatorBaton baton(this, register_context_sp.get()); + emulator_ap->SetBaton(&baton); + emulator_ap->SetReadMemCallback(&ReadMemoryCallback); + emulator_ap->SetReadRegCallback(&ReadRegisterCallback); + emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); + emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); + + if (!emulator_ap->ReadInstruction()) + return Error("Read instruction failed!"); + + if (!emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC)) + return Error("Evaluate instrcution failed!"); + + lldb::addr_t next_pc = baton.m_pc.GetAsUInt32(); + lldb::addr_t next_cpsr = 0; + if (baton.m_cpsr.GetType() != RegisterValue::eTypeInvalid) + { + next_cpsr = baton.m_cpsr.GetAsUInt32(); + } + else + { + const RegisterInfo* cpsr_info = register_context_sp->GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + next_cpsr = register_context_sp->ReadRegisterAsUnsigned(cpsr_info, LLDB_INVALID_ADDRESS); + } + + if (next_cpsr & 0x20) + { + // Thumb mode + error = SetBreakpoint(next_pc, 2, false); + } + else + { + // Arm mode + error = SetBreakpoint(next_pc, 4, false); + } + + if (error.Fail()) + return error; + + m_threads_stepping_with_breakpoint.emplace(tid, next_pc); + + error = Resume(tid, signo); + if (error.Fail()) + return error; + + return Error(); +} + +#else // defined(__arm__) + Error NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo) { @@ -3598,6 +3757,8 @@ NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo) return op.GetError(); } +#endif // defined(__arm__) + Error NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) { |