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