Branch-Coverage-Tests

Minimalinvasiv testen

12. August 2014, 11:30 Uhr | Heiko Rießland
Diesen Artikel anhören

Fortsetzung des Artikels von Teil 3

Erkennung der Programmstruktur

Die Programmstruktur, d.h. die Basisblöcke, ihre Programmadresse und -größe sowie ihre Verknüpfung, lässt sich sowohl statisch als auch dynamisch ermitteln. Dabei können auch im DWARF-Format vorliegende Debug-Informationen aus der Programmdatei genutzt werden, welche u.a. die Zuordnungen von Zeilennummern zu Programmadressen und die Programmadressen der Basisblöcke enthalten.

Allerdings sind im regulären DWARF-Format bislang weder die Größe der Basisblöcke noch ihre Verknüpfung enthalten. Letztere lassen sich nur durch Disassemblierung der Maschinencode-Anweisungen und anschließender Interpretation, Emulation oder Simulation ermitteln. Diese statische Code-Analyse ist sehr aufwendig und zeitintensiv und wird daher auch nur selten durchgeführt.

Die dynamischen Trace-Informationen enthalten die Adressen der tatsächlich ausgeführten Anweisungen und die Reihenfolge der Ausführung. Aus diesen Informationen lässt sich zwar eine Sicht auf mögliche Basisblöcke erzeugen, aber der Nachteil hier ist, dass man leider nur die tatsächlich ausgeführten Basisblöcke sieht. Ohne zu wissen, welche Basisblöcke nicht ausgeführt werden, kann jedoch keine verlässliche Überdeckungsanalyse durchgeführt werden. Was also tun in so einem Fall?

Wege zur sicheren Erkennung der Programmüberdeckung

Normalerweise reichen die Standard-Debug-Informationen aus, um die Überdeckung der Quellcode-Zeilen (C0-Coverage) zu ermitteln. Um jedoch die Zweigüberdeckung (C1-Coverage) aus Trace-Daten ermitteln zu können, werden zusätzlich die Verknüpfungen zwischen den Basisblöcken benötigt. Diese Verknüpfungen sind, wie schon angesprochen, in den DWARF-Informationen nicht vorhanden. Aus dem Anweisungs-Trace kann ermittelt werden, welche Programmverzweigungen genommen wurden, bei direkten Sprüngen – mit einigem Aufwand – zudem auch, welche Verzweigungen nicht genommen wurden. Anders sieht es bei indirekten Sprüngen aus. Da diese nahezu beliebig viele Sprungziele haben können, ist in der Regel nicht mehr ermittelbar, wie viele Verzweigungen tatsächlich existieren und wohin diese Verzweigungen führen.

Für das vorliegende Beispiel mit der Sprungtabelle bedeutet dies, dass in diesem Fall nicht mehr ermittelbar ist, welche möglichen Verzweigungen ausgeführt wurden und welche nicht. Voraussetzung dafür wäre entweder eine aufwendige statische Code-Analyse, welche die Sprungtabellen-Optimierung erkennt, oder eine Debug-Information über die Basisblock-Verknüpfungen.

Im Beispiel mit der Wertetabelle wird die statische Code-Analyse noch aufwendiger, da hier anhand der Speicherzugriffe ermittelt werden müsste, um welchen ausgeführten case-Zweig es sich handelt. Anweisungs-Trace allein reicht dafür nicht mehr aus; für die Auswertung ist zusätzlich zwingend auch noch Daten-Trace erforderlich.

Anreicherung der Debug-Informationen

Um eine aufwendige und damit auch fehleranfällige statische Code-Analyse zu vermeiden, bietet es sich an, die Basisblock-Informationen zu nutzen, die dem Compiler nach allen Programmtransformationen ohnehin zur Verfügung stehen. Dies sind unter anderem die Identifikationsnummern, Adressen und Größen der verschiedenen nach Funktion aufgeteilten Basisblöcke sowie Anzahl und Identifikationsnummern der Nachfolger eines Basisblockes. Diese Informationen reichen aus, um einen Graphen von Basisblöcken zu ermitteln und aus den Verknüpfungen zwischen den Basisblöcken und dem Anweisungs-Trace eine Zweigüberdeckung (Branch Coverage) zu ermitteln.

 

passend zum Thema

»Wir sind überzeugt, dass bei Multicore-Anwendungen der Anteil der Software an der Wertschöpfung eines Produkts noch schneller als bisher wächst und in den nächsten Jahren bis zu 80 Prozent erreichen kann.«
Dipl.-Ing. Heiko Rießland war nach erfolgreichem Abschluss des Infomationstechnik-Studiums an der Technischen Universität Dresden zwölf Jahre in der Entwicklung und dem Vertrieb von Software-Entwicklungswerkzeugen und Emulatoren für 16- und 32-bit-Mikrokontroller tätig. Seit acht Jahren leitet Rießland das Produktmarketing der PLS Programmierbare Logik & Systeme GmbH.
© PLS

Grundvoraussetzung für diese Vorgehensweise ist, dass die eingesetzten Mikrocontroller vollständigen internen oder externen Programm-Trace unterstützen, der direkt zur Statement-Coverage-Analyse verwendet werden kann. Um damit auch Branch Coverage realisieren zu können, bedarf es zusätzlich nur noch eines effizienten Ersatzes für die In­strumentierung des Programmcodes.

Da die benötigten Informationen über die Basisblöcke, also Anfangsadresse, Länge und ihre Verbindungen, dem in den Beispielen verwendeten Compiler intern bei der Codegenerierung schon zur Verfügung stehen, bestand die Aufgabe von PLS vor allem darin, diese Informationen auch von außen zugänglich zu machen. Gelöst werden konnte die Aufgabe mittels Ergänzung des DWARF-Debug-Formats und Erweiterung des verwendeten Compilers. Durch geschickte Verknüpfung mit den Trace-Daten innerhalb des Debug- und Testwerkzeuges können jetzt erstmals Branch-Coverage-Analysen auch nichtinvasiv, ohne Instrumentierung des Codes durchgeführt werden. Darüber hinaus ist dieses von PLS in Zusammenarbeit mit der Fa. Hightec entwickelte und im Feldeinsatz bereits auf seine Praxistauglichkeit hin überprüfte Verfahren auch mit optimiertem Code anwendbar.


  1. Minimalinvasiv testen
  2. Path Coverage
  3. Code-Optimierung: von leicht geändert bis total umgewandelt
  4. Erkennung der Programmstruktur

Lesen Sie mehr zum Thema


Das könnte Sie auch interessieren

Jetzt kostenfreie Newsletter bestellen!

Weitere Artikel zu pls Programmierbare Logik & Systeme GmbH

Weitere Artikel zu Entwicklungswerkzeuge