2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
27 * File: bsd/kern/kern_symfile.c
29 * This file contains creates a dummy symbol file for mach_kernel based on
30 * the symbol table information passed by the SecondaryLoader/PlatformExpert.
31 * This allows us to correctly link other executables (drivers, etc) against the
32 * the kernel in cases where the kernel image on the root device does not match
33 * the live kernel. This can occur during net-booting where the actual kernel
34 * image is obtained from the network via tftp rather than the root
37 * If a symbol table is available, then the file /mach.sym will be created
38 * containing a Mach Header and a LC_SYMTAB load command followed by the
39 * the symbol table data for mach_kernel.
46 #include <mach/vm_param.h>
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/signalvar.h>
51 #include <sys/resourcevar.h>
52 #include <sys/namei.h>
53 #include <sys/vnode.h>
55 #include <sys/timeb.h>
56 #include <sys/times.h>
61 #include <sys/kernel.h>
64 #include <mach-o/loader.h>
65 #include <mach-o/nlist.h>
67 #include <vm/vm_kern.h>
69 extern unsigned char rootdevice
[];
70 extern struct mach_header _mh_execute_header
;
72 static int kernel_symfile_opened
= 0;
73 static int error_code
= 0;
75 extern int IODTGetLoaderInfo(char *key
, void **infoAddr
, int *infoSize
);
76 extern void IODTFreeLoaderInfo(char *key
, void *infoAddr
, int infoSize
);
81 static int output_kernel_symbols(struct proc
*p
)
84 struct pcred
*pcred
= p
->p_cred
;
85 struct ucred
*cred
= pcred
->pc_ucred
;
88 struct load_command
*cmd
;
89 struct mach_header
*orig_mh
, *mh
;
90 struct segment_command
*orig_ds
, *orig_ts
, *orig_le
, *sg
;
91 struct section
*se
, *const_text
;
92 struct symtab_command
*st
, *orig_st
;
94 vm_size_t orig_mhsize
, orig_st_size
;
96 vm_size_t header_size
;
110 // Dispose of unnecessary gumf, the booter doesn't need to load these
111 rc_mh
= IODTGetLoaderInfo("Kernel-__HEADER",
112 (void **)&orig_mh
, &orig_mhsize
);
113 if (rc_mh
&& orig_mh
)
114 IODTFreeLoaderInfo("Kernel-__HEADER",
115 (void *)orig_mh
, round_page_32(orig_mhsize
));
117 rc_sc
= IODTGetLoaderInfo("Kernel-__SYMTAB",
118 (void **) &orig_st
, &orig_st_size
);
119 if (rc_sc
&& orig_st
)
120 IODTFreeLoaderInfo("Kernel-__SYMTAB",
121 (void *)orig_st
, round_page_32(orig_st_size
));
123 if (pcred
->p_svuid
!= pcred
->p_ruid
|| pcred
->p_svgid
!= pcred
->p_rgid
)
126 // Check to see if the root is 'e' or 'n', is this a test for network?
127 if (rootdevice
[0] == 'e' && rootdevice
[1] == 'n')
130 NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, "mach.sym", p
);
131 if((error
= vn_open(&nd
, O_CREAT
| FWRITE
, S_IRUSR
| S_IRGRP
| S_IROTH
))) goto out
;
135 /* Don't dump to non-regular files or files with links. */
137 if (vp
->v_type
!= VREG
|| VOP_GETATTR(vp
, &vattr
, cred
, p
)
138 || vattr
.va_nlink
!= 1)
143 VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
);
144 VOP_SETATTR(vp
, &vattr
, cred
, p
);
145 p
->p_acflag
|= ACORE
;
147 // If the file type is MH_EXECUTE then this must be a kernel
148 // as all Kernel extensions must be of type MH_OBJECT
149 orig_ds
= orig_ts
= orig_le
= NULL
;
151 orig_mh
= &_mh_execute_header
;
152 cmd
= (struct load_command
*) &orig_mh
[1];
153 for (i
= 0; i
< orig_mh
->ncmds
; i
++) {
154 if (cmd
->cmd
== LC_SEGMENT
) {
155 struct segment_command
*sg
= (struct segment_command
*) cmd
;
157 if (!strcmp(SEG_TEXT
, sg
->segname
))
159 else if (!strcmp(SEG_DATA
, sg
->segname
))
161 else if (!strcmp(SEG_LINKEDIT
, sg
->segname
))
164 else if (cmd
->cmd
== LC_SYMTAB
)
165 orig_st
= (struct symtab_command
*) cmd
;
167 cmd
= (struct load_command
*) ((caddr_t
) cmd
+ cmd
->cmdsize
);
170 if (!orig_ts
|| !orig_ds
|| !orig_le
|| !orig_st
)
174 se
= (struct section
*) &orig_ts
[1];
175 for (i
= 0; i
< orig_ts
->nsects
; i
++, se
++) {
176 if (!strcmp("__const", se
->sectname
)) {
184 header_size
= sizeof(struct mach_header
)
187 + sizeof(struct symtab_command
);
189 (void) kmem_alloc_wired(kernel_map
,
190 (vm_offset_t
*) &header
,
191 (vm_size_t
) header_size
);
193 bzero((void *) header
, header_size
);
198 * Set up Mach-O header.
200 mh
= (struct mach_header
*) header
;
201 mh
->magic
= orig_mh
->magic
;
202 mh
->cputype
= orig_mh
->cputype
;
203 mh
->cpusubtype
= orig_mh
->cpusubtype
;
204 mh
->filetype
= orig_mh
->filetype
;
206 mh
->sizeofcmds
= header_size
- sizeof(struct mach_header
);
207 mh
->flags
= orig_mh
->flags
;
209 // Initialise the current file offset and addr
210 offset
= round_page_32(header_size
);
211 addr
= (caddr_t
) const_text
->addr
; // Load address of __TEXT,__const
214 * Construct a TEXT segment load command
215 * the only part of the TEXT segment we keep is the __TEXT,__const
216 * which contains the kernel vtables.
218 sg
= (struct segment_command
*) &mh
[1];
219 bcopy(orig_ts
, sg
, orig_ts
->cmdsize
);
220 sg
->vmaddr
= (unsigned long) addr
;
221 sg
->vmsize
= const_text
->size
;
223 sg
->filesize
= const_text
->size
+ round_page_32(header_size
);
227 se
= (struct section
*)(sg
+1);
228 for ( j
= 0; j
< sg
->nsects
; j
++, se
++ ) {
229 se
->addr
= (unsigned long) addr
;
233 if (!strcmp("__const", se
->sectname
)) {
234 se
->size
= const_text
->size
;
235 addr
+= const_text
->size
;
236 offset
+= const_text
->size
;
240 offset
= round_page_32((vm_address_t
) offset
);
242 // Now copy of the __DATA segment load command, the image need
243 // not be stored to disk nobody needs it, yet!
244 sg
= (struct segment_command
*)((int)sg
+ sg
->cmdsize
);
245 bcopy(orig_ds
, sg
, orig_ds
->cmdsize
);
247 sg
->vmaddr
= (unsigned long) addr
;
248 sg
->vmsize
= 0x1000; // One page for some reason?
249 sg
->fileoff
= offset
;
254 se
= (struct section
*)(sg
+1);
255 for ( j
= 0; j
< sg
->nsects
; j
++, se
++ ) {
256 se
->addr
= (unsigned long) addr
;
261 offset
= round_page_32(offset
);
265 * Set up LC_SYMTAB command
267 st
= (struct symtab_command
*)((int)sg
+ sg
->cmdsize
);
269 st
->cmdsize
= sizeof(struct symtab_command
);
271 st
->nsyms
= orig_st
->nsyms
;
272 st
->strsize
= orig_st
->strsize
;
273 st
->stroff
= offset
+ st
->nsyms
* sizeof(struct nlist
);
276 * Convert the symbol table in place from section references
277 * to absolute references.
279 sym
= (struct nlist
*) orig_le
->vmaddr
;
280 for (i
= 0; i
< st
->nsyms
; i
++, sym
++ ) {
281 if ( (sym
->n_type
& N_TYPE
) == N_SECT
) {
282 sym
->n_sect
= NO_SECT
;
283 sym
->n_type
= (sym
->n_type
& ~N_TYPE
) | N_ABS
;
288 * Write out the load commands at the beginning of the file.
290 error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
) mh
, header_size
, (off_t
) 0,
291 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
296 * Write out the __TEXT,__const data segment.
298 error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
) const_text
->addr
,
299 const_text
->size
, const_text
->offset
,
300 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
305 * Write out kernel symbols
307 offset
= st
->nsyms
* sizeof(struct nlist
) + st
->strsize
; // symtab size
308 error
= vn_rdwr(UIO_WRITE
, vp
,
309 (caddr_t
) orig_le
->vmaddr
, offset
, st
->symoff
,
310 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
);
316 kmem_free(kernel_map
, header
, header_size
);
319 VOP_UNLOCK(vp
, 0, p
);
320 error1
= vn_close(vp
, FWRITE
, cred
, p
);
321 if (!error
) error
= error1
;
329 int get_kernel_symfile(struct proc
*p
, char **symfile
)
331 if (!kernel_symfile_opened
) {
332 kernel_symfile_opened
= 1;
333 error_code
= output_kernel_symbols(p
);
336 *symfile
= "\\mach.sym";