#include <mach/mach.h>
#include "stuff/openstep_mach.h"
#include <libc.h>
#ifndef __OPENSTEP__
#include <utime.h>
#endif
#include "stuff/ofile.h"
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/round.h"
#include "stuff/errors.h"
static void copy_new_symbol_info(
char *p,
unsigned long *size,
struct dysymtab_command *dyst,
struct dysymtab_command *old_dyst,
struct twolevel_hints_command *hints_cmd,
struct twolevel_hints_command *old_hints_cmd,
struct object *object);
static void make_table_of_contents(
struct arch *archs,
char *output,
long toc_time,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings);
static enum bool toc_symbol(
struct nlist *symbol,
enum bool commons_in_toc,
struct section **sections);
static int ranlib_name_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2);
static int ranlib_offset_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2);
static enum bool check_sort_ranlibs(
struct arch *arch,
char *output,
enum bool library_warnings);
static void warn_member(
struct arch *arch,
struct member *member,
const char *format, ...) __attribute__ ((format (printf, 3, 4)));
__private_extern__
void
writeout(
struct arch *archs,
unsigned long narchs,
char *output,
unsigned short mode,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings)
{
unsigned long i, j, k, l, file_size, offset, pad, size;
enum byte_sex target_byte_sex, host_byte_sex;
char *file, *p;
kern_return_t r;
struct fat_header *fat_header;
struct fat_arch *fat_arch;
int fd;
#ifndef __OPENSTEP__
struct utimbuf timep;
#else
time_t timep[2];
#endif
struct dysymtab_command dyst;
struct twolevel_hints_command hints_cmd;
unsigned long mh_flags;
struct load_command *lc;
struct dylib_command *dl;
long toc_time;
toc_time = time(0);
fat_arch = NULL;
fat_header = NULL;
if(narchs == 0){
error("no contents for file: %s (not created)", output);
return;
}
host_byte_sex = get_host_byte_sex();
if(narchs > 1 || archs[0].fat_arch != NULL)
file_size = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
else
file_size = 0;
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_ARCHIVE){
make_table_of_contents(archs + i, output, toc_time, sort_toc,
commons_in_toc, library_warnings);
archs[i].library_size += SARMAG + archs[i].toc_size;
if(archs[i].fat_arch != NULL)
file_size = round(file_size, 1 << archs[i].fat_arch->align);
file_size += archs[i].library_size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = archs[i].library_size;
}
else if(archs[i].type == OFILE_Mach_O){
size = archs[i].object->object_size
- archs[i].object->input_sym_info_size
+ archs[i].object->output_sym_info_size;
if(archs[i].fat_arch != NULL)
file_size = round(file_size, 1 << archs[i].fat_arch->align);
file_size += size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = size;
}
else{
if(archs[i].fat_arch != NULL)
file_size = round(file_size, 1 << archs[i].fat_arch->align);
file_size += archs[i].unknown_size;
if(archs[i].fat_arch != NULL)
archs[i].fat_arch->size = archs[i].unknown_size;
}
}
if((r = vm_allocate(mach_task_self(), (vm_address_t *)&file,
file_size, TRUE)) != KERN_SUCCESS)
mach_fatal(r, "can't vm_allocate() buffer for output file: %s of "
"size %lu", output, file_size);
if(narchs > 1 || archs[0].fat_arch != NULL){
fat_header = (struct fat_header *)file;
fat_header->magic = FAT_MAGIC;
fat_header->nfat_arch = narchs;
offset = sizeof(struct fat_header) +
sizeof(struct fat_arch) * narchs;
fat_arch = (struct fat_arch *)(file + sizeof(struct fat_header));
for(i = 0; i < narchs; i++){
fat_arch[i].cputype = archs[i].fat_arch->cputype;
fat_arch[i].cpusubtype = archs[i].fat_arch->cpusubtype;
offset = round(offset, 1 << archs[i].fat_arch->align);
fat_arch[i].offset = offset;
fat_arch[i].size = archs[i].fat_arch->size;
fat_arch[i].align = archs[i].fat_arch->align;
offset += archs[i].fat_arch->size;
}
}
for(i = 0; i < narchs; i++){
if(archs[i].fat_arch != NULL)
p = file + fat_arch[i].offset;
else
p = file;
if(archs[i].type == OFILE_ARCHIVE){
memcpy(p, ARMAG, SARMAG);
p += SARMAG;
if(library_warnings == TRUE && archs[i].toc_nranlibs == 0){
if(narchs > 1 || archs[i].fat_arch != NULL)
warning("warning library: %s for architecture: %s the "
"table of contents is empty (no object file "
"members in the library)", output,
archs[i].fat_arch_name);
else
warning("warning for library: %s the table of contents "
"is empty (no object file members in the "
"library)", output);
}
target_byte_sex = UNKNOWN_BYTE_SEX;
for(j = 0;
j < archs[i].nmembers && target_byte_sex == UNKNOWN_BYTE_SEX;
j++){
if(archs[i].members[j].type == OFILE_Mach_O)
target_byte_sex =
archs[i].members[j].object->object_byte_sex;
}
if(target_byte_sex == UNKNOWN_BYTE_SEX)
target_byte_sex = host_byte_sex;
memcpy(p, (char *)(&archs[i].toc_ar_hdr),sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(archs[i].toc_long_name == TRUE){
memcpy(p, archs[i].toc_name, archs[i].toc_name_size);
p += round(archs[i].toc_name_size, sizeof(long));
}
l = archs[i].toc_nranlibs * sizeof(struct ranlib);
if(target_byte_sex != host_byte_sex)
l = SWAP_LONG(l);
memcpy(p, (char *)&l, sizeof(long));
p += sizeof(long);
if(target_byte_sex != host_byte_sex)
swap_ranlib(archs[i].toc_ranlibs, archs[i].toc_nranlibs,
target_byte_sex);
memcpy(p, (char *)archs[i].toc_ranlibs,
archs[i].toc_nranlibs * sizeof(struct ranlib));
p += archs[i].toc_nranlibs * sizeof(struct ranlib);
l = archs[i].toc_strsize;
if(target_byte_sex != host_byte_sex)
l = SWAP_LONG(l);
memcpy(p, (char *)&l, sizeof(long));
p += sizeof(long);
memcpy(p, (char *)archs[i].toc_strings, archs[i].toc_strsize);
p += archs[i].toc_strsize;
for(j = 0; j < archs[i].nmembers; j++){
memcpy(p, (char *)(archs[i].members[j].ar_hdr),
sizeof(struct ar_hdr));
p += sizeof(struct ar_hdr);
if(archs[i].members[j].member_long_name == TRUE){
memcpy(p, archs[i].members[j].member_name,
archs[i].members[j].member_name_size);
p += round(archs[i].members[j].member_name_size,
sizeof(long));
}
if(archs[i].members[j].type == OFILE_Mach_O){
memset(&dyst, '\0', sizeof(struct dysymtab_command));
if(archs[i].members[j].object->dyst != NULL)
dyst = *(archs[i].members[j].object->dyst);
if(archs[i].members[j].object->hints_cmd != NULL)
hints_cmd = *(archs[i].members[j].object->hints_cmd);
mh_flags = archs[i].members[j].object->mh->flags;
if(archs[i].members[j].object->object_byte_sex !=
host_byte_sex){
if(swap_object_headers(
archs[i].members[j].object->mh,
archs[i].members[j].object->load_commands) ==
FALSE)
fatal("internal error: swap_object_headers"
"() failed");
if(archs[i].members[j].object->output_nsymbols != 0)
swap_nlist(
archs[i].members[j].object->output_symbols,
archs[i].members[j].object->output_nsymbols,
archs[i].members[j].object->object_byte_sex);
}
if(archs[i].members[j].object->
output_sym_info_size == 0 &&
archs[i].members[j].object->
input_sym_info_size == 0){
size = archs[i].members[j].object->object_size;
memcpy(p, archs[i].members[j].object->object_addr,
size);
}
else{
size = archs[i].members[j].object->object_size
- archs[i].members[j].object->
input_sym_info_size;
memcpy(p, archs[i].members[j].object->object_addr,
size);
copy_new_symbol_info(p, &size, &dyst,
archs[i].members[j].object->dyst, &hints_cmd,
archs[i].members[j].object->hints_cmd,
archs[i].members[j].object);
}
p += size;
pad = round(size, sizeof(long)) - size;
}
else{
memcpy(p, archs[i].members[j].unknown_addr,
archs[i].members[j].unknown_size);
p += archs[i].members[j].unknown_size;
pad = round(archs[i].members[j].unknown_size,
sizeof(long)) -
archs[i].members[j].unknown_size;
}
for(k = 0; k < pad; k++)
*p++ = '\n';
}
}
else if(archs[i].type == OFILE_Mach_O){
memset(&dyst, '\0', sizeof(struct dysymtab_command));
if(archs[i].object->dyst != NULL)
dyst = *(archs[i].object->dyst);
if(archs[i].object->hints_cmd != NULL)
hints_cmd = *(archs[i].object->hints_cmd);
mh_flags = archs[i].object->mh->flags;
if(archs[i].object->mh->filetype == MH_DYLIB){
lc = archs[i].object->load_commands;
for(j = 0; j < archs[i].object->mh->ncmds; j++){
if(lc->cmd == LC_ID_DYLIB){
dl = (struct dylib_command *)lc;
dl->dylib.timestamp = toc_time;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
if(archs[i].object->object_byte_sex != host_byte_sex){
if(swap_object_headers(archs[i].object->mh,
archs[i].object->load_commands) == FALSE)
fatal("internal error: swap_object_headers() failed");
if(archs[i].object->output_nsymbols != 0)
swap_nlist(archs[i].object->output_symbols,
archs[i].object->output_nsymbols,
archs[i].object->object_byte_sex);
}
if(archs[i].object->output_sym_info_size == 0 &&
archs[i].object->input_sym_info_size == 0){
size = archs[i].object->object_size;
memcpy(p, archs[i].object->object_addr, size);
}
else{
size = archs[i].object->object_size
- archs[i].object->input_sym_info_size;
memcpy(p, archs[i].object->object_addr, size);
copy_new_symbol_info(p, &size, &dyst,
archs[i].object->dyst, &hints_cmd,
archs[i].object->hints_cmd,
archs[i].object);
}
}
else{
memcpy(p, archs[i].unknown_addr, archs[i].unknown_size);
}
}
#ifdef __LITTLE_ENDIAN__
if(narchs > 1 || archs[0].fat_arch != NULL){
swap_fat_header(fat_header, BIG_ENDIAN_BYTE_SEX);
swap_fat_arch(fat_arch, narchs, BIG_ENDIAN_BYTE_SEX);
}
#endif
(void)unlink(output);
if((fd = open(output, O_WRONLY | O_CREAT | O_TRUNC, mode)) == -1){
system_error("can't create output file: %s", output);
goto cleanup;
}
if(write(fd, file, file_size) != file_size){
system_error("can't write output file: %s", output);
goto cleanup;
}
if(close(fd) == -1){
system_fatal("can't close output file: %s", output);
goto cleanup;
}
#ifndef __OPENSTEP__
timep.actime = toc_time - 5;
timep.modtime = toc_time - 5;
if(utime(output, &timep) == -1)
#else
timep[0] = toc_time - 5;
timep[1] = toc_time - 5;
if(utime(output, timep) == -1)
#endif
{
system_fatal("can't set the modifiy times in output file: %s",
output);
goto cleanup;
}
cleanup:
if((r = vm_deallocate(mach_task_self(), (vm_address_t)file,
file_size)) != KERN_SUCCESS){
my_mach_error(r, "can't vm_deallocate() buffer for output file");
return;
}
}
static
void
copy_new_symbol_info(
char *p,
unsigned long *size,
struct dysymtab_command *dyst,
struct dysymtab_command *old_dyst,
struct twolevel_hints_command *hints_cmd,
struct twolevel_hints_command *old_hints_cmd,
struct object *object)
{
if(old_dyst != NULL){
memcpy(p + *size, object->output_loc_relocs,
dyst->nlocrel * sizeof(struct relocation_info));
*size += dyst->nlocrel *
sizeof(struct relocation_info);
memcpy(p + *size, object->output_symbols,
object->output_nsymbols * sizeof(struct nlist));
*size += object->output_nsymbols *
sizeof(struct nlist);
if(old_hints_cmd != NULL){
memcpy(p + *size, object->output_hints,
hints_cmd->nhints * sizeof(struct twolevel_hint));
*size += hints_cmd->nhints *
sizeof(struct twolevel_hint);
}
memcpy(p + *size, object->output_ext_relocs,
dyst->nextrel * sizeof(struct relocation_info));
*size += dyst->nextrel *
sizeof(struct relocation_info);
memcpy(p + *size, object->output_indirect_symtab,
dyst->nindirectsyms * sizeof(unsigned long));
*size += dyst->nindirectsyms *
sizeof(unsigned long);
memcpy(p + *size, object->output_tocs,
object->output_ntoc *sizeof(struct dylib_table_of_contents));
*size += object->output_ntoc *
sizeof(struct dylib_table_of_contents);
memcpy(p + *size, object->output_mods,
object->output_nmodtab * sizeof(struct dylib_module));
*size += object->output_nmodtab *
sizeof(struct dylib_module);
memcpy(p + *size, object->output_refs,
object->output_nextrefsyms * sizeof(struct dylib_reference));
*size += object->output_nextrefsyms *
sizeof(struct dylib_reference);
memcpy(p + *size, object->output_strings,
object->output_strings_size);
*size += object->output_strings_size;
}
else{
memcpy(p + *size, object->output_symbols,
object->output_nsymbols * sizeof(struct nlist));
*size += object->output_nsymbols *
sizeof(struct nlist);
memcpy(p + *size, object->output_strings,
object->output_strings_size);
*size += object->output_strings_size;
}
}
static
void
make_table_of_contents(
struct arch *arch,
char *output,
long toc_time,
enum bool sort_toc,
enum bool commons_in_toc,
enum bool library_warnings)
{
unsigned long i, j, k, r, s, nsects;
struct member *member;
struct object *object;
struct load_command *lc;
struct segment_command *sg;
struct nlist *symbols;
unsigned long nsymbols;
char *strings;
unsigned long strings_size;
enum bool sorted;
unsigned short toc_mode;
int oumask, numask;
char *ar_name;
struct section *section;
symbols = NULL;
strings = NULL;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->type == OFILE_Mach_O){
object = member->object;
nsymbols = 0;
nsects = 0;
lc = object->load_commands;
for(j = 0; j < object->mh->ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
nsects += sg->nsects;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
object->sections = allocate(nsects *
sizeof(struct section *));
nsects = 0;
lc = object->load_commands;
for(j = 0; j < object->mh->ncmds; j++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
section = (struct section *)
((char *)sg + sizeof(struct segment_command));
for(k = 0; k < sg->nsects; k++){
object->sections[nsects++] = section++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->output_sym_info_size == 0){
lc = object->load_commands;
for(j = 0; j < object->mh->ncmds; j++){
if(lc->cmd == LC_SYMTAB){
object->st = (struct symtab_command *)lc;
break;
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(object->st != NULL && object->st->nsyms != 0){
symbols = (struct nlist *)(object->object_addr +
object->st->symoff);
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(symbols, object->st->nsyms,
get_host_byte_sex());
nsymbols = object->st->nsyms;
strings = object->object_addr + object->st->stroff;
strings_size = object->st->strsize;
}
}
else {
symbols = object->output_symbols;
nsymbols = object->output_nsymbols;
strings = object->output_strings;
strings_size = object->output_strings_size;
}
for(j = 0; j < nsymbols; j++){
if(toc_symbol(symbols + j, commons_in_toc,
object->sections) == TRUE){
arch->toc_nranlibs++;
arch->toc_strsize += strlen(strings +
symbols[j].n_un.n_strx) + 1;
}
}
}
}
arch->toc_ranlibs = allocate(sizeof(struct ranlib) *arch->toc_nranlibs);
arch->toc_strsize = round(arch->toc_strsize, sizeof(long));
arch->toc_strings = allocate(arch->toc_strsize);
r = 0;
s = 0;
for(i = 0; i < arch->nmembers; i++){
member = arch->members + i;
if(member->type == OFILE_Mach_O){
object = member->object;
nsymbols = 0;
if(object->output_sym_info_size == 0){
if(object->st != NULL){
symbols = (struct nlist *)(object->object_addr +
object->st->symoff);
nsymbols = object->st->nsyms;
strings = object->object_addr + object->st->stroff;
strings_size = object->st->strsize;
}
else{
symbols = NULL;
nsymbols = 0;
strings = NULL;
strings_size = 0;
}
}
else{
symbols = object->output_symbols;
nsymbols = object->output_nsymbols;
strings = object->output_strings;
strings_size = object->output_strings_size;
}
for(j = 0; j < nsymbols; j++){
if(symbols[j].n_un.n_strx > strings_size)
continue;
if(toc_symbol(symbols + j, commons_in_toc,
object->sections) == TRUE){
strcpy(arch->toc_strings + s,
strings + symbols[j].n_un.n_strx);
arch->toc_ranlibs[r].ran_un.ran_name =
arch->toc_strings + s;
arch->toc_ranlibs[r].ran_off = i + 1;
r++;
s += strlen(strings + symbols[j].n_un.n_strx) + 1;
}
}
if(object->output_sym_info_size == 0){
if(object->object_byte_sex != get_host_byte_sex())
swap_nlist(symbols, nsymbols, object->object_byte_sex);
}
}
}
if(sort_toc == TRUE){
qsort(arch->toc_ranlibs, arch->toc_nranlibs, sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_name_qsort);
sorted = check_sort_ranlibs(arch, output, library_warnings);
if(sorted == FALSE){
qsort(arch->toc_ranlibs, arch->toc_nranlibs,
sizeof(struct ranlib),
(int (*)(const void *, const void *))ranlib_offset_qsort);
arch->toc_long_name = FALSE;
}
}
else{
sorted = FALSE;
arch->toc_long_name = FALSE;
}
if(arch->toc_long_name == TRUE){
ar_name = AR_EFMT1 "16";
arch->toc_name_size = 16;
arch->toc_name = SYMDEF_SORTED;
}
else{
if(sorted == TRUE){
ar_name = SYMDEF_SORTED;
arch->toc_name_size = sizeof(SYMDEF_SORTED) - 1;
arch->toc_name = ar_name;
}
else{
ar_name = SYMDEF;
arch->toc_name_size = sizeof(SYMDEF) - 1;
arch->toc_name = ar_name;
}
}
arch->toc_size = sizeof(struct ar_hdr) +
sizeof(long) +
arch->toc_nranlibs * sizeof(struct ranlib) +
sizeof(long) +
arch->toc_strsize;
if(arch->toc_long_name == TRUE)
arch->toc_size += round(arch->toc_name_size, sizeof(long));
for(i = 0; i < arch->nmembers; i++)
arch->members[i].offset += SARMAG + arch->toc_size;
for(i = 0; i < arch->toc_nranlibs; i++){
arch->toc_ranlibs[i].ran_un.ran_strx =
arch->toc_ranlibs[i].ran_un.ran_name - arch->toc_strings;
arch->toc_ranlibs[i].ran_off =
arch->members[arch->toc_ranlibs[i].ran_off - 1].offset;
}
numask = 0;
oumask = umask(numask);
toc_mode = S_IFREG | (0666 & ~oumask);
(void)umask(oumask);
sprintf((char *)(&arch->toc_ar_hdr), "%-*s%-*ld%-*u%-*u%-*o%-*ld",
(int)sizeof(arch->toc_ar_hdr.ar_name),
ar_name,
(int)sizeof(arch->toc_ar_hdr.ar_date),
toc_time,
(int)sizeof(arch->toc_ar_hdr.ar_uid),
(unsigned short)getuid(),
(int)sizeof(arch->toc_ar_hdr.ar_gid),
(unsigned short)getgid(),
(int)sizeof(arch->toc_ar_hdr.ar_mode),
(unsigned int)toc_mode,
(int)sizeof(arch->toc_ar_hdr.ar_size),
(long)(arch->toc_size - sizeof(struct ar_hdr)));
memcpy(arch->toc_ar_hdr.ar_fmag, ARFMAG,
(int)sizeof(arch->toc_ar_hdr.ar_fmag));
}
static
enum bool
toc_symbol(
struct nlist *symbol,
enum bool commons_in_toc,
struct section **sections)
{
if(symbol->n_un.n_strx == 0)
return(FALSE);
if((symbol->n_type & N_EXT) == 0)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_UNDF && symbol->n_value == 0)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_UNDF && symbol->n_value != 0 &&
commons_in_toc == FALSE)
return(FALSE);
if((symbol->n_type & N_TYPE) == N_SECT &&
(sections[symbol->n_sect - 1]->flags & S_ATTR_NO_TOC) != 0)
return(FALSE);
return(TRUE);
}
static
int
ranlib_name_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2)
{
return(strcmp(ran1->ran_un.ran_name, ran2->ran_un.ran_name));
}
static
int
ranlib_offset_qsort(
const struct ranlib *ran1,
const struct ranlib *ran2)
{
if(ran1->ran_off < ran2->ran_off)
return(-1);
if(ran1->ran_off > ran2->ran_off)
return(1);
return(0);
}
static
enum bool
check_sort_ranlibs(
struct arch *arch,
char *output,
enum bool library_warnings)
{
long i;
enum bool multiple_defs;
struct member *member;
multiple_defs = FALSE;
for(i = 0; i < (long)arch->toc_nranlibs - 1; i++){
if(strcmp(arch->toc_ranlibs[i].ran_un.ran_name,
arch->toc_ranlibs[i+1].ran_un.ran_name) == 0){
if(multiple_defs == FALSE){
if(library_warnings == FALSE)
return(FALSE);
fprintf(stderr, "%s: same symbol defined in more than one "
"member ", progname);
if(arch->fat_arch != NULL)
fprintf(stderr, "for architecture: %s ",
arch->fat_arch_name);
fprintf(stderr, "in: %s (table of contents will not be "
"sorted)\n", output);
multiple_defs = TRUE;
}
if(arch->toc_ranlibs[i].ran_off > 0){
member = arch->members + arch->toc_ranlibs[i].ran_off - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_ranlibs[i].ran_un.ran_name);
arch->toc_ranlibs[i].ran_off =
-(arch->toc_ranlibs[i].ran_off);
}
if(arch->toc_ranlibs[i+1].ran_off > 0){
member = arch->members + arch->toc_ranlibs[i+1].ran_off - 1;
warn_member(arch, member, "defines symbol: %s",
arch->toc_ranlibs[i+1].ran_un.ran_name);
arch->toc_ranlibs[i+1].ran_off =
-(arch->toc_ranlibs[i+1].ran_off);
}
}
}
if(multiple_defs == FALSE)
return(TRUE);
else{
for(i = 0; i < arch->toc_nranlibs; i++)
if((int)arch->toc_ranlibs[i].ran_off < 0)
arch->toc_ranlibs[i].ran_off =
-(arch->toc_ranlibs[i].ran_off);
return(FALSE);
}
}
static
void
warn_member(
struct arch *arch,
struct member *member,
const char *format, ...)
{
va_list ap;
fprintf(stderr, "%s: ", progname);
if(arch->fat_arch != NULL)
fprintf(stderr, "for architecture: %s ", arch->fat_arch_name);
if(member->input_ar_hdr != NULL){
fprintf(stderr, "file: %s(%.*s) ", member->input_file_name,
(int)member->member_name_size, member->member_name);
}
else
fprintf(stderr, "file: %s ", member->input_file_name);
va_start(ap, format);
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
va_end(ap);
}