1 //===-- SectionSizes.cpp - Debug section sizes ----------------------------===//
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 "SectionSizes.h"
10 
11 #define DEBUG_TYPE "dwarfdump"
12 
13 using namespace llvm;
14 using namespace object;
15 
16 static size_t getNameColumnWidth(const SectionSizes &Sizes,
17                                  const StringRef SectionNameTitle) {
18   // The minimum column width should be the size of "SECTION".
19   size_t Width = SectionNameTitle.size();
20   for (const auto &DebugSec : Sizes.DebugSectionSizes) {
21     StringRef SectionName = DebugSec.getKey();
22     Width = std::max(Width, SectionName.size());
23   }
24   return Width;
25 }
26 
27 static size_t getSizeColumnWidth(const SectionSizes &Sizes,
28                                  const StringRef SectionSizeTitle) {
29   // The minimum column width should be the size of the column title.
30   size_t Width = SectionSizeTitle.size();
31   for (const auto &DebugSec : Sizes.DebugSectionSizes) {
32     size_t NumWidth = std::to_string(DebugSec.getValue()).size();
33     Width = std::max(Width, NumWidth);
34   }
35   return Width;
36 }
37 
38 static void prettyPrintSectionSizes(const ObjectFile &Obj,
39                                     const SectionSizes &Sizes,
40                                     raw_ostream &OS) {
41   const StringRef SectionNameTitle = "SECTION";
42   const StringRef SectionSizeTitle = "SIZE (b)";
43 
44   size_t NameColWidth = getNameColumnWidth(Sizes, SectionNameTitle);
45   size_t SizeColWidth = getSizeColumnWidth(Sizes, SectionSizeTitle);
46 
47   OS << "----------------------------------------------------" << '\n';
48   OS << SectionNameTitle;
49   size_t SectionNameTitleWidth = SectionNameTitle.size();
50   for (unsigned i = 0; i < (NameColWidth - SectionNameTitleWidth) + 2; i++)
51     OS << " ";
52   OS << SectionSizeTitle << '\n';
53   for (unsigned i = 0; i < NameColWidth; i++)
54     OS << "-";
55   OS << "  ";
56 
57   for (unsigned i = 0; i < SizeColWidth; i++)
58     OS << "-";
59   OS << '\n';
60 
61   for (const auto &DebugSec : Sizes.DebugSectionSizes) {
62     OS << left_justify(DebugSec.getKey(), NameColWidth) << "  ";
63 
64     auto NumBytes = std::to_string(DebugSec.getValue());
65     OS << right_justify(NumBytes, SizeColWidth) << " ("
66        << format("%0.2f", DebugSec.getValue() /
67                               static_cast<double>(Sizes.TotalObjectSize) * 100)
68        << "%)\n";
69   }
70 
71   OS << '\n';
72   OS << " Total Size: " << Sizes.TotalDebugSectionsSize << "  ("
73      << format("%0.2f", Sizes.TotalDebugSectionsSize /
74                             static_cast<double>(Sizes.TotalObjectSize) * 100)
75      << "%)\n";
76   OS << " Total File Size: " << Sizes.TotalObjectSize << '\n';
77   OS << "----------------------------------------------------" << '\n';
78 }
79 
80 void llvm::calculateSectionSizes(const ObjectFile &Obj, SectionSizes &Sizes,
81                                  const Twine &Filename) {
82   // Get total size.
83   Sizes.TotalObjectSize = Obj.getData().size();
84 
85   for (const SectionRef &Section : Obj.sections()) {
86     StringRef SectionName;
87     if (Expected<StringRef> NameOrErr = Section.getName())
88       SectionName = *NameOrErr;
89     else
90       WithColor::defaultWarningHandler(
91           createFileError(Filename, NameOrErr.takeError()));
92 
93     LLVM_DEBUG(dbgs() << SectionName.str() << ": " << Section.getSize()
94                       << '\n');
95 
96     if (!Section.isDebugSection(SectionName))
97       continue;
98 
99     Sizes.TotalDebugSectionsSize += Section.getSize();
100     Sizes.DebugSectionSizes[SectionName] += Section.getSize();
101   }
102 }
103 
104 bool collectObjectSectionSizes(ObjectFile &Obj, DWARFContext & /*DICtx*/,
105                                const Twine &Filename, raw_ostream &OS) {
106   SectionSizes Sizes;
107 
108   // Get the section sizes.
109   calculateSectionSizes(Obj, Sizes, Filename);
110 
111   OS << "----------------------------------------------------\n";
112   OS << "file: " << Filename.str() << '\n';
113 
114   prettyPrintSectionSizes(Obj, Sizes, OS);
115 
116   // TODO: If the input file is an archive, print the cumulative summary of all
117   // files from the archive.
118 
119   return true;
120 }
121