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