forked from OSchip/llvm-project
[lldb] [Windows] Fix continuing from breakpoints and singlestepping on ARM/AArch64
Based on suggestions by Eric Youngdale. This fixes https://llvm.org/PR51673. Differential Revision: https://reviews.llvm.org/D109777
This commit is contained in:
parent
02cd8a6b91
commit
9f34f75ff8
|
@ -312,3 +312,38 @@ ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
|
|||
stream.Printf("%s.dll", basename.GetCString());
|
||||
return ConstString(stream.GetString());
|
||||
}
|
||||
|
||||
size_t
|
||||
PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
|
||||
BreakpointSite *bp_site) {
|
||||
ArchSpec arch = target.GetArchitecture();
|
||||
assert(arch.IsValid());
|
||||
const uint8_t *trap_opcode = nullptr;
|
||||
size_t trap_opcode_size = 0;
|
||||
|
||||
switch (arch.GetMachine()) {
|
||||
case llvm::Triple::aarch64: {
|
||||
static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
|
||||
trap_opcode = g_aarch64_opcode;
|
||||
trap_opcode_size = sizeof(g_aarch64_opcode);
|
||||
|
||||
if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
|
||||
return trap_opcode_size;
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb: {
|
||||
static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
|
||||
trap_opcode = g_thumb_opcode;
|
||||
trap_opcode_size = sizeof(g_thumb_opcode);
|
||||
|
||||
if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
|
||||
return trap_opcode_size;
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
default:
|
||||
return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,9 @@ public:
|
|||
void CalculateTrapHandlerSymbolNames() override {}
|
||||
|
||||
ConstString GetFullNameForDylib(ConstString basename) override;
|
||||
|
||||
size_t GetSoftwareBreakpointTrapOpcode(Target &target,
|
||||
BreakpointSite *bp_site) override;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -289,6 +289,30 @@ NativeProcessWindows::GetAuxvData() const {
|
|||
return llvm::errc::not_supported;
|
||||
}
|
||||
|
||||
llvm::Expected<llvm::ArrayRef<uint8_t>>
|
||||
NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
|
||||
static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
|
||||
static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
|
||||
|
||||
switch (GetArchitecture().GetMachine()) {
|
||||
case llvm::Triple::aarch64:
|
||||
return llvm::makeArrayRef(g_aarch64_opcode);
|
||||
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
return llvm::makeArrayRef(g_thumb_opcode);
|
||||
|
||||
default:
|
||||
return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
|
||||
}
|
||||
}
|
||||
|
||||
size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {
|
||||
// Windows always reports an incremented PC after a breakpoint is hit,
|
||||
// even on ARM.
|
||||
return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size();
|
||||
}
|
||||
|
||||
bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
|
||||
auto it = m_software_breakpoints.find(addr);
|
||||
if (it == m_software_breakpoints.end())
|
||||
|
@ -474,8 +498,9 @@ NativeProcessWindows::OnDebugException(bool first_chance,
|
|||
if (NativeThreadWindows *stop_thread =
|
||||
GetThreadByID(record.GetThreadID())) {
|
||||
auto ®ister_context = stop_thread->GetRegisterContext();
|
||||
// The current EIP is AFTER the BP opcode, which is one byte '0xCC'
|
||||
uint64_t pc = register_context.GetPC() - 1;
|
||||
uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset();
|
||||
// The current PC is AFTER the BP opcode, on all architectures.
|
||||
uint64_t pc = register_context.GetPC() - breakpoint_size;
|
||||
register_context.SetPC(pc);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,11 @@ public:
|
|||
protected:
|
||||
NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id);
|
||||
|
||||
llvm::Expected<llvm::ArrayRef<uint8_t>>
|
||||
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
|
||||
|
||||
size_t GetSoftwareBreakpointPCOffset() override;
|
||||
|
||||
bool FindSoftwareBreakpoint(lldb::addr_t addr);
|
||||
|
||||
void StopThread(lldb::tid_t thread_id, lldb::StopReason reason,
|
||||
|
|
|
@ -48,12 +48,29 @@ Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
|
|||
return Status();
|
||||
|
||||
if (resume_state == eStateStepping) {
|
||||
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
|
||||
|
||||
uint32_t flags_index =
|
||||
GetRegisterContext().ConvertRegisterKindToRegisterNumber(
|
||||
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
|
||||
uint64_t flags_value =
|
||||
GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
|
||||
flags_value |= 0x100; // Set the trap flag on the CPU
|
||||
NativeProcessProtocol &process = GetProcess();
|
||||
const ArchSpec &arch = process.GetArchitecture();
|
||||
switch (arch.GetMachine()) {
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
flags_value |= 0x100; // Set the trap flag on the CPU
|
||||
break;
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
flags_value |= 0x200000; // The SS bit in PState
|
||||
break;
|
||||
default:
|
||||
LLDB_LOG(log, "single stepping unsupported on this architecture");
|
||||
break;
|
||||
}
|
||||
GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
|
||||
}
|
||||
|
||||
|
|
|
@ -436,8 +436,29 @@ void ProcessWindows::RefreshStateAfterStop() {
|
|||
case EXCEPTION_BREAKPOINT: {
|
||||
RegisterContextSP register_context = stop_thread->GetRegisterContext();
|
||||
|
||||
// The current EIP is AFTER the BP opcode, which is one byte.
|
||||
uint64_t pc = register_context->GetPC() - 1;
|
||||
int breakpoint_size = 1;
|
||||
switch (GetTarget().GetArchitecture().GetMachine()) {
|
||||
case llvm::Triple::aarch64:
|
||||
breakpoint_size = 4;
|
||||
break;
|
||||
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
breakpoint_size = 2;
|
||||
break;
|
||||
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
breakpoint_size = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
LLDB_LOG(log, "Unknown breakpoint size for architecture");
|
||||
break;
|
||||
}
|
||||
|
||||
// The current PC is AFTER the BP opcode, on all architectures.
|
||||
uint64_t pc = register_context->GetPC() - breakpoint_size;
|
||||
|
||||
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
|
||||
if (site) {
|
||||
|
|
|
@ -131,12 +131,29 @@ Status TargetThreadWindows::DoResume() {
|
|||
return Status();
|
||||
|
||||
if (resume_state == eStateStepping) {
|
||||
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
|
||||
|
||||
uint32_t flags_index =
|
||||
GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
|
||||
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
|
||||
uint64_t flags_value =
|
||||
GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
|
||||
flags_value |= 0x100; // Set the trap flag on the CPU
|
||||
ProcessSP process = GetProcess();
|
||||
const ArchSpec &arch = process->GetTarget().GetArchitecture();
|
||||
switch (arch.GetMachine()) {
|
||||
case llvm::Triple::x86:
|
||||
case llvm::Triple::x86_64:
|
||||
flags_value |= 0x100; // Set the trap flag on the CPU
|
||||
break;
|
||||
case llvm::Triple::aarch64:
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
flags_value |= 0x200000; // The SS bit in PState
|
||||
break;
|
||||
default:
|
||||
LLDB_LOG(log, "single stepping unsupported on this architecture");
|
||||
break;
|
||||
}
|
||||
GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue