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) 1991 NeXT Computer, Inc.  All rights reserved. 
  24  *      File:   bsd/kern/kern_core.c 
  26  *      This file contains machine independent code for performing core dumps. 
  29  * 16-Feb-91  Mike DeMoney (mike@next.com) 
  30  *      Massaged into MI form from m68k/core.c. 
  33 #include <mach/vm_param.h> 
  34 #include <mach/thread_status.h> 
  36 #include <sys/param.h> 
  37 #include <sys/systm.h> 
  38 #include <sys/signalvar.h> 
  39 #include <sys/resourcevar.h> 
  40 #include <sys/namei.h> 
  41 #include <sys/vnode.h> 
  43 #include <sys/timeb.h> 
  44 #include <sys/times.h> 
  49 #include <sys/kernel.h> 
  52 #include <mach-o/loader.h> 
  53 #include <mach/vm_region.h> 
  54 #include <mach/vm_statistics.h> 
  56 #include <vm/vm_kern.h> 
  59         int     flavor
;                 /* the number for this flavor */ 
  60         int     count
;                  /* count of ints in this flavor */ 
  61 } mythread_state_flavor_t
; 
  65 mythread_state_flavor_t thread_flavor_array
[]={ 
  66                 {PPC_THREAD_STATE 
, PPC_THREAD_STATE_COUNT
}, 
  67                 {PPC_FLOAT_STATE
, PPC_FLOAT_STATE_COUNT
},  
  68                 {PPC_EXCEPTION_STATE
, PPC_EXCEPTION_STATE_COUNT
} 
  71 #elif defined (__i386__) 
  72 mythread_state_flavor_t thread_flavor_array 
[] = {  
  73                 {i386_THREAD_STATE
, i386_THREAD_STATE_COUNT
}, 
  74                 {i386_THREAD_FPSTATE
, i386_THREAD_FPSTATE_COUNT
}, 
  75                 {i386_THREAD_EXCEPTSTATE
, i386_THREAD_EXCEPTSTATE_COUNT
}, 
  76                 {i386_THREAD_CTHREADSTATE
, i386_THREAD_CTHREADSTATE_COUNT
}, 
  77                 {i386_NEW_THREAD_STATE
, i386_NEW_THREAD_STATE_COUNT
}, 
  78                 {i386_FLOAT_STATE
, i386_FLOAT_STATE_COUNT
}, 
  79                 {i386_ISA_PORT_MAP_STATE
, i386_ISA_PORT_MAP_STATE_COUNT
}, 
  80                 {i386_V86_ASSIST_STATE
, i386_V86_ASSIST_STATE_COUNT
}, 
  81                 {THREAD_SYSCALL_STATE
, i386_THREAD_SYSCALL_STATE_COUNT
} 
  86 #error architecture not supported 
  93         mythread_state_flavor_t 
*flavors
; 
  97 collectth_state(thread_act_t th_act
, tir_t 
*t
) 
 101         mythread_state_flavor_t 
*flavors
; 
 102         struct thread_command   
*tc
; 
 104                  *      Fill in thread command structure. 
 107                 hoffset 
= t
->hoffset
; 
 108                 flavors 
= t
->flavors
; 
 110                 tc 
= (struct thread_command 
*) (header 
+ hoffset
); 
 112                 tc
->cmdsize 
= sizeof(struct thread_command
) 
 114                 hoffset 
+= sizeof(struct thread_command
); 
 116                  * Follow with a struct thread_state_flavor and 
 117                  * the appropriate thread state struct for each 
 118                  * thread state flavor. 
 120                 for (i 
= 0; i 
< mynum_flavors
; i
++) { 
 121                         *(mythread_state_flavor_t 
*)(header
+hoffset
) = 
 123                         hoffset 
+= sizeof(mythread_state_flavor_t
); 
 124                         thread_getstatus(th_act
, flavors
[i
].flavor
, 
 125                                         (thread_state_t 
*)(header
+hoffset
), 
 127                         hoffset 
+= flavors
[i
].count
*sizeof(int); 
 130                 t
->hoffset 
= hoffset
; 
 133  * Create a core image on the file "core". 
 135 #define MAX_TSTATE_FLAVORS      10 
 138         register struct proc 
*p
; 
 141         register struct pcred 
*pcred 
= p
->p_cred
; 
 142         register struct ucred 
*cred 
= pcred
->pc_ucred
; 
 146         int             thread_count
, segment_count
; 
 147         int             command_size
, header_size
, tstate_size
; 
 148         int             hoffset
, foffset
, vmoffset
; 
 150         struct machine_slot     
*ms
; 
 151         struct mach_header      
*mh
; 
 152         struct segment_command  
*sc
; 
 153         struct thread_command   
*tc
; 
 157         vm_inherit_t    inherit
; 
 161         char            core_name
[MAXCOMLEN
+6]; 
 162         mythread_state_flavor_t flavors
[MAX_TSTATE_FLAVORS
]; 
 163         vm_size_t       nflavors
,mapsize
; 
 165         int nesting_depth 
= 0; 
 167         struct vm_region_submap_info_64 vbr
; 
 173         if (pcred
->p_svuid 
!= pcred
->p_ruid 
|| pcred
->p_svgid 
!= pcred
->p_rgid
) 
 176         task 
= current_task(); 
 178         mapsize 
= get_vmmap_size(map
); 
 180         if (mapsize 
>=  p
->p_rlimit
[RLIMIT_CORE
].rlim_cur
) 
 182         (void) task_suspend(task
); 
 185          *      Make sure all registers, etc. are in pcb so they get 
 188 #if defined (__ppc__) 
 189         fpu_save(current_act()); 
 190         vec_save(current_act()); 
 192         sprintf(core_name
, "/cores/core.%d", p
->p_pid
); 
 193         NDINIT(&nd
, LOOKUP
, FOLLOW
, UIO_SYSSPACE
, core_name
, p
); 
 194         if(error 
= vn_open(&nd
, O_CREAT 
| FWRITE
, S_IRUSR 
)) 
 198         /* Don't dump to non-regular files or files with links. */ 
 199         if (vp
->v_type 
!= VREG 
|| 
 200             VOP_GETATTR(vp
, &vattr
, cred
, p
) || vattr
.va_nlink 
!= 1) { 
 207         VOP_LEASE(vp
, p
, cred
, LEASE_WRITE
); 
 208         VOP_SETATTR(vp
, &vattr
, cred
, p
); 
 209         p
->p_acflag 
|= ACORE
; 
 212          *      If the task is modified while dumping the file 
 213          *      (e.g., changes in threads or VM, the resulting 
 214          *      file will not necessarily be correct. 
 217         thread_count 
= get_task_numacts(task
); 
 218         segment_count 
= get_vmmap_entries(map
); /* XXX */ 
 220          * nflavors here is really the number of ints in flavors 
 221          * to meet the thread_getstatus() calling convention 
 224         nflavors 
= sizeof(flavors
)/sizeof(int); 
 225         if (thread_getstatus(current_thread(), THREAD_STATE_FLAVOR_LIST
, 
 226                                 (thread_state_t
)(flavors
), 
 227                                  &nflavors
) != KERN_SUCCESS
) 
 228             panic("core flavor list"); 
 229         /* now convert to number of flavors */ 
 230         nflavors 
/= sizeof(mythread_state_flavor_t
)/sizeof(int); 
 232         nflavors 
= mynum_flavors
; 
 233         bcopy(thread_flavor_array
,flavors
,sizeof(thread_flavor_array
)); 
 236         for (i 
= 0; i 
< nflavors
; i
++) 
 237                 tstate_size 
+= sizeof(mythread_state_flavor_t
) + 
 238                   (flavors
[i
].count 
* sizeof(int)); 
 240         command_size 
= segment_count
*sizeof(struct segment_command
) + 
 241           thread_count
*sizeof(struct thread_command
) + 
 242           tstate_size
*thread_count
; 
 244         header_size 
= command_size 
+ sizeof(struct mach_header
); 
 246         (void) kmem_alloc_wired(kernel_map
, 
 247                                     (vm_offset_t 
*)&header
, 
 248                                     (vm_size_t
)header_size
); 
 251          *      Set up Mach-O header. 
 253         mh 
= (struct mach_header 
*) header
; 
 254         ms 
= &machine_slot
[cpu_number()]; 
 255         mh
->magic 
= MH_MAGIC
; 
 256         mh
->cputype 
= ms
->cpu_type
; 
 257         mh
->cpusubtype 
= ms
->cpu_subtype
; 
 258         mh
->filetype 
= MH_CORE
; 
 259         mh
->ncmds 
= segment_count 
+ thread_count
; 
 260         mh
->sizeofcmds 
= command_size
; 
 262         hoffset 
= sizeof(struct mach_header
);   /* offset into header */ 
 263         foffset 
= round_page(header_size
);      /* offset into file */ 
 264         vmoffset 
= VM_MIN_ADDRESS
;              /* offset into VM */ 
 265         /* We use to check for an error, here, now we try and get  
 268         while (segment_count 
> 0){ 
 270                  *      Get region information for next region. 
 274                         vbrcount 
= VM_REGION_SUBMAP_INFO_COUNT_64
; 
 275                         if((kret 
= vm_region_recurse_64(map
,  
 276                                         &vmoffset
, &size
, &nesting_depth
,  
 277                                         &vbr
, &vbrcount
)) != KERN_SUCCESS
) { 
 287                 if(kret 
!= KERN_SUCCESS
) 
 290                 prot 
= vbr
.protection
; 
 291                 maxprot 
= vbr
.max_protection
; 
 292                 inherit 
= vbr
.inheritance
; 
 294                  *      Fill in segment command structure. 
 296                 sc 
= (struct segment_command 
*) (header 
+ hoffset
); 
 297                 sc
->cmd 
= LC_SEGMENT
; 
 298                 sc
->cmdsize 
= sizeof(struct segment_command
); 
 299                 /* segment name is zerod by kmem_alloc */ 
 300                 sc
->vmaddr 
= vmoffset
; 
 302                 sc
->fileoff 
= foffset
; 
 304                 sc
->maxprot 
= maxprot
; 
 309                  *      Write segment out.  Try as hard as possible to 
 310                  *      get read access to the data. 
 312                 if ((prot 
& VM_PROT_READ
) == 0) { 
 313                         vm_protect(map
, vmoffset
, size
, FALSE
, 
 317                  *      Only actually perform write if we can read. 
 318                  *      Note: if we can't read, then we end up with 
 319                  *      a hole in the file. 
 321                 if ((maxprot 
& VM_PROT_READ
) == VM_PROT_READ 
&& vbr
.user_tag 
!= VM_MEMORY_IOKIT
) { 
 322                         error 
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)vmoffset
, size
, foffset
, 
 323                                 UIO_USERSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
); 
 326                 hoffset 
+= sizeof(struct segment_command
); 
 334         thread 
= (thread_t
) queue_first(&task
->thread_list
); 
 335         while (thread_count 
> 0) { 
 337                  *      Fill in thread command structure. 
 339                 tc 
= (struct thread_command 
*) (header 
+ hoffset
); 
 341                 tc
->cmdsize 
= sizeof(struct thread_command
) 
 343                 hoffset 
+= sizeof(struct thread_command
); 
 345                  * Follow with a struct thread_state_flavor and 
 346                  * the appropriate thread state struct for each 
 347                  * thread state flavor. 
 349                 for (i 
= 0; i 
< nflavors
; i
++) { 
 350                         *(mythread_state_flavor_t 
*)(header
+hoffset
) = 
 352                         hoffset 
+= sizeof(mythread_state_flavor_t
); 
 353                         thread_getstatus(thread
, flavors
[i
].flavor
, 
 354                                         (thread_state_t 
*)(header
+hoffset
), 
 356                         hoffset 
+= flavors
[i
].count
*sizeof(int); 
 358                 thread 
= (thread_t
) queue_next(&thread
->thread_list
); 
 363         tir1
.header 
= header
; 
 364         tir1
.hoffset 
= hoffset
; 
 365         tir1
.flavors 
= flavors
; 
 366         tir1
.tstate_size 
= tstate_size
; 
 367         task_act_iterate_wth_args(task
, collectth_state
,&tir1
); 
 371          *      Write out the Mach header at the beginning of the 
 374         error 
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)header
, header_size
, (off_t
)0, 
 375                         UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, p
); 
 376         kmem_free(kernel_map
, header
, header_size
); 
 378         VOP_UNLOCK(vp
, 0, p
); 
 379         error1 
= vn_close(vp
, FWRITE
, cred
, p
);