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 /* 28 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved. 29 * Copyright 2018 Joyent, Inc. 30 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/param.h> 35 #include <sys/thread.h> 36 #include <sys/sysmacros.h> 37 #include <sys/signal.h> 38 #include <sys/cred.h> 39 #include <sys/priv.h> 40 #include <sys/user.h> 41 #include <sys/file.h> 42 #include <sys/errno.h> 43 #include <sys/vnode.h> 44 #include <sys/mode.h> 45 #include <sys/vfs.h> 46 #include <sys/mman.h> 47 #include <sys/kmem.h> 48 #include <sys/proc.h> 49 #include <sys/pathname.h> 50 #include <sys/cmn_err.h> 51 #include <sys/systm.h> 52 #include <sys/elf.h> 53 #include <sys/vmsystm.h> 54 #include <sys/debug.h> 55 #include <sys/procfs.h> 56 #include <sys/regset.h> 57 #include <sys/auxv.h> 58 #include <sys/exec.h> 59 #include <sys/prsystm.h> 60 #include <sys/utsname.h> 61 #include <sys/zone.h> 62 #include <vm/as.h> 63 #include <vm/rm.h> 64 #include <sys/modctl.h> 65 #include <sys/systeminfo.h> 66 #include <sys/machelf.h> 67 #include <sys/sunddi.h> 68 #include "elf_impl.h" 69 #if defined(__i386_COMPAT) 70 #include <sys/sysi86.h> 71 #endif 72 73 void 74 setup_note_header(Phdr *v, proc_t *p) 75 { 76 int nlwp = p->p_lwpcnt; 77 int nzomb = p->p_zombcnt; 78 int nfd; 79 size_t size; 80 prcred_t *pcrp; 81 uf_info_t *fip; 82 uf_entry_t *ufp; 83 int fd; 84 85 fip = P_FINFO(p); 86 nfd = 0; 87 mutex_enter(&fip->fi_lock); 88 for (fd = 0; fd < fip->fi_nfiles; fd++) { 89 UF_ENTER(ufp, fip, fd); 90 if ((ufp->uf_file != NULL) && (ufp->uf_file->f_count > 0)) 91 nfd++; 92 UF_EXIT(ufp); 93 } 94 mutex_exit(&fip->fi_lock); 95 96 v[0].p_type = PT_NOTE; 97 v[0].p_flags = PF_R; 98 v[0].p_filesz = (sizeof (Note) * (10 + 3 * nlwp + nzomb + nfd)) 99 + roundup(sizeof (psinfo_t), sizeof (Word)) 100 + roundup(sizeof (pstatus_t), sizeof (Word)) 101 + roundup(prgetprivsize(), sizeof (Word)) 102 + roundup(priv_get_implinfo_size(), sizeof (Word)) 103 + roundup(strlen(platform) + 1, sizeof (Word)) 104 + roundup(strlen(p->p_zone->zone_name) + 1, sizeof (Word)) 105 + roundup(__KERN_NAUXV_IMPL * sizeof (aux_entry_t), sizeof (Word)) 106 + roundup(sizeof (utsname), sizeof (Word)) 107 + roundup(sizeof (core_content_t), sizeof (Word)) 108 + roundup(sizeof (prsecflags_t), sizeof (Word)) 109 + (nlwp + nzomb) * roundup(sizeof (lwpsinfo_t), sizeof (Word)) 110 + nlwp * roundup(sizeof (lwpstatus_t), sizeof (Word)) 111 + nlwp * roundup(sizeof (prlwpname_t), sizeof (Word)) 112 + nfd * roundup(sizeof (prfdinfo_core_t), sizeof (Word)); 113 114 if (curproc->p_agenttp != NULL) { 115 v[0].p_filesz += sizeof (Note) + 116 roundup(sizeof (psinfo_t), sizeof (Word)); 117 } 118 119 size = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 120 pcrp = kmem_alloc(size, KM_SLEEP); 121 prgetcred(p, pcrp); 122 if (pcrp->pr_ngroups != 0) { 123 v[0].p_filesz += sizeof (Note) + roundup(sizeof (prcred_t) + 124 sizeof (gid_t) * (pcrp->pr_ngroups - 1), sizeof (Word)); 125 } else { 126 v[0].p_filesz += sizeof (Note) + 127 roundup(sizeof (prcred_t), sizeof (Word)); 128 } 129 kmem_free(pcrp, size); 130 131 132 #if defined(__i386_COMPAT) 133 mutex_enter(&p->p_ldtlock); 134 size = prnldt(p) * sizeof (struct ssd); 135 mutex_exit(&p->p_ldtlock); 136 if (size != 0) 137 v[0].p_filesz += sizeof (Note) + roundup(size, sizeof (Word)); 138 #endif /* __i386_COMPAT */ 139 140 if ((size = prhasx(p)? prgetprxregsize(p) : 0) != 0) 141 v[0].p_filesz += nlwp * sizeof (Note) 142 + nlwp * roundup(size, sizeof (Word)); 143 144 #if defined(__sparc) 145 /* 146 * Figure out the number and sizes of register windows. 147 */ 148 { 149 kthread_t *t = p->p_tlist; 150 do { 151 if ((size = prnwindows(ttolwp(t))) != 0) { 152 size = sizeof (gwindows_t) - 153 (SPARC_MAXREGWINDOW - size) * 154 sizeof (struct rwindow); 155 v[0].p_filesz += sizeof (Note) + 156 roundup(size, sizeof (Word)); 157 } 158 } while ((t = t->t_forw) != p->p_tlist); 159 } 160 /* 161 * Space for the Ancillary State Registers. 162 */ 163 if (p->p_model == DATAMODEL_LP64) 164 v[0].p_filesz += nlwp * sizeof (Note) 165 + nlwp * roundup(sizeof (asrset_t), sizeof (Word)); 166 #endif /* __sparc */ 167 168 mutex_enter(&p->p_lock); 169 if ((p->p_upanicflag & P_UPF_PANICKED) != 0) { 170 v[0].p_filesz += sizeof (Note) + 171 roundup(sizeof (prupanic_t), sizeof (Word)); 172 } 173 mutex_exit(&p->p_lock); 174 } 175 176 int 177 write_elfnotes(proc_t *p, int sig, vnode_t *vp, offset_t offset, 178 rlim64_t rlimit, cred_t *credp, core_content_t content) 179 { 180 union { 181 psinfo_t psinfo; 182 pstatus_t pstatus; 183 lwpsinfo_t lwpsinfo; 184 lwpstatus_t lwpstatus; 185 #if defined(__sparc) 186 gwindows_t gwindows; 187 asrset_t asrset; 188 #endif /* __sparc */ 189 char xregs[1]; 190 aux_entry_t auxv[__KERN_NAUXV_IMPL]; 191 prcred_t pcred; 192 prpriv_t ppriv; 193 priv_impl_info_t prinfo; 194 struct utsname uts; 195 prsecflags_t psecflags; 196 prupanic_t upanic; 197 } *bigwad; 198 199 size_t xregsize = prhasx(p)? prgetprxregsize(p) : 0; 200 size_t crsize = sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1); 201 size_t psize = prgetprivsize(); 202 size_t bigsize = MAX(psize, MAX(sizeof (*bigwad), 203 MAX(xregsize, crsize))); 204 205 priv_impl_info_t *prii; 206 207 lwpdir_t *ldp; 208 lwpent_t *lep; 209 kthread_t *t; 210 klwp_t *lwp; 211 user_t *up; 212 int i; 213 int nlwp; 214 int nzomb; 215 int error; 216 uchar_t oldsig; 217 uf_info_t *fip; 218 int fd; 219 vnode_t *vroot; 220 221 #if defined(__i386_COMPAT) 222 struct ssd *ssd; 223 size_t ssdsize; 224 #endif /* __i386_COMPAT */ 225 226 bigsize = MAX(bigsize, priv_get_implinfo_size()); 227 228 bigwad = kmem_alloc(bigsize, KM_SLEEP); 229 230 /* 231 * The order of the elfnote entries should be same here 232 * and in the gcore(1) command. Synchronization is 233 * needed between the kernel and gcore(1). 234 */ 235 236 /* 237 * Get the psinfo, and set the wait status to indicate that a core was 238 * dumped. We have to forge this since p->p_wcode is not set yet. 239 */ 240 mutex_enter(&p->p_lock); 241 prgetpsinfo(p, &bigwad->psinfo); 242 mutex_exit(&p->p_lock); 243 bigwad->psinfo.pr_wstat = wstat(CLD_DUMPED, sig); 244 245 error = elfnote(vp, &offset, NT_PSINFO, sizeof (bigwad->psinfo), 246 (caddr_t)&bigwad->psinfo, rlimit, credp); 247 if (error) 248 goto done; 249 250 /* 251 * Modify t_whystop and lwp_cursig so it appears that the current LWP 252 * is stopped after faulting on the signal that caused the core dump. 253 * As a result, prgetstatus() will record that signal, the saved 254 * lwp_siginfo, and its signal handler in the core file status. We 255 * restore lwp_cursig in case a subsequent signal was received while 256 * dumping core. 257 */ 258 mutex_enter(&p->p_lock); 259 lwp = ttolwp(curthread); 260 261 oldsig = lwp->lwp_cursig; 262 lwp->lwp_cursig = (uchar_t)sig; 263 curthread->t_whystop = PR_FAULTED; 264 265 prgetstatus(p, &bigwad->pstatus, p->p_zone); 266 bigwad->pstatus.pr_lwp.pr_why = 0; 267 268 curthread->t_whystop = 0; 269 lwp->lwp_cursig = oldsig; 270 mutex_exit(&p->p_lock); 271 272 error = elfnote(vp, &offset, NT_PSTATUS, sizeof (bigwad->pstatus), 273 (caddr_t)&bigwad->pstatus, rlimit, credp); 274 if (error) 275 goto done; 276 277 error = elfnote(vp, &offset, NT_PLATFORM, strlen(platform) + 1, 278 platform, rlimit, credp); 279 if (error) 280 goto done; 281 282 up = PTOU(p); 283 for (i = 0; i < __KERN_NAUXV_IMPL; i++) { 284 bigwad->auxv[i].a_type = up->u_auxv[i].a_type; 285 bigwad->auxv[i].a_un.a_val = up->u_auxv[i].a_un.a_val; 286 } 287 error = elfnote(vp, &offset, NT_AUXV, sizeof (bigwad->auxv), 288 (caddr_t)bigwad->auxv, rlimit, credp); 289 if (error) 290 goto done; 291 292 bcopy(&utsname, &bigwad->uts, sizeof (struct utsname)); 293 if (!INGLOBALZONE(p)) { 294 bcopy(p->p_zone->zone_nodename, &bigwad->uts.nodename, 295 _SYS_NMLN); 296 } 297 error = elfnote(vp, &offset, NT_UTSNAME, sizeof (struct utsname), 298 (caddr_t)&bigwad->uts, rlimit, credp); 299 if (error) 300 goto done; 301 302 prgetsecflags(p, &bigwad->psecflags); 303 error = elfnote(vp, &offset, NT_SECFLAGS, sizeof (prsecflags_t), 304 (caddr_t)&bigwad->psecflags, rlimit, credp); 305 if (error) 306 goto done; 307 308 prgetcred(p, &bigwad->pcred); 309 310 if (bigwad->pcred.pr_ngroups != 0) { 311 crsize = sizeof (prcred_t) + 312 sizeof (gid_t) * (bigwad->pcred.pr_ngroups - 1); 313 } else 314 crsize = sizeof (prcred_t); 315 316 error = elfnote(vp, &offset, NT_PRCRED, crsize, 317 (caddr_t)&bigwad->pcred, rlimit, credp); 318 if (error) 319 goto done; 320 321 error = elfnote(vp, &offset, NT_CONTENT, sizeof (core_content_t), 322 (caddr_t)&content, rlimit, credp); 323 if (error) 324 goto done; 325 326 prgetpriv(p, &bigwad->ppriv); 327 328 error = elfnote(vp, &offset, NT_PRPRIV, psize, 329 (caddr_t)&bigwad->ppriv, rlimit, credp); 330 if (error) 331 goto done; 332 333 prii = priv_hold_implinfo(); 334 error = elfnote(vp, &offset, NT_PRPRIVINFO, priv_get_implinfo_size(), 335 (caddr_t)prii, rlimit, credp); 336 priv_release_implinfo(); 337 if (error) 338 goto done; 339 340 /* zone can't go away as long as process exists */ 341 error = elfnote(vp, &offset, NT_ZONENAME, 342 strlen(p->p_zone->zone_name) + 1, p->p_zone->zone_name, 343 rlimit, credp); 344 if (error) 345 goto done; 346 347 348 /* open file table */ 349 vroot = PTOU(p)->u_rdir; 350 if (vroot == NULL) 351 vroot = rootdir; 352 353 VN_HOLD(vroot); 354 355 fip = P_FINFO(p); 356 357 for (fd = 0; fd < fip->fi_nfiles; fd++) { 358 uf_entry_t *ufp; 359 vnode_t *fvp; 360 struct file *fp; 361 vattr_t vattr; 362 prfdinfo_core_t fdinfo; 363 364 bzero(&fdinfo, sizeof (fdinfo)); 365 366 mutex_enter(&fip->fi_lock); 367 UF_ENTER(ufp, fip, fd); 368 if (((fp = ufp->uf_file) == NULL) || (fp->f_count < 1)) { 369 UF_EXIT(ufp); 370 mutex_exit(&fip->fi_lock); 371 continue; 372 } 373 374 fdinfo.pr_fd = fd; 375 fdinfo.pr_fdflags = ufp->uf_flag; 376 fdinfo.pr_fileflags = fp->f_flag2; 377 fdinfo.pr_fileflags <<= 16; 378 fdinfo.pr_fileflags |= fp->f_flag; 379 if ((fdinfo.pr_fileflags & (FSEARCH | FEXEC)) == 0) 380 fdinfo.pr_fileflags += FOPEN; 381 fdinfo.pr_offset = fp->f_offset; 382 383 384 fvp = fp->f_vnode; 385 VN_HOLD(fvp); 386 UF_EXIT(ufp); 387 mutex_exit(&fip->fi_lock); 388 389 /* 390 * There are some vnodes that have no corresponding 391 * path. Its reasonable for this to fail, in which 392 * case the path will remain an empty string. 393 */ 394 (void) vnodetopath(vroot, fvp, fdinfo.pr_path, 395 sizeof (fdinfo.pr_path), credp); 396 397 if (VOP_GETATTR(fvp, &vattr, 0, credp, NULL) != 0) { 398 /* 399 * Try to write at least a subset of information 400 */ 401 fdinfo.pr_major = 0; 402 fdinfo.pr_minor = 0; 403 fdinfo.pr_ino = 0; 404 fdinfo.pr_mode = 0; 405 fdinfo.pr_uid = (uid_t)-1; 406 fdinfo.pr_gid = (gid_t)-1; 407 fdinfo.pr_rmajor = 0; 408 fdinfo.pr_rminor = 0; 409 fdinfo.pr_size = -1; 410 411 error = elfnote(vp, &offset, NT_FDINFO, 412 sizeof (fdinfo), &fdinfo, rlimit, credp); 413 VN_RELE(fvp); 414 if (error) { 415 VN_RELE(vroot); 416 goto done; 417 } 418 continue; 419 } 420 421 if (fvp->v_type == VSOCK) 422 fdinfo.pr_fileflags |= sock_getfasync(fvp); 423 424 VN_RELE(fvp); 425 426 /* 427 * This logic mirrors fstat(), which we cannot use 428 * directly, as it calls copyout(). 429 */ 430 fdinfo.pr_major = getmajor(vattr.va_fsid); 431 fdinfo.pr_minor = getminor(vattr.va_fsid); 432 fdinfo.pr_ino = (ino64_t)vattr.va_nodeid; 433 fdinfo.pr_mode = VTTOIF(vattr.va_type) | vattr.va_mode; 434 fdinfo.pr_uid = vattr.va_uid; 435 fdinfo.pr_gid = vattr.va_gid; 436 fdinfo.pr_rmajor = getmajor(vattr.va_rdev); 437 fdinfo.pr_rminor = getminor(vattr.va_rdev); 438 fdinfo.pr_size = (off64_t)vattr.va_size; 439 440 error = elfnote(vp, &offset, NT_FDINFO, 441 sizeof (fdinfo), &fdinfo, rlimit, credp); 442 if (error) { 443 VN_RELE(vroot); 444 goto done; 445 } 446 } 447 448 VN_RELE(vroot); 449 450 #if defined(__i386_COMPAT) 451 mutex_enter(&p->p_ldtlock); 452 ssdsize = prnldt(p) * sizeof (struct ssd); 453 if (ssdsize != 0) { 454 ssd = kmem_alloc(ssdsize, KM_SLEEP); 455 prgetldt(p, ssd); 456 error = elfnote(vp, &offset, NT_LDT, ssdsize, 457 (caddr_t)ssd, rlimit, credp); 458 kmem_free(ssd, ssdsize); 459 } 460 mutex_exit(&p->p_ldtlock); 461 if (error) 462 goto done; 463 #endif /* defined(__i386_COMPAT) */ 464 465 nlwp = p->p_lwpcnt; 466 nzomb = p->p_zombcnt; 467 /* for each entry in the lwp directory ... */ 468 for (ldp = p->p_lwpdir; nlwp + nzomb != 0; ldp++) { 469 prlwpname_t name = { 0, }; 470 471 if ((lep = ldp->ld_entry) == NULL) /* empty slot */ 472 continue; 473 474 if ((t = lep->le_thread) != NULL) { /* active lwp */ 475 ASSERT(nlwp != 0); 476 nlwp--; 477 lwp = ttolwp(t); 478 mutex_enter(&p->p_lock); 479 prgetlwpsinfo(t, &bigwad->lwpsinfo); 480 if (t->t_name != NULL) { 481 (void) strlcpy(name.pr_lwpname, t->t_name, 482 sizeof (name.pr_lwpname)); 483 } 484 mutex_exit(&p->p_lock); 485 } else { /* zombie lwp */ 486 ASSERT(nzomb != 0); 487 nzomb--; 488 bzero(&bigwad->lwpsinfo, sizeof (bigwad->lwpsinfo)); 489 bigwad->lwpsinfo.pr_lwpid = lep->le_lwpid; 490 bigwad->lwpsinfo.pr_state = SZOMB; 491 bigwad->lwpsinfo.pr_sname = 'Z'; 492 bigwad->lwpsinfo.pr_start.tv_sec = lep->le_start; 493 } 494 495 name.pr_lwpid = bigwad->lwpsinfo.pr_lwpid; 496 497 error = elfnote(vp, &offset, NT_LWPSINFO, 498 sizeof (bigwad->lwpsinfo), (caddr_t)&bigwad->lwpsinfo, 499 rlimit, credp); 500 if (error) 501 goto done; 502 503 if (t == NULL) /* nothing more to do for a zombie */ 504 continue; 505 506 mutex_enter(&p->p_lock); 507 if (t == curthread) { 508 /* 509 * Modify t_whystop and lwp_cursig so it appears that 510 * the current LWP is stopped after faulting on the 511 * signal that caused the core dump. As a result, 512 * prgetlwpstatus() will record that signal, the saved 513 * lwp_siginfo, and its signal handler in the core file 514 * status. We restore lwp_cursig in case a subsequent 515 * signal was received while dumping core. 516 */ 517 oldsig = lwp->lwp_cursig; 518 lwp->lwp_cursig = (uchar_t)sig; 519 t->t_whystop = PR_FAULTED; 520 521 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 522 bigwad->lwpstatus.pr_why = 0; 523 524 t->t_whystop = 0; 525 lwp->lwp_cursig = oldsig; 526 } else { 527 prgetlwpstatus(t, &bigwad->lwpstatus, p->p_zone); 528 } 529 mutex_exit(&p->p_lock); 530 error = elfnote(vp, &offset, NT_LWPSTATUS, 531 sizeof (bigwad->lwpstatus), (caddr_t)&bigwad->lwpstatus, 532 rlimit, credp); 533 if (error) 534 goto done; 535 536 if ((error = elfnote(vp, &offset, NT_LWPNAME, sizeof (name), 537 (caddr_t)&name, rlimit, credp)) != 0) 538 goto done; 539 540 541 #if defined(__sparc) 542 /* 543 * Unspilled SPARC register windows. 544 */ 545 { 546 size_t size = prnwindows(lwp); 547 548 if (size != 0) { 549 size = sizeof (gwindows_t) - 550 (SPARC_MAXREGWINDOW - size) * 551 sizeof (struct rwindow); 552 prgetwindows(lwp, &bigwad->gwindows); 553 error = elfnote(vp, &offset, NT_GWINDOWS, 554 size, (caddr_t)&bigwad->gwindows, 555 rlimit, credp); 556 if (error) 557 goto done; 558 } 559 } 560 /* 561 * Ancillary State Registers. 562 */ 563 if (p->p_model == DATAMODEL_LP64) { 564 prgetasregs(lwp, bigwad->asrset); 565 error = elfnote(vp, &offset, NT_ASRS, 566 sizeof (asrset_t), (caddr_t)bigwad->asrset, 567 rlimit, credp); 568 if (error) 569 goto done; 570 } 571 #endif /* __sparc */ 572 573 if (xregsize) { 574 prgetprxregs(lwp, bigwad->xregs); 575 error = elfnote(vp, &offset, NT_PRXREG, 576 xregsize, bigwad->xregs, rlimit, credp); 577 if (error) 578 goto done; 579 } 580 581 if (t->t_lwp->lwp_spymaster != NULL) { 582 void *psaddr = t->t_lwp->lwp_spymaster; 583 #ifdef _ELF32_COMPAT 584 /* 585 * On a 64-bit kernel with 32-bit ELF compatibility, 586 * this file is compiled into two different objects: 587 * one is compiled normally, and the other is compiled 588 * with _ELF32_COMPAT set -- and therefore with a 589 * psinfo_t defined to be a psinfo32_t. However, the 590 * psinfo_t denoting our spymaster is always of the 591 * native type; if we are in the _ELF32_COMPAT case, 592 * we need to explicitly convert it. 593 */ 594 if (p->p_model == DATAMODEL_ILP32) { 595 psinfo_kto32(psaddr, &bigwad->psinfo); 596 psaddr = &bigwad->psinfo; 597 } 598 #endif 599 600 error = elfnote(vp, &offset, NT_SPYMASTER, 601 sizeof (psinfo_t), psaddr, rlimit, credp); 602 if (error) 603 goto done; 604 } 605 } 606 ASSERT(nlwp == 0); 607 608 /* 609 * If a upanic occurred, add a note for it. 610 */ 611 mutex_enter(&p->p_lock); 612 if ((p->p_upanicflag & P_UPF_PANICKED) != 0) { 613 bzero(&bigwad->upanic, sizeof (prupanic_t)); 614 bigwad->upanic.pru_version = PRUPANIC_VERSION_1; 615 if ((p->p_upanicflag & P_UPF_INVALMSG) != 0) { 616 bigwad->upanic.pru_flags |= PRUPANIC_FLAG_MSG_ERROR; 617 } 618 619 if ((p->p_upanicflag & P_UPF_TRUNCMSG) != 0) { 620 bigwad->upanic.pru_flags |= PRUPANIC_FLAG_MSG_TRUNC; 621 } 622 623 if ((p->p_upanicflag & P_UPF_HAVEMSG) != 0) { 624 bigwad->upanic.pru_flags |= PRUPANIC_FLAG_MSG_VALID; 625 bcopy(p->p_upanic, bigwad->upanic.pru_data, 626 PRUPANIC_BUFLEN); 627 } 628 629 error = elfnote(vp, &offset, NT_UPANIC, sizeof (prupanic_t), 630 &bigwad->upanic, rlimit, credp); 631 if (error != 0) { 632 mutex_exit(&p->p_lock); 633 goto done; 634 } 635 } 636 mutex_exit(&p->p_lock); 637 638 done: 639 kmem_free(bigwad, bigsize); 640 return (error); 641 } 642