2015-11-05 06:32:32 +08:00
//===-- llvm-size.cpp - Print the size of each object section ---*- C++ -*-===//
2011-09-29 04:57:46 +08:00
//
2019-01-19 16:50:56 +08:00
// 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
2011-09-29 04:57:46 +08:00
//
//===----------------------------------------------------------------------===//
//
// This program is a utility that works like traditional Unix "size",
// that is, it prints out the size of each section, and the total size of all
// sections.
//
//===----------------------------------------------------------------------===//
# include "llvm/ADT/APInt.h"
# include "llvm/Object/Archive.h"
2016-02-10 05:39:49 +08:00
# include "llvm/Object/ELFObjectFile.h"
2014-06-18 01:54:13 +08:00
# include "llvm/Object/MachO.h"
2014-06-19 06:04:40 +08:00
# include "llvm/Object/MachOUniversal.h"
2015-01-14 19:23:27 +08:00
# include "llvm/Object/ObjectFile.h"
2011-09-29 04:57:46 +08:00
# include "llvm/Support/Casting.h"
# include "llvm/Support/CommandLine.h"
# include "llvm/Support/FileSystem.h"
# include "llvm/Support/Format.h"
2018-04-14 02:26:06 +08:00
# include "llvm/Support/InitLLVM.h"
2011-09-29 04:57:46 +08:00
# include "llvm/Support/MemoryBuffer.h"
2019-10-15 01:29:15 +08:00
# include "llvm/Support/WithColor.h"
2012-12-04 18:44:52 +08:00
# include "llvm/Support/raw_ostream.h"
2011-09-29 04:57:46 +08:00
# include <algorithm>
# include <string>
2014-06-13 01:38:55 +08:00
# include <system_error>
2015-11-05 06:32:32 +08:00
2011-09-29 04:57:46 +08:00
using namespace llvm ;
using namespace object ;
2019-06-05 18:32:28 +08:00
cl : : OptionCategory SizeCat ( " llvm-size Options " ) ;
2014-07-02 06:26:31 +08:00
enum OutputFormatTy { berkeley , sysv , darwin } ;
2011-09-29 08:59:18 +08:00
static cl : : opt < OutputFormatTy >
2019-06-05 18:32:28 +08:00
OutputFormat ( " format " , cl : : desc ( " Specify output format " ) ,
cl : : values ( clEnumVal ( sysv , " System V format " ) ,
clEnumVal ( berkeley , " Berkeley format " ) ,
clEnumVal ( darwin , " Darwin -m format " ) ) ,
cl : : init ( berkeley ) , cl : : cat ( SizeCat ) ) ;
static cl : : opt < OutputFormatTy >
OutputFormatShort ( cl : : desc ( " Specify output format " ) ,
cl : : values ( clEnumValN ( sysv , " A " , " System V format " ) ,
clEnumValN ( berkeley , " B " , " Berkeley format " ) ,
clEnumValN ( darwin , " m " , " Darwin -m format " ) ) ,
cl : : init ( berkeley ) , cl : : cat ( SizeCat ) ) ;
2011-09-29 08:59:18 +08:00
2016-02-10 05:35:14 +08:00
static bool BerkeleyHeaderPrinted = false ;
static bool MoreThanOneFile = false ;
2016-09-13 01:08:28 +08:00
static uint64_t TotalObjectText = 0 ;
static uint64_t TotalObjectData = 0 ;
static uint64_t TotalObjectBss = 0 ;
static uint64_t TotalObjectTotal = 0 ;
2014-06-18 01:54:13 +08:00
2014-07-02 06:26:31 +08:00
cl : : opt < bool >
2019-06-05 18:32:28 +08:00
DarwinLongFormat ( " l " ,
cl : : desc ( " When format is darwin, use long format "
" to include addresses and offsets. " ) ,
cl : : cat ( SizeCat ) ) ;
2014-06-18 01:54:13 +08:00
2016-03-29 00:48:10 +08:00
cl : : opt < bool >
ELFCommons ( " common " ,
cl : : desc ( " Print common symbols in the ELF file. When using "
2019-09-13 20:00:42 +08:00
" Berkeley format, this is added to bss. " ) ,
2019-06-05 18:32:28 +08:00
cl : : init ( false ) , cl : : cat ( SizeCat ) ) ;
2016-03-29 00:48:10 +08:00
2014-07-02 01:19:10 +08:00
static cl : : list < std : : string >
2019-06-05 18:32:28 +08:00
ArchFlags ( " arch " , cl : : desc ( " architecture(s) from a Mach-O file to dump " ) ,
cl : : ZeroOrMore , cl : : cat ( SizeCat ) ) ;
2018-06-23 06:20:10 +08:00
static bool ArchAll = false ;
2014-07-02 01:19:10 +08:00
2014-07-02 06:26:31 +08:00
enum RadixTy { octal = 8 , decimal = 10 , hexadecimal = 16 } ;
2018-10-30 19:52:47 +08:00
static cl : : opt < RadixTy > Radix (
" radix " , cl : : desc ( " Print size in radix " ) , cl : : init ( decimal ) ,
cl : : values ( clEnumValN ( octal , " 8 " , " Print size in octal " ) ,
clEnumValN ( decimal , " 10 " , " Print size in decimal " ) ,
2019-06-05 18:32:28 +08:00
clEnumValN ( hexadecimal , " 16 " , " Print size in hexadecimal " ) ) ,
cl : : cat ( SizeCat ) ) ;
2011-09-29 08:59:18 +08:00
2019-06-05 18:32:28 +08:00
static cl : : opt < RadixTy > RadixShort (
cl : : desc ( " Print size in radix: " ) ,
cl : : values ( clEnumValN ( octal , " o " , " Print size in octal " ) ,
clEnumValN ( decimal , " d " , " Print size in decimal " ) ,
clEnumValN ( hexadecimal , " x " , " Print size in hexadecimal " ) ) ,
cl : : init ( decimal ) , cl : : cat ( SizeCat ) ) ;
2011-09-29 08:59:18 +08:00
2016-09-13 01:08:28 +08:00
static cl : : opt < bool >
TotalSizes ( " totals " ,
cl : : desc ( " Print totals of all objects - Berkeley format only " ) ,
2019-06-05 18:32:28 +08:00
cl : : init ( false ) , cl : : cat ( SizeCat ) ) ;
2016-09-13 01:08:28 +08:00
static cl : : alias TotalSizesShort ( " t " , cl : : desc ( " Short for --totals " ) ,
cl : : aliasopt ( TotalSizes ) ) ;
2011-09-29 08:59:18 +08:00
static cl : : list < std : : string >
2019-06-05 18:32:28 +08:00
InputFilenames ( cl : : Positional , cl : : desc ( " <input files> " ) , cl : : ZeroOrMore ) ;
2011-09-29 08:59:18 +08:00
2019-06-21 19:49:20 +08:00
static cl : : extrahelp
HelpResponse ( " \n Pass @FILE as argument to read options from FILE. \n " ) ;
2018-06-23 06:20:10 +08:00
static bool HadError = false ;
2016-05-03 05:41:03 +08:00
2011-09-29 08:59:18 +08:00
static std : : string ToolName ;
2019-10-15 01:29:15 +08:00
static void error ( const Twine & Message , StringRef File ) {
2016-06-29 07:16:13 +08:00
HadError = true ;
2019-10-15 01:29:15 +08:00
WithColor : : error ( errs ( ) , ToolName ) < < " ' " < < File < < " ': " < < Message < < " \n " ;
2016-06-29 07:16:13 +08:00
}
2016-05-18 01:10:12 +08:00
// This version of error() prints the archive name and member name, for example:
// "libx.a(foo.o)" after the ToolName before the error message. It sets
2016-09-13 01:08:28 +08:00
// HadError but returns allowing the code to move on to other archive members.
2016-06-01 04:35:34 +08:00
static void error ( llvm : : Error E , StringRef FileName , const Archive : : Child & C ,
StringRef ArchitectureName = StringRef ( ) ) {
2016-05-18 01:10:12 +08:00
HadError = true ;
2019-10-15 01:29:15 +08:00
WithColor : : error ( errs ( ) , ToolName ) < < " ' " < < FileName < < " ' " ;
2016-05-18 01:10:12 +08:00
2016-07-30 01:44:13 +08:00
Expected < StringRef > NameOrErr = C . getName ( ) ;
2016-05-18 01:10:12 +08:00
// TODO: if we have a error getting the name then it would be nice to print
// the index of which archive member this is and or its offset in the
// archive instead of "???" as the name.
2016-07-30 01:44:13 +08:00
if ( ! NameOrErr ) {
consumeError ( NameOrErr . takeError ( ) ) ;
2016-05-18 01:10:12 +08:00
errs ( ) < < " ( " < < " ??? " < < " ) " ;
2016-07-30 01:44:13 +08:00
} else
2016-05-18 01:10:12 +08:00
errs ( ) < < " ( " < < NameOrErr . get ( ) < < " ) " ;
2016-06-01 04:35:34 +08:00
if ( ! ArchitectureName . empty ( ) )
errs ( ) < < " (for architecture " < < ArchitectureName < < " ) " ;
std : : string Buf ;
raw_string_ostream OS ( Buf ) ;
2018-11-11 09:46:03 +08:00
logAllUnhandledErrors ( std : : move ( E ) , OS ) ;
2016-06-01 04:35:34 +08:00
OS . flush ( ) ;
2019-10-15 01:29:15 +08:00
errs ( ) < < " : " < < Buf < < " \n " ;
2016-06-01 04:35:34 +08:00
}
// 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
// before the error message. It sets HadError but returns allowing the code to
2016-09-13 01:08:28 +08:00
// move on to other architecture slices.
2016-06-01 04:35:34 +08:00
static void error ( llvm : : Error E , StringRef FileName ,
StringRef ArchitectureName = StringRef ( ) ) {
HadError = true ;
2019-10-15 01:29:15 +08:00
WithColor : : error ( errs ( ) , ToolName ) < < " ' " < < FileName < < " ' " ;
2016-06-01 04:35:34 +08:00
if ( ! ArchitectureName . empty ( ) )
errs ( ) < < " (for architecture " < < ArchitectureName < < " ) " ;
2016-05-18 01:10:12 +08:00
std : : string Buf ;
raw_string_ostream OS ( Buf ) ;
2018-11-11 09:46:03 +08:00
logAllUnhandledErrors ( std : : move ( E ) , OS ) ;
2016-05-18 01:10:12 +08:00
OS . flush ( ) ;
2019-10-15 01:29:15 +08:00
errs ( ) < < " : " < < Buf < < " \n " ;
2016-05-18 01:10:12 +08:00
}
2016-02-10 05:32:56 +08:00
/// Get the length of the string that represents @p num in Radix including the
/// leading 0x or 0 for hexadecimal and octal respectively.
2011-09-29 09:22:31 +08:00
static size_t getNumLengthAsString ( uint64_t num ) {
2011-09-29 04:57:46 +08:00
APInt conv ( 64 , num ) ;
SmallString < 32 > result ;
2011-09-29 08:59:18 +08:00
conv . toString ( result , Radix , false , true ) ;
2011-09-29 04:57:46 +08:00
return result . size ( ) ;
}
2016-02-10 05:32:56 +08:00
/// Return the printing format for the Radix.
2015-11-05 06:32:32 +08:00
static const char * getRadixFmt ( ) {
2014-06-18 01:54:13 +08:00
switch ( Radix ) {
case octal :
return PRIo64 ;
case decimal :
return PRIu64 ;
case hexadecimal :
return PRIx64 ;
}
return nullptr ;
}
2016-02-10 05:39:49 +08:00
/// Remove unneeded ELF sections from calculation
static bool considerForSize ( ObjectFile * Obj , SectionRef Section ) {
if ( ! Obj - > isELF ( ) )
return true ;
switch ( static_cast < ELFSectionRef > ( Section ) . getType ( ) ) {
case ELF : : SHT_NULL :
case ELF : : SHT_SYMTAB :
2020-07-01 18:57:30 +08:00
return false ;
2016-02-10 05:39:49 +08:00
case ELF : : SHT_STRTAB :
case ELF : : SHT_REL :
case ELF : : SHT_RELA :
2020-07-01 18:57:30 +08:00
return static_cast < ELFSectionRef > ( Section ) . getFlags ( ) & ELF : : SHF_ALLOC ;
2016-02-10 05:39:49 +08:00
}
return true ;
}
2016-03-29 00:48:10 +08:00
/// Total size of all ELF common symbols
2020-04-10 20:24:21 +08:00
static Expected < uint64_t > getCommonSize ( ObjectFile * Obj ) {
2016-03-29 00:48:10 +08:00
uint64_t TotalCommons = 0 ;
2020-04-10 20:24:21 +08:00
for ( auto & Sym : Obj - > symbols ( ) ) {
Expected < uint32_t > SymFlagsOrErr =
Obj - > getSymbolFlags ( Sym . getRawDataRefImpl ( ) ) ;
if ( ! SymFlagsOrErr )
return SymFlagsOrErr . takeError ( ) ;
if ( * SymFlagsOrErr & SymbolRef : : SF_Common )
2016-03-29 00:48:10 +08:00
TotalCommons + = Obj - > getCommonSymbolSize ( Sym . getRawDataRefImpl ( ) ) ;
2020-04-10 20:24:21 +08:00
}
2016-03-29 00:48:10 +08:00
return TotalCommons ;
}
2016-02-10 05:32:56 +08:00
/// Print the size of each Mach-O segment and section in @p MachO.
2014-06-18 01:54:13 +08:00
///
/// This is when used when @c OutputFormat is darwin and produces the same
/// output as darwin's size(1) -m output.
2016-02-10 05:35:14 +08:00
static void printDarwinSectionSizes ( MachOObjectFile * MachO ) {
2014-06-18 01:54:13 +08:00
std : : string fmtbuf ;
raw_string_ostream fmt ( fmtbuf ) ;
const char * radix_fmt = getRadixFmt ( ) ;
if ( Radix = = hexadecimal )
fmt < < " 0x " ;
fmt < < " % " < < radix_fmt ;
uint32_t Filetype = MachO - > getHeader ( ) . filetype ;
uint64_t total = 0 ;
2015-06-04 06:19:36 +08:00
for ( const auto & Load : MachO - > load_commands ( ) ) {
2014-06-18 01:54:13 +08:00
if ( Load . C . cmd = = MachO : : LC_SEGMENT_64 ) {
MachO : : segment_command_64 Seg = MachO - > getSegment64LoadCommand ( Load ) ;
outs ( ) < < " Segment " < < Seg . segname < < " : "
< < format ( fmt . str ( ) . c_str ( ) , Seg . vmsize ) ;
if ( DarwinLongFormat )
2014-07-02 06:26:31 +08:00
outs ( ) < < " (vmaddr 0x " < < format ( " % " PRIx64 , Seg . vmaddr ) < < " fileoff "
< < Seg . fileoff < < " ) " ;
2014-06-18 01:54:13 +08:00
outs ( ) < < " \n " ;
total + = Seg . vmsize ;
uint64_t sec_total = 0 ;
for ( unsigned J = 0 ; J < Seg . nsects ; + + J ) {
MachO : : section_64 Sec = MachO - > getSection64 ( Load , J ) ;
if ( Filetype = = MachO : : MH_OBJECT )
outs ( ) < < " \t Section ( " < < format ( " %.16s " , & Sec . segname ) < < " , "
< < format ( " %.16s " , & Sec . sectname ) < < " ): " ;
else
outs ( ) < < " \t Section " < < format ( " %.16s " , & Sec . sectname ) < < " : " ;
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , Sec . size ) ;
if ( DarwinLongFormat )
2014-07-02 06:26:31 +08:00
outs ( ) < < " (addr 0x " < < format ( " % " PRIx64 , Sec . addr ) < < " offset "
< < Sec . offset < < " ) " ;
2014-06-18 01:54:13 +08:00
outs ( ) < < " \n " ;
sec_total + = Sec . size ;
}
if ( Seg . nsects ! = 0 )
outs ( ) < < " \t total " < < format ( fmt . str ( ) . c_str ( ) , sec_total ) < < " \n " ;
2014-07-02 06:26:31 +08:00
} else if ( Load . C . cmd = = MachO : : LC_SEGMENT ) {
2014-06-18 01:54:13 +08:00
MachO : : segment_command Seg = MachO - > getSegmentLoadCommand ( Load ) ;
2016-02-10 02:33:15 +08:00
uint64_t Seg_vmsize = Seg . vmsize ;
2014-06-18 01:54:13 +08:00
outs ( ) < < " Segment " < < Seg . segname < < " : "
2016-02-10 02:33:15 +08:00
< < format ( fmt . str ( ) . c_str ( ) , Seg_vmsize ) ;
2014-06-18 01:54:13 +08:00
if ( DarwinLongFormat )
2016-02-10 02:33:15 +08:00
outs ( ) < < " (vmaddr 0x " < < format ( " % " PRIx32 , Seg . vmaddr ) < < " fileoff "
2014-07-02 06:26:31 +08:00
< < Seg . fileoff < < " ) " ;
2014-06-18 01:54:13 +08:00
outs ( ) < < " \n " ;
total + = Seg . vmsize ;
uint64_t sec_total = 0 ;
for ( unsigned J = 0 ; J < Seg . nsects ; + + J ) {
MachO : : section Sec = MachO - > getSection ( Load , J ) ;
if ( Filetype = = MachO : : MH_OBJECT )
outs ( ) < < " \t Section ( " < < format ( " %.16s " , & Sec . segname ) < < " , "
< < format ( " %.16s " , & Sec . sectname ) < < " ): " ;
else
outs ( ) < < " \t Section " < < format ( " %.16s " , & Sec . sectname ) < < " : " ;
2016-02-10 02:33:15 +08:00
uint64_t Sec_size = Sec . size ;
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , Sec_size ) ;
2014-06-18 01:54:13 +08:00
if ( DarwinLongFormat )
2016-02-10 02:33:15 +08:00
outs ( ) < < " (addr 0x " < < format ( " % " PRIx32 , Sec . addr ) < < " offset "
2014-07-02 06:26:31 +08:00
< < Sec . offset < < " ) " ;
2014-06-18 01:54:13 +08:00
outs ( ) < < " \n " ;
sec_total + = Sec . size ;
}
if ( Seg . nsects ! = 0 )
outs ( ) < < " \t total " < < format ( fmt . str ( ) . c_str ( ) , sec_total ) < < " \n " ;
}
}
outs ( ) < < " total " < < format ( fmt . str ( ) . c_str ( ) , total ) < < " \n " ;
}
2016-02-10 05:32:56 +08:00
/// Print the summary sizes of the standard Mach-O segments in @p MachO.
2014-06-18 01:54:13 +08:00
///
/// This is when used when @c OutputFormat is berkeley with a Mach-O file and
/// produces the same output as darwin's size(1) default output.
2016-02-10 05:35:14 +08:00
static void printDarwinSegmentSizes ( MachOObjectFile * MachO ) {
2014-06-18 01:54:13 +08:00
uint64_t total_text = 0 ;
uint64_t total_data = 0 ;
uint64_t total_objc = 0 ;
uint64_t total_others = 0 ;
2015-06-04 06:19:36 +08:00
for ( const auto & Load : MachO - > load_commands ( ) ) {
2014-06-18 01:54:13 +08:00
if ( Load . C . cmd = = MachO : : LC_SEGMENT_64 ) {
MachO : : segment_command_64 Seg = MachO - > getSegment64LoadCommand ( Load ) ;
if ( MachO - > getHeader ( ) . filetype = = MachO : : MH_OBJECT ) {
for ( unsigned J = 0 ; J < Seg . nsects ; + + J ) {
MachO : : section_64 Sec = MachO - > getSection64 ( Load , J ) ;
StringRef SegmentName = StringRef ( Sec . segname ) ;
if ( SegmentName = = " __TEXT " )
total_text + = Sec . size ;
else if ( SegmentName = = " __DATA " )
total_data + = Sec . size ;
else if ( SegmentName = = " __OBJC " )
total_objc + = Sec . size ;
else
total_others + = Sec . size ;
2014-07-02 06:26:31 +08:00
}
2014-06-18 01:54:13 +08:00
} else {
StringRef SegmentName = StringRef ( Seg . segname ) ;
if ( SegmentName = = " __TEXT " )
total_text + = Seg . vmsize ;
else if ( SegmentName = = " __DATA " )
total_data + = Seg . vmsize ;
else if ( SegmentName = = " __OBJC " )
total_objc + = Seg . vmsize ;
else
total_others + = Seg . vmsize ;
}
2014-07-02 06:26:31 +08:00
} else if ( Load . C . cmd = = MachO : : LC_SEGMENT ) {
2014-06-18 01:54:13 +08:00
MachO : : segment_command Seg = MachO - > getSegmentLoadCommand ( Load ) ;
if ( MachO - > getHeader ( ) . filetype = = MachO : : MH_OBJECT ) {
for ( unsigned J = 0 ; J < Seg . nsects ; + + J ) {
MachO : : section Sec = MachO - > getSection ( Load , J ) ;
StringRef SegmentName = StringRef ( Sec . segname ) ;
if ( SegmentName = = " __TEXT " )
total_text + = Sec . size ;
else if ( SegmentName = = " __DATA " )
total_data + = Sec . size ;
else if ( SegmentName = = " __OBJC " )
total_objc + = Sec . size ;
else
total_others + = Sec . size ;
2014-07-02 06:26:31 +08:00
}
2014-06-18 01:54:13 +08:00
} else {
StringRef SegmentName = StringRef ( Seg . segname ) ;
if ( SegmentName = = " __TEXT " )
total_text + = Seg . vmsize ;
else if ( SegmentName = = " __DATA " )
total_data + = Seg . vmsize ;
else if ( SegmentName = = " __OBJC " )
total_objc + = Seg . vmsize ;
else
total_others + = Seg . vmsize ;
}
}
}
uint64_t total = total_text + total_data + total_objc + total_others ;
2016-02-10 05:35:14 +08:00
if ( ! BerkeleyHeaderPrinted ) {
2014-06-18 01:54:13 +08:00
outs ( ) < < " __TEXT \t __DATA \t __OBJC \t others \t dec \t hex \n " ;
2016-02-10 05:35:14 +08:00
BerkeleyHeaderPrinted = true ;
2014-06-18 01:54:13 +08:00
}
outs ( ) < < total_text < < " \t " < < total_data < < " \t " < < total_objc < < " \t "
< < total_others < < " \t " < < total < < " \t " < < format ( " % " PRIx64 , total )
< < " \t " ;
}
2016-02-10 05:32:56 +08:00
/// Print the size of each section in @p Obj.
2011-09-29 08:59:18 +08:00
///
/// The format used is determined by @c OutputFormat and @c Radix.
2016-02-10 05:35:14 +08:00
static void printObjectSectionSizes ( ObjectFile * Obj ) {
2011-09-29 04:57:46 +08:00
uint64_t total = 0 ;
std : : string fmtbuf ;
raw_string_ostream fmt ( fmtbuf ) ;
2014-06-18 01:54:13 +08:00
const char * radix_fmt = getRadixFmt ( ) ;
// If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
// size(1) -m output, else if OutputFormat is darwin and not a Mach-O object
// let it fall through to OutputFormat berkeley.
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( Obj ) ;
if ( OutputFormat = = darwin & & MachO )
2016-02-10 05:35:14 +08:00
printDarwinSectionSizes ( MachO ) ;
2014-06-18 01:54:13 +08:00
// If we have a MachOObjectFile and the OutputFormat is berkeley print as
// darwin's default berkeley format for Mach-O files.
else if ( MachO & & OutputFormat = = berkeley )
2016-02-10 05:35:14 +08:00
printDarwinSegmentSizes ( MachO ) ;
2014-06-18 01:54:13 +08:00
else if ( OutputFormat = = sysv ) {
2011-09-29 04:57:46 +08:00
// Run two passes over all sections. The first gets the lengths needed for
// formatting the output. The second actually does the output.
std : : size_t max_name_len = strlen ( " section " ) ;
2011-09-29 08:59:18 +08:00
std : : size_t max_size_len = strlen ( " size " ) ;
std : : size_t max_addr_len = strlen ( " addr " ) ;
2014-03-13 22:37:36 +08:00
for ( const SectionRef & Section : Obj - > sections ( ) ) {
2016-02-10 05:39:49 +08:00
if ( ! considerForSize ( Obj , Section ) )
continue ;
2014-10-08 23:28:58 +08:00
uint64_t size = Section . getSize ( ) ;
2011-09-29 04:57:46 +08:00
total + = size ;
2019-08-14 19:10:11 +08:00
Expected < StringRef > name_or_err = Section . getName ( ) ;
if ( ! name_or_err ) {
error ( name_or_err . takeError ( ) , Obj - > getFileName ( ) ) ;
2014-03-13 22:37:36 +08:00
return ;
2019-08-14 19:10:11 +08:00
}
2014-10-08 23:28:58 +08:00
uint64_t addr = Section . getAddress ( ) ;
2019-08-14 19:10:11 +08:00
max_name_len = std : : max ( max_name_len , name_or_err - > size ( ) ) ;
2011-09-29 09:22:31 +08:00
max_size_len = std : : max ( max_size_len , getNumLengthAsString ( size ) ) ;
max_addr_len = std : : max ( max_addr_len , getNumLengthAsString ( addr ) ) ;
2011-09-29 04:57:46 +08:00
}
2011-09-29 08:59:18 +08:00
// Add extra padding.
2011-09-29 04:57:46 +08:00
max_name_len + = 2 ;
max_size_len + = 2 ;
max_addr_len + = 2 ;
2011-09-29 08:59:18 +08:00
// Setup header format.
2011-09-29 04:57:46 +08:00
fmt < < " %- " < < max_name_len < < " s "
< < " % " < < max_size_len < < " s "
< < " % " < < max_addr_len < < " s \n " ;
// Print header
2014-07-02 06:26:31 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , static_cast < const char * > ( " section " ) ,
static_cast < const char * > ( " size " ) ,
static_cast < const char * > ( " addr " ) ) ;
2011-09-29 04:57:46 +08:00
fmtbuf . clear ( ) ;
// Setup per section format.
fmt < < " %- " < < max_name_len < < " s "
< < " %# " < < max_size_len < < radix_fmt < < " "
< < " %# " < < max_addr_len < < radix_fmt < < " \n " ;
// Print each section.
2014-03-13 22:37:36 +08:00
for ( const SectionRef & Section : Obj - > sections ( ) ) {
2016-02-10 05:39:49 +08:00
if ( ! considerForSize ( Obj , Section ) )
continue ;
2019-08-14 19:10:11 +08:00
Expected < StringRef > name_or_err = Section . getName ( ) ;
if ( ! name_or_err ) {
error ( name_or_err . takeError ( ) , Obj - > getFileName ( ) ) ;
2014-03-13 22:37:36 +08:00
return ;
2019-08-14 19:10:11 +08:00
}
2014-10-08 23:28:58 +08:00
uint64_t size = Section . getSize ( ) ;
uint64_t addr = Section . getAddress ( ) ;
2019-08-14 19:10:11 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , name_or_err - > str ( ) . c_str ( ) , size , addr ) ;
2011-09-29 04:57:46 +08:00
}
2016-03-29 00:48:10 +08:00
if ( ELFCommons ) {
2020-04-10 20:24:21 +08:00
if ( Expected < uint64_t > CommonSizeOrErr = getCommonSize ( Obj ) ) {
total + = * CommonSizeOrErr ;
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , std : : string ( " *COM* " ) . c_str ( ) ,
* CommonSizeOrErr , static_cast < uint64_t > ( 0 ) ) ;
} else {
error ( CommonSizeOrErr . takeError ( ) , Obj - > getFileName ( ) ) ;
return ;
}
2016-03-29 00:48:10 +08:00
}
2011-09-29 04:57:46 +08:00
// Print total.
fmtbuf . clear ( ) ;
fmt < < " %- " < < max_name_len < < " s "
< < " %# " < < max_size_len < < radix_fmt < < " \n " ;
2014-07-02 06:26:31 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , static_cast < const char * > ( " Total " ) ,
2020-01-03 14:04:01 +08:00
total )
< < " \n \n " ;
2011-09-29 04:57:46 +08:00
} else {
2011-09-29 08:59:18 +08:00
// The Berkeley format does not display individual section sizes. It
// displays the cumulative size for each section type.
2011-09-29 04:57:46 +08:00
uint64_t total_text = 0 ;
uint64_t total_data = 0 ;
uint64_t total_bss = 0 ;
2011-09-29 08:59:18 +08:00
// Make one pass over the section table to calculate sizes.
2014-03-13 22:37:36 +08:00
for ( const SectionRef & Section : Obj - > sections ( ) ) {
2014-10-08 23:28:58 +08:00
uint64_t size = Section . getSize ( ) ;
2018-12-14 03:40:12 +08:00
bool isText = Section . isBerkeleyText ( ) ;
bool isData = Section . isBerkeleyData ( ) ;
2014-10-08 23:28:58 +08:00
bool isBSS = Section . isBSS ( ) ;
2011-09-29 04:57:46 +08:00
if ( isText )
total_text + = size ;
else if ( isData )
total_data + = size ;
else if ( isBSS )
total_bss + = size ;
}
2020-04-10 20:24:21 +08:00
if ( ELFCommons ) {
if ( Expected < uint64_t > CommonSizeOrErr = getCommonSize ( Obj ) )
total_bss + = * CommonSizeOrErr ;
else {
error ( CommonSizeOrErr . takeError ( ) , Obj - > getFileName ( ) ) ;
return ;
}
}
2016-03-29 00:48:10 +08:00
2011-09-29 04:57:46 +08:00
total = total_text + total_data + total_bss ;
2016-09-13 01:08:28 +08:00
if ( TotalSizes ) {
TotalObjectText + = total_text ;
TotalObjectData + = total_data ;
TotalObjectBss + = total_bss ;
TotalObjectTotal + = total ;
}
2016-02-10 05:35:14 +08:00
if ( ! BerkeleyHeaderPrinted ) {
2018-09-22 07:48:12 +08:00
outs ( ) < < " text \t "
" data \t "
" bss \t "
" "
< < ( Radix = = octal ? " oct " : " dec " )
< < " \t "
" hex \t "
" filename \n " ;
2016-02-10 05:35:14 +08:00
BerkeleyHeaderPrinted = true ;
2014-06-18 01:54:13 +08:00
}
2011-09-29 04:57:46 +08:00
// Print result.
2018-09-22 07:48:12 +08:00
fmt < < " %#7 " < < radix_fmt < < " \t "
< < " %#7 " < < radix_fmt < < " \t "
< < " %#7 " < < radix_fmt < < " \t " ;
2014-07-02 06:26:31 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , total_text , total_data , total_bss ) ;
2011-09-29 04:57:46 +08:00
fmtbuf . clear ( ) ;
2018-09-22 07:48:12 +08:00
fmt < < " %7 " < < ( Radix = = octal ? PRIo64 : PRIu64 ) < < " \t "
< < " %7 " PRIx64 " \t " ;
2014-07-02 06:26:31 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , total , total ) ;
2011-09-29 04:57:46 +08:00
}
}
2016-11-01 01:11:31 +08:00
/// Checks to see if the @p O ObjectFile is a Mach-O file and if it is and there
2016-02-10 05:32:56 +08:00
/// is a list of architecture flags specified then check to make sure this
/// Mach-O file is one of those architectures or all architectures was
/// specificed. If not then an error is generated and this routine returns
/// false. Else it returns true.
2016-11-01 01:11:31 +08:00
static bool checkMachOAndArchFlags ( ObjectFile * O , StringRef Filename ) {
auto * MachO = dyn_cast < MachOObjectFile > ( O ) ;
if ( ! MachO | | ArchAll | | ArchFlags . empty ( ) )
return true ;
MachO : : mach_header H ;
MachO : : mach_header_64 H_64 ;
Triple T ;
if ( MachO - > is64Bit ( ) ) {
H_64 = MachO - > MachOObjectFile : : getHeader64 ( ) ;
T = MachOObjectFile : : getArchTriple ( H_64 . cputype , H_64 . cpusubtype ) ;
} else {
H = MachO - > MachOObjectFile : : getHeader ( ) ;
T = MachOObjectFile : : getArchTriple ( H . cputype , H . cpusubtype ) ;
}
2020-12-28 01:57:25 +08:00
if ( ! is_contained ( ArchFlags , T . getArchName ( ) ) ) {
2019-10-15 01:29:15 +08:00
error ( " no architecture specified " , Filename ) ;
2016-11-01 01:11:31 +08:00
return false ;
2014-07-02 01:19:10 +08:00
}
return true ;
}
2016-02-10 05:32:56 +08:00
/// Print the section sizes for @p file. If @p file is an archive, print the
/// section sizes for each archive member.
2016-02-10 05:35:14 +08:00
static void printFileSectionSizes ( StringRef file ) {
2011-09-29 04:57:46 +08:00
2011-09-29 08:59:18 +08:00
// Attempt to open the binary.
2016-04-07 06:14:09 +08:00
Expected < OwningBinary < Binary > > BinaryOrErr = createBinary ( file ) ;
if ( ! BinaryOrErr ) {
2016-08-06 02:19:40 +08:00
error ( BinaryOrErr . takeError ( ) , file ) ;
2011-09-29 04:57:46 +08:00
return ;
2016-04-07 06:14:09 +08:00
}
2014-08-20 02:44:46 +08:00
Binary & Bin = * BinaryOrErr . get ( ) . getBinary ( ) ;
2011-09-29 04:57:46 +08:00
2014-08-01 22:31:55 +08:00
if ( Archive * a = dyn_cast < Archive > ( & Bin ) ) {
2011-09-29 08:59:18 +08:00
// This is an archive. Iterate over each member and display its sizes.
2016-11-11 12:28:40 +08:00
Error Err = Error : : success ( ) ;
2016-07-14 10:24:01 +08:00
for ( auto & C : a - > children ( Err ) ) {
Expected < std : : unique_ptr < Binary > > ChildOrErr = C . getAsBinary ( ) ;
2016-05-18 01:10:12 +08:00
if ( ! ChildOrErr ) {
if ( auto E = isNotObjectErrorInvalidFileType ( ChildOrErr . takeError ( ) ) )
2016-07-14 10:24:01 +08:00
error ( std : : move ( E ) , a - > getFileName ( ) , C ) ;
2011-09-29 04:57:46 +08:00
continue ;
2016-05-18 01:10:12 +08:00
}
2014-06-17 00:08:36 +08:00
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * ChildOrErr . get ( ) ) ) {
2014-06-18 01:54:13 +08:00
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
2014-07-02 01:19:10 +08:00
if ( ! checkMachOAndArchFlags ( o , file ) )
return ;
2011-09-29 04:57:46 +08:00
if ( OutputFormat = = sysv )
2014-07-02 06:26:31 +08:00
outs ( ) < < o - > getFileName ( ) < < " (ex " < < a - > getFileName ( ) < < " ): \n " ;
else if ( MachO & & OutputFormat = = darwin )
outs ( ) < < a - > getFileName ( ) < < " ( " < < o - > getFileName ( ) < < " ): \n " ;
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-06-18 01:54:13 +08:00
if ( OutputFormat = = berkeley ) {
if ( MachO )
outs ( ) < < a - > getFileName ( ) < < " ( " < < o - > getFileName ( ) < < " ) \n " ;
else
outs ( ) < < o - > getFileName ( ) < < " (ex " < < a - > getFileName ( ) < < " ) \n " ;
}
2011-09-29 04:57:46 +08:00
}
}
2016-07-14 10:24:01 +08:00
if ( Err )
error ( std : : move ( Err ) , a - > getFileName ( ) ) ;
2014-06-19 06:04:40 +08:00
} else if ( MachOUniversalBinary * UB =
2014-08-01 22:31:55 +08:00
dyn_cast < MachOUniversalBinary > ( & Bin ) ) {
2014-07-02 01:19:10 +08:00
// If we have a list of architecture flags specified dump only those.
2018-12-20 08:57:06 +08:00
if ( ! ArchAll & & ! ArchFlags . empty ( ) ) {
2014-07-02 01:19:10 +08:00
// Look for a slice in the universal binary that matches each ArchFlag.
bool ArchFound ;
2014-07-02 06:26:31 +08:00
for ( unsigned i = 0 ; i < ArchFlags . size ( ) ; + + i ) {
2014-07-02 01:19:10 +08:00
ArchFound = false ;
for ( MachOUniversalBinary : : object_iterator I = UB - > begin_objects ( ) ,
E = UB - > end_objects ( ) ;
I ! = E ; + + I ) {
2016-12-17 06:54:02 +08:00
if ( ArchFlags [ i ] = = I - > getArchFlagName ( ) ) {
2014-07-02 01:19:10 +08:00
ArchFound = true ;
2016-06-01 04:35:34 +08:00
Expected < std : : unique_ptr < ObjectFile > > UO = I - > getAsObjectFile ( ) ;
2014-07-02 01:19:10 +08:00
if ( UO ) {
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * UO . get ( ) ) ) {
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " : \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin ) {
2016-02-10 05:35:14 +08:00
if ( MoreThanOneFile | | ArchFlags . size ( ) > 1 )
2014-07-02 01:19:10 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ): \n " ;
2014-07-02 01:19:10 +08:00
}
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-07-02 01:19:10 +08:00
if ( OutputFormat = = berkeley ) {
2016-02-10 05:35:14 +08:00
if ( ! MachO | | MoreThanOneFile | | ArchFlags . size ( ) > 1 )
2014-07-02 01:19:10 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ) " ;
2014-07-02 01:19:10 +08:00
outs ( ) < < " \n " ;
}
}
2016-06-01 04:35:34 +08:00
} else if ( auto E = isNotObjectErrorInvalidFileType (
UO . takeError ( ) ) ) {
error ( std : : move ( E ) , file , ArchFlags . size ( ) > 1 ?
2016-12-17 06:54:02 +08:00
StringRef ( I - > getArchFlagName ( ) ) : StringRef ( ) ) ;
2016-06-01 04:35:34 +08:00
return ;
2016-06-29 07:16:13 +08:00
} else if ( Expected < std : : unique_ptr < Archive > > AOrErr =
2014-12-10 05:05:36 +08:00
I - > getAsArchive ( ) ) {
std : : unique_ptr < Archive > & UA = * AOrErr ;
2014-07-02 01:19:10 +08:00
// This is an archive. Iterate over each member and display its
2014-07-02 06:26:31 +08:00
// sizes.
2016-11-11 12:28:40 +08:00
Error Err = Error : : success ( ) ;
2016-07-14 10:24:01 +08:00
for ( auto & C : UA - > children ( Err ) ) {
Expected < std : : unique_ptr < Binary > > ChildOrErr = C . getAsBinary ( ) ;
2016-05-18 01:10:12 +08:00
if ( ! ChildOrErr ) {
2016-06-01 04:35:34 +08:00
if ( auto E = isNotObjectErrorInvalidFileType (
ChildOrErr . takeError ( ) ) )
2016-07-14 10:24:01 +08:00
error ( std : : move ( E ) , UA - > getFileName ( ) , C ,
2016-06-01 04:35:34 +08:00
ArchFlags . size ( ) > 1 ?
2016-12-17 06:54:02 +08:00
StringRef ( I - > getArchFlagName ( ) ) : StringRef ( ) ) ;
2014-07-02 01:19:10 +08:00
continue ;
2016-05-18 01:10:12 +08:00
}
2014-07-02 01:19:10 +08:00
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * ChildOrErr . get ( ) ) ) {
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ): \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin )
2014-07-02 01:19:10 +08:00
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( )
2014-07-02 06:26:31 +08:00
< < " ) "
2016-12-17 06:54:02 +08:00
< < " (for architecture " < < I - > getArchFlagName ( )
2014-07-02 06:26:31 +08:00
< < " ): \n " ;
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-07-02 01:19:10 +08:00
if ( OutputFormat = = berkeley ) {
if ( MachO ) {
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( )
< < " ) " ;
if ( ArchFlags . size ( ) > 1 )
2016-12-17 06:54:02 +08:00
outs ( ) < < " (for architecture " < < I - > getArchFlagName ( )
2014-07-02 06:26:31 +08:00
< < " ) " ;
2014-07-02 01:19:10 +08:00
outs ( ) < < " \n " ;
2014-07-02 06:26:31 +08:00
} else
2014-07-02 01:19:10 +08:00
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ) \n " ;
}
}
}
2016-07-14 10:24:01 +08:00
if ( Err )
error ( std : : move ( Err ) , UA - > getFileName ( ) ) ;
2016-06-29 07:16:13 +08:00
} else {
consumeError ( AOrErr . takeError ( ) ) ;
2019-10-15 01:29:15 +08:00
error ( " mach-o universal file for architecture " +
StringRef ( I - > getArchFlagName ( ) ) +
" is not a mach-o file or an archive file " ,
file ) ;
2014-07-02 01:19:10 +08:00
}
}
}
if ( ! ArchFound ) {
2019-10-15 01:29:15 +08:00
error ( " file does not contain architecture " + ArchFlags [ i ] , file ) ;
2014-07-02 01:19:10 +08:00
return ;
}
}
return ;
}
// No architecture flags were specified so if this contains a slice that
// matches the host architecture dump only that.
if ( ! ArchAll ) {
2014-07-02 06:26:31 +08:00
StringRef HostArchName = MachOObjectFile : : getHostArch ( ) . getArchName ( ) ;
2014-07-02 01:19:10 +08:00
for ( MachOUniversalBinary : : object_iterator I = UB - > begin_objects ( ) ,
E = UB - > end_objects ( ) ;
I ! = E ; + + I ) {
2016-12-17 06:54:02 +08:00
if ( HostArchName = = I - > getArchFlagName ( ) ) {
2016-06-01 04:35:34 +08:00
Expected < std : : unique_ptr < ObjectFile > > UO = I - > getAsObjectFile ( ) ;
2014-07-02 01:19:10 +08:00
if ( UO ) {
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * UO . get ( ) ) ) {
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " : \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin ) {
2016-02-10 05:35:14 +08:00
if ( MoreThanOneFile )
2014-07-02 01:19:10 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ): \n " ;
2014-07-02 01:19:10 +08:00
}
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-07-02 01:19:10 +08:00
if ( OutputFormat = = berkeley ) {
2016-02-10 05:35:14 +08:00
if ( ! MachO | | MoreThanOneFile )
2014-07-02 01:19:10 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ) " ;
2014-07-02 01:19:10 +08:00
outs ( ) < < " \n " ;
}
}
2016-06-01 04:35:34 +08:00
} else if ( auto E = isNotObjectErrorInvalidFileType ( UO . takeError ( ) ) ) {
error ( std : : move ( E ) , file ) ;
return ;
2016-06-29 07:16:13 +08:00
} else if ( Expected < std : : unique_ptr < Archive > > AOrErr =
2014-12-10 05:05:36 +08:00
I - > getAsArchive ( ) ) {
std : : unique_ptr < Archive > & UA = * AOrErr ;
2014-07-02 01:19:10 +08:00
// This is an archive. Iterate over each member and display its
// sizes.
2016-11-11 12:28:40 +08:00
Error Err = Error : : success ( ) ;
2016-07-14 10:24:01 +08:00
for ( auto & C : UA - > children ( Err ) ) {
Expected < std : : unique_ptr < Binary > > ChildOrErr = C . getAsBinary ( ) ;
2016-05-18 01:10:12 +08:00
if ( ! ChildOrErr ) {
2016-06-01 04:35:34 +08:00
if ( auto E = isNotObjectErrorInvalidFileType (
ChildOrErr . takeError ( ) ) )
2016-07-14 10:24:01 +08:00
error ( std : : move ( E ) , UA - > getFileName ( ) , C ) ;
2014-07-02 01:19:10 +08:00
continue ;
2016-05-18 01:10:12 +08:00
}
2014-07-02 01:19:10 +08:00
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * ChildOrErr . get ( ) ) ) {
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ): \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin )
2014-07-02 01:19:10 +08:00
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( ) < < " ) "
2016-12-17 06:54:02 +08:00
< < " (for architecture " < < I - > getArchFlagName ( )
2014-07-02 01:19:10 +08:00
< < " ): \n " ;
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-07-02 01:19:10 +08:00
if ( OutputFormat = = berkeley ) {
if ( MachO )
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( )
< < " ) \n " ;
else
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ) \n " ;
}
}
}
2016-07-14 10:24:01 +08:00
if ( Err )
error ( std : : move ( Err ) , UA - > getFileName ( ) ) ;
2016-06-29 07:16:13 +08:00
} else {
consumeError ( AOrErr . takeError ( ) ) ;
2019-10-15 01:29:15 +08:00
error ( " mach-o universal file for architecture " +
StringRef ( I - > getArchFlagName ( ) ) +
" is not a mach-o file or an archive file " ,
file ) ;
2014-07-02 01:19:10 +08:00
}
return ;
}
}
}
// Either all architectures have been specified or none have been specified
// and this does not contain the host architecture so dump all the slices.
2016-02-10 05:35:14 +08:00
bool MoreThanOneArch = UB - > getNumberOfObjects ( ) > 1 ;
2014-06-19 06:04:40 +08:00
for ( MachOUniversalBinary : : object_iterator I = UB - > begin_objects ( ) ,
E = UB - > end_objects ( ) ;
I ! = E ; + + I ) {
2016-06-01 04:35:34 +08:00
Expected < std : : unique_ptr < ObjectFile > > UO = I - > getAsObjectFile ( ) ;
2014-06-24 04:41:02 +08:00
if ( UO ) {
2014-06-19 06:04:40 +08:00
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * UO . get ( ) ) ) {
2014-06-20 06:03:18 +08:00
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
2014-06-19 06:04:40 +08:00
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " : \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin ) {
2016-02-10 05:35:14 +08:00
if ( MoreThanOneFile | | MoreThanOneArch )
2014-06-20 06:03:18 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ): " ;
2014-06-20 06:03:18 +08:00
outs ( ) < < " \n " ;
}
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-06-19 06:04:40 +08:00
if ( OutputFormat = = berkeley ) {
2016-02-10 05:35:14 +08:00
if ( ! MachO | | MoreThanOneFile | | MoreThanOneArch )
2014-06-20 06:03:18 +08:00
outs ( ) < < o - > getFileName ( ) < < " (for architecture "
2016-12-17 06:54:02 +08:00
< < I - > getArchFlagName ( ) < < " ) " ;
2014-06-19 06:04:40 +08:00
outs ( ) < < " \n " ;
}
}
2016-06-01 04:35:34 +08:00
} else if ( auto E = isNotObjectErrorInvalidFileType ( UO . takeError ( ) ) ) {
error ( std : : move ( E ) , file , MoreThanOneArch ?
2016-12-17 06:54:02 +08:00
StringRef ( I - > getArchFlagName ( ) ) : StringRef ( ) ) ;
2016-06-01 04:35:34 +08:00
return ;
2016-06-29 07:16:13 +08:00
} else if ( Expected < std : : unique_ptr < Archive > > AOrErr =
2014-12-10 05:05:36 +08:00
I - > getAsArchive ( ) ) {
std : : unique_ptr < Archive > & UA = * AOrErr ;
2014-06-19 06:04:40 +08:00
// This is an archive. Iterate over each member and display its sizes.
2016-11-11 12:28:40 +08:00
Error Err = Error : : success ( ) ;
2016-07-14 10:24:01 +08:00
for ( auto & C : UA - > children ( Err ) ) {
Expected < std : : unique_ptr < Binary > > ChildOrErr = C . getAsBinary ( ) ;
2016-05-18 01:10:12 +08:00
if ( ! ChildOrErr ) {
2016-06-01 04:35:34 +08:00
if ( auto E = isNotObjectErrorInvalidFileType (
ChildOrErr . takeError ( ) ) )
2016-07-14 10:24:01 +08:00
error ( std : : move ( E ) , UA - > getFileName ( ) , C , MoreThanOneArch ?
2016-12-17 06:54:02 +08:00
StringRef ( I - > getArchFlagName ( ) ) : StringRef ( ) ) ;
2014-06-19 06:04:40 +08:00
continue ;
2016-05-18 01:10:12 +08:00
}
2014-06-19 06:04:40 +08:00
if ( ObjectFile * o = dyn_cast < ObjectFile > ( & * ChildOrErr . get ( ) ) ) {
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ): \n " ;
2014-07-02 06:26:31 +08:00
else if ( MachO & & OutputFormat = = darwin )
2014-06-20 06:03:18 +08:00
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( ) < < " ) "
2016-12-17 06:54:02 +08:00
< < " (for architecture " < < I - > getArchFlagName ( ) < < " ): \n " ;
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-06-19 06:04:40 +08:00
if ( OutputFormat = = berkeley ) {
if ( MachO )
2014-06-20 06:03:18 +08:00
outs ( ) < < UA - > getFileName ( ) < < " ( " < < o - > getFileName ( ) < < " ) "
2016-12-17 06:54:02 +08:00
< < " (for architecture " < < I - > getArchFlagName ( )
2014-06-20 06:03:18 +08:00
< < " ) \n " ;
2014-06-19 06:04:40 +08:00
else
outs ( ) < < o - > getFileName ( ) < < " (ex " < < UA - > getFileName ( )
< < " ) \n " ;
}
}
}
2016-07-14 10:24:01 +08:00
if ( Err )
error ( std : : move ( Err ) , UA - > getFileName ( ) ) ;
2016-06-29 07:16:13 +08:00
} else {
consumeError ( AOrErr . takeError ( ) ) ;
2019-10-15 01:29:15 +08:00
error ( " mach-o universal file for architecture " +
StringRef ( I - > getArchFlagName ( ) ) +
" is not a mach-o file or an archive file " ,
file ) ;
2014-06-19 06:04:40 +08:00
}
}
2014-08-01 22:31:55 +08:00
} else if ( ObjectFile * o = dyn_cast < ObjectFile > ( & Bin ) ) {
2014-07-02 01:19:10 +08:00
if ( ! checkMachOAndArchFlags ( o , file ) )
return ;
2016-12-02 03:12:55 +08:00
MachOObjectFile * MachO = dyn_cast < MachOObjectFile > ( o ) ;
2011-09-29 04:57:46 +08:00
if ( OutputFormat = = sysv )
outs ( ) < < o - > getFileName ( ) < < " : \n " ;
2016-12-02 03:12:55 +08:00
else if ( MachO & & OutputFormat = = darwin & & MoreThanOneFile )
outs ( ) < < o - > getFileName ( ) < < " : \n " ;
2016-02-10 05:35:14 +08:00
printObjectSectionSizes ( o ) ;
2014-06-18 01:54:13 +08:00
if ( OutputFormat = = berkeley ) {
2016-02-10 05:35:14 +08:00
if ( ! MachO | | MoreThanOneFile )
2014-06-18 01:54:13 +08:00
outs ( ) < < o - > getFileName ( ) ;
outs ( ) < < " \n " ;
}
2011-09-29 04:57:46 +08:00
} else {
2019-10-15 01:29:15 +08:00
error ( " unsupported file type " , file ) ;
2011-09-29 04:57:46 +08:00
}
}
2019-09-13 20:00:42 +08:00
static void printBerkeleyTotals ( ) {
2016-09-13 01:08:28 +08:00
std : : string fmtbuf ;
raw_string_ostream fmt ( fmtbuf ) ;
const char * radix_fmt = getRadixFmt ( ) ;
2018-09-22 07:48:12 +08:00
fmt < < " %#7 " < < radix_fmt < < " \t "
< < " %#7 " < < radix_fmt < < " \t "
< < " %#7 " < < radix_fmt < < " \t " ;
2016-09-13 01:08:28 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , TotalObjectText , TotalObjectData ,
TotalObjectBss ) ;
fmtbuf . clear ( ) ;
2018-09-22 07:48:12 +08:00
fmt < < " %7 " < < ( Radix = = octal ? PRIo64 : PRIu64 ) < < " \t "
< < " %7 " PRIx64 " \t " ;
2016-09-13 01:08:28 +08:00
outs ( ) < < format ( fmt . str ( ) . c_str ( ) , TotalObjectTotal , TotalObjectTotal )
< < " (TOTALS) \n " ;
}
2011-09-29 04:57:46 +08:00
int main ( int argc , char * * argv ) {
2018-04-14 02:26:06 +08:00
InitLLVM X ( argc , argv ) ;
2019-06-05 18:32:28 +08:00
cl : : HideUnrelatedOptions ( SizeCat ) ;
2011-09-29 04:57:46 +08:00
cl : : ParseCommandLineOptions ( argc , argv , " llvm object size dumper \n " ) ;
ToolName = argv [ 0 ] ;
if ( OutputFormatShort . getNumOccurrences ( ) )
2015-01-22 09:49:59 +08:00
OutputFormat = static_cast < OutputFormatTy > ( OutputFormatShort ) ;
2011-09-29 04:57:46 +08:00
if ( RadixShort . getNumOccurrences ( ) )
2018-10-30 19:52:47 +08:00
Radix = RadixShort . getValue ( ) ;
2011-09-29 04:57:46 +08:00
2018-11-22 08:44:17 +08:00
for ( StringRef Arch : ArchFlags ) {
if ( Arch = = " all " ) {
2014-07-02 01:19:10 +08:00
ArchAll = true ;
2014-07-02 06:26:31 +08:00
} else {
2018-11-22 08:44:17 +08:00
if ( ! MachOObjectFile : : isValidArch ( Arch ) ) {
2014-07-02 01:19:10 +08:00
outs ( ) < < ToolName < < " : for the -arch option: Unknown architecture "
2018-11-22 08:44:17 +08:00
< < " named ' " < < Arch < < " ' " ;
2014-07-02 01:19:10 +08:00
return 1 ;
}
}
}
2018-11-22 08:44:17 +08:00
if ( InputFilenames . empty ( ) )
2017-12-19 03:46:56 +08:00
InputFilenames . push_back ( " a.out " ) ;
MoreThanOneFile = InputFilenames . size ( ) > 1 ;
llvm : : for_each ( InputFilenames , printFileSectionSizes ) ;
if ( OutputFormat = = berkeley & & TotalSizes )
2019-09-13 20:00:42 +08:00
printBerkeleyTotals ( ) ;
2017-12-19 03:46:56 +08:00
2016-05-03 05:41:03 +08:00
if ( HadError )
return 1 ;
2011-09-29 04:57:46 +08:00
}