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