Xcode 4.2调试不代表堆栈调用

我在 iOS 5模拟器/设备中的 Xcode 4.2调试出现了问题:

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

在 iOS4中,我得到了一个有用的十六进制数的堆栈跟踪,但在 iOS5中,它只给了我:

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

谢谢。

42274 次浏览

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

在这里提交错误报告。

Http://developer.apple.com/bugreporter/

编辑:

我相信,如果你切换回 LLVM GCC 4.2,你不会看到这种情况发生。但是,您可能会失去所需的特性。

我试过的任何方法都不能解决这个问题(试过两个编译器、两个调试器等等) 在为 iOS5更新升级 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调用(整个应用程序只能有一个处理程序)。例如,一些第三方库设置自己的 uncaughtExceptionHandler。因此,尝试在 didFinishLaunchingWithOptions函数的 END 设置它(或者有选择地禁用第三方库)。或者更好的做法是,在 NSSetUncaughtExceptionHandler上设置一个符号断点,以便快速查看是谁在调用它。您可能想要做的是修改您当前的一个,而不是添加另一个。
  2. 您实际上并没有遇到异常(例如,EXC_BAD_ACCESS没有是一个异常; 这要归功于@Erik B 的评论,见下文)

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

一旦你到达这个断点,你可以像往常一样使用调试导航器来导航调用堆栈,检查变量等等。

如果您确实需要一个符号化的调用堆栈,以便进行复制/粘贴或类似操作,那么 gdb 回溯跟踪可以从这里开始工作:

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

(等)

调试器上有一个新特性。每当抛出异常时,您可以设置一个断点,并在那里停止执行,就像在4.0中一样。

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

仅此而已!

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

这里还有一个解决方案,不像前面那样优雅,但是如果您没有添加异常断点或处理程序,那么它只能是一种方法。
当应用程序崩溃时,你得到原始的 第一次抛出调用堆栈(十六进制数字) ,输入 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>.

如果您使用的是 Ldb,那么可以键入 image lookup -a hex(在这种情况下不使用星号) ,并得到类似的输出。

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

另外,为了达到类似的效果,你可以在终端中使用 atos 工具,只需输入:

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

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

重新启用“为拇指编译”(调试配置)对我来说很有用。

在主函数中使用以下代码:

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;
}

您可以添加一个 异常断点(使用断点导航器底部的 +)和 加上动作 bt(单击 Add Action 按钮,选择 Debugger Command,在文本字段中输入“ bt”)。这将在抛出异常时立即显示堆栈跟踪。

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

image lookup -a 0x1234

它会向你展示这样的东西:

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