This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch to readelf...


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 *)&regs->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. */
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]