Index: llvm/tools/llvm-dwarfdump/CMakeLists.txt =================================================================== --- llvm/tools/llvm-dwarfdump/CMakeLists.txt +++ llvm/tools/llvm-dwarfdump/CMakeLists.txt @@ -9,6 +9,7 @@ add_llvm_tool(llvm-dwarfdump Statistics.cpp + SectionsSizes.cpp llvm-dwarfdump.cpp ) Index: llvm/tools/llvm-dwarfdump/SectionsSizes.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-dwarfdump/SectionsSizes.cpp @@ -0,0 +1,167 @@ +//===- SectionsSizes.cpp ---------------------------------------- *- C++ *-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/WithColor.h" + +#define DEBUG_TYPE "dwarfdump" +using namespace llvm; +using namespace object; + +/// Holds cumulative section sizes for an object file. +struct SectionsSizes { + /// Total number of bytes of the object file. + /// This includes .text,.data, .bss and all .debug_* sections. + uint64_t TotalObjectSize = 0; + /// Total number of bytes of all .debug_* sections. + uint64_t TotalDebugSectionsSize = 0; + /// Total number of bytes of the .debug_info section. + uint64_t TotalDebugInfo = 0; + /// Total number of bytes of the .debug_str section. + uint64_t TotalDebugStr = 0; + /// Total number of bytes of the .debug_abbrev section. + uint64_t TotalDebugAbbrev = 0; + /// Total number of bytes of the .debug_line section. + uint64_t TotalDebugLine = 0; + /// Total number of bytes of the .debug_ranges section. + uint64_t TotalDebugRanges = 0; + /// Total number of bytes of the .debug_loc section. + uint64_t TotalDebugLoc = 0; +}; + +static void prettyPrintTheSecsSizes(const ObjectFile &Obj, + const SectionsSizes &Sizes, + raw_ostream &OS) { + OS << "----------------------------------------------------" + << "\n"; + OS << " SECTION \t\t" + << " SIZE" + << "\n"; + OS << "------------ \t\t ------------\n"; + + OS << " .debug_info \t\t " << Sizes.TotalDebugInfo << "\n"; + OS << " .debug_str \t\t " << Sizes.TotalDebugStr << "\n"; + OS << " .debug_abbrev \t\t " << Sizes.TotalDebugAbbrev << "\n"; + OS << " .debug_line \t\t " << Sizes.TotalDebugLine << "\n"; + OS << " .debug_ranges \t\t " << Sizes.TotalDebugRanges << "\n"; + OS << " .debug_loc \t\t " << Sizes.TotalDebugLoc << "\n\n"; + OS << " .debug_*: \t\t " << Sizes.TotalDebugSectionsSize << "\n"; + OS << "----------------------------------------------------" + << "\n"; + OS << " TOTAL: " << Sizes.TotalObjectSize << "\n"; + OS << "----------------------------------------------------" + << "\n"; +} + +static bool isDebugInfo(StringRef SectionName) { + if (SectionName == ".debug_info") + return true; + return false; +} + +static bool isDebugStr(StringRef SectionName) { + if (SectionName == ".debug_str") + return true; + return false; +} + +static bool isDebugAbbrev(StringRef SectionName) { + if (SectionName == ".debug_abbrev") + return true; + return false; +} + +static bool isDebugLine(StringRef SectionName) { + if (SectionName == ".debug_line") + return true; + return false; +} + +static bool isDebugRanges(StringRef SectionName) { + if (SectionName == ".debug_ranges") + return true; + return false; +} + +static bool isDebugLoc(StringRef SectionName) { + if (SectionName == ".debug_loc") + return true; + return false; +} + +static bool isDebugSection(StringRef SectionName) { + if (isDebugInfo(SectionName) || isDebugStr(SectionName) || + isDebugAbbrev(SectionName) || isDebugLine(SectionName) || + isDebugRanges(SectionName) || isDebugLoc(SectionName)) + return true; + return false; +} + +static bool calculateSizes(const ObjectFile &Obj, SectionsSizes &Sizes) { + for (const SectionRef &Section : Obj.sections()) { + StringRef SectionName; + if (Expected NameOrErr = Section.getName()) { + SectionName = *NameOrErr; + } else { + consumeError(NameOrErr.takeError()); + return false; + } + + LLVM_DEBUG(dbgs() << SectionName.str() << ": " << Section.getSize()); + + if (Section.isBerkeleyText() || Section.isBerkeleyData() || + Section.isBSS() || isDebugSection(SectionName)) + Sizes.TotalObjectSize += Section.getSize(); + + if (isDebugSection(SectionName)) + Sizes.TotalDebugSectionsSize += Section.getSize(); + + if (SectionName == ".debug_info") { + Sizes.TotalDebugInfo += Section.getSize(); + } else if (SectionName == ".debug_str") { + Sizes.TotalDebugStr += Section.getSize(); + } else if (SectionName == ".debug_abbrev") { + Sizes.TotalDebugAbbrev += Section.getSize(); + } else if (SectionName == ".debug_line") { + Sizes.TotalDebugLine += Section.getSize(); + } else if (SectionName == ".debug_ranges") { + Sizes.TotalDebugRanges += Section.getSize(); + } else if (SectionName == ".debug_loc") { + Sizes.TotalDebugLoc += Section.getSize(); + } + } + + return true; +} + +bool collectSecsSizesForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, + Twine Filename, raw_ostream &OS) { + SectionsSizes Sizes; + if (!calculateSizes(Obj, Sizes)) { + WithColor::error() << " \n"; + exit(1); + } + + OS << "----------------------------------------------------" + << "\n"; + OS << Filename.str() << ": file format " << Obj.getFileFormatName() << "\n"; + + uint64_t TotalCUs = 0; + for (const auto &CU : static_cast(&DICtx)->compile_units()) { + (void)CU; + ++TotalCUs; + } + + LLVM_DEBUG(dbgs() << "Total num of compile units: " << TotalCUs << "\n"); + + prettyPrintTheSecsSizes(Obj, Sizes, OS); + + return true; +} Index: llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp =================================================================== --- llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -208,6 +208,10 @@ Statistics("statistics", cl::desc("Emit JSON-formatted debug info quality metrics."), cat(DwarfDumpCategory)); +static cl::opt + ShowSecSizes("show-sections-sizes", + cl::desc("Show the sizes of the .debug_* sections."), + cat(DwarfDumpCategory)); static opt Verify("verify", desc("Verify the DWARF debug info."), cat(DwarfDumpCategory)); static opt Quiet("quiet", desc("Use with -verify to not emit to STDOUT."), @@ -413,6 +417,9 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename, raw_ostream &OS); +bool collectSecsSizesForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, + Twine Filename, raw_ostream &OS); + static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, Twine Filename, raw_ostream &OS) { logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(), @@ -635,12 +642,16 @@ return handleFile(Object, verifyObjectFile, OutputFile.os()); })) return 1; - } else if (Statistics) + } else if (Statistics) { for (auto Object : Objects) handleFile(Object, collectStatsForObjectFile, OutputFile.os()); - else + } else if (ShowSecSizes) { + for (auto Object : Objects) + handleFile(Object, collectSecsSizesForObjectFile, OutputFile.os()); + } else { for (auto Object : Objects) handleFile(Object, dumpObjectFile, OutputFile.os()); + } return EXIT_SUCCESS; }