Xcode 4.2 调试不象征堆栈调用

Posted

技术标签:

【中文标题】Xcode 4.2 调试不象征堆栈调用【英文标题】:Xcode 4.2 debug doesn't symbolicate stack call 【发布时间】:2011-12-12 02:23:39 【问题描述】:

我在 ios 5 模拟器/设备中调试 Xcode 4.2 时遇到问题。以下代码按预期崩溃:

NSArray *arr=[NSArray array];
[arr objectAtIndex:100];

在 iOS 4 中,我得到了一个有用的十六进制数字堆栈跟踪。但在 iOS 5 中,它只是给了我:

*** First throw call stack:
(0x16b4052 0x1845d0a 0x16a0674 0x294c 0x6f89d6 0x6f98a6 0x708743 0x7091f8 0x7fcaa9 0x2257fa9 0x16881c5 0x15ed022 0x15eb90a 0x15eadb4 0x15eaccb 0x6f02a7 0x6faa93 0x2889 0x2805)

谢谢。

【问题讨论】:

【参考方案1】:

我尝试过的任何方法都无法解决此问题(尝试了两个编译器、两个调试器等) 为 iOS 5 更新升级 XCode 后,似乎没有堆栈跟踪工作。

但是,我找到了一种有效的解决方法——创建自己的异常处理程序(出于其他原因,这也很有用)。首先,创建一个函数来处理错误并将其输出到控制台(以及您想要对其执行的任何其他操作):

void uncaughtExceptionHandler(NSException *exception) 
    NSLog(@"CRASH: %@", exception);
    NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    // Internal error reporting

接下来,将异常处理程序添加到您的应用委托:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
   
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    // Normal launch stuff

就是这样!

如果这不起作用,那么只有两个可能的原因

    有些东西正在覆盖您的NSSetUncaughtExceptionHandler 调用(整个应用程序只能有一个处理程序)。例如,一些 3rd 方库设置了自己的 uncaughtExceptionHandler。因此,请尝试将其设置在您的 didFinishLaunchingWithOptions 函数的末尾(或有选择地禁用第 3 方库)。或者更好的是,在NSSetUncaughtExceptionHandler 上设置一个符号断点以快速查看是谁在调用它。您可能想要做的是修改当前的而不是添加另一个。 您实际上并没有遇到异常(例如,EXC_BAD_ACCESS 不是异常;感谢@Erik B 的 cmets,见下文)

【讨论】:

很高兴听到它 :) 我发现将崩溃日志写入文件并提示用户在下次启动时提交它很有用(仅在发布模式下,不要进入调试方式)。这让我得到了很好的错误报告......并且用户知道他们的问题正在得到解决:) 这似乎不起作用 -- uncaughtExceptionHandler 例程永远不会被调用。 您能否更具体地说明如何使用它?它似乎对我不起作用。 很遗憾 xCode 没有为我们显示这个。 非常感谢!令人费解的是,Apple 没有在 IDE 中实现这种基本功能。【参考方案2】:

有一个添加异常断点的有用选项(使用断点导航器底部的 +)。这将在任何异常上中断(或者您可以设置条件)。我不知道这个选择是 4.2 中的新选项,还是我终于注意到它试图解决缺少符号的问题。

点击此断点后,您可以像往常一样使用 Debug Navigator 导航调用堆栈、检查变量等。

如果您确实想要一个适合复制/粘贴等的符号化调用堆栈,gdb 回溯将从那里正常工作:

(gdb) bt
#0  0x01f84cf0 in objc_exception_throw ()
#1  0x019efced in -[NSObject doesNotRecognizeSelector:] ()

(等)

【讨论】:

到目前为止,这对我来说非常有效。调试器现在停止在崩溃线上,不需要回溯。 这对我也很有效。非常感谢,没有这个断点我快疯了...... +1 因为它有效。它不会给你一个很好的错误信息来解释异常的原因,但它是一个开始...... 你是我的 HotD @WiseOldDuck。 这恢复了我的预期行为。 注意:还记得在新项目中重新添加此断点!【参考方案3】:

调试器上有一个新功能。您可以在抛出异常时设置断点并在此处停止执行,就像它过去在 4.0 上发生的那样。

在“断点导航器”上,添加一个“异常断点”,然后在选项弹出窗口中按“完成”。

就是这样!

PS:在某些情况下,最好只针对 Objective-C 异常进行中断。

【讨论】:

