Skip to content

Commit 9f34f75

Browse files
committed
[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
1 parent 02cd8a6 commit 9f34f75

File tree

7 files changed

+129
-6
lines changed

7 files changed

+129
-6
lines changed

lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,38 @@ ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
312312
stream.Printf("%s.dll", basename.GetCString());
313313
return ConstString(stream.GetString());
314314
}
315+
316+
size_t
317+
PlatformWindows::GetSoftwareBreakpointTrapOpcode(Target &target,
318+
BreakpointSite *bp_site) {
319+
ArchSpec arch = target.GetArchitecture();
320+
assert(arch.IsValid());
321+
const uint8_t *trap_opcode = nullptr;
322+
size_t trap_opcode_size = 0;
323+
324+
switch (arch.GetMachine()) {
325+
case llvm::Triple::aarch64: {
326+
static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
327+
trap_opcode = g_aarch64_opcode;
328+
trap_opcode_size = sizeof(g_aarch64_opcode);
329+
330+
if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
331+
return trap_opcode_size;
332+
return 0;
333+
} break;
334+
335+
case llvm::Triple::arm:
336+
case llvm::Triple::thumb: {
337+
static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
338+
trap_opcode = g_thumb_opcode;
339+
trap_opcode_size = sizeof(g_thumb_opcode);
340+
341+
if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
342+
return trap_opcode_size;
343+
return 0;
344+
} break;
345+
346+
default:
347+
return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site);
348+
}
349+
}

lldb/source/Plugins/Platform/Windows/PlatformWindows.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ class PlatformWindows : public RemoteAwarePlatform {
6161
void CalculateTrapHandlerSymbolNames() override {}
6262

6363
ConstString GetFullNameForDylib(ConstString basename) override;
64+
65+
size_t GetSoftwareBreakpointTrapOpcode(Target &target,
66+
BreakpointSite *bp_site) override;
6467
};
6568

6669
} // namespace lldb_private

lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,30 @@ NativeProcessWindows::GetAuxvData() const {
289289
return llvm::errc::not_supported;
290290
}
291291

