iOS 上的可恢复断言/断点,例如带有 MS 编译器的 __debugbreak()

Resumable assert/breakpoint on iOS like __debugbreak() with MS compiler

本文关键字:编译器 MS debugbreak 断言 可恢复 断点 iOS      更新时间:2023-10-16

我正在尝试实现自定义资产宏(类似于assert.h具有的宏),但我希望能够在我得到并断言后继续执行。

例如,一个这样的ASSERT实现可以是:

#define ASSERT(expr) ((void)( (!!(expr)) || (__debugbreak(), 0)))

__debugbreak 是Microsoft编译器中的固有函数,用于插入软件断点,相当于 x86 中的_asm int 3。 对于 iOS,有不同的方法可以实现该__debugbreak:

  • __asm__("int $3");适用于 x86。
  • __asm__("bkpt #0");用于常规手臂。
  • 用于 arm64 的__asm__("brk #0");
  • __builtin_trap()
  • raise(SIGTRAP)

但是当我的断言命中时,我不能简单地跨过并继续我在使用 Visual Studio 时可以做的方式; 当我的 iOS 构建中的某些断言时,它会卡在断言上,我别无选择,只能终止,我什至无法手动移动指令指针并跳过断言。

是否可以在 iOS 上实现会中断调试器但仍允许我继续执行的断言?

事实证明,我可以通过进行系统调用来实现我想要的:

#include <unistd.h>
#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__) || defined(__x86_64__))
#define __debugbreak() __asm__ __volatile__("int $3; mov %eax, %eax")
#endif
#define MYASSERT(expr) do { if (!(expr)){ __debugbreak(); } } while(0)

有一个尾随的NOPmov x0, x0是有原因的:当断言中断时,调试器将正好在断言行停止,而不是以下指令恰好所在的某个随机行。

如果有人在iOS上寻找IsDebuggerPresent的等效物,您可以使用AmIBeingDebugged。