coredump-elf.c revision cda2f0fbda4c4b2644babc830244be8aed95de1d
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-2009 Julian Seward
11      jseward@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#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_libcbase.h"
36#include "pub_core_machine.h"
37#include "pub_core_coredump.h"
38#include "pub_core_libcprint.h"
39#include "pub_core_libcfile.h"    // VG_(close) et al
40#include "pub_core_libcproc.h"    // VG_(geteuid), VG_(getegid)
41#include "pub_core_libcassert.h"  // VG_(exit), vg_assert
42#include "pub_core_mallocfree.h"  // VG_(malloc), VG_(free)
43#include "pub_core_threadstate.h"
44#include "pub_core_xarray.h"
45#include "pub_core_clientstate.h"
46#include "pub_core_options.h"
47
48#include "priv_elf.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#include <elf.h>
57#ifndef NT_PRXFPREG
58#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
59#endif /* NT_PRXFPREG */
60
61#if	VG_WORDSIZE == 8
62#define ESZ(x)	Elf64_##x
63#elif	VG_WORDSIZE == 4
64#define ESZ(x)	Elf32_##x
65#else
66#error VG_WORDSIZE needs to ==4 or ==8
67#endif
68
69/* If true, then this Segment may be mentioned in the core */
70static Bool may_dump(const NSegment *seg)
71{
72   if (seg->kind == SkAnonC ||
73       seg->kind == SkShmC ||
74       (seg->kind == SkFileC &&
75        !VKI_S_ISCHR(seg->mode) && !VKI_S_ISBLK(seg->mode)))
76      return True;
77
78   return False;
79}
80
81/* If true, then this Segment's contents will be in the core */
82static Bool should_dump(const NSegment *seg)
83{
84   return may_dump(seg); // && seg->hasW;
85}
86
87static void fill_ehdr(ESZ(Ehdr) *ehdr, Int num_phdrs)
88{
89   VG_(memset)(ehdr, 0, sizeof(*ehdr));
90
91   VG_(memcpy)(ehdr->e_ident, ELFMAG, SELFMAG);
92   ehdr->e_ident[EI_CLASS]   = VG_ELF_CLASS;
93   ehdr->e_ident[EI_DATA]    = VG_ELF_DATA2XXX;
94   ehdr->e_ident[EI_VERSION] = EV_CURRENT;
95
96   ehdr->e_type = ET_CORE;
97   ehdr->e_machine = VG_ELF_MACHINE;
98   ehdr->e_version = EV_CURRENT;
99   ehdr->e_entry = 0;
100   ehdr->e_phoff = sizeof(ESZ(Ehdr));
101   ehdr->e_shoff = 0;
102   ehdr->e_flags = 0;
103   ehdr->e_ehsize = sizeof(ESZ(Ehdr));
104   ehdr->e_phentsize = sizeof(ESZ(Phdr));
105   ehdr->e_phnum = num_phdrs;
106   ehdr->e_shentsize = 0;
107   ehdr->e_shnum = 0;
108   ehdr->e_shstrndx = 0;
109
110}
111
112static void fill_phdr(ESZ(Phdr) *phdr, const NSegment *seg, UInt off, Bool write)
113{
114   SizeT len = seg->end - seg->start;
115
116   write = write && should_dump(seg);
117
118   VG_(memset)(phdr, 0, sizeof(*phdr));
119
120   phdr->p_type = PT_LOAD;
121   phdr->p_offset = off;
122   phdr->p_vaddr = seg->start;
123   phdr->p_paddr = 0;
124   phdr->p_filesz = write ? len : 0;
125   phdr->p_memsz = len;
126   phdr->p_flags = 0;
127
128   if (seg->hasR)
129      phdr->p_flags |= PF_R;
130   if (seg->hasW)
131      phdr->p_flags |= PF_W;
132   if (seg->hasX)
133      phdr->p_flags |= PF_X;
134
135   phdr->p_align = VKI_PAGE_SIZE;
136}
137
138struct note {
139   struct note *next;
140   ESZ(Nhdr) note;
141   Char name[0];
142};
143
144static UInt note_size(const struct note *n)
145{
146   return sizeof(ESZ(Nhdr)) + VG_ROUNDUP(VG_(strlen)(n->name)+1, 4) + VG_ROUNDUP(n->note.n_descsz, 4);
147}
148
149static void add_note(struct note **list, const Char *name, UInt type, const void *data, UInt datasz)
150{
151   Int namelen = VG_(strlen)(name)+1;
152   Int notelen = sizeof(struct note) +
153      VG_ROUNDUP(namelen, 4) +
154      VG_ROUNDUP(datasz, 4);
155   struct note *n = VG_(arena_malloc)(VG_AR_CORE, "coredump-elf.an.1", notelen);
156
157   VG_(memset)(n, 0, notelen);
158
159   n->next = *list;
160   *list = n;
161
162   n->note.n_type = type;
163   n->note.n_namesz = namelen;
164   n->note.n_descsz = datasz;
165
166   VG_(memcpy)(n->name, name, namelen);
167   VG_(memcpy)(n->name+VG_ROUNDUP(namelen,4), data, datasz);
168}
169
170static void write_note(Int fd, const struct note *n)
171{
172   VG_(write)(fd, &n->note, note_size(n));
173}
174
175static void fill_prpsinfo(const ThreadState *tst, struct vki_elf_prpsinfo *prpsinfo)
176{
177   static Char name[VKI_PATH_MAX];
178
179   VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
180
181   switch(tst->status) {
182   case VgTs_Runnable:
183   case VgTs_Yielding:
184      prpsinfo->pr_sname = 'R';
185      break;
186
187   case VgTs_WaitSys:
188      prpsinfo->pr_sname = 'S';
189      break;
190
191   case VgTs_Zombie:
192      prpsinfo->pr_sname = 'Z';
193      break;
194
195   case VgTs_Empty:
196   case VgTs_Init:
197      prpsinfo->pr_sname = '?';
198      break;
199   }
200
201   prpsinfo->pr_uid = 0;
202   prpsinfo->pr_gid = 0;
203
204   if (VG_(resolve_filename)(VG_(cl_exec_fd), name, VKI_PATH_MAX)) {
205      Char *n = name+VG_(strlen)(name)-1;
206
207      while (n > name && *n != '/')
208	 n--;
209      if (n != name)
210	 n++;
211
212      VG_(strncpy)(prpsinfo->pr_fname, n, sizeof(prpsinfo->pr_fname));
213   }
214}
215
216static void fill_prstatus(const ThreadState *tst,
217			  struct vki_elf_prstatus *prs,
218			  const vki_siginfo_t *si)
219{
220   struct vki_user_regs_struct *regs;
221
222   VG_(memset)(prs, 0, sizeof(*prs));
223
224   prs->pr_info.si_signo = si->si_signo;
225   prs->pr_info.si_code = si->si_code;
226   prs->pr_info.si_errno = 0;
227
228   prs->pr_cursig = si->si_signo;
229
230   prs->pr_pid = tst->os_state.lwpid;
231   prs->pr_ppid = 0;
232   prs->pr_pgrp = VG_(getpgrp)();
233   prs->pr_sid = VG_(getpgrp)();
234
235   regs = (struct vki_user_regs_struct *)prs->pr_reg;
236
237   vg_assert(sizeof(*regs) == sizeof(prs->pr_reg));
238
239   ML_(fill_elfregs_from_tst)(regs, &tst->arch);
240}
241
242static void fill_fpu(const ThreadState *tst, vki_elf_fpregset_t *fpu)
243{
244   ML_(fill_elffpregs_from_tst)(fpu, &tst->arch);
245}
246
247#if defined(VGP_x86_linux)
248static void fill_xfpu(const ThreadState *tst, vki_elf_fpxregset_t *xfpu)
249{
250   ML_(fill_elffpxregs_from_tst)(xfpu, &tst->arch);
251}
252#endif
253
254static
255void make_elf_coredump(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
256{
257   Char* buf = NULL;
258   Char *basename = "vgcore";
259   Char *coreext = "";
260   Int seq = 0;
261   Int core_fd;
262   NSegment const * seg;
263   ESZ(Ehdr) ehdr;
264   ESZ(Phdr) *phdrs;
265   Int num_phdrs;
266   Int i, idx;
267   UInt off;
268   struct note *notelist, *note;
269   UInt notesz;
270   struct vki_elf_prpsinfo prpsinfo;
271   struct vki_elf_prstatus prstatus;
272   Addr *seg_starts;
273   Int n_seg_starts;
274
275   if (VG_(clo_log_name) != NULL) {
276      coreext = ".core";
277      basename = VG_(expand_file_name)(
278                    "--log-file (while creating core filename)",
279                    VG_(clo_log_name));
280   }
281
282   vg_assert(coreext);
283   vg_assert(basename);
284   buf = VG_(malloc)( "coredump-elf.mec.1",
285                      VG_(strlen)(coreext) + VG_(strlen)(basename)
286                         + 100/*for the two %ds. */ );
287   vg_assert(buf);
288
289   for(;;) {
290      SysRes sres;
291
292      if (seq == 0)
293	 VG_(sprintf)(buf, "%s%s.%d",
294		      basename, coreext, VG_(getpid)());
295      else
296	 VG_(sprintf)(buf, "%s%s.%d.%d",
297		      basename, coreext, VG_(getpid)(), seq);
298      seq++;
299
300      sres = VG_(open)(buf,
301                       VKI_O_CREAT|VKI_O_WRONLY|VKI_O_EXCL|VKI_O_TRUNC,
302                       VKI_S_IRUSR|VKI_S_IWUSR);
303      if (!sr_isError(sres)) {
304         core_fd = sr_Res(sres);
305	 break;
306      }
307
308      if (sr_isError(sres) && sr_Err(sres) != VKI_EEXIST)
309	 return;		/* can't create file */
310   }
311
312   /* Get the segments */
313   seg_starts = VG_(get_segment_starts)(&n_seg_starts);
314
315   /* First, count how many memory segments to dump */
316   num_phdrs = 1;		/* start with notes */
317   for(i = 0; i < n_seg_starts; i++) {
318      if (!may_dump(VG_(am_find_nsegment(seg_starts[i]))))
319	 continue;
320
321      num_phdrs++;
322   }
323
324   fill_ehdr(&ehdr, num_phdrs);
325
326   notelist = NULL;
327
328   /* Second, work out their layout */
329   phdrs = VG_(arena_malloc)(VG_AR_CORE, "coredump-elf.mec.1",
330                             sizeof(*phdrs) * num_phdrs);
331
332   for(i = 1; i < VG_N_THREADS; i++) {
333      vki_elf_fpregset_t  fpu;
334#if defined(VGP_x86_linux)
335      vki_elf_fpxregset_t xfpu;
336#endif
337
338      if (VG_(threads)[i].status == VgTs_Empty)
339	 continue;
340
341#if defined(VGP_x86_linux)
342      fill_xfpu(&VG_(threads)[i], &xfpu);
343      add_note(&notelist, "LINUX", NT_PRXFPREG, &xfpu, sizeof(xfpu));
344#endif
345
346      fill_fpu(&VG_(threads)[i], &fpu);
347      add_note(&notelist, "CORE", NT_FPREGSET, &fpu, sizeof(fpu));
348
349      fill_prstatus(&VG_(threads)[i], &prstatus, si);
350      add_note(&notelist, "CORE", NT_PRSTATUS, &prstatus, sizeof(prstatus));
351   }
352
353   fill_prpsinfo(&VG_(threads)[tid], &prpsinfo);
354   add_note(&notelist, "CORE", NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo));
355
356   for(note = notelist, notesz = 0; note != NULL; note = note->next)
357      notesz += note_size(note);
358
359   off = sizeof(ehdr) + sizeof(*phdrs) * num_phdrs;
360
361   phdrs[0].p_type = PT_NOTE;
362   phdrs[0].p_offset = off;
363   phdrs[0].p_vaddr = 0;
364   phdrs[0].p_paddr = 0;
365   phdrs[0].p_filesz = notesz;
366   phdrs[0].p_memsz = 0;
367   phdrs[0].p_flags = 0;
368   phdrs[0].p_align = 0;
369
370   off += notesz;
371
372   off = VG_PGROUNDUP(off);
373
374   for(i = 0, idx = 1; i < n_seg_starts; i++) {
375      seg = VG_(am_find_nsegment(seg_starts[i]));
376
377      if (!may_dump(seg))
378	 continue;
379
380      fill_phdr(&phdrs[idx], seg, off, (seg->end - seg->start + off) < max_size);
381
382      off += phdrs[idx].p_filesz;
383
384      idx++;
385   }
386
387   /* write everything out */
388   VG_(write)(core_fd, &ehdr, sizeof(ehdr));
389   VG_(write)(core_fd, phdrs, sizeof(*phdrs) * num_phdrs);
390
391   for(note = notelist; note != NULL; note = note->next)
392      write_note(core_fd, note);
393
394   VG_(lseek)(core_fd, phdrs[1].p_offset, VKI_SEEK_SET);
395
396   for(i = 0, idx = 1; i < n_seg_starts; i++) {
397      seg = VG_(am_find_nsegment(seg_starts[i]));
398
399      if (!should_dump(seg))
400	 continue;
401
402      if (phdrs[idx].p_filesz > 0) {
403	 vg_assert(VG_(lseek)(core_fd, phdrs[idx].p_offset, VKI_SEEK_SET) == phdrs[idx].p_offset);
404	 vg_assert(seg->end - seg->start >= phdrs[idx].p_filesz);
405
406	 (void)VG_(write)(core_fd, (void *)seg->start, phdrs[idx].p_filesz);
407      }
408      idx++;
409   }
410
411   VG_(free)(seg_starts);
412
413   VG_(close)(core_fd);
414}
415
416void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
417{
418   make_elf_coredump(tid, si, max_size);
419}
420
421/*--------------------------------------------------------------------*/
422/*--- end                                                          ---*/
423/*--------------------------------------------------------------------*/
424