Entwicklung/Fehlersuche
TDF LibreOffice Document Liberation Project Community Blogs Weblate Nextcloud Redmine Ask LibreOffice Spende
Optionen zur Fehlersuche
Debugging-Unterstützung muss eingeschaltet sein, um effektiv interaktiv Fehlersuche betreiben zu können. Sie kann für den gesamten Prozess wie folgt aktiviert werden:
./autogen.sh --enable-debug
oder
./autogen.sh --enable-dbgutil
Falls zuvor ein nicht debug-fähiger Build gelaufen ist, muss erst ein make clean laufen. Wenn später wieder auf nicht-debug zurückgeswitched werden soll, muss das Cleanup erneut laufen.
--enable-dbgutil hat den gleichen Effekt wie --enable-debug. Zusätzlich liefert es mehr oder weniger nützliche Informationen und zusätzlichen Debugging-Code. Ebenso unterstützen es der STL-Debugging Modus von libstdc++ auf einigen GCC basierten Systemen (außer macOS, weil Apples libstdc++ den Support nicht bietet, außerdem scheint clang libc++ keinen Debug-Modus zu haben) und nutzt die Debug-Umgebung (inklusive debug STL) von MSVC. Es ist ebenfalls nicht möglich, Code mit und ohne --enable-dbgutil zu mischen.
Ein kompletter build mit --enable-debug oder --enable-dbgutil für alle Module erfordert viel Plattenspeicher.
Wenn das zu viel sein sollte, kann alternativ --enable-symbols für bestimmte Teile verwendet werden
./autogen.sh --enable-dbgutil --enable-symbols="sw/ sc/ xmloff/"
oder nach einem kompletten Release-Build werden nur die Teile debug-fähig übersetzt, die gerade relevant sind:
make <module>.clean && make <module> debug=t
Fehlersuche mit einer IDE
Siehe unter Development/IDE, wie verschiedene IDEs zur Fehlersuche eingesetzt werden können.
Fehlersuche mit gdb
Es gibt zwei Methoden: LibreOffice wird mit dem zugehörigen Skript (soffice, swriter, usw.) gestartet und dann wird der Debugger dem LibreOffice Prozess zugeordnet. Oder der LibreOffice Binärcode (soffice.bin) wird direkt im Debugger gestartet.
Im Folgenden wird die Variable $LOROOT auf den Pfad zu dem Verzeichnis gesetzt, in dem die Quellen aus dem GIT Repository liegen. Dies ist der Pfad zu dem Verzeichnis, in dem das Skript autogen.sh liegt.
Zu gdb-Tools, grafischen Benutzeroberflächen, Tutorials und Hilfsprogrammen siehe die erschöpfende Liste der CPP-Links.
Mit dem Prozess soffice.bin verbinden
Es ist recht einfach, weil sich das Skript zu soffice selbst um alle benötigten Umgebungsvariablen kümmert:
$ instdir/program/soffice # oder /sdraw /swriter ...
$ gdb --pid=$(pidof soffice.bin)
(gdb)
Wenn die Verbindung mit der Meldung "ptrace: Operation not permitted" fehlschlägt, sollte folgendes unternommen werden:
sudo su -
echo 0 > /proc/sys/kernel/yama/ptrace_scope
Oder /etc/sysctl.d/10-ptrace.conf wird bearbeitet und kernel.yama.ptrace_scope = 0 hinzugefügt, um die Sicherheitsbeschränkung dauerhaft zu umgehen.
Bei der Ausführung des Startskriptes (soffice, swriter, …) kann die Option -norestore genutzt werden: sie unterdrückt den Neustart nach gravierenden Fehlern.
Um einen Prozess innerhalb des gdb zu verbinden oder zu trennen, werden die Kommandos attach <pid> und detach verwendet. Der letztere braucht kein Argument.
Nachdem soffice.bin verbunden wurde, stoppt gdb das Programm.
LibreOffice im Debugger (GDB) starten
Der einfachste Weg, LibreOffice aus dem GDB-Debugger zu starten, ist das Kommando run auf oberster Ebene:
make debugrun
Die laufende soffice.bin wird den genannten Kanal überprüfen. So kann sie sogar aus einem anderen Prozess aus über UNO) aufgerufen werden oder direkt gestartet werden:
(gdb) run --writer
(gdb) run --calc
Arbeitet auch mit MSVC. Der startet aber nur soffice.bin. Der Debugger muss manuell über das Visual Studio verbunden werden.
prozessinterne JVM
Die JVM verwendet segmentation violation signals zur Überprüfung von null pointer exceptions https://docs.oracle.com/javase/7/docs/webnotes/tsg/TSG-VM/html/signals.html - Diese Meldungen zeigen keine Abstürze von LO an und können bei der Initialisierung der JVM öfter vorkommen.
Diese Meldungen können ignoriert werden. Dann werden aber auch Abstürze im LibreOffice C++ Code ignoriert. Deshalb ist es mit Vorsicht zu geniessen.
(gdb) handle SIGSEGV nostop
Alternativ kann die JVM unter ▸ ▸ ▸ abgeschaltet werden. Sie wird sowieso nur gebraucht, wenn die Verbindung zwischen LibreOffice und einer Extension debugt werden soll.
Ein GDB-Starter
Sobald das Programm gestoppt wurde, kann nach Symbolen gesucht werden. Dazu werden die Daten beachtet und Breakpoints gesetzt:
(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:
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.
Jetzt ist ein Breakpoint an der genannten Stelle gesetzt. Der Methoden-Name muss dabei voll qualifiziert inklusive Klassenname und des Namespaces sein.
Die allgemeine Syntax lautet: break <location>, wobei <location> ein voll qualifizierter Funktions- oder Methodenname sein kann, eine Speicheradresse oder ein Dateiname gefolgt von einem ":" und einer Zeilennummer. Für weitere Informationen zum Location-Konzept siehe die gdb-Handbuch Seite: Specifying a Location
Zur Auflistung der gesetzten Breakpoints wird folgendes Kommando verwendet:
(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
Zum Entfernen eines Breakpoints wird einer der folgenden Kommandos verwendet:
clear <location>
delete <breakpoint number>
schwebende Breakpoints
Wenn ein angegebenes Symbol zu einer noch nicht geladenen geteilten Library gehört, kann trotzdem ein Breakpoint zu dem Symbol gesetzt werden. gdb setzt einen sogenannten schwebenden Breakpoint der aktiviert wird, sobald das Symbol ansprechbar ist.
(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
Wenn GDB irgendein Symbol automatisch als schwebenden Breakpoint setzen soll, ohne jedesmal nachzufragen, wird folgendes Kommando verwendet:
set breakpoint pending on
um zum Standard-Verhalten zurückzukommen, wird auf "auto" gesetzt.
Bei einer Fehlersuche mit schwebenden Breakpoints braucht man immer den voll qualifizierten Funktions- bzw. Methodennamen: das Kommando info fun hilft dabei auch nicht viel, weil die Symbole im System immer noch nicht bekannt sind. Eine mögliche Lösung bringen die Shared Object Ereignisse.
Texte o. ä. protokollieren
Dank der Magie der gdb pretty printers ab gdb 7 aufwärts protokolliert print string den Inhalt von Zeichenketten unabhängig davon, ob es sich um UTF-16 rtl::OUString oder 8-bit rtl-OString handelt. Es gibt einen pretty printer Support zum vernünftigen Protokoll für viele andere Objekte als Zeichenketten wie z. Bsp. Any, Sequence, Date, Time, etc. Wenn die Struktur nicht-pretty-printed benötigt wird, wird print/r (or p/r) verwendet. Der Pretty Printer wird bei einem eingebauten Debugging und bei einem Start vom instdir automatisch aktiviert.
Hinweis: Wenn pretty printers nicht hervorragend funktionieren, verhindert wahrscheinlich eine GDB Sicherheitseinstellung das Laden. Dann wird eine Fehlermeldung über den "safe-path" ausgegeben. Um das Problem zu vermeiden, wird folgendes der Config-Datei $HOME/.gdbinit hinzugefügt:
add-auto-load-safe-path /path/to/your/lo/git # der Pfad zum Arbeitspfad und zum Installationspfad
Hinweis: Apple GDB ist antik und unterstützt keine Python pretty-printers.
STL Container protokollieren
GDB kann auch die Inhalte von STL-Containern protokollieren, was sehr nützlich sein kann.
Ein Shared Object Ereignis findet immer dann statt, wenn eine Shared Library geladen oder entladen wird. Standardmäßig sind sie nicht aktiviert. Sie können mit folgendem Komando aktiviert werden:
set stop-on-solib-events 1
Jetzt wird das Programm jedesmal angehalten, wenn eine Shared Library geladen wird und es kann nach neuen Symbolen gesucht und Breakpoints gesetzt werden.
Die Shared Objekt Ereignisse sollten nur aktiviert werden, wenn die Shared Librarty relativ zügig geladen wird. Ansonsten muss das continue-Kommando sehr oft gegeben werden, was auf Dauer recht nervig werden kann.
Ob eine Shared Library geladen wurde, lässt sich mit dem Kommando info shared <reg expr> feststellen. Dieses Kommando listet alle geladenen Shared Libraries auf, die dem regulären Ausdruck entsprechen.
UNO debuggen
Folgendes Skript liefert den tatsächlichen Typ einer UNO-Referenz:
(gdb) print *rShape._pInterface
$1 = {_vptr.XInterface = 0x2aaac99f9728 <vtable for SvxShapeText+648>}
(gdb) print rShape._pInterface
$2 = (com::sun::star::uno::XInterface *) 0x2313e9
diverse Helfer
Einige gdb-Extensions, die in gewissen Fällen nützlich sein können.
- info mutex: zeigt an, welche Threads mutex nutzen
- fcatch: stoppt, wenn eine Exception geworfen wird, aber nur, wenn eine bestimmte Funktion betroffen ist
Fehlersuche mit DDD (einem gdb Front-End)
Soll der Debugger zum Prozess soffice.bin verbunden werden, muss LibreOffice gestartet werden:
$ cd $LOROOT/install/program
$ ./soffice # oder ./swriter, ./simpress, ...
Soll LibreOffice direkt aus dem Debugger gestartet werden, müssen auf alle Fälle erst mal die Ungebungsvariablen ermittelt werden:
$ cd $LOROOT/install/program
$ source ./ooenv
Schließlich kann DDD mit dem Kommando ddd gestartet werden.
In beiden Fällen muss das Programm zum Debuggen über einen Klick auf den Eintrag im Menü gestartet werden. Ein Datei Dialog poppt auf: hier wird die ausführbare Datei soffice.bin ausgewählt, die sich in $LOROOT/install/program befindet. Falls LibreOffice bereits läuft muss es dem Prozess soffice.bin hinzugefügt werden: das passiert über den Menüeintrag ▸ . Eine Liste aller laufenden Prozesse wird über einen Doppelklick auf den Prozess soffice.bin (er sollte bereits ausgewählt sein) angezeigt. Auf dem selben Weg wird der Prozess über das Kommando ▸ entfernt.
Nachdem das Programm zum Prozess hinzugefügt wurde, wird es gestoppt und kann debuggt werden. Die Box Kommando Tool öffnet automatisch und bietet ein ganzes Set an Aktionen zur Wiederaufnahme der Ausführung und zur schrittweisen Weiterführung des Programms. Unten im DDD-Fenster befindet sich die GDB Konsole: eine Shell, in der direkt gdb Kommandos ausgeführt werden können. Über der GDB Konsole befindet sich das Quell Fenster. Dort wird der Quelltext angezeigt.
Um Schriftart unhd -größe der GDB Konsole und dem Quellfenster zu ändern gehe man ins Menü ▸ ▸ und ändere die Einstellung .Um die Änderung permanent zu machen wird der Eintrag im Menü gesetzt.
LibreOffice wird aus dem Debugger mit einem Klick auf den Button Run (in der floating Command Tool box) gestartet. Oder mit dem Kommando run oder start direkt in der GDB Konsole. Hier können auch Kommandozeilenargumente an das Programm übergeben werden.
Über das Menü ▸ wird ein Dialog geöffnet, der eine Sequenz von Funktionsaufrufen zeigt: sie starten mit dem Aufruf der Hauptfunktion bis zum letzten Funktionsaufruf: derjenige, mit dem das Programm endete. Bei Auswahl eines Funktionaufrufs wird der zugehörige Quelltext im Quellfenster angezeigt (wenn die Quelldatei gefunden wird). Ein großer Pfeil auf der linken Seite zeigt auf die aktuelle Stelle. Wenn Sie den Ablauf eines anderen Threads untersuchen wollen, öffnen Sie den Dialog Thread mit dem gleichen Namen im Menü .
Unter dem DDD Menü ist ein Eingabefeld mit mehreren Buttons auf der rechten Seite. Für jeden dieser Buttons gibt es eine Aktion, die jedesmal zusammen mit dem Text im Edit Field ausgeführt wird, wenn der Button betätigt wird. Wenn im Edit Field ein voll qualifizierter Variablenname steht und der Button Lookup betätigt wird, erscheint die Quelldatei, die die Variable definiert, im Quellfenster. Bei irgendeinem Text im Edit Field und dem Button Find>> (forward) wird die aktuell angezeigte Quelldatei vorwärts nach dem Text durchsucht.
Wenn die Variable im Edit Field eine gültige Variable im Code ist, wird der Klick auf den Break Button einen Breakpoint im Code setzen. Ein Blick in die Quelldatei zeigt, dass ein kleines "Stoppschild" links neben der Zeile erscheint, in der die Variable definiert wird. Damit wird angezeigt, dass hier ein Breakpoint gesetzt wurde. Ein Rechtsklick darauf öffnet ein Kontextmenü mit mehreren Optionen. Auf dem selben Weg setzt der Watch Button einen Beobachtungspunkt für die angegebene Variable. Eine andere Möglichkeit, einen Breakpoint zu setzen, ist ein Rechtsklick auf die Code-Zeile im Quellfenster und hier den Eintrag Set Breakpoint auszuwählen.
Der Print Button gibt den Wert der Variable im Edit Field der GDB Shell an. Für komplexere Werte gibt der Display Button den Wert der Variablen grafisch im Data Window aus, das sich automatisch über dem Quellfenster öffnet. Wenn man mit der Maus auf eine Variable im Quellfenster zeigt, wird sein Wert automatisch in einem kleinen Quickinfo Fenster über dem Quellfenster angezeigt. Im Datenfenster können alle lokalen Variablen und die Argumente aus dem aktuellen Funktionsaufruf angezeigt werden: um sie anzuzeigen, werden sie im relevanten Data Menü ausgewählt. Jede im Datenfenster angezeigte Daten Box wird Display genannt. Sie kann beliebig im Datenfenster verschoben werden. Zusätzlich erscheint bei einem Rechtsklick darauf ein Kontextmenü, das mehrere Einträge anbietet.
schwebende Breakpoints
Schwebende Breakpoints werden im DDD nicht unterstützt. Sogar wenn ein break <yet unknown symbol> direkt in der GDB-Konsole ausgeführt wird, poppt keine Frage auf, ob ein schwebender Breakpoint gesetzt werden soll. Ein Workaround wäre, die breakpoint pending manuell einzuschalten. Diese stehen standardmäßig auf auto, über das Kommando set breakpoint pending on in der GDB-Konsole oder über den GDB Settings Dialog ( ▸ ) können diese eingeschaltet werden.
Mit dem Break Button kann jeder gültige Text als Breakpoint (schwebend oder nicht) gesetzt werden. Aber Vorsicht! Es gibt einen tricky Haken. Der erste nicht-schwebende Breakpoint, der nach einem schwebenden gesetzt wird, wird durch die nachfolgenden Breakpoints ausgegraut. Im Breackpoints Dialog ( ▸ ) können die nicht-schwebenden Breakpoints nicht gelöscht werden und die Merkmale können nicht verändert werden. Jede Aktion, die auf einem nicht-schwebenden Breakpoint ausgeführt wird, wird auf dem schwebenden ausgeführt. Das gilt auch für Aktionen aus dem Kontextmenü im Quellfenster.
Fallen Sie aber nicht darauf rein, hier geht es nur um ein DDD-Frontend: auch wenn er ausgegraut ist, ist der schwebende Breakpoint aktiv. Das Programm wird hier angehalten und kann über die GDB-Konsole bearbeitet werden. Wenn der schwebende Breakpoint gelöscht wird, kann der nicht-schwebende durch das DDD-Frontend auch bearbeitet werden.
Shared Object Ereignisse werden über das Kommando set stop-on-solib-events 1 in der GDB Konsole oder dem Eintrag Stopping for Shared Library Events im Dialog GDB Settings ( ▸ ) aktiviert.
Öffnen der Quelldateien
Die Quelldateien können über den Dialog Open Source gesucht werden: hier, im Eingabfeld kann ein Text, z. Bsp.: "*main*" (Globbing-Regeln werden berücksichtigt) eingegeben werden, und jeder Quelltext mit einer bekannten Variablen wird gegen den Text geprüft. Dazu wird der Filter Button unten verwendet. Weitere Infos zum Open Source Dialog gibt es unter dem Help Button.
Fehlersuche mit LLDB
Falls Sie z. Bsp. als mac-User kein GDB verfügbar haben, nutzen Sie bitte LLDB.
Die Kommandos in GDB und LLDB sind unterschiedlich.
Es gibt einen hilfreichen Phython Pretty Printer der manuell geladen werden kann, um OUStrings etc. anzuzeigen. Siehe unter solenv/lldb/libreoffice/LO.py.,
Unglücklicherweise hat zumindest Apples LLDB offensichtlich die unschöne Angewohnheit, Kommandozeilenbefehle abzuschneiden. Daher können CPP-UnitTests auf dem üblichen Wege mit einer Exception des cppuhelper::ServiceManager::readRdbFile abbrechen.
Den Stacktrace einer "ignorierten" CPP-Exception finden
Angenommen, das Programm gibt folgendes zurück
warn:linguistic:67283:363302:linguistic/source/gciterator.cxx:679: GrammarCheckingIterator::DequeueAndCheck ignoring N3com3sun4star3uno9ExceptionE msg: C++ code threw St13runtime_error: collate_byname<char>::collate_byname failed to construct for
und wir brauchen einen Stacktrace für die Exception. Die obige Zeilennummer liegt in einem Codebererich, der alle Exceptions fängt. Aber wir brauchen den Stacktrace genau dieses std::runtime_error. Was gemacht werden kann, ist folgendes:
- einen Breakpoint am Anfang des try-Blocks setzen, in diesem Fall in Zeile 608
- wenn das Programm trotzdem noch abbricht, wird dieser Breakpoint gelöscht und ein neuer für alle C++-Exceptions gesetzt.
- fortfahren, bis eine C++-Exception geworfen wird. Dann wird der Backtrace angedruckt. Möglicherweise muss sooft wiederholt werden, bis die richtige Exception geworfen wird.
Dazu wird erst der LLDB-Debugger (in $LODE_HOME/dev/core wenn er aus lode ausgecheckt wurde) mit folgendem Kommando gestartet:
make debugrun
dann wir der erste Breakpoint gesetzt und das Programm gestartet.
(lldb) b linguistic/source/gciterator.cxx:608
# unbekannte Warnungen über locations werden ignoriert
(lldb) run --writer --norestore /more/arguments/to/soffice
dann wird der Breakpoint gelöscht und der für alle C++-Exceptions gesetzt.
(lldb) break set -E cxx
# optional wird der alte gelöscht, im Beispiel "1" in der Liste:
(lldb) break list
(lldb) break delete 1
# fortfahren bis der Backtrace für die Exception da ist
(lldb) c
(lldb) bt
# wiederholen, bis der richtige vorliegt
Fehlersuche mit WinDbg oder Visual Studio (on Windows)
Die Fehlersuche mit Visual Studio extrem einfach. Es wird nur der Debug Build gebraucht, keine IDE.Öffnen Sie nur die Quelldatei im Visual Studio, fügen Sie einen Breakpoint hinzu, starten Sie soffice.exe und hängen Sie den Debugger unter ▸ ein. Die Ausführung stoppt an jedem Breakpoint (die Ausführung wird unter ▸ sofort gestoppt). Visual Studio öffnet den ausgeführten Code automatisch während dem Debugging. Der Call Stack ist im gleichnamigen Fenster verfügbar.
Verwendung von Time Travelling Debugging mit windbg
Siehe https://learn.microsoft.com/de-de/windows-hardware/drivers/debuggercmds/time-travel-debugging-overview. Das kann pro Fehler Szenario einmal eingesetzt werden. Teile davon können im Debugger wiederholt werden.
Förderung der Debugging-Ergebnisse mit Visual Studio
Es gibt viele Einstellungsmöglichkeiten im Visual Studio. Diese können die Ergebnisse und die Produktivität verstärken. Am effektivsen sind die native visualizers. In /solenv/vs liegt eine allgemeine .natvis-Datei, die Objekte bestimmter Klassen in LibreOffice leichter anzeigt. Der Inhalt der Datei wird in PDBs der Debug Builds eingebettet. Dabei verwendet das Debugging den Visualisierer, auch wenn die Integaration in eine IDE nicht verwendet wird. Bitte fügen Sie nützlioche Hinweise zum Visualizer in dieser Datei hinzu und erstellen Sie Patches :)
Auch hilfreich: nicht in triviale Einzeiler wie den ->-Operator einspringen. Hier ist die Erklärung: How to *not* step in certain functions? (Stack Overflow)
Es ist oft hilfreich, die Einstellung "Just My Code" im Visual Studio debugger abzuschalten: ▸ ▸ ; suche und deaktiviere "Enable Just My Code". Anbdernfalls werden Call Stacks unvollständig und nicht hilfreich sein.
Fehlersuche in Release Builds
Die Call Stacks in Visual Studio erscheinen zunächst nutzlos. um das zu vermeiden sollte der Microsoft Symbol Server aktiviert werden: ▸ ▸ ▸ mit einem Klick auf "Microsoft Symbol Servers".
Für Infos zum Aufsetzen von WinDBG oder Visual Studio zum Debuggen von TDF Release Builds mit Symbolen aus dem Netz siehe How to get a backtrace with WinDbg.
Registrieren eines Builds als COM Server
Wenn die COM-Komponente ausgetestet werden soll, kann der lokale Build als COM Server mit dem folgenden Skript registriert werden:
REM usage:
REM libreoffice-registry-set-com-path.bat soffice_exe_path
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4} /ve /t REG_SZ /d "LibreOffice Service Manager (Ver 1.0)" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4} /v AppID /t REG_SZ /d "{82154420-0FBF-11d4-8313-005004526AB4}" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4}\LocalServer32 /ve /t REG_EXPAND_SZ /d "%* --nodefault --nologo" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4}\NotInsertable /ve /t REG_SZ /d "" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4}\ProgID /ve /t REG_SZ /d "com.sun.star.ServiceManager.1" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4}\Programmable /ve /t REG_SZ /d "" /f
reg add HKEY_CLASSES_ROOT\CLSID\{82154420-0FBF-11d4-8313-005004526AB4}\VersionIndependentProgID /ve /t REG_SZ /d "com.sun.star.ServiceManager" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager /ve /t REG_SZ /d "LibreOffice Service Manager" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager\CLSID /ve /t REG_SZ /d "{82154420-0FBF-11d4-8313-005004526AB4}" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager\CurVer /ve /t REG_SZ /d "com.sun.star.ServiceManager.1" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager\NotInsertable /ve /t REG_SZ /d "" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager.1 /ve /t REG_SZ /d "LibreOffice Service Manager (Ver 1.0)" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager.1\CLSID /ve /t REG_SZ /d "{82154420-0FBF-11d4-8313-005004526AB4}" /f
reg add HKEY_CLASSES_ROOT\com.sun.star.ServiceManager.1\NotInsertable /ve /t REG_SZ /d "" /f
Das Pfad zur Batch-Datei muss ein Windows-Pfad sein. In einer Cygwin-Shell muss der Pfad cygpath -w -a -l ./instdir/program/soffice.exe lauten.
Verwendung von Voltron
Siehe Development/Voltron.
Fehlersuche in den Build Tools
Falls der Build abbricht, wenn ein Tool eingesetzt wird, das aktuell lokal mit übersetzt wird, dann findet sich der Bug sehr wahrscheinlich im Tool. Um das Tool im strace, valgrind oder einem Debugger mitlaufen zu lassen, kann die Umgebungsvariable BUILDTOOLTRACE verwendet werden:
make BUILDTOOLTRACE='strace' PARALLELISM=1 # Ablauf in Strace
make BUILDTOOLTRACE='gdb --args' PARALLELISM=1 # debuggen mit GDB
make BUILDTOOLTRACE='$(DEVENV) /debugexe' PARALLELISM=1 # debuggen im Visual Studio
Einsatz von CPPUnit-Tests
Um den CPP-Unit-Test foo in bar laufen zu lassen, gehen Sie wie folgt vor:
cd bar && make CppunitTest_foo
Der Hauptteil ist das, was in einem nicht-verbose log erscheint. Der erste Teil ist üblicherweise das Modul. Wenn nicht, lassen Sie grep foo */*.mk laufen, um es herauszufinden. Z. Bsp. kann der Test-Aufruf bei einer Meldung des Builds
[build CUT] sw_subsequent_ooxmlexport
manuell wie folgt gestartet werden
cd sw && make CppunitTest_sw_subsequent_ooxmlexport
Fehlersuche mit CPPUnit-Tests
Wenn ein CPP-Unit-Test beim Übersetzen abbricht, kann ein Debugger wie folgt eingesetzt werden...
$ export CPPUNITTRACE="gdb --args"
Wenn jetzt übersetzt wird (bei zwingendem nicht-parallelem Build unter -j1) startet GDB mit dem geladenen CPP-Unit-Test. Zum Start unter GDB wird "run" eingegeben. Diese Option war bis Oktober 2013 GDBCPPUNITTRACE
Unter Windows kann der Unit-Test im Visual Studio wie folgt gestartet werden:
$ export CPPUNITTRACE="\"path_to_your_devenv.exe\" /debugexe"
mit dem absoluten Pfad + devenv.exe als path_to_your_devenv.exe. Dadurch startet Visual Studio und der Test wird direkt von der UI gestartet.
Unter macOS funktioniert GDB nicht mehr. Es wurde durch LLDB ersetzt. CPPUNITTRACE kann trotzdem wie folgt genutzt werden:
$ export CPPUNITTRACE="lldb --"
Alternativ, wenn der Test abbricht und sich über eine nicht gefangene Exeption beschwert, kann ein CPP-Unit-Test wie folgt protokoliert werden, um herauszufinden, wo die letzte Exeption geworfen wurde:
$ export DEBUGCPPUNIT=TRUE
Dadurch werden die geworfenen und gefangenen Exceptions im gdbtrace.log geloggt.
Es kann auch eine spezielle Testfall-Methode im CPP-Unit Make Ziel einstellen (welche üblicherweise viele individuelle Testfall-Methoden hat) über
$ CPPUNIT_TEST_NAME=testFDO76163 make CppunitTest_foo
Fehlersuche mit CPPUnit-Tests im STrace
Wenn die GDB Backtraces nicht helfen, kann der STrace wie folgt versucht werden:
$ make CppunitTest_Test_Name CPPUNITTRACE="strace -f -s 77" 2>&1 | tee strace.log
Der Parameter -s erhöht das Zeichenlimit auf 77
Fehlersuche mit perfcheck und andere CPPUnit-Tests, die unter Valgrind laufen
Bei Performanztests (make perfcheck) oder Tests unter Valgrind (siehe folgende Absätze) können die Tests nicht direkt debugged werden. Valgrind hat einen eingebauten GDB-Server. Daher kann der Test nach dem folgendem Export debugged werden.
$ export VALGRIND_GDB=TRUE
danach wird der Test normal und GDB folgendermaßen gestartet:
$ gdb workdir/LinkTarget/Executable/cppunittester
und am GDB Prompt mit:
$ target remote | vgdb
Fehlersuche in ausführbaren Programmen
LibreOffice hat im VCL-Modul einige Demoprogramme gebündelt. Um diese Programme zu debuggen, muss erst die Umgebungsvariable LOTRACE auf den Debugger gesetzt werden. Unter Linux funktioniert das wie folgt:
$ export LOTRACE="gdb --args"
Unter Windows kann das Programm im Visual Studio wie folgt gestartet werden:
$ export LOTRACE="\"path_to_your_devenv.exe\" /debugexe"
mit dem absoluten Pfad + devenv.exe als path_to_your_devenv.exe. Dadurch startet Visual Studio und der Test wird direkt von der UI gestartet.
Unter macOS funktioniert GDB nicht mehr. Es wurde durch LLDB ersetzt. LOTRACE kann trotzdem wie folgt genutzt werden:
$ export LOTRACE="lldb --"
Die App wird mit folgendem bin/run Skript gestartet:
$ bin/run vcldemo
Valgrind (Speichercheck) CPP-Unit-Tests
Zum Kompile-Zeitpunkt kann der Speichercheck über die CPP-Unit und andere Tests wie folgt laufen:
$ export VALGRIND=memcheck
Das setzt automatisch G_SLICE=always-malloc und startet die hunspell Regressions-Tests unter valgrind --tool=memcheck
Valgrind (Speichercheck) LibreOffice selbst
$ export VALGRIND=memcheck
Das setzt automatisch G_SLICE=always-malloc und startet LibreOffice selbst unter valgrind --tool=memcheck
Valgrind (helgrind) CPP-Unit-Tests
Zum Kompile-Zeitpunkt kann helgrind über die CPP-Unit und andere Tests wie folgt laufen:
$ export VALGRIND=helgrind
Valgrind (helgrind) LibreOffice selbst
$ export VALGRIND=helgrind
Das startet LibreOffice selbst unter valgrind --tool=memcheck
Starten der Folge-Tests
Ein top-level make check wird zunächst einen kompletten build erstellen, dann alle Folgetests starten. Ein top-level make subsequentcheck wird stattdessen lediglich die Folgetests starten.
Das kann entweder innerhalb eines Moduls geschehen oder als einzelnes Modul.
Ein einzelner Folgetest kann über sein Ziel (siehe in foo/Module_foo.mk) gestartet werden, z. Bsp. mit cd sw && make -rs JunitTest_sw_complex. Der cd foo-Teil ist nicht nötig, aber beschleunigt den Prozess.
Wenn der Test abbricht, kann das daran liegen, dass das Gebietsschema nicht "en-US" ist. In diesem Fall wird "export LANG=C" laufen gelassen und der Test nochmal gestartet.
Fehlersuche in den Folge-Tests
Der abgebrochene Test erzeugt eine Log-Datei, die in einem Text-Editor angezeigt werden kann:
workdir/JunitTest/<module>_<complex|unoapi>/done.log
Die Log-Datei enthält einen Java Stack-Trace des abgebrochenen Tests. Wenn soffice.bin abgebrochen ist und eine Core-Datei hinterlassen hat, dann ist das auch eine C++-Stack-Trace.
Falls es keinen Abbruch gibt, bringt ein Blick in den Stack-Trace einen Hinweis auf den abgebrochenen Java-Test-Code. Die interessantesten Frames sind üblicherweise in den Klassen complex.<module>...", der Code dafür findet sich in <module>/qa/complex/. Das sollte einige interessante UNO API Methoden zeigen, die auf der C++-Seite der soffice.bin aufgerufen werden.
Folgendes Kommando startet LibreOffice aus instdir innerhalb GDB zum Debuggen:
make debugrun
erst wird die schreckliche GDB TUI mittels "C-x a" abgeschaltet, dann kann ein Breakpoint an der fraglichen Stelle gesetzt werden. Zum Start sollte sich ein neues Fenster öffnen.
Dann kann (in einem anderen Terminal) folgendes laufen:
make gb_JunitTest_DEBUGRUN=T <module>.subsequentcheck
Das führt den Test gegen die aktuell laufende soffice.bin aus, wobei hoffentlich der Breakpoint getroffen wird und das Problem ab hier untersucht werden kann.
Fehlersuche mit den qadevOOo/unoapi Folgetests
Die qadevOOo/unoapi Tests sind ziemlich tricky zu debuggen.
Wenn ein Test fehlschlägt, wird erst die Methode benötigt, die beanstandet wird. Diese Datei wird in einem Text-Editor geöffnet:
workdir/JunitTest/<module>_unoapi/done.log
Am Ende findetr sich dort eine Zusammenfassung, die die fehlschlagende Test-Komponente zeigt:
Failures that appeared during scenario execution:
toolkit.AccessibleStatusBarItem
1 of 53 tests failed
Die Suche nach FAIL zeigt ein Fehler wie folgt:
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
Kurz nach oben gescrollt sollte sich eine Zeile wie folgt finden:
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, ifc.accessibility._XAccessibleText, corresponding to qadevOOo/tests/java/ifc/accessibility/_XAccessibleText.java.
There is also a Java setup code specific to the tested component toolkit.AccessibleStatusBarItem in qadevOOo/tests/java/mod/_toolkit/AccessibleStatusBarItem.java.
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.
Fehlersuche mit 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 SAL_RAND_REPEATABLE=1 (s. the #Environment_Variables 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 RR=1. This requires ~35GB of storage per make check 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:
#!/bin/bash
dir=/home/foobar/.local/share/rr/latest-trace/
pid=$(rr ps $dir | grep soffice.bin | cut -f 1 | tail -n 1)
exec rr replay -p $pid $dir -- "$@"
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
-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 ignorejava.exeby runningdrconfig.exe -quiet -reg java.exe -norun. (Strangely, the in-processjvm.dllis 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 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:
export JSIMD_FORCEMMX=1.
- DrMemory reports various other false positives than can be suppressed via the
-suppressargument.
Here is a sample drmemory-suppressions.txt 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 <not in a module> ... jvm.dll!* UNINITIALIZED READ name=UR in JIT code from jvm.dll <not in a module> ... 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 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/refcount_leak.py 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
Environment Variables
These environment variables are useful for debugging purpose:
OOO_DISABLE_RECOVERY=1disable recovery of corrupted documents on startup.OOO_EXIT_POST_STARTUP=1exit immediately after opening document. Useful for debugging open performance.SAL_DISABLEGL=1disable use of OpenGLSAL_DISABLE_OPENCL=1disable use of OpenCL in calc.SAL_NO_MOUSEGRABS=1prevents LibreOffice from grabbing the mouse during debugging on X11.SAL_RAND_REPEATABLE=1makes the random number generator start from a fixed seed, which makes tests that use random numbers predictable.SAL_USE_VCLPLUGIN=gen/kf5/gtk3force the use of a specific VCL UI backend.SW_DEBUG=1enable writer document dump keybinds (F12 for layout.xml, Shift+F12 for nodes.xml)SD_DEBUG=1enable draw graphic object dump keybind (F12 for model.xml)
Macros Controlling Debug Code
- The
NDEBUGmacro is the standard way to control the standardassertfunctionality. It is defined in plain production builds, left undefined for--enable-debug/--enable-dbgutil(note that defining it disables assertions).
- The
SAL_LOG_INFOandSAL_LOG_WARNmacros control whether theSAL_INFOandSAL_WARNfunctionality, resp., frominclude/sal/log.hxxis activated. They are left undefined in plain production builds, defined for--enable-debug/--enable-dbgutil. If activated, their runtime behaviour is controlled by theSAL_LOGenvironment variable (see the documentation ininclude/sal/log.hxxfor details).
To enable SAL_INFO and SAL_WARN for sw component type:
export SAL_LOG="+INFO.sw.ww8+WARN"
- The
DBG_UTILmacro 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 obsoleteDBG_ASSERTetc. macros frominclude/tools/debug.hxx.) It is left undefined in production builds, and defined for--enable-dbgutil.
- The
_GLIBCXX_DEBUGmacro enables helpful assertions in the libstdc++ STL implementation, which affect ABI compatiblity; it is also enabled by--enable-dbgutilon ELF based GCC platforms (TODO: this could work on all GCC platforms if only somebody tested it).
- The
OSL_DEBUG_LEVELmacro controls additional, potentially excessively expensive debug code (but which does not affect compatibility). It is defined as0in plain production builds, as1for--enable-debug/--enable-dbgutil(enabling the obsoleteOSL_ASSERTetc. macros frominclude/osl/diagnose.h), and as2or higher with an explicitdbglevel=Nargument tomake.
Debugging Python components in LibreOffice
To debug the loading of python components, change the line DEBUG=0 in pythonloader.py.
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.
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 py-bt, py-bt-full, py-print, py-locals, py-up, py-down, py-list become available at the gdb prompt, in addition to gdb's own C++ debugging commands. See documentation at [1].
For the python that is bundled with LO, gdb debugging is enabled by instdir/program/libpython3.5m.so.1.0-gdb.py; 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
sudo dnf --enablerepo=fedora-debuginfo --enablerepo=updates-debuginfo install python3-debuginfo.
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 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). 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:
-Xdebug
-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n
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: localhost
Port: 8000
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:
- How to get a Callgrind trace
- Video about using Callgrind with KCachegrind for profiling.
Visualize results
To visualize results KCachegrind could be used.
- Turn off cycle detection. The results are often nearly meaningless for non-trivial cases.
- Turn off the 'Relative' button and use absolute cycle counts everywhere or it is very easy to lose a sense of proportion.
- 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)
Der linux kernel profiler (perf) erzeugt eine weniger detailierte Ausgabe als callgrind, ist aber viel günstiger in der Ausführung (da er ein
Muster Profiler ist). Mit callgrind oder perf sollte man keine Debug-Version kompilieren, stattdessen besser mit --enable-symbols.
Sie brauchen eine extra Zulassung d. i.
sudo sh -c "echo 0 > /proc/sys/kernel/kptr_restrict"
oder auch:
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, use KDAB Hotspot.
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`