#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stuff/bool.h"
#include "stuff/ofile.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
char *progname = NULL;
struct flags {
uint32_t nfiles;
enum bool m;
enum bool l;
enum bool x;
};
static void usage(
void);
static void size(
struct ofile *ofile,
char *arch_name,
void *cookie);
extern char apple_version[];
char *version = apple_version;
int
main(
int argc,
char **argv,
char **envp)
{
int i;
enum bool args_left;
struct flags flag;
struct arch_flag *arch_flags;
uint32_t narch_flags;
enum bool all_archs;
progname = argv[0];
arch_flags = NULL;
narch_flags = 0;
all_archs = FALSE;
flag.nfiles = 0;
flag.m = FALSE;
flag.l = FALSE;
flag.x = FALSE;
for(i = 1; i < argc; i++){
if(argv[i][0] == '-'){
if(argv[i][1] == '\0'){
flag.nfiles += argc - i - 1;
break;
}
if(strcmp(argv[i], "-m") == 0){
flag.m = TRUE;
continue;
}
if(strcmp(argv[i], "-l") == 0){
flag.l = TRUE;
flag.m = TRUE;
continue;
}
if(strcmp(argv[i], "-x") == 0){
flag.x = TRUE;
flag.m = TRUE;
continue;
}
if(strcmp(argv[i], "-arch") == 0){
if(i + 1 == argc){
error("missing argument(s) to %s option", argv[i]);
usage();
}
if(strcmp("all", argv[i+1]) == 0){
all_archs = TRUE;
}
else{
arch_flags = reallocate(arch_flags,
(narch_flags + 1) * sizeof(struct arch_flag));
if(get_arch_from_flag(argv[i+1],
arch_flags + narch_flags) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[i], argv[i+1]);
arch_usage();
usage();
}
narch_flags++;
}
i++;
continue;
}
}
flag.nfiles++;
}
if(flag.m == FALSE)
printf("__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n");
args_left = TRUE;
for (i = 1; i < argc; i++) {
if(args_left == TRUE && argv[i][0] == '-'){
if(argv[i][1] == '\0'){
args_left = FALSE;
continue;
}
if(strcmp(argv[i], "-m") == 0)
continue;
if(strcmp(argv[i], "-l") == 0)
continue;
if(strcmp(argv[i], "-x") == 0)
continue;
if(strcmp(argv[i], "-arch") == 0){
i++;
continue;
}
}
ofile_process(argv[i], arch_flags, narch_flags, all_archs, FALSE,
TRUE, TRUE, size, &flag);
}
if(flag.nfiles == 0)
ofile_process("a.out", arch_flags, narch_flags, all_archs, FALSE,
TRUE, TRUE, size, &flag);
if(errors == 0)
return(EXIT_SUCCESS);
else
return(EXIT_FAILURE);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [-m] [-l] [-x] [--] "
"[[-arch <arch_flag>] ...] [file ...]\n", progname);
exit(EXIT_FAILURE);
}
static
void
size(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
struct flags *flag;
uint64_t seg_sum, sect_sum;
uint32_t i, j;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
uint64_t text, data, objc, others, sum;
uint32_t ncmds;
flag = (struct flags *)cookie;
if(ofile->mh != NULL)
ncmds = ofile->mh->ncmds;
else
ncmds = ofile->mh64->ncmds;
if(flag->m == TRUE){
if(flag->nfiles > 1 || ofile->member_ar_hdr != NULL ||
arch_name != NULL){
if(ofile->member_ar_hdr != NULL){
printf("%s(%.*s)", ofile->file_name,
(int)ofile->member_name_size,
ofile->member_name);
}
else{
printf("%s", ofile->file_name);
}
if(arch_name != NULL)
printf(" (for architecture %s):\n", arch_name);
else
printf(":\n");
}
lc = ofile->load_commands;
seg_sum = 0;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
printf("Segment %.16s: ", sg->segname);
if(flag->x == TRUE)
printf("0x%x", (unsigned int)sg->vmsize);
else
printf("%u", sg->vmsize);
if(sg->flags & SG_FVMLIB)
printf(" (fixed vm library segment)\n");
else{
if(flag->l == TRUE)
printf(" (vmaddr 0x%x fileoff %u)\n",
(unsigned int)sg->vmaddr, sg->fileoff);
else
printf("\n");
}
seg_sum += sg->vmsize;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
sect_sum = 0;
for(j = 0; j < sg->nsects; j++){
if(ofile->mh_filetype == MH_OBJECT)
printf("\tSection (%.16s, %.16s): ",
s->segname, s->sectname);
else
printf("\tSection %.16s: ", s->sectname);
if(flag->x == TRUE)
printf("0x%x", (unsigned int)s->size);
else
printf("%u", s->size);
if(flag->l == TRUE)
printf(" (addr 0x%x offset %u)\n",
(unsigned int)s->addr, s->offset);
else
printf("\n");
sect_sum += s->size;
s++;
}
if(sg->nsects > 0){
if(flag->x == TRUE)
printf("\ttotal 0x%llx\n", sect_sum);
else
printf("\ttotal %llu\n", sect_sum);
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
printf("Segment %.16s: ", sg64->segname);
if(flag->x == TRUE)
printf("0x%llx", sg64->vmsize);
else
printf("%llu", sg64->vmsize);
if(sg64->flags & SG_FVMLIB)
printf(" (fixed vm library segment)\n");
else{
if(flag->l == TRUE)
printf(" (vmaddr 0x%llx fileoff %llu)\n",
sg64->vmaddr, sg64->fileoff);
else
printf("\n");
}
seg_sum += sg64->vmsize;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
sect_sum = 0;
for(j = 0; j < sg64->nsects; j++){
if(ofile->mh_filetype == MH_OBJECT)
printf("\tSection (%.16s, %.16s): ",
s64->segname, s64->sectname);
else
printf("\tSection %.16s: ", s64->sectname);
if(flag->x == TRUE)
printf("0x%llx", s64->size);
else
printf("%llu", s64->size);
if(flag->l == TRUE)
printf(" (addr 0x%llx offset %u)\n",
s64->addr,
s64->offset);
else
printf("\n");
sect_sum += s64->size;
s64++;
}
if(sg64->nsects > 0){
if(flag->x == TRUE)
printf("\ttotal 0x%llx\n", sect_sum);
else
printf("\ttotal %llu\n", sect_sum);
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(flag->x == TRUE)
printf("total 0x%llx\n", seg_sum);
else
printf("total %llu\n", seg_sum);
}
else{
text = 0;
data = 0;
objc = 0;
others = 0;
lc = ofile->load_commands;
for(i = 0; i < ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
if(ofile->mh_filetype == MH_OBJECT){
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(strcmp(s->segname, SEG_TEXT) == 0)
text += s->size;
else if(strcmp(s->segname, SEG_DATA) == 0)
data += s->size;
else if(strcmp(s->segname, SEG_OBJC) == 0)
objc += s->size;
else
others += s->size;
s++;
}
}
else{
if(strcmp(sg->segname, SEG_TEXT) == 0)
text += sg->vmsize;
else if(strcmp(sg->segname, SEG_DATA) == 0)
data += sg->vmsize;
else if(strcmp(sg->segname, SEG_OBJC) == 0)
objc += sg->vmsize;
else
others += sg->vmsize;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
if(ofile->mh_filetype == MH_OBJECT){
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(strcmp(s64->segname, SEG_TEXT) == 0)
text += s64->size;
else if(strcmp(s64->segname, SEG_DATA) == 0)
data += s64->size;
else if(strcmp(s64->segname, SEG_OBJC) == 0)
objc += s64->size;
else
others += s64->size;
s64++;
}
}
else{
if(strcmp(sg64->segname, SEG_TEXT) == 0)
text += sg64->vmsize;
else if(strcmp(sg64->segname, SEG_DATA) == 0)
data += sg64->vmsize;
else if(strcmp(sg64->segname, SEG_OBJC) == 0)
objc += sg64->vmsize;
else
others += sg64->vmsize;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
printf("%llu\t%llu\t%llu\t%llu\t", text, data, objc, others);
sum = text + data + objc + others;
printf("%llu\t%llx", sum, sum);
if(flag->nfiles > 1 || ofile->member_ar_hdr != NULL ||
arch_name != NULL){
if(ofile->member_ar_hdr != NULL){
printf("\t%s(%.*s)", ofile->file_name,
(int)ofile->member_name_size,
ofile->member_name);
}
else{
printf("\t%s", ofile->file_name);
}
if(arch_name != NULL)
printf(" (for architecture %s)", arch_name);
}
printf("\n");
}
}