mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-20 15:14:45 +00:00
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
This commit is contained in:
parent
63c8be9571
commit
d8c338d42f
@ -22,7 +22,6 @@
|
|||||||
#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
|
#include "Plugins/ABI/SysV-ppc64/ABISysV_ppc64.h"
|
||||||
#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
|
#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
|
||||||
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
|
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
|
||||||
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
|
|
||||||
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
|
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
|
||||||
#include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h"
|
#include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h"
|
||||||
#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
|
#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
|
||||||
@ -251,7 +250,6 @@ SystemInitializerFull::Initialize()
|
|||||||
SymbolFileSymtab::Initialize();
|
SymbolFileSymtab::Initialize();
|
||||||
UnwindAssemblyInstEmulation::Initialize();
|
UnwindAssemblyInstEmulation::Initialize();
|
||||||
UnwindAssembly_x86::Initialize();
|
UnwindAssembly_x86::Initialize();
|
||||||
EmulateInstructionARM::Initialize();
|
|
||||||
EmulateInstructionARM64::Initialize();
|
EmulateInstructionARM64::Initialize();
|
||||||
EmulateInstructionMIPS64::Initialize();
|
EmulateInstructionMIPS64::Initialize();
|
||||||
SymbolFileDWARFDebugMap::Initialize();
|
SymbolFileDWARFDebugMap::Initialize();
|
||||||
@ -355,7 +353,6 @@ SystemInitializerFull::Terminate()
|
|||||||
SymbolFileSymtab::Terminate();
|
SymbolFileSymtab::Terminate();
|
||||||
UnwindAssembly_x86::Terminate();
|
UnwindAssembly_x86::Terminate();
|
||||||
UnwindAssemblyInstEmulation::Terminate();
|
UnwindAssemblyInstEmulation::Terminate();
|
||||||
EmulateInstructionARM::Terminate();
|
|
||||||
EmulateInstructionARM64::Terminate();
|
EmulateInstructionARM64::Terminate();
|
||||||
EmulateInstructionMIPS64::Terminate();
|
EmulateInstructionMIPS64::Terminate();
|
||||||
SymbolFileDWARFDebugMap::Terminate();
|
SymbolFileDWARFDebugMap::Terminate();
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
|
#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
|
||||||
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
|
#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
|
||||||
|
#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
|
||||||
#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
|
#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
|
||||||
#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
|
#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
|
||||||
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
|
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
|
||||||
@ -110,6 +111,8 @@ SystemInitializerCommon::Initialize()
|
|||||||
PlatformKalimba::Initialize();
|
PlatformKalimba::Initialize();
|
||||||
platform_android::PlatformAndroid::Initialize();
|
platform_android::PlatformAndroid::Initialize();
|
||||||
|
|
||||||
|
EmulateInstructionARM::Initialize();
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// Apple/Darwin hosted plugins
|
// Apple/Darwin hosted plugins
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
@ -157,6 +160,8 @@ SystemInitializerCommon::Terminate()
|
|||||||
PlatformRemoteiOS::Terminate();
|
PlatformRemoteiOS::Terminate();
|
||||||
PlatformiOSSimulator::Terminate();
|
PlatformiOSSimulator::Terminate();
|
||||||
|
|
||||||
|
EmulateInstructionARM::Terminate();
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
DynamicLoaderDarwinKernel::Terminate();
|
DynamicLoaderDarwinKernel::Terminate();
|
||||||
ObjectFileMachO::Terminate();
|
ObjectFileMachO::Terminate();
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
// Other libraries and framework includes
|
// Other libraries and framework includes
|
||||||
#include "lldb/Core/Debugger.h"
|
#include "lldb/Core/Debugger.h"
|
||||||
|
#include "lldb/Core/EmulateInstruction.h"
|
||||||
#include "lldb/Core/Error.h"
|
#include "lldb/Core/Error.h"
|
||||||
#include "lldb/Core/Module.h"
|
#include "lldb/Core/Module.h"
|
||||||
#include "lldb/Core/ModuleSpec.h"
|
#include "lldb/Core/ModuleSpec.h"
|
||||||
@ -2375,6 +2376,19 @@ NativeProcessLinux::MonitorBreakpoint(lldb::pid_t pid, NativeThreadProtocolSP th
|
|||||||
if (log)
|
if (log)
|
||||||
log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s",
|
log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s",
|
||||||
__FUNCTION__, pid, error.AsCString());
|
__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
|
else
|
||||||
if (log)
|
if (log)
|
||||||
@ -3590,6 +3604,151 @@ NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
|
|||||||
return op.GetError();
|
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
|
Error
|
||||||
NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
|
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();
|
return op.GetError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // defined(__arm__)
|
||||||
|
|
||||||
Error
|
Error
|
||||||
NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
|
NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +192,10 @@ namespace process_linux {
|
|||||||
std::unique_ptr<ThreadStateCoordinator> m_coordinator_up;
|
std::unique_ptr<ThreadStateCoordinator> m_coordinator_up;
|
||||||
HostThread m_coordinator_thread;
|
HostThread m_coordinator_thread;
|
||||||
|
|
||||||
|
// List of thread ids stepping with a breakpoint with the address of
|
||||||
|
// the relevan breakpoint
|
||||||
|
std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint;
|
||||||
|
|
||||||
struct OperationArgs
|
struct OperationArgs
|
||||||
{
|
{
|
||||||
OperationArgs(NativeProcessLinux *monitor);
|
OperationArgs(NativeProcessLinux *monitor);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user