Development/How to debug

Debugging options
You need to enable debugging support to do any practical interactive debugging. You can enable it for the entire build with:

or

If you have done a non-debug build before, you need to run. If you later want to switch back to doing non-debug builds, you have to run the cleanup again.

Using  is like   and additionally it 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 macOS 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.

Note that a complete build with  or   for all modules takes a large amount of disk space. If you find this too much you can either use  to enable debugger symbols for just specific parts

or do a full non-debug build and then rebuild just the modules you are interested in:

Debugging with an IDE
See Development/IDE for how to setup various IDEs for debugging.

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 directly from the debugger.

In the following notes the  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 autogen.sh script is placed.

For gdb tools, graphical interfaces, tutorials and helpers, see the exhaustive list at cpplinks.

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:

If the attaching fails with "ptrace: Operation not permitted", do this:

Or edit /etc/sysctl.d/10-ptrace.conf and add  to permanently bypass this security restriction.

When you execute the launch script (soffice, swriter, …) you can pass the  option: it will suppress restart/restore after fatal errors.

For attaching and detaching a process from inside the gdb shell you can utilize the  and   commands, the latter doesn't need any argument.

After attaching to the  process gdb stops the program.

Start LibreOffice from the debugger (gdb)
The easiest way start LibreOffice from the gdb debuger is run command on the top-level:

The started  will listen on a named pipe, so you can even connect to it from another process via UNO), or run it directly:

It also works with MSVC, but it will only launch  and you have to attach the debugger manually from Visual Studio.

In-process JVM
The JVM will use segmentation violation signals to check for null pointer exceptions https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/signals.html - these signals do not indicate a crash in LO and happen multiple times when the JVM is initialised.

These signals can be ignored, but this will also ignore them if LibreOffice's C++ code crashes, so use with care.

(gdb) handle SIGSEGV nostop

Alternatively, disable JVM in ; it is only needed to debug a Java extension's interaction with LibreOffice.

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

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:, where 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 have been set up you can use the command:

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

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.

If you want gdb to set up as pending breakpoint any unknown symbol automatically without asking you every time, 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  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 :

add-auto-load-safe-path /path/to/your/lo/git # the path to your workdir and instdir

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.

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  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  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:

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:

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

Finally you can start DDD with the  command.

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

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  and modify the   property. In order to make your custumizations permanent you have to check the  entry in the   menu.

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

By  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  dialog box using the entry with the same name under the   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  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  (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  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  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  entry.

The  button will print the value of the symbol you entered in the edit field to the gdb shell, for more complex values the   button will show the symbol value graphically in the   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  menu. Each data box displayed in the Data Window is called a. 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  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  property to on (by default is set to auto, you can perform that by executing the   command in the GDB Console or by checking the related option in the   dialog.

Now by the  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  dialog  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  command in the GDB Console or check the   entry in the   dialog

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

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.

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.

Finding a stacktrace of an "ignored" C++ exception
Say your debug build is giving you

warn:linguistic:67283:363302:linguistic/source/gciterator.cxx:679: GrammarCheckingIterator::DequeueAndCheck ignoring N3com3sun4star3uno9ExceptionE msg: C++ code threw St13runtime_error: collate_byname ::collate_byname failed to construct for

and you would like a stacktrace for the exception. The line number above is in a part of the code that catches all exceptions, but we want a stack trace for that std::runtime_error. What we can do is


 * 1) add a breakpoint at the start of the   block, in this case line 608
 * 2) once we've broken there, delete that breakpoint and instead add one for all C++ exceptions
 * 3) continue until we get a C++ exception, then print the backtrace (possibly repeating until we hit the right one)

To do this, first start the lldb debugger (in $LODE_HOME/dev/core if you checked out through lode) with

make debugrun

then when lldb has started, add the initial break point and start the program

then remove that breakpoint and start breaking on all C++ exceptions:

Debugging with WinDbg or Visual Studio (on Windows)
Debugging with Visual Studio is extremely simple, only a debug build is needed, no need to use IDE integration. Simply open the source file of interest in Visual Studio, add a breakpoint, start, and attach debugger to   via. Execution will halt when the breakpoint is hit (to stop execution immediately, use ). Visual Studio opens the source files for the executed code automatically during debugging. Call stack is available in the window with the same name.

