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 51 struct EBLHOOK(siginfo) 52 { 53 FIELD (INT, si_signo); 54 FIELD (INT, si_code); 55 FIELD (INT, si_errno); 56 }; 57 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 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 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