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 #define ALIGN_INT 4
45 #define TYPE_INT ELF_T_SWORD
46 #ifndef PR_REG
47 # define PR_REG ULONG
48 #endif
49 #ifndef ALIGN_PR_REG
50 # define ALIGN_PR_REG ALIGN_ULONG
51 #endif
52 #ifndef PRPSINFO_UID_T
53 # define PRPSINFO_UID_T UID_T
54 # define ALIGN_PRPSINFO_UID_T ALIGN_UID_T
55 # define TYPE_PRPSINFO_UID_T TYPE_UID_T
56 #endif
57 #ifndef PRPSINFO_GID_T
58 # define PRPSINFO_GID_T GID_T
59 # define ALIGN_PRPSINFO_GID_T ALIGN_GID_T
60 # define TYPE_PRPSINFO_GID_T TYPE_GID_T
61 #endif
62
63 #define FIELD(type, name) type name __attribute__ ((aligned (ALIGN_##type)))
64
EBLHOOK(siginfo)65 struct EBLHOOK(siginfo)
66 {
67 FIELD (INT, si_signo);
68 FIELD (INT, si_code);
69 FIELD (INT, si_errno);
70 };
71
EBLHOOK(timeval)72 struct EBLHOOK(timeval)
73 {
74 FIELD (ULONG, tv_sec);
75 FIELD (ULONG, tv_usec);
76 };
77
78 /* On sparc64, tv_usec (suseconds_t) is actually 32 bits with 32 bits padding.
79 The 'T'|0x80 value for .format indicates this as a special kludge. */
80 #if SUSECONDS_HALF
81 # define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T'|0x80, .count = 2)
82 #else
83 # define TIMEVAL_FIELD(name) FIELD (time, ULONG, name, 'T', .count = 2)
84 #endif
85
86
EBLHOOK(prstatus)87 struct EBLHOOK(prstatus)
88 {
89 struct EBLHOOK(siginfo) pr_info;
90 FIELD (SHORT, pr_cursig);
91 FIELD (ULONG, pr_sigpend);
92 FIELD (ULONG, pr_sighold);
93 FIELD (PID_T, pr_pid);
94 FIELD (PID_T, pr_ppid);
95 FIELD (PID_T, pr_pgrp);
96 FIELD (PID_T, pr_sid);
97 struct EBLHOOK(timeval) pr_utime;
98 struct EBLHOOK(timeval) pr_stime;
99 struct EBLHOOK(timeval) pr_cutime;
100 struct EBLHOOK(timeval) pr_cstime;
101 struct
102 {
103 FIELD (PR_REG, pr_reg[PRSTATUS_REGS_SIZE / sizeof (PR_REG)]);
104 }
105 #ifdef ALIGN_PR_REG
106 __attribute__ ((aligned (ALIGN_PR_REG)))
107 #endif
108 ;
109 FIELD (INT, pr_fpvalid);
110 };
111
112 #define FNAMESZ 16
113 #define PRARGSZ 80
114
EBLHOOK(prpsinfo)115 struct EBLHOOK(prpsinfo)
116 {
117 FIELD (CHAR, pr_state);
118 FIELD (CHAR, pr_sname);
119 FIELD (CHAR, pr_zomb);
120 FIELD (CHAR, pr_nice);
121 FIELD (ULONG, pr_flag);
122 FIELD (PRPSINFO_UID_T, pr_uid);
123 FIELD (PRPSINFO_GID_T, pr_gid);
124 FIELD (PID_T, pr_pid);
125 FIELD (PID_T, pr_ppid);
126 FIELD (PID_T, pr_pgrp);
127 FIELD (PID_T, pr_sid);
128 FIELD (CHAR, pr_fname[FNAMESZ]);
129 FIELD (CHAR, pr_psargs[PRARGSZ]);
130 };
131
132 #undef FIELD
133
134 #define FIELD(igroup, itype, item, fmt, ...) \
135 { \
136 .name = #item, \
137 .group = #igroup, \
138 .offset = offsetof (struct EBLHOOK(prstatus), pr_##item), \
139 .type = TYPE_##itype, \
140 .format = fmt, \
141 __VA_ARGS__ \
142 }
143
144 static const Ebl_Core_Item prstatus_items[] =
145 {
146 FIELD (signal, INT, info.si_signo, 'd'),
147 FIELD (signal, INT, info.si_code, 'd'),
148 FIELD (signal, INT, info.si_errno, 'd'),
149 FIELD (signal, SHORT, cursig, 'd'),
150
151 /* Use different group name for a newline delimiter. */
152 FIELD (signal2, ULONG, sigpend, 'B'),
153 FIELD (signal3, ULONG, sighold, 'B'),
154 FIELD (identity, PID_T, pid, 'd', .thread_identifier = true),
155 FIELD (identity, PID_T, ppid, 'd'),
156 FIELD (identity, PID_T, pgrp, 'd'),
157 FIELD (identity, PID_T, sid, 'd'),
158 TIMEVAL_FIELD (utime),
159 TIMEVAL_FIELD (stime),
160 TIMEVAL_FIELD (cutime),
161 TIMEVAL_FIELD (cstime),
162 #ifdef PRSTATUS_REGSET_ITEMS
163 PRSTATUS_REGSET_ITEMS,
164 #endif
165 FIELD (register, INT, fpvalid, 'd'),
166 };
167
168 #undef FIELD
169
170 #define FIELD(igroup, itype, item, fmt, ...) \
171 { \
172 .name = #item, \
173 .group = #igroup, \
174 .offset = offsetof (struct EBLHOOK(prpsinfo), pr_##item), \
175 .type = TYPE_##itype, \
176 .format = fmt, \
177 __VA_ARGS__ \
178 }
179
180 static const Ebl_Core_Item prpsinfo_items[] =
181 {
182 FIELD (state, CHAR, state, 'd'),
183 FIELD (state, CHAR, sname, 'c'),
184 FIELD (state, CHAR, zomb, 'd'),
185 FIELD (state, CHAR, nice, 'd'),
186 FIELD (state, ULONG, flag, 'x'),
187 FIELD (identity, PRPSINFO_UID_T, uid, 'd'),
188 FIELD (identity, PRPSINFO_GID_T, gid, 'd'),
189 FIELD (identity, PID_T, pid, 'd'),
190 FIELD (identity, PID_T, ppid, 'd'),
191 FIELD (identity, PID_T, pgrp, 'd'),
192 FIELD (identity, PID_T, sid, 'd'),
193 FIELD (command, CHAR, fname, 's', .count = FNAMESZ),
194 FIELD (command, CHAR, psargs, 's', .count = PRARGSZ),
195 };
196
197 static const Ebl_Core_Item vmcoreinfo_items[] =
198 {
199 {
200 .type = ELF_T_BYTE, .format = '\n'
201 }
202 };
203
204 #undef FIELD
205
206 int
EBLHOOK(core_note)207 EBLHOOK(core_note) (const GElf_Nhdr *nhdr, const char *name,
208 GElf_Word *regs_offset, size_t *nregloc,
209 const Ebl_Register_Location **reglocs,
210 size_t *nitems, const Ebl_Core_Item **items)
211 {
212 switch (nhdr->n_namesz)
213 {
214 case sizeof "CORE" - 1: /* Buggy old Linux kernels. */
215 if (memcmp (name, "CORE", nhdr->n_namesz) == 0)
216 break;
217 return 0;
218
219 case sizeof "CORE":
220 if (memcmp (name, "CORE", nhdr->n_namesz) == 0)
221 break;
222 /* Buggy old Linux kernels didn't terminate "LINUX".
223 Fall through. */
224
225 case sizeof "LINUX":
226 if (memcmp (name, "LINUX", nhdr->n_namesz) == 0)
227 break;
228 return 0;
229
230 case sizeof "VMCOREINFO":
231 if (nhdr->n_type != 0
232 || memcmp (name, "VMCOREINFO", sizeof "VMCOREINFO") != 0)
233 return 0;
234 *regs_offset = 0;
235 *nregloc = 0;
236 *nitems = 1;
237 *items = vmcoreinfo_items;
238 return 1;
239
240 default:
241 return 0;
242 }
243
244 switch (nhdr->n_type)
245 {
246 case NT_PRSTATUS:
247 if (nhdr->n_descsz != sizeof (struct EBLHOOK(prstatus)))
248 return 0;
249 *regs_offset = offsetof (struct EBLHOOK(prstatus), pr_reg);
250 *nregloc = sizeof prstatus_regs / sizeof prstatus_regs[0];
251 *reglocs = prstatus_regs;
252 *nitems = sizeof prstatus_items / sizeof prstatus_items[0];
253 *items = prstatus_items;
254 return 1;
255
256 case NT_PRPSINFO:
257 if (nhdr->n_descsz != sizeof (struct EBLHOOK(prpsinfo)))
258 return 0;
259 *regs_offset = 0;
260 *nregloc = 0;
261 *reglocs = NULL;
262 *nitems = sizeof prpsinfo_items / sizeof prpsinfo_items[0];
263 *items = prpsinfo_items;
264 return 1;
265
266 #define EXTRA_REGSET(type, size, table) \
267 case type: \
268 if (nhdr->n_descsz != size) \
269 return 0; \
270 *regs_offset = 0; \
271 *nregloc = sizeof table / sizeof table[0]; \
272 *reglocs = table; \
273 *nitems = 0; \
274 *items = NULL; \
275 return 1;
276
277 #define EXTRA_REGSET_ITEMS(type, size, table, extra_items) \
278 case type: \
279 if (nhdr->n_descsz != size) \
280 return 0; \
281 *regs_offset = 0; \
282 *nregloc = sizeof table / sizeof table[0]; \
283 *reglocs = table; \
284 *nitems = sizeof extra_items / sizeof extra_items[0]; \
285 *items = extra_items; \
286 return 1;
287
288 #define EXTRA_ITEMS(type, size, extra_items) \
289 case type: \
290 if (nhdr->n_descsz != size) \
291 return 0; \
292 *regs_offset = 0; \
293 *nregloc = 0; \
294 *reglocs = NULL; \
295 *nitems = sizeof extra_items / sizeof extra_items[0]; \
296 *items = extra_items; \
297 return 1;
298
299 #ifdef FPREGSET_SIZE
300 EXTRA_REGSET (NT_FPREGSET, FPREGSET_SIZE, fpregset_regs)
301 #endif
302
303 #ifdef EXTRA_NOTES
304 EXTRA_NOTES
305 #endif
306 }
307
308 return 0;
309 }
310