Enhancing your debugging experience with Visual Studio
There's lots of configuration options around Visual Studio can will improve your experience and productivity. Most notable are the native visualizers. There is a custom .natvis file in /solenv/vs, which allows to visualize objects of some classes used in LO code easier. The contents of the file is embedded into PDBs for debug builds, so debugging makes use of the visualizers even when one doesn't use IDE integration (generated solution files). Please add your useful additions to the visualizers to that file, and submit patches :)

Also helpful: preventing to step into functions that are trivial one-lines, like the operator-> for smart pointers. Here's the howto: [https://stackoverflow.com/questions/40488311/visual-studio-2015-how-to-not-step-in-certain-functions How to *not* step in certain functions? (Stack Overflow)]

It's often useful to *disable* "Just My Code" feature of Visual Studio debugger: Options->Debugger->General; locate and uncheck the "Enable Just My Code" item. Otherwise, call stacks would be incomplete and unhelpful.

Debugging release builds
In Visual Studio, the call stacks may at first appear useless; to avoid this, enable the Microsoft Symbol Server in the configuration: 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.

Registering a build as the COM server provider
If you have to debug the COM component process, you can register your build as the COM server provider using the following script:

The path argument to the bat file has to be a Windows path, so if you call it from the cygwin shell, you need to use something like cygpath -w -a -l ./instdir/program/soffice.exe.

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  environment variable to run the build tool in strace, valgrind or a debugger:

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

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:

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 macOS you no longer have access to gdb which has been replaced by lldb. However you can still use CPPUNITTRACE through

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.

You can run a specific test case method inside the CppUnit make target (which normally has lots of individual test case methods) using

Debugging cppunit tests with strace
If gdb backtraces are not helpful, you can try an strace with

The -s parameter increases the character limit to 77

Debugging perfcheck and other cppunit tests that run 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

and in the gdb prompt

Debugging executables
LibreOffice has a number of bundled demo executables in the VCL module. To debug these, you first set the LOTRACE environment variable to point to your debugger. On Linux, this is:

On Windows you can start the executable in Visual studio with:

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 macOS you no longer have access to gdb which has been replaced by lldb. However you can still use LOTRACE through

To run the app, you use the bin/run script:

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

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

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

Running the subsequent tests
A top-level  will first do a full build, then run all the subsequent tests, while a top-level   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/Module_foo.mk), e.g. . The   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:

workdir/JunitTest/ _/done.log

The log file will contain a Java stack trace of the failed test, and if the  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, and the code for these is in. This should point you to some interesting UNO API method that is called on the C++ side in.

Now for debugging, this will start the office installation from the 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 .subsequentcheck

This will execute the test against the running 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:

workdir/JunitTest/ _unoapi/done.log

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

Search for FAIL. This shows an error such as:

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

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

Which points at the Java test code that is executed here,, corresponding to.

There is also a Java setup code specific to the tested component  in.

Now reduce the test a bit for faster testing: edit the corresponding scenario file, usually named, and remove everything except the one line that corresponds to the failing test, here  , 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 surprisingly it's not actually in the toolkit module, but  points at  , which contains a  method.

Once you have found out this information, proceed with  etc. as described in the previous section.

Debugging with rr
rr works fine to debug LibreOffice, even with fancy stuff like in-process JVM. Note that rr currently requires Linux and a recent Intel CPU.

To record LO itself, use:

rr record instdir/program/soffice

