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
setup_note_header(Phdr * v,proc_t * p)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
write_elfnotes(proc_t * p,int sig,vnode_t * vp,offset_t offset,rlim64_t rlimit,cred_t * credp,core_content_t content)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