ld64 with ppc
[darwin-xtools.git] / cctools / libstuff / seg_addr_table.c
blob44afe51227f8511dff7de048a6ec157f095d88e8
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
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.
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.
21 * @APPLE_LICENSE_HEADER_END@
23 #ifndef RLD
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/mman.h>
33 #include <mach/mach.h>
34 #include <libc.h>
36 #include "stuff/bool.h"
37 #include "stuff/errors.h"
38 #include "stuff/allocate.h"
39 #include "stuff/guess_short_name.h"
40 #include "stuff/seg_addr_table.h"
43 * parse_default_seg_addr_table() simply calls parse_seg_addr_table() with
44 * the default file that contains the segment address table.
46 struct seg_addr_table *
47 parse_default_seg_addr_table(
48 char **seg_addr_table_name,
49 uint32_t *table_size)
51 #ifdef __GONZO_BUNSEN_BEAKER__
52 *seg_addr_table_name = "/Local/Developer/seg_addr_table";
53 #else
54 *seg_addr_table_name = "/AppleInternal/Developer/seg_addr_table";
55 #endif
56 return(parse_seg_addr_table(*seg_addr_table_name,
57 "default", "segment address table", table_size));
61 * parse_seg_addr_table() opens the file_name passed to it and parses it as a
62 * segment address table. The flag and argument parameters are used for
63 * error messages if there is a problem parsing the file. The file should
64 * contains lines of the form:
65 * <hex address> <install name>
66 * or
67 * <hex address> <hex address> <install name>
68 * The first form with one <hex address> specifies the -seg1addr of the
69 * dynamic shared library with the specified <install name>. The second form
70 * specifies the -segs_read_only_addr and the -segs_read_write_addr addresses
71 * of the dynamic shared library. The fields are to be separated by spaces or
72 * tabs. Comment lines starting with a '#' character are ignored as well as
73 * lines with just spaces and tabs. This routine returns the parsed table as an
74 * array of seg_addr_table structs. The last entry in the table has a NULL
75 * install_name. For lines with two addresses the field split will be TRUE
76 * otherwise it will be FALSE.
78 struct seg_addr_table *
79 parse_seg_addr_table(
80 char *file_name,/* file name of the seg_addr_table file */
81 char *flag, /* "-seg_addr_table" or "default" */
82 char *argument, /* -seg_addr_table argument or "segment address table" */
83 uint32_t *table_size)
85 int fd;
86 struct stat stat_buf;
87 uint32_t j, k, file_size, seg_addr_table_size, line;
88 char *file_addr, *endp;
89 struct seg_addr_table *new_seg_addr_table;
91 if((fd = open(file_name, O_RDONLY, 0)) == -1)
92 system_fatal("Can't open: %s for %s %s",
93 file_name, flag, argument);
94 if(fstat(fd, &stat_buf) == -1)
95 system_fatal("Can't stat file: %s for %s %s",
96 file_name, flag, argument);
98 * For some reason mapping files with zero size fails
99 * so it has to be handled specially.
101 file_addr = NULL;
102 if(stat_buf.st_size != 0){
103 file_addr = mmap(0, stat_buf.st_size, PROT_READ|PROT_WRITE,
104 MAP_FILE|MAP_PRIVATE, fd, 0);
105 if((intptr_t)file_addr == -1)
106 system_error("can't map file: %s for %s %s", file_name, flag,
107 argument);
109 else
110 fatal("Empty file: %s for %s %s", file_name, flag, argument);
111 close(fd);
112 file_size = stat_buf.st_size;
115 * Got the file mapped now parse it.
117 if(file_addr[file_size - 1] != '\n')
118 fatal("file: %s for %s %s does not end in new line",
119 file_name, flag, argument);
120 seg_addr_table_size = 0;
121 for(j = 1; j < file_size; j++){
122 if(file_addr[j] == '\n'){
123 seg_addr_table_size++;
126 seg_addr_table_size++;
127 new_seg_addr_table = allocate(sizeof(struct seg_addr_table) *
128 seg_addr_table_size);
129 k = 0;
130 line = 1;
131 for(j = 0; j < file_size; /* no increment expression */ ){
132 /* Skip lines that start with '#' */
133 if(file_addr[j] == '#'){
134 j++;
135 while(file_addr[j] != '\n')
136 j++;
137 continue;
139 /* Skip blank lines */
140 while(file_addr[j] == ' ' || file_addr[j] == '\t')
141 j++;
142 if(file_addr[j] == '\n'){
143 j++;
144 line++;
145 continue;
147 new_seg_addr_table[k].seg1addr =
148 strtoul(file_addr + j, &endp, 16);
149 if(endp == NULL)
150 fatal("improper hexadecimal number on line %u in "
151 "file: %s for %s %s", j, file_name, flag, argument);
152 j = endp - file_addr;
153 if(j == file_size)
154 fatal("missing library install name on line %u in file: "
155 "%s for %s %s", j, file_name, flag, argument);
157 * Since we checked to see the file ends in a '\n' we can
158 * be assured this won't run off the end of the file.
160 while(file_addr[j] == ' ' || file_addr[j] == '\t')
161 j++;
162 if(file_addr[j] == '\n')
163 fatal("missing library install name on line %u in file: "
164 "%s for %s %s", j, file_name, flag, argument);
166 new_seg_addr_table[k].segs_read_write_addr =
167 strtoul(file_addr + j, &endp, 16);
168 if(endp == NULL || endp == file_addr + j){
169 new_seg_addr_table[k].split = FALSE;
170 new_seg_addr_table[k].segs_read_write_addr = UINT_MAX;
172 else{
173 j = endp - file_addr;
174 new_seg_addr_table[k].split = TRUE;
175 new_seg_addr_table[k].segs_read_only_addr =
176 new_seg_addr_table[k].seg1addr;
177 new_seg_addr_table[k].seg1addr = UINT_MAX;
178 while(file_addr[j] == ' ' || file_addr[j] == '\t')
179 j++;
182 new_seg_addr_table[k].install_name = file_addr + j;
183 new_seg_addr_table[k].line = line;
184 k++;
185 while(file_addr[j] != '\n')
186 j++;
187 file_addr[j] = '\0';
188 line++;
189 j++;
192 new_seg_addr_table[k].install_name = NULL;
193 new_seg_addr_table[k].seg1addr = 0;
194 new_seg_addr_table[k].split = FALSE;
195 new_seg_addr_table[k].segs_read_only_addr = UINT_MAX;
196 new_seg_addr_table[k].segs_read_write_addr = UINT_MAX;
197 new_seg_addr_table[k].line = line;
199 *table_size = k;
200 return(new_seg_addr_table);
204 * search_seg_addr_table() searches the specified segment address table for the
205 * specified name and returns the entry to it if it is found. If it is not
206 * found NULL is returned.
208 struct seg_addr_table *
209 search_seg_addr_table(
210 struct seg_addr_table *seg_addr_table,
211 char *install_name)
213 struct seg_addr_table *p;
215 if(seg_addr_table == NULL)
216 return(NULL);
218 for(p = seg_addr_table; p->install_name != NULL; p++){
219 if(strcmp(p->install_name, install_name) == 0)
220 return(p);
222 return(NULL);
226 * process_seg_addr_table() is used to create an new segment address table from
227 * an existing segment address table. It opens and parses "file_name" as a
228 * segment address table. It copies the comment lines that don't start with
229 * "comment_prefix" to "out_fp". For entries in the file it calls the function
230 * processor() pass to it and passes it the parsed entry from the file, the
231 * "out_fp" and the "cookie" passed to process_seg_addr_table().
233 void
234 process_seg_addr_table(
235 char *file_name,
236 FILE *out_fp,
237 char *comment_prefix,
238 void (*processor)(struct seg_addr_table *entry, FILE *out_fp, void *cookie),
239 void *cookie)
241 int fd;
242 struct stat stat_buf;
243 uint32_t i, file_size, line, comment_prefix_length;
244 char *file_addr, *endp;
245 struct seg_addr_table entry;
247 file_addr = NULL;
248 if((fd = open(file_name, O_RDONLY, 0)) == -1)
249 system_fatal("can't open file: %s", file_name);
250 if(fstat(fd, &stat_buf) == -1)
251 system_fatal("can't stat file: %s", file_name);
253 * For some reason mapping files with zero size fails
254 * so it has to be handled specially.
256 if(stat_buf.st_size != 0){
257 file_addr = mmap(0, stat_buf.st_size, PROT_READ|PROT_WRITE,
258 MAP_FILE|MAP_PRIVATE, fd, 0);
259 if((intptr_t)file_addr == -1)
260 system_error("can't map file: %s", file_name);
262 else
263 fatal("empty file: %s ", file_name);
264 close(fd);
265 file_size = stat_buf.st_size;
268 * Got the file mapped now parse and process it.
270 if(file_addr[file_size - 1] != '\n')
271 fatal("file: %s does not end in new line", file_name);
273 line = 1;
274 comment_prefix_length = strlen(comment_prefix);
275 for(i = 0; i < file_size; /* no increment expression */ ){
276 /* Copy comment lines that start with '#' */
277 if(file_addr[i] == '#'){
278 if(strncmp(comment_prefix, file_addr + i + 1,
279 comment_prefix_length) == 0){
280 i++;
281 while(file_addr[i] != '\n')
282 i++;
283 if(file_addr[i] == '\n'){
284 i++;
285 line++;
287 continue;
289 fputc(file_addr[i], out_fp);
290 i++;
291 while(file_addr[i] != '\n'){
292 fputc(file_addr[i], out_fp);
293 i++;
295 continue;
297 /* Copy blank lines */
298 while(file_addr[i] == ' ' || file_addr[i] == '\t'){
299 fputc(file_addr[i], out_fp);
300 i++;
302 if(file_addr[i] == '\n'){
303 fputc(file_addr[i], out_fp);
304 i++;
305 line++;
306 continue;
308 entry.seg1addr = strtoul(file_addr + i, &endp, 16);
309 if(endp == NULL)
310 fatal("improper hexadecimal number on line %u in file: %s",
311 line, file_name);
312 i = endp - file_addr;
313 if(i == file_size)
314 fatal("missing library install name on line %u in file: %s",
315 line, file_name);
317 * Since we checked to see the file ends in a '\n' we can
318 * be assured this won't run off the end of the file.
320 while(file_addr[i] == ' ' || file_addr[i] == '\t')
321 i++;
322 if(file_addr[i] == '\n')
323 fatal("missing library install name on line %u in file: %s",
324 line, file_name);
326 entry.segs_read_write_addr = strtoul(file_addr + i, &endp, 16);
327 if(endp == NULL || endp == file_addr + i){
328 entry.split = FALSE;
329 entry.segs_read_write_addr = UINT_MAX;
331 else{
332 i = endp - file_addr;
333 entry.split = TRUE;
334 entry.segs_read_only_addr = entry.seg1addr;
335 entry.seg1addr = UINT_MAX;
336 while(file_addr[i] == ' ' || file_addr[i] == '\t')
337 i++;
340 entry.install_name = file_addr + i;
341 entry.line = line;
342 while(file_addr[i] != '\n')
343 i++;
344 file_addr[i] = '\0';
346 processor(&entry, out_fp, cookie);
348 line++;
349 i++;
352 #endif /* !defined(RLD) */