16

I'm trying to put the equivalent of asm{int 3} (or similar) into my iPhone program. My goal is to have Xcode stop exactly on the offending line, without having to fiddle with the call stack (so _Debugger doesn't sound like it would do, not that I could find which framework it's in anyway...), and leave me able to resume execution (which is why I'm not happy with assert).

(I'm used to both these behaviours on other systems, and I'd like to reproduce them on iOS.)

My best attempt so far has been this:

asm volatile("bkpt 1");

This stops Xcode on the line in question, but when I try to continue with Cmd+Alt+P, Xcode appears to run the BKPT again. And if I use Shift+Cmd+O, I just get this:

Watchdog has expired.  Remote device was disconnected?  Debugging session terminated.

(Needless to say, the remote device IS still connected.)

I don't have a huge amount of experience with iOS, Mac, ARM, gdb, or gcc's asm stuff. So I'm stumped already. Is there some way of getting iOS and Xcode to do what I want?

(I don't know if it makes a difference but judging by the instruction size my program is ARM code.)

DaveyDaveDave
  • 9,821
  • 11
  • 64
  • 77
  • 1
    Line breakpoints weren't good enough for you? – zneak Sep 05 '10 at 00:01
  • Breakpoints aren't suitable, as the breaking instruction will come as part of a macro expansion. –  Sep 05 '10 at 01:08
  • Not putting this as an answer because I have no way to test it, but have you tried `raise(SIGTRAP)` instead (assuming iOS is still unixy enough to support that)? – Logan Capaldo Sep 05 '10 at 14:20
  • Logan - yes! (Add POSIX to the list of things I'm not too handy with yet.) Xcode will keep going after stopping due to a SIGTRAP, though it stops 3 calls deeper than the raise point. I don't love fiddling with the call stack, but it's easy to do, and compared to a total inability to resume I'm certainly OK with this tradeoff! Please add an answer in your name, and I'll be glad to mark it as the right one. –  Sep 05 '10 at 14:52

9 Answers9

17

Try:

__builtin_trap();

works on Mac as well as iOS, and you can drag the little green cursor to the next line to continue running.

William Denniss
  • 16,089
  • 7
  • 81
  • 124
Richard Groves
  • 3,596
  • 3
  • 21
  • 21
  • Better than the marked answer, because the stack frame is preserved (meaning local variables are also visible). But still gives issues under iOS6 and XCode 4.6. Cannot step, or continue after `__builtin_trap() ` was executed, even after the green position marker is dragged to the next line. – Brent Faust Mar 14 '13 at 02:31
  • Annoying - must have either changed or I was on the simulator where you can continue. 'raise( SIGINT )' as mentioned in http://stackoverflow.com/questions/1149113/breaking-into-the-debugger-on-iphone does allow you to continue, but you are not at the correct stack frame. – Richard Groves Mar 26 '13 at 17:02
  • `int pthread_kill(pthread_t thread, int sig);` allows for continuation, and pauses on the current thread. – pxpgraphics Feb 13 '16 at 16:43
  • Gives me `EXC_BAD_INSTRUCTION`, highlighted in red, non-reusmable (on Simulator at least). – Nicolas Miari Nov 21 '16 at 05:46
6

raise(SIGTRAP) is a relatively portable way to have an "in code" breakpoint.

Logan Capaldo
  • 39,555
  • 5
  • 63
  • 78
  • this is surprisingly inconsistent. i've been using it for a while but i've seen certain machines, builds or otherwise behave strangely... (the same as how asm bkpt is originally described actually) – jheriko Mar 06 '13 at 21:06
  • This wipes out the stack trace on iOS6. – Brent Faust Mar 14 '13 at 02:23
  • SIGTRAP seems to cause the main thread to stop, rather than the one executing the `raise(SIGTRAP)`. Ditto for `raise(SIGINT)`. – Ilya Jun 12 '15 at 08:59
  • No way to continue after that. – Seva Alekseyev Jan 23 '16 at 20:12
  • 1
    `kill(getpid(), SIGSTOP)` allows for continuation – pxpgraphics Feb 01 '16 at 20:51
  • 1
    @pxpgraphics This works as you described (resuming included), however the Xcode editor seems to stop one stack frame further, at some assembly code, not at the source code. You have to go back one level in the call stack. – Nicolas Miari Nov 21 '16 at 05:44
4

I've tried all of these solutions and although @RichardGroves answer preserved the stack, the best solution is to:

  1. create your own assert method, such as Debug::assert(...)
  2. set a breakpoint within XCode on that implementation
  3. use the Step Out command to get back to the caller

This is because it's the only reliable way to both

  • view the stack trace
  • step / continue
Brent Faust
  • 9,103
  • 6
  • 53
  • 57
1
int resume = false;
for (int i = 0; i < 20 && !resume; ++i)
    sleep(1);

Above is a poor man's trap in that you have to manually attach to the program in question. Increase the delay as appropriate. Put the code where you want to break, and insert a breakpoint on the sleep statement, build and run your program, and attach to it from Xcode. Once Xcode breaks, you can right-click on the resume variable and edit it to 1, to resume execution.

Screenshot

Community
  • 1
  • 1
Vivek
  • 564
  • 4
  • 13
1

I tried to find implementation that behaves the same as __debugbreak() that comes with Microsoft compiler and breaks inside my code and not somewhere inside system libraries and allows me to continue execution. This implementation of __debugbreak() works exactly as I wanted:

#if defined(__APPLE__) && defined(__aarch64__)
#define __debugbreak() __asm__ __volatile__(            \
    "   mov    x0, %x0;    \n" /* pid                */ \
    "   mov    x1, #0x11;  \n" /* SIGSTOP            */ \
    "   mov    x16, #0x25; \n" /* syscall 37 = kill  */ \
    "   svc    #0x80       \n" /* software interrupt */ \
    "   mov    x0, x0      \n" /* nop                */ \
    ::  "r"(getpid())                                   \
    :   "x0", "x1", "x16", "memory")
#elif defined(__APPLE__) && defined(__arm__)
#define __debugbreak() __asm__ __volatile__(            \
    "   mov    r0, %0;     \n" /* pid                */ \
    "   mov    r1, #0x11;  \n" /* SIGSTOP            */ \
    "   mov    r12, #0x25; \n" /* syscall 37 = kill  */ \
    "   svc    #0x80       \n" /* software interrupt */ \
    "   mov    r0, r0      \n" /* nop                */ \
    ::  "r"(getpid())                                   \
    :   "r0", "r1", "r12", "memory")
