1/*
2 * Copyright (c) 2007 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 __linux__
24#include <libc.h>
25#else
26#include <stdio.h>
27#include <stdint.h>
28#include <stdarg.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#endif
33
34#include <errno.h>
35
36#include <sys/stat.h>
37#include <sys/file.h>
38#include <sys/mman.h>
39
40#include <mach-o/swap.h>
41
42#ifdef __APPLE__
43#include <IOKit/IOTypes.h>
44#else
45#undef OSSwapInt32
46#define OSSwapInt32 	__builtin_bswap32
47#include <stdbool.h>
48#endif
49
50/*********************************************************************
51*********************************************************************/
52static int
53writeFile(int fd, const void * data, size_t length)
54{
55    int error = 0;
56
57    if (length != (size_t)write(fd, data, length)) {
58        error = -1;
59    }
60
61    if (error != 0) {
62        perror("couldn't write output");
63    }
64
65    return error;
66}
67
68/*********************************************************************
69*********************************************************************/
70static int
71readFile(const char *path, vm_offset_t * objAddr, vm_size_t * objSize)
72{
73    int error = -1;
74    int fd;
75    struct stat stat_buf;
76
77    *objAddr = 0;
78    *objSize = 0;
79
80    do {
81        if ((fd = open(path, O_RDONLY)) == -1) {
82            continue;
83        }
84
85        if (fstat(fd, &stat_buf) == -1) {
86            continue;
87        }
88
89        if (0 == (stat_buf.st_mode & S_IFREG)) {
90            continue;
91        }
92
93        if (0 == stat_buf.st_size) {
94            error = 0;
95            continue;
96        }
97
98        *objSize = stat_buf.st_size;
99
100        *objAddr = (vm_offset_t)mmap(NULL /* address */, *objSize,
101            PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE /* flags */,
102            fd, 0 /* offset */);
103
104        if ((void *)*objAddr == MAP_FAILED) {
105                *objAddr = 0;
106                *objSize = 0;
107            continue;
108        }
109
110        error = 0;
111
112    } while (false);
113
114    if (-1 != fd) {
115        close(fd);
116    }
117    if (error) {
118        fprintf(stderr, "couldn't read %s: %s\n", path, strerror(errno));
119    }
120
121    return error;
122}
123
124/*********************************************************************
125*********************************************************************/
126int main(int argc, char * argv[])
127{
128    int                     error;
129    const char            * output_name = NULL;
130    const char            * newseg_name = NULL;
131    struct mach_header    * hdr;
132    struct mach_header_64 * hdr64;
133    struct load_command   * cmds;
134    boolean_t		        swap = false;
135    uint32_t		        ncmds, cmdtype;
136    uint32_t		        len;
137    vm_offset_t		        input;
138    vm_size_t		        input_size;
139    uint32_t		        nsects = 0;
140    uint32_t                * flags = NULL;
141    uint32_t		        attr;
142    typedef char            segname_t[16];
143    segname_t             * names = NULL;
144
145    if ((argc != 5) || strcmp("-o", argv[3])) {
146        fprintf(stderr, "Usage: %s NEWSEGNAME input -o output\n", argv[0]);
147        exit(1);
148    }
149
150    output_name = argv[4];
151    newseg_name = argv[1];
152
153    error = readFile(argv[2], &input, &input_size);
154    if (error) {
155        exit(1);
156    }
157
158    hdr = (typeof(hdr)) input;
159    switch (hdr->magic) {
160        case MH_CIGAM:
161            swap = true;
162            // fall thru
163        case MH_MAGIC:
164            ncmds = hdr->ncmds;
165            cmds  = (typeof(cmds)) (hdr+1);
166            break;
167
168        case MH_CIGAM_64:
169            swap = true;
170            // fall thru
171        case MH_MAGIC_64:
172            hdr64 = (typeof(hdr64)) hdr;
173            ncmds = hdr64->ncmds;
174            cmds  = (typeof(cmds)) (hdr64+1);
175            break;
176
177        default:
178            fprintf(stderr, "not macho input file\n");
179            exit(1);
180            break;
181    }
182
183    if (swap) {
184        ncmds = OSSwapInt32(ncmds);
185    }
186    while (ncmds--) {
187        cmdtype = cmds->cmd;
188        if (swap) {
189            cmdtype = OSSwapInt32(cmdtype);
190        }
191        nsects = 0;
192        len    = 0;
193        if (LC_SEGMENT == cmdtype) {
194            struct segment_command * segcmd;
195            struct section         * sects;
196
197            segcmd = (typeof(segcmd)) cmds;
198            nsects = segcmd->nsects;
199            sects  = (typeof(sects))(segcmd + 1);
200            names  = &sects->segname;
201            flags  = &sects->flags;
202            len    = sizeof(*sects);
203        } else if (LC_SEGMENT_64 == cmdtype) {
204            struct segment_command_64 * segcmd;
205            struct section_64         * sects;
206
207            segcmd = (typeof(segcmd)) cmds;
208            nsects = segcmd->nsects;
209            sects  = (typeof(sects))(segcmd + 1);
210            names  = &sects->segname;
211            flags  = &sects->flags;
212            len    = sizeof(*sects);
213        }
214
215        if (swap)
216            nsects = OSSwapInt32(nsects);
217        while (nsects--) {
218            attr = *flags;
219            if (swap) {
220                attr = OSSwapInt32(attr);
221            }
222
223            if (!(S_ATTR_DEBUG & attr)) {
224                strncpy((char *)names, newseg_name, sizeof(*names));
225            }
226
227            names = (typeof(names))(((uintptr_t) names) + len);
228            flags = (typeof(flags))(((uintptr_t) flags) + len);
229        }
230
231        len = cmds->cmdsize;
232        if (swap) {
233            len = OSSwapInt32(len);
234        }
235        cmds = (typeof(cmds))(((uintptr_t) cmds) + len);
236    }
237
238    int fd = open(output_name, O_WRONLY|O_CREAT|O_TRUNC, 0755);
239    if (-1 == fd) {
240        error = -1;
241    } else {
242        error = writeFile(fd, (const void *) input, input_size);
243        close(fd);
244    }
245
246    if (error) {
247        fprintf(stderr, "couldn't write output: %s\n", strerror(errno));
248        exit(1);
249    }
250
251    exit(0);
252    return 0;
253}
254