(Note: To avoid crashes when using rr versions up to 5.3.0 with recent libc++ versions, setting environment variable  (s. the section) might help as a workaround (fixed in https://github.com/mozilla/rr/commit/862605a8d4abca6d28d2296ccc6d6148ffc93ff6 ).

To replay, you want to start with the soffice.bin process:

rr replay -p $(rr ps | grep soffice.bin | cut -f 1 | tail -n 1)

On current master towards libreoffice-6-2, all tests (CppUnitTest, JUnitTest, PythonTest, UITest) can be recorded by setting the environment variable. This requires ~35GB of storage per  run.

There was some success with getting Eclipse CDT 9.4.3 to use rr as the debugger, following the instructions in the rr documentation, using a Debug Configuration derived from "C/C++ Application" (and with the full path to soffice.bin in the Application field), but with this slightly enhanced rrgdb wrapper script:

In order for Qt Creator (tested with 4.10 release candidate) to find debug info, the sysroot for GDB needs to be explicitly set, which can e.g. be achieved by adding the following line in "Tools" -> "Options" -> "Debugger" -> "GDB" -> "Additional Startup Commands":

set sysroot /

Then follow the instructions in the rr documentation.

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: http://www.drmemory.org/

You need to install it and enable its insertion into your system path. Then either get a release build from TDF: https://download.documentfoundation.org/libreoffice/stable/ or a daily build from the debug box TB39: https://dev-builds.libreoffice.org/daily/master/Win-x86@39/

Then you need to rename the file soffice.bin to soffice.exe in the LibreOffice's program/ directory. The original soffice.exe is just a trivial wrapper binary.

Finally you'll need a console of some sort; as of now, in order to get anything sensible from the tool, you want to run the following from inside LibreOffice's program/ directory:

drmemory -no_count_leaks -ignore_asserts -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.


 * 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, 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  , or configure DrMemory to ignore   by running  . (Strangely, the in-process   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, 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 https://github.com/DynamoRIO/drmemory/issues/540. 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:.


 * DrMemory reports various other false positives than can be suppressed via the  argument.

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

UNADDRESSABLE ACCESS name=suppress all UA in java.exe java.exe!* UNINITIALIZED READ name=suppress all UR in java.exe java.exe!* UNADDRESSABLE ACCESS name=suppress all UA in jvm.dll jvm.dll!* UNINITIALIZED READ name=suppress all UR in jvm.dll jvm.dll!* WARNING name=suppress all warning in jvm.dll jvm.dll!* UNADDRESSABLE ACCESS name=UA in JIT code from jvm.dll ... jvm.dll!* UNINITIALIZED READ name=UR in JIT code from jvm.dll ... jvm.dll!* INVALID HEAP ARGUMENT name=https://connect.microsoft.com/VisualStudio/feedback/details/750951/std-locale-implementation-in-crt-assumes-all-facets-to-be-allocated-on-crt-heap-and-crashes-in-destructor-in-debug-mode-if-a-facet-was-allocated-by-a-custom-allocator drmemorylib.dll!replace_free *!std::_DebugHeapDelete<> *!std::_Fac_node::~_Fac_node *!std::_Fac_node::`scalar deleting destructor' *!std::_DebugHeapDelete<> *!std::_Fac_tidy_reg_t::~_Fac_tidy_reg_t *!std::`dynamic atexit destructor for '_Fac_tidy_reg'' *!_CRT_INIT *!__DllMainCRTStartup *!_DllMainCRTStartup ntdll.dll!RtlQueryEnvironmentVariable ntdll.dll!LdrShutdownProcess ntdll.dll!RtlExitUserProcess KERNEL32.dll!ExitProcess UNINITIALIZED READ name=https://github.com/DynamoRIO/drmemory/issues/1824 (input UR) system call NtUserGetClipboardFormatName UNICODE_STRING.MaximumLength sysdtrans.dll!CDataFormatTranslator::getClipboardFormatName UNADDRESSABLE ACCESS name=https://github.com/DynamoRIO/drmemory/issues/1824 (input UA) system call NtUserGetClipboardFormatName UNICODE_STRING content sysdtrans.dll!CDataFormatTranslator::getClipboardFormatName UNINITIALIZED READ name=https://github.com/DynamoRIO/drmemory/issues/1824 (output1) sal3.dll!* sal3.dll!rtl_ustr_compareIgnoreAsciiCase_WithLength ftransl.dll!rtl::OUString::equalsIgnoreAsciiCase ftransl.dll!CDataFormatTranslator::findDataFlavorForNativeFormatName ftransl.dll!CDataFormatTranslator::getDataFlavorFromSystemDataType sysdtrans.dll!CDataFormatTranslator::getDataFlavorFromFormatEtc sysdtrans.dll!CDOTransferable::formatEtcToDataFlavor sysdtrans.dll!CDOTransferable::initFlavorList sysdtrans.dll!CDTransObjFactory::createTransferableFromDataObj UNINITIALIZED READ name=https://github.com/DynamoRIO/drmemory/issues/1824 (output2) sal3.dll!rtl::compareIgnoreAsciiCase sal3.dll!rtl_ustr_compareIgnoreAsciiCase_WithLength sysdtrans.dll!rtl::OUString::equalsIgnoreAsciiCase sysdtrans.dll!CDataFormatTranslator::isTextHtmlFormat UNINITIALIZED READ name=https://github.com/DynamoRIO/drmemory/issues/1825 system call NtGdiAddFontResourceW parameter value #4 GDI32.dll!GdiAddFontResourceW GDI32.dll!AddFontResourceExW vcllo.dll!ImplAddTempFont vcllo.dll!WinSalGraphics::AddTempDevFont vcllo.dll!OutputDevice::AddTempDevFont UNINITIALIZED READ name=https://github.com/DynamoRIO/drmemory/issues/1827 * KERNELBASE.dll!WaitNamedPipeW sal3.dll!osl_createPipe UNINITIALIZED READ name=CPython custom allocator PyObject_Realloc python??_d.dll!PyObject_Realloc UNINITIALIZED READ name=CPython custom allocator PyObject_Free python??_d.dll!PyObject_Free UNINITIALIZED READ name=CPython custom allocator PyObject_Realloc python??.dll!PyObject_Realloc UNINITIALIZED READ name=CPython custom allocator PyObject_Free python??.dll!PyObject_Free WARNING name=prefetching unaddressable memory in jpeg-turbo vcllo.dll!jsimd_idct_islow_sse2 vcllo.dll!jsimd_idct_islow vcllo.dll!decompress_data

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)

bin/refcount_leak.py
If  and   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  and   and sort them by how likely they are.

For usage hints see the comments at the top of  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  that leak.

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

This may be the easiest way to track down a leak, but the disadvantages are that it cannot detect bare  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.

Environment Variables

 * disable recovery of corrupted documents on startup.
 * exit immediately after opening document. Useful for debugging open performance.
 * disable use of OpenGL
 * disable use of OpenCL in calc.
 * prevents LibreOffice from grabbing the mouse during debugging on X11.
 * makes the random number generator start from a fixed seed, which makes tests that use random numbers predictable.
 * force the use of a specific VCL UI backend.

Macros Controlling Debug Code

 * The  macro is the standard way to control the standard   functionality.  It is defined in plain production builds, left undefined for  /  (note that defining it disables assertions).


 * The  and   macros control whether the   and   functionality, resp., from   is activated.  They are left undefined in plain production builds, defined for  / .  If activated, their runtime behaviour is controlled by the   environment variable (see the documentation in   for details).

To enable  and   for   component type:

export SAL_LOG="+INFO.sw.ww8+WARN"


 * The  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   etc. macros from  .)  It is left undefined in production builds, and defined for.


 * The  macro enables helpful assertions in the libstdc++ STL implementation, which affect ABI compatiblity; it is also enabled by   on ELF based GCC platforms (TODO: this could work on all GCC platforms if only somebody tested it).


 * The  macro controls additional, potentially excessively expensive debug code (but which does not affect compatibility).  It is defined as   in plain production builds, as   for  /  (enabling the obsolete   etc. macros from  ), and as   or higher with an explicit   argument to.

Debugging Python components in LibreOffice
To debug the loading of python components, change the line  in.

To debug scripts using the Python Script Provider, set the variable  and (optionally)   to redirect to the file.

To see the method calls executed by the  Python/UNO bridge, set the environment variables   and (optionally).

When starting soffice in a terminal, pdb can be used as a python-level debugger; to invoke it and effectively set a breakpoint, add this line in an appropriate place in your python code, typically during initialisation:

import pdb; pdb.set_trace

Another option is to use gdb for debugging, which can load a custom pretty-printing file that matches the python library that is used by LO. Then commands such as,  ,  ,  ,  ,  ,   become available at the gdb prompt, in addition to gdb's own C++ debugging commands. See documentation at.

For the python that is bundled with LO, gdb debugging is enabled by ; if LO is built against a system python, the file might be in some non-obvious place; on Fedora 29 it can be installed with

.

Debugging memory leaks with valgrind (including ref-count leaks)
Say you know that a given unit test is leaking.

Then Run a unit test like this:

$ make CppunitTest_cppcanvas_test VALGRIND='memcheck --vgdb=yes --vgdb-error=0 --leak-check=full --suppressions=$$BUILDDIR/solenv/sanitizers/valgrind-suppressions'

then in another terminal do

$ gdb workdir/LinkTarget/Executable/cppunittester

and once that gdb comes, enter the command

(gdb) target remote | vgdb

now you can execute commands like setting breakpoint, or continue, and it will control the program running in the other terminal

Most usefully, you can set a breakpoint at a location like

(gdb) br cppunittester.cxx:473

which is just after the unit test has finished, and then you can set a breakpoint at the constructor of the object you are interested in, like

(gdb) br MyObject::MyObject

then take note of the hex value of the "this" pointer when the breakpoint triggers. Then when the end-of-unit-test breakpoint triggers, valgrind can tell you who is still harbouring a pointer to the object you are interested in with:

(gdb) monitor who_points_at 0xegegegeg

For a summary of the available valgrind memcheck debugging commands, see Memcheck Monitor Commands.

Debugging Java components in LibreOffice
If you want to debug the parts of LibreOffice that are implemented in Java, GDB is not useful as it currently does not support Java as Java runs in it's own virtual machine.

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  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 ). To get this set up, you have to use remote Java debugging in eclipse for example.

