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
EBLHOOK(siginfo)67 struct EBLHOOK(siginfo)
68 {
69 FIELD (INT, si_signo);
70 FIELD (INT, si_code);
71 FIELD (INT, si_errno);
72 };
73
EBLHOOK(timeval)74 struct 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
EBLHOOK(prstatus)89 struct 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
EBLHOOK(prpsinfo)121 struct 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
150 static 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
186 static 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
203 static const Ebl_Core_Item vmcoreinfo_items[] =
204 {
205 {
206 .type = ELF_T_BYTE, .format = '\n'
207 }
208 };
209
210 #undef FIELD
211
212 int
EBLHOOK(core_note)213 EBLHOOK(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