1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/param.h> 31 #include <sys/thread.h> 32 #include <sys/sysmacros.h> 33 #include <sys/signal.h> 34 #include <sys/cred.h> 35 #include <sys/priv.h> 36 #include <sys/user.h> 37 #include <sys/errno.h> 38 #include <sys/vnode.h> 39 #include <sys/mman.h> 40 #include <sys/kmem.h> 41 #include <sys/proc.h> 42 #include <sys/pathname.h> 43 #include <sys/cmn_err.h> 44 #include <sys/systm.h> 45 #include <sys/elf.h> 46 #include <sys/vmsystm.h> 47 #include <sys/debug.h> 48 #include <sys/procfs.h> 49 #include <sys/regset.h> 50 #include <sys/auxv.h> 51 #include <sys/exec.h> 52 #include <sys/prsystm.h> 53 #include <sys/utsname.h> 54 #include <sys/zone.h> 55 #include <vm/as.h> 56 #include <vm/rm.h> 57 #include <sys/modctl.h> 58 #include <sys/systeminfo.h> 59 #include <sys/machelf.h> 60 #include "elf_impl.h" 61 #if defined(__i386) || defined(__i386_COMPAT) 62 #include <sys/sysi86.h> 63 #endif 64 65 void 66 setup_note_header(Phdr *v, proc_t *p) 67 { 68 int nlwp = p->p_lwpcnt; 69 int nzomb = p->p_zombcnt; 70 size_t size; 71 prcred_t *pcrp; 72 73 v[0].p_type = PT_NOTE; 74 v[0].p_flags = PF_R; 75 v[0].p_filesz = (sizeof (Note) * (9 + 2 * nlwp + nzomb)) 76 + roundup(sizeof (psinfo_t), sizeof (Word)) 77 + roundup(sizeof (pstatus_t), sizeof (Word)) 78 + roundup(prgetprivsize(), sizeof (Word)) 79 + roundup(priv_get_implinfo_size(), sizeof (Word)) 80 + roundup(strlen(platform) + 1, sizeof (Word)) 81 + roundup(strlen(p->p_zone->zone_name) + 1, sizeof (Word)) 82 + roundup(__KERN_NAUXV_IMPL * sizeof (aux_entry_t), sizeof (Word)) 83 + roundup(sizeof (utsname), sizeof (Word)) 84 + roundup(sizeof (core_content_t), sizeof (Word)) 85 + (nlwp + nzomb) * roundup(sizeof (lwpsinfo_t), sizeof (Word)) 86 + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word)); 87 88 size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 89 pcrp = kmem_alloc(size, KM_SLEEP); 90 prgetcred(p, pcrp); 91 if (pcrp->pr_ngroups != 0) { 92 v[0].p_filesz += sizeof (Note) + roundup(sizeof (prcred_t) + 93 sizeof (gid_t) * (pcrp->pr_ngroups - 1), sizeof (Word)); 94 } else { 95 v[0].p_filesz += sizeof (Note) + 96 roundup(sizeof (prcred_t), sizeof (Word)); 97 } 98 kmem_free(pcrp, size); 99 100 #if defined(__i386) || defined(__i386_COMPAT) 101 mutex_enter(&p->p_ldtlock); 102 size = prnldt(p) * sizeof (struct ssd); 103 mutex_exit(&p->p_ldtlock); 104 if (size != 0) 105 v[0].p_filesz += sizeof (Note) + roundup(size, sizeof (Word)); 106 #endif /* __i386 || __i386_COMPAT */ 107 108 if ((size = prhasx(p)? prgetprxregsize(p) : 0) != 0) 109 v[0].p_filesz += nlwp * sizeof (Note) 110 + nlwp * roundup(size, sizeof (Word)); 111 112 #if defined(__sparc) 113 /* 114 * Figure out the number and sizes of register windows. 115 */ 116 { 117 kthread_t *t = p->p_tlist; 118 do { 119 if ((size = prnwindows(ttolwp(t))) != 0) { 120 size = sizeof (gwindows_t) - 121 (SPARC_MAXREGWINDOW - size) * 122 sizeof (struct rwindow); 123 v[0].p_filesz += sizeof (Note) + 124 roundup(size, sizeof (Word)); 125 } 126 } while ((t = t->t_forw) != p->p_tlist); 127 } 128 /* 129 * Space for the Ancillary State Registers. 130 */ 131 if (p->p_model == DATAMODEL_LP64) 132 v[0].p_filesz += nlwp * sizeof (Note) 133 + nlwp * roundup(sizeof (asrset_t), sizeof (Word)); 134 #endif /* __sparc */ 135 } 136 137 int 138 write_elfnotes(proc_t *p, int sig, vnode_t *vp, offset_t offset, 139 rlim64_t rlimit, cred_t *credp, core_content_t content) 140 { 141 union { 142 psinfo_t psinfo; 143 pstatus_t pstatus; 144 lwpsinfo_t lwpsinfo; 145 lwpstatus_t lwpstatus; 146 #if defined(__sparc) 147 gwindows_t gwindows; 148 asrset_t asrset; 149 #endif /* __sparc */ 150 char xregs[1]; 151 aux_entry_t auxv[__KERN_NAUXV_IMPL]; 152 prcred_t pcred; 153 prpriv_t ppriv; 154 priv_impl_info_t prinfo; 155 struct utsname uts; 156 } *bigwad; 157 158 size_t xregsize = prhasx(p)? prgetprxregsize(p) : 0; 159 size_t crsize = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 160 size_t psize = prgetprivsize(); 161 size_t bigsize = MAX(psize, MAX(sizeof (*bigwad), 162 MAX(xregsize, crsize))); 163 164 priv_impl_info_t *prii; 165 166 lwpdir_t *ldp; 167 lwpent_t *lep; 168 kthread_t *t; 169 klwp_t *lwp; 170 user_t *up; 171 int i; 172 int nlwp; 173 int nzomb; 174 int error; 175 uchar_t oldsig; 176 #if defined(__i386) || defined(__i386_COMPAT) 177 struct ssd *ssd; 178 size_t ssdsize; 179 #endif /* __i386 || __i386_COMPAT */ 180 181 bigsize = MAX(bigsize, priv_get_implinfo_size()); 182 183 bigwad = kmem_alloc(bigsize, KM_SLEEP); 184 185 /* 186 * The order of the elfnote entries should be same here 187 * and in the gcore(1) command. Synchronization is 188 * needed between the kernel and gcore(1). 189 */ 190 191 /* 192 * Get the psinfo, and set the wait status to indicate that a core was 193 * dumped. We have to forge this since p->p_wcode is not set yet. 194 */ 195 mutex_enter(&p->p_lock); 196 prgetpsinfo(p, &bigwad->psinfo); 197 mutex_exit(&p->p_lock); 198 bigwad->psinfo.pr_wstat = wstat(CLD_DUMPED, sig); 199 200 error = elfnote(vp, &offset, NT_PSINFO, sizeof (bigwad->psinfo), 201 (caddr_t)&bigwad->psinfo, rlimit, credp); 202 if (error) 203 goto done; 204 205 /* 206 * Modify t_whystop and lwp_cursig so it appears that the current LWP 207 * is stopped after faulting on the signal that caused the core dump. 208 * As a result, prgetstatus() will record that signal, the saved 209 * lwp_siginfo, and its signal handler in the core file status. We 210 * restore lwp_cursig in case a subsequent signal was received while 211 * dumping core. 212 */ 213 mutex_enter(&p->p_lock); 214 lwp = ttolwp(curthread); 215 216 oldsig = lwp->lwp_cursig; 217 lwp->lwp_cursig = (uchar_t)sig; 218 curthread->t_whystop = PR_FAULTED; 219 220 prgetstatus(p, &bigwad->pstatus, p->p_zone); 221 bigwad->pstatus.pr_lwp.pr_why = 0; 222 223 curthread->t_whystop = 0; 224 lwp->lwp_cursig = oldsig; 225 mutex_exit(&p->p_lock); 226 227 error = elfnote(vp, &offset, NT_PSTATUS, sizeof (bigwad->pstatus), 228 (caddr_t)&bigwad->pstatus, rlimit, credp); 229 if (error) 230 goto done; 231 232 error = elfnote(vp, &offset, NT_PLATFORM, strlen(platform) + 1, 233 platform, rlimit, credp); 234 if (error) 235 goto done; 236 237 up = PTOU(p); 238 for (i = 0; i < __KERN_NAUXV_IMPL; i++) { 239 bigwad->auxv[i].a_type = up->u_auxv[i].a_type; 240 bigwad->auxv[i].a_un.a_val = up->u_auxv[i].a_un.a_val; 241 } 242 error = elfnote(vp, &offset, NT_AUXV, sizeof (bigwad->auxv), 243 (caddr_t)bigwad->auxv, rlimit, credp); 244 if (error) 245 goto done; 246 247 bcopy(&utsname, &bigwad->uts, sizeof (struct utsname)); 248 if (!INGLOBALZONE(p)) { 249 bcopy(p->p_zone->zone_nodename, &bigwad->uts.nodename, 250 _SYS_NMLN); 251 } 252 error = elfnote(vp, &offset, NT_UTSNAME, sizeof (struct utsname), 253 (caddr_t)&bigwad->uts, rlimit, credp); 254 if (error) 255 goto done; 256 257 prgetcred(p, &bigwad->pcred); 258 259 if (bigwad->pcred.pr_ngroups != 0) { 260 crsize = sizeof (prcred_t) + 261 sizeof (gid_t) * (bigwad->pcred.pr_ngroups - 1); 262 } else 263 crsize = sizeof (prcred_t); 264 265 error = elfnote(vp, &offset, NT_PRCRED, crsize, 266 (caddr_t)&bigwad->pcred, rlimit, credp); 267 if (error) 268 goto done; 269 270 error = elfnote(vp, &offset, NT_CONTENT, sizeof (core_content_t), 271 (caddr_t)&content, rlimit, credp); 272 if (error) 273 goto done; 274 275 prgetpriv(p, &bigwad->ppriv); 276 277 error = elfnote(vp, &offset, NT_PRPRIV, psize, 278 (caddr_t)&bigwad->ppriv, rlimit, credp); 279 if (error) 280 goto done; 281 282 prii = priv_hold_implinfo(); 283 error = elfnote(vp, &offset, NT_PRPRIVINFO, priv_get_implinfo_size(), 284 (caddr_t)prii, rlimit, credp); 285 priv_release_implinfo(); 286 if (error) 287 goto done; 288 289 /* zone can't go away as long as process exists */ 290 error = elfnote(vp, &offset, NT_ZONENAME, 291 strlen(p->p_zone->zone_name) + 1, p->p_zone->zone_name, 292 rlimit, credp); 293 if (error) 294 goto done; 295 296 #if defined(__i386) || defined(__i386_COMPAT) 297 mutex_enter(&p->p_ldtlock); 298 ssdsize = prnldt(p) * sizeof (struct ssd); 299 if (ssdsize != 0) { 300 ssd = kmem_alloc(ssdsize, KM_SLEEP); 301 prgetldt(p, ssd); 302 error = elfnote(vp, &offset, NT_LDT, ssdsize, 303 (caddr_t)ssd, rlimit, credp); 304 kmem_free(ssd, ssdsize); 305 } 306 mutex_exit(&p->p_ldtlock); 307 if (error) 308 goto done; 309 #endif /* __i386 || defined(__i386_COMPAT) */ 310 311 nlwp = p->p_lwpcnt; 312 nzomb = p->p_zombcnt; 313 /* for each entry in the lwp directory ... */ 314 for (ldp = p->p_lwpdir; nlwp + nzomb != 0; ldp++) { 315 316 if ((lep = ldp->ld_entry) == NULL) /* empty slot */ 317 continue; 318 319 if ((t = lep->le_thread) != NULL) { /* active lwp */ 320 ASSERT(nlwp != 0); 321 nlwp--; 322 lwp = ttolwp(t); 323 mutex_enter(&p->p_lock); 324 prgetlwpsinfo(t, &bigwad->lwpsinfo); 325 mutex_exit(&p->p_lock); 326 } else { /* zombie lwp */ 327 ASSERT(nzomb != 0); 328 nzomb--; 329 bzero(&bigwad->lwpsinfo, sizeof (bigwad->lwpsinfo)); 330 bigwad->lwpsinfo.pr_lwpid = lep->le_lwpid; 331 bigwad->lwpsinfo.pr_state = SZOMB; 332 bigwad->lwpsinfo.pr_sname = 'Z'; 333 bigwad->lwpsinfo.pr_start.tv_sec = lep->le_start; 334 } 335 error = elfnote(vp, &offset, NT_LWPSINFO, 336 sizeof (bigwad->lwpsinfo), (caddr_t)&bigwad->lwpsinfo, 337 rlimit, credp); 338 if (error) 339 goto done; 340 if (t == NULL) /* nothing more to do for a zombie */ 341 continue; 342 343 mutex_enter(&p->p_lock); 344 if (t == curthread) { 345 /* 346 * Modify t_whystop and lwp_cursig so it appears that 347 * the current LWP is stopped after faulting on the 348 * signal that caused the core dump. As a result, 349 * prgetlwpstatus() will record that signal, the saved 350 * lwp_siginfo, and its signal handler in the core file 351 * status. We restore lwp_cursig in case a subsequent 352 * signal was received while dumping core. 353 */ 354 oldsig = lwp->lwp_cursig; 355 lwp->lwp_cursig = (uchar_t)sig; 356 t->t_whystop = PR_FAULTED; 357 358 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 359 bigwad->lwpstatus.pr_why = 0; 360 361 t->t_whystop = 0; 362 lwp->lwp_cursig = oldsig; 363 } else { 364 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 365 } 366 mutex_exit(&p->p_lock); 367 error = elfnote(vp, &offset, NT_LWPSTATUS, 368 sizeof (bigwad->lwpstatus), (caddr_t)&bigwad->lwpstatus, 369 rlimit, credp); 370 if (error) 371 goto done; 372 373 #if defined(__sparc) 374 /* 375 * Unspilled SPARC register windows. 376 */ 377 { 378 size_t size = prnwindows(lwp); 379 380 if (size != 0) { 381 size = sizeof (gwindows_t) - 382 (SPARC_MAXREGWINDOW - size) * 383 sizeof (struct rwindow); 384 prgetwindows(lwp, &bigwad->gwindows); 385 error = elfnote(vp, &offset, NT_GWINDOWS, 386 size, (caddr_t)&bigwad->gwindows, 387 rlimit, credp); 388 if (error) 389 goto done; 390 } 391 } 392 /* 393 * Ancillary State Registers. 394 */ 395 if (p->p_model == DATAMODEL_LP64) { 396 prgetasregs(lwp, bigwad->asrset); 397 error = elfnote(vp, &offset, NT_ASRS, 398 sizeof (asrset_t), (caddr_t)bigwad->asrset, 399 rlimit, credp); 400 if (error) 401 goto done; 402 } 403 #endif /* __sparc */ 404 405 if (xregsize) { 406 prgetprxregs(lwp, bigwad->xregs); 407 error = elfnote(vp, &offset, NT_PRXREG, 408 xregsize, bigwad->xregs, rlimit, credp); 409 if (error) 410 goto done; 411 } 412 } 413 ASSERT(nlwp == 0); 414 415 done: 416 kmem_free(bigwad, bigsize); 417 return (error); 418 } 419