Preparing LibreOffice to enable Debugging
To enable the Java Virtual Machine to be debugged, you start LibreOffice normally and enable the debugging by adding the jvm version you use to the Tools settings currently under Tools > LibreOfficeDev > Advanced and add the following parameters:

the first of the two enables debugging, the second sets the port of the Virtual Machine, if you enable suspend (writing suspend=y instead of suspend=n) the Machine is halted until a debugger attaches to it which can be used to debug the starting progress of the jvm.

Preparing Eclipse for Debugging
In Eclipse, make sure you opened the libreoffice folder as a Java Project, then you can add a debug configuration of the type Remote Java Application This debug configuration should have:

the Connection type: Standard (socket attach)

and the Connection Properties:

Host:

Port:

This port should be the same as the one you prepared inside Libreoffice. If you then start the module that is in Java, and during that starting progress start the debugging configuration you should find it working at stopping at your breakpoints.

Performance debugging (Callgrind)
Callgrind is the most commonly used tool for searching for performance issues. See the following for instructions:


 * 1) How to get a Callgrind trace
 * 2) Video about using Callgrind with KCachegrind for profiling.

Visualize results
To visualize results KCachegrind could be used.
 * 1) Turn off cycle detection. The results are often nearly meaningless for non-trivial cases.
 * 2) Turn off the 'Relative' button and use absolute cycle counts everywhere or it is very easy to lose a sense of proportion.
 * 3) Check all counts vs. the total in the bottom status bar for sanity.

