]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved. | |
23 | * | |
24 | * File: bsd/kern/kern_symfile.c | |
25 | * | |
26 | * This file contains creates a dummy symbol file for mach_kernel based on | |
27 | * the symbol table information passed by the SecondaryLoader/PlatformExpert. | |
28 | * This allows us to correctly link other executables (drivers, etc) against the | |
29 | * the kernel in cases where the kernel image on the root device does not match | |
30 | * the live kernel. This can occur during net-booting where the actual kernel | |
31 | * image is obtained from the network via tftp rather than the root | |
32 | * device. | |
33 | * | |
34 | * If a symbol table is available, then the file /mach.sym will be created | |
35 | * containing a Mach Header and a LC_SYMTAB load command followed by the | |
36 | * the symbol table data for mach_kernel. | |
37 | * | |
38 | * HISTORY | |
39 | * | |
40 | * . | |
41 | */ | |
42 | ||
43 | #include <mach/vm_param.h> | |
44 | ||
45 | #include <sys/param.h> | |
46 | #include <sys/systm.h> | |
47 | #include <sys/signalvar.h> | |
48 | #include <sys/resourcevar.h> | |
49 | #include <sys/namei.h> | |
50 | #include <sys/vnode.h> | |
51 | #include <sys/proc.h> | |
52 | #include <sys/timeb.h> | |
53 | #include <sys/times.h> | |
54 | #include <sys/buf.h> | |
55 | #include <sys/acct.h> | |
56 | #include <sys/file.h> | |
57 | #include <sys/uio.h> | |
58 | #include <sys/kernel.h> | |
59 | #include <sys/stat.h> | |
60 | ||
61 | #include <mach-o/loader.h> | |
62 | #include <mach-o/nlist.h> | |
63 | ||
64 | #include <vm/vm_kern.h> | |
65 | ||
66 | extern unsigned char rootdevice[]; | |
67 | extern vm_size_t page_size; | |
68 | ||
69 | ||
70 | int kernel_symfile_opened = 0; | |
71 | int error_code = 0; | |
72 | ||
73 | extern int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize ); | |
74 | extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize ); | |
75 | ||
76 | struct segment_command *findSegmentByName( struct mach_header *mh, const char *section_name ); | |
77 | ||
78 | /* | |
79 | * | |
80 | */ | |
81 | int get_kernel_symfile( struct proc *p, char **symfile ) | |
82 | { | |
83 | if ( kernel_symfile_opened == 0 ) | |
84 | { | |
85 | kernel_symfile_opened = 1; | |
86 | error_code = output_kernel_symbols( p ); | |
87 | } | |
88 | if ( error_code == 0 ) *symfile = "\\mach.sym"; | |
89 | ||
90 | return error_code; | |
91 | } | |
92 | ||
93 | /* | |
94 | * | |
95 | */ | |
96 | int output_kernel_symbols( register struct proc *p ) | |
97 | { | |
98 | register struct vnode *vp; | |
99 | register struct pcred *pcred = p->p_cred; | |
100 | register struct ucred *cred = pcred->pc_ucred; | |
101 | struct nameidata nd; | |
102 | struct vattr vattr; | |
103 | struct mach_header *orig_mh, *mh; | |
104 | struct load_command *lc; | |
105 | struct segment_command *orig_ds, *orig_ts, *sg; | |
106 | struct section *se; | |
107 | struct symtab_command *sc, *sc0; | |
108 | struct nlist *nl; | |
109 | vm_size_t orig_mhsize, sc0_size; | |
110 | vm_offset_t header; | |
111 | vm_size_t header_size; | |
112 | int error, error1; | |
113 | int i, j; | |
114 | int symfoffset, symsize; | |
115 | int rc_mh, rc_sc; | |
116 | ||
117 | error = EFAULT; | |
118 | ||
119 | vp = NULL; | |
120 | header = NULL; | |
121 | orig_mh = NULL; | |
122 | sc0 = NULL; | |
123 | ||
124 | rc_mh = IODTGetLoaderInfo( "Kernel-__HEADER", (void **)&orig_mh, &orig_mhsize ); | |
125 | rc_sc = IODTGetLoaderInfo( "Kernel-__SYMTAB", (void **)&sc0, &sc0_size ); | |
126 | ||
127 | if ( rc_mh != 0 || orig_mh == 0 || orig_mhsize < sizeof(struct mach_header) ) goto out; | |
128 | if ( rc_sc != 0 || sc0 == 0 || sc0_size < sizeof(struct symtab_command) ) goto out; | |
129 | ||
130 | if ( pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid ) goto out; | |
131 | ||
132 | if ( rootdevice[0] == 'e' && rootdevice[1] == 'n' ) goto out; | |
133 | ||
134 | NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "mach.sym", p); | |
135 | if( (error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IRGRP | S_IROTH )) != 0 ) goto out; | |
136 | ||
137 | vp = nd.ni_vp; | |
138 | ||
139 | /* Don't dump to non-regular files or files with links. */ | |
140 | error = EFAULT; | |
141 | if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) goto out; | |
142 | ||
143 | VATTR_NULL(&vattr); | |
144 | vattr.va_size = 0; | |
145 | VOP_LEASE(vp, p, cred, LEASE_WRITE); | |
146 | VOP_SETATTR(vp, &vattr, cred, p); | |
147 | p->p_acflag |= ACORE; | |
148 | ||
149 | orig_ts = findSegmentByName(orig_mh, "__TEXT"); | |
150 | orig_ds = findSegmentByName(orig_mh, "__DATA"); | |
151 | ||
152 | if ( orig_ts == NULL || orig_ds == NULL ) goto out; | |
153 | ||
154 | header_size = sizeof(struct mach_header) | |
155 | + orig_ts->cmdsize | |
156 | + orig_ds->cmdsize | |
157 | + sizeof(struct symtab_command); | |
158 | ||
159 | (void) kmem_alloc_wired( kernel_map, | |
160 | (vm_offset_t *)&header, | |
161 | (vm_size_t)header_size); | |
162 | ||
163 | if ( header == NULL ) goto out; | |
164 | ||
165 | bzero( (void *)header, header_size ); | |
166 | ||
167 | /* | |
168 | * Set up Mach-O header. | |
169 | */ | |
170 | mh = (struct mach_header *) header; | |
171 | mh->magic = orig_mh->magic; | |
172 | mh->cputype = orig_mh->cputype; | |
173 | mh->cpusubtype = orig_mh->cpusubtype; | |
174 | mh->filetype = orig_mh->filetype; | |
175 | mh->ncmds = 3; | |
176 | mh->sizeofcmds = header_size - sizeof(struct mach_header); | |
177 | ||
178 | /* | |
179 | * Copy __DATA and __TEXT segment commands from mach_kernel so loadable drivers | |
180 | * get correct section alignment hints. | |
181 | */ | |
182 | sg = (struct segment_command *)(mh+1); | |
183 | bcopy( orig_ts, sg, orig_ts->cmdsize ); | |
184 | ||
185 | sg = (struct segment_command *)((int)sg + sg->cmdsize); | |
186 | bcopy( orig_ds, sg, orig_ds->cmdsize ); | |
187 | ||
188 | sg = (struct segment_command *)(mh+1); | |
189 | ||
190 | for ( i = 0; i < 2; i++ ) | |
191 | { | |
192 | sg->vmaddr = 0; | |
193 | sg->vmsize = 0x1000; | |
194 | sg->fileoff = 0; | |
195 | sg->filesize = 0; | |
196 | sg->maxprot = 0; | |
197 | sg->initprot = 0; | |
198 | sg->flags = 0; | |
199 | ||
200 | se = (struct section *)(sg+1); | |
201 | for ( j = 0; j < sg->nsects; j++, se++ ) | |
202 | { | |
203 | se->addr = 0; | |
204 | se->size = 0; | |
205 | se->offset = 0; | |
206 | se->nreloc = 0; | |
207 | } | |
208 | ||
209 | sg = (struct segment_command *)((int)sg + sg->cmdsize); | |
210 | } | |
211 | ||
212 | symfoffset = round_page(header_size); | |
213 | ||
214 | /* | |
215 | * Set up LC_SYMTAB command | |
216 | */ | |
217 | sc = (struct symtab_command *)sg; | |
218 | sc->cmd = LC_SYMTAB; | |
219 | sc->cmdsize = sizeof(struct symtab_command); | |
220 | sc->symoff = symfoffset; | |
221 | sc->nsyms = sc0->nsyms; | |
222 | sc->strsize = sc0->strsize; | |
223 | sc->stroff = symfoffset + sc->nsyms * sizeof(struct nlist); | |
224 | ||
225 | symsize = sc->nsyms * sizeof(struct nlist) + sc->strsize; | |
226 | ||
227 | nl = (struct nlist *)(sc0+1); | |
228 | for (i = 0; i < sc->nsyms; i++, nl++ ) | |
229 | { | |
230 | if ( (nl->n_type & N_TYPE) == N_SECT ) | |
231 | { | |
232 | nl->n_sect = NO_SECT; | |
233 | nl->n_type = (nl->n_type & ~N_TYPE) | N_ABS; | |
234 | } | |
235 | } | |
236 | ||
237 | /* | |
238 | * Write out the load commands at the beginning of the | |
239 | * file. | |
240 | */ | |
241 | error = vn_rdwr(UIO_WRITE, vp, (caddr_t)mh, header_size, (off_t)0, | |
242 | UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); | |
243 | if ( error != 0 ) goto out; | |
244 | ||
245 | /* | |
246 | * Write out kernel symbols | |
247 | */ | |
248 | error = vn_rdwr(UIO_WRITE, vp, (caddr_t)(sc0+1), symsize, symfoffset, | |
249 | UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); | |
250 | if ( error != 0 ) goto out; | |
251 | ||
252 | out: | |
253 | if ( header != 0 ) kmem_free(kernel_map, header, header_size); | |
254 | if ( orig_mh != 0 ) IODTFreeLoaderInfo( "Kernel-__HEADER", (void *)orig_mh, round_page(orig_mhsize) ); | |
255 | if ( sc0 != 0 ) IODTFreeLoaderInfo( "Kernel-__SYMTAB", (void *)sc0, round_page(sc0_size) ); | |
256 | ||
257 | if ( vp != 0 ) | |
258 | { | |
259 | VOP_UNLOCK(vp, 0, p); | |
260 | error1 = vn_close(vp, FWRITE, cred, p); | |
261 | if (error == 0) error = error1; | |
262 | } | |
263 | ||
264 | return(error); | |
265 | } | |
266 | ||
267 | /* | |
268 | * | |
269 | */ | |
270 | struct segment_command *findSegmentByName( struct mach_header *mh, const char *section_name ) | |
271 | { | |
272 | struct segment_command *sg; | |
273 | int i; | |
274 | ||
275 | sg = (struct segment_command *)(mh+1); | |
276 | ||
277 | for ( i=0; i < mh->ncmds; i++ ) | |
278 | { | |
279 | if ( (sg->cmd == LC_SEGMENT) && (strcmp(sg->segname, section_name) == 0) ) | |
280 | { | |
281 | return sg; | |
282 | } | |
283 | ||
284 | sg = (struct segment_command *)((int)sg + sg->cmdsize); | |
285 | } | |
286 | ||
287 | return NULL; | |
288 | } | |
289 | ||
290 | ||
291 | ||
292 | ||
293 |