Add "-format darwin" to llvm-size to be like darwin's size(1) -m output, and

and the -l option for the long format.  Also when the object is a Mach-O
file and the format is berkeley produce output like darwin’s default size(1)
summary berkeley derived output.

Like System V format, there are also some small changes in how and where
the file names and archive member names are printed for darwin and
Mach-O.

Like the changes to llvm-nm these are the first steps in seeing if it is
possible to make llvm-size produce the same output as darwin's size(1).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@211117 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Kevin Enderby 2014-06-17 17:54:13 +00:00
parent 3f1f259c22
commit acc5e810aa
4 changed files with 275 additions and 26 deletions

Binary file not shown.

Binary file not shown.

View File

@ -2,6 +2,14 @@ RUN: llvm-size -A %p/Inputs/macho-text-data-bss.macho-x86_64 \
RUN: | FileCheck %s -check-prefix A
RUN: llvm-size -B %p/Inputs/macho-text-data-bss.macho-x86_64 \
RUN: | FileCheck %s -check-prefix B
RUN: llvm-size -format darwin %p/Inputs/macho-text-data-bss.macho-x86_64 \
RUN: | FileCheck %s -check-prefix m
RUN: llvm-size %p/Inputs/macho-archive-x86_64.a \
RUN: | FileCheck %s -check-prefix AR
RUN: llvm-size -format darwin %p/Inputs/macho-archive-x86_64.a \
RUN: | FileCheck %s -check-prefix mAR
RUN: llvm-size -format darwin -x -l %p/Inputs/hello-world.macho-x86_64 \
RUN: | FileCheck %s -check-prefix mxl
A: section size addr
A: __text 12 0
@ -11,5 +19,49 @@ A: __compact_unwind 32 16
A: __eh_frame 64 48
A: Total 116
B: text data bss dec hex filename
B: 12 100 4 116 74
B: __TEXT __DATA __OBJC others dec hex
B: 76 8 0 32 116 74
m: Segment : 116
m: Section (__TEXT, __text): 12
m: Section (__DATA, __data): 4
m: Section (__DATA, __bss): 4
m: Section (__LD, __compact_unwind): 32
m: Section (__TEXT, __eh_frame): 64
m: total 116
m: total 116
AR: __TEXT __DATA __OBJC others dec hex
AR: 70 0 0 32 102 66 {{.*}}/macho-archive-x86_64.a(foo.o)
AR: 0 4 0 0 4 4 {{.*}}/macho-archive-x86_64.a(bar.o)
mAR: {{.*}}/macho-archive-x86_64.a(foo.o):
mAR: Segment : 104
mAR: Section (__TEXT, __text): 6
mAR: Section (__LD, __compact_unwind): 32
mAR: Section (__TEXT, __eh_frame): 64
mAR: total 102
mAR: total 104
mAR: {{.*}}/macho-archive-x86_64.a(bar.o):
mAR: Segment : 4
mAR: Section (__TEXT, __text): 0
mAR: Section (__DATA, __data): 4
mAR: total 4
mAR: total 4
mxl: Segment __PAGEZERO: 0x100000000 (vmaddr 0x0 fileoff 0)
mxl: Segment __TEXT: 0x1000 (vmaddr 0x100000000 fileoff 0)
mxl: Section __text: 0x3b (addr 0x100000f30 offset 3888)
mxl: Section __stubs: 0x6 (addr 0x100000f6c offset 3948)
mxl: Section __stub_helper: 0x1a (addr 0x100000f74 offset 3956)
mxl: Section __cstring: 0xd (addr 0x100000f8e offset 3982)
mxl: Section __unwind_info: 0x48 (addr 0x100000f9b offset 3995)
mxl: Section __eh_frame: 0x18 (addr 0x100000fe8 offset 4072)
mxl: total 0xc8
mxl: Segment __DATA: 0x1000 (vmaddr 0x100001000 fileoff 4096)
mxl: Section __nl_symbol_ptr: 0x10 (addr 0x100001000 offset 4096)
mxl: Section __la_symbol_ptr: 0x8 (addr 0x100001010 offset 4112)
mxl: total 0x18
mxl: Segment __LINKEDIT: 0x1000 (vmaddr 0x100002000 fileoff 8192)
mxl: total 0x100003000

View File

