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