1 #include "llvm/ADT/DenseMap.h"
2 #include "llvm/ADT/StringExtras.h"
3 #include "llvm/ADT/StringSet.h"
4 #include "llvm/DebugInfo/DIContext.h"
5 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
6 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
7 #include "llvm/Object/ObjectFile.h"
8 #include "llvm/Support/JSON.h"
9 
10 #define DEBUG_TYPE "dwarfdump"
11 using namespace llvm;
12 using namespace object;
13 
14 /// This represents the number of categories of debug location coverage being
15 /// calculated. The first category is the number of variables with 0% location
16 /// coverage, but the last category is the number of variables with 100%
17 /// location coverage.
18 constexpr int NumOfCoverageCategories = 12;
19 
20 /// Holds statistics for one function (or other entity that has a PC range and
21 /// contains variables, such as a compile unit).
22 struct PerFunctionStats {
23   /// Number of inlined instances of this function.
24   unsigned NumFnInlined = 0;
25   /// Number of inlined instances that have abstract origins.
26   unsigned NumAbstractOrigins = 0;
27   /// Number of variables and parameters with location across all inlined
28   /// instances.
29   unsigned TotalVarWithLoc = 0;
30   /// Number of constants with location across all inlined instances.
31   unsigned ConstantMembers = 0;
32   /// List of all Variables and parameters in this function.
33   StringSet<> VarsInFunction;
34   /// Compile units also cover a PC range, but have this flag set to false.
35   bool IsFunction = false;
36   /// Verify function definition has PC addresses (for detecting when
37   /// a function has been inlined everywhere).
38   bool HasPCAddresses = false;
39   /// Function has source location information.
40   bool HasSourceLocation = false;
41   /// Number of function parameters.
42   unsigned NumParams = 0;
43   /// Number of function parameters with source location.
44   unsigned NumParamSourceLocations = 0;
45   /// Number of function parameters with type.
46   unsigned NumParamTypes = 0;
47   /// Number of function parameters with a DW_AT_location.
48   unsigned NumParamLocations = 0;
49   /// Number of variables.
50   unsigned NumVars = 0;
51   /// Number of variables with source location.
52   unsigned NumVarSourceLocations = 0;
53   /// Number of variables with type.
54   unsigned NumVarTypes = 0;
55   /// Number of variables with DW_AT_location.
56   unsigned NumVarLocations = 0;
57 };
58 
59 /// Holds accumulated global statistics about DIEs.
60 struct GlobalStats {
61   /// Total number of PC range bytes covered by DW_AT_locations.
62   unsigned ScopeBytesCovered = 0;
63   /// Total number of PC range bytes in each variable's enclosing scope.
64   unsigned ScopeBytes = 0;
65   /// Total number of PC range bytes covered by DW_AT_locations with
66   /// the debug entry values (DW_OP_entry_value).
67   unsigned ScopeEntryValueBytesCovered = 0;
68   /// Total number of PC range bytes covered by DW_AT_locations of
69   /// formal parameters.
70   unsigned ParamScopeBytesCovered = 0;
71   /// Total number of PC range bytes in each variable's enclosing scope
72   /// (only for parameters).
73   unsigned ParamScopeBytes = 0;
74   /// Total number of PC range bytes covered by DW_AT_locations with
75   /// the debug entry values (DW_OP_entry_value) (only for parameters).
76   unsigned ParamScopeEntryValueBytesCovered = 0;
77   /// Total number of PC range bytes covered by DW_AT_locations (only for local
78   /// variables).
79   unsigned VarScopeBytesCovered = 0;
80   /// Total number of PC range bytes in each variable's enclosing scope
81   /// (only for local variables).
82   unsigned VarScopeBytes = 0;
83   /// Total number of PC range bytes covered by DW_AT_locations with
84   /// the debug entry values (DW_OP_entry_value) (only for local variables).
85   unsigned VarScopeEntryValueBytesCovered = 0;
86   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
87   unsigned CallSiteEntries = 0;
88   /// Total number of call site DIEs (DW_TAG_call_site).
89   unsigned CallSiteDIEs = 0;
90   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
91   unsigned CallSiteParamDIEs = 0;
92   /// Total byte size of concrete functions. This byte size includes
93   /// inline functions contained in the concrete functions.
94   unsigned FunctionSize = 0;
95   /// Total byte size of inlined functions. This is the total number of bytes
96   /// for the top inline functions within concrete functions. This can help
97   /// tune the inline settings when compiling to match user expectations.
98   unsigned InlineFunctionSize = 0;
99 };
100 
101 /// Holds accumulated debug location statistics about local variables and
102 /// formal parameters.
103 struct LocationStats {
104   /// Map the scope coverage decile to the number of variables in the decile.
105   /// The first element of the array (at the index zero) represents the number
106   /// of variables with the no debug location at all, but the last element
107   /// in the vector represents the number of fully covered variables within
108   /// its scope.
109   std::vector<unsigned> VarParamLocStats{
110       std::vector<unsigned>(NumOfCoverageCategories, 0)};
111   /// Map non debug entry values coverage.
112   std::vector<unsigned> VarParamNonEntryValLocStats{
113       std::vector<unsigned>(NumOfCoverageCategories, 0)};
114   /// The debug location statistics for formal parameters.
115   std::vector<unsigned> ParamLocStats{
116       std::vector<unsigned>(NumOfCoverageCategories, 0)};
117   /// Map non debug entry values coverage for formal parameters.
118   std::vector<unsigned> ParamNonEntryValLocStats{
119       std::vector<unsigned>(NumOfCoverageCategories, 0)};
120   /// The debug location statistics for local variables.
121   std::vector<unsigned> VarLocStats{
122       std::vector<unsigned>(NumOfCoverageCategories, 0)};
123   /// Map non debug entry values coverage for local variables.
124   std::vector<unsigned> VarNonEntryValLocStats{
125       std::vector<unsigned>(NumOfCoverageCategories, 0)};
126   /// Total number of local variables and function parameters processed.
127   unsigned NumVarParam = 0;
128   /// Total number of formal parameters processed.
129   unsigned NumParam = 0;
130   /// Total number of local variables processed.
131   unsigned NumVar = 0;
132 };
133 
134 /// Collect debug location statistics for one DIE.
135 static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope,
136                             std::vector<unsigned> &VarParamLocStats,
137                             std::vector<unsigned> &ParamLocStats,
138                             std::vector<unsigned> &VarLocStats, bool IsParam,
139                             bool IsLocalVar) {
140   auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned {
141     // No debug location at all for the variable.
142     if (BytesCovered == 0)
143       return 0;
144     // Fully covered variable within its scope.
145     if (BytesCovered >= BytesInScope)
146       return NumOfCoverageCategories - 1;
147     // Get covered range (e.g. 20%-29%).
148     unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope;
149     LocBucket /= 10;
150     return LocBucket + 1;
151   };
152 
153   unsigned CoverageBucket = getCoverageBucket();
154   VarParamLocStats[CoverageBucket]++;
155   if (IsParam)
156     ParamLocStats[CoverageBucket]++;
157   else if (IsLocalVar)
158     VarLocStats[CoverageBucket]++;
159 }
160 
161 /// Collect debug info quality metrics for one DIE.
162 static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
163                                std::string VarPrefix, uint64_t BytesInScope,
164                                uint32_t InlineDepth,
165                                StringMap<PerFunctionStats> &FnStatMap,
166                                GlobalStats &GlobalStats,
167                                LocationStats &LocStats) {
168   bool HasLoc = false;
169   bool HasSrcLoc = false;
170   bool HasType = false;
171   bool IsArtificial = false;
172   uint64_t BytesCovered = 0;
173   uint64_t BytesEntryValuesCovered = 0;
174   auto &FnStats = FnStatMap[FnPrefix];
175   bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter;
176   bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable;
177 
178   if (Die.getTag() == dwarf::DW_TAG_call_site ||
179       Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
180     GlobalStats.CallSiteDIEs++;
181     return;
182   }
183 
184   if (Die.getTag() == dwarf::DW_TAG_call_site_parameter ||
185       Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) {
186     GlobalStats.CallSiteParamDIEs++;
187     return;
188   }
189 
190   if (!IsParam && !IsLocalVar && Die.getTag() != dwarf::DW_TAG_member) {
191     // Not a variable or constant member.
192     return;
193   }
194 
195   if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
196       Die.findRecursively(dwarf::DW_AT_decl_line))
197     HasSrcLoc = true;
198 
199   if (Die.findRecursively(dwarf::DW_AT_type))
200     HasType = true;
201 
202   if (Die.find(dwarf::DW_AT_artificial))
203     IsArtificial = true;
204 
205   auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
206     DWARFUnit *U = Die.getDwarfUnit();
207     DataExtractor Data(toStringRef(D),
208                        Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
209     DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize());
210     // Consider the expression containing the DW_OP_entry_value as
211     // an entry value.
212     return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
213       return Op.getCode() == dwarf::DW_OP_entry_value ||
214              Op.getCode() == dwarf::DW_OP_GNU_entry_value;
215     });
216   };
217 
218   if (Die.find(dwarf::DW_AT_const_value)) {
219     // This catches constant members *and* variables.
220     HasLoc = true;
221     BytesCovered = BytesInScope;
222   } else {
223     if (Die.getTag() == dwarf::DW_TAG_member) {
224       // Non-const member.
225       return;
226     }
227     // Handle variables and function arguments.
228     Expected<std::vector<DWARFLocationExpression>> Loc =
229         Die.getLocations(dwarf::DW_AT_location);
230     if (!Loc) {
231       consumeError(Loc.takeError());
232     } else {
233       HasLoc = true;
234       // Get PC coverage.
235       auto Default = find_if(
236           *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
237       if (Default != Loc->end()) {
238         // Assume the entire range is covered by a single location.
239         BytesCovered = BytesInScope;
240       } else {
241         for (auto Entry : *Loc) {
242           uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC;
243           BytesCovered += BytesEntryCovered;
244           if (IsEntryValue(Entry.Expr))
245             BytesEntryValuesCovered += BytesEntryCovered;
246         }
247       }
248     }
249   }
250 
251   // Calculate the debug location statistics.
252   if (BytesInScope) {
253     LocStats.NumVarParam++;
254     if (IsParam)
255       LocStats.NumParam++;
256     else if (IsLocalVar)
257       LocStats.NumVar++;
258 
259     collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats,
260                     LocStats.ParamLocStats, LocStats.VarLocStats, IsParam,
261                     IsLocalVar);
262     // Non debug entry values coverage statistics.
263     collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope,
264                     LocStats.VarParamNonEntryValLocStats,
265                     LocStats.ParamNonEntryValLocStats,
266                     LocStats.VarNonEntryValLocStats, IsParam, IsLocalVar);
267   }
268 
269   // Collect PC range coverage data.
270   if (DWARFDie D =
271           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
272     Die = D;
273   // By using the variable name + the path through the lexical block tree, the
274   // keys are consistent across duplicate abstract origins in different CUs.
275   std::string VarName = StringRef(Die.getName(DINameKind::ShortName));
276   FnStats.VarsInFunction.insert(VarPrefix + VarName);
277   if (BytesInScope) {
278     FnStats.TotalVarWithLoc += (unsigned)HasLoc;
279     // Turns out we have a lot of ranges that extend past the lexical scope.
280     GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered);
281     GlobalStats.ScopeBytes += BytesInScope;
282     GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
283     if (IsParam) {
284       GlobalStats.ParamScopeBytesCovered +=
285           std::min(BytesInScope, BytesCovered);
286       GlobalStats.ParamScopeBytes += BytesInScope;
287       GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
288     } else if (IsLocalVar) {
289       GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered);
290       GlobalStats.VarScopeBytes += BytesInScope;
291       GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered;
292     }
293     assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes);
294   } else if (Die.getTag() == dwarf::DW_TAG_member) {
295     FnStats.ConstantMembers++;
296   } else {
297     FnStats.TotalVarWithLoc += (unsigned)HasLoc;
298   }
299   if (!IsArtificial) {
300     if (IsParam) {
301       FnStats.NumParams++;
302       if (HasType)
303         FnStats.NumParamTypes++;
304       if (HasSrcLoc)
305         FnStats.NumParamSourceLocations++;
306       if (HasLoc)
307         FnStats.NumParamLocations++;
308     } else if (IsLocalVar) {
309       FnStats.NumVars++;
310       if (HasType)
311         FnStats.NumVarTypes++;
312       if (HasSrcLoc)
313         FnStats.NumVarSourceLocations++;
314       if (HasLoc)
315         FnStats.NumVarLocations++;
316     }
317   }
318 }
319 
320 /// Recursively collect debug info quality metrics.
321 static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
322                                   std::string VarPrefix, uint64_t BytesInScope,
323                                   uint32_t InlineDepth,
324                                   StringMap<PerFunctionStats> &FnStatMap,
325                                   GlobalStats &GlobalStats,
326                                   LocationStats &LocStats) {
327   // Handle any kind of lexical scope.
328   const dwarf::Tag Tag = Die.getTag();
329   const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
330   const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
331   const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
332   if (IsFunction || IsInlinedFunction || IsBlock) {
333 
334     // Reset VarPrefix when entering a new function.
335     if (Die.getTag() == dwarf::DW_TAG_subprogram ||
336         Die.getTag() == dwarf::DW_TAG_inlined_subroutine)
337       VarPrefix = "v";
338 
339     // Ignore forward declarations.
340     if (Die.find(dwarf::DW_AT_declaration))
341       return;
342 
343     // Check for call sites.
344     if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
345       GlobalStats.CallSiteEntries++;
346 
347     // PC Ranges.
348     auto RangesOrError = Die.getAddressRanges();
349     if (!RangesOrError) {
350       llvm::consumeError(RangesOrError.takeError());
351       return;
352     }
353 
354     auto Ranges = RangesOrError.get();
355     uint64_t BytesInThisScope = 0;
356     for (auto Range : Ranges)
357       BytesInThisScope += Range.HighPC - Range.LowPC;
358 
359     // Count the function.
360     if (!IsBlock) {
361       StringRef Name = Die.getName(DINameKind::LinkageName);
362       if (Name.empty())
363         Name = Die.getName(DINameKind::ShortName);
364       FnPrefix = Name;
365       // Skip over abstract origins.
366       if (Die.find(dwarf::DW_AT_inline))
367         return;
368       // We've seen an (inlined) instance of this function.
369       auto &FnStats = FnStatMap[Name];
370       if (IsInlinedFunction) {
371         FnStats.NumFnInlined++;
372         if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
373           FnStats.NumAbstractOrigins++;
374       }
375       FnStats.IsFunction = true;
376       if (BytesInThisScope && !IsInlinedFunction)
377         FnStats.HasPCAddresses = true;
378       std::string FnName = StringRef(Die.getName(DINameKind::ShortName));
379       if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
380           Die.findRecursively(dwarf::DW_AT_decl_line))
381         FnStats.HasSourceLocation = true;
382     }
383 
384     if (BytesInThisScope) {
385       BytesInScope = BytesInThisScope;
386       if (IsFunction)
387         GlobalStats.FunctionSize += BytesInThisScope;
388       else if (IsInlinedFunction && InlineDepth == 0)
389         GlobalStats.InlineFunctionSize += BytesInThisScope;
390     }
391   } else {
392     // Not a scope, visit the Die itself. It could be a variable.
393     collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
394                        FnStatMap, GlobalStats, LocStats);
395   }
396 
397   // Set InlineDepth correctly for child recursion
398   if (IsFunction)
399     InlineDepth = 0;
400   else if (IsInlinedFunction)
401     ++InlineDepth;
402 
403   // Traverse children.
404   unsigned LexicalBlockIndex = 0;
405   DWARFDie Child = Die.getFirstChild();
406   while (Child) {
407     std::string ChildVarPrefix = VarPrefix;
408     if (Child.getTag() == dwarf::DW_TAG_lexical_block)
409       ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
410 
411     collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope,
412                           InlineDepth, FnStatMap, GlobalStats, LocStats);
413     Child = Child.getSibling();
414   }
415 }
416 
417 /// Print machine-readable output.
418 /// The machine-readable format is single-line JSON output.
419 /// \{
420 static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) {
421   OS << ",\"" << Key << "\":" << Value;
422   LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
423 }
424 static void printLocationStats(raw_ostream &OS,
425                                const char *Key,
426                                std::vector<unsigned> &LocationStats) {
427   OS << ",\"" << Key << " with 0% of its scope covered\":"
428      << LocationStats[0];
429   LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: "
430                           << LocationStats[0] << '\n');
431   OS << ",\"" << Key << " with (0%,10%) of its scope covered\":"
432      << LocationStats[1];
433   LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: "
434                           << LocationStats[1] << '\n');
435   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
436     OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10
437        << "%) of its scope covered\":" << LocationStats[i];
438     LLVM_DEBUG(llvm::dbgs()
439                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
440                << "%) of its scope covered: " << LocationStats[i]);
441   }
442   OS << ",\"" << Key << " with 100% of its scope covered\":"
443      << LocationStats[NumOfCoverageCategories - 1];
444   LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: "
445                           << LocationStats[NumOfCoverageCategories - 1]);
446 }
447 /// \}
448 
449 /// Collect debug info quality metrics for an entire DIContext.
450 ///
451 /// Do the impossible and reduce the quality of the debug info down to a few
452 /// numbers. The idea is to condense the data into numbers that can be tracked
453 /// over time to identify trends in newer compiler versions and gauge the effect
454 /// of particular optimizations. The raw numbers themselves are not particularly
455 /// useful, only the delta between compiling the same program with different
456 /// compilers is.
457 bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
458                                Twine Filename, raw_ostream &OS) {
459   StringRef FormatName = Obj.getFileFormatName();
460   GlobalStats GlobalStats;
461   LocationStats LocStats;
462   StringMap<PerFunctionStats> Statistics;
463   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
464     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
465       collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
466                             LocStats);
467 
468   /// The version number should be increased every time the algorithm is changed
469   /// (including bug fixes). New metrics may be added without increasing the
470   /// version.
471   unsigned Version = 4;
472   unsigned VarParamTotal = 0;
473   unsigned VarParamUnique = 0;
474   unsigned VarParamWithLoc = 0;
475   unsigned NumFunctions = 0;
476   unsigned NumInlinedFunctions = 0;
477   unsigned NumFuncsWithSrcLoc = 0;
478   unsigned NumAbstractOrigins = 0;
479   unsigned ParamTotal = 0;
480   unsigned ParamWithType = 0;
481   unsigned ParamWithLoc = 0;
482   unsigned ParamWithSrcLoc = 0;
483   unsigned VarTotal = 0;
484   unsigned VarWithType = 0;
485   unsigned VarWithSrcLoc = 0;
486   unsigned VarWithLoc = 0;
487   for (auto &Entry : Statistics) {
488     PerFunctionStats &Stats = Entry.getValue();
489     unsigned TotalVars = Stats.VarsInFunction.size() * Stats.NumFnInlined;
490     // Count variables in concrete out-of-line functions and in global scope.
491     if (Stats.HasPCAddresses || !Stats.IsFunction)
492       TotalVars += Stats.VarsInFunction.size();
493     unsigned Constants = Stats.ConstantMembers;
494     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
495     VarParamTotal += TotalVars;
496     VarParamUnique += Stats.VarsInFunction.size();
497     LLVM_DEBUG(for (auto &V
498                     : Stats.VarsInFunction) llvm::dbgs()
499                << Entry.getKey() << ": " << V.getKey() << "\n");
500     NumFunctions += Stats.IsFunction;
501     NumFuncsWithSrcLoc += Stats.HasSourceLocation;
502     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
503     NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
504     ParamTotal += Stats.NumParams;
505     ParamWithType += Stats.NumParamTypes;
506     ParamWithLoc += Stats.NumParamLocations;
507     ParamWithSrcLoc += Stats.NumParamSourceLocations;
508     VarTotal += Stats.NumVars;
509     VarWithType += Stats.NumVarTypes;
510     VarWithLoc += Stats.NumVarLocations;
511     VarWithSrcLoc += Stats.NumVarSourceLocations;
512   }
513 
514   // Print summary.
515   OS.SetBufferSize(1024);
516   OS << "{\"version\":" << Version;
517   LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
518              llvm::dbgs() << "---------------------------------\n");
519   printDatum(OS, "file", Filename.str());
520   printDatum(OS, "format", FormatName);
521   printDatum(OS, "source functions", NumFunctions);
522   printDatum(OS, "source functions with location", NumFuncsWithSrcLoc);
523   printDatum(OS, "inlined functions", NumInlinedFunctions);
524   printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins);
525   printDatum(OS, "unique source variables", VarParamUnique);
526   printDatum(OS, "source variables", VarParamTotal);
527   printDatum(OS, "variables with location", VarParamWithLoc);
528   printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
529   printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs);
530   printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs);
531   printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes);
532   printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
533   printDatum(OS, "entry value scope bytes covered",
534              GlobalStats.ScopeEntryValueBytesCovered);
535   printDatum(OS, "formal params scope bytes total",
536              GlobalStats.ParamScopeBytes);
537   printDatum(OS, "formal params scope bytes covered",
538              GlobalStats.ParamScopeBytesCovered);
539   printDatum(OS, "formal params entry value scope bytes covered",
540              GlobalStats.ParamScopeEntryValueBytesCovered);
541   printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes);
542   printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered);
543   printDatum(OS, "vars entry value scope bytes covered",
544              GlobalStats.VarScopeEntryValueBytesCovered);
545   printDatum(OS, "total function size", GlobalStats.FunctionSize);
546   printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
547   printDatum(OS, "total formal params", ParamTotal);
548   printDatum(OS, "formal params with source location", ParamWithSrcLoc);
549   printDatum(OS, "formal params with type", ParamWithType);
550   printDatum(OS, "formal params with binary location", ParamWithLoc);
551   printDatum(OS, "total vars", VarTotal);
552   printDatum(OS, "vars with source location", VarWithSrcLoc);
553   printDatum(OS, "vars with type", VarWithType);
554   printDatum(OS, "vars with binary location", VarWithLoc);
555   printDatum(OS, "total variables procesed by location statistics",
556              LocStats.NumVarParam);
557   printLocationStats(OS, "variables", LocStats.VarParamLocStats);
558   printLocationStats(OS, "variables (excluding the debug entry values)",
559                      LocStats.VarParamNonEntryValLocStats);
560   printDatum(OS, "total params procesed by location statistics",
561              LocStats.NumParam);
562   printLocationStats(OS, "params", LocStats.ParamLocStats);
563   printLocationStats(OS, "params (excluding the debug entry values)",
564                      LocStats.ParamNonEntryValLocStats);
565   printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar);
566   printLocationStats(OS, "vars", LocStats.VarLocStats);
567   printLocationStats(OS, "vars (excluding the debug entry values)",
568                      LocStats.VarNonEntryValLocStats);
569   OS << "}\n";
570   LLVM_DEBUG(
571       llvm::dbgs() << "Total Availability: "
572                    << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
573                    << "%\n";
574       llvm::dbgs() << "PC Ranges covered: "
575                    << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
576                                       GlobalStats.ScopeBytes)
577                    << "%\n");
578   return true;
579 }
580