FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_coredump / coredump-solaris.c
blob00d131b370fafef5598b3abde75ce2faa93dc0f9
2 /*--------------------------------------------------------------------*/
3 /*--- Dumping core on Solaris. coredump-solaris.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2013-2017 Ivo Raisr
11 ivosh@ivosh.net
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 #if defined(VGO_solaris)
31 #include "pub_core_basics.h"
32 #include "pub_core_vki.h"
33 #include "pub_core_aspacehl.h"
34 #include "pub_core_aspacemgr.h"
35 #include "pub_core_coredump.h"
36 #include "pub_core_debuglog.h"
37 #include "pub_core_libcassert.h"
38 #include "pub_core_libcbase.h"
39 #include "pub_core_libcfile.h"
40 #include "pub_core_libcprint.h"
41 #include "pub_core_libcproc.h"
42 #include "pub_core_machine.h"
43 #include "pub_core_mallocfree.h"
44 #include "pub_core_options.h"
45 #include "pub_core_syscall.h"
46 #include "pub_core_threadstate.h"
47 #include "pub_core_xarray.h"
48 #include "pub_core_clientstate.h"
50 typedef struct __attribute__ ((__packed__)) note {
51 struct note *next;
52 VKI_ESZ(Nhdr) nhdr;
53 HChar name[8];
54 HChar data[0];
55 } note_t;
57 static void add_note(note_t **list, UInt type, const void *data,
58 UInt datasz);
60 /* If true, then this Segment may be mentioned in the core */
61 static Bool may_dump(const NSegment *seg)
63 if ((seg->kind == SkAnonC) ||
64 (seg->kind == SkShmC) ||
65 ((seg->kind == SkFileC) &&
66 !VKI_S_ISCHR(seg->mode) && !VKI_S_ISBLK(seg->mode)))
67 return True;
69 return False;
72 /* If true, then this Segment's contents will be in the core */
73 static Bool should_dump(const NSegment *seg)
75 return may_dump(seg);
78 #if defined(SOLARIS_PRXREGSET_T)
79 static Bool should_dump_xregs(const ThreadState *tst)
81 #if defined(VGP_x86_solaris)
82 return False;
83 #elif defined(VGP_amd64_solaris)
84 const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
86 /* Dump 256-bit wide %ymm only when their upper half is non-zero. */
87 #define YMM_NON_ZERO(reg) \
88 ((reg[4] != 0) || (reg[5] != 0) || (reg[6] != 0) || (reg[7] != 0))
89 if (YMM_NON_ZERO(arch->vex.guest_YMM0) ||
90 YMM_NON_ZERO(arch->vex.guest_YMM1) ||
91 YMM_NON_ZERO(arch->vex.guest_YMM2) ||
92 YMM_NON_ZERO(arch->vex.guest_YMM3) ||
93 YMM_NON_ZERO(arch->vex.guest_YMM4) ||
94 YMM_NON_ZERO(arch->vex.guest_YMM5) ||
95 YMM_NON_ZERO(arch->vex.guest_YMM6) ||
96 YMM_NON_ZERO(arch->vex.guest_YMM7) ||
97 YMM_NON_ZERO(arch->vex.guest_YMM9) ||
98 YMM_NON_ZERO(arch->vex.guest_YMM0) ||
99 YMM_NON_ZERO(arch->vex.guest_YMM10) ||
100 YMM_NON_ZERO(arch->vex.guest_YMM11) ||
101 YMM_NON_ZERO(arch->vex.guest_YMM12) ||
102 YMM_NON_ZERO(arch->vex.guest_YMM13) ||
103 YMM_NON_ZERO(arch->vex.guest_YMM14) ||
104 YMM_NON_ZERO(arch->vex.guest_YMM15))
105 return True;
107 return False;
109 #undef YMM_NON_ZERO
110 #else
111 # error Unknown ELF platform
112 #endif
114 #endif /* SOLARIS_PRXREGSET_T */
116 static void write_part(Int fd, const HChar *filename,
117 void *buf, SizeT buf_size, const HChar *part)
119 Int ret = VG_(write)(fd, buf, buf_size);
120 if (ret < 0) {
121 VG_(umsg)("Failed to write %s to coredump file %s, it may be "
122 "incomplete.\n", part, filename);
123 VG_(debugLog)(1, "coredump-solaris", "write_part: failed to write "
124 "%s to file %s. Buffer address=%p, length=%lu. "
125 "Error=%d.\n", part, filename, buf, buf_size, -ret);
129 /*====================================================================*/
130 /*=== Miscellaneous getters ===*/
131 /*====================================================================*/
133 static Int get_uid(void)
135 return sr_Res(VG_(do_syscall0)(SYS_getuid));
138 static Int get_gid(void)
140 return sr_Res(VG_(do_syscall0)(SYS_getgid));
143 static Int get_dmodel(void)
145 #if defined(VGP_x86_solaris)
146 return PR_MODEL_ILP32;
147 #elif defined(VGP_amd64_solaris)
148 return PR_MODEL_LP64;
149 #else
150 # error "Unknown platform"
151 #endif
154 static vki_zoneid_t get_zoneid(void)
156 SysRes sres = VG_(do_syscall2)(SYS_zone, VKI_ZONE_LOOKUP,
157 (UWord) NULL);
158 if (sr_isError(sres))
159 return 0;
161 return sr_Res(sres);
164 static UInt count_auxv(void)
166 UInt count = 1;
168 vki_auxv_t *auxv = (vki_auxv_t *) VG_(client_auxv);
169 while (auxv->a_type != VKI_AT_NULL) {
170 count += 1;
171 auxv++;
174 return count;
177 static Addr compute_stkbase(const ThreadState *tst)
179 return tst->client_stack_highest_byte + 1
180 - tst->client_stack_szB;
183 static Int get_wstat(const vki_siginfo_t *si)
185 return (si->si_signo & 0xff) | WCOREFLG;
188 /*====================================================================*/
189 /*=== Utility fillers ===*/
190 /*====================================================================*/
192 static void fill_platform(HChar *buf, UInt buf_size)
194 vg_assert(buf != NULL);
195 vg_assert(buf_size >= 1);
197 buf[0] = '\0';
199 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_PLATFORM,
200 (UWord) buf, buf_size);
203 static void fill_zonename(HChar *buf, UInt buf_size)
205 vg_assert(buf != NULL);
206 vg_assert(buf_size >= 1);
208 buf[0] = '\0';
210 VG_(do_syscall5)(SYS_zone, VKI_ZONE_GETATTR, get_zoneid(),
211 VKI_ZONE_ATTR_NAME, (UWord) buf, buf_size);
214 static void fill_thread_state(const ThreadState *tst,
215 HChar *state, HChar *sname)
217 switch (tst->status) {
218 case VgTs_Runnable:
219 case VgTs_Yielding:
220 *state = VKI_SRUN;
221 *sname = 'R';
222 break;
224 case VgTs_WaitSys:
225 *state = VKI_SSLEEP;
226 *sname = 'S';
227 break;
229 case VgTs_Zombie:
230 *state = VKI_SZOMB;
231 *sname = 'Z';
232 break;
234 case VgTs_Empty:
235 case VgTs_Init:
236 *state = 0;
237 *sname = '?';
238 break;
242 static void fill_siginfo(const vki_siginfo_t *si, vki_siginfo_t *di,
243 Short *signo)
245 di->si_signo = si->si_signo;
246 di->si_code = si->si_code;
247 di->si_errno = 0;
248 di->si_addr = si->si_addr;
249 *signo = si->si_signo;
252 static void fill_argv(Int *argc, Addr *argv)
254 Addr *ptr = (Addr *) VG_(get_initial_client_SP)();
255 *argc = *ptr++;
256 *argv = (Addr) ptr;
259 static void fill_scheduling_class(HChar *buf, SizeT buf_size)
261 vg_assert(buf != NULL);
262 vg_assert(buf_size >= 1);
264 /* Valgrind currently schedules one thread at time which
265 resembles the default timeshare class. */
266 VG_(strncpy)(buf, "TS", buf_size);
269 static void fill_regset(vki_prgregset_t *regs, const ThreadState *tst)
271 const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
273 #if defined(VGP_x86_solaris)
274 (*regs)[VKI_EIP] = arch->vex.guest_EIP;
275 (*regs)[VKI_EAX] = arch->vex.guest_EAX;
276 (*regs)[VKI_EBX] = arch->vex.guest_EBX;
277 (*regs)[VKI_ECX] = arch->vex.guest_ECX;
278 (*regs)[VKI_EDX] = arch->vex.guest_EDX;
279 (*regs)[VKI_ESI] = arch->vex.guest_ESI;
280 (*regs)[VKI_EDI] = arch->vex.guest_EDI;
281 (*regs)[VKI_EBP] = arch->vex.guest_EBP;
282 (*regs)[VKI_UESP] = arch->vex.guest_ESP;
283 (*regs)[VKI_SS] = arch->vex.guest_SS;
284 (*regs)[VKI_CS] = arch->vex.guest_CS;
285 (*regs)[VKI_DS] = arch->vex.guest_DS;
286 (*regs)[VKI_ES] = arch->vex.guest_ES;
287 (*regs)[VKI_FS] = arch->vex.guest_FS;
288 (*regs)[VKI_GS] = arch->vex.guest_GS;
289 (*regs)[VKI_EFL] = LibVEX_GuestX86_get_eflags(&arch->vex);
290 #elif defined(VGP_amd64_solaris)
291 (*regs)[VKI_REG_RIP] = arch->vex.guest_RIP;
292 (*regs)[VKI_REG_RAX] = arch->vex.guest_RAX;
293 (*regs)[VKI_REG_RBX] = arch->vex.guest_RBX;
294 (*regs)[VKI_REG_RCX] = arch->vex.guest_RCX;
295 (*regs)[VKI_REG_RDX] = arch->vex.guest_RDX;
296 (*regs)[VKI_REG_RBP] = arch->vex.guest_RBP;
297 (*regs)[VKI_REG_RSI] = arch->vex.guest_RSI;
298 (*regs)[VKI_REG_RDI] = arch->vex.guest_RDI;
299 (*regs)[VKI_REG_R8] = arch->vex.guest_R8;
300 (*regs)[VKI_REG_R9] = arch->vex.guest_R9;
301 (*regs)[VKI_REG_R10] = arch->vex.guest_R10;
302 (*regs)[VKI_REG_R11] = arch->vex.guest_R11;
303 (*regs)[VKI_REG_R12] = arch->vex.guest_R12;
304 (*regs)[VKI_REG_R13] = arch->vex.guest_R13;
305 (*regs)[VKI_REG_R14] = arch->vex.guest_R14;
306 (*regs)[VKI_REG_R15] = arch->vex.guest_R15;
307 (*regs)[VKI_REG_RSP] = arch->vex.guest_RSP;
308 (*regs)[VKI_REG_CS] = VKI_UCS_SEL;
309 (*regs)[VKI_REG_DS] = 0;
310 (*regs)[VKI_REG_ES] = 0;
311 (*regs)[VKI_REG_FS] = 0;
312 (*regs)[VKI_REG_GS] = 0;
313 (*regs)[VKI_REG_SS] = VKI_UDS_SEL;
314 (*regs)[VKI_REG_FSBASE] = arch->vex.guest_FS_CONST;
315 (*regs)[VKI_REG_GSBASE] = 0;
316 (*regs)[VKI_REG_RFL] = LibVEX_GuestAMD64_get_rflags(&arch->vex);
317 #else
318 # error "Unknown platform"
319 #endif
322 static void fill_fpregset(vki_fpregset_t *fpu, const ThreadState *tst)
324 const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
326 #if defined(VGP_x86_solaris)
327 VG_(memset)(fpu, 0, sizeof(*fpu));
329 struct vki_fpchip_state *fs = &fpu->fp_reg_set.fpchip_state;
330 vg_assert(sizeof(fs->state) == 108);
332 LibVEX_GuestX86_get_x87(CONST_CAST(VexGuestX86State *, &arch->vex),
333 (UChar *) &fs->state);
335 /* SSE */
336 UInt mxcsr = LibVEX_GuestX86_get_mxcsr(CONST_CAST(VexGuestX86State *,
337 &arch->vex));
338 fs->mxcsr = mxcsr;
340 /* XMM registers */
341 #define COPY_OUT_XMM(dest, src) \
342 do { \
343 dest._l[0] = src[0]; \
344 dest._l[1] = src[1]; \
345 dest._l[2] = src[2]; \
346 dest._l[3] = src[3]; \
347 } while (0);
348 COPY_OUT_XMM(fs->xmm[0], arch->vex.guest_XMM0);
349 COPY_OUT_XMM(fs->xmm[1], arch->vex.guest_XMM1);
350 COPY_OUT_XMM(fs->xmm[2], arch->vex.guest_XMM2);
351 COPY_OUT_XMM(fs->xmm[3], arch->vex.guest_XMM3);
352 COPY_OUT_XMM(fs->xmm[4], arch->vex.guest_XMM4);
353 COPY_OUT_XMM(fs->xmm[5], arch->vex.guest_XMM5);
354 COPY_OUT_XMM(fs->xmm[6], arch->vex.guest_XMM6);
355 COPY_OUT_XMM(fs->xmm[7], arch->vex.guest_XMM7);
356 #undef COPY_OUT_XMM
357 #elif defined(VGP_amd64_solaris)
358 VG_(memset)(fpu, 0, sizeof(*fpu));
359 struct vki_fpchip_state *fs = &fpu->fp_reg_set.fpchip_state;
361 /* LibVEX_GuestAMD64_fxsave() requires at least 416 bytes. */
362 vg_assert(sizeof(*fs) >= 416);
363 LibVEX_GuestAMD64_fxsave(CONST_CAST(VexGuestAMD64State *, &arch->vex),
364 (Addr) fs);
365 #else
366 # error Unknown platform
367 #endif
370 /*====================================================================*/
371 /*=== Header fillers ===*/
372 /*====================================================================*/
374 static void fill_ehdr(VKI_ESZ(Ehdr) *ehdr, Int num_phdrs)
376 VG_(memset)(ehdr, 0, sizeof(*ehdr));
378 VG_(memcpy)(ehdr->e_ident, VKI_ELFMAG, VKI_SELFMAG);
379 ehdr->e_ident[VKI_EI_CLASS] = VG_ELF_CLASS;
380 ehdr->e_ident[VKI_EI_DATA] = VG_ELF_DATA2XXX;
381 ehdr->e_ident[VKI_EI_VERSION] = VKI_EV_CURRENT;
383 ehdr->e_type = VKI_ET_CORE;
384 ehdr->e_machine = VG_ELF_MACHINE;
385 ehdr->e_version = VKI_EV_CURRENT;
386 ehdr->e_entry = 0;
387 ehdr->e_flags = 0;
388 ehdr->e_ehsize = sizeof(VKI_ESZ(Ehdr));
390 ehdr->e_phoff = sizeof(VKI_ESZ(Ehdr));
391 ehdr->e_phentsize = sizeof(VKI_ESZ(Phdr));
393 /* If the count of program headers can't fit in the mere 16 bits
394 * shortsightedly allotted to them in the ELF header, we use the
395 * extended formats and put the real values in the section header
396 * at index 0.
398 if (num_phdrs >= VKI_PN_XNUM) {
399 ehdr->e_phnum = VKI_PN_XNUM;
400 ehdr->e_shnum = 1;
401 ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * num_phdrs;
402 ehdr->e_shentsize = sizeof(VKI_ESZ(Shdr));
403 } else {
404 ehdr->e_phnum = num_phdrs;
405 ehdr->e_shnum = 0;
406 ehdr->e_shoff = 0;
407 ehdr->e_shentsize = 0;
410 ehdr->e_shstrndx = 0;
413 static void fill_phdr(VKI_ESZ(Phdr) *phdr, const NSegment *seg, UInt off,
414 Bool really_write)
416 SizeT len = seg->end - seg->start + 1;
418 really_write = really_write && should_dump(seg);
420 VG_(memset)(phdr, 0, sizeof(*phdr));
422 phdr->p_type = PT_LOAD;
423 phdr->p_offset = off;
424 phdr->p_vaddr = seg->start;
425 phdr->p_paddr = 0;
426 phdr->p_filesz = really_write ? len : 0;
427 phdr->p_memsz = len;
428 phdr->p_flags = 0;
430 if (seg->hasR)
431 phdr->p_flags |= PF_R;
432 if (seg->hasW)
433 phdr->p_flags |= PF_W;
434 if (seg->hasX)
435 phdr->p_flags |= PF_X;
437 phdr->p_align = VKI_PAGE_SIZE;
440 /* Fills the section header at index zero when num_phdrs >= PN_XNUM. */
441 static void fill_zero_shdr(VKI_ESZ(Shdr) *shdr, UInt num_phdrs)
443 vg_assert(num_phdrs >= VKI_PN_XNUM);
445 VG_(memset)(shdr, 0, sizeof(*shdr));
447 shdr->sh_name = 0; // STR_NONE
448 shdr->sh_info = num_phdrs;
451 static void fill_prpsinfo(vki_elf_prpsinfo_t *prpsinfo,
452 const ThreadState *tst,
453 const vki_siginfo_t *si)
455 VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
457 fill_thread_state(tst, &prpsinfo->pr_state, &prpsinfo->pr_sname);
458 prpsinfo->pr_uid = get_uid();
459 prpsinfo->pr_gid = get_gid();
460 prpsinfo->pr_pid = VG_(getpid)();
461 prpsinfo->pr_ppid = VG_(getppid)();
462 prpsinfo->pr_pgrp = VG_(getpgrp)();
463 prpsinfo->pr_sid = VG_(getpgrp)();
464 fill_scheduling_class(prpsinfo->pr_clname, sizeof(prpsinfo->pr_clname));
465 VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), True);
466 VG_(client_cmd_and_args)(prpsinfo->pr_psargs,
467 sizeof(prpsinfo->pr_psargs));
468 fill_argv(&prpsinfo->pr_argc, (Addr *) &prpsinfo->pr_argv);
469 prpsinfo->pr_envp = (char **) VG_(client_envp);
470 prpsinfo->pr_wstat = get_wstat(si);
471 prpsinfo->pr_euid = VG_(geteuid)();
472 prpsinfo->pr_egid = VG_(getegid)();
473 prpsinfo->pr_dmodel = get_dmodel();
476 static void fill_prstatus(vki_elf_prstatus_t *prs,
477 const ThreadState *tst,
478 const vki_siginfo_t *si)
480 VG_(memset)(prs, 0, sizeof(*prs));
482 prs->pr_flags = VKI_ELF_OLD_PR_PCINVAL;
483 fill_siginfo(si, &prs->pr_info, &prs->pr_cursig);
484 prs->pr_nlwp = VG_(count_living_threads)();
485 prs->pr_sighold = tst->sig_mask;
486 prs->pr_pid = VG_(getpid)();
487 prs->pr_ppid = VG_(getppid)();
488 prs->pr_pgrp = VG_(getpgrp)();
489 prs->pr_sid = VG_(getpgrp)();
490 fill_scheduling_class(prs->pr_clname, sizeof(prs->pr_clname));
491 prs->pr_who = tst->os_state.lwpid;
492 prs->pr_brkbase = (vki_caddr_t) VG_(brk_base);
493 prs->pr_brksize = VG_(brk_limit) - VG_(brk_base);
494 prs->pr_stkbase = (vki_caddr_t) compute_stkbase(tst);
495 prs->pr_stksize = tst->client_stack_szB;
496 fill_regset(&prs->pr_reg, tst);
499 static void fill_psinfo(vki_psinfo_t *psinfo, const ThreadState *tst,
500 const vki_siginfo_t *si)
502 VG_(memset)(psinfo, 0, sizeof(*psinfo));
504 psinfo->pr_nlwp = VG_(count_living_threads)();
505 psinfo->pr_uid = get_uid();
506 psinfo->pr_gid = get_gid();
507 psinfo->pr_pid = VG_(getpid)();
508 psinfo->pr_ppid = VG_(getppid)();
509 psinfo->pr_pgid = VG_(getpgrp)();
510 psinfo->pr_sid = VG_(getpgrp)();
511 psinfo->pr_euid = VG_(geteuid)();
512 psinfo->pr_egid = VG_(getegid)();
513 VG_(client_fname)(psinfo->pr_fname, sizeof(psinfo->pr_fname), True);
514 psinfo->pr_wstat = get_wstat(si);
515 VG_(client_cmd_and_args)(psinfo->pr_psargs,
516 sizeof(psinfo->pr_psargs));
517 fill_argv(&psinfo->pr_argc, (Addr *) &psinfo->pr_argv);
518 psinfo->pr_envp = (uintptr_t) VG_(client_envp);
519 psinfo->pr_dmodel = get_dmodel();
520 psinfo->pr_zoneid = get_zoneid();
522 psinfo->pr_lwp.pr_lwpid = tst->os_state.lwpid;
523 fill_thread_state(tst, &psinfo->pr_lwp.pr_state,
524 &psinfo->pr_lwp.pr_sname);
525 fill_scheduling_class(psinfo->pr_lwp.pr_clname,
526 sizeof(psinfo->pr_lwp.pr_clname));
529 static void fill_pstatus(vki_pstatus_t *pstatus,
530 const ThreadState *tst,
531 const vki_siginfo_t *si)
533 VG_(memset)(pstatus, 0, sizeof(*pstatus));
535 pstatus->pr_flags = VKI_PR_PCINVAL;
536 pstatus->pr_nlwp = VG_(count_living_threads)();
537 pstatus->pr_pid = VG_(getpid)();
538 pstatus->pr_ppid = VG_(getppid)();
539 pstatus->pr_pgid = VG_(getpgrp)();
540 pstatus->pr_sid = VG_(getpgrp)();
541 pstatus->pr_brkbase = (uintptr_t) VG_(brk_base);
542 pstatus->pr_brksize = VG_(brk_limit) - VG_(brk_base);
543 pstatus->pr_stkbase = (uintptr_t) compute_stkbase(tst);
544 pstatus->pr_stksize = tst->client_stack_szB;
545 pstatus->pr_dmodel = get_dmodel();
546 pstatus->pr_zoneid = get_zoneid();
548 pstatus->pr_lwp.pr_flags = VKI_PR_PCINVAL;
549 pstatus->pr_lwp.pr_lwpid = tst->os_state.lwpid;
550 fill_siginfo(si, &pstatus->pr_lwp.pr_info,
551 &pstatus->pr_lwp.pr_cursig);
552 pstatus->pr_lwp.pr_lwphold = tst->sig_mask;
553 fill_scheduling_class(pstatus->pr_lwp.pr_clname,
554 sizeof(pstatus->pr_lwp.pr_clname));
555 fill_regset(&pstatus->pr_lwp.pr_reg, tst);
556 fill_fpregset(&pstatus->pr_lwp.pr_fpreg, tst);
559 #if defined(SOLARIS_PRXREGSET_T)
560 static void fill_xregs(vki_prxregset_t *xregs, const ThreadState *tst)
562 const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
564 #if defined(VGP_x86_solaris)
565 VG_(memset)(xregs, 0, sizeof(*xregs));
566 xregs->pr_xsize = sizeof(xregs->pr_un.pr_xsave);
568 /* SSE */
569 UInt mxcsr = LibVEX_GuestX86_get_mxcsr(CONST_CAST(VexGuestX86State *,
570 &arch->vex));
571 xregs->pr_un.pr_xsave.pr_mxcsr = mxcsr;
573 /* XMM registers */
574 #define COPY_OUT_XMM(dest, src) \
575 do { \
576 dest._l[0] = src[0]; \
577 dest._l[1] = src[1]; \
578 dest._l[2] = src[2]; \
579 dest._l[3] = src[3]; \
580 } while (0);
581 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[0], arch->vex.guest_XMM0);
582 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[1], arch->vex.guest_XMM1);
583 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[2], arch->vex.guest_XMM2);
584 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[3], arch->vex.guest_XMM3);
585 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[4], arch->vex.guest_XMM4);
586 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[5], arch->vex.guest_XMM5);
587 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[6], arch->vex.guest_XMM6);
588 COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[7], arch->vex.guest_XMM7);
589 #undef COPY_OUT_XMM
591 #elif defined(VGP_amd64_solaris)
592 VG_(memset)(xregs, 0, sizeof(*xregs));
593 xregs->pr_xsize = sizeof(xregs->pr_un.pr_xsave);
595 /* LibVEX_GuestAMD64_fxsave() requires at least 416 bytes. */
596 vg_assert(sizeof(xregs->pr_un.pr_xsave) >= 416);
597 LibVEX_GuestAMD64_fxsave(CONST_CAST(VexGuestAMD64State *, &arch->vex),
598 (Addr) &xregs->pr_un.pr_xsave);
599 #else
600 # error "Unknown platform"
601 #endif
603 #endif /* SOLARIS_PRXREGSET_T */
605 static void fill_utsname(struct vki_utsname *uts)
607 VG_(memset)(uts, 0, sizeof(*uts));
609 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_SYSNAME,
610 (UWord) &uts->sysname, sizeof(uts->sysname));
611 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_HOSTNAME,
612 (UWord) &uts->nodename, sizeof(uts->nodename));
613 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_RELEASE,
614 (UWord) &uts->release, sizeof(uts->release));
615 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_VERSION,
616 (UWord) &uts->version, sizeof(uts->version));
617 VG_(do_syscall3)(SYS_systeminfo, VKI_SI_MACHINE,
618 (UWord) &uts->machine, sizeof(uts->machine));
621 static vki_prcred_t *create_prcred(SizeT *size)
623 UInt group_list[VKI_NGROUPS_MAX];
624 Int ngroups = VG_(getgroups)(VKI_NGROUPS_MAX, group_list);
625 if (ngroups == -1)
626 ngroups = 0;
628 *size = sizeof(vki_prcred_t) + (ngroups - 1) * sizeof(gid_t);
629 vki_prcred_t *prcred = VG_(malloc)("coredump-elf.cp.1", *size);
630 VG_(memset)(prcred, 0, *size);
632 prcred->pr_euid = VG_(geteuid)();
633 prcred->pr_ruid = get_uid();
634 prcred->pr_suid = prcred->pr_euid;
635 prcred->pr_egid = VG_(getegid)();
636 prcred->pr_rgid = get_gid();
637 prcred->pr_sgid = prcred->pr_egid;
638 prcred->pr_ngroups = ngroups;
640 UInt i;
641 for (i = 0; i < ngroups; i++)
642 prcred->pr_groups[i] = group_list[i];
644 return prcred;
647 static void fill_core_content(vki_core_content_t *content)
649 *content = VKI_CC_CONTENT_STACK | VKI_CC_CONTENT_HEAP
650 | VKI_CC_CONTENT_SHANON | VKI_CC_CONTENT_TEXT
651 | VKI_CC_CONTENT_DATA | VKI_CC_CONTENT_RODATA
652 | VKI_CC_CONTENT_ANON | VKI_CC_CONTENT_SHM
653 | VKI_CC_CONTENT_ISM | VKI_CC_CONTENT_DISM;
656 static vki_prpriv_t *create_prpriv(SizeT *size)
658 Int fd = VG_(fd_open)("/proc/self/priv", O_RDONLY, 0);
659 if (fd < 0)
660 return NULL;
662 struct vg_stat stats;
663 if (VG_(fstat)(fd, &stats) != 0) {
664 VG_(close)(fd);
665 return NULL;
668 vki_prpriv_t *prpriv = VG_(malloc)("coredump-elf.cp.1", stats.size);
670 if (VG_(read)(fd, prpriv, stats.size) != stats.size) {
671 VG_(free)(prpriv);
672 VG_(close)(fd);
673 return NULL;
676 VG_(close)(fd);
677 *size = stats.size;
678 return prpriv;
681 static vki_priv_impl_info_t *create_priv_info(SizeT *size)
683 /* Size of the returned priv_impl_info_t is apriori unknown. */
684 vki_priv_impl_info_t first_cut[100];
685 SysRes sres = VG_(do_syscall5)(SYS_privsys, VKI_PRIVSYS_GETIMPLINFO,
686 0, 0, (UWord) first_cut,
687 sizeof(first_cut));
688 if (sr_isError(sres))
689 return NULL;
691 SizeT real_size = first_cut[0].priv_headersize
692 + first_cut[0].priv_globalinfosize;
693 vki_priv_impl_info_t *priv_info = VG_(malloc)("coredump-elf.cpi.1",
694 real_size);
696 if (real_size <= sizeof(first_cut)) {
697 /* if the first_cut was large enough */
698 VG_(memcpy)(priv_info, first_cut, real_size);
699 } else {
700 /* otherwise repeat the syscall with buffer large enough */
701 sres = VG_(do_syscall5)(SYS_privsys, VKI_PRIVSYS_GETIMPLINFO,
702 0, 0, (UWord) priv_info, real_size);
703 if (sr_isError(sres)) {
704 VG_(free)(priv_info);
705 return NULL;
709 *size = real_size;
710 return priv_info;
713 static void fill_lwpsinfo(vki_lwpsinfo_t *lwp,
714 const ThreadState *tst)
716 VG_(memset)(lwp, 0, sizeof(*lwp));
718 lwp->pr_lwpid = tst->os_state.lwpid;
719 fill_thread_state(tst, &lwp->pr_state, &lwp->pr_sname);
720 fill_scheduling_class(lwp->pr_clname, sizeof(lwp->pr_clname));
723 static void fill_lwpstatus(vki_lwpstatus_t *lwp,
724 const ThreadState *tst,
725 const vki_siginfo_t *si)
727 VG_(memset)(lwp, 0, sizeof(*lwp));
729 lwp->pr_flags = VKI_PR_PCINVAL;
730 lwp->pr_lwpid = tst->os_state.lwpid;
731 fill_siginfo(si, &lwp->pr_info, &lwp->pr_cursig);
732 fill_scheduling_class(lwp->pr_clname, sizeof(lwp->pr_clname));
733 fill_regset(&lwp->pr_reg, tst);
734 fill_fpregset(&lwp->pr_fpreg, tst);
737 static void fill_old_note_for_thread(note_t **notes,
738 const ThreadState *tst,
739 const vki_siginfo_t *si)
741 vki_elf_prstatus_t prstatus;
742 fill_prstatus(&prstatus, tst, si);
743 add_note(notes, VKI_NT_PRSTATUS, &prstatus, sizeof(vki_elf_prstatus_t));
745 vki_fpregset_t fpu;
746 fill_fpregset(&fpu, tst);
747 add_note(notes, VKI_NT_PRFPREG, &fpu, sizeof(vki_fpregset_t));
749 #if defined(SOLARIS_PRXREGSET_T)
750 if (should_dump_xregs(tst)) {
751 vki_prxregset_t xregs;
752 fill_xregs(&xregs, tst);
753 add_note(notes, VKI_NT_PRXREG, &xregs, sizeof(vki_prxregset_t));
755 #endif /* SOLARIS_PRXREGSET_T */
758 static void fill_new_note_for_thread(note_t **notes,
759 const ThreadState *tst,
760 const vki_siginfo_t *si)
762 vki_lwpsinfo_t lwpsinfo;
763 fill_lwpsinfo(&lwpsinfo, tst);
764 add_note(notes, VKI_NT_LWPSINFO, &lwpsinfo, sizeof(vki_lwpsinfo_t));
766 vki_lwpstatus_t lwpstatus;
767 fill_lwpstatus(&lwpstatus, tst, si);
768 add_note(notes, VKI_NT_LWPSTATUS, &lwpstatus, sizeof(vki_lwpstatus_t));
770 #if defined(SOLARIS_PRXREGSET_T)
771 if (should_dump_xregs(tst)) {
772 vki_prxregset_t xregs;
773 fill_xregs(&xregs, tst);
774 add_note(notes, VKI_NT_PRXREG, &xregs, sizeof(vki_prxregset_t));
776 #endif /* SOLARIS_PRXREGSET_T */
779 /*====================================================================*/
780 /*=== Note utility functions ===*/
781 /*====================================================================*/
783 static void add_note(note_t **list, UInt type, const void *data,
784 UInt datasz)
786 UInt note_size = sizeof(note_t) + VG_ROUNDUP(datasz, 4);
788 note_t *n = VG_(malloc)("coredump-elf.an.1", note_size);
790 VG_(memset)(n, 0, note_size);
791 n->nhdr.n_type = type;
792 n->nhdr.n_namesz = 5;
793 n->nhdr.n_descsz = VG_ROUNDUP(datasz, 4);
794 VG_(memcpy)(n->name, "CORE", 4);
795 VG_(memcpy)(n->data, data, datasz);
797 if (*list == NULL) {
798 *list = n;
799 return;
802 note_t *tail = *list;
803 while (tail->next != NULL)
804 tail = tail->next;
805 tail->next = n;
808 static UInt note_size(const note_t *note)
810 return sizeof(note_t) - sizeof(note_t *) + note->nhdr.n_descsz;
813 static UInt notes_size(const note_t *list)
815 UInt size = 0;
816 const note_t *note;
818 for (note = list; note != NULL; note = note->next)
819 size += note_size(note);
821 return size;
824 static void fill_notes_phdr(VKI_ESZ(Phdr) *phdr, UInt offset,
825 UInt size_of_notes)
827 phdr->p_type = PT_NOTE;
828 phdr->p_offset = offset;
829 phdr->p_vaddr = 0;
830 phdr->p_paddr = 0;
831 phdr->p_filesz = size_of_notes;
832 phdr->p_memsz = 0;
833 phdr->p_flags = PF_R;
834 phdr->p_align = 0;
837 static void write_notes(Int fd, const HChar *filename,
838 const note_t *list)
840 const note_t *note;
842 for (note = list; note != NULL; note = note->next)
843 write_part(fd, filename, CONST_CAST(void *, &note->nhdr),
844 note_size(note), "notes");
847 static void free_notes(note_t *list)
849 while (list != NULL) {
850 note_t *next = list->next;
851 VG_(free)(list);
852 list = next;
856 /*====================================================================*/
857 /*=== Main coredump function ===*/
858 /*====================================================================*/
860 void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si,
861 ULong max_size)
863 const HChar *basename = "vgcore";
864 const HChar *coreext = "";
865 Int core_fd;
867 if (VG_(clo_log_fname_unexpanded) != NULL) {
868 coreext = ".core";
869 basename = VG_(expand_file_name)("--log-file",
870 VG_(clo_log_fname_unexpanded));
873 vg_assert(coreext != NULL);
874 vg_assert(basename != NULL);
876 UInt filename_size = VG_(strlen)(coreext) + VG_(strlen)(basename)
877 + 100; /* for the two %d's */
878 HChar *filename = VG_(malloc)("coredump-elf.mc.1", filename_size);
880 /* Try to come with a non-existent coredump filename. */
881 UInt seq = 0;
882 for (;;) {
883 Int oflags = VKI_O_CREAT|VKI_O_WRONLY|VKI_O_EXCL|VKI_O_TRUNC;
885 if (seq == 0)
886 VG_(snprintf)(filename, filename_size, "%s%s.%d",
887 basename, coreext, VG_(getpid)());
888 else
889 VG_(snprintf)(filename, filename_size, "%s%s.%d.%u",
890 basename, coreext, VG_(getpid)(), seq);
891 seq++;
893 #ifdef VKI_O_LARGEFILE
894 oflags |= VKI_O_LARGEFILE;
895 #endif
897 SysRes sres = VG_(open)(filename, oflags,
898 VKI_S_IRUSR|VKI_S_IWUSR);
899 if (!sr_isError(sres)) {
900 core_fd = sr_Res(sres);
901 break;
904 if (sr_isError(sres) && sr_Err(sres) != VKI_EEXIST) {
905 VG_(umsg)("Cannot create coredump file %s (%lu)\n",
906 filename, sr_Err(sres));
907 VG_(free)(filename);
908 return;
912 /* Get the client segments. Free seg_starts after use. */
913 Int n_seg_starts;
914 Addr *seg_starts = VG_(get_segment_starts)(SkFileC | SkAnonC | SkShmC,
915 &n_seg_starts);
917 /* Count how many memory segments to dump. */
918 Int i;
919 UInt num_phdrs = 2; /* two CORE note sections */
920 for (i = 0; i < n_seg_starts; i++) {
921 if (!may_dump(VG_(am_find_nsegment)(seg_starts[i])))
922 continue;
924 num_phdrs++;
927 VKI_ESZ(Ehdr) ehdr;
928 fill_ehdr(&ehdr, num_phdrs);
930 VKI_ESZ(Shdr) shdr;
931 if (ehdr.e_shnum > 0)
932 fill_zero_shdr(&shdr, num_phdrs);
933 UInt phdrs_size = num_phdrs * ehdr.e_phentsize;
935 /* Construct the old-style notes. */
936 note_t *old_notes = NULL;
938 vki_elf_prpsinfo_t prpsinfo;
939 fill_prpsinfo(&prpsinfo, &VG_(threads)[tid], si);
940 add_note(&old_notes, VKI_NT_PRPSINFO, &prpsinfo,
941 sizeof(vki_elf_prpsinfo_t));
943 HChar platform[256 + 1];
944 fill_platform(platform, sizeof(platform));
945 add_note(&old_notes, VKI_NT_PLATFORM, platform,
946 VG_(strlen)(platform) + 1);
948 add_note(&old_notes, VKI_NT_AUXV, VG_(client_auxv),
949 count_auxv() * sizeof(auxv_t));
951 /* Add detail about the faulting thread as the first note.
952 This is how gdb determines which thread faulted. Note that
953 mdb does not need such aid. */
954 fill_old_note_for_thread(&old_notes, &VG_(threads)[tid], si);
956 /* Now add details for all threads except the one that faulted. */
957 ThreadId t_idx;
958 for (t_idx = 1; t_idx < VG_N_THREADS; t_idx++)
959 if ((VG_(threads)[t_idx].status != VgTs_Empty) &&
960 (VG_(threads)[t_idx].status != VgTs_Zombie)) {
961 if (t_idx == tid)
962 continue;
964 fill_old_note_for_thread(&old_notes, &VG_(threads)[t_idx], si);
967 /* Construct the new-style notes. */
968 note_t *new_notes = NULL;
969 vki_psinfo_t psinfo;
970 fill_psinfo(&psinfo, &VG_(threads)[tid], si);
971 add_note(&new_notes, VKI_NT_PSINFO, &psinfo, sizeof(vki_psinfo_t));
973 vki_pstatus_t pstatus;
974 fill_pstatus(&pstatus, &VG_(threads)[tid], si);
975 add_note(&new_notes, VKI_NT_PSTATUS, &pstatus, sizeof(vki_pstatus_t));
977 add_note(&new_notes, VKI_NT_PLATFORM, platform,
978 VG_(strlen)(platform) + 1);
980 add_note(&new_notes, VKI_NT_AUXV, VG_(client_auxv),
981 count_auxv() * sizeof(auxv_t));
983 struct vki_utsname uts;
984 fill_utsname(&uts);
985 add_note(&new_notes, VKI_NT_UTSNAME, &uts,
986 sizeof(struct vki_utsname));
988 SizeT prcred_size;
989 vki_prcred_t *prcred = create_prcred(&prcred_size);
990 if (prcred != NULL) {
991 add_note(&new_notes, VKI_NT_PRCRED, prcred, prcred_size);
992 VG_(free)(prcred);
995 vki_core_content_t core_content;
996 fill_core_content(&core_content);
997 add_note(&new_notes, VKI_NT_CONTENT, &core_content,
998 sizeof(vki_core_content_t));
1000 SizeT priv_size;
1001 vki_prpriv_t *prpriv = create_prpriv(&priv_size);
1002 if (prpriv != NULL) {
1003 add_note(&new_notes, VKI_NT_PRPRIV, prpriv, priv_size);
1004 VG_(free)(prpriv);
1007 vki_priv_impl_info_t *priv_info = create_priv_info(&priv_size);
1008 if (priv_info != NULL) {
1009 add_note(&new_notes, VKI_NT_PRPRIVINFO, priv_info, priv_size);
1010 VG_(free)(priv_info);
1013 HChar zonename[VKI_ZONENAME_MAX + 1];
1014 fill_zonename(zonename, sizeof(zonename));
1015 add_note(&new_notes, VKI_NT_ZONENAME, zonename,
1016 VG_(strlen)(zonename) + 1);
1018 /* Add detail about the faulting thread as the first note.
1019 This is how gdb determines which thread faulted. Note that
1020 mdb does not need such aid. */
1021 fill_new_note_for_thread(&new_notes, &VG_(threads)[tid], si);
1023 /* Now add details for all threads except the one that faulted. */
1024 for (t_idx = 1; t_idx < VG_N_THREADS; t_idx++) {
1025 if ((VG_(threads)[t_idx].status != VgTs_Empty) &&
1026 (VG_(threads)[t_idx].status != VgTs_Zombie)) {
1027 if (t_idx == tid)
1028 continue;
1030 fill_new_note_for_thread(&new_notes, &VG_(threads)[t_idx], si);
1034 VKI_ESZ(Phdr) *phdrs = VG_(malloc)("coredump-elf.mc.2", phdrs_size);
1036 UInt size_of_notes = notes_size(old_notes);
1037 UInt offset = ehdr.e_ehsize + phdrs_size +
1038 (ehdr.e_shnum * ehdr.e_shentsize);
1040 /* fill program header for old notes */
1041 fill_notes_phdr(&phdrs[0], offset, size_of_notes);
1042 offset += size_of_notes;
1044 size_of_notes = notes_size(new_notes);
1045 /* fill program header for new notes */
1046 fill_notes_phdr(&phdrs[1], offset, size_of_notes);
1047 offset += size_of_notes;
1049 /* fill program headers for segments */
1050 UInt idx;
1051 for (i = 0, idx = 2; i < n_seg_starts; i++) {
1052 NSegment const *seg = VG_(am_find_nsegment)(seg_starts[i]);
1054 if (!may_dump(seg))
1055 continue;
1057 fill_phdr(&phdrs[idx], seg, offset,
1058 (seg->end - seg->start + 1 + offset) < max_size);
1060 offset += phdrs[idx].p_filesz;
1062 idx++;
1065 /* write everything out */
1066 write_part(core_fd, filename, &ehdr, sizeof(ehdr),
1067 "elf headers");
1068 write_part(core_fd, filename, phdrs, phdrs_size,
1069 "program headers");
1070 if (ehdr.e_shnum > 0)
1071 write_part(core_fd, filename, &shdr, sizeof(shdr),
1072 "section headers");
1073 write_notes(core_fd, filename, old_notes);
1074 write_notes(core_fd, filename, new_notes);
1076 VG_(lseek)(core_fd, phdrs[2].p_offset, VKI_SEEK_SET);
1078 for (i = 0, idx = 2; i < n_seg_starts; i++) {
1079 NSegment const *seg = VG_(am_find_nsegment)(seg_starts[i]);
1081 if (!should_dump(seg))
1082 continue;
1084 if (phdrs[idx].p_filesz > 0) {
1085 Off64T off = VG_(lseek)(core_fd, phdrs[idx].p_offset,
1086 VKI_SEEK_SET);
1087 vg_assert(off == phdrs[idx].p_offset);
1088 vg_assert(seg->end - seg->start + 1 >= phdrs[idx].p_filesz);
1090 write_part(core_fd, filename, (void *) seg->start,
1091 phdrs[idx].p_filesz, "program segment");
1093 idx++;
1096 VG_(close)(core_fd);
1097 VG_(free)(filename);
1098 VG_(free)(phdrs);
1099 free_notes(old_notes);
1100 free_notes(new_notes);
1101 VG_(free)(seg_starts);
1104 #endif
1106 /*--------------------------------------------------------------------*/
1107 /*--- end ---*/
1108 /*--------------------------------------------------------------------*/