1/* Common core note type descriptions for Linux.
2   Copyright (C) 2007-2010 Red Hat, Inc.
3   Copyright (C) H.J. Lu <hjl.tools@gmail.com>, 2015.
4   This file is part of elfutils.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#include <string.h>
31
32/* The including CPU_corenote.c file provides prstatus_regs and
33   defines macros ULONG, [PUG]ID_T, and ALIGN_*, TYPE_*.
34
35   Here we describe the common layout used in <linux/elfcore.h>.  */
36
37#define	CHAR			int8_t
38#define	ALIGN_CHAR		1
39#define	TYPE_CHAR		ELF_T_BYTE
40#define	SHORT			uint16_t
41#define ALIGN_SHORT		2
42#define TYPE_SHORT		ELF_T_HALF
43#define	INT			int32_t
44#ifndef ALIGN_INT
45# define ALIGN_INT		4
46#endif
47#define TYPE_INT		ELF_T_SWORD
48#ifndef PR_REG
49# define PR_REG			ULONG
50#endif
51#ifndef ALIGN_PR_REG
52# define ALIGN_PR_REG		ALIGN_ULONG
53#endif
54#ifndef PRPSINFO_UID_T
55# define PRPSINFO_UID_T		UID_T
56# define ALIGN_PRPSINFO_UID_T	ALIGN_UID_T
57# define TYPE_PRPSINFO_UID_T	TYPE_UID_T
58#endif
59#ifndef PRPSINFO_GID_T
60# define PRPSINFO_GID_T		GID_T
61# define ALIGN_PRPSINFO_GID_T	ALIGN_GID_T
62# define TYPE_PRPSINFO_GID_T	TYPE_GID_T
63#endif
64
65#define FIELD(type, name) type name __attribute__ ((aligned (ALIGN_##type)))
66
67struct EBLHOOK(siginfo)
68{
69  FIELD (INT, si_signo);
70  FIELD (INT, si_code);
71  FIELD (INT, si_errno);
72};
73
74struct EBLHOOK(timeval)
75{
76  FIELD (ULONG, tv_sec);
77  FIELD (ULONG, tv_usec);
78};
79
80/* On sparc64, tv_usec (suseconds_t) is actually 32 bits with 32 bits padding.
81   The 'T'|0x80 value for .format indicates this as a special kludge.  */
82#if SUSECONDS_HALF
83# define TIMEVAL_FIELD(name)	FIELD (time, ULONG, name, 'T'|0x80, .count = 2)
84#else
85# define TIMEVAL_FIELD(name)	FIELD (time, ULONG, name, 'T', .count = 2)
86#endif
87
88
89struct EBLHOOK(prstatus)
90{
91  struct EBLHOOK(siginfo) pr_info;
92  FIELD (SHORT, pr_cursig);
93  FIELD (ULONG, pr_sigpend);
94  FIELD (ULONG, pr_sighold);
95  FIELD (PID_T, pr_pid);
96  FIELD (PID_T, pr_ppid);
97  FIELD (PID_T, pr_pgrp);
98  FIELD (PID_T, pr_sid);
99  struct EBLHOOK(timeval) pr_utime;
100  struct EBLHOOK(timeval) pr_stime;
101  struct EBLHOOK(timeval) pr_cutime;
102  struct EBLHOOK(timeval) pr_cstime;
103  struct
104  {
105    FIELD (PR_REG, pr_reg[PRSTATUS_REGS_SIZE / sizeof (PR_REG)]);
106  }
107#ifdef ALIGN_PR_REG
108    __attribute__ ((aligned (ALIGN_PR_REG)))
109#endif
110    ;
111  FIELD (INT, pr_fpvalid);
112}
113#ifdef ALIGN_PRSTATUS
114  attribute_packed __attribute__ ((aligned (ALIGN_PRSTATUS)))
115#endif
116;
117
118#define	FNAMESZ	16
119#define	PRARGSZ	80
120
121struct EBLHOOK(prpsinfo)
122{
123  FIELD (CHAR, pr_state);
124  FIELD (CHAR, pr_sname);
125  FIELD (CHAR, pr_zomb);
126  FIELD (CHAR, pr_nice);
127  FIELD (ULONG, pr_flag);
128  FIELD (PRPSINFO_UID_T, pr_uid);
129  FIELD (PRPSINFO_GID_T, pr_gid);
130  FIELD (PID_T, pr_pid);
131  FIELD (PID_T, pr_ppid);
132  FIELD (PID_T, pr_pgrp);
133  FIELD (PID_T, pr_sid);
134  FIELD (CHAR, pr_fname[FNAMESZ]);
135  FIELD (CHAR, pr_psargs[PRARGSZ]);
136};
137
138#undef	FIELD
139
140#define FIELD(igroup, itype, item, fmt, ...)			\
141    {								\
142      .name = #item,						\
143      .group = #igroup,					\
144      .offset = offsetof (struct EBLHOOK(prstatus), pr_##item),	\
145      .type = TYPE_##itype,					\
146      .format = fmt,						\
147      __VA_ARGS__						\
148    }
149
150static const Ebl_Core_Item prstatus_items[] =
151  {
152    FIELD (signal, INT, info.si_signo, 'd'),
153    FIELD (signal, INT, info.si_code, 'd'),
154    FIELD (signal, INT, info.si_errno, 'd'),
155    FIELD (signal, SHORT, cursig, 'd'),
156
157    /* Use different group name for a newline delimiter.  */
158    FIELD (signal2, ULONG, sigpend, 'B'),
159    FIELD (signal3, ULONG, sighold, 'B'),
160    FIELD (identity, PID_T, pid, 'd', .thread_identifier = true),
161    FIELD (identity, PID_T, ppid, 'd'),
162    FIELD (identity, PID_T, pgrp, 'd'),
163    FIELD (identity, PID_T, sid, 'd'),
164    TIMEVAL_FIELD (utime),
165    TIMEVAL_FIELD (stime),
166    TIMEVAL_FIELD (cutime),
167    TIMEVAL_FIELD (cstime),
168#ifdef PRSTATUS_REGSET_ITEMS
169    PRSTATUS_REGSET_ITEMS,
170#endif
171    FIELD (register, INT, fpvalid, 'd'),
172  };
173
174#undef	FIELD
175
176#define FIELD(igroup, itype, item, fmt, ...)			\
177    {								\
178      .name = #item,						\
179      .group = #igroup,					\
180      .offset = offsetof (struct EBLHOOK(prpsinfo), pr_##item),	\
181      .type = TYPE_##itype,					\
182      .format = fmt,						\
183      __VA_ARGS__						\
184    }
185
186static const Ebl_Core_Item prpsinfo_items[] =
187  {
188    FIELD (state, CHAR, state, 'd'),
189    FIELD (state, CHAR, sname, 'c'),
190    FIELD (state, CHAR, zomb, 'd'),
191    FIELD (state, CHAR, nice, 'd'),
192    FIELD (state, ULONG, flag, 'x'),
193    FIELD (identity, PRPSINFO_UID_T, uid, 'd'),
194    FIELD (identity, PRPSINFO_GID_T, gid, 'd'),
195    FIELD (identity, PID_T, pid, 'd'),
196    FIELD (identity, PID_T, ppid, 'd'),
197    FIELD (identity, PID_T, pgrp, 'd'),
198    FIELD (identity, PID_T, sid, 'd'),
199    FIELD (command, CHAR, fname, 's', .count = FNAMESZ),
200    FIELD (command, CHAR, psargs, 's', .count = PRARGSZ),
201  };
202
203static const Ebl_Core_Item vmcoreinfo_items[] =
204  {
205    {
206      .type = ELF_T_BYTE, .format = '\n'
207    }
208  };
209
210#undef	FIELD
211
212int
213EBLHOOK(core_note) (const GElf_Nhdr *nhdr, const char *name,
214		    GElf_Word *regs_offset, size_t *nregloc,
215		    const Ebl_Register_Location **reglocs,
216		    size_t *nitems, const Ebl_Core_Item **items)
217{
218  switch (nhdr->n_namesz)
219    {
220    case sizeof "CORE" - 1:	/* Buggy old Linux kernels.  */
221      if (memcmp (name, "CORE", nhdr->n_namesz) == 0)
222	break;
223      return 0;
224
225    case sizeof "CORE":
226      if (memcmp (name, "CORE", nhdr->n_namesz) == 0)
227	break;
228      /* Buggy old Linux kernels didn't terminate "LINUX".  */
229      FALLTHROUGH;
230
231    case sizeof "LINUX":
232      if (memcmp (name, "LINUX", nhdr->n_namesz) == 0)
233	break;
234      return 0;
235
236    case sizeof "VMCOREINFO":
237      if (nhdr->n_type != 0
238	  || memcmp (name, "VMCOREINFO", sizeof "VMCOREINFO") != 0)
239	return 0;
240      *regs_offset = 0;
241      *nregloc = 0;
242      *nitems = 1;
243      *items = vmcoreinfo_items;
244      return 1;
245
246    default:
247      return 0;
248    }
249
250  switch (nhdr->n_type)
251    {
252    case NT_PRSTATUS:
253      if (nhdr->n_descsz != sizeof (struct EBLHOOK(prstatus)))
254	return 0;
255      *regs_offset = offsetof (struct EBLHOOK(prstatus), pr_reg);
256      *nregloc = sizeof prstatus_regs / sizeof prstatus_regs[0];
257      *reglocs = prstatus_regs;
258      *nitems = sizeof prstatus_items / sizeof prstatus_items[0];
259      *items = prstatus_items;
260      return 1;
261
262    case NT_PRPSINFO:
263      if (nhdr->n_descsz != sizeof (struct EBLHOOK(prpsinfo)))
264	return 0;
265      *regs_offset = 0;
266      *nregloc = 0;
267      *reglocs = NULL;
268      *nitems = sizeof prpsinfo_items / sizeof prpsinfo_items[0];
269      *items = prpsinfo_items;
270      return 1;
271
272#define EXTRA_REGSET(type, size, table)					      \
273    case type:								      \
274      if (nhdr->n_descsz != size)					      \
275	return 0;							      \
276      *regs_offset = 0;							      \
277      *nregloc = sizeof table / sizeof table[0];			      \
278      *reglocs = table;							      \
279      *nitems = 0;							      \
280      *items = NULL;							      \
281      return 1;
282
283#define EXTRA_REGSET_ITEMS(type, size, table, extra_items)		      \
284    case type:								      \
285      if (nhdr->n_descsz != size)					      \
286	return 0;							      \
287      *regs_offset = 0;							      \
288      *nregloc = sizeof table / sizeof table[0];			      \
289      *reglocs = table;							      \
290      *nitems = sizeof extra_items / sizeof extra_items[0];		      \
291      *items = extra_items;						      \
292      return 1;
293
294#define EXTRA_ITEMS(type, size, extra_items)				      \
295    case type:								      \
296      if (nhdr->n_descsz != size)					      \
297	return 0;							      \
298      *regs_offset = 0;							      \
299      *nregloc = 0;							      \
300      *reglocs = NULL;							      \
301      *nitems = sizeof extra_items / sizeof extra_items[0];		      \
302      *items = extra_items;						      \
303      return 1;
304
305#ifdef FPREGSET_SIZE
306    EXTRA_REGSET (NT_FPREGSET, FPREGSET_SIZE, fpregset_regs)
307#endif
308
309#ifdef EXTRA_NOTES
310    EXTRA_NOTES
311#endif
312    }
313
314  return 0;
315}
316