#elif defined(__APPLE__) && defined(__i386__)
#define __debugbreak() __asm__ __volatile__("int $3; mov %eax, %eax")
#endif

#define ASSERT(expr) do { if (!(expr)){ __debugbreak(); } } while(0)
Pavel P
  • 15,789
  • 11
  • 79
  • 128
0

int pthread_kill(pthread_t thread, int sig); allows for continuation, and pauses on the current thread, via pthread_self().

Similar to other signal functions (e.g., kill(), raise(), etc.), however,pthread_kill() is used to request that a signal be delivered to a particular thread.

Pthread_kill Manual

pxpgraphics
  • 1,357
  • 11
  • 21
  • As far as I can tell, this doesn't actually cause the debugger to stop when invoked from a background thread - only from the main thread. – brian sharon Feb 15 '16 at 22:37
  • #include pthread_kill (pthread_self(), SIGINT); Stops in the debugger two levels below your code. – gnasher729 Sep 09 '16 at 14:36
0
std::runtime_error::runtime_error("breakpoint")

together with an XCode exception breakpoint of type

Exception:C++ "named:std::runtime"

worked for me (using XCode 8.0).
It yields the same result as if I had set a breakpoint manually at the line where the

std::runtime_error::runtime_error

function is called, i.e. correct thread, correct call stack, and the possibility to resume.

zx485
  • 28,498
  • 28
  • 50
  • 59
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
0

To force xcode to break, use

kill(getpid(), SIGSTOP)

You can then step out/up and use lldb per usual. When you're done, you can hit continue and it works just like a breakpoint set from the Xcode GUI.

Tested with Swift 5 and Xcode 11.3

spnkr
  • 952
  • 9
  • 18
0

Direct equivalent of x86 int3 / int 3 in arm / arm64 is

#if TARGET_CPU_ARM | TARGET_CPU_ARM64 | TARGET_CPU_ARM64E
asm volatile("trap");
#endif
Kamil.S
  • 5,205
  • 2
  • 22
  • 51