编写LLDB脚本以在崩溃后获取堆栈跟踪

时间:2014-11-07 23:56:34

标签: crash automation lldb

我试图在我们的某个测试崩溃时自动添加从mac核心转储生成堆栈跟踪的功能。

我能够在linux上用

轻松完成
gdb --batch --quiet -ex "thread apply all bt" -ex "quit" <binary> <core file> 2> /dev/null

但我在使用lldb在mac(OSX 10.8)上做同样的事情时遇到了一些麻烦。首先,我使用的lldb版本是lldb-310.2.37。

我最初的方法是使用-s选项并传入一个脚本文件,如下所示:

target create -c <core file> <binary>
thread backtrace all
quit

最初我遇到了一些麻烦,我认为这是因为在脚本文件末尾错过了一行,导致lldb无法退出,但在修复后,我得到以下内容: 在&lt; lldbSource&#39;中执行命令。

(lldb)  target create -c <core file> <binary>
Core file '<core file>' (x86_64) was loaded.
(lldb)  thread backtrace all
error: Aborting reading of commands after command #1: 'thread backtrace all' failed with error: invalid thread
Aborting after_file command execution, command file: 'lldbSource' failed.

有趣的是,在那之后,我们仍然在运行lldb,并且发出&#39;线程回溯全部&#39;手动工作得很好。

所以,方法#2是创建一个python脚本并使用他们的python API(我试过这个,然后找出我描述的初始阻塞是由于缺少换行符。)

我的剧本:

import lldb
debugger = lldb.SBDebugger.Create()
target = debugger.CreateTarget('<binary>')
if target:
 process = target.LoadCore('<core file>')
 if process:
  print process.exit_description
  for thread in process:
   print 'Thread %s:' % str(thread.GetThreadID())
   print '\n'.join(str(frame) for frame in thread)

我采用这种方法的问题是process.exit_description正在返回None(我尝试的其他所有事情也是如此; LLDB&#python API文档几乎是完全没用的。)

我从该通话中寻找的输出类似于以下内容:

Process 0 stopped
* thread #1: tid = 0x0000, 0x00007fff8aca4670 libsystem_c.dylib`strlen + 16, stop reason = signal SIGSTOP
    frame #0: 0x00007fff8aca4670 libsystem_c.dylib`strlen + 16
libsystem_c.dylib`strlen + 16:
-> 0x7fff8aca4670:  pcmpeqb (%rdi), %xmm0
   0x7fff8aca4674:  andl   $0xf, %ecx
   0x7fff8aca4677:  shll   %cl, %eax
   0x7fff8aca4679:  pmovmskb %xmm0, %ecx

加载核心文件时,LLDB会自动输出。我不一定需要汇编转储,但我至少需要线程,框架和原因。

我认为我使用的第一种方法,如果可以使用,将是理想的,但无论哪种方式对我来说都可以。我无法控制将要使用的LLDB版本,因此我无法更新到最新版本,看看它是否是修复过的错误。

也欢迎获得所需输出的其他方法。对于上下文,这将从perl脚本调用。

2 个答案:

答案 0 :(得分:6)

xcode 7.2(--batch)附带的lldb版本支持lldb-340.4.119命令行参数,可能更早。

the man page中没有记录,但在lldb --help中记录了它:

   -b 
   --batch 
        Tells the debugger to running the commands from -s, -S, -o & -O,
        and then quit.  However if any run command stopped due to a signal
        or crash, the debugger will return to the interactive prompt at the
        place of the crash.

这些其他命令行选项对lldb自动化非常有用:

   -o 
   --one-line 
        Tells the debugger to execute this one-line lldb command after any
        file provided on the command line has been loaded.

   -k 
   --one-line-on-crash 
        When in batch mode, tells the debugger to execute this one-line
        lldb command if the target crashes.

使用这些工具,我拼凑了以下命令:

ulimit -c unlimited && (<binary> || (lldb -c `ls -t /cores/* | head -n1` \
  --batch -o 'thread backtrace all' -o 'quit' && exit 1))

此命令:

  1. Enables core dumps
  2. 运行可执行文件<binary>
  3. 如果失败,请在/cores中最近创建的核心转储上运行lldb(希望是正确的)
  4. 打印所有线程的回溯
  5. 以非零状态退出,以便此命令可以嵌入其他工作流程(CI脚本,Makefile等)。
  6. 我宁愿直接在<binary>上运行lldb,这样命令就不依赖猜测正确的核心文件了。但lldb似乎仍然没有办法让它以非零退出状态退出 - 相当于GDB的-return-child-result选项或quit 1命令 - 所以我无法知道是否调试的程序是否成功。我filed an issue要求提供此功能。

答案 1 :(得分:1)

来自lldb.llvm.org的TOT lldb有一个新的&#34; - 批次&#34;模式工作非常类似于gdb批处理模式,并修复了一些使命令行源命令行为更好的错误。如果您可以构建自己的lldb,那么现在就可以获得这些修复,否则您将不得不等到下一个Xcode更新。

exit_description为None,因为您的进程没有退出,它崩溃了。请注意,至少在OS X上,当进程崩溃时,几个线程可能同时存在异常,说这个进程崩溃并不是很有用。你必须问线程。使用GetStatus方法可以获得lldb在线程停止时打印出来的停止状态。

stream = lldb.SBStream()
process.threads[0].GetStatus(stream)
print stream.GetData()

这似乎没有一个非常有用的帮助字符串。