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