调试

From The Document Foundation Wiki
Jump to: navigation, search

调试选项

首先,要开启调试选项:..autogen.sh --enable-debug 开启所有模块的调试或者是 -enable-debug --enable-selective-debuginfo="sw/ xmloff/" 开启部分模块调试功能。

另外一个重要的调试选项就是 --enable-dbgutil。此选项会增加一些 STL 的一些断言和调试代码,选项支持 GCC 平台(不包括 Mac OS X 因为 Apple 的libstdc++ 不支持)和 MSVC 平台。

使用 --enable-debug 或者 --enable-dbgutil 选项编译所有模块大约会使用 30G 的硬盘空间,如果您想减少空间占用可以使用 --enable-selective-debuginfo 选项,或者先不使用 debug 选项编译然后在重新编译您需要调试的模块:

make <module>.clean && make <module> debug=t

使用 gdb 调试

有两种方法启动调试:

  • 使用专用启动脚本(soffice, swriter 等)启动应用程序,然后附加应用程序进程到调试器。
  • 通过应用程序直接启动 Libreoffice 进程(soffice.bin)

在以下的说明中都需要添加环境变量 $LOROOT 为您的源代码路径,也就是 autogen.sh 脚本所在的路径。

附加 soffice.bin 进程

这种方法很简单, soffice 脚本会设置需要的变量。

$ instdir/program/soffice  # or /sdraw /swriter ...
$ gdb --pid=$(pidof soffice.bin)
(gdb)

运行启动脚本时(soffice, swriter...),你可以加上 -norestore 选项,这样当系统发生错误时不会触发 restart/restore 恢复机制。

使用 attach <pid>detach 命令附加和分离 soffice.bin 进程到 gdb。

从调试器(gdb)中启动 LibreOffice

从 3.5 版本开始,您可以通过以下简单的名利直接启动调试器:

make debugrun

从 5.0 开始这个选项也适用于 MSVC,但是只能附加到 soffice.bin进程,。

gdb 使用简要说明

当程序停止时,您可以查找符号、查看变量、设置断点等:

(gdb) info fun DrawEllipse
All functions matching regular expression "DrawEllipse":
 
File $LOROOT/svtools/source/filter.vcl/wmf/winmtf.cxx:
void WinMtfOutput::DrawEllipse(Rectangle const&);
 
File $LOROOT/clone/libs-gui/vcl/source/gdi/outdev5.cxx:<span style="color:#000000" />
void OutputDevice::DrawEllipse(Rectangle const&);
 
File $LOROOT/clone/libs-gui/vcl/source/gdi/pdfwriter.cxx:
void vcl::PDFWriter::DrawEllipse(Rectangle const&);
 
Non-debugging symbols:
0x00007f826dd4a318  OutputDevice::DrawEllipse(Rectangle const&)
0x00007f826dd4a318  [mailto:_ZN12OutputDevice11DrawEllipseERK9Rectangle@plt _ZN12OutputDevice11DrawEllipseERK9Rectangle@plt]

(gdb) break  vcl::PDFWriter::DrawEllipse
Breakpoint 1 at 0x7f826c7c5e20: file /opt/shared/work/source_code/libreoffice/libo/clone/libs-gui/vcl/source/gdi/pdfwriter.cxx, line 159.

如上命令,已经在函数出设置了断点。设置函数断点时,必须使用函数全名,包括类名和命名空间。

设置断点的通用语法是:break <location>,<location> 可以是函数全名、内存地址或者是文件名 + ‘:’ + 行号构成的定位。更多信息请查看 gdb 的手册: [specifying a Location](http://sourceware.org/gdb/current/onlinedocs/gdb/Specify-Location.html#Specify-Location)

用如下命令查看断点列表:

(gdb) info break
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00007f826c7c5e20 in vcl::PDFWriter::DrawEllipse(Rectangle const&)
                                               at /opt/shared/work/source_code/libreoffice/libo/clone/libsgui/vcl/source/gdi/pdfwriter.cxx:159

用如下命令删除断点:

clear <location>
delete <breakpoint number>

Pending breakpoints

当您设置的断点符号未加载时,您可以设置 pending breakpoint,当符号可用时 gdb 会自动进入断点。

(gdb) break SVGActionWriter::ImplWriteRect
Can't find member of namespace, class, struct, or union named "SVGActionWriter::ImplWriteRect"
Hint: try 'SVGActionWriter::ImplWriteRect<TAB> or 'SVGActionWriter::ImplWriteRect<ESC-?>
(Note leading single quote.)
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (SVGActionWriter::ImplWriteRect) pending.
(gdb) info break
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   <PENDING>  SVGActionWriter::ImplWriteRect

通过如下命令设置 pending breakpoint:

set breakpoint pending on

恢复默认使用 "auto" 选项。

关于 pending breakpoint 的讨论:您必须记住函数全名 info fun 命令是无效的,因为符号没有加载。一个可行的解决方案是使用 shared objet events(译者注:详情查看下文)

Dumping Strings(etc)

在 gdb 7 及以后的版本中,通过 gdb pretty printers 您可以打印 UTF-16 的 rtl::OUString 和 8-bit 的 rtl::OString 的内容。同时也可以其他对象的格式化内容,如: Sequence, Date, Time 等等。如果你不需要显示格式化内容请使用 *print/r(或者 p/r)*。 pretty printers 在 gdb 启动时自动激活。

备注1:如果您的 pretty printers 没有正常工作,可能是因为权限设置导致的,请认真查看日志信息,如果是请尝试在 $HOME/.gdinit 中加入:

 add-auto-load-safe-path /path/to/your/lo/git

备注2:Apple gdb 不支持 Pyton pretty-printers。

Dumping STL 容器

pretty-print 同样可以格式化打印出 STL 容器的内容。

早期版本 LO 处理;从 4.0 版本开始 libstdc++ 不在捆绑

如果您使用早期版本的 LO pretty printer 没有正常工作是因为 LO 使用自己的 libstdc++,所以 gdb 不鞥自动加载相关的 Python 脚本。

在 Fedora 16 系统中,您可以在 .gdbinit 文件中加入(您可能需要根据您的系统修改相应的版本号):

# workaround OOo/LO shipping its own libstdc++
python
import sys
sys.path.insert(0, '/usr/share/gcc-4.6.1/python')
end
source /usr/share/gdb/auto-load/usr/lib64/libstdc++.so.6.0.16-gdb.py

Shared ObjectEvents(共享对象事件)

当一个共享库加载时引发共享对象事件。默认情况下共享对象事件是关闭的,你可以使用如下命令开启共享对象事件:

set stop-on-solib-events 1

开启共享事件对象后,每次加载共享库是 gdb 会暂停,您可以查找符号设置断点等。

您可能只需要找到你需要的共享库加载,这个过程中您需要多次执行 continue 命令。

那么,是如何找您想要的共享库呢,您可以使用 info shared <reg expr> 命令,此命令会使用正则表达式匹配出所有符合条件的共享库。

调试 UNO

如果您想查看 UNO reference 指向的真是 C++ 对象,您可以使用如下命令:

(gdb) print *rShape._pInterface
$1 = {_vptr.XInterface = 0x2aaac99f9728 <vtable for SvxShapeText+648>}
(gdb) print rShape._pInterface
$2 = (com::sun::star::uno::XInterface *) 0x2313e9

其他帮助

一些 gdb 的其他帮助信息:

  • fcatch: stop when an exception is thrown, but only if a certain given function is on the stack.

Debugging with DDD (a gdb front-end)

待翻译...