@ -16,6 +16,7 @@
#include "llvm/ADT/APInt.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@ -31,13 +32,13 @@
using namespace llvm;
using namespace object;
enum OutputFormatTy {berkeley, sysv};
enum OutputFormatTy {berkeley, sysv, darwin};
static cl::opt<OutputFormatTy>
OutputFormat("format",
cl::desc("Specify output format"),
cl::values(clEnumVal(sysv, "System V format"),
clEnumVal(berkeley, "Berkeley format"),
clEnumValEnd),
clEnumVal(darwin, "Darwin -m format"), clEnumValEnd),
cl::init(berkeley));
static cl::opt<OutputFormatTy>
@ -47,6 +48,13 @@ static cl::opt<OutputFormatTy>
clEnumValEnd),
cl::init(berkeley));
static bool berkeleyHeaderPrinted = false;
static bool moreThanOneFile = false;
cl::opt<bool> DarwinLongFormat("l",
cl::desc("When format is darwin, use long format "
"to include addresses and offsets."));
enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16};
static cl::opt<unsigned int>
Radix("-radix",
@ -85,6 +93,182 @@ static size_t getNumLengthAsString(uint64_t num) {
return result.size();
}
/// @brief Return the the printing format for the Radix.
static const char * getRadixFmt(void) {
switch (Radix) {
case octal:
return PRIo64;
case decimal:
return PRIu64;
case hexadecimal:
return PRIx64;
}
return nullptr;
}
/// @brief Print the size of each Mach-O segment and section in @p MachO.
///
/// This is when used when @c OutputFormat is darwin and produces the same
/// output as darwin's size(1) -m output.
static void PrintDarwinSectionSizes(MachOObjectFile *MachO) {
std::string fmtbuf;
raw_string_ostream fmt(fmtbuf);
const char *radix_fmt = getRadixFmt();
if (Radix == hexadecimal)
fmt << "0x";
fmt << "%" << radix_fmt;
uint32_t LoadCommandCount = MachO->getHeader().ncmds;
uint32_t Filetype = MachO->getHeader().filetype;
MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
uint64_t total = 0;
for (unsigned I = 0; ; ++I) {
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)
outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
<< " fileoff " << Seg.fileoff << ")";
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() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
<< format("%.16s", &Sec.sectname) << "): ";
else
outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
outs() << format(fmt.str().c_str(), Sec.size);
if (DarwinLongFormat)
outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
<< " offset " << Sec.offset << ")";
outs() << "\n";
sec_total += Sec.size;
}
if (Seg.nsects != 0)
outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
}
else if (Load.C.cmd == MachO::LC_SEGMENT) {
MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load);
outs() << "Segment " << Seg.segname << ": "
<< format(fmt.str().c_str(), Seg.vmsize);
if (DarwinLongFormat)
outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr)
<< " fileoff " << Seg.fileoff << ")";
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() << "\tSection (" << format("%.16s", &Sec.segname) << ", "
<< format("%.16s", &Sec.sectname) << "): ";
else
outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": ";
outs() << format(fmt.str().c_str(), Sec.size);
if (DarwinLongFormat)
outs() << " (addr 0x" << format("%" PRIx64, Sec.addr)
<< " offset " << Sec.offset << ")";
outs() << "\n";
sec_total += Sec.size;
}
if (Seg.nsects != 0)
outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n";
}
if (I == LoadCommandCount - 1)
break;
else
Load = MachO->getNextLoadCommandInfo(Load);
}
outs() << "total " << format(fmt.str().c_str(), total) << "\n";
}
/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO.
///
/// 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.
static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) {
uint32_t LoadCommandCount = MachO->getHeader().ncmds;
MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo();
uint64_t total_text = 0;
uint64_t total_data = 0;
uint64_t total_objc = 0;
uint64_t total_others = 0;
for (unsigned I = 0; ; ++I) {
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;
}
} 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;
}
}
else if (Load.C.cmd == MachO::LC_SEGMENT) {
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;
}
} 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;
}
}
if (I == LoadCommandCount - 1)
break;
else
Load = MachO->getNextLoadCommandInfo(Load);
}
uint64_t total = total_text + total_data + total_objc + total_others;
if (!berkeleyHeaderPrinted) {
outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n";
berkeleyHeaderPrinted = true;
}
outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t"
<< total_others << "\t" << total << "\t" << format("%" PRIx64, total)
<< "\t";
}
/// @brief Print the size of each section in @p Obj.
///
/// The format used is determined by @c OutputFormat and @c Radix.
@ -92,20 +276,19 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
uint64_t total = 0;
std::string fmtbuf;
raw_string_ostream fmt(fmtbuf);
const char *radix_fmt = getRadixFmt();
const char *radix_fmt = nullptr;
switch (Radix) {
case octal:
radix_fmt = PRIo64;
break;
case decimal:
radix_fmt = PRIu64;
break;
case hexadecimal:
radix_fmt = PRIx64;
break;
}
if (OutputFormat == sysv) {
// 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)
PrintDarwinSectionSizes(MachO);
// 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)
PrintDarwinSegmentSizes(MachO);
else if (OutputFormat == sysv) {
// 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");
@ -204,6 +387,13 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
total = total_text + total_data + total_bss;
if (!berkeleyHeaderPrinted) {
outs() << " text data bss "
<< (Radix == octal ? "oct" : "dec")
<< " hex filename\n";
berkeleyHeaderPrinted = true;
}
// Print result.
fmt << "%#7" << radix_fmt << " "
<< "%#7" << radix_fmt << " "
@ -251,20 +441,31 @@ static void PrintFileSectionSizes(StringRef file) {
continue;
}
if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
if (OutputFormat == sysv)
outs() << o->getFileName() << " (ex " << a->getFileName()
<< "):\n";
else if(MachO && OutputFormat == darwin)
outs() << a->getFileName() << "(" << o->getFileName() << "):\n";
PrintObjectSectionSizes(o);
if (OutputFormat == berkeley)
outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
if (OutputFormat == berkeley) {
if (MachO)
outs() << a->getFileName() << "(" << o->getFileName() << ")\n";
else
outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n";
}
}
}
} else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
if (OutputFormat == sysv)
outs() << o->getFileName() << " :\n";
PrintObjectSectionSizes(o);
if (OutputFormat == berkeley)
outs() << o->getFileName() << "\n";
if (OutputFormat == berkeley) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
if (!MachO || moreThanOneFile)
outs() << o->getFileName();
outs() << "\n";
}
} else {
errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n";
}
@ -290,11 +491,7 @@ int main(int argc, char **argv) {
if (InputFilenames.size() == 0)
InputFilenames.push_back("a.out");
if (OutputFormat == berkeley)
outs() << " text data bss "
<< (Radix == octal ? "oct" : "dec")
<< " hex filename\n";
moreThanOneFile = InputFilenames.size() > 1;
std::for_each(InputFilenames.begin(), InputFilenames.end(),
PrintFileSectionSizes);