Table of Contents
Fetching ...

Accurate Coverage Metrics for Compiler-Generated Debugging Information

J. Ryan Stinnett, Stephen Kell

TL;DR

Debug information for optimised code is often incomplete, hindering source-level debugging. The authors introduce a residualisation-based model and a robust, source-line based coverage metric for local variables in DWARF debug info, addressing the limitations of naive instruction-based measures. They implement a static, source-analysis baseline, validate across multiple compilers and codebases through case studies and a replication study, and demonstrate that the metric tracks debuggability changes and explains compiler-induced variations. The approach provides a principled baseline to guide language implementations toward improved debuggability and outlines future work on state-retention in debuggers and automatic residualisation of debug information.

Abstract

Many debugging tools rely on compiler-produced metadata to present a source-language view of program states, such as variable values and source line numbers. While this tends to work for unoptimised programs, current compilers often generate only partial debugging information in optimised programs. Current approaches for measuring the extent of coverage of local variables are based on crude assumptions (for example, assuming variables could cover their whole parent scope) and are not comparable from one compilation to another. In this work, we propose some new metrics, computable by our tools, which could serve as motivation for language implementations to improve debugging quality.

Accurate Coverage Metrics for Compiler-Generated Debugging Information

TL;DR

Debug information for optimised code is often incomplete, hindering source-level debugging. The authors introduce a residualisation-based model and a robust, source-line based coverage metric for local variables in DWARF debug info, addressing the limitations of naive instruction-based measures. They implement a static, source-analysis baseline, validate across multiple compilers and codebases through case studies and a replication study, and demonstrate that the metric tracks debuggability changes and explains compiler-induced variations. The approach provides a principled baseline to guide language implementations toward improved debuggability and outlines future work on state-retention in debuggers and automatic residualisation of debug information.

Abstract

Many debugging tools rely on compiler-produced metadata to present a source-language view of program states, such as variable values and source line numbers. While this tends to work for unoptimised programs, current compilers often generate only partial debugging information in optimised programs. Current approaches for measuring the extent of coverage of local variables are based on crude assumptions (for example, assuming variables could cover their whole parent scope) and are not comparable from one compilation to another. In this work, we propose some new metrics, computable by our tools, which could serve as motivation for language implementations to improve debugging quality.
Paper Structure (30 sections, 4 equations, 11 figures, 1 table)

This paper contains 30 sections, 4 equations, 11 figures, 1 table.

Figures (11)

  • Figure 1: How Dwarf might describe a local variable over four distinct address ranges within a function. Most expressions compute where it is located: in a register or (later) on the stack. Over the second range, however, it is not represented explicitly; its value is computed as a scaled difference of two registers. (The textual syntax is for illustration only.)
  • Figure 2: How Dwarf can conceptually residualise control-flow positions that were eliminated during optimisation, using the "location views" extension of olivaConsistentViewsRecommended2010. A single program counter value (here 0xd06) can have a numbered sequence of "views" such that a single local variable is described differently for each view. At debug time, control appears to pass through each view in sequence, even though the program counter does not advance.
  • Figure 3: Classical view of the life cycle of a local variable.
  • Figure 4: Variable $x$ is in different states across a range of program points $p$. The right-hand C source function is annotated with these points. The left-hand flow chart illustrates $x$'s lifecycle in a hypothetical compilation, from before $x$'s introduction (Decl), across its definition (Def), last use (Last Use) and the subsequent reclamation of its stack or register storage (Dealloc). A final Unrecov event models the point from which there is no longer enough state to reconstruct the value.
  • Figure 5: Coverage achievability in the Git codebase. The gap between the lines represents "artificial" coverage that other tools suggest exists but cannot be achieved as it is outside the variable's defined ranges. The "other tools" line is always 1.0 by definition and included only to emphasise the difference between approaches.
  • ...and 6 more figures