2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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@
30 #include <sys/types.h>
33 #include <mach/mach.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
,
51 #ifdef __GONZO_BUNSEN_BEAKER__
52 *seg_addr_table_name
= "/Local/Developer/seg_addr_table";
54 *seg_addr_table_name
= "/AppleInternal/Developer/seg_addr_table";
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>
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
*
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" */
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.
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
,
110 fatal("Empty file: %s for %s %s", file_name
, flag
, argument
);
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
);
131 for(j
= 0; j
< file_size
; /* no increment expression */ ){
132 /* Skip lines that start with '#' */
133 if(file_addr
[j
] == '#'){
135 while(file_addr
[j
] != '\n')
139 /* Skip blank lines */
140 while(file_addr
[j
] == ' ' || file_addr
[j
] == '\t')
142 if(file_addr
[j
] == '\n'){
147 new_seg_addr_table
[k
].seg1addr
=
148 strtoul(file_addr
+ j
, &endp
, 16);
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
;
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')
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
;
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')
182 new_seg_addr_table
[k
].install_name
= file_addr
+ j
;
183 new_seg_addr_table
[k
].line
= line
;
185 while(file_addr
[j
] != '\n')
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
;
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
,
213 struct seg_addr_table
*p
;
215 if(seg_addr_table
== NULL
)
218 for(p
= seg_addr_table
; p
->install_name
!= NULL
; p
++){
219 if(strcmp(p
->install_name
, install_name
) == 0)
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().
234 process_seg_addr_table(
237 char *comment_prefix
,
238 void (*processor
)(struct seg_addr_table
*entry
, FILE *out_fp
, void *cookie
),
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
;
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
);
263 fatal("empty file: %s ", file_name
);
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
);
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){
281 while(file_addr
[i
] != '\n')
283 if(file_addr
[i
] == '\n'){
289 fputc(file_addr
[i
], out_fp
);
291 while(file_addr
[i
] != '\n'){
292 fputc(file_addr
[i
], out_fp
);
297 /* Copy blank lines */
298 while(file_addr
[i
] == ' ' || file_addr
[i
] == '\t'){
299 fputc(file_addr
[i
], out_fp
);
302 if(file_addr
[i
] == '\n'){
303 fputc(file_addr
[i
], out_fp
);
308 entry
.seg1addr
= strtoul(file_addr
+ i
, &endp
, 16);
310 fatal("improper hexadecimal number on line %u in file: %s",
312 i
= endp
- file_addr
;
314 fatal("missing library install name on line %u in file: %s",
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')
322 if(file_addr
[i
] == '\n')
323 fatal("missing library install name on line %u in file: %s",
326 entry
.segs_read_write_addr
= strtoul(file_addr
+ i
, &endp
, 16);
327 if(endp
== NULL
|| endp
== file_addr
+ i
){
329 entry
.segs_read_write_addr
= UINT_MAX
;
332 i
= endp
- file_addr
;
334 entry
.segs_read_only_addr
= entry
.seg1addr
;
335 entry
.seg1addr
= UINT_MAX
;
336 while(file_addr
[i
] == ' ' || file_addr
[i
] == '\t')
340 entry
.install_name
= file_addr
+ i
;
342 while(file_addr
[i
] != '\n')
346 processor(&entry
, out_fp
, cookie
);
352 #endif /* !defined(RLD) */