diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h @@ -61,6 +61,9 @@ void CalculateTrapHandlerSymbolNames() override {} ConstString GetFullNameForDylib(ConstString basename) override; + + size_t GetSoftwareBreakpointTrapOpcode(Target &target, + BreakpointSite *bp_site) override; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -312,3 +312,38 @@ 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); + } +} diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -108,6 +108,11 @@ protected: NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id); + llvm::Expected> + 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, diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp --- a/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -289,6 +289,30 @@ return llvm::errc::not_supported; } +llvm::Expected> +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 @@ 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); } diff --git a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp --- a/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp @@ -48,12 +48,29 @@ 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); } diff --git a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp --- a/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -436,8 +436,29 @@ 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) { diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -131,12 +131,29 @@ 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); }