【问题标题】:Xcode 4.2 debug doesn't symbolicate stack callXcode 4.2 调试不象征堆栈调用
【发布时间】: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)

谢谢。

【问题讨论】:

    标签: ios xcode debug-symbols


    【解决方案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
    }
    

    就是这样!

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

    1. 有些东西正在覆盖您的NSSetUncaughtExceptionHandler 调用(整个应用程序只能有一个处理程序)。例如,一些 3rd 方库设置了自己的 uncaughtExceptionHandler。因此,请尝试将其设置在您的 didFinishLaunchingWithOptions 函数的末尾(或有选择地禁用第 3 方库)。或者更好的是,在NSSetUncaughtExceptionHandler 上设置一个符号断点以快速查看是谁在调用它。您可能想要做的是修改当前的而不是添加另一个。
    2. 您实际上并没有遇到异常(例如,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”(调试配置)对我有用。

        【讨论】:

          猜你喜欢
          • 2016-12-13
          • 2017-11-04
          • 1970-01-01
          • 1970-01-01
          • 2012-03-05
          • 2022-01-18
          • 1970-01-01
          • 2011-12-11
          • 2011-01-18
          相关资源
          最近更新 更多