我可以在 iOS 中的代码中创建一个断点,比如 VC++ 上的 `__asmint 3`,然后在它被命中后继续执行吗?

Posted

技术标签:

【中文标题】我可以在 iOS 中的代码中创建一个断点,比如 VC++ 上的 `__asmint 3`,然后在它被命中后继续执行吗?【英文标题】:Can I create a breakpoint in code in iOS, like `__asmint 3` on VC++, and continue execution after it's been hit?我可以在 iOS 中的代码中创建一个断点,比如 VC++ 上的 `__asmint 3`,然后在它被命中后继续执行吗? 【发布时间】:2010-09-04 23:57:57 【问题描述】:

我正在尝试将 asmint 3(或类似)的等效项放入我的 iPhone 程序中。我的目标是让 Xcode 准确地停在有问题的行上,而不必摆弄调用堆栈(所以_Debugger 听起来不像它会做的那样,并不是说我无论如何都能找到它所在的框架......),让我能够继续执行(这就是我对assert 不满意的原因)。

(我在其他系统上已经习惯了这两种行为,我想在 ios 上重现它们。)

到目前为止我最好的尝试是这样的:

asm volatile("bkpt 1");

这会在有问题的行上停止 Xcode,但是当我尝试继续使用 Cmd+Alt+P 时,Xcode 似乎再次运行BKPT。如果我使用 Shift+Cmd+O,我会得到这个:

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

(不用说,远程设备仍然连接。)

我在 iOS、Mac、ARM、gdb 或 gcc 的 asm 方面没有大量经验。所以我已经难住了。有什么方法可以让 iOS 和 Xcode 做我想做的事吗?

(我不知道这是否有区别,但从指令大小来看,我的程序是 ARM 代码。)

【问题讨论】:

行断点对你来说不够好? 断点不合适,因为中断指令将作为宏扩展的一部分出现。 不把它作为答案,因为我没有办法测试它,但你试过raise(SIGTRAP) 代替(假设iOS仍然足够unixy来支持它)? 洛根 - 是的! (将 POSIX 添加到我还不太方便的事情列表中。)由于 SIGTRAP,Xcode 将在停止后继续运行,尽管它停止了比引发点更深的 3 个调用。我不喜欢摆弄调用堆栈,但这很容易做到,而且与完全无法恢复相比,我当然可以接受这种权衡!请以您的名义添加答案,我很乐意将其标记为正确的答案。 【参考方案1】:

试试:

__builtin_trap();

适用于 Mac 和 iOS,您可以将绿色小光标拖到下一行继续运行。

【讨论】:

比标记的答案更好,因为堆栈帧被保留(意味着局部变量也是可见的)。但在 iOS6 和 XCode 4.6 下仍然存在问题。执行__builtin_trap() 后,即使将绿色位置标记拖到下一行,也无法步进或继续。 烦人 - 要么已经改变,要么我在模拟器上,你可以继续。 ***.com/questions/1149113/… 中提到的“raise(SIGINT)”确实允许您继续,但您不在正确的堆栈帧中。 int pthread_kill(pthread_t thread, int sig); 允许继续,并在当前线程上暂停。 给我EXC_BAD_INSTRUCTION,以红色突出显示,不可重复使用(至少在模拟器上)。【参考方案2】:

raise(SIGTRAP) 是一种相对可移植的方式来设置“代码中”断点。

【讨论】:

这出人意料地不一致。我已经使用了一段时间,但我看到某些机器、构建或其他行为异常......(与 asm bkpt 最初描述的实际相同) 这会清除 iOS6 上的堆栈跟踪。 SIGTRAP 似乎导致主线程停止,而不是执行raise(SIGTRAP) 的线程。 raise(SIGINT) 同上。 kill(getpid(), SIGSTOP) 允许继续 @pxpgraphics 这如您所描述的那样工作(恢复包括在内),但是 Xcode 编辑器似乎在某些汇编代码处停止了一个堆栈帧,而不是在源代码处。您必须在调用堆栈中返回上一级。【参考方案3】:

我已经尝试了所有这些解决方案,虽然@RichardGroves 的回答保留了堆栈,但最好的解决方案是:

    创建自己的断言方法,例如Debug::assert(...) 在该实现的 XCode 中设置断点 使用 Step Out 命令返回呼叫者

这是因为这是唯一可靠的方法

查看堆栈跟踪 步骤/继续

【讨论】:

【参考方案4】:
int resume = false;
for (int i = 0; i < 20 && !resume; ++i)
    sleep(1);

以上是一个穷人的陷阱,您必须手动附加到相关程序。适当增加延迟。将代码放在要中断的位置,并在 sleep 语句上插入断点,构建并运行程序,然后从 Xcode 附加到它。一旦 Xcode 中断,您可以右键单击 resume 变量并将其编辑为 1,以恢复执行。

【讨论】:

【参考方案5】:

我试图找到与 Microsoft 编译器附带的 __debugbreak() 行为相同的实现,它在我的代码内部而不是在系统库中的某个地方中断,并允许我继续执行。这个implementation of __debugbreak() 完全符合我的要求:

#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)

【讨论】:

【参考方案6】:

int pthread_kill(pthread_t thread, int sig); 允许通过pthread_self() 在当前线程上继续和暂停。

类似于其他信号函数(例如,kill()raise() 等),但是,pthread_kill() 用于请求将信号传递给特定线程。

Pthread_kill Manual

【讨论】:

据我所知,这实际上不会导致调试器在从后台线程调用时停止 - 仅从主线程调用。 #include pthread_kill (pthread_self(), SIGINT);在代码下方两个级别的调试器中停止。【参考方案7】:
std::runtime_error::runtime_error("breakpoint")

连同类型为

的 XCode 异常断点

异常:C++“命名:std::runtime”

为我工作(使用 XCode 8.0)。 它产生的结果与我在

所在的行手动设置断点相同
std::runtime_error::runtime_error

函数被调用,即正确的线程、正确的调用堆栈以及恢复的可能性。

【讨论】:

【参考方案8】:

要强制 xcode 中断,请使用

kill(getpid(), SIGSTOP)

然后,您可以像往常一样跳出/向上并使用 lldb。完成后,您可以点击继续,它就像在 Xcode GUI 中设置断点一样工作。

使用 Swift 5 和 Xcode 11.3 测试

【讨论】:

【参考方案9】:

在 arm / arm64 中直接相当于 x86 int3 / int 3

#if TARGET_CPU_ARM | TARGET_CPU_ARM64 | TARGET_CPU_ARM64E
asm volatile("trap");
#endif

【讨论】:

以上是关于我可以在 iOS 中的代码中创建一个断点,比如 VC++ 上的 `__asmint 3`,然后在它被命中后继续执行吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 v-for vue js 中创建增量变量

我可以通过 IOS 中的 phonegap/cordova 在 www 目录中创建一个文件夹吗?

如何以最简单的方式在 V 2010Express C# 中创建 MRU?

如何调试在 ASP 页中创建的 Visual Studio 6.0 中的 COM 对象?

iOS开发网络篇—多线程断点下载

可以使用 OLEDB 在 C# 中创建数据库吗?