2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
24 * File: bsd/kern/kern_symfile.c
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
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.
43 #include <mach/vm_param.h>
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>
52 #include <sys/timeb.h>
53 #include <sys/times.h>
58 #include <sys/kernel.h>
61 #include <mach-o/loader.h>
62 #include <mach-o/nlist.h>
64 #include <vm/vm_kern.h>
66 extern unsigned char rootdevice
[];
67 extern struct mach_header _mh_execute_header
;
69 static int kernel_symfile_opened
= 0;
70 static int error_code
= 0;
72 extern int IODTGetLoaderInfo(char *key
, void **infoAddr
, int *infoSize
);
73 extern void IODTFreeLoaderInfo(char *key
, void *infoAddr
, int infoSize
);
78 static int output_kernel_symbols(struct proc
*p
)
81 struct pcred
*pcred
= p
->p_cred
;
82 struct ucred
*cred
= pcred
->pc_ucred
;
85 struct load_command
*cmd
;
86 struct mach_header
*orig_mh
, *mh
;
87 struct segment_command
*orig_ds
, *orig_ts
, *orig_le
, *sg
;
88 struct section
*se
, *const_text
;
89 struct symtab_command
*st
, *orig_st
;
91 vm_size_t orig_mhsize
, orig_st_size
;
93 vm_size_t header_size
;
107 // Dispose of unnecessary gumf, the booter doesn't need to load these
108 rc_mh
= IODTGetLoaderInfo("Kernel-__HEADER",
109 (void **)&orig_mh
, &orig_mhsize
);
110 if (rc_mh
&& orig_mh
)
111 IODTFreeLoaderInfo("Kernel-__HEADER",
112 (void *)orig_mh
, round_page(orig_mhsize
));
114 rc_sc
= IODTGetLoaderInfo("Kernel-__SYMTAB",
115 (void **) &orig_st
, &orig_st_size
);
116 if (rc_sc
&& orig_st
)
117 IODTFreeLoaderInfo("Kernel-__SYMTAB",
118 (void *)orig_st
, round_page(orig_st_size
));
120 if (pcred
->p_svuid
!= pcred
->p_ruid
|| pcred
->p_svgid
!= pcred
->p_rgid
)
123 // Check to see if the root is 'e' or 'n', is this a test for network?
124 if (rootdevice
[0] == 'e' && rootdevice
[1] == 'n')
127 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, "mach.sym", p
);
128 if((error
= vn_open(&nd
, O_CREAT
| FWRITE
, S_IRUSR
| S_IRGRP
| S_IROTH
))) goto out
;
132 /* Don't dump to non-regular files or files with links. */
134 if (vp
->v_type
!= VREG
|| VOP_GETATTR(vp
, &vattr
, cred
, p
)
135 || vattr
.va_nlink
!= 1)
140 VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
);
141 VOP_SETATTR(vp
, &vattr
, cred
, p
);
142 p
->p_acflag
|= ACORE
;
144 // If the file type is MH_EXECUTE then this must be a kernel
145 // as all Kernel extensions must be of type MH_OBJECT
146 orig_ds
= orig_ts
= orig_le
= NULL
;
148 orig_mh
= &_mh_execute_header
;
149 cmd
= (struct load_command
*) &orig_mh
[1];
150 for (i
= 0; i
< orig_mh
->ncmds
; i
++) {
151 if (cmd
->cmd
== LC_SEGMENT
) {
152 struct segment_command
*sg
= (struct segment_command
*) cmd
;
154 if (!strcmp(SEG_TEXT
, sg
->segname
))
156 else if (!strcmp(SEG_DATA
, sg
->segname
))
158 else if (!strcmp(SEG_LINKEDIT
, sg
->segname
))
161 else if (cmd
->cmd
== LC_SYMTAB
)
162 orig_st
= (struct symtab_command
*) cmd
;
164 cmd
= (struct load_command
*) ((caddr_t
) cmd
+ cmd
->cmdsize
);
167 if (!orig_ts
|| !orig_ds
|| !orig_le
|| !orig_st
)
171 se
= (struct section
*) &orig_ts
[1];
172 for (i
= 0; i
< orig_ts
->nsects
; i
++, se
++) {
173 if (!strcmp("__const", se
->sectname
)) {
181 header_size
= sizeof(struct mach_header
)
184 + sizeof(struct symtab_command
);
186 (void) kmem_alloc_wired(kernel_map
,
187 (vm_offset_t
*) &header
,
188 (vm_size_t
) header_size
);
190 bzero((void *) header
, header_size
);
195 * Set up Mach-O header.
197 mh
= (struct mach_header
*) header
;
198 mh
->magic
= orig_mh
->magic
;
199 mh
->cputype
= orig_mh
->cputype
;
200 mh
->cpusubtype
= orig_mh
->cpusubtype
;
201 mh
->filetype
= orig_mh
->filetype
;
203 mh
->sizeofcmds
= header_size
- sizeof(struct mach_header
);
204 mh
->flags
= orig_mh
->flags
;
206 // Initialise the current file offset and addr
207 offset
= round_page(header_size
);
208 addr
= (caddr_t
) const_text
->addr
; // Load address of __TEXT,__const
211 * Construct a TEXT segment load command
212 * the only part of the TEXT segment we keep is the __TEXT,__const
213 * which contains the kernel vtables.
215 sg
= (struct segment_command
*) &mh
[1];
216 bcopy(orig_ts
, sg
, orig_ts
->cmdsize
);
217 sg
->vmaddr
= (unsigned long) addr
;
218 sg
->vmsize
= const_text
->size
;
220 sg
->filesize
= const_text
->size
+ round_page(header_size
);
224 se
= (struct section
*)(sg
+1);
225 for ( j
= 0; j
< sg
->nsects
; j
++, se
++ ) {
226 se
->addr
= (unsigned long) addr
;
230 if (!strcmp("__const", se
->sectname
)) {
231 se
->size
= const_text
->size
;
232 addr
+= const_text
->size
;
233 offset
+= const_text
->size
;
237 offset
= round_page((vm_address_t
) offset
);
239 // Now copy of the __DATA segment load command, the image need
240 // not be stored to disk nobody needs it, yet!
241 sg
= (struct segment_command
*)((int)sg
+ sg
->cmdsize
);
242 bcopy(orig_ds
, sg
, orig_ds
->cmdsize
);
244 sg
->vmaddr
= (unsigned long) addr
;
245 sg
->vmsize
= 0x1000; // One page for some reason?
246 sg
->fileoff
= offset
;
251 se
= (struct section
*)(sg
+1);
252 for ( j
= 0; j
< sg
->nsects
; j
++, se
++ ) {
253 se
->addr
= (unsigned long) addr
;
258 offset
= round_page(offset
);
262 * Set up LC_SYMTAB command
264 st
= (struct symtab_command
*)((int)sg
+ sg
->cmdsize
);
266 st
->cmdsize
= sizeof(struct symtab_command
);
268 st
->nsyms
= orig_st
->nsyms
;
269 st
->strsize
= orig_st
->strsize
;
270 st
->stroff
= offset
+ st
->nsyms
* sizeof(struct nlist
);
273 * Convert the symbol table in place from section references
274 * to absolute references.
276 sym
= (struct nlist
*) orig_le
->vmaddr
;
277 for (i
= 0; i
< st
->nsyms
; i
++, sym
++ ) {
278 if ( (sym
->n_type
& N_TYPE
) == N_SECT
) {
279 sym
->n_sect
= NO_SECT
;
280 sym
->n_type
= (sym
->n_type
& ~N_TYPE
) | N_ABS
;
285 * Write out the load commands at the beginning of the file.
287 error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
) mh
, header_size
, (off_t
) 0,
288 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
293 * Write out the __TEXT,__const data segment.
295 error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
) const_text
->addr
,
296 const_text
->size
, const_text
->offset
,
297 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
302 * Write out kernel symbols
304 offset
= st
->nsyms
* sizeof(struct nlist
) + st
->strsize
; // symtab size
305 error
= vn_rdwr(UIO_WRITE
, vp
,
306 (caddr_t
) orig_le
->vmaddr
, offset
, st
->symoff
,
307 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
313 kmem_free(kernel_map
, header
, header_size
);
316 VOP_UNLOCK(vp
, 0, p
);
317 error1
= vn_close(vp
, FWRITE
, cred
, p
);
318 if (!error
) error
= error1
;
326 int get_kernel_symfile(struct proc
*p
, char **symfile
)
328 if (!kernel_symfile_opened
) {
329 kernel_symfile_opened
= 1;
330 error_code
= output_kernel_symbols(p
);
333 *symfile
= "\\mach.sym";