gpt4 book ai didi

swift - lldb 如何处理特殊用途的 _swift_runtime_on_report 函数?

转载 作者:行者123 更新时间:2023-12-04 08:50:27 25 4
gpt4 key购买 nike

同时分析 Swift assertionFailure()在幕后工作我注意到实际的 fatal error 是通过 _swift_runtime_on_report 报告的功能。它的实现在这里定义:https://github.com/apple/swift/blob/master/stdlib/public/runtime/Errors.cpp作为

SWIFT_NOINLINE SWIFT_RUNTIME_EXPORT void
_swift_runtime_on_report(uintptr_t flags, const char *message,
RuntimeErrorDetails *details) {
// Do nothing. This function is meant to be used by the debugger.

// The following is necessary to avoid calls from being optimized out.
asm volatile("" // Do nothing.
: // Output list, empty.
: "r" (flags), "r" (message), "r" (details) // Input list.
: // Clobber list, empty.
);
}
显然,这只是对一个实际上什么都不做的函数的花哨的写法。它只是坐在那里等待 lldb要特殊对待。我的意思是:
libswiftCore.dylib`_swift_runtime_on_report:
-> 0x7fff64d1cd50 <+0>: push rbp
0x7fff64d1cd51 <+1>: mov rbp, rsp
0x7fff64d1cd54 <+4>: pop rbp
0x7fff64d1cd55 <+5>: ret
0x7fff64d1cd56 <+6>: nop word ptr cs:[rax + rax]
x86-64 在这里并不那么重要。 Xcode 中的第一行(带有箭头->) fatal error (无论它究竟是什么意思)的事实是。有趣的是,甚至在内存地址 0x7fff64d1cd50 处设置断点事先不会触发它,无论如何它都会发生 fatal error 而不会到达断点。
当我修改程序计数器 (rip) 时,我可以跳到 0x7fff64d1cd51并在 0x7fff64d1cd54 处捕获断点不触发 fatal error 。因此,在 0x7fff64d1cd50 处读取程序内存似乎是合理的。被 lldb 捕获最终以优雅的方式出现 fatal error 。
现在是谜语中最令人困惑的部分。在我的简约 XCode 项目中,我有 main.swift包含由...组成
assertionFailure()
但是,如果我故意添加一个像这样定义的 C 函数(这里的主体无关):
#include <stdint.h>
_swift_runtime_on_report(uintptr_t flags, const char *message,
void *details) {
int i = 0;
i++;
return i;
}
它会混淆 lldb足以解除对原版的内存限制 _swift_runtime_on_report函数(此时我可以在 0x7fff64d1cd50 处捕获断点)。最终它省略了“优雅的” fatal error 步骤,它将在 ud2 上失败。 (即 x86 故意的错误指令)
有趣的是,从 Swift 调用我的本地“冒名顶替者”函数也是完全合法的,一切都像一个完全正常的 C 函数一样工作。
所以我的问题是如何 lldb_swift_runtime_on_report 中完全失败/ 0x7fff64d1cd50 ?以及为什么我能够用这个甚至没有被调用的本地 C 函数来打破这种机制。显然是通过符号/定义冲突,但到底发生了什么?

最佳答案

我不确定我明白你在问什么。
_swift_runtime_on_report 是一个存在的函数,因此 lldb 可以在其上设置断点,并检索有关错误的一些信息以显示给用户。您可以通过发出以下命令在调试 swift 程序时看到该断点:

(lldb) break list -i
Current breakpoints:
Kind: shared-library-event
-1: address = dyld[0x00000000000121ad], locations = 1, resolved = 1, hit count = 1

-1.1: where = dyld`_dyld_debugger_notification, address = 0x00000001000221ad, resolved, hit count = 1

Kind: swift-language-runtime-report
-2: address = libswiftCore.dylib[0x00007fff66b14380], locations = 1, resolved = 1, hit count = 1

-2.1: where = libswiftCore.dylib`_swift_runtime_on_report, address = 0x00007fff689d5380, resolved, hit count = 1
Swift promise 在遇到 fatal error 时调用此函数,然后再破坏您的程序。这允许 lldb - 在正常调试中 - 捕获错误并将其报告给您,而不是让程序从您下面退出。它还允许 swift REPL 捕获并清除可能发生在 REPL 顶层的任何抛出,因为否则它们会导致 REPL 退出。
当我使用一行“assertionFailure()”构建和调试 swift 文件时,调试器会停止:
Fatal error: file errors/errors.swift, line 2
2020-09-29 16:52:40.373185-0700 errors[17428:2120547] Fatal error: file errors/errors.swift, line 2
Process 17428 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = Fatal error
frame #0: 0x00007fff689d5380 libswiftCore.dylib`_swift_runtime_on_report
libswiftCore.dylib`_swift_runtime_on_report:
-> 0x7fff689d5380 <+0>: pushq %rbp
0x7fff689d5381 <+1>: movq %rsp, %rbp
0x7fff689d5384 <+4>: popq %rbp
0x7fff689d5385 <+5>: retq
Target 0: (errors) stopped.
这里唯一有点棘手的是,如果你在这个函数上也放了一个断点,lldb 只会在停止原因中报告错误,因为这是一个更高优先级的停止原因。另一件可能让您感到困惑的事情是 lldb 从不显示它插入的断点,它总是显示它覆盖的指令。如果你没有看到你插入的断点,那是设计好的。
无论如何,我不知道这其中的哪一部分不适合你?没有设置断点吗?还是没有被击中?或者你有另一个我只是想念的问题吗?

关于swift - lldb 如何处理特殊用途的 _swift_runtime_on_report 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64126434/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com