For an alternative way to look at the results, you could try gprof2dot.

Performance debugging (perf)
The linux kernel profiler (perf) produces less detailed output than callgrind, but is much cheaper to run (since it's a sampling profiler). With callgrind or perf, you should not use a debug build, but one built with --enable-symbols.

You may need extra permissions ie.

sudo sh -c "echo 0 > /proc/sys/kernel/kptr_restrict"

or also:

sudo sh -c 'echo 1 >/proc/sys/kernel/perf_event_paranoid'

in order to use kernel symbols in the output.

Use

perf record -g --pid=`pidof soffice.bin`

to capture data, and then

perf report

to see the output.

For a really nice visualization of the result, install FlameGraph by doing:

git clone https://github.com/brendangregg/FlameGraph

and then running

Or install KDAB Hotspot for a nice GUI.

You can export a flamegraph from Hotspot via. Formats available are BMP and SVG.

If you find that the resulting data is too coarse, there are two options


 * Capture data for a longer period of time, perhaps by performing the action more than once
 * Increase the profiler sampling frequency e.g.

perf record -g -F 10000 --pid=`pidof soffice.bin`

If you find that parts of the call stacks are missing, you may need to increase the size of the stack capture with:

perf record --call-graph dwarf,65528 --pid=`pidof soffice.bin`