xref: /freebsd/contrib/llvm-project/llvm/tools/llvm-dwarfdump/Statistics.cpp (revision ba3c1f5972d7b90feb6e6da47905ff2757e0fe57)
1 //===-- Statistics.cpp - Debug Info quality metrics -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm-dwarfdump.h"
10 #include "llvm/ADT/DenseMap.h"
11 #include "llvm/ADT/StringSet.h"
12 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
13 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
15 #include "llvm/Object/ObjectFile.h"
16 #include "llvm/Support/JSON.h"
17 
18 #define DEBUG_TYPE "dwarfdump"
19 using namespace llvm;
20 using namespace llvm::dwarfdump;
21 using namespace llvm::object;
22 
23 namespace {
24 /// This represents the number of categories of debug location coverage being
25 /// calculated. The first category is the number of variables with 0% location
26 /// coverage, but the last category is the number of variables with 100%
27 /// location coverage.
28 constexpr int NumOfCoverageCategories = 12;
29 
30 /// This is used for zero location coverage bucket.
31 constexpr unsigned ZeroCoverageBucket = 0;
32 
33 /// The UINT64_MAX is used as an indication of the overflow.
34 constexpr uint64_t OverflowValue = std::numeric_limits<uint64_t>::max();
35 
36 /// This represents variables DIE offsets.
37 using AbstractOriginVarsTy = llvm::SmallVector<uint64_t>;
38 /// This maps function DIE offset to its variables.
39 using AbstractOriginVarsTyMap = llvm::DenseMap<uint64_t, AbstractOriginVarsTy>;
40 /// This represents function DIE offsets containing an abstract_origin.
41 using FunctionsWithAbstractOriginTy = llvm::SmallVector<uint64_t>;
42 
43 /// This represents a data type for the stats and it helps us to
44 /// detect an overflow.
45 /// NOTE: This can be implemented as a template if there is an another type
46 /// needing this.
47 struct SaturatingUINT64 {
48   /// Number that represents the stats.
49   uint64_t Value;
50 
51   SaturatingUINT64(uint64_t Value_) : Value(Value_) {}
52 
53   void operator++(int) { return *this += 1; }
54   void operator+=(uint64_t Value_) {
55     if (Value != OverflowValue) {
56       if (Value < OverflowValue - Value_)
57         Value += Value_;
58       else
59         Value = OverflowValue;
60     }
61   }
62 };
63 
64 /// Utility struct to store the full location of a DIE - its CU and offset.
65 struct DIELocation {
66   DWARFUnit *DwUnit;
67   uint64_t DIEOffset;
68   DIELocation(DWARFUnit *_DwUnit, uint64_t _DIEOffset)
69       : DwUnit(_DwUnit), DIEOffset(_DIEOffset) {}
70 };
71 /// This represents DWARF locations of CrossCU referencing DIEs.
72 using CrossCUReferencingDIELocationTy = llvm::SmallVector<DIELocation>;
73 
74 /// This maps function DIE offset to its DWARF CU.
75 using FunctionDIECUTyMap = llvm::DenseMap<uint64_t, DWARFUnit *>;
76 
77 /// Holds statistics for one function (or other entity that has a PC range and
78 /// contains variables, such as a compile unit).
79 struct PerFunctionStats {
80   /// Number of inlined instances of this function.
81   uint64_t NumFnInlined = 0;
82   /// Number of out-of-line instances of this function.
83   uint64_t NumFnOutOfLine = 0;
84   /// Number of inlined instances that have abstract origins.
85   uint64_t NumAbstractOrigins = 0;
86   /// Number of variables and parameters with location across all inlined
87   /// instances.
88   uint64_t TotalVarWithLoc = 0;
89   /// Number of constants with location across all inlined instances.
90   uint64_t ConstantMembers = 0;
91   /// Number of arificial variables, parameters or members across all instances.
92   uint64_t NumArtificial = 0;
93   /// List of all Variables and parameters in this function.
94   StringSet<> VarsInFunction;
95   /// Compile units also cover a PC range, but have this flag set to false.
96   bool IsFunction = false;
97   /// Function has source location information.
98   bool HasSourceLocation = false;
99   /// Number of function parameters.
100   uint64_t NumParams = 0;
101   /// Number of function parameters with source location.
102   uint64_t NumParamSourceLocations = 0;
103   /// Number of function parameters with type.
104   uint64_t NumParamTypes = 0;
105   /// Number of function parameters with a DW_AT_location.
106   uint64_t NumParamLocations = 0;
107   /// Number of local variables.
108   uint64_t NumLocalVars = 0;
109   /// Number of local variables with source location.
110   uint64_t NumLocalVarSourceLocations = 0;
111   /// Number of local variables with type.
112   uint64_t NumLocalVarTypes = 0;
113   /// Number of local variables with DW_AT_location.
114   uint64_t NumLocalVarLocations = 0;
115 };
116 
117 /// Holds accumulated global statistics about DIEs.
118 struct GlobalStats {
119   /// Total number of PC range bytes covered by DW_AT_locations.
120   SaturatingUINT64 TotalBytesCovered = 0;
121   /// Total number of parent DIE PC range bytes covered by DW_AT_Locations.
122   SaturatingUINT64 ScopeBytesCovered = 0;
123   /// Total number of PC range bytes in each variable's enclosing scope.
124   SaturatingUINT64 ScopeBytes = 0;
125   /// Total number of PC range bytes covered by DW_AT_locations with
126   /// the debug entry values (DW_OP_entry_value).
127   SaturatingUINT64 ScopeEntryValueBytesCovered = 0;
128   /// Total number of PC range bytes covered by DW_AT_locations of
129   /// formal parameters.
130   SaturatingUINT64 ParamScopeBytesCovered = 0;
131   /// Total number of PC range bytes in each parameter's enclosing scope.
132   SaturatingUINT64 ParamScopeBytes = 0;
133   /// Total number of PC range bytes covered by DW_AT_locations with
134   /// the debug entry values (DW_OP_entry_value) (only for parameters).
135   SaturatingUINT64 ParamScopeEntryValueBytesCovered = 0;
136   /// Total number of PC range bytes covered by DW_AT_locations (only for local
137   /// variables).
138   SaturatingUINT64 LocalVarScopeBytesCovered = 0;
139   /// Total number of PC range bytes in each local variable's enclosing scope.
140   SaturatingUINT64 LocalVarScopeBytes = 0;
141   /// Total number of PC range bytes covered by DW_AT_locations with
142   /// the debug entry values (DW_OP_entry_value) (only for local variables).
143   SaturatingUINT64 LocalVarScopeEntryValueBytesCovered = 0;
144   /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
145   SaturatingUINT64 CallSiteEntries = 0;
146   /// Total number of call site DIEs (DW_TAG_call_site).
147   SaturatingUINT64 CallSiteDIEs = 0;
148   /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
149   SaturatingUINT64 CallSiteParamDIEs = 0;
150   /// Total byte size of concrete functions. This byte size includes
151   /// inline functions contained in the concrete functions.
152   SaturatingUINT64 FunctionSize = 0;
153   /// Total byte size of inlined functions. This is the total number of bytes
154   /// for the top inline functions within concrete functions. This can help
155   /// tune the inline settings when compiling to match user expectations.
156   SaturatingUINT64 InlineFunctionSize = 0;
157 };
158 
159 /// Holds accumulated debug location statistics about local variables and
160 /// formal parameters.
161 struct LocationStats {
162   /// Map the scope coverage decile to the number of variables in the decile.
163   /// The first element of the array (at the index zero) represents the number
164   /// of variables with the no debug location at all, but the last element
165   /// in the vector represents the number of fully covered variables within
166   /// its scope.
167   std::vector<SaturatingUINT64> VarParamLocStats{
168       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
169   /// Map non debug entry values coverage.
170   std::vector<SaturatingUINT64> VarParamNonEntryValLocStats{
171       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
172   /// The debug location statistics for formal parameters.
173   std::vector<SaturatingUINT64> ParamLocStats{
174       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
175   /// Map non debug entry values coverage for formal parameters.
176   std::vector<SaturatingUINT64> ParamNonEntryValLocStats{
177       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
178   /// The debug location statistics for local variables.
179   std::vector<SaturatingUINT64> LocalVarLocStats{
180       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
181   /// Map non debug entry values coverage for local variables.
182   std::vector<SaturatingUINT64> LocalVarNonEntryValLocStats{
183       std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)};
184   /// Total number of local variables and function parameters processed.
185   SaturatingUINT64 NumVarParam = 0;
186   /// Total number of formal parameters processed.
187   SaturatingUINT64 NumParam = 0;
188   /// Total number of local variables processed.
189   SaturatingUINT64 NumVar = 0;
190 };
191 } // namespace
192 
193 /// Collect debug location statistics for one DIE.
194 static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope,
195                             std::vector<SaturatingUINT64> &VarParamLocStats,
196                             std::vector<SaturatingUINT64> &ParamLocStats,
197                             std::vector<SaturatingUINT64> &LocalVarLocStats,
198                             bool IsParam, bool IsLocalVar) {
199   auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned {
200     // No debug location at all for the variable.
201     if (ScopeBytesCovered == 0)
202       return 0;
203     // Fully covered variable within its scope.
204     if (ScopeBytesCovered >= BytesInScope)
205       return NumOfCoverageCategories - 1;
206     // Get covered range (e.g. 20%-29%).
207     unsigned LocBucket = 100 * (double)ScopeBytesCovered / BytesInScope;
208     LocBucket /= 10;
209     return LocBucket + 1;
210   };
211 
212   unsigned CoverageBucket = getCoverageBucket();
213 
214   VarParamLocStats[CoverageBucket].Value++;
215   if (IsParam)
216     ParamLocStats[CoverageBucket].Value++;
217   else if (IsLocalVar)
218     LocalVarLocStats[CoverageBucket].Value++;
219 }
220 
221 /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
222 /// and DeclLine. The identifier aims to be unique for any unique entities,
223 /// but keeping the same among different instances of the same entity.
224 static std::string constructDieID(DWARFDie Die,
225                                   StringRef Prefix = StringRef()) {
226   std::string IDStr;
227   llvm::raw_string_ostream ID(IDStr);
228   ID << Prefix
229      << Die.getName(DINameKind::LinkageName);
230 
231   // Prefix + Name is enough for local variables and parameters.
232   if (!Prefix.empty() && !Prefix.equals("g"))
233     return ID.str();
234 
235   auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file);
236   std::string File;
237   if (DeclFile) {
238     DWARFUnit *U = Die.getDwarfUnit();
239     if (const auto *LT = U->getContext().getLineTableForUnit(U))
240       if (LT->getFileNameByIndex(
241               dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(),
242               DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
243         File = std::string(sys::path::filename(File));
244   }
245   ID << ":" << (File.empty() ? "/" : File);
246   ID << ":"
247      << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0);
248   return ID.str();
249 }
250 
251 /// Return the number of bytes in the overlap of ranges A and B.
252 static uint64_t calculateOverlap(DWARFAddressRange A, DWARFAddressRange B) {
253   uint64_t Lower = std::max(A.LowPC, B.LowPC);
254   uint64_t Upper = std::min(A.HighPC, B.HighPC);
255   if (Lower >= Upper)
256     return 0;
257   return Upper - Lower;
258 }
259 
260 /// Collect debug info quality metrics for one DIE.
261 static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix,
262                                const std::string &VarPrefix,
263                                uint64_t BytesInScope, uint32_t InlineDepth,
264                                StringMap<PerFunctionStats> &FnStatMap,
265                                GlobalStats &GlobalStats,
266                                LocationStats &LocStats,
267                                AbstractOriginVarsTy *AbstractOriginVariables) {
268   const dwarf::Tag Tag = Die.getTag();
269   // Skip CU node.
270   if (Tag == dwarf::DW_TAG_compile_unit)
271     return;
272 
273   bool HasLoc = false;
274   bool HasSrcLoc = false;
275   bool HasType = false;
276   uint64_t TotalBytesCovered = 0;
277   uint64_t ScopeBytesCovered = 0;
278   uint64_t BytesEntryValuesCovered = 0;
279   auto &FnStats = FnStatMap[FnPrefix];
280   bool IsParam = Tag == dwarf::DW_TAG_formal_parameter;
281   bool IsLocalVar = Tag == dwarf::DW_TAG_variable;
282   bool IsConstantMember = Tag == dwarf::DW_TAG_member &&
283                           Die.find(dwarf::DW_AT_const_value);
284 
285   // For zero covered inlined variables the locstats will be
286   // calculated later.
287   bool DeferLocStats = false;
288 
289   if (Tag == dwarf::DW_TAG_call_site || Tag == dwarf::DW_TAG_GNU_call_site) {
290     GlobalStats.CallSiteDIEs++;
291     return;
292   }
293 
294   if (Tag == dwarf::DW_TAG_call_site_parameter ||
295       Tag == dwarf::DW_TAG_GNU_call_site_parameter) {
296     GlobalStats.CallSiteParamDIEs++;
297     return;
298   }
299 
300   if (!IsParam && !IsLocalVar && !IsConstantMember) {
301     // Not a variable or constant member.
302     return;
303   }
304 
305   // Ignore declarations of global variables.
306   if (IsLocalVar && Die.find(dwarf::DW_AT_declaration))
307     return;
308 
309   if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
310       Die.findRecursively(dwarf::DW_AT_decl_line))
311     HasSrcLoc = true;
312 
313   if (Die.findRecursively(dwarf::DW_AT_type))
314     HasType = true;
315 
316   if (Die.find(dwarf::DW_AT_abstract_origin)) {
317     if (Die.find(dwarf::DW_AT_location) || Die.find(dwarf::DW_AT_const_value)) {
318       if (AbstractOriginVariables) {
319         auto Offset = Die.find(dwarf::DW_AT_abstract_origin);
320         // Do not track this variable any more, since it has location
321         // coverage.
322         llvm::erase_value(*AbstractOriginVariables, (*Offset).getRawUValue());
323       }
324     } else {
325       // The locstats will be handled at the end of
326       // the collectStatsRecursive().
327       DeferLocStats = true;
328     }
329   }
330 
331   auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
332     DWARFUnit *U = Die.getDwarfUnit();
333     DataExtractor Data(toStringRef(D),
334                        Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
335     DWARFExpression Expression(Data, U->getAddressByteSize(),
336                                U->getFormParams().Format);
337     // Consider the expression containing the DW_OP_entry_value as
338     // an entry value.
339     return llvm::any_of(Expression, [](const DWARFExpression::Operation &Op) {
340       return Op.getCode() == dwarf::DW_OP_entry_value ||
341              Op.getCode() == dwarf::DW_OP_GNU_entry_value;
342     });
343   };
344 
345   if (Die.find(dwarf::DW_AT_const_value)) {
346     // This catches constant members *and* variables.
347     HasLoc = true;
348     ScopeBytesCovered = BytesInScope;
349     TotalBytesCovered = BytesInScope;
350   } else {
351     // Handle variables and function arguments.
352     Expected<std::vector<DWARFLocationExpression>> Loc =
353         Die.getLocations(dwarf::DW_AT_location);
354     if (!Loc) {
355       consumeError(Loc.takeError());
356     } else {
357       HasLoc = true;
358       // Get PC coverage.
359       auto Default = find_if(
360           *Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
361       if (Default != Loc->end()) {
362         // Assume the entire range is covered by a single location.
363         ScopeBytesCovered = BytesInScope;
364         TotalBytesCovered = BytesInScope;
365       } else {
366         // Caller checks this Expected result already, it cannot fail.
367         auto ScopeRanges = cantFail(Die.getParent().getAddressRanges());
368         for (auto Entry : *Loc) {
369           TotalBytesCovered += Entry.Range->HighPC - Entry.Range->LowPC;
370           uint64_t ScopeBytesCoveredByEntry = 0;
371           // Calculate how many bytes of the parent scope this entry covers.
372           // FIXME: In section 2.6.2 of the DWARFv5 spec it says that "The
373           // address ranges defined by the bounded location descriptions of a
374           // location list may overlap". So in theory a variable can have
375           // multiple simultaneous locations, which would make this calculation
376           // misleading because we will count the overlapped areas
377           // twice. However, clang does not currently emit DWARF like this.
378           for (DWARFAddressRange R : ScopeRanges) {
379             ScopeBytesCoveredByEntry += calculateOverlap(*Entry.Range, R);
380           }
381           ScopeBytesCovered += ScopeBytesCoveredByEntry;
382           if (IsEntryValue(Entry.Expr))
383             BytesEntryValuesCovered += ScopeBytesCoveredByEntry;
384         }
385       }
386     }
387   }
388 
389   // Calculate the debug location statistics.
390   if (BytesInScope && !DeferLocStats) {
391     LocStats.NumVarParam.Value++;
392     if (IsParam)
393       LocStats.NumParam.Value++;
394     else if (IsLocalVar)
395       LocStats.NumVar.Value++;
396 
397     collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats,
398                     LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam,
399                     IsLocalVar);
400     // Non debug entry values coverage statistics.
401     collectLocStats(ScopeBytesCovered - BytesEntryValuesCovered, BytesInScope,
402                     LocStats.VarParamNonEntryValLocStats,
403                     LocStats.ParamNonEntryValLocStats,
404                     LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar);
405   }
406 
407   // Collect PC range coverage data.
408   if (DWARFDie D =
409           Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
410     Die = D;
411 
412   std::string VarID = constructDieID(Die, VarPrefix);
413   FnStats.VarsInFunction.insert(VarID);
414 
415   GlobalStats.TotalBytesCovered += TotalBytesCovered;
416   if (BytesInScope) {
417     GlobalStats.ScopeBytesCovered += ScopeBytesCovered;
418     GlobalStats.ScopeBytes += BytesInScope;
419     GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
420     if (IsParam) {
421       GlobalStats.ParamScopeBytesCovered += ScopeBytesCovered;
422       GlobalStats.ParamScopeBytes += BytesInScope;
423       GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
424     } else if (IsLocalVar) {
425       GlobalStats.LocalVarScopeBytesCovered += ScopeBytesCovered;
426       GlobalStats.LocalVarScopeBytes += BytesInScope;
427       GlobalStats.LocalVarScopeEntryValueBytesCovered +=
428           BytesEntryValuesCovered;
429     }
430     assert(GlobalStats.ScopeBytesCovered.Value <= GlobalStats.ScopeBytes.Value);
431   }
432 
433   if (IsConstantMember) {
434     FnStats.ConstantMembers++;
435     return;
436   }
437 
438   FnStats.TotalVarWithLoc += (unsigned)HasLoc;
439 
440   if (Die.find(dwarf::DW_AT_artificial)) {
441     FnStats.NumArtificial++;
442     return;
443   }
444 
445   if (IsParam) {
446     FnStats.NumParams++;
447     if (HasType)
448       FnStats.NumParamTypes++;
449     if (HasSrcLoc)
450       FnStats.NumParamSourceLocations++;
451     if (HasLoc)
452       FnStats.NumParamLocations++;
453   } else if (IsLocalVar) {
454     FnStats.NumLocalVars++;
455     if (HasType)
456       FnStats.NumLocalVarTypes++;
457     if (HasSrcLoc)
458       FnStats.NumLocalVarSourceLocations++;
459     if (HasLoc)
460       FnStats.NumLocalVarLocations++;
461   }
462 }
463 
464 /// Recursively collect variables from subprogram with DW_AT_inline attribute.
465 static void collectAbstractOriginFnInfo(
466     DWARFDie Die, uint64_t SPOffset,
467     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
468     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo) {
469   DWARFDie Child = Die.getFirstChild();
470   while (Child) {
471     const dwarf::Tag ChildTag = Child.getTag();
472     if (ChildTag == dwarf::DW_TAG_formal_parameter ||
473         ChildTag == dwarf::DW_TAG_variable) {
474       GlobalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
475       LocalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset());
476     } else if (ChildTag == dwarf::DW_TAG_lexical_block)
477       collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo,
478                                   LocalAbstractOriginFnInfo);
479     Child = Child.getSibling();
480   }
481 }
482 
483 /// Recursively collect debug info quality metrics.
484 static void collectStatsRecursive(
485     DWARFDie Die, std::string FnPrefix, std::string VarPrefix,
486     uint64_t BytesInScope, uint32_t InlineDepth,
487     StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats,
488     LocationStats &LocStats, FunctionDIECUTyMap &AbstractOriginFnCUs,
489     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
490     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
491     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed,
492     AbstractOriginVarsTy *AbstractOriginVarsPtr = nullptr) {
493   // Skip NULL nodes.
494   if (Die.isNULL())
495     return;
496 
497   const dwarf::Tag Tag = Die.getTag();
498   // Skip function types.
499   if (Tag == dwarf::DW_TAG_subroutine_type)
500     return;
501 
502   // Handle any kind of lexical scope.
503   const bool HasAbstractOrigin =
504       Die.find(dwarf::DW_AT_abstract_origin) != std::nullopt;
505   const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
506   const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
507   const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
508   // We want to know how many variables (with abstract_origin) don't have
509   // location info.
510   const bool IsCandidateForZeroLocCovTracking =
511       (IsInlinedFunction || (IsFunction && HasAbstractOrigin));
512 
513   AbstractOriginVarsTy AbstractOriginVars;
514 
515   // Get the vars of the inlined fn, so the locstats
516   // reports the missing vars (with coverage 0%).
517   if (IsCandidateForZeroLocCovTracking) {
518     auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin);
519     if (OffsetFn) {
520       uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue();
521       if (LocalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) {
522         AbstractOriginVars = LocalAbstractOriginFnInfo[OffsetOfInlineFnCopy];
523         AbstractOriginVarsPtr = &AbstractOriginVars;
524       } else {
525         // This means that the DW_AT_inline fn copy is out of order
526         // or that the abstract_origin references another CU,
527         // so this abstract origin instance will be processed later.
528         FnsWithAbstractOriginToBeProcessed.push_back(Die.getOffset());
529         AbstractOriginVarsPtr = nullptr;
530       }
531     }
532   }
533 
534   if (IsFunction || IsInlinedFunction || IsBlock) {
535     // Reset VarPrefix when entering a new function.
536     if (IsFunction || IsInlinedFunction)
537       VarPrefix = "v";
538 
539     // Ignore forward declarations.
540     if (Die.find(dwarf::DW_AT_declaration))
541       return;
542 
543     // Check for call sites.
544     if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
545       GlobalStats.CallSiteEntries++;
546 
547     // PC Ranges.
548     auto RangesOrError = Die.getAddressRanges();
549     if (!RangesOrError) {
550       llvm::consumeError(RangesOrError.takeError());
551       return;
552     }
553 
554     auto Ranges = RangesOrError.get();
555     uint64_t BytesInThisScope = 0;
556     for (auto Range : Ranges)
557       BytesInThisScope += Range.HighPC - Range.LowPC;
558 
559     // Count the function.
560     if (!IsBlock) {
561       // Skip over abstract origins, but collect variables
562       // from it so it can be used for location statistics
563       // for inlined instancies.
564       if (Die.find(dwarf::DW_AT_inline)) {
565         uint64_t SPOffset = Die.getOffset();
566         AbstractOriginFnCUs[SPOffset] = Die.getDwarfUnit();
567         collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo,
568                                     LocalAbstractOriginFnInfo);
569         return;
570       }
571 
572       std::string FnID = constructDieID(Die);
573       // We've seen an instance of this function.
574       auto &FnStats = FnStatMap[FnID];
575       FnStats.IsFunction = true;
576       if (IsInlinedFunction) {
577         FnStats.NumFnInlined++;
578         if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
579           FnStats.NumAbstractOrigins++;
580       } else {
581         FnStats.NumFnOutOfLine++;
582       }
583       if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
584           Die.findRecursively(dwarf::DW_AT_decl_line))
585         FnStats.HasSourceLocation = true;
586       // Update function prefix.
587       FnPrefix = FnID;
588     }
589 
590     if (BytesInThisScope) {
591       BytesInScope = BytesInThisScope;
592       if (IsFunction)
593         GlobalStats.FunctionSize += BytesInThisScope;
594       else if (IsInlinedFunction && InlineDepth == 0)
595         GlobalStats.InlineFunctionSize += BytesInThisScope;
596     }
597   } else {
598     // Not a scope, visit the Die itself. It could be a variable.
599     collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
600                        FnStatMap, GlobalStats, LocStats, AbstractOriginVarsPtr);
601   }
602 
603   // Set InlineDepth correctly for child recursion
604   if (IsFunction)
605     InlineDepth = 0;
606   else if (IsInlinedFunction)
607     ++InlineDepth;
608 
609   // Traverse children.
610   unsigned LexicalBlockIndex = 0;
611   unsigned FormalParameterIndex = 0;
612   DWARFDie Child = Die.getFirstChild();
613   while (Child) {
614     std::string ChildVarPrefix = VarPrefix;
615     if (Child.getTag() == dwarf::DW_TAG_lexical_block)
616       ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
617     if (Child.getTag() == dwarf::DW_TAG_formal_parameter)
618       ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.';
619 
620     collectStatsRecursive(
621         Child, FnPrefix, ChildVarPrefix, BytesInScope, InlineDepth, FnStatMap,
622         GlobalStats, LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
623         LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed,
624         AbstractOriginVarsPtr);
625     Child = Child.getSibling();
626   }
627 
628   if (!IsCandidateForZeroLocCovTracking)
629     return;
630 
631   // After we have processed all vars of the inlined function (or function with
632   // an abstract_origin), we want to know how many variables have no location.
633   for (auto Offset : AbstractOriginVars) {
634     LocStats.NumVarParam++;
635     LocStats.VarParamLocStats[ZeroCoverageBucket]++;
636     auto FnDie = Die.getDwarfUnit()->getDIEForOffset(Offset);
637     if (!FnDie)
638       continue;
639     auto Tag = FnDie.getTag();
640     if (Tag == dwarf::DW_TAG_formal_parameter) {
641       LocStats.NumParam++;
642       LocStats.ParamLocStats[ZeroCoverageBucket]++;
643     } else if (Tag == dwarf::DW_TAG_variable) {
644       LocStats.NumVar++;
645       LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
646     }
647   }
648 }
649 
650 /// Print human-readable output.
651 /// \{
652 static void printDatum(json::OStream &J, const char *Key, json::Value Value) {
653   if (Value == OverflowValue)
654     J.attribute(Key, "overflowed");
655   else
656     J.attribute(Key, Value);
657 
658   LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
659 }
660 
661 static void printLocationStats(json::OStream &J, const char *Key,
662                                std::vector<SaturatingUINT64> &LocationStats) {
663   if (LocationStats[0].Value == OverflowValue)
664     J.attribute((Twine(Key) +
665                  " with (0%,10%) of parent scope covered by DW_AT_location")
666                     .str(),
667                 "overflowed");
668   else
669     J.attribute(
670         (Twine(Key) + " with 0% of parent scope covered by DW_AT_location")
671             .str(),
672         LocationStats[0].Value);
673   LLVM_DEBUG(
674       llvm::dbgs() << Key
675                    << " with 0% of parent scope covered by DW_AT_location: \\"
676                    << LocationStats[0].Value << '\n');
677 
678   if (LocationStats[1].Value == OverflowValue)
679     J.attribute((Twine(Key) +
680                  " with (0%,10%) of parent scope covered by DW_AT_location")
681                     .str(),
682                 "overflowed");
683   else
684     J.attribute((Twine(Key) +
685                  " with (0%,10%) of parent scope covered by DW_AT_location")
686                     .str(),
687                 LocationStats[1].Value);
688   LLVM_DEBUG(llvm::dbgs()
689              << Key
690              << " with (0%,10%) of parent scope covered by DW_AT_location: "
691              << LocationStats[1].Value << '\n');
692 
693   for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
694     if (LocationStats[i].Value == OverflowValue)
695       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
696                    Twine(i * 10) +
697                    "%) of parent scope covered by DW_AT_location")
698                       .str(),
699                   "overflowed");
700     else
701       J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," +
702                    Twine(i * 10) +
703                    "%) of parent scope covered by DW_AT_location")
704                       .str(),
705                   LocationStats[i].Value);
706     LLVM_DEBUG(llvm::dbgs()
707                << Key << " with [" << (i - 1) * 10 << "%," << i * 10
708                << "%) of parent scope covered by DW_AT_location: "
709                << LocationStats[i].Value);
710   }
711   if (LocationStats[NumOfCoverageCategories - 1].Value == OverflowValue)
712     J.attribute(
713         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
714             .str(),
715         "overflowed");
716   else
717     J.attribute(
718         (Twine(Key) + " with 100% of parent scope covered by DW_AT_location")
719             .str(),
720         LocationStats[NumOfCoverageCategories - 1].Value);
721   LLVM_DEBUG(
722       llvm::dbgs() << Key
723                    << " with 100% of parent scope covered by DW_AT_location: "
724                    << LocationStats[NumOfCoverageCategories - 1].Value);
725 }
726 
727 static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) {
728   for (const auto &It : Sizes.DebugSectionSizes)
729     J.attribute((Twine("#bytes in ") + It.first).str(), int64_t(It.second));
730 }
731 
732 /// Stop tracking variables that contain abstract_origin with a location.
733 /// This is used for out-of-order DW_AT_inline subprograms only.
734 static void updateVarsWithAbstractOriginLocCovInfo(
735     DWARFDie FnDieWithAbstractOrigin,
736     AbstractOriginVarsTy &AbstractOriginVars) {
737   DWARFDie Child = FnDieWithAbstractOrigin.getFirstChild();
738   while (Child) {
739     const dwarf::Tag ChildTag = Child.getTag();
740     if ((ChildTag == dwarf::DW_TAG_formal_parameter ||
741          ChildTag == dwarf::DW_TAG_variable) &&
742         (Child.find(dwarf::DW_AT_location) ||
743          Child.find(dwarf::DW_AT_const_value))) {
744       auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin);
745       if (OffsetVar)
746         llvm::erase_value(AbstractOriginVars, (*OffsetVar).getRawUValue());
747     } else if (ChildTag == dwarf::DW_TAG_lexical_block)
748       updateVarsWithAbstractOriginLocCovInfo(Child, AbstractOriginVars);
749     Child = Child.getSibling();
750   }
751 }
752 
753 /// Collect zero location coverage for inlined variables which refer to
754 /// a DW_AT_inline copy of subprogram that is out of order in the DWARF.
755 /// Also cover the variables of a concrete function (represented with
756 /// the DW_TAG_subprogram) with an abstract_origin attribute.
757 static void collectZeroLocCovForVarsWithAbstractOrigin(
758     DWARFUnit *DwUnit, GlobalStats &GlobalStats, LocationStats &LocStats,
759     AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo,
760     FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed) {
761   // The next variable is used to filter out functions that have been processed,
762   // leaving FnsWithAbstractOriginToBeProcessed with just CrossCU references.
763   FunctionsWithAbstractOriginTy ProcessedFns;
764   for (auto FnOffset : FnsWithAbstractOriginToBeProcessed) {
765     DWARFDie FnDieWithAbstractOrigin = DwUnit->getDIEForOffset(FnOffset);
766     auto FnCopy = FnDieWithAbstractOrigin.find(dwarf::DW_AT_abstract_origin);
767     AbstractOriginVarsTy AbstractOriginVars;
768     if (!FnCopy)
769       continue;
770     uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
771     // If there is no entry within LocalAbstractOriginFnInfo for the given
772     // FnCopyRawUValue, function isn't out-of-order in DWARF. Rather, we have
773     // CrossCU referencing.
774     if (!LocalAbstractOriginFnInfo.count(FnCopyRawUValue))
775       continue;
776     AbstractOriginVars = LocalAbstractOriginFnInfo[FnCopyRawUValue];
777     updateVarsWithAbstractOriginLocCovInfo(FnDieWithAbstractOrigin,
778                                            AbstractOriginVars);
779 
780     for (auto Offset : AbstractOriginVars) {
781       LocStats.NumVarParam++;
782       LocStats.VarParamLocStats[ZeroCoverageBucket]++;
783       auto Tag = DwUnit->getDIEForOffset(Offset).getTag();
784       if (Tag == dwarf::DW_TAG_formal_parameter) {
785         LocStats.NumParam++;
786         LocStats.ParamLocStats[ZeroCoverageBucket]++;
787       } else if (Tag == dwarf::DW_TAG_variable) {
788         LocStats.NumVar++;
789         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
790       }
791     }
792     ProcessedFns.push_back(FnOffset);
793   }
794   for (auto ProcessedFn : ProcessedFns)
795     llvm::erase_value(FnsWithAbstractOriginToBeProcessed, ProcessedFn);
796 }
797 
798 /// Collect zero location coverage for inlined variables which refer to
799 /// a DW_AT_inline copy of subprogram that is in a different CU.
800 static void collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
801     LocationStats &LocStats, FunctionDIECUTyMap AbstractOriginFnCUs,
802     AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo,
803     CrossCUReferencingDIELocationTy &CrossCUReferencesToBeResolved) {
804   for (const auto &CrossCUReferenceToBeResolved :
805        CrossCUReferencesToBeResolved) {
806     DWARFUnit *DwUnit = CrossCUReferenceToBeResolved.DwUnit;
807     DWARFDie FnDIEWithCrossCUReferencing =
808         DwUnit->getDIEForOffset(CrossCUReferenceToBeResolved.DIEOffset);
809     auto FnCopy =
810         FnDIEWithCrossCUReferencing.find(dwarf::DW_AT_abstract_origin);
811     if (!FnCopy)
812       continue;
813     uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue();
814     AbstractOriginVarsTy AbstractOriginVars =
815         GlobalAbstractOriginFnInfo[FnCopyRawUValue];
816     updateVarsWithAbstractOriginLocCovInfo(FnDIEWithCrossCUReferencing,
817                                            AbstractOriginVars);
818     for (auto Offset : AbstractOriginVars) {
819       LocStats.NumVarParam++;
820       LocStats.VarParamLocStats[ZeroCoverageBucket]++;
821       auto Tag = (AbstractOriginFnCUs[FnCopyRawUValue])
822                      ->getDIEForOffset(Offset)
823                      .getTag();
824       if (Tag == dwarf::DW_TAG_formal_parameter) {
825         LocStats.NumParam++;
826         LocStats.ParamLocStats[ZeroCoverageBucket]++;
827       } else if (Tag == dwarf::DW_TAG_variable) {
828         LocStats.NumVar++;
829         LocStats.LocalVarLocStats[ZeroCoverageBucket]++;
830       }
831     }
832   }
833 }
834 
835 /// \}
836 
837 /// Collect debug info quality metrics for an entire DIContext.
838 ///
839 /// Do the impossible and reduce the quality of the debug info down to a few
840 /// numbers. The idea is to condense the data into numbers that can be tracked
841 /// over time to identify trends in newer compiler versions and gauge the effect
842 /// of particular optimizations. The raw numbers themselves are not particularly
843 /// useful, only the delta between compiling the same program with different
844 /// compilers is.
845 bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
846                                           const Twine &Filename,
847                                           raw_ostream &OS) {
848   StringRef FormatName = Obj.getFileFormatName();
849   GlobalStats GlobalStats;
850   LocationStats LocStats;
851   StringMap<PerFunctionStats> Statistics;
852   // This variable holds variable information for functions with
853   // abstract_origin globally, across all CUs.
854   AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo;
855   // This variable holds information about the CU of a function with
856   // abstract_origin.
857   FunctionDIECUTyMap AbstractOriginFnCUs;
858   CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
859   for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
860     if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
861       // This variable holds variable information for functions with
862       // abstract_origin, but just for the current CU.
863       AbstractOriginVarsTyMap LocalAbstractOriginFnInfo;
864       FunctionsWithAbstractOriginTy FnsWithAbstractOriginToBeProcessed;
865 
866       collectStatsRecursive(
867           CUDie, "/", "g", 0, 0, Statistics, GlobalStats, LocStats,
868           AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
869           LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
870 
871       // collectZeroLocCovForVarsWithAbstractOrigin will filter out all
872       // out-of-order DWARF functions that have been processed within it,
873       // leaving FnsWithAbstractOriginToBeProcessed with only CrossCU
874       // references.
875       collectZeroLocCovForVarsWithAbstractOrigin(
876           CUDie.getDwarfUnit(), GlobalStats, LocStats,
877           LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed);
878 
879       // Collect all CrossCU references into CrossCUReferencesToBeResolved.
880       for (auto CrossCUReferencingDIEOffset :
881            FnsWithAbstractOriginToBeProcessed)
882         CrossCUReferencesToBeResolved.push_back(
883             DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset));
884     }
885   }
886 
887   /// Resolve CrossCU references.
888   collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
889       LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
890       CrossCUReferencesToBeResolved);
891 
892   /// Collect the sizes of debug sections.
893   SectionSizes Sizes;
894   calculateSectionSizes(Obj, Sizes, Filename);
895 
896   /// The version number should be increased every time the algorithm is changed
897   /// (including bug fixes). New metrics may be added without increasing the
898   /// version.
899   unsigned Version = 9;
900   SaturatingUINT64 VarParamTotal = 0;
901   SaturatingUINT64 VarParamUnique = 0;
902   SaturatingUINT64 VarParamWithLoc = 0;
903   SaturatingUINT64 NumFunctions = 0;
904   SaturatingUINT64 NumInlinedFunctions = 0;
905   SaturatingUINT64 NumFuncsWithSrcLoc = 0;
906   SaturatingUINT64 NumAbstractOrigins = 0;
907   SaturatingUINT64 ParamTotal = 0;
908   SaturatingUINT64 ParamWithType = 0;
909   SaturatingUINT64 ParamWithLoc = 0;
910   SaturatingUINT64 ParamWithSrcLoc = 0;
911   SaturatingUINT64 LocalVarTotal = 0;
912   SaturatingUINT64 LocalVarWithType = 0;
913   SaturatingUINT64 LocalVarWithSrcLoc = 0;
914   SaturatingUINT64 LocalVarWithLoc = 0;
915   for (auto &Entry : Statistics) {
916     PerFunctionStats &Stats = Entry.getValue();
917     uint64_t TotalVars = Stats.VarsInFunction.size() *
918                          (Stats.NumFnInlined + Stats.NumFnOutOfLine);
919     // Count variables in global scope.
920     if (!Stats.IsFunction)
921       TotalVars =
922           Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial;
923     uint64_t Constants = Stats.ConstantMembers;
924     VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
925     VarParamTotal += TotalVars;
926     VarParamUnique += Stats.VarsInFunction.size();
927     LLVM_DEBUG(for (auto &V
928                     : Stats.VarsInFunction) llvm::dbgs()
929                << Entry.getKey() << ": " << V.getKey() << "\n");
930     NumFunctions += Stats.IsFunction;
931     NumFuncsWithSrcLoc += Stats.HasSourceLocation;
932     NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
933     NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
934     ParamTotal += Stats.NumParams;
935     ParamWithType += Stats.NumParamTypes;
936     ParamWithLoc += Stats.NumParamLocations;
937     ParamWithSrcLoc += Stats.NumParamSourceLocations;
938     LocalVarTotal += Stats.NumLocalVars;
939     LocalVarWithType += Stats.NumLocalVarTypes;
940     LocalVarWithLoc += Stats.NumLocalVarLocations;
941     LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations;
942   }
943 
944   // Print summary.
945   OS.SetBufferSize(1024);
946   json::OStream J(OS, 2);
947   J.objectBegin();
948   J.attribute("version", Version);
949   LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
950              llvm::dbgs() << "---------------------------------\n");
951 
952   printDatum(J, "file", Filename.str());
953   printDatum(J, "format", FormatName);
954 
955   printDatum(J, "#functions", NumFunctions.Value);
956   printDatum(J, "#functions with location", NumFuncsWithSrcLoc.Value);
957   printDatum(J, "#inlined functions", NumInlinedFunctions.Value);
958   printDatum(J, "#inlined functions with abstract origins",
959              NumAbstractOrigins.Value);
960 
961   // This includes local variables and formal parameters.
962   printDatum(J, "#unique source variables", VarParamUnique.Value);
963   printDatum(J, "#source variables", VarParamTotal.Value);
964   printDatum(J, "#source variables with location", VarParamWithLoc.Value);
965 
966   printDatum(J, "#call site entries", GlobalStats.CallSiteEntries.Value);
967   printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs.Value);
968   printDatum(J, "#call site parameter DIEs",
969              GlobalStats.CallSiteParamDIEs.Value);
970 
971   printDatum(J, "sum_all_variables(#bytes in parent scope)",
972              GlobalStats.ScopeBytes.Value);
973   printDatum(J,
974              "sum_all_variables(#bytes in any scope covered by DW_AT_location)",
975              GlobalStats.TotalBytesCovered.Value);
976   printDatum(J,
977              "sum_all_variables(#bytes in parent scope covered by "
978              "DW_AT_location)",
979              GlobalStats.ScopeBytesCovered.Value);
980   printDatum(J,
981              "sum_all_variables(#bytes in parent scope covered by "
982              "DW_OP_entry_value)",
983              GlobalStats.ScopeEntryValueBytesCovered.Value);
984 
985   printDatum(J, "sum_all_params(#bytes in parent scope)",
986              GlobalStats.ParamScopeBytes.Value);
987   printDatum(J,
988              "sum_all_params(#bytes in parent scope covered by DW_AT_location)",
989              GlobalStats.ParamScopeBytesCovered.Value);
990   printDatum(J,
991              "sum_all_params(#bytes in parent scope covered by "
992              "DW_OP_entry_value)",
993              GlobalStats.ParamScopeEntryValueBytesCovered.Value);
994 
995   printDatum(J, "sum_all_local_vars(#bytes in parent scope)",
996              GlobalStats.LocalVarScopeBytes.Value);
997   printDatum(J,
998              "sum_all_local_vars(#bytes in parent scope covered by "
999              "DW_AT_location)",
1000              GlobalStats.LocalVarScopeBytesCovered.Value);
1001   printDatum(J,
1002              "sum_all_local_vars(#bytes in parent scope covered by "
1003              "DW_OP_entry_value)",
1004              GlobalStats.LocalVarScopeEntryValueBytesCovered.Value);
1005 
1006   printDatum(J, "#bytes within functions", GlobalStats.FunctionSize.Value);
1007   printDatum(J, "#bytes within inlined functions",
1008              GlobalStats.InlineFunctionSize.Value);
1009 
1010   // Print the summary for formal parameters.
1011   printDatum(J, "#params", ParamTotal.Value);
1012   printDatum(J, "#params with source location", ParamWithSrcLoc.Value);
1013   printDatum(J, "#params with type", ParamWithType.Value);
1014   printDatum(J, "#params with binary location", ParamWithLoc.Value);
1015 
1016   // Print the summary for local variables.
1017   printDatum(J, "#local vars", LocalVarTotal.Value);
1018   printDatum(J, "#local vars with source location", LocalVarWithSrcLoc.Value);
1019   printDatum(J, "#local vars with type", LocalVarWithType.Value);
1020   printDatum(J, "#local vars with binary location", LocalVarWithLoc.Value);
1021 
1022   // Print the debug section sizes.
1023   printSectionSizes(J, Sizes);
1024 
1025   // Print the location statistics for variables (includes local variables
1026   // and formal parameters).
1027   printDatum(J, "#variables processed by location statistics",
1028              LocStats.NumVarParam.Value);
1029   printLocationStats(J, "#variables", LocStats.VarParamLocStats);
1030   printLocationStats(J, "#variables - entry values",
1031                      LocStats.VarParamNonEntryValLocStats);
1032 
1033   // Print the location statistics for formal parameters.
1034   printDatum(J, "#params processed by location statistics",
1035              LocStats.NumParam.Value);
1036   printLocationStats(J, "#params", LocStats.ParamLocStats);
1037   printLocationStats(J, "#params - entry values",
1038                      LocStats.ParamNonEntryValLocStats);
1039 
1040   // Print the location statistics for local variables.
1041   printDatum(J, "#local vars processed by location statistics",
1042              LocStats.NumVar.Value);
1043   printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
1044   printLocationStats(J, "#local vars - entry values",
1045                      LocStats.LocalVarNonEntryValLocStats);
1046   J.objectEnd();
1047   OS << '\n';
1048   LLVM_DEBUG(
1049       llvm::dbgs() << "Total Availability: "
1050                    << (VarParamTotal.Value
1051                            ? (int)std::round((VarParamWithLoc.Value * 100.0) /
1052                                              VarParamTotal.Value)
1053                            : 0)
1054                    << "%\n";
1055       llvm::dbgs() << "PC Ranges covered: "
1056                    << (GlobalStats.ScopeBytes.Value
1057                            ? (int)std::round(
1058                                  (GlobalStats.ScopeBytesCovered.Value * 100.0) /
1059                                  GlobalStats.ScopeBytes.Value)
1060                            : 0)
1061                    << "%\n");
1062   return true;
1063 }
1064