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