1/*
2 * Copyright (c) 2006 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#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <limits.h>
27#include <fcntl.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/mman.h>
31#include "stuff/allocate.h"
32#include "stuff/errors.h"
33#include "stuff/breakout.h"
34#include "stuff/rnd.h"
35
36/*
37 * The structure that holds the -arch <arch> <file> information from the command
38 * line flags.
39 */
40struct arch_ctf {
41    struct arch_flag arch_flag;
42    enum bool arch_found;
43    char *filename;
44    char *contents;
45    uint32_t size;
46};
47struct arch_ctf *arch_ctfs;
48uint32_t narch_ctfs = 0;
49
50/* used by error routines as the name of the program */
51char *progname = NULL;
52
53static void usage(
54    void);
55
56static void process(
57    struct arch *archs,
58    uint32_t narchs);
59
60static void ctf_insert(
61    struct arch *arch,
62    struct member *member,
63    struct object *object);
64
65static void add_ctf_section(
66    struct arch *arch,
67    char *arch_name,
68    uint32_t offset,
69    uint64_t addr,
70    uint32_t size);
71
72/* apple_version is created by the libstuff/Makefile */
73extern char apple_version[];
74char *version = apple_version;
75
76/*
77 * The ctf_insert(1) tool has the following usage:
78 *
79 *	ctf_insert input -arch arch ctf_file ...  -o output
80 *
81 * Where the input is a Mach-O file that is the ctf_file(s) are to be inserted
82 * into and output is the file to be created.
83 */
84int
85main(
86int argc,
87char **argv,
88char **envp)
89{
90    uint32_t i;
91    char *input, *output, *contents;
92    struct arch *archs;
93    uint32_t narchs;
94    struct stat stat_buf;
95    int fd;
96
97	progname = argv[0];
98	input = NULL;
99	output = NULL;
100	archs = NULL;
101	narchs = 0;
102	for(i = 1; i < argc; i++){
103	    if(strcmp(argv[i], "-o") == 0){
104		if(i + 1 == argc){
105		    error("missing argument to: %s option", argv[i]);
106		    usage();
107		}
108		if(output != NULL){
109		    error("more than one: %s option specified", argv[i]);
110		    usage();
111		}
112		output = argv[i+1];
113		i++;
114	    }
115	    else if(strcmp(argv[i], "-arch") == 0){
116		if(i + 2 == argc){
117		    error("missing argument(s) to: %s option", argv[i]);
118		    usage();
119		}
120		else{
121		    arch_ctfs = reallocate(arch_ctfs,
122			    (narch_ctfs + 1) * sizeof(struct arch_ctf));
123		    if(get_arch_from_flag(argv[i+1],
124				  &(arch_ctfs[narch_ctfs].arch_flag)) == 0){
125			error("unknown architecture specification flag: "
126			      "%s %s %s", argv[i], argv[i+1], argv[i+2]);
127			arch_usage();
128			usage();
129		    }
130		    if((fd = open(argv[i+2], O_RDONLY, 0)) == -1)
131			system_fatal("can't open file: %s", argv[i+2]);
132		    if(fstat(fd, &stat_buf) == -1)
133			system_fatal("can't stat file: %s", argv[i+2]);
134		    /*
135		     * For some reason mapping files with zero size fails
136		     * so it has to be handled specially.
137		     */
138		    contents = NULL;
139		    if(stat_buf.st_size != 0){
140			contents = mmap(0, stat_buf.st_size,
141					PROT_READ|PROT_WRITE,
142				        MAP_FILE|MAP_PRIVATE, fd, 0);
143			if((intptr_t)contents == -1)
144			    system_error("can't map file : %s", argv[i+2]);
145		    }
146		    arch_ctfs[narch_ctfs].filename = argv[i+2];
147		    arch_ctfs[narch_ctfs].contents = contents;
148		    arch_ctfs[narch_ctfs].size = stat_buf.st_size;
149		    arch_ctfs[narch_ctfs].arch_found = FALSE;
150		    narch_ctfs++;
151		    i += 2;
152		}
153	    }
154	    else{
155		if(input != NULL){
156		    error("more than one input file file: %s specified",
157			  input);
158		    usage();
159		}
160		input = argv[i];
161	    }
162	}
163	if(input == NULL || output == NULL || narch_ctfs == 0)
164	    usage();
165
166	breakout(input, &archs, &narchs, FALSE);
167	if(errors)
168	    exit(EXIT_FAILURE);
169
170	checkout(archs, narchs);
171
172	process(archs, narchs);
173
174	for(i = 0; i < narch_ctfs; i++){
175	    if(arch_ctfs[i].arch_found == FALSE)
176		fatal("input file: %s does not contain a matching architecture "
177		      "for specified '-arch %s %s' option", input,
178		      arch_ctfs[i].arch_flag.name, arch_ctfs[i].filename);
179	}
180
181	writeout(archs, narchs, output, 0777, TRUE, FALSE, FALSE, NULL);
182
183	if(errors)
184	    return(EXIT_FAILURE);
185	else
186	    return(EXIT_SUCCESS);
187}
188
189/*
190 * usage() prints the current usage message and exits indicating failure.
191 */
192static
193void
194usage(
195void)
196{
197	fprintf(stderr, "Usage: %s input [-arch <arch> <file>]... -o output\n",
198		progname);
199	exit(EXIT_FAILURE);
200}
201
202/*
203 * process() walks the archs and calls ctf_insert() to do the work.
204 */
205static
206void
207process(
208struct arch *archs,
209uint32_t narchs)
210{
211    uint32_t i;
212
213	for(i = 0; i < narchs; i++){
214	    if(archs[i].type == OFILE_Mach_O)
215		ctf_insert(archs + i, NULL, archs[i].object);
216	    else
217		fatal_arch(archs + i, NULL, "file type not valid input for "
218			   "this this program to process: ");
219	}
220}
221
222/*
223 * ctf_insert() does the work to add the ctf section in the specified broken
224 * out ofile for the architecure specifed with a -arch command line option.
225 */
226static
227void
228ctf_insert(
229struct arch *arch,
230struct member *member,
231struct object *object)
232{
233    uint32_t i, move_size;
234    cpu_type_t cputype;
235    cpu_subtype_t cpusubtype;
236    uint32_t flags, offset;
237    uint64_t addr;
238
239	if(object->mh != NULL){
240	    cputype = object->mh->cputype;
241	    cpusubtype = object->mh->cpusubtype & ~CPU_SUBTYPE_MASK;
242	    flags = object->mh->flags;
243	    offset = object->seg_linkedit->fileoff;
244	    addr = object->seg_linkedit->vmaddr;
245	}
246	else{
247	    cputype = object->mh64->cputype;
248	    cpusubtype = object->mh64->cpusubtype & ~CPU_SUBTYPE_MASK;
249	    flags = object->mh64->flags;
250	    offset = object->seg_linkedit64->fileoff;
251	    addr = object->seg_linkedit64->vmaddr;
252	}
253
254	/*
255	 * Make sure this object is valid to process.  Since the input should
256	 * be a mach_kernel that is statically linked we should not see any
257	 * dynamic symbol table info. Or a code signature at the point this
258	 * program is called in the build process.
259	 */
260	if((flags & MH_DYLDLINK) == MH_DYLDLINK ||
261	   object->dyld_info != NULL ||
262	   object->split_info_cmd != NULL ||
263	   object->hints_cmd != NULL)
264	     fatal_arch(arch, member, "file is input for the dynamic linker so "
265			"not a valid input for this program to process: ");
266	/*
267	 * Allow a dynamic symbol table load command where it only has an
268	 * indirect symbol table and no other tables.
269	 */
270        if(object->dyst != NULL &&
271	   (object->dyst->ntoc != 0 ||
272	    object->dyst->nmodtab != 0 ||
273	    object->dyst->nmodtab != 0 ||
274	    object->dyst->nextrefsyms != 0 ||
275	    object->dyst->nextrel != 0))
276	     fatal_arch(arch, member, "file is input for the dynamic linker so "
277			"not a valid input for this program to process: ");
278	if(object->mh_filetype != MH_EXECUTE)
279	     fatal_arch(arch, member, "file type is not MH_EXECUTE so "
280			"not a valid input for this program to process: ");
281	if(object->seg_linkedit == NULL && object->seg_linkedit64 == NULL)
282	     fatal_arch(arch, member, "file type does not have a __LINKEDIT "
283			"segment so not a valid input for this program to "
284			"process: ");
285	if(object->code_sig_cmd != NULL)
286	     fatal_arch(arch, member, "file type has code signature "
287			"so not a valid input for this program to process: ");
288
289	/*
290	 * Now see if one of the -arch flags matches this object.
291	 */
292	for(i = 0; i < narch_ctfs; i++){
293	    if(arch_ctfs[i].arch_flag.cputype == cputype &&
294	       arch_ctfs[i].arch_flag.cpusubtype == cpusubtype)
295		break;
296	}
297	/*
298	 * If we didn't find a matching -arch flag it is an error.
299	 */
300	if(i >= narch_ctfs){
301	     fatal_arch(arch, member, "no matching -arch option for this slice "
302			"of file: ");
303	     return;
304	}
305	arch_ctfs[i].arch_found = TRUE;
306
307	/*
308	 * Add the section for the ctf data for this arch.  It is placed in
309	 * the file where the linkedit info was and that info will then be
310	 * moved.
311	 */
312	add_ctf_section(arch, arch_ctfs[i].arch_flag.name,
313			offset, addr, arch_ctfs[i].size);
314
315	/*
316	 * Now set up all the pointers and sizes of the symbol and string table.
317	 */
318	if(object->st != NULL && object->st->nsyms != 0){
319	    if(object->mh != NULL){
320		object->output_symbols = (struct nlist *)
321		    (object->object_addr + object->st->symoff);
322		if(object->object_byte_sex != get_host_byte_sex())
323		    swap_nlist(object->output_symbols,
324			       object->st->nsyms,
325			       get_host_byte_sex());
326		object->output_symbols64 = NULL;
327	    }
328	    else{
329		object->output_symbols64 = (struct nlist_64 *)
330		    (object->object_addr + object->st->symoff);
331		if(object->object_byte_sex != get_host_byte_sex())
332		    swap_nlist_64(object->output_symbols64,
333				  object->st->nsyms,
334				  get_host_byte_sex());
335		object->output_symbols = NULL;
336	    }
337	    object->output_nsymbols = object->st->nsyms;
338	    object->output_strings =
339		object->object_addr + object->st->stroff;
340	    object->output_strings_size = object->st->strsize;
341	    if(object->mh != NULL){
342		object->input_sym_info_size =
343		    object->st->nsyms * sizeof(struct nlist) +
344		    object->st->strsize;
345	    }
346	    else{
347		object->input_sym_info_size =
348		    object->st->nsyms * sizeof(struct nlist_64) +
349		    object->st->strsize;
350	    }
351	}
352	if(object->dyst != NULL){
353	    object->output_ilocalsym = object->dyst->ilocalsym;
354	    object->output_nlocalsym = object->dyst->nlocalsym;
355	    object->output_iextdefsym = object->dyst->iextdefsym;
356	    object->output_nextdefsym = object->dyst->nextdefsym;
357	    object->output_iundefsym = object->dyst->iundefsym;
358	    object->output_nundefsym = object->dyst->nundefsym;
359	    object->output_indirect_symtab = (uint32_t *)
360		(object->object_addr + object->dyst->indirectsymoff);
361	    object->output_loc_relocs = (struct relocation_info *)
362		(object->object_addr + object->dyst->locreloff);
363	    if(object->mh != NULL){
364		object->input_sym_info_size +=
365		    object->dyst->nindirectsyms *
366			sizeof(uint32_t);
367	    }
368	    else{
369		object->input_sym_info_size +=
370		    object->dyst->nindirectsyms *
371			sizeof(uint32_t) +
372		    object->input_indirectsym_pad;
373	    }
374	    object->input_sym_info_size +=
375		object->dyst->nlocrel *
376		    sizeof(struct relocation_info);
377	}
378	if(object->func_starts_info_cmd != NULL){
379	    object->output_func_start_info_data = object->object_addr +
380		object->func_starts_info_cmd->dataoff;
381	    object->output_func_start_info_data_size =
382		object->func_starts_info_cmd->datasize;
383	    object->input_sym_info_size +=
384		object->func_starts_info_cmd->datasize;
385	}
386	if(object->data_in_code_cmd != NULL){
387	    object->output_data_in_code_info_data = object->object_addr +
388		object->data_in_code_cmd->dataoff;
389	    object->output_data_in_code_info_data_size =
390		object->data_in_code_cmd->datasize;
391	    object->input_sym_info_size +=
392		object->data_in_code_cmd->datasize;
393	}
394	if(object->code_sign_drs_cmd != NULL){
395	    object->output_code_sign_drs_info_data = object->object_addr +
396		object->code_sign_drs_cmd->dataoff;
397	    object->output_code_sign_drs_info_data_size =
398		object->code_sign_drs_cmd->datasize;
399	    object->input_sym_info_size +=
400		object->code_sign_drs_cmd->datasize;
401	}
402	object->output_sym_info_size = object->input_sym_info_size;
403
404	/*
405	 * Now move the link edit info by the size of the ctf for this arch
406	 * rounded to the load command size for this arch.
407	 */
408	if(object->mh != NULL){
409	    move_size = rnd(arch_ctfs[i].size, sizeof(uint32_t));
410	    object->seg_linkedit->fileoff += move_size;
411	}
412	else{
413	    move_size = rnd(arch_ctfs[i].size, sizeof(uint64_t));
414	    object->seg_linkedit64->fileoff += move_size;
415	}
416	if(object->st != NULL && object->st->nsyms != 0){
417	    object->st->symoff += move_size;
418	    object->st->stroff += move_size;
419	}
420	if(object->dyst != NULL){
421	    if(object->dyst->nindirectsyms != 0)
422	        object->dyst->indirectsymoff += move_size;
423	    if(object->dyst->nlocrel != 0)
424		object->dyst->locreloff += move_size;
425	}
426	if(object->func_starts_info_cmd != NULL)
427	    object->func_starts_info_cmd->dataoff += move_size;
428	if(object->data_in_code_cmd != NULL)
429	    object->data_in_code_cmd->dataoff += move_size;
430	if(object->code_sign_drs_cmd != NULL)
431	    object->code_sign_drs_cmd->dataoff += move_size;
432
433	/*
434	 * Record the new content for writeout() to put in to the output file.
435	 */
436	object->output_new_content = arch_ctfs[i].contents;
437	object->output_new_content_size = move_size;
438}
439
440/*
441 * add_ctf_section() sees if there is space to add an LC_SEGMENT load command
442 * and one section stucture in the padding after the headers for the specified
443 * arch and arch_name.  If so it adds a segment load command and section struct
444 * filled in with the offset, size and addr fields.  If it can't be added or
445 * one already exists a fatal error message is printed.
446 */
447static
448void
449add_ctf_section(
450struct arch *arch,
451char *arch_name,
452uint32_t offset,
453uint64_t addr,
454uint32_t size)
455{
456    uint32_t i, j, low_fileoff, mach_header_size, added_header_size;
457    uint32_t ncmds, sizeofcmds;
458    struct load_command *lc;
459    struct segment_command *sg;
460    struct segment_command_64 *sg64;
461    struct section *s;
462    struct section_64 *s64;
463    struct segment_command *sg_CTF;
464    struct section *s_ctf;
465    struct segment_command_64 *sg64_CTF;
466    struct section_64 *s64_ctf;
467
468        if(arch->object->mh != NULL){
469            ncmds = arch->object->mh->ncmds;
470	    sizeofcmds = arch->object->mh->sizeofcmds;
471	    mach_header_size = sizeof(struct mach_header);
472	    added_header_size = sizeof(struct segment_command) +
473				sizeof(struct section);
474	}
475	else{
476            ncmds = arch->object->mh64->ncmds;
477	    sizeofcmds = arch->object->mh64->sizeofcmds;
478	    mach_header_size = sizeof(struct mach_header_64);
479	    added_header_size = sizeof(struct segment_command_64) +
480				sizeof(struct section_64);
481	}
482
483	/*
484	 * The size of the new load commands that includes the added segment
485	 * load command and section structure is larger than the existing load
486	 * commands, so see if they can be fitted in before the contents of the
487	 * first section (or segment in the case of a LINKEDIT segment only
488	 * file).
489	 */
490	low_fileoff = UINT_MAX;
491	lc = arch->object->load_commands;
492	for(i = 0; i < ncmds; i++){
493	    if(lc->cmd == LC_SEGMENT){
494		sg = (struct segment_command *)lc;
495		if(strcmp(sg->segname, "__CTF") == 0)
496		    fatal("can't insert __CTF segment for: %s (for "
497			  "architecture %s) because it already contains "
498			  "this segment", arch->file_name, arch_name);
499		s = (struct section *)
500		    ((char *)sg + sizeof(struct segment_command));
501		if(sg->nsects != 0){
502		    for(j = 0; j < sg->nsects; j++){
503			if(s->size != 0 &&
504			(s->flags & S_ZEROFILL) != S_ZEROFILL &&
505			(s->flags & S_THREAD_LOCAL_ZEROFILL) !=
506				    S_THREAD_LOCAL_ZEROFILL &&
507			s->offset < low_fileoff)
508			    low_fileoff = s->offset;
509			s++;
510		    }
511		}
512		else{
513		    if(sg->filesize != 0 && sg->fileoff < low_fileoff)
514			low_fileoff = sg->fileoff;
515		}
516	    }
517	    else if(lc->cmd == LC_SEGMENT_64){
518		sg64 = (struct segment_command_64 *)lc;
519		if(strcmp(sg64->segname, "__CTF") == 0)
520		    fatal("can't insert __CTF segment for: %s (for "
521			  "architecture %s) because it already contains "
522			  "this segment", arch->file_name, arch_name);
523		s64 = (struct section_64 *)
524		    ((char *)sg64 + sizeof(struct segment_command_64));
525		if(sg64->nsects != 0){
526		    for(j = 0; j < sg64->nsects; j++){
527			if(s64->size != 0 &&
528			(s64->flags & S_ZEROFILL) != S_ZEROFILL &&
529			(s64->flags & S_THREAD_LOCAL_ZEROFILL) !=
530				      S_THREAD_LOCAL_ZEROFILL &&
531			s64->offset < low_fileoff)
532			    low_fileoff = s64->offset;
533			s64++;
534		    }
535		}
536		else{
537		    if(sg64->filesize != 0 && sg64->fileoff < low_fileoff)
538			low_fileoff = sg64->fileoff;
539		}
540	    }
541	    lc = (struct load_command *)((char *)lc + lc->cmdsize);
542	}
543	if(sizeofcmds + mach_header_size + added_header_size > low_fileoff)
544{
545printf("added_header_size = %d\n", added_header_size);
546printf("space available = %d\n", low_fileoff - (sizeofcmds + mach_header_size));
547	    fatal("can't insert (__CTF,__ctf) section for: %s (for architecture"
548		  " %s) because larger updated load commands do not fit (the "
549		  "program must be relinked using a larger -headerpad value)",
550		  arch->file_name, arch_name);
551}
552	/*
553	 * There is space for the new load command. So just use that space for
554	 * the new segment and section and set the fields.
555	 */
556        if(arch->object->mh != NULL){
557	    sg_CTF = (struct segment_command *)
558		     ((char *)arch->object->load_commands + sizeofcmds);
559	    memset(sg_CTF, '\0', sizeof(struct segment_command));
560	    sg_CTF->cmd = LC_SEGMENT;
561	    sg_CTF->cmdsize = sizeof(struct segment_command) +
562			      sizeof(struct section);
563	    strcpy(sg_CTF->segname, "__CTF");
564	    sg_CTF->vmaddr = addr;
565	    sg_CTF->vmsize = 0;
566	    sg_CTF->fileoff = offset;
567	    sg_CTF->filesize = size;
568	    sg_CTF->maxprot = VM_PROT_READ;
569	    sg_CTF->initprot = VM_PROT_READ;
570	    sg_CTF->nsects = 1;
571	    sg_CTF->flags = 0;
572	    s_ctf = (struct section *)
573		    ((char *)sg_CTF + sizeof(struct segment_command));
574	    memset(s_ctf, '\0', sizeof(struct section));
575	    strcpy(s_ctf->sectname, "__ctf");
576	    strcpy(s_ctf->segname, "__CTF");
577	    s_ctf->addr = addr;
578	    s_ctf->size = size;
579	    s_ctf->offset = offset;
580	    s_ctf->align = 0;
581	    s_ctf->reloff = 0;
582	    s_ctf->nreloc = 0;
583	    s_ctf->flags = S_REGULAR;
584	    s_ctf->reserved1 = 0;
585	    s_ctf->reserved2 = 0;
586            arch->object->mh->sizeofcmds = sizeofcmds +
587					   sizeof(struct segment_command) +
588					   sizeof(struct section);
589            arch->object->mh->ncmds = ncmds + 1;
590        }
591	else{
592	    sg64_CTF = (struct segment_command_64 *)
593		   ((char *)arch->object->load_commands + sizeofcmds);
594	    memset(sg64_CTF, '\0', sizeof(struct segment_command_64));
595	    sg64_CTF->cmd = LC_SEGMENT_64;
596	    sg64_CTF->cmdsize = sizeof(struct segment_command_64) +
597				sizeof(struct section_64);
598	    strcpy(sg64_CTF->segname, "__CTF");
599	    sg64_CTF->vmaddr = addr;
600	    sg64_CTF->vmsize = 0;
601	    sg64_CTF->fileoff = offset;
602	    sg64_CTF->filesize = size;
603	    sg64_CTF->maxprot = VM_PROT_READ;
604	    sg64_CTF->initprot = VM_PROT_READ;
605	    sg64_CTF->nsects = 1;
606	    sg64_CTF->flags = 0;
607	    s64_ctf = (struct section_64 *)
608		  ((char *)sg64_CTF + sizeof(struct segment_command_64));
609	    memset(s64_ctf, '\0', sizeof(struct section_64));
610	    strcpy(s64_ctf->sectname, "__ctf");
611	    strcpy(s64_ctf->segname, "__CTF");
612	    s64_ctf->addr = addr;
613	    s64_ctf->size = size;
614	    s64_ctf->offset = offset;
615	    s64_ctf->align = 0;
616	    s64_ctf->reloff = 0;
617	    s64_ctf->nreloc = 0;
618	    s64_ctf->flags = S_REGULAR;
619	    s64_ctf->reserved1 = 0;
620	    s64_ctf->reserved2 = 0;
621            arch->object->mh64->sizeofcmds = sizeofcmds +
622					     sizeof(struct segment_command_64) +
623					     sizeof(struct section_64);
624            arch->object->mh64->ncmds = ncmds + 1;
625        }
626}
627