X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..5eebf7385fedb1517b66b53c28e5aa6bb0a2be50:/bsd/kern/kern_symfile.c diff --git a/bsd/kern/kern_symfile.c b/bsd/kern/kern_symfile.c index d90edce20..9091fca23 100644 --- a/bsd/kern/kern_symfile.c +++ b/bsd/kern/kern_symfile.c @@ -64,230 +64,273 @@ #include extern unsigned char rootdevice[]; -extern vm_size_t page_size; +extern struct mach_header _mh_execute_header; +static int kernel_symfile_opened = 0; +static int error_code = 0; -int kernel_symfile_opened = 0; -int error_code = 0; - -extern int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize ); -extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize ); - -struct segment_command *findSegmentByName( struct mach_header *mh, const char *section_name ); +extern int IODTGetLoaderInfo(char *key, void **infoAddr, int *infoSize); +extern void IODTFreeLoaderInfo(char *key, void *infoAddr, int infoSize); /* * */ -int get_kernel_symfile( struct proc *p, char **symfile ) +static int output_kernel_symbols(struct proc *p) { - if ( kernel_symfile_opened == 0 ) - { - kernel_symfile_opened = 1; - error_code = output_kernel_symbols( p ); + struct vnode *vp; + struct pcred *pcred = p->p_cred; + struct ucred *cred = pcred->pc_ucred; + struct nameidata nd; + struct vattr vattr; + struct load_command *cmd; + struct mach_header *orig_mh, *mh; + struct segment_command *orig_ds, *orig_ts, *orig_le, *sg; + struct section *se, *const_text; + struct symtab_command *st, *orig_st; + struct nlist *sym; + vm_size_t orig_mhsize, orig_st_size; + vm_offset_t header; + vm_size_t header_size; + int error, error1; + int i, j; + caddr_t addr; + vm_offset_t offset; + int rc_mh, rc_sc; + + error = EFAULT; + + vp = NULL; + header = NULL; + orig_mh = NULL; + orig_st = NULL; + + // Dispose of unnecessary gumf, the booter doesn't need to load these + rc_mh = IODTGetLoaderInfo("Kernel-__HEADER", + (void **)&orig_mh, &orig_mhsize); + if (rc_mh == 0 && orig_mh) + IODTFreeLoaderInfo("Kernel-__HEADER", + (void *)orig_mh, round_page_32(orig_mhsize)); + + rc_sc = IODTGetLoaderInfo("Kernel-__SYMTAB", + (void **) &orig_st, &orig_st_size); + if (rc_sc == 0 && orig_st) + IODTFreeLoaderInfo("Kernel-__SYMTAB", + (void *)orig_st, round_page_32(orig_st_size)); + + if (pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid) + goto out; + + // Check to see if the root is 'e' or 'n', is this a test for network? + if (rootdevice[0] == 'e' && rootdevice[1] == 'n') + goto out; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "mach.sym", p); + if((error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IRGRP | S_IROTH))) goto out; + + vp = nd.ni_vp; + + /* Don't dump to non-regular files or files with links. */ + error = EFAULT; + if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred, p) + || vattr.va_nlink != 1) + goto out; + + VATTR_NULL(&vattr); + vattr.va_size = 0; + VOP_LEASE(vp, p, cred, LEASE_WRITE); + VOP_SETATTR(vp, &vattr, cred, p); + p->p_acflag |= ACORE; + + // If the file type is MH_EXECUTE then this must be a kernel + // as all Kernel extensions must be of type MH_OBJECT + orig_ds = orig_ts = orig_le = NULL; + orig_st = NULL; + orig_mh = &_mh_execute_header; + cmd = (struct load_command *) &orig_mh[1]; + for (i = 0; i < orig_mh->ncmds; i++) { + if (cmd->cmd == LC_SEGMENT) { + struct segment_command *sg = (struct segment_command *) cmd; + + if (!strcmp(SEG_TEXT, sg->segname)) + orig_ts = sg; + else if (!strcmp(SEG_DATA, sg->segname)) + orig_ds = sg; + else if (!strcmp(SEG_LINKEDIT, sg->segname)) + orig_le = sg; + } + else if (cmd->cmd == LC_SYMTAB) + orig_st = (struct symtab_command *) cmd; + + cmd = (struct load_command *) ((caddr_t) cmd + cmd->cmdsize); } - if ( error_code == 0 ) *symfile = "\\mach.sym"; - return error_code; -} + if (!orig_ts || !orig_ds || !orig_le || !orig_st) + goto out; -/* - * - */ -int output_kernel_symbols( register struct proc *p ) -{ - register struct vnode *vp; - register struct pcred *pcred = p->p_cred; - register struct ucred *cred = pcred->pc_ucred; - struct nameidata nd; - struct vattr vattr; - struct mach_header *orig_mh, *mh; - struct load_command *lc; - struct segment_command *orig_ds, *orig_ts, *sg; - struct section *se; - struct symtab_command *sc, *sc0; - struct nlist *nl; - vm_size_t orig_mhsize, sc0_size; - vm_offset_t header; - vm_size_t header_size; - int error, error1; - int i, j; - int symfoffset, symsize; - int rc_mh, rc_sc; - - error = EFAULT; - - vp = NULL; - header = NULL; - orig_mh = NULL; - sc0 = NULL; - - rc_mh = IODTGetLoaderInfo( "Kernel-__HEADER", (void **)&orig_mh, &orig_mhsize ); - rc_sc = IODTGetLoaderInfo( "Kernel-__SYMTAB", (void **)&sc0, &sc0_size ); - - if ( rc_mh != 0 || orig_mh == 0 || orig_mhsize < sizeof(struct mach_header) ) goto out; - if ( rc_sc != 0 || sc0 == 0 || sc0_size < sizeof(struct symtab_command) ) goto out; - - if ( pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid ) goto out; - - if ( rootdevice[0] == 'e' && rootdevice[1] == 'n' ) goto out; - - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "mach.sym", p); - if( (error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IRGRP | S_IROTH )) != 0 ) goto out; - - vp = nd.ni_vp; - - /* Don't dump to non-regular files or files with links. */ - error = EFAULT; - if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) goto out; - - VATTR_NULL(&vattr); - vattr.va_size = 0; - VOP_LEASE(vp, p, cred, LEASE_WRITE); - VOP_SETATTR(vp, &vattr, cred, p); - p->p_acflag |= ACORE; - - orig_ts = findSegmentByName(orig_mh, "__TEXT"); - orig_ds = findSegmentByName(orig_mh, "__DATA"); - - if ( orig_ts == NULL || orig_ds == NULL ) goto out; - - header_size = sizeof(struct mach_header) - + orig_ts->cmdsize - + orig_ds->cmdsize - + sizeof(struct symtab_command); - - (void) kmem_alloc_wired( kernel_map, - (vm_offset_t *)&header, - (vm_size_t)header_size); - - if ( header == NULL ) goto out; - - bzero( (void *)header, header_size ); - - /* - * Set up Mach-O header. - */ - mh = (struct mach_header *) header; - mh->magic = orig_mh->magic; - mh->cputype = orig_mh->cputype; - mh->cpusubtype = orig_mh->cpusubtype; - mh->filetype = orig_mh->filetype; - mh->ncmds = 3; - mh->sizeofcmds = header_size - sizeof(struct mach_header); - - /* - * Copy __DATA and __TEXT segment commands from mach_kernel so loadable drivers - * get correct section alignment hints. - */ - sg = (struct segment_command *)(mh+1); - bcopy( orig_ts, sg, orig_ts->cmdsize ); - - sg = (struct segment_command *)((int)sg + sg->cmdsize); - bcopy( orig_ds, sg, orig_ds->cmdsize ); - - sg = (struct segment_command *)(mh+1); - - for ( i = 0; i < 2; i++ ) - { - sg->vmaddr = 0; - sg->vmsize = 0x1000; - sg->fileoff = 0; - sg->filesize = 0; - sg->maxprot = 0; - sg->initprot = 0; - sg->flags = 0; - - se = (struct section *)(sg+1); - for ( j = 0; j < sg->nsects; j++, se++ ) - { - se->addr = 0; - se->size = 0; - se->offset = 0; - se->nreloc = 0; - } - - sg = (struct segment_command *)((int)sg + sg->cmdsize); - } - - symfoffset = round_page(header_size); - - /* - * Set up LC_SYMTAB command - */ - sc = (struct symtab_command *)sg; - sc->cmd = LC_SYMTAB; - sc->cmdsize = sizeof(struct symtab_command); - sc->symoff = symfoffset; - sc->nsyms = sc0->nsyms; - sc->strsize = sc0->strsize; - sc->stroff = symfoffset + sc->nsyms * sizeof(struct nlist); - - symsize = sc->nsyms * sizeof(struct nlist) + sc->strsize; - - nl = (struct nlist *)(sc0+1); - for (i = 0; i < sc->nsyms; i++, nl++ ) - { - if ( (nl->n_type & N_TYPE) == N_SECT ) - { - nl->n_sect = NO_SECT; - nl->n_type = (nl->n_type & ~N_TYPE) | N_ABS; - } - } - - /* - * Write out the load commands at the beginning of the - * file. - */ - error = vn_rdwr(UIO_WRITE, vp, (caddr_t)mh, header_size, (off_t)0, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); - if ( error != 0 ) goto out; - - /* - * Write out kernel symbols - */ - error = vn_rdwr(UIO_WRITE, vp, (caddr_t)(sc0+1), symsize, symfoffset, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); - if ( error != 0 ) goto out; + const_text = NULL; + se = (struct section *) &orig_ts[1]; + for (i = 0; i < orig_ts->nsects; i++, se++) { + if (!strcmp("__const", se->sectname)) { + const_text = se; + break; + } + } + if (!const_text) + goto out; + + header_size = sizeof(struct mach_header) + + orig_ts->cmdsize + + orig_ds->cmdsize + + sizeof(struct symtab_command); + + (void) kmem_alloc_wired(kernel_map, + (vm_offset_t *) &header, + (vm_size_t) header_size); + if (header) + bzero((void *) header, header_size); + else + goto out; + + /* + * Set up Mach-O header. + */ + mh = (struct mach_header *) header; + mh->magic = orig_mh->magic; + mh->cputype = orig_mh->cputype; + mh->cpusubtype = orig_mh->cpusubtype; + mh->filetype = orig_mh->filetype; + mh->ncmds = 3; + mh->sizeofcmds = header_size - sizeof(struct mach_header); + mh->flags = orig_mh->flags; + + // Initialise the current file offset and addr + offset = round_page_32(header_size); + addr = (caddr_t) const_text->addr; // Load address of __TEXT,__const + + /* + * Construct a TEXT segment load command + * the only part of the TEXT segment we keep is the __TEXT,__const + * which contains the kernel vtables. + */ + sg = (struct segment_command *) &mh[1]; + bcopy(orig_ts, sg, orig_ts->cmdsize); + sg->vmaddr = (unsigned long) addr; + sg->vmsize = const_text->size; + sg->fileoff = 0; + sg->filesize = const_text->size + round_page_32(header_size); + sg->maxprot = 0; + sg->initprot = 0; + sg->flags = 0; + se = (struct section *)(sg+1); + for ( j = 0; j < sg->nsects; j++, se++ ) { + se->addr = (unsigned long) addr; + se->size = 0; + se->offset = offset; + se->nreloc = 0; + if (!strcmp("__const", se->sectname)) { + se->size = const_text->size; + addr += const_text->size; + offset += const_text->size; + const_text = se; + } + } + offset = round_page_32((vm_address_t) offset); + + // Now copy of the __DATA segment load command, the image need + // not be stored to disk nobody needs it, yet! + sg = (struct segment_command *)((int)sg + sg->cmdsize); + bcopy(orig_ds, sg, orig_ds->cmdsize); + + sg->vmaddr = (unsigned long) addr; + sg->vmsize = 0x1000; // One page for some reason? + sg->fileoff = offset; + sg->filesize = 0; + sg->maxprot = 0; + sg->initprot = 0; + sg->flags = 0; + se = (struct section *)(sg+1); + for ( j = 0; j < sg->nsects; j++, se++ ) { + se->addr = (unsigned long) addr; + se->size = 0; + se->offset = offset; + se->nreloc = 0; + } + offset = round_page_32(offset); + + + /* + * Set up LC_SYMTAB command + */ + st = (struct symtab_command *)((int)sg + sg->cmdsize); + st->cmd = LC_SYMTAB; + st->cmdsize = sizeof(struct symtab_command); + st->symoff = offset; + st->nsyms = orig_st->nsyms; + st->strsize = orig_st->strsize; + st->stroff = offset + st->nsyms * sizeof(struct nlist); + + /* + * Convert the symbol table in place from section references + * to absolute references. + */ + sym = (struct nlist *) orig_le->vmaddr; + for (i = 0; i < st->nsyms; i++, sym++ ) { + if ( (sym->n_type & N_TYPE) == N_SECT) { + sym->n_sect = NO_SECT; + sym->n_type = (sym->n_type & ~N_TYPE) | N_ABS; + } + } + + /* + * Write out the load commands at the beginning of the file. + */ + error = vn_rdwr(UIO_WRITE, vp, (caddr_t) mh, header_size, (off_t) 0, + UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); + if (error) + goto out; + + /* + * Write out the __TEXT,__const data segment. + */ + error = vn_rdwr(UIO_WRITE, vp, (caddr_t) const_text->addr, + const_text->size, const_text->offset, + UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); + if (error) + goto out; + + /* + * Write out kernel symbols + */ + offset = st->nsyms * sizeof(struct nlist) + st->strsize; // symtab size + error = vn_rdwr(UIO_WRITE, vp, + (caddr_t) orig_le->vmaddr, offset, st->symoff, + UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); + if (error) + goto out; out: - if ( header != 0 ) kmem_free(kernel_map, header, header_size); - if ( orig_mh != 0 ) IODTFreeLoaderInfo( "Kernel-__HEADER", (void *)orig_mh, round_page(orig_mhsize) ); - if ( sc0 != 0 ) IODTFreeLoaderInfo( "Kernel-__SYMTAB", (void *)sc0, round_page(sc0_size) ); - - if ( vp != 0 ) - { - VOP_UNLOCK(vp, 0, p); - error1 = vn_close(vp, FWRITE, cred, p); - if (error == 0) error = error1; - } - - return(error); -} + if (header) + kmem_free(kernel_map, header, header_size); + + if (vp) { + VOP_UNLOCK(vp, 0, p); + error1 = vn_close(vp, FWRITE, cred, p); + if (!error) error = error1; + } + return(error); +} /* * */ -struct segment_command *findSegmentByName( struct mach_header *mh, const char *section_name ) +int get_kernel_symfile(struct proc *p, char **symfile) { - struct segment_command *sg; - int i; - - sg = (struct segment_command *)(mh+1); - - for ( i=0; i < mh->ncmds; i++ ) - { - if ( (sg->cmd == LC_SEGMENT) && (strcmp(sg->segname, section_name) == 0) ) - { - return sg; - } - - sg = (struct segment_command *)((int)sg + sg->cmdsize); + if (!kernel_symfile_opened) { + kernel_symfile_opened = 1; + error_code = output_kernel_symbols(p); } + if (!error_code) + *symfile = "\\mach.sym"; - return NULL; -} - - - - - + return error_code; +}