Die Ermittlung eines Code Coverages beruht auf der Beobachtung des Kontrollflusses, während der zu messende Programmcode mit entsprechenden Teststimuli entweder auf einem realen Target oder zumindest in einer Simulation ausgeführt wird. Gleichzeitig werden die Abarbeitung der einzelnen Statements, die eingeschlagenen Wege an Verzweigungen und/oder die konkreten Wahrheitswerte von Einzelbedingungen je nach geforderter Coverage-Stufe festgehalten und anschließend bewertet.
Eine typische Herangehensweise für die Gewinnung der notwendigen Daten ist die Instrumentierung des originalen Programmcodes. Allerdings ändert der eingefügte Testcode nicht nur das Laufzeitverhalten und die Codegröße, sondern gegebenenfalls auch das Speicherlayout. Dies kann sich insbesondere bei sicherheitskritischen Anwendungen oder Systemen mit hohen Echtzeitanforderungen als überaus kritisch erweisen.
Eine Alternative zur Ausführung von instrumentiertem Code stellt die Datengewinnung mittels Trace durch einen Debugger dar. Voraussetzung dafür ist aber eine geeignete Trace-Hardware inklusive einer Trace-Schnittstelle im eingebetteten System. Viele aktuelle High-End-Mikrocontroller bieten inzwischen die dafür notwendigen Features und im günstigsten Fall kann der Debugger wie bei der Universal Debug Engine® (UDE) von PLS die Ermittlung des Coverages sogar selbst übernehmen.
Für das Code Coverage spielt natürlich der Code Trace die entscheidende Rolle. Typischerweise werden dabei die Adressen der ausgeführten Maschinenbefehle oder zumindest der Verzweigungsoperationen – genauer gesagt der angesprungenen Ziele – aufgezeichnet. Aus diesen Informationen lässt sich dann unter Zuhilfenahme der Programmbinaries ohne Weiteres ein Statement Coverage errechnen. Doch Vorsicht: Ermittelt man ein Code Coverage für Produktionscode, der auf realer Hardware getestet und mittels Trace beobachtet wird, dann handelt es sich beim Ergebnis immer um Maschinencode- und nicht um Quellcode-orientiertes Coverage. Gerade bei optimiertem Code kommt es deshalb zwischen dem, was der Entwickler ursprünglich in einer höheren Programmiersprache verfasst hat und dem Resultat aus der Kompilierung immer wieder zu großen Abweichungen. Dazu mehr an späterer Stelle.
Als weitere Stolperfalle erweisen sich leider gar nicht so selten Beschränkungen der Trace-Größe durch die Trace-Hardware. Für eine belastbare Coverage-Berechnung muss natürlich der Trace für die zu messenden Funktionen oder Module auch vollständig sein. Wird die Trace-Aufzeichnung mangels ausreichender Größe des Trace-Speichers abgeschnitten, kann das Coverage logischerweise auch nicht korrekt berechnet werden. Vermeiden lässt sich dieses Dilemma entweder durch eine geschickte Wahl des Programmcodes, für den das Coverage in einem Durchgang berechnet werden soll. So können Filter den Trace beispielsweise auf nur eine Funktion beschränken. Oder man greift vorsichtshalber gleich auf größere, externe Trace-Speicher zurück, wie sie beispielsweise im Universal Access Device 3+ von PLS mit bis zu 4 GByte zur Verfügung stehen.