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