diff --git a/llvm/docs/CommandGuide/llvm-dwarfdump.rst b/llvm/docs/CommandGuide/llvm-dwarfdump.rst --- a/llvm/docs/CommandGuide/llvm-dwarfdump.rst +++ b/llvm/docs/CommandGuide/llvm-dwarfdump.rst @@ -105,6 +105,10 @@ When displaying debug info entries, only show children to a maximum depth of . +.. option:: --show-section-sizes + + Show the sizes of all debug sections, expressed in bytes. + .. option:: --statistics Collect debug info quality metrics and print the results diff --git a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/i386_macho_with_debug.yaml b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/i386_macho_with_debug.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/i386_macho_with_debug.yaml @@ -0,0 +1,88 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACE + cputype: 0x00000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 312 + flags: 0x00002000 +LoadCommands: + - cmd: LC_SEGMENT + cmdsize: 192 + segname: '' + vmaddr: 0 + vmsize: 72 + fileoff: 340 + filesize: 72 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 18 + offset: 0x00000154 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x0000000000000014 + size: 52 + offset: 0x00000168 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 656384 + sdk: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 412 + nsyms: 1 + stroff: 424 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... diff --git a/llvm/test/tools/llvm-dwarfdump/X86/Inputs/x86_64_macho_with_debug.yaml b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/x86_64_macho_with_debug.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/Inputs/x86_64_macho_with_debug.yaml @@ -0,0 +1,89 @@ +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 352 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 80 + fileoff: 384 + filesize: 80 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 15 + offset: 0x00000180 + align: 4 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __debug_info + segname: __DWARF + addr: 0x0000000000000010 + size: 64 + offset: 0x00000190 + align: 3 + reloff: 0x00000000 + nreloc: 0 + flags: 0x6800000B + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_VERSION_MIN_MACOSX + cmdsize: 16 + version: 656384 + sdk: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 464 + nsyms: 1 + stroff: 480 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 0 + iextdefsym: 0 + nextdefsym: 1 + iundefsym: 1 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - '' +... diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_archive.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_archive.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_archive.test @@ -0,0 +1,66 @@ +## Check how llvm-dwarfdump calculates section sizes +## with --show-section-sizes on an archive. + +# RUN: rm -rf %t && mkdir -p %t +# RUN: yaml2obj --docnum=1 %s -o %t/1.o +# RUN: yaml2obj --docnum=2 %s -o %t/2.o + +# RUN: rm -f %t.a +# RUN: llvm-ar rc %t.a %t/1.o %t/2.o + +# RUN: llvm-dwarfdump --show-section-sizes %t.a \ +# RUN: | FileCheck %s -DARCHIVE=%t.a --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: [[ARCHIVE]](1.o) +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:----------- -------- +# CHECK-NEXT:.debug_info 17 (3.17%) +# CHECK-NEXT:.debug_line 19 (3.54%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 36 (6.72%) +# CHECK-NEXT: Total File Size: 536 +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:file: [[ARCHIVE]](2.o) +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:----------- -------- +# CHECK-NEXT:.debug_loc 1 (0.20%) +# CHECK-NEXT:.debug_line 13 (2.54%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 14 (2.73%) +# CHECK-NEXT: Total File Size: 512 +# CHECK-NEXT:---------------------------------------------------- + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: +- Name: .text1 + Type: SHT_PROGBITS +- Name: .debug_info + Type: SHT_PROGBITS + Size: 17 +- Name: .debug_line + Type: SHT_PROGBITS + Size: 19 +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: +- Name: .text2 + Type: SHT_PROGBITS +- Name: .debug_loc + Type: SHT_PROGBITS + Size: 1 +- Name: .debug_line + Type: SHT_PROGBITS + Size: 13 diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_coff.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_coff.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_coff.test @@ -0,0 +1,43 @@ +## Check how llvm-dwarfdump calculates section sizes +## with --show-section-sizes for COFF objects. + +# RUN: yaml2obj %s | llvm-dwarfdump - --show-section-sizes \ +# RUN: | FileCheck %s --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: {{.*}} +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:------------- -------- +# CHECK-NEXT:.debug_info 2 (0.70%) +# CHECK-NEXT:.debug_abbrev 1 (0.35%) +# CHECK-NEXT:.debug_str 1 (0.35%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 4 (1.40%) +# CHECK-NEXT: Total File Size: 286 +# CHECK-NEXT:---------------------------------------------------- + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 +sections: + - Name: .bss + Characteristics: [] + SectionData: '' + - Name: .debug_str + Characteristics: [] + SectionData: 00 + - Name: .debug_abbrev + Characteristics: [] + Alignment: 1 + SectionData: 00 + - Name: .debug_info + Characteristics: [] + SectionData: 1111 +## This is a debug section following the Mach-O naming style, and is used +## to show that such sections are not included in the report. + - Name: __debug_foo + Characteristics: [] + SectionData: 00 +symbols: +... diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_elf.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_elf.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_elf.test @@ -0,0 +1,55 @@ +## Check how llvm-dwarfdump calculates section sizes +## with --show-section-sizes for ELF objects. + +# RUN: yaml2obj %s | llvm-dwarfdump - --show-section-sizes \ +# RUN: | FileCheck %s --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: {{.*}} +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:--------------- -------- +# CHECK-NEXT:.debug_info 17 (1.62%) +# CHECK-NEXT:.debug_loc 1 (0.10%) +# CHECK-NEXT:.debug_type 26 (2.48%) +# CHECK-NEXT:.debug_foo 100 (9.54%) +# CHECK-NEXT:.debug_info.dwo 9 (0.86%) +# CHECK-NEXT:.debug_line 19 (1.81%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 172 (16.41%) +# CHECK-NEXT: Total File Size: 1048 +# CHECK-NEXT:---------------------------------------------------- + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .debug_info + Type: SHT_PROGBITS + Size: 17 + - Name: .debug_line + Type: SHT_PROGBITS + Size: 19 + - Name: .debug_loc + Type: SHT_PROGBITS + Size: 1 + - Name: .debug_type + Type: SHT_PROGBITS + Size: 13 + - Name: .debug_type [1] + Type: SHT_PROGBITS + Size: 13 + - Name: .debug_foo + Type: SHT_PROGBITS + Size: 100 + - Name: .debug_info.dwo + Type: SHT_PROGBITS + Size: 9 +## This is a debug section following the Mach-O naming style, and is used +## to show that such sections are not included in the report. + - Name: __debug_bar + Type: SHT_PROGBITS + Size: 1 diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_fat_binary.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_fat_binary.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_fat_binary.test @@ -0,0 +1,31 @@ +## Check how llvm-dwarfdump calculates section sizes +## with --show-section-sizes on a fat binary. + +# RUN: yaml2obj %p/Inputs/i386_macho_with_debug.yaml -o %t-i386.o +# RUN: yaml2obj %p/Inputs/x86_64_macho_with_debug.yaml -o %t-x86_64.o + +# RUN: llvm-lipo %t-i386.o %t-x86_64.o -create -output %t.o + +# RUN: llvm-dwarfdump --show-section-sizes %t.o \ +# RUN: | FileCheck %s -DFILE=%t.o --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: [[FILE]](i386) +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:------------ -------- +# CHECK-NEXT:__debug_info 52 (12.04%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 52 (12.04%) +# CHECK-NEXT: Total File Size: 432 +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:file: [[FILE]](x86_64) +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:------------ -------- +# CHECK-NEXT:__debug_info 64 (13.11%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 64 (13.11%) +# CHECK-NEXT: Total File Size: 488 +# CHECK-NEXT:---------------------------------------------------- diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_macho.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_macho.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_macho.test @@ -0,0 +1,106 @@ +## Check how llvm-dwarfdump calculates section sizes +## with --show-section-sizes for Mach-O objects. + +# RUN: yaml2obj %s | llvm-dwarfdump - --show-section-sizes \ +# RUN: | FileCheck %s --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: {{.*}} +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:------------ -------- +# CHECK-NEXT:__debug_info 4 (0.93%) +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 4 (0.93%) +# CHECK-NEXT: Total File Size: 432 +# CHECK-NEXT:---------------------------------------------------- + +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x01000007 + cpusubtype: 0x00000003 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 360 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 4 + fileoff: 392 + filesize: 0 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: +## This is a debug section following the ELF naming style, and is used +## to show that such sections are not included in the report. + - sectname: .debug_line + segname: __DWARF + addr: 0x0000000000000000 + size: 0 + offset: 0x00000188 + align: 0 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + content: '' + - sectname: __debug_info + segname: __DWARF + addr: 0x0000000000000000 + size: 4 + offset: 0x00000000 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x00000001 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 658944 + sdk: 658944 + ntools: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 392 + nsyms: 2 + stroff: 424 + strsize: 8 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 1 + iextdefsym: 1 + nextdefsym: 0 + iundefsym: 1 + nundefsym: 1 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + StringTable: + - '' + - _b + - _a + - '' +... diff --git a/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_no_debug_sections.test b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_no_debug_sections.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/section_sizes_no_debug_sections.test @@ -0,0 +1,29 @@ +## Check how llvm-dwarfdump calculates section sizes with +## --show-section-sizes in the case there isn't any debug section. + +# RUN: yaml2obj %s | llvm-dwarfdump - --show-section-sizes \ +# RUN: | FileCheck %s --match-full-lines --strict-whitespace + +# CHECK:---------------------------------------------------- +# CHECK-NEXT:file: {{.*}} +# CHECK-NEXT:---------------------------------------------------- +# CHECK-NEXT:SECTION SIZE (b) +# CHECK-NEXT:------- -------- +# CHECK-EMPTY: +# CHECK-NEXT: Total Size: 0 (0.00%) +# CHECK-NEXT: Total File Size: 456 +# CHECK-NEXT:---------------------------------------------------- + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .foo + Type: SHT_PROGBITS + Size: 17 + - Name: .bar + Type: SHT_PROGBITS + Size: 19 diff --git a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll --- a/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll +++ b/llvm/test/tools/llvm-dwarfdump/X86/statistics.ll @@ -48,7 +48,11 @@ ; CHECK: "scope bytes covered": ; CHECK: "total function size":[[FUNCSIZE:[0-9]+]] ; CHECK: "total inlined function size":[[INLINESIZE:[0-9]+]] - +; CHECK: "size of __debug_info":380 +; CHECK: "size of __debug_loc":35 +; CHECK: "size of __debug_abbrev":303 +; CHECK: "size of __debug_line":117 +; CHECK: "size of __debug_str":204 ; ModuleID = '/tmp/quality.cpp' source_filename = "/tmp/quality.cpp" diff --git a/llvm/tools/llvm-dwarfdump/CMakeLists.txt b/llvm/tools/llvm-dwarfdump/CMakeLists.txt --- a/llvm/tools/llvm-dwarfdump/CMakeLists.txt +++ b/llvm/tools/llvm-dwarfdump/CMakeLists.txt @@ -8,6 +8,7 @@ ) add_llvm_tool(llvm-dwarfdump + SectionSizes.cpp Statistics.cpp llvm-dwarfdump.cpp ) diff --git a/llvm/tools/llvm-dwarfdump/SectionSizes.h b/llvm/tools/llvm-dwarfdump/SectionSizes.h new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-dwarfdump/SectionSizes.h @@ -0,0 +1,38 @@ +//===- SectionSizes.h - Debug section sizes ---------------------*- 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 +// +//===-----------------------------------------------------------------------===/ + +#ifndef LLVM_TOOLS_SECTION_SIZES_H +#define LLVM_TOOLS_SECTION_SIZES_H + +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/WithColor.h" + +namespace llvm { + +using SectionSizeMap = StringMap; + +/// Holds cumulative section sizes for an object file. +struct SectionSizes { + /// Map of .debug section names and their sizes across all such-named + /// sections. + SectionSizeMap DebugSectionSizes; + /// Total number of bytes of all sections. + uint64_t TotalObjectSize = 0; + /// Total number of bytes of all debug sections. + uint64_t TotalDebugSectionsSize = 0; +}; + +/// Calculate the section sizes. +void calculateSectionSizes(const object::ObjectFile &Obj, SectionSizes &Sizes, + const Twine &Filename); + +} // end namespace llvm + +#endif // LLVM_TOOLS_SECTION_SIZES_H diff --git a/llvm/tools/llvm-dwarfdump/SectionSizes.cpp b/llvm/tools/llvm-dwarfdump/SectionSizes.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-dwarfdump/SectionSizes.cpp @@ -0,0 +1,120 @@ +//===-- SectionSizes.cpp - Debug section sizes ----------------------------===// +// +// 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 "SectionSizes.h" + +#define DEBUG_TYPE "dwarfdump" + +using namespace llvm; +using namespace object; + +static size_t getNameColumnWidth(const SectionSizes &Sizes, + const StringRef SectionNameTitle) { + // The minimum column width should be the size of "SECTION". + size_t Width = SectionNameTitle.size(); + for (const auto &DebugSec : Sizes.DebugSectionSizes) { + StringRef SectionName = DebugSec.getKey(); + Width = std::max(Width, SectionName.size()); + } + return Width; +} + +static size_t getSizeColumnWidth(const SectionSizes &Sizes, + const StringRef SectionSizeTitle) { + // The minimum column width should be the size of the column title. + size_t Width = SectionSizeTitle.size(); + for (const auto &DebugSec : Sizes.DebugSectionSizes) { + size_t NumWidth = std::to_string(DebugSec.getValue()).size(); + Width = std::max(Width, NumWidth); + } + return Width; +} + +static void prettyPrintSectionSizes(const ObjectFile &Obj, + const SectionSizes &Sizes, + raw_ostream &OS) { + const StringRef SectionNameTitle = "SECTION"; + const StringRef SectionSizeTitle = "SIZE (b)"; + + size_t NameColWidth = getNameColumnWidth(Sizes, SectionNameTitle); + size_t SizeColWidth = getSizeColumnWidth(Sizes, SectionSizeTitle); + + OS << "----------------------------------------------------" << '\n'; + OS << SectionNameTitle; + size_t SectionNameTitleWidth = SectionNameTitle.size(); + for (unsigned i = 0; i < (NameColWidth - SectionNameTitleWidth) + 2; i++) + OS << " "; + OS << SectionSizeTitle << '\n'; + for (unsigned i = 0; i < NameColWidth; i++) + OS << "-"; + OS << " "; + + for (unsigned i = 0; i < SizeColWidth; i++) + OS << "-"; + OS << '\n'; + + for (const auto &DebugSec : Sizes.DebugSectionSizes) { + OS << left_justify(DebugSec.getKey(), NameColWidth) << " "; + + auto NumBytes = std::to_string(DebugSec.getValue()); + OS << right_justify(NumBytes, SizeColWidth) << " (" + << format("%0.2f", DebugSec.getValue() / + static_cast(Sizes.TotalObjectSize) * 100) + << "%)\n"; + } + + OS << '\n'; + OS << " Total Size: " << Sizes.TotalDebugSectionsSize << " (" + << format("%0.2f", Sizes.TotalDebugSectionsSize / + static_cast(Sizes.TotalObjectSize) * 100) + << "%)\n"; + OS << " Total File Size: " << Sizes.TotalObjectSize << '\n'; + OS << "----------------------------------------------------" << '\n'; +} + +void llvm::calculateSectionSizes(const ObjectFile &Obj, SectionSizes &Sizes, + const Twine &Filename) { + // Get total size. + Sizes.TotalObjectSize = Obj.getData().size(); + + for (const SectionRef &Section : Obj.sections()) { + StringRef SectionName; + if (Expected NameOrErr = Section.getName()) + SectionName = *NameOrErr; + else + WithColor::defaultWarningHandler( + createFileError(Filename, NameOrErr.takeError())); + + LLVM_DEBUG(dbgs() << SectionName.str() << ": " << Section.getSize() + << '\n'); + + if (!Section.isDebugSection(SectionName)) + continue; + + Sizes.TotalDebugSectionsSize += Section.getSize(); + Sizes.DebugSectionSizes[SectionName] += Section.getSize(); + } +} + +bool collectObjectSectionSizes(ObjectFile &Obj, DWARFContext & /*DICtx*/, + const Twine &Filename, raw_ostream &OS) { + SectionSizes Sizes; + + // Get the section sizes. + calculateSectionSizes(Obj, Sizes, Filename); + + OS << "----------------------------------------------------\n"; + OS << "file: " << Filename.str() << '\n'; + + prettyPrintSectionSizes(Obj, Sizes, OS); + + // TODO: If the input file is an archive, print the cumulative summary of all + // files from the archive. + + return true; +} diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp --- a/llvm/tools/llvm-dwarfdump/Statistics.cpp +++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp @@ -15,6 +15,8 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/JSON.h" +#include "SectionSizes.h" + #define DEBUG_TYPE "dwarfdump" using namespace llvm; using namespace object; @@ -468,6 +470,7 @@ OS << ",\"" << Key << "\":" << Value; LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); } + static void printLocationStats(raw_ostream &OS, const char *Key, std::vector &LocationStats) { @@ -491,6 +494,12 @@ LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: " << LocationStats[NumOfCoverageCategories - 1]); } + +static void printSectionSizes(raw_ostream &OS, const SectionSizes &Sizes) { + for (const auto &DebugSec : Sizes.DebugSectionSizes) + OS << ",\"size of " << DebugSec.getKey() << "\":" << DebugSec.getValue(); +} + /// \} /// Collect debug info quality metrics for an entire DIContext. @@ -512,6 +521,10 @@ collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats, LocStats); + /// Collect the sizes of debug sections. + SectionSizes Sizes; + calculateSectionSizes(Obj, Sizes, Filename); + /// The version number should be increased every time the algorithm is changed /// (including bug fixes). New metrics may be added without increasing the /// version. @@ -602,6 +615,7 @@ printDatum(OS, "vars with binary location", VarWithLoc); printDatum(OS, "total variables procesed by location statistics", LocStats.NumVarParam); + printSectionSizes(OS, Sizes); printLocationStats(OS, "variables", LocStats.VarParamLocStats); printLocationStats(OS, "variables (excluding the debug entry values)", LocStats.VarParamNonEntryValLocStats); diff --git a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp --- a/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -208,6 +208,11 @@ Statistics("statistics", cl::desc("Emit JSON-formatted debug info quality metrics."), cat(DwarfDumpCategory)); +static cl::opt + ShowSectionSizes("show-section-sizes", + cl::desc("Show the sizes of all debug sections, " + "expressed in bytes."), + 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 +418,9 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, const Twine &Filename, raw_ostream &OS); +bool collectObjectSectionSizes(ObjectFile &Obj, DWARFContext & /*DICtx*/, + const Twine &Filename, raw_ostream &OS); + static bool dumpObjectFile(ObjectFile &Obj, DWARFContext &DICtx, const Twine &Filename, raw_ostream &OS) { logAllUnhandledErrors(DICtx.loadRegisterInfo(Obj), errs(), @@ -635,12 +643,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 (ShowSectionSizes) { + for (auto Object : Objects) + handleFile(Object, collectObjectSectionSizes, OutputFile.os()); + } else { for (auto Object : Objects) handleFile(Object, dumpObjectFile, OutputFile.os()); + } return EXIT_SUCCESS; }