]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_symfile.c
xnu-124.7.tar.gz
[apple/xnu.git] / bsd / kern / kern_symfile.c
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