Home | History | Annotate | Download | only in backends
      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