292+
llvm::Expected<llvm::ArrayRef<uint8_t>>
293+
NativeProcessWindows::GetSoftwareBreakpointTrapOpcode(size_t size_hint) {
294+
static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x3e, 0xd4}; // brk #0xf000
295+
static const uint8_t g_thumb_opcode[] = {0xfe, 0xde}; // udf #0xfe
296+
297+
switch (GetArchitecture().GetMachine()) {
298+
case llvm::Triple::aarch64:
299+
return llvm::makeArrayRef(g_aarch64_opcode);
300+
301+
case llvm::Triple::arm:
302+
case llvm::Triple::thumb:
303+
return llvm::makeArrayRef(g_thumb_opcode);
304+
305+
default:
306+
return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint);
307+
}
308+
}
309+
310+
size_t NativeProcessWindows::GetSoftwareBreakpointPCOffset() {
311+
// Windows always reports an incremented PC after a breakpoint is hit,
312+
// even on ARM.
313+
return cantFail(GetSoftwareBreakpointTrapOpcode(0)).size();
314+
}
315+
292316
bool NativeProcessWindows::FindSoftwareBreakpoint(lldb::addr_t addr) {
293317
auto it = m_software_breakpoints.find(addr);
294318
if (it == m_software_breakpoints.end())
@@ -474,8 +498,9 @@ NativeProcessWindows::OnDebugException(bool first_chance,
474498
if (NativeThreadWindows *stop_thread =
475499
GetThreadByID(record.GetThreadID())) {
476500
auto &register_context = stop_thread->GetRegisterContext();
477-
// The current EIP is AFTER the BP opcode, which is one byte '0xCC'
478-
uint64_t pc = register_context.GetPC() - 1;
501+
uint32_t breakpoint_size = GetSoftwareBreakpointPCOffset();
502+
// The current PC is AFTER the BP opcode, on all architectures.
503+
uint64_t pc = register_context.GetPC() - breakpoint_size;
479504
register_context.SetPC(pc);
480505
}
481506

lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ class NativeProcessWindows : public NativeProcessProtocol,
108108
protected:
109109
NativeThreadWindows *GetThreadByID(lldb::tid_t thread_id);
110110

111+
llvm::Expected<llvm::ArrayRef<uint8_t>>
112+
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
113+
114+
size_t GetSoftwareBreakpointPCOffset() override;
115+
111116
bool FindSoftwareBreakpoint(lldb::addr_t addr);
112117

113118
void StopThread(lldb::tid_t thread_id, lldb::StopReason reason,

lldb/source/Plugins/Process/Windows/Common/NativeThreadWindows.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,29 @@ Status NativeThreadWindows::DoResume(lldb::StateType resume_state) {
4848
return Status();
4949

5050
if (resume_state == eStateStepping) {
51+
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
52+
5153
uint32_t flags_index =
5254
GetRegisterContext().ConvertRegisterKindToRegisterNumber(
5355
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
5456
uint64_t flags_value =
5557
GetRegisterContext().ReadRegisterAsUnsigned(flags_index, 0);
56-
flags_value |= 0x100; // Set the trap flag on the CPU
58+
NativeProcessProtocol &process = GetProcess();
59+
const ArchSpec &arch = process.GetArchitecture();
60+
switch (arch.GetMachine()) {
61+
case llvm::Triple::x86:
62+
case llvm::Triple::x86_64:
63+
flags_value |= 0x100; // Set the trap flag on the CPU
64+
break;
65+
case llvm::Triple::aarch64:
66+
case llvm::Triple::arm:
67+
case llvm::Triple::thumb:
68+
flags_value |= 0x200000; // The SS bit in PState
69+
break;
70+
default:
71+
LLDB_LOG(log, "single stepping unsupported on this architecture");
72+
break;
73+
}
5774
GetRegisterContext().WriteRegisterFromUnsigned(flags_index, flags_value);
5875
}
5976

lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,29 @@ void ProcessWindows::RefreshStateAfterStop() {
436436
case EXCEPTION_BREAKPOINT: {
437437
RegisterContextSP register_context = stop_thread->GetRegisterContext();
438438

439-
// The current EIP is AFTER the BP opcode, which is one byte.
440-
uint64_t pc = register_context->GetPC() - 1;
439+
int breakpoint_size = 1;
440+
switch (GetTarget().GetArchitecture().GetMachine()) {
441+
case llvm::Triple::aarch64:
442+
breakpoint_size = 4;
443+
break;
444+
445+
case llvm::Triple::arm:
446+
case llvm::Triple::thumb:
447+
breakpoint_size = 2;
448+
break;
449+
450+
case llvm::Triple::x86:
451+
case llvm::Triple::x86_64:
452+
breakpoint_size = 1;
453+
break;
454+
455+
default:
456+
LLDB_LOG(log, "Unknown breakpoint size for architecture");
457+
break;
458+
}
459+
460+
// The current PC is AFTER the BP opcode, on all architectures.
461+
uint64_t pc = register_context->GetPC() - breakpoint_size;
441462

442463
BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc));
443464
if (site) {

lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,29 @@ Status TargetThreadWindows::DoResume() {
131131
return Status();
132132

133133
if (resume_state == eStateStepping) {
134+
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
135+
134136
uint32_t flags_index =
135137
GetRegisterContext()->ConvertRegisterKindToRegisterNumber(
136138
eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
137139
uint64_t flags_value =
138140
GetRegisterContext()->ReadRegisterAsUnsigned(flags_index, 0);
139-
flags_value |= 0x100; // Set the trap flag on the CPU
141+
ProcessSP process = GetProcess();
142+
const ArchSpec &arch = process->GetTarget().GetArchitecture();
143+
switch (arch.GetMachine()) {
144+
case llvm::Triple::x86:
145+
case llvm::Triple::x86_64:
146+
flags_value |= 0x100; // Set the trap flag on the CPU
147+
break;
148+
case llvm::Triple::aarch64:
149+
case llvm::Triple::arm:
150+
case llvm::Triple::thumb:
151+
flags_value |= 0x200000; // The SS bit in PState
152+
break;
153+
default:
154+
LLDB_LOG(log, "single stepping unsupported on this architecture");
155+
break;
156+
}
140157
GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
141158
}
142159

0 commit comments

Comments
 (0)