1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23#ifndef RLD
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "stuff/ofile.h"
28#include "stuff/breakout.h"
29#include "stuff/allocate.h"
30#include "stuff/errors.h"
31#include "stuff/rnd.h"
32#include "stuff/crc32.h"
33
34static void breakout_internal(
35    char *filename,
36    struct arch **archs,
37    uint32_t *narchs,
38    enum bool calculate_input_prebind_cksum,
39    struct ofile *ofile);
40static void breakout_loop_through_archive(
41    char *filename,
42    struct arch *arch,
43    struct ofile *ofile);
44static void cksum_object(
45    struct arch *arch,
46    enum bool calculate_input_prebind_cksum);
47static struct arch *new_arch(
48    struct arch **archs,
49    uint32_t *narchs);
50static struct member *new_member(
51    struct arch *arch);
52
53__private_extern__
54struct ofile *
55breakout_mem(
56void *membuf,
57uint32_t length,
58char *filename,
59struct arch **archs,
60uint32_t *narchs,
61enum bool calculate_input_prebind_cksum)
62{
63    struct ofile *ofile;
64    uint32_t previous_errors;
65
66	*archs = NULL;
67	*narchs = 0;
68	ofile = allocate(sizeof(struct ofile));
69
70	/*
71	 * If the file_name is NULL, we will use a dummy file name so
72	 * that error reporting, etc. works.
73	 */
74	if(filename == NULL)
75	    filename = "(broken out from memory)";
76
77	/*
78	 * Rely on the ofile_*() routines to do all the checking and only
79	 * return valid ofiles files broken out.
80	 */
81	if(ofile_map_from_memory((char *)membuf, length, filename, 0,NULL, NULL,
82				 ofile, FALSE) == FALSE){
83	    free(ofile);
84	    return(NULL);
85	}
86
87	previous_errors = errors;
88	breakout_internal(filename, archs, narchs,
89			  calculate_input_prebind_cksum, ofile);
90	errors += previous_errors;
91	if(errors != 0){
92	    free(ofile);
93	    return(NULL);
94	}
95	return(ofile);
96}
97
98__private_extern__
99struct ofile *
100breakout(
101char *filename,
102struct arch **archs,
103uint32_t *narchs,
104enum bool calculate_input_prebind_cksum)
105{
106    struct ofile *ofile;
107    uint32_t previous_errors;
108
109	*archs = NULL;
110	*narchs = 0;
111	ofile = allocate(sizeof(struct ofile));
112	/*
113	 * Rely on the ofile_*() routines to do all the checking and only
114	 * return valid ofiles files broken out.
115	 */
116	if(ofile_map(filename, NULL, NULL, ofile, FALSE) == FALSE){
117	    free(ofile);
118	    return(NULL);
119	}
120
121	previous_errors = errors;
122	breakout_internal(filename, archs, narchs,
123			  calculate_input_prebind_cksum, ofile);
124	errors += previous_errors;
125	if(errors != 0){
126	    free(ofile);
127	    return(NULL);
128	}
129	return(ofile);
130}
131
132static
133void
134breakout_internal(
135char *filename,
136struct arch **archs,
137uint32_t *narchs,
138enum bool calculate_input_prebind_cksum,
139struct ofile *ofile)
140{
141    struct arch *arch;
142
143	errors = 0;
144	if(ofile->file_type == OFILE_FAT && errors == 0){
145	    /* loop through the fat architectures (can't have zero archs) */
146	    (void)ofile_first_arch(ofile);
147	    do{
148		if(errors != 0)
149		    break;
150		arch = new_arch(archs, narchs);
151		arch->file_name = savestr(filename);
152		arch->type = ofile->arch_type;
153		arch->fat_arch = ofile->fat_archs + ofile->narch;
154		arch->fat_arch_name = savestr(ofile->arch_flag.name);
155
156		if(ofile->arch_type == OFILE_ARCHIVE){
157		    breakout_loop_through_archive(filename, arch, ofile);
158		}
159		else if(ofile->arch_type == OFILE_Mach_O){
160		    arch->object = allocate(sizeof(struct object));
161		    memset(arch->object, '\0', sizeof(struct object));
162		    arch->object->object_addr = ofile->object_addr;
163		    arch->object->object_size = ofile->object_size;
164		    arch->object->object_byte_sex = ofile->object_byte_sex;
165		    arch->object->mh64 = ofile->mh64;
166		    arch->object->mh = ofile->mh;
167		    arch->object->mh_filetype = ofile->mh_filetype;
168		    arch->object->mh_cputype = ofile->mh_cputype;
169		    arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
170		    arch->object->load_commands = ofile->load_commands;
171		    cksum_object(arch, calculate_input_prebind_cksum);
172		}
173		else{ /* ofile->arch_type == OFILE_UNKNOWN */
174		    arch->unknown_addr = ofile->file_addr +
175					 arch->fat_arch->offset;
176		    arch->unknown_size = arch->fat_arch->size;
177		}
178	    }while(ofile_next_arch(ofile) == TRUE);
179	}
180	else if(ofile->file_type == OFILE_ARCHIVE && errors == 0){
181	    arch = new_arch(archs, narchs);
182	    arch->file_name = savestr(filename);
183	    arch->type = ofile->file_type;
184
185	    breakout_loop_through_archive(filename, arch, ofile);
186	}
187	else if(ofile->file_type == OFILE_Mach_O && errors == 0){
188	    arch = new_arch(archs, narchs);
189	    arch->file_name = savestr(filename);
190	    arch->type = ofile->file_type;
191	    arch->object = allocate(sizeof(struct object));
192	    memset(arch->object, '\0', sizeof(struct object));
193	    arch->object->object_addr = ofile->object_addr;
194	    arch->object->object_size = ofile->object_size;
195	    arch->object->object_byte_sex = ofile->object_byte_sex;
196	    arch->object->mh64 = ofile->mh64;
197	    arch->object->mh = ofile->mh;
198	    arch->object->mh_filetype = ofile->mh_filetype;
199	    arch->object->mh_cputype = ofile->mh_cputype;
200	    arch->object->mh_cpusubtype = ofile->mh_cpusubtype;
201	    arch->object->load_commands = ofile->load_commands;
202	    cksum_object(arch, calculate_input_prebind_cksum);
203	}
204	else if(errors == 0){ /* ofile->file_type == OFILE_UNKNOWN */
205	    arch = new_arch(archs, narchs);
206	    arch->file_name = savestr(filename);
207	    arch->type = ofile->file_type;
208	    arch->unknown_addr = ofile->file_addr;
209	    arch->unknown_size = ofile->file_size;
210	}
211	if(errors != 0){
212	    free_archs(*archs, *narchs);
213	    *archs = NULL;
214	    *narchs = 0;
215	}
216}
217
218static
219void
220breakout_loop_through_archive(
221char *filename,
222struct arch *arch,
223struct ofile *ofile)
224{
225    struct member *member;
226    enum bool flag;
227    struct ar_hdr *ar_hdr;
228    uint32_t size, ar_name_size;
229    char ar_name_buf[sizeof(ofile->member_ar_hdr->ar_name) + 1];
230    char ar_size_buf[sizeof(ofile->member_ar_hdr->ar_size) + 1];
231
232	/* loop through archive (can be empty) */
233	if((flag = ofile_first_member(ofile)) == TRUE && errors == 0){
234	    /*
235	     * If the first member is a table of contents then skip
236	     * it as it is always rebuilt (so to get the time to
237	     * match the modtime so it won't appear out of date).
238	     * Also force it to be a long name so members can be 8 byte
239	     * aligned.
240	     */
241	    if(ofile->member_ar_hdr != NULL &&
242	       strncmp(ofile->member_name, SYMDEF,
243		       sizeof(SYMDEF) - 1) == 0){
244		arch->toc_long_name = TRUE;
245		flag = ofile_next_member(ofile);
246	    }
247	    while(flag == TRUE && errors == 0){
248		member = new_member(arch);
249		member->type = ofile->member_type;
250		member->member_name = ofile->member_name;
251		/*
252		 * Determine the size this member will have in the library which
253		 * includes the padding as a result of rounding the size of the
254		 * member.  To get all members on an 8 byte boundary (so that
255		 * mapping in object files can be used directly) the size of the
256		 * member is CHANGED to reflect this padding.  In the UNIX
257		 * definition of archives the size of the member is never
258		 * changed but the offset to the next member is defined to be
259		 * the offset of the previous member plus the size of the
260		 * previous member rounded to 2.  So to get 8 byte boundaries
261		 * without breaking the UNIX definition of archives the size is
262		 * changed here.  As with the UNIX ar(1) program the padded
263		 * bytes will be set to the character '\n'.
264		 */
265		if(ofile->mh != NULL || ofile->mh64 != NULL)
266		    size = rnd(ofile->object_size, 8);
267		else
268		    size = rnd(ofile->member_size, 8);
269		/*
270		 * We will force the use of long names so we can make sure the
271		 * size of the name and the size of struct ar_hdr are rounded to
272		 * 8 bytes.  And that rounded size is what will be in the
273		 * ar_name with the AR_EFMT1 string.  To avoid growing the size
274		 * of names first trim the name size before rounding up.
275		 */
276		member->member_long_name = TRUE;
277		for(ar_name_size = ofile->member_name_size;
278		    ar_name_size > 1 ;
279		    ar_name_size--){
280		    if(ofile->member_name[ar_name_size - 1] != '\0')
281		       break;
282		}
283		member->member_name_size = ar_name_size;
284		ar_name_size = rnd(ar_name_size, 8) +
285			       (rnd(sizeof(struct ar_hdr), 8) -
286				sizeof(struct ar_hdr));
287		size += ar_name_size;
288		/*
289		 * Now with the output sizes of the long member name and rounded
290		 * size of the member the offset to this member can be set and
291		 * then left incremented for the next member's offset.
292		 */
293		member->offset = arch->library_size;
294		arch->library_size += sizeof(struct ar_hdr) + size;
295		/*
296		 * Since we are rounding the member size and forcing a the use
297		 * of a long name make a new ar_hdr with this information.
298		 * Note the code in writeout() will do the padding with '\n'
299		 * characters as needed.
300		 */
301		ar_hdr = allocate(sizeof(struct ar_hdr));
302		*ar_hdr = *(ofile->member_ar_hdr);
303		sprintf(ar_name_buf, "%s%-*lu", AR_EFMT1,
304			(int)(sizeof(ar_hdr->ar_name) - (sizeof(AR_EFMT1) - 1)),
305		        (long unsigned int)ar_name_size);
306		memcpy(ar_hdr->ar_name, ar_name_buf,
307		      sizeof(ar_hdr->ar_name));
308		sprintf(ar_size_buf, "%-*ld",
309			(int)sizeof(ar_hdr->ar_size), (long unsigned int)size);
310		memcpy(ar_hdr->ar_size, ar_size_buf,
311		      sizeof(ar_hdr->ar_size));
312
313		member->ar_hdr = ar_hdr;
314		member->input_ar_hdr = ofile->member_ar_hdr;
315		member->input_file_name = filename;
316
317		if(ofile->member_type == OFILE_Mach_O){
318		    member->object = allocate(sizeof(struct object));
319		    memset(member->object, '\0', sizeof(struct object));
320		    member->object->object_addr = ofile->object_addr;
321		    member->object->object_size = ofile->object_size;
322		    member->object->object_byte_sex = ofile->object_byte_sex;
323		    member->object->mh64 = ofile->mh64;
324		    member->object->mh = ofile->mh;
325		    member->object->mh_filetype = ofile->mh_filetype;
326		    member->object->mh_cputype = ofile->mh_cputype;
327		    member->object->mh_cpusubtype = ofile->mh_cpusubtype;
328		    member->object->load_commands = ofile->load_commands;
329		}
330		else{ /* ofile->member_type == OFILE_UNKNOWN */
331		    member->unknown_addr = ofile->member_addr;
332		    member->unknown_size = ofile->member_size;
333		}
334		flag = ofile_next_member(ofile);
335	    }
336	}
337}
338
339/*
340 * cksum_object() is called to set the pointer to the LC_PREBIND_CKSUM load
341 * command in the object struct for the specified arch.  If the parameter
342 * calculate_input_prebind_cksum is TRUE then calculate the value
343 * of the check sum for the input object if needed, set that into the
344 * the calculated_input_prebind_cksum field of the object struct for the
345 * specified arch.  This is needed for prebound files where the original
346 * checksum (or zero) is recorded in the LC_PREBIND_CKSUM load command.
347 * Only redo_prebinding operations sets the value of the cksum field to
348 * non-zero and only if previously zero.  All other operations will set this
349 * field to zero indicating a new original prebound file.
350 */
351static
352void
353cksum_object(
354struct arch *arch,
355enum bool calculate_input_prebind_cksum)
356{
357    uint32_t i, buf_size, ncmds;
358    struct load_command *lc;
359    enum byte_sex host_byte_sex;
360    char *buf;
361
362	arch->object->cs = NULL;
363	lc = arch->object->load_commands;
364	if(arch->object->mh != NULL)
365	    ncmds = arch->object->mh->ncmds;
366	else
367	    ncmds = arch->object->mh64->ncmds;
368	for(i = 0;
369	    i < ncmds && arch->object->cs == NULL;
370	    i++){
371	    if(lc->cmd == LC_PREBIND_CKSUM)
372		arch->object->cs = (struct prebind_cksum_command *)lc;
373	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
374	}
375
376	/*
377	 * If we don't want to calculate the input check sum, or there is no
378	 * LC_PREBIND_CKSUM load command or there is one and the check sum is
379	 * not zero then return.
380	 */
381	if(calculate_input_prebind_cksum == FALSE ||
382	   arch->object->cs == NULL ||
383	   arch->object->cs->cksum != 0)
384	    return;
385
386
387	host_byte_sex = get_host_byte_sex();
388	buf_size = 0;
389	buf = NULL;
390	if(arch->object->object_byte_sex != host_byte_sex){
391	    if(arch->object->mh != NULL){
392		buf_size = sizeof(struct mach_header) +
393			   arch->object->mh->sizeofcmds;
394		buf = allocate(buf_size);
395		memcpy(buf, arch->object->mh, buf_size);
396		if(swap_object_headers(arch->object->mh,
397				       arch->object->load_commands) == FALSE)
398		    return;
399	    }
400	    else{
401		buf_size = sizeof(struct mach_header_64) +
402			   arch->object->mh64->sizeofcmds;
403		buf = allocate(buf_size);
404		memcpy(buf, arch->object->mh64, buf_size);
405		if(swap_object_headers(arch->object->mh64,
406				       arch->object->load_commands) == FALSE)
407		    return;
408	    }
409	}
410
411	arch->object->calculated_input_prebind_cksum =
412	    crc32(arch->object->object_addr, arch->object->object_size);
413
414	if(arch->object->object_byte_sex != host_byte_sex){
415	    if(arch->object->mh != NULL)
416		memcpy(arch->object->mh, buf, buf_size);
417	    else
418		memcpy(arch->object->mh64, buf, buf_size);
419	    free(buf);
420	}
421}
422
423__private_extern__
424void
425free_archs(
426struct arch *archs,
427uint32_t narchs)
428{
429    uint32_t i, j;
430
431	for(i = 0; i < narchs; i++){
432	    if(archs[i].type == OFILE_ARCHIVE){
433		for(j = 0; j < archs[i].nmembers; j++){
434		    if(archs[i].members[j].type == OFILE_Mach_O){
435			if(archs[i].members[j].object->ld_r_ofile != NULL)
436			   ofile_unmap(archs[i].members[j].object->ld_r_ofile);
437			free(archs[i].members[j].object);
438		    }
439		}
440		if(archs[i].nmembers > 0 && archs[i].members != NULL)
441		    free(archs[i].members);
442	    }
443	    else if(archs[i].type == OFILE_Mach_O){
444		if(archs[i].object->ld_r_ofile != NULL)
445		    ofile_unmap(archs[i].object->ld_r_ofile);
446		free(archs[i].object);
447	    }
448	}
449	if(narchs > 0 && archs != NULL)
450	    free(archs);
451}
452
453static
454struct arch *
455new_arch(
456struct arch **archs,
457uint32_t *narchs)
458{
459    struct arch *arch;
460
461	*archs = reallocate(*archs, (*narchs + 1) * sizeof(struct arch));
462	arch = *archs + *narchs;
463	*narchs = *narchs + 1;
464	memset(arch, '\0', sizeof(struct arch));
465	return(arch);
466}
467
468static
469struct member *
470new_member(
471struct arch *arch)
472{
473    struct member *member;
474
475	arch->members = reallocate(arch->members,
476				  (arch->nmembers + 1) * sizeof(struct member));
477	member = arch->members + arch->nmembers;
478	arch->nmembers++;
479	memset(member, '\0', sizeof(struct member));
480	return(member);
481}
482#endif /* !defined(RLD) */
483