This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
Patch to readelf...
- To: binutils mailing list <binutils@sourceware.cygnus.com>
- Subject: Patch to readelf...
- From: scottb <scottb@netwinder.org>
- Date: Thu, 19 Aug 1999 11:06:40 -0400
- Organization: Rebel.com
Hi,
I've been plumbing the depths of ARM Linux corefiles lately and have
extended readelf's capabilities in the area of dumping core files. I
thought I would pass along the work and see if anyone thought it was
interesting enough for inclusion in the tree.
1999-08-19 Scott Bambrough <scottb@netwinder.org>
* include/elf/common.h: Added NT_TASKSTRUCT note type.
* binutils/readelf.c: Added code to parse the NT_PRSTATUS,
NT_PRPSINFO, and NT_FPREGSET note segments found in elf core
files. Added ARM specific code to process arm registers and
arm floating point registers.
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/binutils/binutils/binutils/readelf.c,v
retrieving revision 1.20
diff -u -r1.20 readelf.c
--- readelf.c 1999/08/09 17:16:23 1.20
+++ readelf.c 1999/08/19 14:40:25
@@ -20,12 +20,15 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
-
+
#include <assert.h>
#include <sys/stat.h>
#include <stdio.h>
#include <time.h>
+#include <sys/procfs.h>
+#include <signal.h>
+#include <sys/user.h>
#if __GNUC__ >= 2
/* Define BFD64 here, even if our default architecture is 32 bit ELF
@@ -6267,7 +6270,500 @@
return 1;
}
+static char *
+get_note_type (e_type)
+ unsigned e_type;
+{
+ static char buff[64];
+
+ switch (e_type)
+ {
+ case NT_PRSTATUS: return _("NT_PRSTATUS (prstatus structure)");
+ case NT_FPREGSET: return _("NT_FPREGSET (floating point registers)");
+ case NT_PRPSINFO: return _("NT_PRPSINFO (prpsinfo structure)");
+ case NT_TASKSTRUCT: return _("NT_TASKSTRUCT (task structure)");
+ case NT_PSTATUS: return _("NT_PSTATUS (pstatus structure)");
+ case NT_FPREGS: return _("NT_FPREGS (floating point registers)");
+ case NT_PSINFO: return _("NT_PSINFO (psinfo structure)");
+ case NT_LWPSTATUS: return _("NT_LWPSTATUS (lwpstatus_t structure)");
+ case NT_LWPSINFO: return _("NT_LWPSINFO (lwpsinfo_t structure)");
+ default:
+ sprintf (buff, _("Unknown note type: (0x%08x)"), e_type);
+ return buff;
+ }
+}
+
+static char *
+get_signal_type (nsig)
+ unsigned long int nsig;
+{
+ static char buff[64];
+
+ switch (nsig)
+ {
+ case 0 : return _("NONE");
+ case SIGHUP : return _("SIGHUP - Hangup (POSIX)");
+ case SIGINT : return _("SIGINT - Interrupt (ANSI)");
+ case SIGQUIT : return _("SIGQUIT - Quit (POSIX)");
+ case SIGILL : return _("SIGILL - Illegal instruction (ANSI)");
+ case SIGTRAP : return _("SIGTRAP - Trace trap (POSIX)");
+ case SIGABRT : return _("SIGABRT - Abort (ANSI)");
+ case SIGBUS : return _("SIGBUS - BUS error (4.2 BSD)");
+ case SIGFPE : return _("SIGFPE - Floating-point exception (ANSI)");
+ case SIGKILL : return _("SIGKILL - Kill, unblockable (POSIX)");
+ case SIGUSR1 : return _("SIGUSR1 - User-defined signal 1 (POSIX)");
+ case SIGSEGV : return _("SIGSEGV - Segmentation violation (ANSI)");
+ case SIGUSR2 : return _("SIGUSR2 - User-defined signal 2 (POSIX)");
+ case SIGPIPE : return _("SIGPIPE - Broken pipe (POSIX)");
+ case SIGALRM : return _("SIGALRM - Alarm clock (POSIX)");
+ case SIGTERM : return _("SIGTERM - Termination (ANSI)");
+ case SIGSTKFLT : return _("SIGSTKFLT - Stack fault");
+ case SIGCHLD : return _("SIGCHLD - Child status has changed (POSIX)");
+ case SIGCONT : return _("SIGCONT - Continue (POSIX)");
+ case SIGSTOP : return _("SIGSTOP - Stop, unblockable (POSIX)");
+ case SIGTSTP : return _("SIGTSTP - Keyboard stop (POSIX)");
+ case SIGTTIN : return _("SIGTTIN - Background read from tty (POSIX)");
+ case SIGTTOU : return _("SIGTTOU - Background write to tty (POSIX)");
+ case SIGURG : return _("SIGURG - Urgent condition on socket (4.2 BSD)");
+ case SIGXCPU : return _("SIGXCPU - CPU limit exceeded (4.2 BSD)");
+ case SIGXFSZ : return _("SIGXFSZ - File size limit exceeded (4.2 BSD)");
+ case SIGVTALRM : return _("SIGVTALRM - Virtual alarm clock (4.2 BSD)");
+ case SIGPROF : return _("SIGPROF - Profiling alarm clock (4.2 BSD)");
+ case SIGWINCH : return _("SIGWINCH - Window size change (4.3 BSD, Sun)");
+ case SIGPOLL : return _("SIGPOLL - Pollable event occurred (System V)");
+ case SIGPWR : return _("SIGPWR - Power failure restart (System V)");
+
+ default:
+ sprintf (buff, _("Unknown signal: (0x%08x)"), nsig);
+ return buff;
+ }
+}
+
static int
+process_note (pnote)
+ Elf_External_Note *pnote;
+{
+ Elf32_Internal_Note *internal;
+ char *pname;
+
+ internal = (Elf32_Internal_Note *)pnote;
+ pname = malloc (internal->namesz + 1);
+ if (pname == NULL)
+ {
+ error (_("Out of memory\n"));
+ return 0;
+ }
+ memcpy (pname, pnote->name, internal->namesz);
+ pname[internal->namesz] = '\0';
+
+ printf(" %s\t\t0x%08lx\t%s\n",
+ pname, internal->descsz, get_note_type(internal->type));
+
+ free (pname);
+ return 1;
+}
+
+static void
+print_process_identifiers(pid, ppid, pgrp, sid)
+ unsigned long int pid;
+ unsigned long int ppid;
+ unsigned long int pgrp;
+ unsigned long int sid;
+{
+ printf(_(" Process identifiers:\n"));
+ printf(_(" Process id: 0x%08lx\n"), pid);
+ printf(_(" Parent process id: 0x%08lx\n"), ppid);
+ printf(_(" Group id: 0x%08lx\n"), pgrp);
+ printf(_(" Session id: 0x%08lx\n"), sid);
+}
+
+static void
+arm_print_gregs (regs)
+ elf_gregset_t *regs;
+{
+ unsigned int i;
+ static char* registers[] = { "r0", "r1", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9",
+ "r10", "fp", "ip", "sp", "lr",
+ "pc", "cpsr" };
+
+ /* if not an ARM machine then exit */
+ if (elf_header.e_machine != EM_ARM)
+ return;
+
+ printf(_("\n General registers:\n"));
+
+ for (i=0;i<17;i++) {
+ if (i != 0 && (i % 3) == 0) printf("\n");
+ printf(_("%6s: 0x%08x\t"), registers[i], regs[i]);
+ }
+ if ((i % 3) != 0) printf("\n");
+}
+
+static void
+arm_print_fpsr (regs)
+ struct user_fp *regs;
+{
+ unsigned int i;
+
+ printf("\n Floating point status register: (0x%08x)\n",regs->fpsr);
+
+ i = regs->fpsr >> 24;
+ switch (i)
+ {
+ case 0x00: printf(_(" System id: pre-FPA software system\n")); break;
+ case 0x80: printf(_(" System id: pre-FPA hardware system\n")); break;
+ case 0x01: printf(_(" System id: floating point emulator\n")); break;
+ case 0x81: printf(_(" System id: FPA11 hardware system\n")); break;
+ default: printf(_(" System id: unknown floating point system\n"));
+ }
+
+ i = regs->fpsr >> 16;
+ printf(_("\n Exception traps enabled: "));
+ if ((i & 0x1F) == 0) {
+ printf(_("(none)"));
+ } else {
+ if (i & 0x10) printf(_("IXE "));
+ if (i & 0x08) printf(_("UFE "));
+ if (i & 0x04) printf(_("OFE "));
+ if (i & 0x02) printf(_("OZE "));
+ if (i & 0x01) printf(_("IOE"));
+ }
+ printf("\n");
+
+ i = regs->fpsr >> 8;
+ printf(_("\n System control byte:\n"));
+ printf(_(" AC %s: use alternative carry definition\n"),
+ i & 0x10 ? _("set") : _("clear"));
+ printf(_(" EP %s: use expanded packed decimal format\n"),
+ i & 0x08 ? _("set") : _("clear"));
+ printf(_(" SO %s: select synchronous operation of FPA\n"),
+ i & 0x04 ? _("set") : _("clear"));
+ printf(_(" NE %s: NaN exception\n"),
+ i & 0x02 ? _("set") : _("clear"));
+ printf(_(" ND %s: No denormalized numbers\n"),
+ i & 0x01 ? _("set") : _("clear"));
+
+ i = regs->fpsr;
+ printf(_("\n Cumulative exception flags: "));
+ if ((i & 0x1F) == 0) {
+ printf(_("(none)"));
+ } else {
+ if (i & 0x10) printf(_("IXC "));
+ if (i & 0x08) printf(_("UFC "));
+ if (i & 0x04) printf(_("OFC "));
+ if (i & 0x02) printf(_("OZC "));
+ if (i & 0x01) printf(_("IOC"));
+ }
+ printf("\n");
+}
+
+static void
+arm_print_fpregs (regs)
+ struct user_fp *regs;
+{
+ unsigned int i;
+ unsigned long int *p;
+ static char* registers[] = { "f0", "f1", "f2", "f3",
+ "f4", "f5", "f6", "f7" };
+
+ /* if not an ARM machine then exit */
+ if (elf_header.e_machine != EM_ARM)
+ return;
+
+ printf(_("\n Floating point registers:\n"));
+
+ p = (unsigned long int *)®s->fpregs[0];
+ for (i=0;i<8;i++) {
+ printf(_("\t%6s: 0x%08x 0x%08x 0x%08x"),
+ registers[i], *p++, *p++, *p++);
+#if 0
+ /* check for NWFPE */
+ if (regs->init_flag)
+ {
+ switch (regs->ftype[i])
+ {
+ case 1: printf(_(" (float)")); break;
+ case 2: printf(_(" (double)")); break;
+ case 3: printf(_(" (extended)")); break;
+ }
+ }
+#endif
+ printf("\n");
+ }
+
+ printf(_("\t%6s: 0x%08x\n"), _("fpsr"), regs->fpsr);
+ printf(_("\t%6s: 0x%08x\n"), _("fpcr"), regs->fpcr);
+
+ arm_print_fpsr(regs);
+}
+
+static int
+process_prstatus (pnote)
+ Elf_External_Note *pnote;
+{
+ Elf32_Internal_Note *internal;
+ prstatus_t *pdata;
+ char utime[20], stime[20], cutime[20], cstime[20];
+
+ internal = (Elf32_Internal_Note *)pnote;
+ pdata = (prstatus_t*)(pnote->name + internal->namesz);
+
+ sprintf(utime,"%ld sec, %ld usec",
+ (unsigned long int)pdata->pr_utime.tv_sec,
+ (unsigned long int)pdata->pr_utime.tv_usec);
+ sprintf(stime,"%ld sec, %ld usec",
+ (unsigned long int)pdata->pr_stime.tv_sec,
+ (unsigned long int)pdata->pr_stime.tv_usec);
+ sprintf(cutime,"%ld sec, %ld usec",
+ (unsigned long int)pdata->pr_cutime.tv_sec,
+ (unsigned long int)pdata->pr_cutime.tv_usec);
+ sprintf(cstime,"%ld sec, %ld usec",
+ (unsigned long int)pdata->pr_cstime.tv_sec,
+ (unsigned long int)pdata->pr_cstime.tv_usec);
+
+ printf(_("\nPRSTATUS Note:\n"));
+
+ print_process_identifiers((unsigned long int)pdata->pr_pid,
+ (unsigned long int)pdata->pr_ppid,
+ (unsigned long int)pdata->pr_pgrp,
+ (unsigned long int)pdata->pr_sid);
+
+ printf(_("\n Process timings:\n"));
+ printf(_(" User time: %s\n"), utime);
+ printf(_(" System time: %s\n"), stime);
+ printf(_(" Cumulative user time: %s\n"), cutime);
+ printf(_(" Cumulative system time: %s\n"), cstime);
+
+ printf(_("\n Signal information:\n"));
+ printf(_(" Process terminated with signal %ld (%s)\n"),
+ (unsigned long int)pdata->pr_info.si_signo,
+ get_signal_type ((unsigned long int)pdata->pr_info.si_signo));
+ printf(_(" Error number: 0x%08lx\n"),
+ (unsigned long int)pdata->pr_info.si_errno);
+ printf(_(" Error code: 0x%08lx\n"),
+ (unsigned long int)pdata->pr_info.si_code);
+ printf(_(" Current signal: %ld (%s)\n"),
+ (unsigned long int)pdata->pr_cursig,
+ get_signal_type ((unsigned long int)pdata->pr_cursig));
+ printf(_(" Pending signal: %ld (%s)\n"),
+ pdata->pr_sigpend, get_signal_type (pdata->pr_sigpend));
+ printf(_(" Blocked signal: %ld (%s)\n"),
+ pdata->pr_sighold, get_signal_type (pdata->pr_sighold));
+
+ arm_print_gregs(&pdata->pr_reg);
+
+ printf("\n FPU used: %s\n",pdata->pr_fpvalid ? _("YES") : _("NO"));
+
+ return 1;
+}
+
+static int
+process_prpsinfo (pnote)
+ Elf_External_Note *pnote;
+{
+ Elf32_Internal_Note *internal;
+ prpsinfo_t *pdata;
+
+ internal = (Elf32_Internal_Note *)pnote;
+ pdata = (prpsinfo_t*)(pnote->name + internal->namesz);
+
+ printf(_("\nPRPSINFO Note:\n"));
+
+ print_process_identifiers((unsigned long int)pdata->pr_pid,
+ (unsigned long int)pdata->pr_ppid,
+ (unsigned long int)pdata->pr_pgrp,
+ (unsigned long int)pdata->pr_sid);
+
+ printf(_("\n Process information:\n"));
+ printf(_(" Process filename: %s\n"), pdata->pr_fname);
+ printf(_(" Process arguments: %s\n"), pdata->pr_psargs);
+ printf(_(" Process user id: 0x%08lx\n"), pdata->pr_uid);
+ printf(_(" Process group id: 0x%08lx\n"), pdata->pr_gid);
+ printf(_(" Process flags: 0x%08lx\n"), pdata->pr_flag);
+ printf(_(" Process nice level: 0x%02x\n"), pdata->pr_nice);
+
+ printf(_(" Process state: %c (%0x02x)"),
+ pdata->pr_sname, pdata->pr_state);
+ printf(pdata->pr_zomb ? _(" (zombie)\n") : "\n");
+
+ return 1;
+}
+
+static int
+process_fpregset (pnote)
+ Elf_External_Note *pnote;
+{
+ Elf32_Internal_Note *internal;
+ struct user_fp *pdata;
+
+ internal = (Elf32_Internal_Note *)pnote;
+ pdata = (struct user_fp*)(pnote->name + internal->namesz);
+
+ printf(_("\nFPREGSET Note:"));
+ arm_print_fpregs (pdata);
+
+ return 1;
+}
+
+static int
+process_note_data (pnote)
+ Elf_External_Note *pnote;
+{
+ Elf32_Internal_Note *internal;
+ internal = (Elf32_Internal_Note *)pnote;
+
+ switch (internal->type)
+ {
+ case NT_PRSTATUS: return process_prstatus(pnote);
+ case NT_PRPSINFO: return process_prpsinfo(pnote);
+ case NT_FPREGSET: return process_fpregset(pnote);
+ case NT_TASKSTRUCT:
+ default:
+ return 0;
+ }
+}
+
+static int
+process_note_segment (file, offset, length)
+ FILE * file;
+ unsigned long offset;
+ unsigned long length;
+{
+ Elf_External_Note *pnotes, *external;
+ Elf32_Internal_Note *internal;
+ unsigned int notesz, nlength;
+ unsigned char *p;
+
+ if (length <= 0)
+ return(0);
+
+ GET_DATA_ALLOC (offset, length, pnotes, Elf_External_Note *, "notes");
+
+ external = pnotes;
+ p = (unsigned char *)pnotes;
+ nlength = length;
+
+ printf("\nNotes at offset 0x%08lx with length 0x%08lx:\n",offset,length);
+ printf(" Owner\t\tData size\tDescription\n");
+
+ while (nlength > 0) {
+ process_note (external);
+ internal = (Elf32_Internal_Note *)p;
+ notesz = 3*sizeof(unsigned long) + internal->namesz + internal->descsz;
+ nlength -= notesz;
+ p += notesz;
+ external = (Elf_External_Note *)p;
+ }
+
+ free (pnotes);
+ return 1;
+}
+
+static int
+process_note_segment_data (file, offset, length)
+ FILE * file;
+ unsigned long offset;
+ unsigned long length;
+{
+ Elf_External_Note *pnotes, *external;
+ Elf32_Internal_Note *internal;
+ unsigned int notesz, nlength;
+ unsigned char *p;
+
+ if (length <= 0)
+ return(0);
+
+ GET_DATA_ALLOC (offset, length, pnotes, Elf_External_Note *, "notes");
+
+ external = pnotes;
+ p = (unsigned char *)pnotes;
+ nlength = length;
+
+ while (nlength > 0) {
+ process_note_data (external);
+ internal = (Elf32_Internal_Note *)p;
+ notesz = 3*sizeof(unsigned long) + internal->namesz + internal->descsz;
+ nlength -= notesz;
+ p += notesz;
+ external = (Elf_External_Note *)p;
+ }
+
+ free (pnotes);
+ return 1;
+}
+
+static int
+process_note_segments (file)
+ FILE * file;
+{
+ Elf_Internal_Phdr * program_headers;
+ Elf_Internal_Phdr * segment;
+ unsigned int i;
+
+ program_headers = (Elf_Internal_Phdr *) malloc
+ (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+
+ if (program_headers == NULL)
+ {
+ error (_("Out of memory\n"));
+ return 0;
+ }
+
+ i = get_32bit_program_headers (file, program_headers);
+
+ if (i == 0)
+ {
+ free (program_headers);
+ return 0;
+ }
+
+ for (i = 0, segment = program_headers;
+ i < elf_header.e_phnum;
+ i ++, segment ++)
+ {
+ if (segment->p_type == PT_NOTE)
+ {
+ process_note_segment (file,
+ (unsigned long)segment->p_offset,
+ (unsigned long)segment->p_filesz);
+ }
+ }
+
+ for (i = 0, segment = program_headers;
+ i < elf_header.e_phnum;
+ i ++, segment ++)
+ {
+ if (segment->p_type == PT_NOTE)
+ {
+ process_note_segment_data (file,
+ (unsigned long)segment->p_offset,
+ (unsigned long)segment->p_filesz);
+ }
+ }
+
+ free (program_headers);
+ return 1;
+}
+
+static int
+process_arm_corefile (file)
+ FILE * file;
+{
+ /* if not a core file then exit */
+ if (elf_header.e_type != ET_CORE)
+ return 1;
+
+ /* no program headers means no NOTE segment */
+ if (elf_header.e_phnum == 0)
+ return 1;
+
+ process_note_segments (file);
+
+ return 1;
+}
+
+static int
process_arch_specific (file)
FILE * file;
{
@@ -6276,6 +6772,9 @@
switch (elf_header.e_machine)
{
+ case EM_ARM:
+ return process_arm_corefile (file);
+ break;
case EM_MIPS:
case EM_MIPS_RS4_BE:
return process_mips_specific (file);
Index: include/elf/common.h
===================================================================
RCS file: /cvs/binutils/binutils/include/elf/common.h,v
retrieving revision 1.3
diff -u -r1.3 common.h
--- common.h 1999/06/03 08:20:07 1.3
+++ common.h 1999/08/19 14:40:27
@@ -239,6 +239,7 @@
#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+#define NT_TASKSTRUCT 4 /* Contains copy of task struct */
/* Note segments for core files on dir-style procfs systems. */