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.)
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.
raise(SIGTRAP)
is a relatively portable way to have an "in code" breakpoint.
I've tried all of these solutions and although @RichardGroves answer preserved the stack, the best solution is to:
- create your own assert method, such as
Debug::assert(...)
- set a breakpoint within XCode on that implementation
- 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
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.
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)
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
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.
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
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
精彩评论