我可以在 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
【讨论】:
据我所知,这实际上不会导致调试器在从后台线程调用时停止 - 仅从主线程调用。 #includestd::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`,然后在它被命中后继续执行吗?的主要内容,如果未能解决你的问题,请参考以下文章
我可以通过 IOS 中的 phonegap/cordova 在 www 目录中创建一个文件夹吗?
如何以最简单的方式在 V 2010Express C# 中创建 MRU?