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