#ifndef RLD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stuff/ofile.h"
#include "stuff/breakout.h"
#include "stuff/allocate.h"
#include "stuff/errors.h"
#include "stuff/rnd.h"
#include "stuff/crc32.h"
static void breakout_internal(
char *filename,
struct arch **archs,
uint32_t *narchs,
enum bool calculate_input_prebind_cksum,
struct ofile *ofile);
static void breakout_loop_through_archive(
char *filename,
struct arch *arch,
struct ofile *ofile);
static void cksum_object(
struct arch *arch,
enum bool calculate_input_prebind_cksum);
static struct arch *new_arch(
struct arch **archs,
uint32_t *narchs);
static struct member *new_member(
struct arch *arch);
__private_extern__
struct ofile *
breakout_mem(
void *membuf,
uint32_t length,
char *filename,
struct arch **archs,
uint32_t *narchs,
enum bool calculate_input_prebind_cksum)
{
struct ofile *ofile;
uint32_t previous_errors;
*archs = NULL;
*narchs = 0;
ofile = allocate(sizeof(struct ofile));
if(filename == NULL)
filename = "(broken out from memory)";
if(ofile_map_from_memory((char *)membuf, length, filename, NULL, NULL,
ofile, FALSE) == FALSE){
free(ofile);
return(NULL);
}
previous_errors = errors;
breakout_internal(filename, archs, narchs,
calculate_input_prebind_cksum, ofile);
errors += previous_errors;
if(errors != 0){
free(ofile);
return(NULL);
}
return(ofile);
}
__private_extern__
struct ofile *
breakout(
char *filename,
struct arch **archs,
uint32_t *narchs,
enum bool calculate_input_prebind_cksum)
{
struct ofile *ofile;
uint32_t previous_errors;
*archs = NULL;
*narchs = 0;
ofile = allocate(sizeof(struct ofile));
if(ofile_map(filename, NULL, NULL, ofile, FALSE) == FALSE){
free(ofile);
return(NULL);
}
previous_errors = errors;
breakout_internal(filename, archs, narchs,
calculate_input_prebind_cksum, ofile);
errors += previous_errors;
if(errors != 0){
free(ofile);
return(NULL);
}
return(ofile);
}
static
void
breakout_internal(
char *filename,
struct arch **archs,
uint32_t *narchs,
enum bool calculate_input_prebind_cksum,
struct ofile *ofile)
{
struct arch *arch;
errors = 0;
if(ofile->file_type == OFILE_FAT && errors == 0){
(void)ofile_first_arch(ofile);
do{
if(errors != 0)
break;
arch = new_arch(archs, narchs);
arch->file_name = savestr(filename);
arch->type = ofile->arch_type;
arch->fat_arch = ofile->fat_archs + ofile->narch;
arch->fat_arch_name = savestr(ofile->arch_flag.name);
if(ofile->arch_type == OFILE_ARCHIVE){
breakout_loop_through_archive(filename, arch, ofile);
}
else if(ofile->arch_type == OFILE_Mach_O){
arch->object = allocate(sizeof(struct object));
memset(arch->object, '\0', sizeof(struct object));
arch->object->object_addr = ofile->object_addr;
arch->object->object_size = ofile->object_size;
arch->object->object_byte_sex = ofile->object_byte_sex;
arch->object->mh64 = ofile->mh64;
arch->object->mh = ofile->mh;
arch->object->mh_filetype = ofile->mh_filetype;
arch->object->mh_cputype = ofile->mh_cputype;
arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
arch->object->load_commands = ofile->load_commands;
cksum_object(arch, calculate_input_prebind_cksum);
}
else{
arch->unknown_addr = ofile->file_addr +
arch->fat_arch->offset;
arch->unknown_size = arch->fat_arch->size;
}
}while(ofile_next_arch(ofile) == TRUE);
}
else if(ofile->file_type == OFILE_ARCHIVE && errors == 0){
arch = new_arch(archs, narchs);
arch->file_name = savestr(filename);
arch->type = ofile->file_type;
breakout_loop_through_archive(filename, arch, ofile);
}
else if(ofile->file_type == OFILE_Mach_O && errors == 0){
arch = new_arch(archs, narchs);
arch->file_name = savestr(filename);
arch->type = ofile->file_type;
arch->object = allocate(sizeof(struct object));
memset(arch->object, '\0', sizeof(struct object));
arch->object->object_addr = ofile->object_addr;
arch->object->object_size = ofile->object_size;
arch->object->object_byte_sex = ofile->object_byte_sex;
arch->object->mh64 = ofile->mh64;
arch->object->mh = ofile->mh;
arch->object->mh_filetype = ofile->mh_filetype;
arch->object->mh_cputype = ofile->mh_cputype;
arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
arch->object->load_commands = ofile->load_commands;
cksum_object(arch, calculate_input_prebind_cksum);
}
else if(errors == 0){
arch = new_arch(archs, narchs);
arch->file_name = savestr(filename);
arch->type = ofile->file_type;
arch->unknown_addr = ofile->file_addr;
arch->unknown_size = ofile->file_size;
}
if(errors != 0){
free_archs(*archs, *narchs);
*archs = NULL;
*narchs = 0;
}
}
static
void
breakout_loop_through_archive(
char *filename,
struct arch *arch,
struct ofile *ofile)
{
struct member *member;
enum bool flag;
struct ar_hdr *ar_hdr;
uint32_t size, ar_name_size;
char ar_name_buf[sizeof(ofile->member_ar_hdr->ar_name) + 1];
char ar_size_buf[sizeof(ofile->member_ar_hdr->ar_size) + 1];
if((flag = ofile_first_member(ofile)) == TRUE && errors == 0){
if(ofile->member_ar_hdr != NULL &&
strncmp(ofile->member_name, SYMDEF,
sizeof(SYMDEF) - 1) == 0){
arch->toc_long_name = TRUE;
flag = ofile_next_member(ofile);
}
while(flag == TRUE && errors == 0){
member = new_member(arch);
member->type = ofile->member_type;
member->member_name = ofile->member_name;
if(ofile->mh != NULL || ofile->mh64 != NULL)
size = rnd(ofile->object_size, 8);
else
size = rnd(ofile->member_size, 8);
member->member_long_name = TRUE;
for(ar_name_size = ofile->member_name_size;
ar_name_size > 1 ;
ar_name_size--){
if(ofile->member_name[ar_name_size - 1] != '\0')
break;
}
member->member_name_size = ar_name_size;
ar_name_size = rnd(ar_name_size, 8) +
(rnd(sizeof(struct ar_hdr), 8) -
sizeof(struct ar_hdr));
size += ar_name_size;
member->offset = arch->library_size;
arch->library_size += sizeof(struct ar_hdr) + size;
ar_hdr = allocate(sizeof(struct ar_hdr));
*ar_hdr = *(ofile->member_ar_hdr);
sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
(int)(sizeof(ar_hdr->ar_name) - (sizeof(AR_EFMT1) - 1)),
(long unsigned int)ar_name_size);
memcpy(ar_hdr->ar_name, ar_name_buf,
sizeof(ar_hdr->ar_name));
sprintf(ar_size_buf, "%-*ld",
(int)sizeof(ar_hdr->ar_size), (long unsigned int)size);
memcpy(ar_hdr->ar_size, ar_size_buf,
sizeof(ar_hdr->ar_size));
member->ar_hdr = ar_hdr;
member->input_ar_hdr = ofile->member_ar_hdr;
member->input_file_name = filename;
if(ofile->member_type == OFILE_Mach_O){
member->object = allocate(sizeof(struct object));
memset(member->object, '\0', sizeof(struct object));
member->object->object_addr = ofile->object_addr;
member->object->object_size = ofile->object_size;
member->object->object_byte_sex = ofile->object_byte_sex;
member->object->mh64 = ofile->mh64;
member->object->mh = ofile->mh;
member->object->mh_filetype = ofile->mh_filetype;
member->object->mh_cputype = ofile->mh_cputype;
member->object->mh_cpusubtype = ofile->mh_cpusubtype;
member->object->load_commands = ofile->load_commands;
}
else{
member->unknown_addr = ofile->member_addr;
member->unknown_size = ofile->member_size;
}
flag = ofile_next_member(ofile);
}
}
}
static
void
cksum_object(
struct arch *arch,
enum bool calculate_input_prebind_cksum)
{
uint32_t i, buf_size, ncmds;
struct load_command *lc;
enum byte_sex host_byte_sex;
char *buf;
arch->object->cs = NULL;
lc = arch->object->load_commands;
if(arch->object->mh != NULL)
ncmds = arch->object->mh->ncmds;
else
ncmds = arch->object->mh64->ncmds;
for(i = 0;
i < ncmds && arch->object->cs == NULL;
i++){
if(lc->cmd == LC_PREBIND_CKSUM)
arch->object->cs = (struct prebind_cksum_command *)lc;
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
if(calculate_input_prebind_cksum == FALSE ||
arch->object->cs == NULL ||
arch->object->cs->cksum != 0)
return;
host_byte_sex = get_host_byte_sex();
buf_size = 0;
buf = NULL;
if(arch->object->object_byte_sex != host_byte_sex){
if(arch->object->mh != NULL){
buf_size = sizeof(struct mach_header) +
arch->object->mh->sizeofcmds;
buf = allocate(buf_size);
memcpy(buf, arch->object->mh, buf_size);
if(swap_object_headers(arch->object->mh,
arch->object->load_commands) == FALSE)
return;
}
else{
buf_size = sizeof(struct mach_header_64) +
arch->object->mh64->sizeofcmds;
buf = allocate(buf_size);
memcpy(buf, arch->object->mh64, buf_size);
if(swap_object_headers(arch->object->mh64,
arch->object->load_commands) == FALSE)
return;
}
}
arch->object->calculated_input_prebind_cksum =
crc32(arch->object->object_addr, arch->object->object_size);
if(arch->object->object_byte_sex != host_byte_sex){
if(arch->object->mh != NULL)
memcpy(arch->object->mh, buf, buf_size);
else
memcpy(arch->object->mh64, buf, buf_size);
free(buf);
}
}
__private_extern__
void
free_archs(
struct arch *archs,
uint32_t narchs)
{
uint32_t i, j;
for(i = 0; i < narchs; i++){
if(archs[i].type == OFILE_ARCHIVE){
for(j = 0; j < archs[i].nmembers; j++){
if(archs[i].members[j].type == OFILE_Mach_O){
if(archs[i].members[j].object->ld_r_ofile != NULL)
ofile_unmap(archs[i].members[j].object->ld_r_ofile);
free(archs[i].members[j].object);
}
}
if(archs[i].nmembers > 0 && archs[i].members != NULL)
free(archs[i].members);
}
else if(archs[i].type == OFILE_Mach_O){
if(archs[i].object->ld_r_ofile != NULL)
ofile_unmap(archs[i].object->ld_r_ofile);
free(archs[i].object);
}
}
if(narchs > 0 && archs != NULL)
free(archs);
}
static
struct arch *
new_arch(
struct arch **archs,
uint32_t *narchs)
{
struct arch *arch;
*archs = reallocate(*archs, (*narchs + 1) * sizeof(struct arch));
arch = *archs + *narchs;
*narchs = *narchs + 1;
memset(arch, '\0', sizeof(struct arch));
return(arch);
}
static
struct member *
new_member(
struct arch *arch)
{
struct member *member;
arch->members = reallocate(arch->members,
(arch->nmembers + 1) * sizeof(struct member));
member = arch->members + arch->nmembers;
arch->nmembers++;
memset(member, '\0', sizeof(struct member));
return(member);
}
#endif