1 /* Common core note type descriptions for Linux. 2 Copyright (C) 2007-2010 Red Hat, Inc. 3 Copyright (C) H.J. Lu <hjl.tools (at) 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 65 struct EBLHOOK(siginfo) 66 { 67 FIELD (INT, si_signo); 68 FIELD (INT, si_code); 69 FIELD (INT, si_errno); 70 }; 71 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 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 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 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