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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2012 DEY Storage Systems, Inc. All rights reserved.
29 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/thread.h>
35 #include <sys/sysmacros.h>
36 #include <sys/signal.h>
41 #include <sys/errno.h>
42 #include <sys/vnode.h>
48 #include <sys/pathname.h>
49 #include <sys/cmn_err.h>
50 #include <sys/systm.h>
52 #include <sys/vmsystm.h>
53 #include <sys/debug.h>
54 #include <sys/procfs.h>
55 #include <sys/regset.h>
58 #include <sys/prsystm.h>
59 #include <sys/utsname.h>
63 #include <sys/modctl.h>
64 #include <sys/systeminfo.h>
65 #include <sys/machelf.h>
66 #include <sys/sunddi.h>
68 #if defined(__i386) || defined(__i386_COMPAT)
69 #include <sys/sysi86.h>
73 setup_note_header(Phdr
*v
, proc_t
*p
)
75 int nlwp
= p
->p_lwpcnt
;
76 int nzomb
= p
->p_zombcnt
;
86 mutex_enter(&fip
->fi_lock
);
87 for (fd
= 0; fd
< fip
->fi_nfiles
; fd
++) {
88 UF_ENTER(ufp
, fip
, fd
);
89 if ((ufp
->uf_file
!= NULL
) && (ufp
->uf_file
->f_count
> 0))
93 mutex_exit(&fip
->fi_lock
);
95 v
[0].p_type
= PT_NOTE
;
97 v
[0].p_filesz
= (sizeof (Note
) * (10 + 2 * nlwp
+ nzomb
+ nfd
))
98 + roundup(sizeof (psinfo_t
), sizeof (Word
))
99 + roundup(sizeof (pstatus_t
), sizeof (Word
))
100 + roundup(prgetprivsize(), sizeof (Word
))
101 + roundup(priv_get_implinfo_size(), sizeof (Word
))
102 + roundup(strlen(platform
) + 1, sizeof (Word
))
103 + roundup(strlen(p
->p_zone
->zone_name
) + 1, sizeof (Word
))
104 + roundup(__KERN_NAUXV_IMPL
* sizeof (aux_entry_t
), sizeof (Word
))
105 + roundup(sizeof (utsname
), sizeof (Word
))
106 + roundup(sizeof (core_content_t
), sizeof (Word
))
107 + roundup(sizeof (prsecflags_t
), sizeof (Word
))
108 + (nlwp
+ nzomb
) * roundup(sizeof (lwpsinfo_t
), sizeof (Word
))
109 + nlwp
* roundup(sizeof (lwpstatus_t
), sizeof (Word
))
110 + nfd
* roundup(sizeof (prfdinfo_t
), sizeof (Word
));
112 if (curproc
->p_agenttp
!= NULL
) {
113 v
[0].p_filesz
+= sizeof (Note
) +
114 roundup(sizeof (psinfo_t
), sizeof (Word
));
117 size
= sizeof (prcred_t
) + sizeof (gid_t
) * (ngroups_max
- 1);
118 pcrp
= kmem_alloc(size
, KM_SLEEP
);
120 if (pcrp
->pr_ngroups
!= 0) {
121 v
[0].p_filesz
+= sizeof (Note
) + roundup(sizeof (prcred_t
) +
122 sizeof (gid_t
) * (pcrp
->pr_ngroups
- 1), sizeof (Word
));
124 v
[0].p_filesz
+= sizeof (Note
) +
125 roundup(sizeof (prcred_t
), sizeof (Word
));
127 kmem_free(pcrp
, size
);
130 #if defined(__i386) || defined(__i386_COMPAT)
131 mutex_enter(&p
->p_ldtlock
);
132 size
= prnldt(p
) * sizeof (struct ssd
);
133 mutex_exit(&p
->p_ldtlock
);
135 v
[0].p_filesz
+= sizeof (Note
) + roundup(size
, sizeof (Word
));
136 #endif /* __i386 || __i386_COMPAT */
138 if ((size
= prhasx(p
)? prgetprxregsize(p
) : 0) != 0)
139 v
[0].p_filesz
+= nlwp
* sizeof (Note
)
140 + nlwp
* roundup(size
, sizeof (Word
));
145 write_elfnotes(proc_t
*p
, int sig
, vnode_t
*vp
, offset_t offset
,
146 rlim_t rlimit
, cred_t
*credp
, core_content_t content
)
152 lwpstatus_t lwpstatus
;
154 aux_entry_t auxv
[__KERN_NAUXV_IMPL
];
157 priv_impl_info_t prinfo
;
159 prsecflags_t psecflags
;
162 size_t xregsize
= prhasx(p
)? prgetprxregsize(p
) : 0;
163 size_t crsize
= sizeof (prcred_t
) + sizeof (gid_t
) * (ngroups_max
- 1);
164 size_t psize
= prgetprivsize();
165 size_t bigsize
= MAX(psize
, MAX(sizeof (*bigwad
),
166 MAX(xregsize
, crsize
)));
168 priv_impl_info_t
*prii
;
184 #if defined(__i386) || defined(__i386_COMPAT)
187 #endif /* __i386 || __i386_COMPAT */
189 bigsize
= MAX(bigsize
, priv_get_implinfo_size());
191 bigwad
= kmem_alloc(bigsize
, KM_SLEEP
);
194 * The order of the elfnote entries should be same here
195 * and in the gcore(1) command. Synchronization is
196 * needed between the kernel and gcore(1).
200 * Get the psinfo, and set the wait status to indicate that a core was
201 * dumped. We have to forge this since p->p_wcode is not set yet.
203 mutex_enter(&p
->p_lock
);
204 prgetpsinfo(p
, &bigwad
->psinfo
);
205 mutex_exit(&p
->p_lock
);
206 bigwad
->psinfo
.pr_wstat
= wstat(CLD_DUMPED
, sig
);
208 error
= elfnote(vp
, &offset
, NT_PSINFO
, sizeof (bigwad
->psinfo
),
209 (caddr_t
)&bigwad
->psinfo
, rlimit
, credp
);
214 * Modify t_whystop and lwp_cursig so it appears that the current LWP
215 * is stopped after faulting on the signal that caused the core dump.
216 * As a result, prgetstatus() will record that signal, the saved
217 * lwp_siginfo, and its signal handler in the core file status. We
218 * restore lwp_cursig in case a subsequent signal was received while
221 mutex_enter(&p
->p_lock
);
222 lwp
= ttolwp(curthread
);
224 oldsig
= lwp
->lwp_cursig
;
225 lwp
->lwp_cursig
= (uchar_t
)sig
;
226 curthread
->t_whystop
= PR_FAULTED
;
228 prgetstatus(p
, &bigwad
->pstatus
, p
->p_zone
);
229 bigwad
->pstatus
.pr_lwp
.pr_why
= 0;
231 curthread
->t_whystop
= 0;
232 lwp
->lwp_cursig
= oldsig
;
233 mutex_exit(&p
->p_lock
);
235 error
= elfnote(vp
, &offset
, NT_PSTATUS
, sizeof (bigwad
->pstatus
),
236 (caddr_t
)&bigwad
->pstatus
, rlimit
, credp
);
240 error
= elfnote(vp
, &offset
, NT_PLATFORM
, strlen(platform
) + 1,
241 platform
, rlimit
, credp
);
246 for (i
= 0; i
< __KERN_NAUXV_IMPL
; i
++) {
247 bigwad
->auxv
[i
].a_type
= up
->u_auxv
[i
].a_type
;
248 bigwad
->auxv
[i
].a_un
.a_val
= up
->u_auxv
[i
].a_un
.a_val
;
250 error
= elfnote(vp
, &offset
, NT_AUXV
, sizeof (bigwad
->auxv
),
251 (caddr_t
)bigwad
->auxv
, rlimit
, credp
);
255 bcopy(&utsname
, &bigwad
->uts
, sizeof (struct utsname
));
256 if (!INGLOBALZONE(p
)) {
257 bcopy(p
->p_zone
->zone_nodename
, &bigwad
->uts
.nodename
,
260 error
= elfnote(vp
, &offset
, NT_UTSNAME
, sizeof (struct utsname
),
261 (caddr_t
)&bigwad
->uts
, rlimit
, credp
);
265 prgetsecflags(p
, &bigwad
->psecflags
);
266 error
= elfnote(vp
, &offset
, NT_SECFLAGS
, sizeof (prsecflags_t
),
267 (caddr_t
)&bigwad
->psecflags
, rlimit
, credp
);
271 prgetcred(p
, &bigwad
->pcred
);
273 if (bigwad
->pcred
.pr_ngroups
!= 0) {
274 crsize
= sizeof (prcred_t
) +
275 sizeof (gid_t
) * (bigwad
->pcred
.pr_ngroups
- 1);
277 crsize
= sizeof (prcred_t
);
279 error
= elfnote(vp
, &offset
, NT_PRCRED
, crsize
,
280 (caddr_t
)&bigwad
->pcred
, rlimit
, credp
);
284 error
= elfnote(vp
, &offset
, NT_CONTENT
, sizeof (core_content_t
),
285 (caddr_t
)&content
, rlimit
, credp
);
289 prgetpriv(p
, &bigwad
->ppriv
);
291 error
= elfnote(vp
, &offset
, NT_PRPRIV
, psize
,
292 (caddr_t
)&bigwad
->ppriv
, rlimit
, credp
);
296 prii
= priv_hold_implinfo();
297 error
= elfnote(vp
, &offset
, NT_PRPRIVINFO
, priv_get_implinfo_size(),
298 (caddr_t
)prii
, rlimit
, credp
);
299 priv_release_implinfo();
303 /* zone can't go away as long as process exists */
304 error
= elfnote(vp
, &offset
, NT_ZONENAME
,
305 strlen(p
->p_zone
->zone_name
) + 1, p
->p_zone
->zone_name
,
311 /* open file table */
312 vroot
= PTOU(p
)->u_rdir
;
320 for (fd
= 0; fd
< fip
->fi_nfiles
; fd
++) {
327 bzero(&fdinfo
, sizeof (fdinfo
));
329 mutex_enter(&fip
->fi_lock
);
330 UF_ENTER(ufp
, fip
, fd
);
331 if (((fp
= ufp
->uf_file
) == NULL
) || (fp
->f_count
< 1)) {
333 mutex_exit(&fip
->fi_lock
);
338 fdinfo
.pr_fdflags
= ufp
->uf_flag
;
339 fdinfo
.pr_fileflags
= OFLAGS(fp
->f_flag
);
340 fdinfo
.pr_offset
= fp
->f_offset
;
346 mutex_exit(&fip
->fi_lock
);
349 * There are some vnodes that have no corresponding
350 * path. Its reasonable for this to fail, in which
351 * case the path will remain an empty string.
353 (void) vnodetopath(vroot
, fvp
, fdinfo
.pr_path
,
354 sizeof (fdinfo
.pr_path
), credp
);
356 if (fop_getattr(fvp
, &vattr
, 0, credp
, NULL
) != 0) {
358 * Try to write at least a subset of information
364 fdinfo
.pr_uid
= (uid_t
)-1;
365 fdinfo
.pr_gid
= (gid_t
)-1;
366 fdinfo
.pr_rmajor
= 0;
367 fdinfo
.pr_rminor
= 0;
370 error
= elfnote(vp
, &offset
, NT_FDINFO
,
371 sizeof (fdinfo
), &fdinfo
, rlimit
, credp
);
380 if (fvp
->v_type
== VSOCK
)
381 fdinfo
.pr_fileflags
|= sock_getfasync(fvp
);
386 * This logic mirrors fstat(), which we cannot use
387 * directly, as it calls copyout().
389 fdinfo
.pr_major
= getmajor(vattr
.va_fsid
);
390 fdinfo
.pr_minor
= getminor(vattr
.va_fsid
);
391 fdinfo
.pr_ino
= (ino64_t
)vattr
.va_nodeid
;
392 fdinfo
.pr_mode
= VTTOIF(vattr
.va_type
) | vattr
.va_mode
;
393 fdinfo
.pr_uid
= vattr
.va_uid
;
394 fdinfo
.pr_gid
= vattr
.va_gid
;
395 fdinfo
.pr_rmajor
= getmajor(vattr
.va_rdev
);
396 fdinfo
.pr_rminor
= getminor(vattr
.va_rdev
);
397 fdinfo
.pr_size
= (off64_t
)vattr
.va_size
;
399 error
= elfnote(vp
, &offset
, NT_FDINFO
,
400 sizeof (fdinfo
), &fdinfo
, rlimit
, credp
);
409 #if defined(__i386) || defined(__i386_COMPAT)
410 mutex_enter(&p
->p_ldtlock
);
411 ssdsize
= prnldt(p
) * sizeof (struct ssd
);
413 ssd
= kmem_alloc(ssdsize
, KM_SLEEP
);
415 error
= elfnote(vp
, &offset
, NT_LDT
, ssdsize
,
416 (caddr_t
)ssd
, rlimit
, credp
);
417 kmem_free(ssd
, ssdsize
);
419 mutex_exit(&p
->p_ldtlock
);
422 #endif /* __i386 || defined(__i386_COMPAT) */
425 nzomb
= p
->p_zombcnt
;
426 /* for each entry in the lwp directory ... */
427 for (ldp
= p
->p_lwpdir
; nlwp
+ nzomb
!= 0; ldp
++) {
429 if ((lep
= ldp
->ld_entry
) == NULL
) /* empty slot */
432 if ((t
= lep
->le_thread
) != NULL
) { /* active lwp */
436 mutex_enter(&p
->p_lock
);
437 prgetlwpsinfo(t
, &bigwad
->lwpsinfo
);
438 mutex_exit(&p
->p_lock
);
439 } else { /* zombie lwp */
442 bzero(&bigwad
->lwpsinfo
, sizeof (bigwad
->lwpsinfo
));
443 bigwad
->lwpsinfo
.pr_lwpid
= lep
->le_lwpid
;
444 bigwad
->lwpsinfo
.pr_state
= SZOMB
;
445 bigwad
->lwpsinfo
.pr_sname
= 'Z';
446 bigwad
->lwpsinfo
.pr_start
.tv_sec
= lep
->le_start
;
448 error
= elfnote(vp
, &offset
, NT_LWPSINFO
,
449 sizeof (bigwad
->lwpsinfo
), (caddr_t
)&bigwad
->lwpsinfo
,
453 if (t
== NULL
) /* nothing more to do for a zombie */
456 mutex_enter(&p
->p_lock
);
457 if (t
== curthread
) {
459 * Modify t_whystop and lwp_cursig so it appears that
460 * the current LWP is stopped after faulting on the
461 * signal that caused the core dump. As a result,
462 * prgetlwpstatus() will record that signal, the saved
463 * lwp_siginfo, and its signal handler in the core file
464 * status. We restore lwp_cursig in case a subsequent
465 * signal was received while dumping core.
467 oldsig
= lwp
->lwp_cursig
;
468 lwp
->lwp_cursig
= (uchar_t
)sig
;
469 t
->t_whystop
= PR_FAULTED
;
471 prgetlwpstatus(t
, &bigwad
->lwpstatus
, p
->p_zone
);
472 bigwad
->lwpstatus
.pr_why
= 0;
475 lwp
->lwp_cursig
= oldsig
;
477 prgetlwpstatus(t
, &bigwad
->lwpstatus
, p
->p_zone
);
479 mutex_exit(&p
->p_lock
);
480 error
= elfnote(vp
, &offset
, NT_LWPSTATUS
,
481 sizeof (bigwad
->lwpstatus
), (caddr_t
)&bigwad
->lwpstatus
,
488 prgetprxregs(lwp
, bigwad
->xregs
);
489 error
= elfnote(vp
, &offset
, NT_PRXREG
,
490 xregsize
, bigwad
->xregs
, rlimit
, credp
);
495 if (t
->t_lwp
->lwp_spymaster
!= NULL
) {
496 void *psaddr
= t
->t_lwp
->lwp_spymaster
;
499 * On a 64-bit kernel with 32-bit ELF compatibility,
500 * this file is compiled into two different objects:
501 * one is compiled normally, and the other is compiled
502 * with _ELF32_COMPAT set -- and therefore with a
503 * psinfo_t defined to be a psinfo32_t. However, the
504 * psinfo_t denoting our spymaster is always of the
505 * native type; if we are in the _ELF32_COMPAT case,
506 * we need to explicitly convert it.
508 if (p
->p_model
== DATAMODEL_ILP32
) {
509 psinfo_kto32(psaddr
, &bigwad
->psinfo
);
510 psaddr
= &bigwad
->psinfo
;
514 error
= elfnote(vp
, &offset
, NT_SPYMASTER
,
515 sizeof (psinfo_t
), psaddr
, rlimit
, credp
);
523 kmem_free(bigwad
, bigsize
);