How to debug

From The Document Foundation Wiki
Jump to: navigation, search

Debugging options

You need to enable debugging support to do any practical interactive debugging. You can enable it for the entire build with ./ --enable-debug or just for specific modules with --enable-debug --enable-selective-debuginfo="sw/ xmloff/".

Another very helpful option for debugging is --enable-dbgutil, which is like --enable-debug and additionally enables more-or-less useful assertions and additional debugging code, and also the STL debugging mode of libstdc++ on some GCC based platforms (but not Mac OS X because Apple's libstdc++ lacks support for it, and clang libc++ does not appear to have a debug mode), and uses the debug runtimes (including debug STL) with MSVC. Note that it is not possible to mix code built with and without --enable-dbgutil.

Note that a complete build with --enable-debug or --enable-dbgutil for all modules takes ~30G of disk space. If you find this too much you can either use --enable-selective-debuginfo or do a full non-debug build and then rebuild just the modules you are interested in:

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

Debugging with gdb

There are two methods: you can start LibreOffice using the dedicated script (soffice, swriter, etc.) and then attach the debugger to the LibreOffice process, or start LibreOffice binary (soffice.bin) directly from the debugger.
In the following notes the $LOROOT variable is set to the path to the directory where you cloned the core git repository, that is the path to the directory where the script is placed.

Attaching to the soffice.bin process

This is quite simple, because the soffice script will take care to set up all the needed environment variables:

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

When you execute the launch script (soffice, swriter, …) you can pass the -norestore option: it will suppress restart/restore after fatal errors.
For attaching and detaching a process from inside the gdb shell you can utilize the attach <pid> and detach commands, the latter doesn't need any argument.
After attaching to the soffice.bin process gdb stops the program.

Start LibreOffice from the debugger (gdb)

On 3.5 and later the easiest way to do this is this simple command on the top-level (the started soffice.bin will listen on a named pipe, so you can even connect to it from another process via UNO):

 make debugrun

On 5.0 and later this will also work with MSVC, but it will only launch soffice.bin and you have to attach the debugger manually from Visual Studio.

A gdb primer

Once the program is stopped you can search for symbols, watch data and set up breakpoints:

(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.

Now a breakpoint at the location related to the given method is set. Note that the method name must be fully qualified including the class name and the wrapping namespaces.
The general syntax is: break <location>, where <location> can be a fully qualified function or method name, a memory address or a file name followed by a “:” and a line number. For more details on the location concept read the gdb manual page: Specifying a Location

For listing breakpoints that has been set up you can use the command:

(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

To remove a breakpoint you can use one of the following commands:

clear <location>
delete <breakpoint number>

Pending breakpoints

In case a given symbol belongs to a not yet loaded shared library you can still add a breakpoint related to that symbol, gdb will set up a so said pending breakpoint that will be activated as soon as the symbol will be available.

(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

If you want that gdb sets up as pendinding breakpoint any unknown symbol automatically without asking you every time what it should do, you have to execute the following command:

set breakpoint pending on

to return to the default state set it to “auto”.

An issue with pending breakpoints is that you have to remember the full qualified function or method name: the info fun command will not help you because the symbol is still unknown. A possible solution is provided by shared object events.

Dumping Strings (etc)

Through the magic of gdb pretty printers then with gdb 7 onwards print string will dump the contents of the string regardless of whether it's a UTF-16 rtl::OUString or 8-bit rtl::OString. There is pretty-printer support for sane dumping of a variety of other objects as well as strings, e.g. Any, Sequence, Date, Time, etc. Use print/r (or p/r) if you really need to see the structure non-pretty-printed. The pretty printers are activated automatically for in-build debugging and for running from instdir.

Note: if pretty printers do not work out of the box, probably a gdb security setting prevents them from being loaded; look for an error message about "safe-path". To avoid that problem, append this to the configuration file $HOME/.gdbinit:

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

Note: Apple gdb is antique and does not support Python pretty-printers.

Dumping STL containers

GDB can also pretty-print the contents of STL containers, which is very useful.

The following applies only to older LO versions; since version 4.0 the libstdc++ is no longer bundled

But this may not work out of the box because the LO installation set contains its own libstdc++, so gdb cannot auto-load the related Python files.

On a Fedora 16 system, the following addition to .gdbinit works around the problem (you may want to adapt the version numbers to your system):

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

Shared Object Events

A shared object event happens every time a shared library is loaded or unloaded. By default is not activate, but you can turn it on with the following command:

set stop-on-solib-events 1

Now every time a shared library is loaded the program is stopped and you'll be able to search for new symbols and set up new breakpoints.
You should activate shared object events only when you know that the shared library, you are interested in, will be loaded in a short time, on the contrary you should give the continue command a lot of times and everything will become very annoying.
How can you know if a shared library you are interested in has been loaded ? That can be found out using the info shared <reg expr> command. This command will list all loaded shared libraries that match the given regular expression.

Debug UNO

When you search for the real C++ type of a UNO reference you can use:

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

Misc helpers

Some gdb extensions that could be useful in certain circumstances:

  • info mutex: displays which threads have which mutex locked
  • 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)

If you want to attach the debugger to the soffice.bin process you have to start LibreOffice:

$ cd $LOROOT/install/program
$ ./soffice    # or ./swriter, ./simpress, ...

In case you want to start LibreOffice from the debugger you need in any case to source the environment variables before running it:

$ cd $LOROOT/install/program
$ source ./ooenv

Finally you can start DDD with the ddd command.

In both cases you have to set up the program to be debugged click on the Open Program entry in the File menu. A file dialog window will pop up: select the soffice.bin executable that you can find under $LOROOT/install/program. In case you have already started LibreOffice you need to attach to the soffice.bin process: you can do that by the File>Attach to process menu entry. A list of running process is presented to you, double click on the soffice.bin process (it should be already selected). In the same way to detach the process execute the command File>Detach.

After attaching to the process the program is suspended and you can start debugging it. The Command Tool box will open automatically providing a whole set of action buttons for resume execution and step through the program. At the bottom of the DDD window you can see the GDB Console: a shell where you can execute gdb commands directly. Above the GDB Console there is the Source Window where you can look at the program source code.

To change the font type and size of the GDB Console and the Source Window you have to go to Edit>Preferences...>Fonts and modify the Fixed Font property. In order to make your custumizations permanent you have to check the Save Options entry in the Edit menu.

To start LibreOffice from the debugger you can click on the Run button (in the floating Command Tool box). Or you can give the run or start command directly in the GDB Console, that will let you to pass command line arguments to the program.

By Status>Backtrace menu entry you will open a dialog box showing a sequence of function calls: they start from the call to the main funtion up to the last function call: the one where the program has been stopped. Select a function call in this list and the source code where the function call is performed will be displayed in the Source Window (if the source file is found). A big arrow on the left will show the current execution position. If you want to examine the backtrace for a different thread you have to open the Thread dialog box using the entry with the same name under the Status menu.

Below the DDD menu there is an edit field with several buttons on the right. You can think for each button as an action that will be performed using the text present in the edit field every time the button is clicked. If you write in the edit field a fully qualified symbol name and then click the Lookup button the source file where the symbol is defined will be opened in the Source Window. In case you write any string in the edit field and click the Find>> (forward) button the current showed source file will be forward searched for the given string.

When the symbol you write in the edit field is a valid location clicking on the Break button will set up a breakpoint at that location. If you open the source file containing the given symbol you will see that a small "stop" icon has appeared on the left at the line where the symbol is defined, pointing out that a breakpoint has been created. Right clicking on it, a context menu will open with several options. In the same way clicking on the Watch button will define a watch point for the given symbol. Another way to set up a breakpoint is to right click on a line of code in the Source Window and select the Set Breakpoint entry.

The Print button will print the value of the symbol you entered in the edit field to the gdb shell, for more complex values the Display button will show the symbol value graphically in the Data Window that will open automatically above the Source Window. Indeed if you point the mouse on a variable symbol in the Source Window its value will be displayed automatically in a small tooltip box. In the Data Window you can display also all available local variables and the arguments passed to the current function: to make them visible you have to select the related entries in the Data menu. Each data box displayed in the Data Window is called a Display. You can move it in the Data Window as you like, moreover when you righ click on it a context menu appears presenting to you several setting entries.

Pending Breakpoints

Pending breakpoints are not supported by DDD. Even if you execute the break <yet unknown symbol> command directly in the GDB Console, no question will be presented to you for adding it as a pending breakpoint. One workaround is to set the breakpoint pending property to on (by default is set to auto, you can perform that by executing the set breakpoint pending on command in the GDB Console or by checking the related option in the GDB Settings dialog (Edit>GDB Settings ...).
Now by the Break button you can set up any valid string as a breakpoint (pending or not). However pay attention! There is a tricky drawback. The first non-pending breakpoint that you create after you set up a pending one, is shadowed by the latter. Opening the Breackpoints dialog (Source>Breakpoints...) you will see that the non-pending breakpoint can't be deleted, and its properties can't be set. Every action you perform on the non-pending breakpoint, even through the context breakpoint menu in the Source Window, will be performed on the pending one.
Anyway don't make mistake, this is only a DDD front-end issue: even if it is shadowed the non-pending breakpoint is set and the program will stop at it, and in any case it can be managed directly through the GDB Console. When the pending breakpoint is deleted the non-pending one can be managed through the DDD front-end, too.

Shared Object Events

To enable shared object events you can give the set stop-on-solib-events 1 command in the GDB Console or check the Stopping for Shared Library Events entry in the GDB Settings dialog (Edit>GDB Setting...)

Opening Source Files

You can search for source files through the Open Source dialog (File>Open Source...): here, in the Filter edit field you can enter a string e.g. : "*main*" (globbing rules are used) and any source file containing a known symbol will be matched against that string when you click the Filter button placed at the bottom. For more details on the features of the Open Source dialog click on the Help button.

Debugging with Eclipse CDT on Linux

1- Add new debug configuration (libreoffice).

2- In Main tab-> C/C++ Application, browse soffice.bin file that should be in : {your build path}/libreoffice/instdir/program/soffice.bin. (Make sure you enabled debug in your build).

3- In the project field, add libreoffice project.

4- Click on "Select other" in the Debug configurations window.

5- Check "Use configuration specific settings" and select "Standard Attach to Process Launcher".

6- Make sure you have these parameters in the Debugger tab: - Debugger: gdb/mi - GDB debugger: gdb - GDB command file: .gdbinit. - GDB command set: Standard (Linux). - Protocol: mi. - Check "Use full file path to set breakpoints".

7- Click on apply and close.

8- Modify the debugger timeout to prevent this message when debugging: "Target is not responding (timed out)". Go to Window -> Preferences -> C/C++ -> Debug -> GDB MI and set the debugger timeout to 200000 ms and launch timeout to 300000 ms.

9- If you're using Ubuntu, the last step before debugging libreoffice is modifying the ptrace_scope to make it less restrictive. That would prevent this message: "Could not attach to process. If your uid matches the uid of the target process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try again as the root user. For more details, see /etc/sysctl.d/10-ptrace.conf". All you need is just setting ptrace_scope to 0 in /etc/sysctl.d/10-ptrace.conf.

10- Enjoy the debug and add breakpoints in eclipse as well as you want.

Debugging with lldb

If you don't have gdb available, say because you're stuck with macOS, you have to use lldb.

The commands are different between gdb and lldb.

There is some helpful python pretty printing that you can load manually to print OUStrings etc., see solenv/lldb/libreoffice/

Unfortunately at least Apple's lldb appears to have a nasty habit of truncating command line arguments, so starting CppUnit tests in the usual way may fail with an exception from cppuhelper::ServiceManager::readRdbFile.

Debugging with WinDbg or Visual Studio (on Windows)

In Visual Studio, the call stacks may at first appear useless; to avoid this, enable the Microsoft Symbol Server in the configuration: Tools ▸ Options ▸ Debugging ▸ Symbols and click on "Microsoft Symbol Servers".

For info on how to set up WinDbg or Visual Studio for debugging TDF release builds with downloaded symbols see How to get a backtrace with WinDbg.

Manually disable the custom allocator for memcheck

The recommended way to use valgrind/memcheck is to run soffice --valgrind, or to export the environment variable VALGRIND=memcheck, which will do the following automatically for you.

By default LibreOffice uses a custom memory allocator, so valgrind won't be able to give full results unless this is disabled, disable it at runtime with...

$ export G_SLICE=always-malloc

this is deliberately the same variable name and value that disables glib's different custom allocator to make debugging easier. This can also be disabled at build-time with

$ ./ --with-alloc=system

Debugging build tools

In case the build breaks when invoking some tool that is actually custom built during the build process, there is likely a bug somewhere in the code of that tool. You can use the BUILDTOOLTRACE environment variable to run the build tool in strace, valgrind or a debugger:

make BUILDTOOLTRACE='strace' PARALLELISM=1              # run in strace
make BUILDTOOLTRACE='gdb --args' PARALLELISM=1          # debug with gdb
make BUILDTOOLTRACE='$(DEVENV) /debugexe' PARALLELISM=1 # debug with Visual Studio

Running cppunit tests

To run cppunnit test foo in module bar, do: cd bar && make CppunitTest_foo

The foo part is what is shown in a non-verbose build log, and its first component will usually be the module (the bar part); if not, run grep foo */*.mk to find out. E.g. the test run when the build system prints [build CUT] sw_subsequent_ooxmlexport can be manually run with cd sw && make CppunitTest_sw_subsequent_ooxmlexport

Debugging cppunit tests

At build time, if a cppunit test crashes you can get a debugger in there with...

$ export CPPUNITTRACE="gdb --args"

now when you build (forcing a non-parallel build with -j1), gdb will start with the cppunit test loaded, type "run" to execute the test under gdb. This option used to be GDBCPPUNITTRACE before October 2013

On windows you can start the unit test in Visual studio with:

$ export CPPUNITTRACE="\"path_to_your_devenv.exe\" /debugexe"

with path_to_your_devenv.exe being the absolute path + devenv.exe. This will start Visual studio and you start the test directly from the UI.

On Mac OSX you no longer have access to gdb which has been replaced by lldb. However you can still use CPPUNITTRACE through

$ export CPPUNITTRACE="lldb --"

Alternatively, if the test crashes and complains about an uncaught execption you can trace a cppunit test to find where the last exception was thrown from with


which will log the throws and catches to gdbtrace.log.

Debugging perfcheck and cppunit tests running with valgrind

For performance tests (make perfcheck) or tests running under valgrind (see paragraphs below) the tests can not be debugged directly. However valgrind includes a gdbserver and the test can be run after exporting


then start the test normally and start gdb with

$ gdb workdir/LinkTarget/Executable/cppunittester

and in the gdb prompt

$ target remote | vgdb

Valgrinding (memcheck) cppunit tests

At build time, you can memcheck the cppunit and other tests with

$ export VALGRIND=memcheck

This will automatically set G_SLICE=always-malloc and should cause the cppunit tests and the hunspell regression tests to be run under valgrind --tool=memcheck

Valgrinding (memcheck) LibreOffice itself

$ export VALGRIND=memcheck

This will automatically set G_SLICE=always-malloc and cause LibreOffice to run itself under valgrind with --tool=memcheck

Valgrinding (helgrind) cppunit tests

At build time, you can helgrind the cppunit and other tests with

$ export VALGRIND=helgrind

Valgrinding (helgrind) LibreOffice itself

$ export VALGRIND=helgrind

This will cause LibreOffice to run itself under valgrind with --tool=helgrind

Running the subsequent tests

A top-level make check will first do a full build, then run all the subsequent tests, while a top-level make subsequentcheck will only run all the subsequent tests.

You can also do these from within a module, or one module only.

You can run a single subsequent test via its target (look into foo/, e.g. cd sw && make -rs JunitTest_sw_complex. The cd foo part is not necessary, but speeds up the process.

If tests fail, it may be due to a locale different from "en-US". In this case, run an "export LANG=C" and give it a new try.

Debugging the subsequent tests

There will be a log file of the failed test, you can look at it with a text editor:


The log file will contain a Java stack trace of the failed test, and if the soffice.bin crashed and left a core file, then you will see a C++ stack trace of the crash as well.

If there is no crash, then a look at the Java stack trace should point you to the Java test code that fails; the most interesting frames are usually in classes complex.<module>...", and the code for these is in <module>/qa/complex/. This should point you to some interesting UNO API method that is called on the C++ side in soffice.bin.

Now for debugging, this will start the office installation from the instdir inside of gdb:

make debugrun

First make the horrible gdb TUI go away with "C-x a", then set a breakpoint at the offending method, and run, and a start center should pop up.

Then you can run (in another terminal):

make gb_JunitTest_DEBUGRUN=T <module>.subsequentcheck

This will execute the test against the running <soffice>soffice.bin, and hopefully the breakpoint should be hit, and you can debug the problem from there.

Debugging the qadevOOo/unoapi subsequent tests

The qadevOOo/unoapi tests are somewhat tricky to debug.

If a test fails, then first you need to find out which method it complained about, open this file in a text editor:


At the end there is the following summary, pointing out the component test that failed:

Failures that appeared during scenario execution:
1 of 53 tests failed

Search for FAIL. This shows an error such as:

LOG> getCharacterBounds(6)
LOG> Text at this place:  
LOG> Character bounds outside component
LOG> Character rect: 43, -566, 0, 0
LOG> Component rect: 91, 2, 71, 18
Method getCharacterBounds() finished with state FAILED
LOG> getCharacterBounds(): PASSED.FAILED

If you scroll up a bit you see a line like this:

checking: [toolkit.AccessibleStatusBarItem::com::sun::star::accessibility::XAccessibleText] is iface: [] testcode: [ifc.accessibility._XAccessibleText]

Which points at the Java test code that is executed here, ifc.accessibility._XAccessibleText, corresponding to qadevOOo/tests/java/ifc/accessibility/ There is also a Java setup code specific to the tested component toolkit.AccessibleStatusBarItem in qadevOOo/tests/java/mod/_toolkit/

Now reduce the test a bit for faster testing: edit the corresponding scenario file, usually named <module>/qa/unoapi/<module>.sce, and remove everything except the one line that corresponds to the failing test, here AccessibleStatusBarItem, and check that it still fails:

Now the difficult part in this case is finding out where the failing method is implemented; often (e.g. in Writer) the class will be named almost the same as the tested component, but in this example checkCharacterBounds surprisingly it's not actually in the toolkit module, but git grep points at accessibility/source/standard/vclxaccessiblestatusbaritem.cxx, which contains a VCLXAccessibleStatusBarItem::getCharacterBounds method.

Once you have found out this information, proceed with make debugrun etc. as described in the previous section #Debugging the subsequent tests.

Searching for a memory corruption on Windows using DrMemory

If you have a crasher bug on Windows, and the stack trace is inside 'malloc' or 'free' or 'new' or 'delete' then most likely you have a memory corruption - often intermittent bugs are these too. For these cases, there is a wonder-new-tool (for Windows), called DrMemory; you get it here:

You need to install it and enable its insertion into your system path. Then either get a release build from TDF: or a daily build from the debug box TB39:

Then you'll need a console of some sort; as of now, in order to get anything sensible from the tool, you want to run:

drmemory -no_count_leaks -ignore_asserts -no_check_gdi -no_check_uninitialized -- soffice.exe

That means you get rather further, hopefully to the point where it crashes with your bug. Since the file-picker crashes drmemory itself, you'll need to use 'recent files' or the command-line to be able to load your document.

Expect it to be -really- slow; that's normal :-) but it is doing some clever things. Hopefully at the end of the day, your bug yields an:

Error #7: UNADDRESSABLE ACCESS: writing 0x2b9ca0f4-0x2b9ca0f8 4 byte(s)

error log, which is a serious error and a very helpful trace around it.

Running CppUnit tests with DrMemory

You can run any CppUnit test with DrMemory for tracking down uninitialized memory accesses and memory management bugs like this:

CPPUNITTRACE="drmemory -no_check_gdi -free_max_frames 30 -suppress C:/Users/xxx/drmemory-suppressions.txt" make CppunitTest_sw_uiwriter

Note that:

  • DrMemory tends to run out of memory itself and die while reporting the copious memory leaks in some of the bigger CppUnit tests in 32-bit builds; to avoid that use the arguments -no_count_leaks -no_check_handle_leaks .
  • DrMemory tends to grind to a halt (or at least, 2 hours of continuous CPU-time were observed with 1.9.0-4 before running out of patience) when running java.exe, which is spawned by several unit tests, notably CppunitTest_dbaccess_hsqldb_test and CppunitTest_dbaccess_RowSetClones and CppunitTest_services. To work around this problem, you can use -no_follow_children, or configure DrMemory to ignore java.exe by running drconfig.exe -quiet -reg java.exe -norun. (Strangely, the in-process jvm.dll is less problematic: millions of errors are produced, but they can easily be suppressed, as described below.)
  • DrMemory does not have an equivalent of valgind's memcheck's --track-origins=yes, so tracking down the root cause of uninitialized memory accesses often involves some additional work; in such cases try if you can reproduce the problem with valgrind on another platform to get a better stack trace.
  • DrMemory reports false positives in JPEG images imported by the SSE2 code in jpeg-turbo Unfortunately it may do so in places far away from the JPEG import filter, for example in CppunitTest_sw_globalfilter the UNINITIALIZED READ errors are reported when exporting the VCL Bitmap to a PNG. The work-around is to force jpeg-turbo to stop using SSE2 by setting an environment variable: export JSIMD_FORCEMMX=1.
  • DrMemory reports various other false positives than can be suppressed via the -suppress argument.

Here is a sample drmemory-suppressions.txt for false positives encountered when running the CppunitTests with DrMemory-1.9.0-4:

name=suppress all UA in java.exe

name=suppress all UR in java.exe

name=suppress all UA in jvm.dll

name=suppress all UR in jvm.dll

name=suppress all warning in jvm.dll

name=UA in JIT code from jvm.dll
<not in a module>

name=UR in JIT code from jvm.dll
<not in a module>

*!std::_Fac_node::`scalar deleting destructor'
*!std::`dynamic atexit destructor for '_Fac_tidy_reg

name= (input UR)
system call NtUserGetClipboardFormatName UNICODE_STRING.MaximumLength

name= (input UA)
system call NtUserGetClipboardFormatName UNICODE_STRING content

name= (output1)

name= (output2)

system call NtGdiAddFontResourceW parameter value #4


name=CPython custom allocator PyObject_Realloc

name=CPython custom allocator PyObject_Free

name=CPython custom allocator PyObject_Realloc

name=CPython custom allocator PyObject_Free

name=prefetching unaddressable memory in jpeg-turbo

Debugging C++ UNO life cycles

The reference count is stored as m_refCount, so e.g. break in the UNO object constructor and add a watch to it to see who takes shared ownership of the object.

(gdb) watch * (&m_refCount)


If acquire() and release() calls on an UNO service are not matched, the object will leak. There is a script that can parse gdb backtraces and try to balance acquire() and release() and sort them by how likely they are.

For usage hints see the comments at the top of bin/ in the core repository.

Beware that gdb takes a lot of time to print backtraces; 4000 backtraces take > 3 hours on a laptop with a current 15W TDP CPU.

Another disadvantage is that the result of the script requires some manual interpretation, but it can detect bare calls to acquire() that leak.

instrument uno::Reference

There is a patch on gerrit that adds a dummy memory allocation into every uno::Reference so that standard tools like valgrind and address sanitizer can detect when the uno::Reference itself is leaked.

This may be the easiest way to track down a leak, but the disadvantages are that it cannot detect bare acquire() calls and that instrumentation requires a full rebuild; also the added global lock may cause deadlocks with configmgr.

Note that the patch is currently incomplete and may not detect leaks from uno::Any and rtl::Reference (but that could be fixed).

Assertions and Logging

See Development/GeneralProgrammingGuidelines#Assertions and Logging.

Environment Variables

  • SAL_NO_MOUSEGRABS=1 prevents LibreOffice from grabbing the mouse during debugging on X11.

Macros Controlling Debug Code

  • The NDEBUG macro is the standard way to control the standard assert functionality. It is defined in plain production builds, left undefined for --enable-debug/--enable-dbgutil (note that defining it disables assertions).
  • The SAL_LOG_INFO and SAL_LOG_WARN macros control whether the SAL_INFO and SAL_WARN functionality, resp., from include/sal/log.hxx is activated. They are left undefined in plain production builds, defined for --enable-debug/--enable-dbgutil. If activated, their runtime behaviour is controlled by the SAL_LOG environment variable (see the documentation in include/sal/log.hxx for details).
  • The DBG_UTIL macro enables additional code that potentially affects ABI compatibility, changing public data structures. (So enabling it is an all-or-nothing decision; you generally cannot build just part of LibreOffice with this enabled. For historical reasons, it also controls the obsolete DBG_ASSERT etc. macros from include/tools/debug.hxx.) It is left undefined in production builds, and defined for --enable-dbgutil.
  • The _GLIBCXX_DEBUG macro enables helpful assertions in the libstdc++ STL implementation, which affect ABI compatiblity; it is also enabled by --enable-dbgutil on ELF based GCC platforms (TODO: this could work on all GCC platforms if only somebody tested it).
  • The OSL_DEBUG_LEVEL macro controls additional, potentially excessively expensive debug code (but which does not affect compatibility). It is defined as 0 in plain production builds, as 1 for --enable-debug/--enable-dbgutil (enabling the obsolete OSL_ASSERT etc. macros from include/osl/diagnose.h), and as 2 or higher with an explicit dbglevel=N argument to make.

Debugging Python components in LibreOffice

To debug the loading of python components, change the line DEBUG=0 in

To debug scripts using the Python Script Provider, set the variable PYSCRIPT_LOG_LEVEL=DEBUG and (optionally) PYSCRIPT_LOG_STDOUT=0 to redirect to the file $UserInstallation/Scripts/python/log.txt.

To see the method calls executed by the pyuno Python/UNO bridge, set the environment variables PYUNO_LOGLEVEL=ARGS and (optionally) PYUNO_LOGTARGET=mylogfile.

Debugging Java components in LibreOffice

If you want to debug the parts of LibreOffice that are implemented in Java, GDB may be less useful.

It may occasionally be useful to just get the Java level stack trace, like when there is a deadlock with Java code potentially involved; the jstack tool can print it, just give it the process id of soffice.bin as argument.

For actual debugging an IDE is most convenient (although there is also a command line debugger jdb); there is a description how to set things up for Eclipse and NetBeans on this OOo forum posting.