Skip to content

AArch64 debug problems on Windows #51015

@llvmbot

Description

@llvmbot
Bugzilla Link 51673
Resolution FIXED
Resolved on Sep 22, 2021 04:14
Version 10.0
OS Windows NT
Reporter LLVM Bugzilla Contributor
CC @JDevlieghere,@mstorsjo
Fixed by commit(s) 9f34f75

Extended Description

I was using lldb on Windows (Raspberry Pi 4 - ARM Cortex-A72 processor), and there were a couple of x86-isms that persist that make it impossible to set and use breakpoints.

Platform::GetSoftwareBreakpointTrapOpcode()
NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode()
Uses "0xd4 0x20 0x00 0x00" for breakpoint on aarch64, but this does not work on Windows as it fails with a STATUS_ILLEGAL_INSTRUCTION exception being thrown.

case llvm::Triple::aarch64: {
static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4};

The compiler intrinsic __debug_break() generates "{0x00, 0x00, 0x3e, 0xd4}". If I instead use this, then the program stops at the requested breakpoint, as expected.


TargetThreadWindows::DoResume()
NativeThreadWindows::DoResume()
Sets flag 0x100 for single step, but that's only valid for x86/x64.

if (resume_state == eStateStepping) {
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 /* only correct for x86/x64 */
GetRegisterContext()->WriteRegisterFromUnsigned(flags_index, flags_value);
}

For AArch64, it should instead be 0x200000, as this is the location of the 'SS' bit of the PState register. Using this value, then single stepping works as expected.

Without a fix in this area, single stepping simply doesn't work.


ProcessWindows::RefreshStateAfterStop()
When handling EXCEPTION_BREAKPOINT, it assumes that the breakpoint instruction is 1 byte, which is only correct for x86/x64.

// The current EIP is AFTER the BP opcode, which is one byte.
uint64_t pc = register_context->GetPC() - 1;

The basic theory here is that after a breakpoint exception, that the program counter points to the instruction after the breakpoint, so we need to back up one instruction to get to the real breakpoint. On x86, a breakpoint is a single byte 0xCC. For AArch64 it needs to be 4 bytes (as noted above). Other architectures are going to be different of course. One can temporarily tweak this so that it works, of course, but on the surface it seems like the breakpoint information is already encapsulated in Platform.cpp, I suppose it would be best to simply leverage that.

Note that I am currently working in a LLVM 10.0 source tree, but I looked ahead to version 12 and I see no changes in this area.

I should add that with fixes/tweaks in all 3 of these places, the AArch64 lldb actually behaves pretty normally. I am still having a little trouble with PDB files, but I can address that separately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugzillaIssues migrated from bugzillalldb

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions