Home | History | Annotate | Download | only in m_coredump
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- Dumping core.                                 coredump-elf.c ---*/
      4 /*--------------------------------------------------------------------*/
      5 
      6 /*
      7    This file is part of Valgrind, a dynamic binary instrumentation
      8    framework.
      9 
     10    Copyright (C) 2000-2010 Julian Seward
     11       jseward (at) acm.org
     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_linux)
     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_libcbase.h"
     38 #include "pub_core_machine.h"
     39 #include "pub_core_coredump.h"
     40 #include "pub_core_libcprint.h"
     41 #include "pub_core_libcfile.h"    // VG_(close) et al
     42 #include "pub_core_libcproc.h"    // VG_(geteuid), VG_(getegid)
     43 #include "pub_core_libcassert.h"  // VG_(exit), vg_assert
     44 #include "pub_core_mallocfree.h"  // VG_(malloc), VG_(free)
     45 #include "pub_core_threadstate.h"
     46 #include "pub_core_xarray.h"
     47 #include "pub_core_clientstate.h"
     48 #include "pub_core_options.h"
     49 
     50 /*
     51   Dump core
     52 
     53   Generate a standard ELF core file corresponding to the client state
     54   at the time of a crash.
     55  */
     56 #ifdef ANDROID
     57 #include <linux/elf.h>
     58 #define NT_FPREGSET 2
     59 #else
     60 #include <elf.h>
     61 #endif
     62 #ifndef NT_PRXFPREG
     63 #define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
     64 #endif /* NT_PRXFPREG */
     65 
     66 #if	VG_WORDSIZE == 8
     67 #define ESZ(x)	Elf64_##x
     68 #elif	VG_WORDSIZE == 4
     69 #define ESZ(x)	Elf32_##x
     70 #else
     71 #error VG_WORDSIZE needs to ==4 or ==8
     72 #endif
     73 
     74 /* If true, then this Segment may be mentioned in the core */
     75 static Bool may_dump(const NSegment *seg)
     76 {
     77    if (seg->kind == SkAnonC ||
     78        seg->kind == SkShmC ||
     79        (seg->kind == SkFileC &&
     80         !VKI_S_ISCHR(seg->mode) && !VKI_S_ISBLK(seg->mode)))
     81       return True;
     82 
     83    return False;
     84 }
     85 
     86 /* If true, then this Segment's contents will be in the core */
     87 static Bool should_dump(const NSegment *seg)
     88 {
     89    return may_dump(seg); // && seg->hasW;
     90 }
     91 
     92 static void fill_ehdr(ESZ(Ehdr) *ehdr, Int num_phdrs)
     93 {
     94    VG_(memset)(ehdr, 0, sizeof(*ehdr));
     95 
     96    VG_(memcpy)(ehdr->e_ident, ELFMAG, SELFMAG);
     97    ehdr->e_ident[EI_CLASS]   = VG_ELF_CLASS;
     98    ehdr->e_ident[EI_DATA]    = VG_ELF_DATA2XXX;
     99    ehdr->e_ident[EI_VERSION] = EV_CURRENT;
    100 
    101    ehdr->e_type = ET_CORE;
    102    ehdr->e_machine = VG_ELF_MACHINE;
    103    ehdr->e_version = EV_CURRENT;
    104    ehdr->e_entry = 0;
    105    ehdr->e_phoff = sizeof(ESZ(Ehdr));
    106    ehdr->e_shoff = 0;
    107    ehdr->e_flags = 0;
    108    ehdr->e_ehsize = sizeof(ESZ(Ehdr));
    109    ehdr->e_phentsize = sizeof(ESZ(Phdr));
    110    ehdr->e_phnum = num_phdrs;
    111    ehdr->e_shentsize = 0;
    112    ehdr->e_shnum = 0;
    113    ehdr->e_shstrndx = 0;
    114 
    115 }
    116 
    117 static void fill_phdr(ESZ(Phdr) *phdr, const NSegment *seg, UInt off, Bool write)
    118 {
    119    SizeT len = seg->end - seg->start;
    120 
    121    write = write && should_dump(seg);
    122 
    123    VG_(memset)(phdr, 0, sizeof(*phdr));
    124 
    125    phdr->p_type = PT_LOAD;
    126    phdr->p_offset = off;
    127    phdr->p_vaddr = seg->start;
    128    phdr->p_paddr = 0;
    129    phdr->p_filesz = write ? len : 0;
    130    phdr->p_memsz = len;
    131    phdr->p_flags = 0;
    132 
    133    if (seg->hasR)
    134       phdr->p_flags |= PF_R;
    135    if (seg->hasW)
    136       phdr->p_flags |= PF_W;
    137    if (seg->hasX)
    138       phdr->p_flags |= PF_X;
    139 
    140    phdr->p_align = VKI_PAGE_SIZE;
    141 }
    142 
    143 struct note {
    144    struct note *next;
    145    ESZ(Nhdr) note;
    146    Char name[0];
    147 };
    148 
    149 static UInt note_size(const struct note *n)
    150 {
    151    return sizeof(ESZ(Nhdr)) + VG_ROUNDUP(VG_(strlen)(n->name)+1, 4) + VG_ROUNDUP(n->note.n_descsz, 4);
    152 }
    153 
    154 static void add_note(struct note **list, const Char *name, UInt type, const void *data, UInt datasz)
    155 {
    156    Int namelen = VG_(strlen)(name)+1;
    157    Int notelen = sizeof(struct note) +
    158       VG_ROUNDUP(namelen, 4) +
    159       VG_ROUNDUP(datasz, 4);
    160    struct note *n = VG_(arena_malloc)(VG_AR_CORE, "coredump-elf.an.1", notelen);
    161 
    162    VG_(memset)(n, 0, notelen);
    163 
    164    n->next = *list;
    165    *list = n;
    166 
    167    n->note.n_type = type;
    168    n->note.n_namesz = namelen;
    169    n->note.n_descsz = datasz;
    170 
    171    VG_(memcpy)(n->name, name, namelen);
    172    VG_(memcpy)(n->name+VG_ROUNDUP(namelen,4), data, datasz);
    173 }
    174 
    175 static void write_note(Int fd, const struct note *n)
    176 {
    177    VG_(write)(fd, &n->note, note_size(n));
    178 }
    179 
    180 static void fill_prpsinfo(const ThreadState *tst, struct vki_elf_prpsinfo *prpsinfo)
    181 {
    182    static Char name[VKI_PATH_MAX];
    183 
    184    VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
    185 
    186    switch(tst->status) {
    187    case VgTs_Runnable:
    188    case VgTs_Yielding:
    189       prpsinfo->pr_sname = 'R';
    190       break;
    191 
    192    case VgTs_WaitSys:
    193       prpsinfo->pr_sname = 'S';
    194       break;
    195 
    196    case VgTs_Zombie:
    197       prpsinfo->pr_sname = 'Z';
    198       break;
    199 
    200    case VgTs_Empty:
    201    case VgTs_Init:
    202       prpsinfo->pr_sname = '?';
    203       break;
    204    }
    205 
    206    prpsinfo->pr_uid = 0;
    207    prpsinfo->pr_gid = 0;
    208 
    209    if (VG_(resolve_filename)(VG_(cl_exec_fd), name, VKI_PATH_MAX)) {
    210       Char *n = name+VG_(strlen)(name)-1;
    211 
    212       while (n > name && *n != '/')
    213 	 n--;
    214       if (n != name)
    215 	 n++;
    216 
    217       VG_(strncpy)(prpsinfo->pr_fname, n, sizeof(prpsinfo->pr_fname));
    218    }
    219 }
    220 
    221 static void fill_prstatus(const ThreadState *tst,
    222 			  struct vki_elf_prstatus *prs,
    223 			  const vki_siginfo_t *si)
    224 {
    225    struct vki_user_regs_struct *regs;
    226    ThreadArchState* arch = (ThreadArchState*)&tst->arch;
    227 
    228    VG_(memset)(prs, 0, sizeof(*prs));
    229 
    230    prs->pr_info.si_signo = si->si_signo;
    231    prs->pr_info.si_code = si->si_code;
    232    prs->pr_info.si_errno = 0;
    233 
    234    prs->pr_cursig = si->si_signo;
    235 
    236    prs->pr_pid = tst->os_state.lwpid;
    237    prs->pr_ppid = 0;
    238    prs->pr_pgrp = VG_(getpgrp)();
    239    prs->pr_sid = VG_(getpgrp)();
    240 
    241    regs = (struct vki_user_regs_struct *)prs->pr_reg;
    242 
    243    vg_assert(sizeof(*regs) == sizeof(prs->pr_reg));
    244 
    245 #if defined(VGP_x86_linux)
    246    regs->eflags = LibVEX_GuestX86_get_eflags( &arch->vex );
    247    regs->esp    = arch->vex.guest_ESP;
    248    regs->eip    = arch->vex.guest_EIP;
    249 
    250    regs->ebx    = arch->vex.guest_EBX;
    251    regs->ecx    = arch->vex.guest_ECX;
    252    regs->edx    = arch->vex.guest_EDX;
    253    regs->esi    = arch->vex.guest_ESI;
    254    regs->edi    = arch->vex.guest_EDI;
    255    regs->ebp    = arch->vex.guest_EBP;
    256    regs->eax    = arch->vex.guest_EAX;
    257 
    258    regs->cs     = arch->vex.guest_CS;
    259    regs->ds     = arch->vex.guest_DS;
    260    regs->ss     = arch->vex.guest_SS;
    261    regs->es     = arch->vex.guest_ES;
    262    regs->fs     = arch->vex.guest_FS;
    263    regs->gs     = arch->vex.guest_GS;
    264 
    265 #elif defined(VGP_amd64_linux)
    266    regs->eflags = LibVEX_GuestAMD64_get_rflags( &((ThreadArchState*)arch)->vex );
    267    regs->rsp    = arch->vex.guest_RSP;
    268    regs->rip    = arch->vex.guest_RIP;
    269 
    270    regs->rbx    = arch->vex.guest_RBX;
    271    regs->rcx    = arch->vex.guest_RCX;
    272    regs->rdx    = arch->vex.guest_RDX;
    273    regs->rsi    = arch->vex.guest_RSI;
    274    regs->rdi    = arch->vex.guest_RDI;
    275    regs->rbp    = arch->vex.guest_RBP;
    276    regs->rax    = arch->vex.guest_RAX;
    277    regs->r8     = arch->vex.guest_R8;
    278    regs->r9     = arch->vex.guest_R9;
    279    regs->r10    = arch->vex.guest_R10;
    280    regs->r11    = arch->vex.guest_R11;
    281    regs->r12    = arch->vex.guest_R12;
    282    regs->r13    = arch->vex.guest_R13;
    283    regs->r14    = arch->vex.guest_R14;
    284    regs->r15    = arch->vex.guest_R15;
    285 
    286 //::    regs->cs     = arch->vex.guest_CS;
    287 //::    regs->fs     = arch->vex.guest_FS;
    288 //::    regs->gs     = arch->vex.guest_GS;
    289 
    290 #elif defined(VGP_ppc32_linux)
    291 #  define DO(n)  regs->gpr[n] = arch->vex.guest_GPR##n
    292    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    293    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    294    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    295    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    296 #  undef DO
    297 
    298    regs->nip = arch->vex.guest_CIA;
    299    regs->msr = 0xf032;   /* pretty arbitrary */
    300    regs->orig_gpr3 = arch->vex.guest_GPR3;
    301    regs->ctr = arch->vex.guest_CTR;
    302    regs->link = arch->vex.guest_LR;
    303    regs->xer = LibVEX_GuestPPC32_get_XER( &((ThreadArchState*)arch)->vex );
    304    regs->ccr = LibVEX_GuestPPC32_get_CR( &((ThreadArchState*)arch)->vex );
    305    regs->mq = 0;
    306    regs->trap = 0;
    307    regs->dar = 0; /* should be fault address? */
    308    regs->dsisr = 0;
    309    regs->result = 0;
    310 
    311 #elif defined(VGP_ppc64_linux)
    312 #  define DO(n)  regs->gpr[n] = arch->vex.guest_GPR##n
    313    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    314    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    315    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    316    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    317 #  undef DO
    318 
    319    regs->nip = arch->vex.guest_CIA;
    320    regs->msr = 0xf032;   /* pretty arbitrary */
    321    regs->orig_gpr3 = arch->vex.guest_GPR3;
    322    regs->ctr = arch->vex.guest_CTR;
    323    regs->link = arch->vex.guest_LR;
    324    regs->xer = LibVEX_GuestPPC64_get_XER( &((ThreadArchState*)arch)->vex );
    325    regs->ccr = LibVEX_GuestPPC64_get_CR( &((ThreadArchState*)arch)->vex );
    326    /* regs->mq = 0; */
    327    regs->trap = 0;
    328    regs->dar = 0; /* should be fault address? */
    329    regs->dsisr = 0;
    330    regs->result = 0;
    331 
    332 #elif defined(VGP_arm_linux)
    333    regs->ARM_r0   = arch->vex.guest_R0;
    334    regs->ARM_r1   = arch->vex.guest_R1;
    335    regs->ARM_r2   = arch->vex.guest_R2;
    336    regs->ARM_r3   = arch->vex.guest_R3;
    337    regs->ARM_r4   = arch->vex.guest_R4;
    338    regs->ARM_r5   = arch->vex.guest_R5;
    339    regs->ARM_r6   = arch->vex.guest_R6;
    340    regs->ARM_r7   = arch->vex.guest_R7;
    341    regs->ARM_r8   = arch->vex.guest_R8;
    342    regs->ARM_r9   = arch->vex.guest_R9;
    343    regs->ARM_r10  = arch->vex.guest_R10;
    344    regs->ARM_fp   = arch->vex.guest_R11;
    345    regs->ARM_ip   = arch->vex.guest_R12;
    346    regs->ARM_sp   = arch->vex.guest_R13;
    347    regs->ARM_lr   = arch->vex.guest_R14;
    348    regs->ARM_pc   = arch->vex.guest_R15T;
    349    regs->ARM_cpsr = LibVEX_GuestARM_get_cpsr( &((ThreadArchState*)arch)->vex );
    350 
    351 #else
    352 #  error Unknown ELF platform
    353 #endif
    354 }
    355 
    356 static void fill_fpu(const ThreadState *tst, vki_elf_fpregset_t *fpu)
    357 {
    358    __attribute__((unused))
    359    ThreadArchState* arch = (ThreadArchState*)&tst->arch;
    360 
    361 #if defined(VGP_x86_linux)
    362 //:: static void fill_fpu(vki_elf_fpregset_t *fpu, const Char *from)
    363 //:: {
    364 //::    if (VG_(have_ssestate)) {
    365 //::       UShort *to;
    366 //::       Int i;
    367 //::
    368 //::       /* This is what the kernel does */
    369 //::       VG_(memcpy)(fpu, from, 7*sizeof(long));
    370 //::
    371 //::       to = (UShort *)&fpu->st_space[0];
    372 //::       from += 18 * sizeof(UShort);
    373 //::
    374 //::       for (i = 0; i < 8; i++, to += 5, from += 8)
    375 //:: 	 VG_(memcpy)(to, from, 5*sizeof(UShort));
    376 //::    } else
    377 //::       VG_(memcpy)(fpu, from, sizeof(*fpu));
    378 //:: }
    379 
    380 //::    fill_fpu(fpu, (const Char *)&arch->m_sse);
    381 
    382 #elif defined(VGP_amd64_linux)
    383 //::    fpu->cwd = ?;
    384 //::    fpu->swd = ?;
    385 //::    fpu->twd = ?;
    386 //::    fpu->fop = ?;
    387 //::    fpu->rip = ?;
    388 //::    fpu->rdp = ?;
    389 //::    fpu->mxcsr = ?;
    390 //::    fpu->mxcsr_mask = ?;
    391 //::    fpu->st_space = ?;
    392 
    393 #  define DO(n)  VG_(memcpy)(fpu->xmm_space + n * 4, &arch->vex.guest_XMM##n, sizeof(arch->vex.guest_XMM##n))
    394    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    395    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    396 #  undef DO
    397 
    398    VG_(memset)(fpu->padding, 0, sizeof(fpu->padding));
    399 
    400 #elif defined(VGP_ppc32_linux)
    401    /* The guest state has the FPR fields declared as ULongs, so need
    402       to fish out the values without converting them. */
    403 #  define DO(n)  (*fpu)[n] = *(double*)(&arch->vex.guest_FPR##n)
    404    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    405    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    406    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    407    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    408 #  undef DO
    409 
    410 #elif defined(VGP_ppc64_linux)
    411    /* The guest state has the FPR fields declared as ULongs, so need
    412       to fish out the values without converting them. */
    413 #  define DO(n)  (*fpu)[n] = *(double*)(&arch->vex.guest_FPR##n)
    414    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    415    DO(8);  DO(9);  DO(10); DO(11); DO(12); DO(13); DO(14); DO(15);
    416    DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23);
    417    DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31);
    418 #  undef DO
    419 
    420 #elif defined(VGP_arm_linux)
    421    // umm ...
    422 
    423 #else
    424 #  error Unknown ELF platform
    425 #endif
    426 }
    427 
    428 #if defined(VGP_x86_linux)
    429 static void fill_xfpu(const ThreadState *tst, vki_elf_fpxregset_t *xfpu)
    430 {
    431    ThreadArchState* arch = (ThreadArchState*)&tst->arch;
    432 
    433 //::    xfpu->cwd = ?;
    434 //::    xfpu->swd = ?;
    435 //::    xfpu->twd = ?;
    436 //::    xfpu->fop = ?;
    437 //::    xfpu->fip = ?;
    438 //::    xfpu->fcs = ?;
    439 //::    xfpu->foo = ?;
    440 //::    xfpu->fos = ?;
    441 //::    xfpu->mxcsr = ?;
    442    xfpu->reserved = 0;
    443 //::    xfpu->st_space = ?;
    444 
    445 #  define DO(n)  VG_(memcpy)(xfpu->xmm_space + n * 4, &arch->vex.guest_XMM##n, sizeof(arch->vex.guest_XMM##n))
    446    DO(0);  DO(1);  DO(2);  DO(3);  DO(4);  DO(5);  DO(6);  DO(7);
    447 #  undef DO
    448 
    449    VG_(memset)(xfpu->padding, 0, sizeof(xfpu->padding));
    450 }
    451 #endif
    452 
    453 static
    454 void make_elf_coredump(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
    455 {
    456    Char* buf = NULL;
    457    Char *basename = "vgcore";
    458    Char *coreext = "";
    459    Int seq = 0;
    460    Int core_fd;
    461    NSegment const * seg;
    462    ESZ(Ehdr) ehdr;
    463    ESZ(Phdr) *phdrs;
    464    Int num_phdrs;
    465    Int i, idx;
    466    UInt off;
    467    struct note *notelist, *note;
    468    UInt notesz;
    469    struct vki_elf_prpsinfo prpsinfo;
    470    struct vki_elf_prstatus prstatus;
    471    Addr *seg_starts;
    472    Int n_seg_starts;
    473 
    474    if (VG_(clo_log_fname_expanded) != NULL) {
    475       coreext = ".core";
    476       basename = VG_(expand_file_name)(
    477                     "--log-file (while creating core filename)",
    478                     VG_(clo_log_fname_expanded));
    479    }
    480 
    481    vg_assert(coreext);
    482    vg_assert(basename);
    483    buf = VG_(malloc)( "coredump-elf.mec.1",
    484                       VG_(strlen)(coreext) + VG_(strlen)(basename)
    485                          + 100/*for the two %ds. */ );
    486    vg_assert(buf);
    487 
    488    for(;;) {
    489       SysRes sres;
    490 
    491       if (seq == 0)
    492 	 VG_(sprintf)(buf, "%s%s.%d",
    493 		      basename, coreext, VG_(getpid)());
    494       else
    495 	 VG_(sprintf)(buf, "%s%s.%d.%d",
    496 		      basename, coreext, VG_(getpid)(), seq);
    497       seq++;
    498 
    499       sres = VG_(open)(buf,
    500                        VKI_O_CREAT|VKI_O_WRONLY|VKI_O_EXCL|VKI_O_TRUNC,
    501                        VKI_S_IRUSR|VKI_S_IWUSR);
    502       if (!sr_isError(sres)) {
    503          core_fd = sr_Res(sres);
    504 	 break;
    505       }
    506 
    507       if (sr_isError(sres) && sr_Err(sres) != VKI_EEXIST)
    508 	 return;		/* can't create file */
    509    }
    510 
    511    /* Get the segments */
    512    seg_starts = VG_(get_segment_starts)(&n_seg_starts);
    513 
    514    /* First, count how many memory segments to dump */
    515    num_phdrs = 1;		/* start with notes */
    516    for(i = 0; i < n_seg_starts; i++) {
    517       if (!may_dump(VG_(am_find_nsegment(seg_starts[i]))))
    518 	 continue;
    519 
    520       num_phdrs++;
    521    }
    522 
    523    fill_ehdr(&ehdr, num_phdrs);
    524 
    525    notelist = NULL;
    526 
    527    /* Second, work out their layout */
    528    phdrs = VG_(arena_malloc)(VG_AR_CORE, "coredump-elf.mec.1",
    529                              sizeof(*phdrs) * num_phdrs);
    530 
    531    for(i = 1; i < VG_N_THREADS; i++) {
    532       vki_elf_fpregset_t  fpu;
    533 
    534       if (VG_(threads)[i].status == VgTs_Empty)
    535 	 continue;
    536 
    537 #if defined(VGP_x86_linux)
    538       {
    539          vki_elf_fpxregset_t xfpu;
    540          fill_xfpu(&VG_(threads)[i], &xfpu);
    541          add_note(&notelist, "LINUX", NT_PRXFPREG, &xfpu, sizeof(xfpu));
    542       }
    543 #endif
    544 
    545       fill_fpu(&VG_(threads)[i], &fpu);
    546       add_note(&notelist, "CORE", NT_FPREGSET, &fpu, sizeof(fpu));
    547 
    548       fill_prstatus(&VG_(threads)[i], &prstatus, si);
    549       add_note(&notelist, "CORE", NT_PRSTATUS, &prstatus, sizeof(prstatus));
    550    }
    551 
    552    fill_prpsinfo(&VG_(threads)[tid], &prpsinfo);
    553    add_note(&notelist, "CORE", NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo));
    554 
    555    for(note = notelist, notesz = 0; note != NULL; note = note->next)
    556       notesz += note_size(note);
    557 
    558    off = sizeof(ehdr) + sizeof(*phdrs) * num_phdrs;
    559 
    560    phdrs[0].p_type = PT_NOTE;
    561    phdrs[0].p_offset = off;
    562    phdrs[0].p_vaddr = 0;
    563    phdrs[0].p_paddr = 0;
    564    phdrs[0].p_filesz = notesz;
    565    phdrs[0].p_memsz = 0;
    566    phdrs[0].p_flags = 0;
    567    phdrs[0].p_align = 0;
    568 
    569    off += notesz;
    570 
    571    off = VG_PGROUNDUP(off);
    572 
    573    for(i = 0, idx = 1; i < n_seg_starts; i++) {
    574       seg = VG_(am_find_nsegment(seg_starts[i]));
    575 
    576       if (!may_dump(seg))
    577 	 continue;
    578 
    579       fill_phdr(&phdrs[idx], seg, off, (seg->end - seg->start + off) < max_size);
    580 
    581       off += phdrs[idx].p_filesz;
    582 
    583       idx++;
    584    }
    585 
    586    /* write everything out */
    587    VG_(write)(core_fd, &ehdr, sizeof(ehdr));
    588    VG_(write)(core_fd, phdrs, sizeof(*phdrs) * num_phdrs);
    589 
    590    for(note = notelist; note != NULL; note = note->next)
    591       write_note(core_fd, note);
    592 
    593    VG_(lseek)(core_fd, phdrs[1].p_offset, VKI_SEEK_SET);
    594 
    595    for(i = 0, idx = 1; i < n_seg_starts; i++) {
    596       seg = VG_(am_find_nsegment(seg_starts[i]));
    597 
    598       if (!should_dump(seg))
    599 	 continue;
    600 
    601       if (phdrs[idx].p_filesz > 0) {
    602 	 vg_assert(VG_(lseek)(core_fd, phdrs[idx].p_offset, VKI_SEEK_SET) == phdrs[idx].p_offset);
    603 	 vg_assert(seg->end - seg->start >= phdrs[idx].p_filesz);
    604 
    605 	 (void)VG_(write)(core_fd, (void *)seg->start, phdrs[idx].p_filesz);
    606       }
    607       idx++;
    608    }
    609 
    610    VG_(free)(seg_starts);
    611 
    612    VG_(close)(core_fd);
    613 }
    614 
    615 void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
    616 {
    617    make_elf_coredump(tid, si, max_size);
    618 }
    619 
    620 #endif // defined(VGO_linux)
    621 
    622 /*--------------------------------------------------------------------*/
    623 /*--- end                                                          ---*/
    624 /*--------------------------------------------------------------------*/
    625