目标:
我想象征[NSThread callStackSymbols]
的“输出”。
旁注:
我知道如何使用崩溃日志来做到这一点。但是,我需要调查一些我想查看调用堆栈的问题。不幸的是,这些天框架的地址都是<redacted>
。在正确的点(或在最后 - 看到我的问题的结尾)导致崩溃是不可接受的,但如果我找不到另一种解决方案,那将是可行的方法。
我必须在设备上运行我的测试,所以我不能使用模拟器。
目前的做法:
当我这样称呼时:
NSLog(@"call stack:\n%@", [NSThread callStackSymbols]);
我得到了这个输出:
2015-12-08 15:04:03.888 Conversion[76776:4410388] call stack:
(
0 Conversion 0x000694b5 -[ViewController viewDidLoad] + 128
1 UIKit 0x27259f55 <redacted> + 1028
...
9 UIKit 0x274f67a7 <redacted> + 134
10 FrontBoardServices 0x2b358ca5 <redacted> + 232
11 FrontBoardServices 0x2b358f91 <redacted> + 44
12 CoreFoundation 0x230e87c7 <redacted> + 14
...
16 CoreFoundation 0x23038ecd CFRunLoopRunInMode + 108
17 UIKit 0x272c7607 <redacted> + 526
18 UIKit 0x272c22dd UIApplicationMain + 144
19 Conversion 0x000767b5 main + 108
20 libdyld.dylib 0x34f34873 <redacted> + 2
)
(此输出中的“转换”是应用程序。)
现在我可以使用此命令“符号化”地址:
xcrun atos -o /path/to/Conversion.app -arch arm64 -l 0x0???
像这样运行(当然,-l
的值正确),我可以输入0x000694b5
这样的地址,它会吐出类似-[ViewController viewDidLoad] + 128
的内容。当然问题是起始地址(-l选项的值)。
当我有崩溃日志时,我可以获得这些。但是,我想在没有崩溃的情况下离开。
问题:
Q1:我可以在运行时确定起始地址,也可以将其包含在日志输出中,以便将其提供给atos -l
选项吗?
#import <mach-o/dyld.h>
...
intptr_t slide = _dyld_get_image_vmaddr_slide(0);
const struct mach_header * load_addr = _dyld_get_image_header(0);
NSLog(@"slide %lx load addr %lx", (long)slide, (long)load_addr);
/ EDIT
(因为我对框架的方法调用感兴趣,我当然需要框架的起始地址。应用程序的起始地址经常变化(随机化),我还不知道,框架的起始地址是否随机化。 )
Q2:还有其他方法可以调查调用堆栈中的方法吗? (断点在我的场景中也相当笨拙。)
编辑:
问题3:如何表示框架的地址?例如,我在哪里可以找到UIKit的dSYM(或任何需要的东西)?
(例如我有一些内容:~/Library/Developer/Xcode/iOS\ DeviceSupport/9.1\ \(13B143\)/Symbols/System/Library/Frameworks/UIKit.framework/
。我会在这里查看更多细节。)
/ EDIT
也许是解决方案:
一种方法可能是,将日志输出保存到文件,并在测试结束时导致应用程序崩溃。这样崩溃日志会显示起始地址,并且通过日志中的调用堆栈信息,我应该能够表示callStackSymbols
输出。我会尝试下一步。
答案 0 :(得分:3)
到崩溃日志中添加日志片段到目前为止运作良好,所以我现在将其添加为答案。 (绝对欢迎更好的答案:-))
<强>制剂强>
在源代码的相关位置添加callStackSymbols日志记录:
NSLog(@"call stack:\n%@", [NSThread callStackSymbols]);
使应用程序崩溃(例如,打开某个屏幕时):
strcpy(0, "000");
将日志记录输出重定向到文件:
FILE *logfile = freopen([pathForLog cStringUsingEncoding:NSASCIIStringEncoding], "a+", stderr);
<强>执行:强>
在Xcode中运行应用程序一次,然后将其安装在设备上,然后停止它。 然后直接在设备上启动应用程序,这样Xcode就不会发现崩溃。
使用该应用程序以便记录调用堆栈(可以多次)。
最终让应用程序崩溃(在我的情况下,打开一个调用坏strcpy的屏幕)。
获取文件:
在Xcode中打开&#34;窗口 - &gt;设备&#34;,选择设备,选择应用程序并下载应用程序容器,以便提取日志文件。
在同一屏幕中打开设备日志并导出崩溃日志。
在Xcode中打开&#34;窗口 - &gt;项目&#34;,选择项目并使其在Finder中显示派生数据文件夹(派生数据路径右侧的小箭头按钮)。在派生数据文件夹中,导航到&#34; Build / Products / Debug-iphoneos /&#34;并复制MyApp.app和MyApp.app.dSYM。
调整崩溃日志:
对我而言,它可以在&#34; Binary Images:&#34;之前添加额外的线程部分。所以找到&#34;二进制图像的位置:&#34;。插入一行&#34;线程9999:&#34;。复制并粘贴调用堆栈转储并删除前导空白列,使其如下所示:
2015-12-09 15:28:58.971 MyApp[21376:3050653] call tree (
Thread 9999:
0 MyApp 0x00000001001d95f8 -[MyClass myMethod:] + 100
1 UIKit 0x000000018a5fc2ac <redacted> + 172
2 UIKit 0x000000018a5d5ca4 <redacted> + 88
3 UIKit 0x000000018a5d5b8c <redacted> + 460
4 UIKit 0x000000018a5d5cc0 <redacted> + 116
5 UIKit 0x000000018a5d5b8c <redacted> + 460
6 UIKit 0x000000018a5d5cc0 <redacted> + 116
7 UIKit 0x000000018a5d5b8c <redacted> + 460
8 UIKit 0x000000018a8e85ac <redacted> + 460
9 UIKit 0x000000018a5d4abc <redacted> + 96
10 UIKit 0x000000018a935b7c <redacted> + 344
11 UIKit 0x000000018a9306f8 <redacted> + 124
12 UIKit 0x000000018aa584d8 <redacted> + 44
13 UIKit 0x000000018a933d9c <redacted> + 188
14 UIKit 0x000000018a70b668 <redacted> + 116
15 UIKit 0x000000018a70b454 <redacted> + 252
16 UIKit 0x000000018a70af38 <redacted> + 1404
17 UIKit 0x000000018a70a9a8 <redacted> + 124
18 UIKit 0x000000018a616d3c <redacted> + 312
19 UIKit 0x000000018a616bc4 <redacted> + 108
20 QuartzCore 0x0000000189dddc2c <redacted> + 284
21 libdispatch.dylib 0x000000019a3a96a8 <redacted> + 16
22 libdispatch.dylib 0x000000019a3aedb0 _dispatch_main_queue_callback_4CF + 1844
23 CoreFoundation 0x00000001850001f8 <redacted> + 12
24 CoreFoundation 0x0000000184ffe060 <redacted> + 1628
25 CoreFoundation 0x0000000184f2cca0 CFRunLoopRunSpecific + 384
26 GraphicsServices 0x000000018ff94088 GSEventRunModal + 180
27 UIKit 0x000000018a644ffc UIApplicationMain + 204
28 MyApp 0x0000000100093918 main + 124
29 libdyld.dylib 0x000000019a3da8b8 <redacted> + 4
Binary Images:
...
&#34;线程9999:&#34; line使symbolicatecrash
脚本想要表示下一行。我选择了9999所以我知道,这些是我添加的部分。
运行符号:
找到symbolicatecrash
脚本:
$ find /Applications/Xcode.app -name symbolicatecrash -type f
/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash
$
符号化命令几乎是这样的:
$ symbolicatecrash myapp.crash MyApp.app.dSYM > myapp-sym.crash
您需要设置DEVELOPER_DIR并添加脚本的路径,因此最终看起来像这样:
$ DEVELOPER_DIR='/Applications/Xcode.app/Contents/Developer' /Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash myapp.crash MyApp.app.dSYM > myapp-sym.crash
或包裹以获得更好的观赏乐趣:
$ DEVELOPER_DIR='/Applications/Xcode.app/Contents/Developer' ...
/Applications/Xcode.app/Contents/SharedFrameworks/ ...
DTDeviceKitBase.framework/Versions/A/Resources/ ...
symbolicatecrash myapp.crash MyApp.app.dSYM > myapp-sym.crash
结果:
符号化的片段现在看起来像这样:
2015-12-09 15:28:58.971 MyApp[21376:3050653] call tree (
Thread 9999:
0 MyApp 0x00000001001d95f8 -[MyClass myMethod:] (MyFile.m:15)
1 UIKit 0x000000018a5fc2ac -[UIScrollView _willMoveToWindow:] + 172
2 UIKit 0x000000018a5d5ca4 __85-[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]_block_invoke + 88
3 UIKit 0x000000018a5d5b8c -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 460
4 UIKit 0x000000018a5d5cc0 __85-[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]_block_invoke + 116
5 UIKit 0x000000018a5d5b8c -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 460
6 UIKit 0x000000018a5d5cc0 __85-[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]_block_invoke + 116
7 UIKit 0x000000018a5d5b8c -[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:] + 460
8 UIKit 0x000000018a8e85ac __UIViewWillBeRemovedFromSuperview + 460
9 UIKit 0x000000018a5d4abc -[UIView(Hierarchy) removeFromSuperview] + 96
10 UIKit 0x000000018a935b7c __71-[UIPresentationController _initViewHierarchyForPresentationSuperview:]_block_invoke596 + 344
11 UIKit 0x000000018a9306f8 -[UIPresentationController transitionDidFinish:] + 124
12 UIKit 0x000000018aa584d8 -[_UICurrentContextPresentationController transitionDidFinish:] + 44
13 UIKit 0x000000018a933d9c __56-[UIPresentationController runTransitionForCurrentState]_block_invoke_2 + 188
14 UIKit 0x000000018a70b668 -[_UIViewControllerTransitionContext completeTransition:] + 116
15 UIKit 0x000000018a70b454 -[UITransitionView notifyDidCompleteTransition:] + 252
16 UIKit 0x000000018a70af38 -[UITransitionView _didCompleteTransition:] + 1404
17 UIKit 0x000000018a70a9a8 -[UITransitionView _transitionDidStop:finished:] + 124
18 UIKit 0x000000018a616d3c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312
19 UIKit 0x000000018a616bc4 -[UIViewAnimationState animationDidStop:finished:] + 108
20 QuartzCore 0x0000000189dddc2c CA::Layer::run_animation_callbacks(void*) + 284
21 libdispatch.dylib 0x000000019a3a96a8 _dispatch_client_callout + 16
22 libdispatch.dylib 0x000000019a3aedb0 _dispatch_main_queue_callback_4CF + 1844
23 CoreFoundation 0x00000001850001f8 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
24 CoreFoundation 0x0000000184ffe060 __CFRunLoopRun + 1628
25 CoreFoundation 0x0000000184f2cca0 CFRunLoopRunSpecific + 384
26 GraphicsServices 0x000000018ff94088 GSEventRunModal + 180
27 UIKit 0x000000018a644ffc UIApplicationMain + 204
28 MyApp 0x0000000100093918 main (main.m:16)
29 libdyld.dylib 0x000000019a3da8b8 <redacted> + 4
Binary Images:
...
除非我找到更简单的方法,否则这将是我现在的方法。创建一个从日志文件中提取调用堆栈的脚本,删除前导空格并将其插入崩溃日志中可能很有用。
答案 1 :(得分:0)
SYMBOLICATECRASH
Apple发布了一个带有XCode的脚本,可以完整地加速崩溃报告的符号化过程。如果您有dSYM,app二进制文件和崩溃报告,这可能是最简单的符号化方法。您不必担心任何地址 - 此脚本将解析整个故障转储文件并使用ATOS将所有地址解析为符号。
在您的系统上找到“symbolicatecrash”:
cd /Applications/Xcode.app
find . -name symbolicatecrash
导出DEVELOPER_DIR环境变量(如果它不存在)
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
将.app二进制文件,崩溃报告和.dSYM文件复制到临时文件夹(例如〜/ tmp)。 像下面的示例一样运行脚本:
/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash -v ApteligentExampleApp.crash ApteligentExampleApp.app.dSYM/
如果一切顺利,脚本应该象征整个崩溃文件并将结果输出到终端窗口。此脚本不会执行任何您无法使用ATOS或其他工具手动执行的操作,但它可以更快地为您提供所需的内容。