这绝对是我的解决方案。 这对我来说是个问题。我和一位同事共享同一个 Xcode 项目,我问他是否有问题,他没有。不同之处在于他的项目打破了 Objective-c 异常 (objc_exception_throw) 你刚刚帮助找到了一个无法追踪的错误。太感谢了。我一直在到处寻找这样的东西。 这就像一个魅力!这正是我正在寻找的,这比添加异常处理程序要好,因为添加断点可以将您带到引发异常的正确位置,异常处理程序可以工作,但只是给您一个想法。【参考方案4】:

这里还有一个解决方案,不像以前那么优雅,但是如果你没有添加异常断点或处理程序,它可能只是一种方法。 当应用程序崩溃时,您得到原始 first throw 调用堆栈(十六进制数字),在 Xcode 控制台中输入 info line *hex(不要忘记星号和 0x 十六进制说明符),例如:

(gdb) info line *0x2658
Line 15 of "path/to/file/main.m" starts at address 0x25f2 <main+50>
and ends at 0x267e <main+190>.

如果你使用 lldb,你可以输入image lookup -a hex(在这种情况下不带星号),你会得到类似的输出。

使用此方法,您可以从抛出堆栈顶部(大约有 5-7 个系统异常传播器)遍历导致崩溃的函数,并确定确切的文件和代码行。

另外,为了达到类似的效果,您可以在终端中使用 atos 实用程序,只需键入:

atos -o path/to/AplicationBundle.app/Executable 0xAdress1 0xAdress2 0xAdress3 ...

你会得到符号化的堆栈跟踪(至少对于你有调试符号的函数)。 这种方法更可取,因为您不需要为每个地址调用info line,只需从控制台输出复制地址并将它们粘贴到终端。

【讨论】:

【参考方案5】:

您可以添加一个异常断点(使用断点导航器底部的+)并添加操作 bt 到它(单击添加操作按钮,选择调试器命令,在文本字段中输入“bt”)。这将在抛出异常后立即显示堆栈跟踪。

【讨论】:

【参考方案6】:

这是一个常见问题,在 4.2 中没有获取堆栈跟踪。您可以尝试在 LLDB 和 GDB 之间进行交换,看看是否可以获得更好的结果。

在此处提交错误报告。

http://developer.apple.com/bugreporter/

编辑:

我相信,如果您换回 LLVM GCC 4.2,您将不会看到这种情况发生。不过,您可能会失去所需的功能。

【讨论】:

是的,我尝试切换编译器,但问题仍然存在。但无论如何谢谢:) 他建议切换调试器,而不是编译器。 仅供参考:在这种情况下,它与您使用的编译器或调试器的版本无关。这是 iOS 控制台输出的变化。 有趣的是,这方面的经验有多少不同 - 我认为存在一些问题。我无法让调试器在异常断点处停止。从 GDB 切换到 LLDB 解决了这个问题。【参考方案7】:

在你的主函数中使用这段代码:

int main(int argc, char *argv[])

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int retVal;
    @try 
        retVal = UIApplicationMain(argc, argv, nil, nil);
    
    @catch (NSException *exception) 
        NSLog(@"CRASH: %@", exception);
        NSLog(@"Stack Trace: %@", [exception callStackSymbols]);
    
    @finally 
        [pool release];
    
    return retVal;

【讨论】:

这似乎不适用于情节提要。 2012-06-04 20:34:52.211 问题[1944:207] 如果要使用主情节提要文件,应用程序委托必须实现窗口属性。 2012-06-04 20:34:52.213 问题[1944:207] 应用程序在应用程序启动结束时应该有一个根视图控制器【参考方案8】:

在 Xcode 的调试控制台提示符下输入:

image lookup -a 0x1234

它会告诉你类似的东西:

  Address: MyApp[0x00018eb0] (MyApp.__TEXT.__text + 91088)
  Summary: MyApp`-[MyViewController viewDidAppear:] + 192 at MyViewController.m:202

【讨论】:

谢谢,我真的在找这个。令人惊讶的是,没有将整个“第一次抛出调用堆栈”显示为调用堆栈的快捷方式,因为我想可以轻松编写 Python lldb 脚本。【参考方案9】:

重新打开“Compile for Thumb”(调试配置)对我有用。

【讨论】:

以上是关于Xcode 4.2 调试不象征堆栈调用的主要内容,如果未能解决你的问题,请参考以下文章

如何查看xcode调用堆栈

从 Xcode 视图调试中找出视图代码的位置

如何在 Java 的 Eclipse 调试视图中过滤调用堆栈

在运行时打印调用堆栈(XCode)

Jetbrains Rider:在调试器调用堆栈中显示“外部代码”

Clang:错误:链接器命令失败,退出代码 1(使用 -v 查看调用)Xcode 10、Xcode 10.1 Beta、Swift 4.2