xcodeassemblylldb

How to set a breakpoint on an assembly file using Xcode?


I tried "breakpoint [line number]", "breakpoint filename.s:line_number" but they don't work. Currently I have to step through all lines, and it's a hassle


Solution

  • As an alternative you can:

    1. show memory with assembly instructions with

      di with explicit arguments

    if you need reach out further

    di -c 1000 ;
    

    if you need to disassemble a specific address

    di -s <address>
    
    1. set a memory break point with

      br s -a

    Another alternative / (not valid for MacOS Monterey 12.x and newer)
    is slightly more destructive but actually more effortless , which may or may not be useful in your case. You can make an invalid syscall in your assembly code. Your program will happily continue execution but lldb will break on the next instruction after the syscall with SIGSYS/EXC_SYSCALL. You haven't specified if you're targetting x86-64 or arm so the setup will differ slightly.

    For x86-64 you'd have

    syscall
    

    Assuming your rax register does not happen to be a valid syscall i.e in 0x2000xxx range the destructive part will include:

    1. Zeroing upper 32bits of rax register

    2. r11 will become rflags

    3. rcx will become rip (it's used by the XNU kernel for returning to the user space from the syscall), however if you single step rcx will become rsp as mentioned by me here

    For 32 bit and 64bit arm you can make a system call with:

    svc 0x80 
    

    Btw any 1 byte^ number will work, but by convention it's 0x80. 32bit uses r12 for syscall number. 64bit uses x16. More info here & here. So basically valid ranges are 0x0 - 0x0xxx. Even invalid syscalls seem to affect x0 & x1 (for 64bit, as I don't have a 32bit device to test). So as long as you take into account x0 & x1 being affected after the syscall and happen to have x16 that is an invalid syscall you're good to go.

    UPDATE To @PeterCordes excellent remark yet another alternative for x86 is:

    int3
    

    i.e. debugger trap

    32bit arm equivalent is

    trap
    

    64 bit arm equivalent is

    brk    #0xf000
    

    The difference vs syscall approach is the program execution after int3 / trap / brk #0xf000 will continue if and only if debugger is attached and lldb continue command follows, the added value is it won't affect the registers at all. In the syscall approach the program will also continue execution without debugger attached with the aforementioned registers affected.