blob: afb6b2386218e25642adff7a526a7849853fb88e [file] [log] [blame]
Eugene Zelenkoffec81c2015-11-04 22:32:32 +00001//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Michael J. Spencerc4ad4662011-09-28 20:57:46 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This program is a utility that works like traditional Unix "size",
10// that is, it prints out the size of each section, and the total size of all
11// sections.
12//
13//===----------------------------------------------------------------------===//
14
15#include "llvm/ADT/APInt.h"
16#include "llvm/Object/Archive.h"
Rafael Espindolaa0ff5562016-02-09 21:39:49 +000017#include "llvm/Object/ELFObjectFile.h"
Kevin Enderby246a4602014-06-17 17:54:13 +000018#include "llvm/Object/MachO.h"
Kevin Enderby4b8fc282014-06-18 22:04:40 +000019#include "llvm/Object/MachOUniversal.h"
Chandler Carruthd9903882015-01-14 11:23:27 +000020#include "llvm/Object/ObjectFile.h"
Fangrui Song47db32e2021-07-09 10:26:53 -070021#include "llvm/Option/Arg.h"
22#include "llvm/Option/ArgList.h"
23#include "llvm/Option/Option.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000024#include "llvm/Support/Casting.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/FileSystem.h"
27#include "llvm/Support/Format.h"
Alex Brachet1f173a02023-02-10 19:40:56 +000028#include "llvm/Support/LLVMDriver.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000029#include "llvm/Support/MemoryBuffer.h"
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +000030#include "llvm/Support/WithColor.h"
Chandler Carruth4d88a1c2012-12-04 10:44:52 +000031#include "llvm/Support/raw_ostream.h"
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000032#include <algorithm>
33#include <string>
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000034#include <system_error>
Eugene Zelenkoffec81c2015-11-04 22:32:32 +000035
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000036using namespace llvm;
37using namespace object;
38
Fangrui Song47db32e2021-07-09 10:26:53 -070039namespace {
40using namespace llvm::opt; // for HelpHidden in Opts.inc
41enum ID {
42 OPT_INVALID = 0, // This is not an option ID.
Jan Svoboda3f092f32023-08-04 11:19:09 -070043#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
Fangrui Song47db32e2021-07-09 10:26:53 -070044#include "Opts.inc"
45#undef OPTION
46};
47
Chandler Carruthdd647e32024-12-11 15:44:44 -080048#define OPTTABLE_STR_TABLE_CODE
Fangrui Song47db32e2021-07-09 10:26:53 -070049#include "Opts.inc"
Chandler Carruthdd647e32024-12-11 15:44:44 -080050#undef OPTTABLE_STR_TABLE_CODE
51
52#define OPTTABLE_PREFIXES_TABLE_CODE
53#include "Opts.inc"
54#undef OPTTABLE_PREFIXES_TABLE_CODE
Fangrui Song47db32e2021-07-09 10:26:53 -070055
serge-sans-paille07d9ab92022-12-23 13:25:58 +010056static constexpr opt::OptTable::Info InfoTable[] = {
Jan Svoboda3f092f32023-08-04 11:19:09 -070057#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
Fangrui Song47db32e2021-07-09 10:26:53 -070058#include "Opts.inc"
59#undef OPTION
60};
61
serge-sans-paille07bb29d2022-12-30 08:32:59 +010062class SizeOptTable : public opt::GenericOptTable {
Fangrui Song47db32e2021-07-09 10:26:53 -070063public:
Chandler Carruthdd647e32024-12-11 15:44:44 -080064 SizeOptTable()
65 : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
66 setGroupedShortOptions(true);
67 }
Fangrui Song47db32e2021-07-09 10:26:53 -070068};
Serge Gueltondaeeb332019-06-05 10:32:28 +000069
Kevin Enderby10769742014-07-01 22:26:31 +000070enum OutputFormatTy { berkeley, sysv, darwin };
Fangrui Song47db32e2021-07-09 10:26:53 -070071enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 };
72} // namespace
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000073
Fangrui Song47db32e2021-07-09 10:26:53 -070074static bool ArchAll = false;
75static std::vector<StringRef> ArchFlags;
76static bool ELFCommons;
77static OutputFormatTy OutputFormat;
78static bool DarwinLongFormat;
Vitaly Bukae67cd152025-02-24 12:58:01 -080079static RadixTy Radix = RadixTy::decimal;
Fangrui Song47db32e2021-07-09 10:26:53 -070080static bool TotalSizes;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +000081
Fangrui Song47db32e2021-07-09 10:26:53 -070082static std::vector<std::string> InputFilenames;
83
84static std::string ToolName;
85
86// States
87static bool HadError = false;
Rafael Espindola1dc30a42016-02-09 21:35:14 +000088static bool BerkeleyHeaderPrinted = false;
89static bool MoreThanOneFile = false;
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +000090static uint64_t TotalObjectText = 0;
91static uint64_t TotalObjectData = 0;
92static uint64_t TotalObjectBss = 0;
93static uint64_t TotalObjectTotal = 0;
Kevin Enderby246a4602014-06-17 17:54:13 +000094
Fangrui Song47db32e2021-07-09 10:26:53 -070095static void error(const Twine &Message, StringRef File = "") {
Kevin Enderby42398052016-06-28 23:16:13 +000096 HadError = true;
Fangrui Song47db32e2021-07-09 10:26:53 -070097 if (File.empty())
98 WithColor::error(errs(), ToolName) << Message << '\n';
99 else
100 WithColor::error(errs(), ToolName)
101 << "'" << File << "': " << Message << '\n';
Kevin Enderby42398052016-06-28 23:16:13 +0000102}
103
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000104// This version of error() prints the archive name and member name, for example:
105// "libx.a(foo.o)" after the ToolName before the error message. It sets
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000106// HadError but returns allowing the code to move on to other archive members.
Kevin Enderby9acb1092016-05-31 20:35:34 +0000107static void error(llvm::Error E, StringRef FileName, const Archive::Child &C,
108 StringRef ArchitectureName = StringRef()) {
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000109 HadError = true;
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000110 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000111
Kevin Enderbyf4586032016-07-29 17:44:13 +0000112 Expected<StringRef> NameOrErr = C.getName();
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000113 // TODO: if we have a error getting the name then it would be nice to print
114 // the index of which archive member this is and or its offset in the
115 // archive instead of "???" as the name.
Kevin Enderbyf4586032016-07-29 17:44:13 +0000116 if (!NameOrErr) {
117 consumeError(NameOrErr.takeError());
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000118 errs() << "(" << "???" << ")";
Kevin Enderbyf4586032016-07-29 17:44:13 +0000119 } else
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000120 errs() << "(" << NameOrErr.get() << ")";
121
Kevin Enderby9acb1092016-05-31 20:35:34 +0000122 if (!ArchitectureName.empty())
123 errs() << " (for architecture " << ArchitectureName << ") ";
124
125 std::string Buf;
126 raw_string_ostream OS(Buf);
Jonas Devlieghere45eb84f2018-11-11 01:46:03 +0000127 logAllUnhandledErrors(std::move(E), OS);
Kevin Enderby9acb1092016-05-31 20:35:34 +0000128 OS.flush();
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000129 errs() << ": " << Buf << "\n";
Kevin Enderby9acb1092016-05-31 20:35:34 +0000130}
131
132// This version of error() prints the file name and which architecture slice it // is from, for example: "foo.o (for architecture i386)" after the ToolName
133// before the error message. It sets HadError but returns allowing the code to
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000134// move on to other architecture slices.
Kevin Enderby9acb1092016-05-31 20:35:34 +0000135static void error(llvm::Error E, StringRef FileName,
136 StringRef ArchitectureName = StringRef()) {
137 HadError = true;
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000138 WithColor::error(errs(), ToolName) << "'" << FileName << "'";
Kevin Enderby9acb1092016-05-31 20:35:34 +0000139
140 if (!ArchitectureName.empty())
141 errs() << " (for architecture " << ArchitectureName << ") ";
142
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000143 std::string Buf;
144 raw_string_ostream OS(Buf);
Jonas Devlieghere45eb84f2018-11-11 01:46:03 +0000145 logAllUnhandledErrors(std::move(E), OS);
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000146 OS.flush();
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000147 errs() << ": " << Buf << "\n";
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000148}
149
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000150/// Get the length of the string that represents @p num in Radix including the
151/// leading 0x or 0 for hexadecimal and octal respectively.
Andrew Trick7dc278d2011-09-29 01:22:31 +0000152static size_t getNumLengthAsString(uint64_t num) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000153 APInt conv(64, num);
154 SmallString<32> result;
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000155 conv.toString(result, Radix, false, true);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000156 return result.size();
157}
158
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000159/// Return the printing format for the Radix.
Eugene Zelenkoffec81c2015-11-04 22:32:32 +0000160static const char *getRadixFmt() {
Kevin Enderby246a4602014-06-17 17:54:13 +0000161 switch (Radix) {
162 case octal:
163 return PRIo64;
164 case decimal:
165 return PRIu64;
166 case hexadecimal:
167 return PRIx64;
168 }
169 return nullptr;
170}
171
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000172/// Remove unneeded ELF sections from calculation
173static bool considerForSize(ObjectFile *Obj, SectionRef Section) {
174 if (!Obj->isELF())
175 return true;
176 switch (static_cast<ELFSectionRef>(Section).getType()) {
177 case ELF::SHT_NULL:
178 case ELF::SHT_SYMTAB:
gbreynoo41ca82c2020-07-01 11:57:30 +0100179 return false;
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000180 case ELF::SHT_STRTAB:
181 case ELF::SHT_REL:
182 case ELF::SHT_RELA:
gbreynoo41ca82c2020-07-01 11:57:30 +0100183 return static_cast<ELFSectionRef>(Section).getFlags() & ELF::SHF_ALLOC;
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000184 }
185 return true;
186}
187
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000188/// Total size of all ELF common symbols
vgxbjac003762020-04-10 20:24:21 +0800189static Expected<uint64_t> getCommonSize(ObjectFile *Obj) {
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000190 uint64_t TotalCommons = 0;
vgxbjac003762020-04-10 20:24:21 +0800191 for (auto &Sym : Obj->symbols()) {
192 Expected<uint32_t> SymFlagsOrErr =
193 Obj->getSymbolFlags(Sym.getRawDataRefImpl());
194 if (!SymFlagsOrErr)
vgxbjac003762020-04-10 20:24:21 +0800195 return SymFlagsOrErr.takeError();
196 if (*SymFlagsOrErr & SymbolRef::SF_Common)
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000197 TotalCommons += Obj->getCommonSymbolSize(Sym.getRawDataRefImpl());
vgxbjac003762020-04-10 20:24:21 +0800198 }
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000199 return TotalCommons;
200}
201
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000202/// Print the size of each Mach-O segment and section in @p MachO.
Kevin Enderby246a4602014-06-17 17:54:13 +0000203///
204/// This is when used when @c OutputFormat is darwin and produces the same
205/// output as darwin's size(1) -m output.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000206static void printDarwinSectionSizes(MachOObjectFile *MachO) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000207 std::string fmtbuf;
208 raw_string_ostream fmt(fmtbuf);
209 const char *radix_fmt = getRadixFmt();
210 if (Radix == hexadecimal)
211 fmt << "0x";
212 fmt << "%" << radix_fmt;
213
Kevin Enderby246a4602014-06-17 17:54:13 +0000214 uint32_t Filetype = MachO->getHeader().filetype;
Kevin Enderby246a4602014-06-17 17:54:13 +0000215
216 uint64_t total = 0;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000217 for (const auto &Load : MachO->load_commands()) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000218 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
219 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
220 outs() << "Segment " << Seg.segname << ": "
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400221 << format(fmtbuf.c_str(), Seg.vmsize);
Kevin Enderby246a4602014-06-17 17:54:13 +0000222 if (DarwinLongFormat)
Kevin Enderby10769742014-07-01 22:26:31 +0000223 outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff "
224 << Seg.fileoff << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000225 outs() << "\n";
226 total += Seg.vmsize;
227 uint64_t sec_total = 0;
228 for (unsigned J = 0; J < Seg.nsects; ++J) {
229 MachO::section_64 Sec = MachO->getSection64(Load, J);
230 if (Filetype == MachO::MH_OBJECT)
231 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
232 << format("%.16s", &Sec.sectname) << "): ";
233 else
234 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400235 outs() << format(fmtbuf.c_str(), Sec.size);
Kevin Enderby246a4602014-06-17 17:54:13 +0000236 if (DarwinLongFormat)
Kevin Enderby10769742014-07-01 22:26:31 +0000237 outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset "
238 << Sec.offset << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000239 outs() << "\n";
240 sec_total += Sec.size;
241 }
242 if (Seg.nsects != 0)
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400243 outs() << "\ttotal " << format(fmtbuf.c_str(), sec_total) << "\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000244 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000245 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000246 uint64_t Seg_vmsize = Seg.vmsize;
Kevin Enderby246a4602014-06-17 17:54:13 +0000247 outs() << "Segment " << Seg.segname << ": "
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400248 << format(fmtbuf.c_str(), Seg_vmsize);
Kevin Enderby246a4602014-06-17 17:54:13 +0000249 if (DarwinLongFormat)
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000250 outs() << " (vmaddr 0x" << format("%" PRIx32, Seg.vmaddr) << " fileoff "
Kevin Enderby10769742014-07-01 22:26:31 +0000251 << Seg.fileoff << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000252 outs() << "\n";
253 total += Seg.vmsize;
254 uint64_t sec_total = 0;
255 for (unsigned J = 0; J < Seg.nsects; ++J) {
256 MachO::section Sec = MachO->getSection(Load, J);
257 if (Filetype == MachO::MH_OBJECT)
258 outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
259 << format("%.16s", &Sec.sectname) << "): ";
260 else
261 outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000262 uint64_t Sec_size = Sec.size;
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400263 outs() << format(fmtbuf.c_str(), Sec_size);
Kevin Enderby246a4602014-06-17 17:54:13 +0000264 if (DarwinLongFormat)
Kevin Enderby2058e9d2016-02-09 18:33:15 +0000265 outs() << " (addr 0x" << format("%" PRIx32, Sec.addr) << " offset "
Kevin Enderby10769742014-07-01 22:26:31 +0000266 << Sec.offset << ")";
Kevin Enderby246a4602014-06-17 17:54:13 +0000267 outs() << "\n";
268 sec_total += Sec.size;
269 }
270 if (Seg.nsects != 0)
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400271 outs() << "\ttotal " << format(fmtbuf.c_str(), sec_total) << "\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000272 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000273 }
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400274 outs() << "total " << format(fmtbuf.c_str(), total) << "\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000275}
276
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000277/// Print the summary sizes of the standard Mach-O segments in @p MachO.
Kevin Enderby246a4602014-06-17 17:54:13 +0000278///
279/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
280/// produces the same output as darwin's size(1) default output.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000281static void printDarwinSegmentSizes(MachOObjectFile *MachO) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000282 uint64_t total_text = 0;
283 uint64_t total_data = 0;
284 uint64_t total_objc = 0;
285 uint64_t total_others = 0;
Alexey Samsonovd319c4f2015-06-03 22:19:36 +0000286 for (const auto &Load : MachO->load_commands()) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000287 if (Load.C.cmd == MachO::LC_SEGMENT_64) {
288 MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load);
289 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
290 for (unsigned J = 0; J < Seg.nsects; ++J) {
291 MachO::section_64 Sec = MachO->getSection64(Load, J);
292 StringRef SegmentName = StringRef(Sec.segname);
293 if (SegmentName == "__TEXT")
294 total_text += Sec.size;
295 else if (SegmentName == "__DATA")
296 total_data += Sec.size;
297 else if (SegmentName == "__OBJC")
298 total_objc += Sec.size;
299 else
300 total_others += Sec.size;
Kevin Enderby10769742014-07-01 22:26:31 +0000301 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000302 } else {
303 StringRef SegmentName = StringRef(Seg.segname);
304 if (SegmentName == "__TEXT")
305 total_text += Seg.vmsize;
306 else if (SegmentName == "__DATA")
307 total_data += Seg.vmsize;
308 else if (SegmentName == "__OBJC")
309 total_objc += Seg.vmsize;
310 else
311 total_others += Seg.vmsize;
312 }
Kevin Enderby10769742014-07-01 22:26:31 +0000313 } else if (Load.C.cmd == MachO::LC_SEGMENT) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000314 MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
315 if (MachO->getHeader().filetype == MachO::MH_OBJECT) {
316 for (unsigned J = 0; J < Seg.nsects; ++J) {
317 MachO::section Sec = MachO->getSection(Load, J);
318 StringRef SegmentName = StringRef(Sec.segname);
319 if (SegmentName == "__TEXT")
320 total_text += Sec.size;
321 else if (SegmentName == "__DATA")
322 total_data += Sec.size;
323 else if (SegmentName == "__OBJC")
324 total_objc += Sec.size;
325 else
326 total_others += Sec.size;
Kevin Enderby10769742014-07-01 22:26:31 +0000327 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000328 } else {
329 StringRef SegmentName = StringRef(Seg.segname);
330 if (SegmentName == "__TEXT")
331 total_text += Seg.vmsize;
332 else if (SegmentName == "__DATA")
333 total_data += Seg.vmsize;
334 else if (SegmentName == "__OBJC")
335 total_objc += Seg.vmsize;
336 else
337 total_others += Seg.vmsize;
338 }
339 }
Kevin Enderby246a4602014-06-17 17:54:13 +0000340 }
341 uint64_t total = total_text + total_data + total_objc + total_others;
342
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000343 if (!BerkeleyHeaderPrinted) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000344 outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000345 BerkeleyHeaderPrinted = true;
Kevin Enderby246a4602014-06-17 17:54:13 +0000346 }
347 outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
348 << total_others << "\t" << total << "\t" << format("%" PRIx64, total)
349 << "\t";
350}
351
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000352/// Print the size of each section in @p Obj.
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000353///
354/// The format used is determined by @c OutputFormat and @c Radix.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000355static void printObjectSectionSizes(ObjectFile *Obj) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000356 uint64_t total = 0;
357 std::string fmtbuf;
358 raw_string_ostream fmt(fmtbuf);
Kevin Enderby246a4602014-06-17 17:54:13 +0000359 const char *radix_fmt = getRadixFmt();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000360
Kevin Enderby246a4602014-06-17 17:54:13 +0000361 // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
362 // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
363 // let it fall through to OutputFormat berkeley.
364 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
365 if (OutputFormat == darwin && MachO)
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000366 printDarwinSectionSizes(MachO);
Kevin Enderby246a4602014-06-17 17:54:13 +0000367 // If we have a MachOObjectFile and the OutputFormat is berkeley print as
368 // darwin's default berkeley format for Mach-O files.
369 else if (MachO && OutputFormat == berkeley)
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000370 printDarwinSegmentSizes(MachO);
Kevin Enderby246a4602014-06-17 17:54:13 +0000371 else if (OutputFormat == sysv) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000372 // Run two passes over all sections. The first gets the lengths needed for
373 // formatting the output. The second actually does the output.
374 std::size_t max_name_len = strlen("section");
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000375 std::size_t max_size_len = strlen("size");
376 std::size_t max_addr_len = strlen("addr");
Alexey Samsonov48803e52014-03-13 14:37:36 +0000377 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000378 if (!considerForSize(Obj, Section))
379 continue;
Rafael Espindola80291272014-10-08 15:28:58 +0000380 uint64_t size = Section.getSize();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000381 total += size;
382
George Rimarbcc00e12019-08-14 11:10:11 +0000383 Expected<StringRef> name_or_err = Section.getName();
384 if (!name_or_err) {
385 error(name_or_err.takeError(), Obj->getFileName());
Alexey Samsonov48803e52014-03-13 14:37:36 +0000386 return;
George Rimarbcc00e12019-08-14 11:10:11 +0000387 }
388
Rafael Espindola80291272014-10-08 15:28:58 +0000389 uint64_t addr = Section.getAddress();
George Rimarbcc00e12019-08-14 11:10:11 +0000390 max_name_len = std::max(max_name_len, name_or_err->size());
Andrew Trick7dc278d2011-09-29 01:22:31 +0000391 max_size_len = std::max(max_size_len, getNumLengthAsString(size));
392 max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000393 }
394
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000395 // Add extra padding.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000396 max_name_len += 2;
397 max_size_len += 2;
398 max_addr_len += 2;
399
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000400 // Setup header format.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000401 fmt << "%-" << max_name_len << "s "
402 << "%" << max_size_len << "s "
403 << "%" << max_addr_len << "s\n";
404
405 // Print header
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400406 outs() << format(fmtbuf.c_str(), static_cast<const char *>("section"),
Kevin Enderby10769742014-07-01 22:26:31 +0000407 static_cast<const char *>("size"),
408 static_cast<const char *>("addr"));
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000409 fmtbuf.clear();
410
411 // Setup per section format.
412 fmt << "%-" << max_name_len << "s "
413 << "%#" << max_size_len << radix_fmt << " "
414 << "%#" << max_addr_len << radix_fmt << "\n";
415
416 // Print each section.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000417 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindolaa0ff5562016-02-09 21:39:49 +0000418 if (!considerForSize(Obj, Section))
419 continue;
George Rimarbcc00e12019-08-14 11:10:11 +0000420
421 Expected<StringRef> name_or_err = Section.getName();
422 if (!name_or_err) {
423 error(name_or_err.takeError(), Obj->getFileName());
Alexey Samsonov48803e52014-03-13 14:37:36 +0000424 return;
George Rimarbcc00e12019-08-14 11:10:11 +0000425 }
426
Rafael Espindola80291272014-10-08 15:28:58 +0000427 uint64_t size = Section.getSize();
428 uint64_t addr = Section.getAddress();
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400429 outs() << format(fmtbuf.c_str(), name_or_err->str().c_str(), size, addr);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000430 }
431
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000432 if (ELFCommons) {
vgxbjac003762020-04-10 20:24:21 +0800433 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj)) {
434 total += *CommonSizeOrErr;
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400435 outs() << format(fmtbuf.c_str(), std::string("*COM*").c_str(),
vgxbjac003762020-04-10 20:24:21 +0800436 *CommonSizeOrErr, static_cast<uint64_t>(0));
437 } else {
438 error(CommonSizeOrErr.takeError(), Obj->getFileName());
439 return;
440 }
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000441 }
442
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000443 // Print total.
444 fmtbuf.clear();
445 fmt << "%-" << max_name_len << "s "
446 << "%#" << max_size_len << radix_fmt << "\n";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400447 outs() << format(fmtbuf.c_str(), static_cast<const char *>("Total"), total)
TH3CHARLieabd70782020-01-03 14:04:01 +0800448 << "\n\n";
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000449 } else {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000450 // The Berkeley format does not display individual section sizes. It
451 // displays the cumulative size for each section type.
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000452 uint64_t total_text = 0;
453 uint64_t total_data = 0;
454 uint64_t total_bss = 0;
455
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000456 // Make one pass over the section table to calculate sizes.
Alexey Samsonov48803e52014-03-13 14:37:36 +0000457 for (const SectionRef &Section : Obj->sections()) {
Rafael Espindola80291272014-10-08 15:28:58 +0000458 uint64_t size = Section.getSize();
Jordan Rupprecht4888c4a2018-12-13 19:40:12 +0000459 bool isText = Section.isBerkeleyText();
460 bool isData = Section.isBerkeleyData();
Rafael Espindola80291272014-10-08 15:28:58 +0000461 bool isBSS = Section.isBSS();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000462 if (isText)
463 total_text += size;
464 else if (isData)
465 total_data += size;
466 else if (isBSS)
467 total_bss += size;
468 }
469
vgxbjac003762020-04-10 20:24:21 +0800470 if (ELFCommons) {
471 if (Expected<uint64_t> CommonSizeOrErr = getCommonSize(Obj))
472 total_bss += *CommonSizeOrErr;
473 else {
474 error(CommonSizeOrErr.takeError(), Obj->getFileName());
475 return;
476 }
477 }
Hemant Kulkarni274457e2016-03-28 16:48:10 +0000478
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000479 total = total_text + total_data + total_bss;
480
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000481 if (TotalSizes) {
482 TotalObjectText += total_text;
483 TotalObjectData += total_data;
484 TotalObjectBss += total_bss;
485 TotalObjectTotal += total;
486 }
487
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000488 if (!BerkeleyHeaderPrinted) {
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000489 outs() << " text\t"
490 " data\t"
491 " bss\t"
492 " "
493 << (Radix == octal ? "oct" : "dec")
494 << "\t"
495 " hex\t"
496 "filename\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000497 BerkeleyHeaderPrinted = true;
Kevin Enderby246a4602014-06-17 17:54:13 +0000498 }
499
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000500 // Print result.
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000501 fmt << "%#7" << radix_fmt << "\t"
502 << "%#7" << radix_fmt << "\t"
503 << "%#7" << radix_fmt << "\t";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400504 outs() << format(fmtbuf.c_str(), total_text, total_data, total_bss);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000505 fmtbuf.clear();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000506 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
507 << "%7" PRIx64 "\t";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400508 outs() << format(fmtbuf.c_str(), total, total);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000509 }
510}
511
David Majnemer91160d82016-10-31 17:11:31 +0000512/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000513/// is a list of architecture flags specified then check to make sure this
514/// Mach-O file is one of those architectures or all architectures was
515/// specificed. If not then an error is generated and this routine returns
516/// false. Else it returns true.
David Majnemer91160d82016-10-31 17:11:31 +0000517static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
518 auto *MachO = dyn_cast<MachOObjectFile>(O);
519
520 if (!MachO || ArchAll || ArchFlags.empty())
521 return true;
522
523 MachO::mach_header H;
524 MachO::mach_header_64 H_64;
525 Triple T;
526 if (MachO->is64Bit()) {
527 H_64 = MachO->MachOObjectFile::getHeader64();
528 T = MachOObjectFile::getArchTriple(H_64.cputype, H_64.cpusubtype);
529 } else {
530 H = MachO->MachOObjectFile::getHeader();
531 T = MachOObjectFile::getArchTriple(H.cputype, H.cpusubtype);
532 }
Kazu Hirata07992332020-12-27 09:57:25 -0800533 if (!is_contained(ArchFlags, T.getArchName())) {
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000534 error("no architecture specified", Filename);
David Majnemer91160d82016-10-31 17:11:31 +0000535 return false;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000536 }
537 return true;
538}
539
Rafael Espindola49a0e5e2016-02-09 21:32:56 +0000540/// Print the section sizes for @p file. If @p file is an archive, print the
541/// section sizes for each archive member.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000542static void printFileSectionSizes(StringRef file) {
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000543
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000544 // Attempt to open the binary.
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +0000545 Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
546 if (!BinaryOrErr) {
Kevin Enderby600fb3f2016-08-05 18:19:40 +0000547 error(BinaryOrErr.takeError(), file);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000548 return;
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +0000549 }
Rafael Espindola48af1c22014-08-19 18:44:46 +0000550 Binary &Bin = *BinaryOrErr.get().getBinary();
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000551
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000552 if (Archive *a = dyn_cast<Archive>(&Bin)) {
Michael J. Spencercc5f8d42011-09-29 00:59:18 +0000553 // This is an archive. Iterate over each member and display its sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000554 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000555 for (auto &C : a->children(Err)) {
556 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000557 if (!ChildOrErr) {
558 if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000559 error(std::move(E), a->getFileName(), C);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000560 continue;
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000561 }
Rafael Espindolaae460022014-06-16 16:08:36 +0000562 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
Kevin Enderby246a4602014-06-17 17:54:13 +0000563 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000564 if (!checkMachOAndArchFlags(o, file))
565 return;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000566 if (OutputFormat == sysv)
Kevin Enderby10769742014-07-01 22:26:31 +0000567 outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n";
568 else if (MachO && OutputFormat == darwin)
569 outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000570 printObjectSectionSizes(o);
Shivam Gupta25fdcb82022-08-30 18:47:24 +0530571 if (!MachO && OutputFormat == darwin)
572 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000573 if (OutputFormat == berkeley) {
574 if (MachO)
575 outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
576 else
577 outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
578 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000579 }
580 }
Lang Hamesfc209622016-07-14 02:24:01 +0000581 if (Err)
582 error(std::move(Err), a->getFileName());
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000583 } else if (MachOUniversalBinary *UB =
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000584 dyn_cast<MachOUniversalBinary>(&Bin)) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000585 // If we have a list of architecture flags specified dump only those.
Jordan Rupprecht16a0de22018-12-20 00:57:06 +0000586 if (!ArchAll && !ArchFlags.empty()) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000587 // Look for a slice in the universal binary that matches each ArchFlag.
588 bool ArchFound;
Kevin Enderby10769742014-07-01 22:26:31 +0000589 for (unsigned i = 0; i < ArchFlags.size(); ++i) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000590 ArchFound = false;
591 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
592 E = UB->end_objects();
593 I != E; ++I) {
Kevin Enderby59343a92016-12-16 22:54:02 +0000594 if (ArchFlags[i] == I->getArchFlagName()) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000595 ArchFound = true;
Kevin Enderby9acb1092016-05-31 20:35:34 +0000596 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000597 if (UO) {
598 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
599 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
600 if (OutputFormat == sysv)
601 outs() << o->getFileName() << " :\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000602 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000603 if (MoreThanOneFile || ArchFlags.size() > 1)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000604 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000605 << I->getArchFlagName() << "): \n";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000606 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000607 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000608 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000609 if (!MachO || MoreThanOneFile || ArchFlags.size() > 1)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000610 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000611 << I->getArchFlagName() << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000612 outs() << "\n";
613 }
614 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000615 } else if (auto E = isNotObjectErrorInvalidFileType(
616 UO.takeError())) {
617 error(std::move(E), file, ArchFlags.size() > 1 ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000618 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby9acb1092016-05-31 20:35:34 +0000619 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000620 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000621 I->getAsArchive()) {
622 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000623 // This is an archive. Iterate over each member and display its
Kevin Enderby10769742014-07-01 22:26:31 +0000624 // sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000625 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000626 for (auto &C : UA->children(Err)) {
627 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000628 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000629 if (auto E = isNotObjectErrorInvalidFileType(
630 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000631 error(std::move(E), UA->getFileName(), C,
Kevin Enderby9acb1092016-05-31 20:35:34 +0000632 ArchFlags.size() > 1 ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000633 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000634 continue;
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000635 }
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000636 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
637 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
638 if (OutputFormat == sysv)
639 outs() << o->getFileName() << " (ex " << UA->getFileName()
640 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000641 else if (MachO && OutputFormat == darwin)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000642 outs() << UA->getFileName() << "(" << o->getFileName()
Kevin Enderby10769742014-07-01 22:26:31 +0000643 << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000644 << " (for architecture " << I->getArchFlagName()
Kevin Enderby10769742014-07-01 22:26:31 +0000645 << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000646 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000647 if (OutputFormat == berkeley) {
648 if (MachO) {
649 outs() << UA->getFileName() << "(" << o->getFileName()
650 << ")";
651 if (ArchFlags.size() > 1)
Kevin Enderby59343a92016-12-16 22:54:02 +0000652 outs() << " (for architecture " << I->getArchFlagName()
Kevin Enderby10769742014-07-01 22:26:31 +0000653 << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000654 outs() << "\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000655 } else
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000656 outs() << o->getFileName() << " (ex " << UA->getFileName()
657 << ")\n";
658 }
659 }
660 }
Lang Hamesfc209622016-07-14 02:24:01 +0000661 if (Err)
662 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000663 } else {
664 consumeError(AOrErr.takeError());
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000665 error("mach-o universal file for architecture " +
666 StringRef(I->getArchFlagName()) +
667 " is not a mach-o file or an archive file",
668 file);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000669 }
670 }
671 }
672 if (!ArchFound) {
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000673 error("file does not contain architecture " + ArchFlags[i], file);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000674 return;
675 }
676 }
677 return;
678 }
679 // No architecture flags were specified so if this contains a slice that
680 // matches the host architecture dump only that.
681 if (!ArchAll) {
Kevin Enderby10769742014-07-01 22:26:31 +0000682 StringRef HostArchName = MachOObjectFile::getHostArch().getArchName();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000683 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
684 E = UB->end_objects();
685 I != E; ++I) {
Kevin Enderby59343a92016-12-16 22:54:02 +0000686 if (HostArchName == I->getArchFlagName()) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000687 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000688 if (UO) {
689 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
690 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
691 if (OutputFormat == sysv)
692 outs() << o->getFileName() << " :\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000693 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000694 if (MoreThanOneFile)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000695 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000696 << I->getArchFlagName() << "):\n";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000697 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000698 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000699 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000700 if (!MachO || MoreThanOneFile)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000701 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000702 << I->getArchFlagName() << ")";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000703 outs() << "\n";
704 }
705 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000706 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
707 error(std::move(E), file);
708 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000709 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000710 I->getAsArchive()) {
711 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000712 // This is an archive. Iterate over each member and display its
713 // sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000714 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000715 for (auto &C : UA->children(Err)) {
716 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000717 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000718 if (auto E = isNotObjectErrorInvalidFileType(
719 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000720 error(std::move(E), UA->getFileName(), C);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000721 continue;
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000722 }
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000723 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
724 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
725 if (OutputFormat == sysv)
726 outs() << o->getFileName() << " (ex " << UA->getFileName()
727 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000728 else if (MachO && OutputFormat == darwin)
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000729 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000730 << " (for architecture " << I->getArchFlagName()
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000731 << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000732 printObjectSectionSizes(o);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000733 if (OutputFormat == berkeley) {
734 if (MachO)
735 outs() << UA->getFileName() << "(" << o->getFileName()
736 << ")\n";
737 else
738 outs() << o->getFileName() << " (ex " << UA->getFileName()
739 << ")\n";
740 }
741 }
742 }
Lang Hamesfc209622016-07-14 02:24:01 +0000743 if (Err)
744 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000745 } else {
746 consumeError(AOrErr.takeError());
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000747 error("mach-o universal file for architecture " +
748 StringRef(I->getArchFlagName()) +
749 " is not a mach-o file or an archive file",
750 file);
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000751 }
752 return;
753 }
754 }
755 }
756 // Either all architectures have been specified or none have been specified
757 // and this does not contain the host architecture so dump all the slices.
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000758 bool MoreThanOneArch = UB->getNumberOfObjects() > 1;
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000759 for (MachOUniversalBinary::object_iterator I = UB->begin_objects(),
760 E = UB->end_objects();
761 I != E; ++I) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000762 Expected<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
Rafael Espindola4f7932b2014-06-23 20:41:02 +0000763 if (UO) {
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000764 if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000765 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000766 if (OutputFormat == sysv)
767 outs() << o->getFileName() << " :\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000768 else if (MachO && OutputFormat == darwin) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000769 if (MoreThanOneFile || MoreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000770 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000771 << I->getArchFlagName() << "):";
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000772 outs() << "\n";
773 }
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000774 printObjectSectionSizes(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000775 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000776 if (!MachO || MoreThanOneFile || MoreThanOneArch)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000777 outs() << o->getFileName() << " (for architecture "
Kevin Enderby59343a92016-12-16 22:54:02 +0000778 << I->getArchFlagName() << ")";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000779 outs() << "\n";
780 }
781 }
Kevin Enderby9acb1092016-05-31 20:35:34 +0000782 } else if (auto E = isNotObjectErrorInvalidFileType(UO.takeError())) {
783 error(std::move(E), file, MoreThanOneArch ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000784 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby9acb1092016-05-31 20:35:34 +0000785 return;
Kevin Enderby42398052016-06-28 23:16:13 +0000786 } else if (Expected<std::unique_ptr<Archive>> AOrErr =
Rafael Espindola0bfe8282014-12-09 21:05:36 +0000787 I->getAsArchive()) {
788 std::unique_ptr<Archive> &UA = *AOrErr;
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000789 // This is an archive. Iterate over each member and display its sizes.
Mehdi Amini41af4302016-11-11 04:28:40 +0000790 Error Err = Error::success();
Lang Hamesfc209622016-07-14 02:24:01 +0000791 for (auto &C : UA->children(Err)) {
792 Expected<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000793 if (!ChildOrErr) {
Kevin Enderby9acb1092016-05-31 20:35:34 +0000794 if (auto E = isNotObjectErrorInvalidFileType(
795 ChildOrErr.takeError()))
Lang Hamesfc209622016-07-14 02:24:01 +0000796 error(std::move(E), UA->getFileName(), C, MoreThanOneArch ?
Kevin Enderby59343a92016-12-16 22:54:02 +0000797 StringRef(I->getArchFlagName()) : StringRef());
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000798 continue;
Kevin Enderbyac9e15552016-05-17 17:10:12 +0000799 }
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000800 if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
801 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
802 if (OutputFormat == sysv)
803 outs() << o->getFileName() << " (ex " << UA->getFileName()
804 << "):\n";
Kevin Enderby10769742014-07-01 22:26:31 +0000805 else if (MachO && OutputFormat == darwin)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000806 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000807 << " (for architecture " << I->getArchFlagName() << "):\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000808 printObjectSectionSizes(o);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000809 if (OutputFormat == berkeley) {
810 if (MachO)
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000811 outs() << UA->getFileName() << "(" << o->getFileName() << ")"
Kevin Enderby59343a92016-12-16 22:54:02 +0000812 << " (for architecture " << I->getArchFlagName()
Kevin Enderby1983fcf2014-06-19 22:03:18 +0000813 << ")\n";
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000814 else
815 outs() << o->getFileName() << " (ex " << UA->getFileName()
816 << ")\n";
817 }
818 }
819 }
Lang Hamesfc209622016-07-14 02:24:01 +0000820 if (Err)
821 error(std::move(Err), UA->getFileName());
Kevin Enderby42398052016-06-28 23:16:13 +0000822 } else {
823 consumeError(AOrErr.takeError());
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000824 error("mach-o universal file for architecture " +
825 StringRef(I->getArchFlagName()) +
826 " is not a mach-o file or an archive file",
827 file);
Kevin Enderby4b8fc282014-06-18 22:04:40 +0000828 }
829 }
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000830 } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000831 if (!checkMachOAndArchFlags(o, file))
832 return;
Kevin Enderby5997c942016-12-01 19:12:55 +0000833 MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000834 if (OutputFormat == sysv)
835 outs() << o->getFileName() << " :\n";
Kevin Enderby5997c942016-12-01 19:12:55 +0000836 else if (MachO && OutputFormat == darwin && MoreThanOneFile)
837 outs() << o->getFileName() << ":\n";
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000838 printObjectSectionSizes(o);
Shivam Gupta25fdcb82022-08-30 18:47:24 +0530839 if (!MachO && OutputFormat == darwin)
840 outs() << o->getFileName() << "\n";
Kevin Enderby246a4602014-06-17 17:54:13 +0000841 if (OutputFormat == berkeley) {
Rafael Espindola1dc30a42016-02-09 21:35:14 +0000842 if (!MachO || MoreThanOneFile)
Kevin Enderby246a4602014-06-17 17:54:13 +0000843 outs() << o->getFileName();
844 outs() << "\n";
845 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000846 } else {
Jordan Rupprecht1d32d8b2019-10-14 17:29:15 +0000847 error("unsupported file type", file);
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000848 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000849}
850
James Hendersoncd893e52019-09-13 12:00:42 +0000851static void printBerkeleyTotals() {
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000852 std::string fmtbuf;
853 raw_string_ostream fmt(fmtbuf);
854 const char *radix_fmt = getRadixFmt();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000855 fmt << "%#7" << radix_fmt << "\t"
856 << "%#7" << radix_fmt << "\t"
857 << "%#7" << radix_fmt << "\t";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400858 outs() << format(fmtbuf.c_str(), TotalObjectText, TotalObjectData,
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000859 TotalObjectBss);
860 fmtbuf.clear();
Jordan Rupprecht8d60f9b2018-09-21 23:48:12 +0000861 fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << "\t"
862 << "%7" PRIx64 "\t";
Youngsuk Kimd4f6ad52024-09-13 05:50:49 -0400863 outs() << format(fmtbuf.c_str(), TotalObjectTotal, TotalObjectTotal)
Hemant Kulkarni5f4ca2f2016-09-12 17:08:28 +0000864 << "(TOTALS)\n";
865}
866
Alex Brachet1f173a02023-02-10 19:40:56 +0000867int llvm_size_main(int argc, char **argv, const llvm::ToolContext &) {
Fangrui Song47db32e2021-07-09 10:26:53 -0700868 BumpPtrAllocator A;
869 StringSaver Saver(A);
870 SizeOptTable Tbl;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000871 ToolName = argv[0];
gbreynoo55b556e2022-07-18 14:53:20 +0100872 opt::InputArgList Args =
873 Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
874 error(Msg);
875 exit(1);
876 });
Fangrui Song47db32e2021-07-09 10:26:53 -0700877 if (Args.hasArg(OPT_help)) {
878 Tbl.printHelp(
879 outs(),
880 (Twine(ToolName) + " [options] <input object files>").str().c_str(),
881 "LLVM object size dumper");
882 // TODO Replace this with OptTable API once it adds extrahelp support.
883 outs() << "\nPass @FILE as argument to read options from FILE.\n";
884 return 0;
885 }
886 if (Args.hasArg(OPT_version)) {
887 outs() << ToolName << '\n';
888 cl::PrintVersionMessage();
889 return 0;
890 }
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000891
Fangrui Song47db32e2021-07-09 10:26:53 -0700892 ELFCommons = Args.hasArg(OPT_common);
893 DarwinLongFormat = Args.hasArg(OPT_l);
894 TotalSizes = Args.hasArg(OPT_totals);
895 StringRef V = Args.getLastArgValue(OPT_format_EQ, "berkeley");
896 if (V == "berkeley")
897 OutputFormat = berkeley;
898 else if (V == "darwin")
899 OutputFormat = darwin;
900 else if (V == "sysv")
901 OutputFormat = sysv;
902 else
903 error("--format value should be one of: 'berkeley', 'darwin', 'sysv'");
904 V = Args.getLastArgValue(OPT_radix_EQ, "10");
905 if (V == "8")
906 Radix = RadixTy::octal;
907 else if (V == "10")
908 Radix = RadixTy::decimal;
909 else if (V == "16")
910 Radix = RadixTy::hexadecimal;
911 else
912 error("--radix value should be one of: 8, 10, 16 ");
913
914 for (const auto *A : Args.filtered(OPT_arch_EQ)) {
915 SmallVector<StringRef, 2> Values;
916 llvm::SplitString(A->getValue(), Values, ",");
917 for (StringRef V : Values) {
918 if (V == "all")
919 ArchAll = true;
920 else if (MachOObjectFile::isValidArch(V))
921 ArchFlags.push_back(V);
922 else {
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000923 outs() << ToolName << ": for the -arch option: Unknown architecture "
Fangrui Song47db32e2021-07-09 10:26:53 -0700924 << "named '" << V << "'";
Kevin Enderbyafef4c92014-07-01 17:19:10 +0000925 return 1;
926 }
927 }
928 }
929
Fangrui Song47db32e2021-07-09 10:26:53 -0700930 InputFilenames = Args.getAllArgValues(OPT_INPUT);
Fangrui Song64449e62018-11-22 00:44:17 +0000931 if (InputFilenames.empty())
Dimitry Andrice4f5d012017-12-18 19:46:56 +0000932 InputFilenames.push_back("a.out");
933
934 MoreThanOneFile = InputFilenames.size() > 1;
935 llvm::for_each(InputFilenames, printFileSectionSizes);
936 if (OutputFormat == berkeley && TotalSizes)
James Hendersoncd893e52019-09-13 12:00:42 +0000937 printBerkeleyTotals();
Dimitry Andrice4f5d012017-12-18 19:46:56 +0000938
Kevin Enderby64f7a992016-05-02 21:41:03 +0000939 if (HadError)
940 return 1;
Alex Brachetd5090cd2022-10-06 05:16:13 +0000941 return 0;
Michael J. Spencerc4ad4662011-09-28 20:57:46 +0000942}