public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* RFC: Objdump: Dumping PE specific headers
@ 2023-05-25 16:21 Nick Clifton
  2023-05-26  6:20 ` Jan Beulich
  2023-05-26 14:40 ` Nick Clifton
  0 siblings, 2 replies; 9+ messages in thread
From: Nick Clifton @ 2023-05-25 16:21 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1970 bytes --]

Hi Guys,

  Whilst looking at PR 310145, I realised that we currently do not have
  a way to display the contents of PE type files in their native
  format.  Since objdump does have a --private option which provides
  this kind of functionality for other file format types, I thought that
  it would be helpful if objdump could also handle PE files.  Hence this
  patch.

  At the moment it only dumps the file header and section headers, but
  this could be extended in the future.  (Especially if someone else is
  interested in doing the work...).  The output looks something like
  this:

    $ objdump -P header,sections test-section-flags.exe --wide

    test-section-flags.exe:     file format pei-x86-64

    PEI File Header:
      Magic:         0x5a4d		- IMAGE_DOS_SIGNATURE
      Machine Num:   0x8664		- AMD64
      Num sections:  6
      Time and date: 0x646f522d		- Thu May 25 13:18:53 2023
      Symbols off:   0x00001000
      Num symbols:   60
      Opt hdr sz:    240
      flags:         0x0226		- EXECUTABLE,LINE NUMS STRIPPED,LARGE ADDRESS AWARE,DEBUG STRIPPED

    Section headers (at 152+240=0x00000188 to 0x00000278):
     # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr  nrel  nlnno   Flags
     1 .text    00000030 00001000 00000200 00000400 00000000 00000000 0     0       60000020 EXECUTE,READ,CODE
     2 my_sect  00000004 00002000 00000200 00000600 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA
     3 .rdata   00000040 00003000 00000200 00000800 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
     4 .pdata   0000000c 00004000 00000200 00000a00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
     5 .xdata   00000008 00005000 00000200 00000c00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
     6 .idata   00000014 00006000 00000200 00000e00 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA

  Thoughts, comments ?

Cheers
  Nick


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: pr30145.patch --]
[-- Type: text/x-patch, Size: 15315 bytes --]

diff --git a/binutils/configure b/binutils/configure
index f27ee48be73..6987769fc51 100755
--- a/binutils/configure
+++ b/binutils/configure
@@ -14571,7 +14571,7 @@ do
 	fi
 	DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386"
 	BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)'
-	od_vectors="$od_vectors objdump_private_desc_xcoff"
+	od_vectors="$od_vectors objdump_private_desc_xcoff objdump_private_desc_pe"
     else
 	case $targ in
 	*-*-hms*) BUILD_SRCONV='$(SRCONV_PROG)' ;;
@@ -14685,6 +14685,9 @@ do
 	powerpc*-*-aix* | rs6000-*-aix*)
 	  od_vectors="$od_vectors objdump_private_desc_xcoff"
 	  ;;
+	*-*-pe* | *-*-cygwin* | *-*-mingw*)
+	  od_vectors="$od_vectors objdump_private_desc_pe"
+	  ;;
         *-*-darwin*)
 	  od_vectors="$od_vectors objdump_private_desc_mach_o"
 	  ;;
@@ -14706,6 +14709,8 @@ for i in $od_vectors ; do
 	    od_files="$od_files od-elf32_avr" ;;
 	objdump_private_desc_xcoff)
 	    od_files="$od_files od-xcoff" ;;
+	objdump_private_desc_pe)
+	    od_files="$od_files od-pe" ;;
 	objdump_private_desc_mach_o)
 	    od_files="$od_files od-macho" ;;
 	*) as_fn_error $? "*** unknown private vector $i" "$LINENO" 5 ;;
diff --git a/binutils/configure.ac b/binutils/configure.ac
index dc93ac1f390..b5798bf755f 100644
--- a/binutils/configure.ac
+++ b/binutils/configure.ac
@@ -348,7 +348,7 @@ do
 	fi
 	DLLTOOL_DEFS="$DLLTOOL_DEFS -DDLLTOOL_I386"
 	BUILD_DLLWRAP='$(DLLWRAP_PROG)$(EXEEXT)'
-	od_vectors="$od_vectors objdump_private_desc_xcoff"
+	od_vectors="$od_vectors objdump_private_desc_xcoff objdump_private_desc_pe"
     else
 	case $targ in
 	*-*-hms*) BUILD_SRCONV='$(SRCONV_PROG)' ;;
@@ -470,6 +470,9 @@ changequote([,])dnl
 	powerpc*-*-aix* | rs6000-*-aix*)
 	  od_vectors="$od_vectors objdump_private_desc_xcoff"
 	  ;;
+	*-*-pe* | *-*-cygwin* | *-*-mingw*)
+	  od_vectors="$od_vectors objdump_private_desc_pe"
+	  ;;
         *-*-darwin*)
 	  od_vectors="$od_vectors objdump_private_desc_mach_o"
 	  ;;
@@ -491,6 +494,8 @@ for i in $od_vectors ; do
 	    od_files="$od_files od-elf32_avr" ;;
 	objdump_private_desc_xcoff)
 	    od_files="$od_files od-xcoff" ;;
+	objdump_private_desc_pe)
+	    od_files="$od_files od-pe" ;;
 	objdump_private_desc_mach_o)
 	    od_files="$od_files od-macho" ;;
 	*) AC_MSG_ERROR(*** unknown private vector $i) ;;
diff --git a/binutils/objdump.c b/binutils/objdump.c
index 3f4399194ad..a35982ea969 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -115,7 +115,7 @@ static bool disassemble;		/* -d */
 static bool disassemble_all;		/* -D */
 static int disassemble_zeroes;		/* --disassemble-zeroes */
 static bool formats_info;		/* -i */
-static int wide_output;			/* -w */
+int wide_output;			/* -w */
 static int insn_width;			/* --insn-width */
 static bfd_vma start_address = (bfd_vma) -1; /* --start-address */
 static bfd_vma stop_address = (bfd_vma) -1;  /* --stop-address */
diff --git a/binutils/objdump.h b/binutils/objdump.h
index 4785489d42a..8d0b3878c1c 100644
--- a/binutils/objdump.h
+++ b/binutils/objdump.h
@@ -18,6 +18,9 @@
    Foundation, 51 Franklin Street - Fifth Floor, Boston,
    MA 02110-1301, USA.  */
 
+/* Non-zero if wide output has been enabled.  */
+extern int wide_output;	
+
 struct objdump_private_option
 {
   /* Option name.  */
@@ -43,11 +46,15 @@ struct objdump_private_desc
   /* List of options.  Terminated by a NULL name.  */
   struct objdump_private_option *options;
 };
+
 /* ELF32_AVR specific target.  */
 extern const struct objdump_private_desc objdump_private_desc_elf32_avr;
 
 /* XCOFF specific target.  */
 extern const struct objdump_private_desc objdump_private_desc_xcoff;
 
+/* PE specific target.  */
+extern const struct objdump_private_desc objdump_private_desc_pe;
+
 /* Mach-O specific target.  */
 extern const struct objdump_private_desc objdump_private_desc_mach_o;
--- /dev/null	2023-05-25 08:58:13.102395769 +0100
+++ current/binutils/od-pe.c	2023-05-25 17:08:28.632031144 +0100
@@ -0,0 +1,388 @@
+/* od-pe.c -- dump information about a PE object file.
+   Copyright (C) 2011-2023 Free Software Foundation, Inc.
+   Written by Tristan Gingold, Adacore and Nick Clifton, Red Hat.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include <stddef.h>
+#include <time.h>
+#include "safe-ctype.h"
+#include "bfd.h"
+#include "objdump.h"
+#include "bucomm.h"
+#include "bfdlink.h"
+#include "coff/internal.h"
+#define L_LNNO_SIZE 4 /* FIXME: which value should we use ?  */
+#include "coff/external.h"
+#include "coff/pe.h"
+#include "libcoff.h"
+#include "libpei.h"
+
+/* Index of the options in the options[] array.  */
+#define OPT_FILE_HEADER 0
+#define OPT_AOUT 1
+#define OPT_SECTIONS 2
+#define OPT_SYMS 3
+#define OPT_RELOCS 4
+#define OPT_LINENO 5
+#define OPT_LOADER 6
+#define OPT_EXCEPT 7
+#define OPT_TYPCHK 8
+#define OPT_TRACEBACK 9
+#define OPT_TOC 10
+#define OPT_LDINFO 11
+
+/* List of actions.  */
+static struct objdump_private_option options[] =
+  {
+    { "header", 0 },
+    { "aout", 0 },
+    { "sections", 0 },
+    { "syms", 0 },
+    { "relocs", 0 },
+    { "lineno", 0 },
+    { "loader", 0 },
+    { "except", 0 },
+    { "typchk", 0 },
+    { "traceback", 0 },
+    { "toc", 0 },
+    { "ldinfo", 0 },
+    { NULL, 0 }
+  };
+
+/* Simplified section header.  */
+struct pe_section
+{
+  /* NUL terminated name.  */
+  char name[9];
+
+  /* Section flags.  */
+  unsigned int flags;
+
+  /* Offsets in file.  */
+  ufile_ptr scnptr;
+  ufile_ptr relptr;
+  ufile_ptr lnnoptr;
+
+  /* Number of relocs and line numbers.  */
+  unsigned int nreloc;
+  unsigned int nlnno;
+};
+
+/* Translation entry type.  The last entry must be {0, NULL}.  */
+
+struct xlat_table
+{
+  unsigned int  val;
+  const char *  name;
+};
+
+/* PE file flags.  */
+static const struct xlat_table file_flag_xlat[] =
+  {
+    { IMAGE_FILE_RELOCS_STRIPPED,     "RELOCS STRIPPED"},
+    { IMAGE_FILE_EXECUTABLE_IMAGE,    "EXECUTABLE"},
+    { IMAGE_FILE_LINE_NUMS_STRIPPED,  "LINE NUMS STRIPPED"},
+    { IMAGE_FILE_LOCAL_SYMS_STRIPPED, "LOCAL SYMS STRIPPED"},
+    { IMAGE_FILE_AGGRESSIVE_WS_TRIM,  "AGGRESSIVE WS TRIM"},
+    { IMAGE_FILE_LARGE_ADDRESS_AWARE, "LARGE ADDRESS AWARE"},
+    { IMAGE_FILE_16BIT_MACHINE,       "16BIT MACHINE"},
+    { IMAGE_FILE_BYTES_REVERSED_LO,   "BYTES REVERSED LO"},
+    { IMAGE_FILE_32BIT_MACHINE,       "32BIT MACHINE"},
+    { IMAGE_FILE_DEBUG_STRIPPED,      "DEBUG STRIPPED"},
+    { IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, "REMOVABLE RUN FROM SWAP"},
+    { IMAGE_FILE_NET_RUN_FROM_SWAP,   "NET RUN FROM SWAP"},
+    { IMAGE_FILE_SYSTEM,              "SYSTEM"},
+    { IMAGE_FILE_DLL,                 "DLL"},
+    { IMAGE_FILE_UP_SYSTEM_ONLY,      "UP SYSTEM ONLY"},
+    { IMAGE_FILE_BYTES_REVERSED_HI,   "BYTES REVERSED HI"},
+    { 0, NULL }
+  };
+
+/* PE section flags.  */
+static const struct xlat_table section_flag_xlat[] =
+  {
+    { IMAGE_SCN_MEM_DISCARDABLE, "DISCARDABLE" },
+    { IMAGE_SCN_MEM_EXECUTE,     "EXECUTE" },
+    { IMAGE_SCN_MEM_READ,        "READ" },
+    { IMAGE_SCN_MEM_WRITE,       "WRITE" },
+    { IMAGE_SCN_TYPE_NO_PAD,     "NO PAD" },
+    { IMAGE_SCN_CNT_CODE,        "CODE" },
+    { IMAGE_SCN_CNT_INITIALIZED_DATA,   "INITIALIZED DATA" },
+    { IMAGE_SCN_CNT_UNINITIALIZED_DATA, "UNINITIALIZED DATA" },
+    { IMAGE_SCN_LNK_OTHER,       "OTHER" },
+    { IMAGE_SCN_LNK_INFO,        "INFO" },
+    { IMAGE_SCN_LNK_REMOVE,      "REMOVE" },
+    { IMAGE_SCN_LNK_COMDAT,      "COMDAT" },
+    { IMAGE_SCN_MEM_FARDATA,     "FARDATA" },
+    { IMAGE_SCN_MEM_PURGEABLE,   "PURGEABLE" },
+    { IMAGE_SCN_MEM_16BIT,       "16BIT" },
+    { IMAGE_SCN_MEM_LOCKED,      "LOCKED" },
+    { IMAGE_SCN_MEM_PRELOAD,     "PRELOAD" },
+    { IMAGE_SCN_LNK_NRELOC_OVFL, "NRELOC OVFL" },
+    { IMAGE_SCN_MEM_NOT_CACHED,  "NOT CACHED" },
+    { IMAGE_SCN_MEM_NOT_PAGED,   "NOT PAGED" },
+    { IMAGE_SCN_MEM_SHARED,      "SHARED" },    
+    { 0, NULL }
+  };
+
+
+/* Display help.  */
+
+static void
+pe_help (FILE *stream)
+{
+  fprintf (stream, _("\
+For PE files:\n\
+  header      Display the file header\n\
+  sections    Display the section headers\n\
+"));
+}
+
+/* Return true if ABFD is handled.  */
+
+static int
+pe_filter (bfd *abfd)
+{
+  return bfd_get_flavour (abfd) == bfd_target_coff_flavour;
+}
+
+/* Display the list of name (from TABLE) for FLAGS, using comma to separate
+   them.  A name is displayed if FLAGS & VAL is not 0.  */
+
+static void
+dump_flags (const struct xlat_table * table, unsigned int flags)
+{
+  unsigned int r = flags;
+  bool first = true;
+  const struct xlat_table *t;
+
+  for (t = table; t->name; t++)
+    if ((flags & t->val) != 0)
+      {
+        r &= ~t->val;
+
+        if (first)
+          first = false;
+        else
+          putchar (',');
+        fputs (t->name, stdout);
+      }
+
+  /* Undecoded flags.  */
+  if (r != 0)
+    {
+      if (!first)
+        putchar (',');
+      printf (_("unknown: 0x%x"), r);
+    }
+}
+
+static void
+decode_machine_number (unsigned int machine)
+{
+  switch (machine)
+    {
+    case IMAGE_FILE_MACHINE_ARM: printf ("ARM\n"); break;
+    case IMAGE_FILE_MACHINE_ARM64: printf ("ARM64\n"); break;
+    case IMAGE_FILE_MACHINE_I386: printf ("I386\n"); break;
+    case IMAGE_FILE_MACHINE_POWERPC: printf ("POWERPC\n"); break;
+    case IMAGE_FILE_MACHINE_LOONGARCH64: printf ("LOONGARCH64\n"); break;
+    case IMAGE_FILE_MACHINE_AMD64: printf ("AMD64\n"); break;
+
+      // FIXME: Add more machine numbers.
+    default: printf (_("unknown\n"));
+    }
+}
+
+/* Dump the file header.  */
+
+static void
+dump_pe_file_header (bfd * abfd, struct external_PEI_filehdr * fhdr)
+{
+  printf (_("\nPEI File Header:\n"));
+  printf (_("  Magic:         %#x\t\t- IMAGE_DOS_SIGNATURE\n"), (int) bfd_h_get_16 (abfd, fhdr->e_magic));
+
+  unsigned int machine = (int) bfd_h_get_16 (abfd, fhdr->f_magic);
+  printf (_("  Machine Num:   %#x\t\t- "), machine);
+  decode_machine_number (machine);
+
+  printf (_("  Num sections:  %d\n"), (int) bfd_h_get_16 (abfd, fhdr->f_nscns));
+
+  long timedat = bfd_h_get_32 (abfd, fhdr->f_timdat);
+  printf (_("  Time and date: 0x%08lx\t- "), timedat);
+  if (timedat == 0)
+    printf (_("not set\n"));
+  else
+    {
+      /* Not correct on all platforms, but works on unix.  */
+      time_t t = timedat;
+      fputs (ctime (& t), stdout);
+    }
+
+  printf (_("  Symbols off:   0x%08lx\n"), (long) bfd_h_get_32 (abfd, fhdr->f_symptr));
+  printf (_("  Num symbols:   %ld\n"), (long) bfd_h_get_32 (abfd, fhdr->f_nsyms));
+  printf (_("  Opt hdr sz:    %d\n"), (int) bfd_h_get_16 (abfd, fhdr->f_opthdr));
+
+  unsigned int flags = (int) bfd_h_get_16 (abfd, fhdr->f_flags);
+  printf (_("  flags:         0x%04x\t\t- "), flags);
+  dump_flags (file_flag_xlat, flags);
+
+  putchar ('\n');
+}
+
+/* Dump the sections header.  */
+
+static void
+dump_pe_sections_header (bfd * abfd, struct external_PEI_filehdr * hdr)
+{
+  unsigned int off;
+  unsigned int opthdr = (unsigned int) bfd_h_get_16 (abfd, hdr->f_opthdr);
+  unsigned int n_scns = (unsigned int) bfd_h_get_16 (abfd, hdr->f_nscns);
+
+  off = sizeof (struct external_PEI_filehdr) + opthdr;
+
+  printf (_("\nSection headers (at %u+%u=0x%08x to 0x%08x):\n"),
+          (unsigned int) sizeof (struct external_PEI_filehdr), opthdr, off,
+          off + (unsigned int) sizeof (struct external_scnhdr) * n_scns);
+
+  if (n_scns == 0)
+    {
+      printf (_("  No section headers\n"));
+      return;
+    }
+  if (bfd_seek (abfd, off, SEEK_SET) != 0)
+    {
+      non_fatal (_("cannot seek to section headers start\n"));
+      return;
+    }
+
+  /* We don't translate this string as it consists of field names.  */
+  if (wide_output)
+    printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr  nrel  nlnno   Flags\n");
+  else
+    printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr  nrel  nlnno\n");
+
+  unsigned int i;
+  for (i = 0; i < n_scns; i++)
+    {
+      struct external_scnhdr scn;
+      unsigned int flags;
+
+      if (bfd_bread (& scn, sizeof (scn), abfd) != sizeof (scn))
+        {
+          non_fatal (_("cannot read section header"));
+          return;
+        }
+
+      printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %-5d %-5d",
+              i + 1, scn.s_name,
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_paddr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_vaddr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_size),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_scnptr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_relptr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_lnnoptr),
+              (unsigned int) bfd_h_get_16 (abfd, scn.s_nreloc),
+              (unsigned int) bfd_h_get_16 (abfd, scn.s_nlnno));
+
+      flags = bfd_h_get_32 (abfd, scn.s_flags);
+      if (wide_output)
+	printf (_("   %08x "), flags);
+      else
+	printf (_("\n            Flags: %08x: "), flags);
+
+      if (~flags == 0)
+        {
+          /* Stripped executable ?  */
+          putchar ('\n');
+        }
+      else
+        {
+	  flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK;
+          dump_flags (section_flag_xlat, flags);
+          putchar ('\n');
+        }
+    }
+}
+
+/* Handle a PE format file.  */
+
+static void
+dump_pe (bfd * abfd, struct external_PEI_filehdr * fhdr)
+{
+  unsigned short magic = bfd_h_get_16 (abfd, fhdr->e_magic);
+
+  if (magic != IMAGE_DOS_SIGNATURE)
+    {
+      non_fatal ("not a PE format file - unexpected magic number");
+      return;
+    }
+  
+  if (options[OPT_FILE_HEADER].selected)
+    dump_pe_file_header (abfd, fhdr);
+  
+  if (options[OPT_SECTIONS].selected)
+    dump_pe_sections_header (abfd, fhdr);
+}
+
+/* Dump ABFD (according to the options[] array).  */
+
+static void
+pe_dump_obj (bfd *abfd)
+{
+  struct external_PEI_filehdr fhdr;
+
+  /* Read file header.  */
+  if (bfd_seek (abfd, 0, SEEK_SET) != 0
+      || bfd_bread (& fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
+    {
+      non_fatal (_("cannot seek to/read file header"));
+      return;
+    }
+
+  dump_pe (abfd, & fhdr);
+}
+
+/* Dump a PE file.  */
+
+static void
+pe_dump (bfd *abfd)
+{
+  /* We rely on BFD to decide if the file is a core file.  Note that core
+     files are only supported on native environment by BFD.  */
+  switch (bfd_get_format (abfd))
+    {
+    case bfd_core:
+      break;
+    default:
+      pe_dump_obj (abfd);
+      break;
+    }
+}
+
+/* Vector for pe.  */
+
+const struct objdump_private_desc objdump_private_desc_pe =
+  {
+    pe_help,
+    pe_filter,
+    pe_dump,
+    options
+  };

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-25 16:21 RFC: Objdump: Dumping PE specific headers Nick Clifton
@ 2023-05-26  6:20 ` Jan Beulich
  2023-05-26 15:44   ` Fangrui Song
       [not found]   ` <DS7PR12MB5765E0FC436669802ABB76ABCB479@DS7PR12MB5765.namprd12.prod.outlook.com>
  2023-05-26 14:40 ` Nick Clifton
  1 sibling, 2 replies; 9+ messages in thread
From: Jan Beulich @ 2023-05-26  6:20 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

Nick,

On 25.05.2023 18:21, Nick Clifton via Binutils wrote:
>   Whilst looking at PR 310145, I realised that we currently do not have
>   a way to display the contents of PE type files in their native
>   format.  Since objdump does have a --private option which provides
>   this kind of functionality for other file format types, I thought that
>   it would be helpful if objdump could also handle PE files.  Hence this
>   patch.
> 
>   At the moment it only dumps the file header and section headers, but
>   this could be extended in the future.  (Especially if someone else is
>   interested in doing the work...).  The output looks something like
>   this:
> 
>     $ objdump -P header,sections test-section-flags.exe --wide
> 
>     test-section-flags.exe:     file format pei-x86-64
> 
>     PEI File Header:
>       Magic:         0x5a4d		- IMAGE_DOS_SIGNATURE
>       Machine Num:   0x8664		- AMD64
>       Num sections:  6
>       Time and date: 0x646f522d		- Thu May 25 13:18:53 2023
>       Symbols off:   0x00001000
>       Num symbols:   60
>       Opt hdr sz:    240
>       flags:         0x0226		- EXECUTABLE,LINE NUMS STRIPPED,LARGE ADDRESS AWARE,DEBUG STRIPPED
> 
>     Section headers (at 152+240=0x00000188 to 0x00000278):
>      # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr  nrel  nlnno   Flags
>      1 .text    00000030 00001000 00000200 00000400 00000000 00000000 0     0       60000020 EXECUTE,READ,CODE
>      2 my_sect  00000004 00002000 00000200 00000600 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA
>      3 .rdata   00000040 00003000 00000200 00000800 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
>      4 .pdata   0000000c 00004000 00000200 00000a00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
>      5 .xdata   00000008 00005000 00000200 00000c00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
>      6 .idata   00000014 00006000 00000200 00000e00 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA
> 
>   Thoughts, comments ?

thanks for doing this; I had been wondering several times in the past
whether I simply didn't know the right option to pass to have such
information printed. Just one remark: I don't think printing the
signature (Magic:) at the beginning of the file is useful here either,
as without that signature no output would appear anyway (for the file
being unrecognized), and afaik there are no alternative signatures
that could be in use. Instead what may be of interest to print is the
file offset of the PE header/signature, as especially in older
(bi-modal) binaries this may not be near the beginning of the file. I
don't see this information being printed by any other option.

Another minor aspect: The nrel and nlnno fields of the section dump
may read better (if any are non-zero) when padded to the left, not to
the right.

Jan

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-25 16:21 RFC: Objdump: Dumping PE specific headers Nick Clifton
  2023-05-26  6:20 ` Jan Beulich
@ 2023-05-26 14:40 ` Nick Clifton
  2023-05-28  3:13   ` Alan Modra
  1 sibling, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2023-05-26 14:40 UTC (permalink / raw)
  To: binutils

[-- Attachment #1: Type: text/plain, Size: 1204 bytes --]

Hi Guys,

   Right - I am commit the attached, revised version of my original patch.

   Following Jan's suggestions I have changed the layout slightly and dropped
   this display of the IMAGE_DOS_SIGNATURE magic number.  In addition I have
   added:

     * Support for displaying some of the contents of the optional header,
       if it is present.

     * Support for displaying PE format object files (which do not have the
       PEI_filehdr structure at the start of the file).

     * Documentation (gasp), a testcase and a NEWS entry.

Cheers
   Nick

2023-05-26  Nick Clifton  <nickc@redhat.com>

	* od-pe.c: New file: Dumps fields in PE format headers.
	* configure.ac (od_vectors): Add objdump_private_desc_pe for PE
	format targets.
	(od_files): Add od-pe for PE format targets.
	* configure: Regenerate.
	* Makefile.am (CFILES): Add od-pe.c
	(EXTRA_objdump_SOURCE): Likewise.
	* Makefile.in: Generate.
	* NEWS: Mention the new feature.
	* doc/binutils.texi: Document the new support.
	* objdump.c (wide_output): Change from local to global.
	* objdump.h (wide_output): Prototype.
	(objdump_private_desc_pe): Prototype.
	* testsuite/binutils-all/objdump.exp: Add a test of the new feature.


[-- Attachment #2: fred --]
[-- Type: text/plain, Size: 16679 bytes --]

--- /dev/null	2023-05-25 08:58:13.102395769 +0100
+++ current/binutils/od-pe.c	2023-05-26 15:24:38.401889536 +0100
@@ -0,0 +1,565 @@
+/* od-pe.c -- dump information about a PE object file.
+   Copyright (C) 2011-2023 Free Software Foundation, Inc.
+   Written by Tristan Gingold, Adacore and Nick Clifton, Red Hat.
+
+   This file is part of GNU Binutils.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include "sysdep.h"
+#include <stddef.h>
+#include <time.h>
+#include "safe-ctype.h"
+#include "bfd.h"
+#include "objdump.h"
+#include "bucomm.h"
+#include "bfdlink.h"
+#include "coff/internal.h"
+#define L_LNNO_SIZE 4 /* FIXME: which value should we use ?  */
+#include "coff/external.h"
+#include "coff/pe.h"
+#include "libcoff.h"
+#include "libpei.h"
+
+/* Index of the options in the options[] array.  */
+#define OPT_FILE_HEADER 0
+#define OPT_AOUT 1
+#define OPT_SECTIONS 2
+#define OPT_SYMS 3
+#define OPT_RELOCS 4
+#define OPT_LINENO 5
+#define OPT_LOADER 6
+#define OPT_EXCEPT 7
+#define OPT_TYPCHK 8
+#define OPT_TRACEBACK 9
+#define OPT_TOC 10
+#define OPT_LDINFO 11
+
+/* List of actions.  */
+static struct objdump_private_option options[] =
+{
+  { "header", 0 },
+  { "aout", 0 },
+  { "sections", 0 },
+  { "syms", 0 },
+  { "relocs", 0 },
+  { "lineno", 0 },
+  { "loader", 0 },
+  { "except", 0 },
+  { "typchk", 0 },
+  { "traceback", 0 },
+  { "toc", 0 },
+  { "ldinfo", 0 },
+  { NULL, 0 }
+};
+
+/* Simplified section header.  */
+struct pe_section
+{
+  /* NUL terminated name.  */
+  char name[9];
+
+  /* Section flags.  */
+  unsigned int flags;
+
+  /* Offsets in file.  */
+  ufile_ptr scnptr;
+  ufile_ptr relptr;
+  ufile_ptr lnnoptr;
+
+  /* Number of relocs and line numbers.  */
+  unsigned int nreloc;
+  unsigned int nlnno;
+};
+
+/* Translation entry type.  The last entry must be {0, NULL}.  */
+
+struct xlat_table
+{
+  unsigned int  val;
+  const char *  name;
+};
+
+/* PE file flags.  */
+static const struct xlat_table file_flag_xlat[] =
+{
+  { IMAGE_FILE_RELOCS_STRIPPED,     "RELOCS STRIPPED"},
+  { IMAGE_FILE_EXECUTABLE_IMAGE,    "EXECUTABLE"},
+  { IMAGE_FILE_LINE_NUMS_STRIPPED,  "LINE NUMS STRIPPED"},
+  { IMAGE_FILE_LOCAL_SYMS_STRIPPED, "LOCAL SYMS STRIPPED"},
+  { IMAGE_FILE_AGGRESSIVE_WS_TRIM,  "AGGRESSIVE WS TRIM"},
+  { IMAGE_FILE_LARGE_ADDRESS_AWARE, "LARGE ADDRESS AWARE"},
+  { IMAGE_FILE_16BIT_MACHINE,       "16BIT MACHINE"},
+  { IMAGE_FILE_BYTES_REVERSED_LO,   "BYTES REVERSED LO"},
+  { IMAGE_FILE_32BIT_MACHINE,       "32BIT MACHINE"},
+  { IMAGE_FILE_DEBUG_STRIPPED,      "DEBUG STRIPPED"},
+  { IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, "REMOVABLE RUN FROM SWAP"},
+  { IMAGE_FILE_NET_RUN_FROM_SWAP,   "NET RUN FROM SWAP"},
+  { IMAGE_FILE_SYSTEM,              "SYSTEM"},
+  { IMAGE_FILE_DLL,                 "DLL"},
+  { IMAGE_FILE_UP_SYSTEM_ONLY,      "UP SYSTEM ONLY"},
+  { IMAGE_FILE_BYTES_REVERSED_HI,   "BYTES REVERSED HI"},
+  { 0, NULL }
+};
+
+/* PE section flags.  */
+static const struct xlat_table section_flag_xlat[] =
+{
+  { IMAGE_SCN_MEM_DISCARDABLE, "DISCARDABLE" },
+  { IMAGE_SCN_MEM_EXECUTE,     "EXECUTE" },
+  { IMAGE_SCN_MEM_READ,        "READ" },
+  { IMAGE_SCN_MEM_WRITE,       "WRITE" },
+  { IMAGE_SCN_TYPE_NO_PAD,     "NO PAD" },
+  { IMAGE_SCN_CNT_CODE,        "CODE" },
+  { IMAGE_SCN_CNT_INITIALIZED_DATA,   "INITIALIZED DATA" },
+  { IMAGE_SCN_CNT_UNINITIALIZED_DATA, "UNINITIALIZED DATA" },
+  { IMAGE_SCN_LNK_OTHER,       "OTHER" },
+  { IMAGE_SCN_LNK_INFO,        "INFO" },
+  { IMAGE_SCN_LNK_REMOVE,      "REMOVE" },
+  { IMAGE_SCN_LNK_COMDAT,      "COMDAT" },
+  { IMAGE_SCN_MEM_FARDATA,     "FARDATA" },
+  { IMAGE_SCN_MEM_PURGEABLE,   "PURGEABLE" },
+  { IMAGE_SCN_MEM_LOCKED,      "LOCKED" },
+  { IMAGE_SCN_MEM_PRELOAD,     "PRELOAD" },
+  { IMAGE_SCN_LNK_NRELOC_OVFL, "NRELOC OVFL" },
+  { IMAGE_SCN_MEM_NOT_CACHED,  "NOT CACHED" },
+  { IMAGE_SCN_MEM_NOT_PAGED,   "NOT PAGED" },
+  { IMAGE_SCN_MEM_SHARED,      "SHARED" },    
+  { 0, NULL }
+};
+
+
+/* Display help.  */
+
+static void
+pe_help (FILE *stream)
+{
+  fprintf (stream, _("\
+For PE files:\n\
+  header      Display the file header\n\
+  sections    Display the section headers\n\
+"));
+}
+
+/* Return true if ABFD is handled.  */
+
+static int
+pe_filter (bfd *abfd)
+{
+  return bfd_get_flavour (abfd) == bfd_target_coff_flavour;
+}
+
+/* Display the list of name (from TABLE) for FLAGS, using comma to
+   separate them.  A name is displayed if FLAGS & VAL is not 0.  */
+
+static void
+dump_flags (const struct xlat_table * table, unsigned int flags)
+{
+  unsigned int r = flags;
+  bool first = true;
+  const struct xlat_table *t;
+
+  for (t = table; t->name; t++)
+    if ((flags & t->val) != 0)
+      {
+        r &= ~t->val;
+
+        if (first)
+          first = false;
+        else
+          putchar (',');
+        fputs (t->name, stdout);
+      }
+
+  /* Undecoded flags.  */
+  if (r != 0)
+    {
+      if (!first)
+        putchar (',');
+      printf (_("unknown: 0x%x"), r);
+    }
+}
+
+static const char *
+decode_machine_number (unsigned int machine)
+{
+  switch (machine)
+    {
+    case IMAGE_FILE_MACHINE_ALPHA:       return "ALPHA";
+    case IMAGE_FILE_MACHINE_AMD64:       return "AMD64";
+    case IMAGE_FILE_MACHINE_ARM:         return "ARM";
+    case IMAGE_FILE_MACHINE_ARM64:       return "ARM64";
+    case IMAGE_FILE_MACHINE_I386:        return "I386";
+    case IMAGE_FILE_MACHINE_IA64:        return "IA64";
+    case IMAGE_FILE_MACHINE_LOONGARCH64: return "LOONGARCH64";
+    case IMAGE_FILE_MACHINE_POWERPC:     return "POWERPC";
+    case 0x0500:                         return "SH (big endian)";
+    case 0x0550:                         return "SH (little endian)";
+    case 0x0b00:                         return "MCore";
+    case 0x0093:                         return "TI C4X";
+      // FIXME: Add more machine numbers.
+    default: return N_("unknown");
+    }
+}
+
+/* Dump the file header.  */
+
+static void
+dump_pe_file_header (bfd *                            abfd,
+		     struct external_PEI_filehdr *    fhdr,
+		     struct external_PEI_IMAGE_hdr *  ihdr)
+{
+  unsigned long ihdr_off = 0;
+
+  if (fhdr != NULL)
+    {
+      printf (_("\nFile Header:\n"));
+
+      /* FIXME: The fields in the file header are boring an generally have
+	 fixed values.  Is there any benefit in displaying them ?  */
+
+      /* Display the first string found in the stub.
+	 FIXME: Look for more than one string ?
+	 FIXME: Strictly speaking we may not have read the full stub, since
+	 it can be longer than the dos_message array in the PEI_fileheader
+	 structure.  */
+      const unsigned char * message = (const unsigned char *) fhdr->dos_message;
+      unsigned int len = sizeof (fhdr->dos_message);
+      unsigned int i;
+      unsigned int seen_count = 0;
+      unsigned int string_start = 0;
+  
+      for (i = 0; i < len; i++)
+	{
+	  if (ISPRINT (message[i]))
+	    {
+	      if (string_start == 0)
+		string_start = i;
+	      ++ seen_count;
+	      if (seen_count > 4)
+		break;
+	    }
+	  else
+	    {
+	      seen_count = string_start = 0;
+	    }
+	}
+
+      if (seen_count > 4)
+	{
+	  printf (_("  Stub message:  "));
+	  while (string_start < len)
+	    {
+	      char c = message[string_start ++];
+	      if (! ISPRINT (c))
+		break;
+	      putchar (c);
+	    }
+	  putchar ('\n');
+	}
+
+      ihdr_off = (long) bfd_h_get_32 (abfd, fhdr->e_lfanew);
+    }
+
+  printf (_("\nImage Header (at offset %#lx):\n"), ihdr_off);
+	  
+  unsigned int machine = (int) bfd_h_get_16 (abfd, ihdr->f_magic);
+  printf (_("  Machine Num:   %#x\t\t- %s\n"), machine,
+	  decode_machine_number (machine));
+
+  printf (_("  Num sections:  %d\n"), (int) bfd_h_get_16 (abfd, ihdr->f_nscns));
+
+  long timedat = bfd_h_get_32 (abfd, ihdr->f_timdat);
+  printf (_("  Time and date: %#08lx\t- "), timedat);
+  if (timedat == 0)
+    printf (_("not set\n"));
+  else
+    {
+      /* Not correct on all platforms, but works on unix.  */
+      time_t t = timedat;
+      fputs (ctime (& t), stdout);
+    }
+
+  printf (_("  Symbols off:   %#08lx\n"),
+	  (long) bfd_h_get_32 (abfd, ihdr->f_symptr));
+  printf (_("  Num symbols:   %ld\n"),
+	  (long) bfd_h_get_32 (abfd, ihdr->f_nsyms));
+
+  unsigned int opt_header_size = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
+  printf (_("  Opt hdr sz:    %#x\n"), opt_header_size);
+
+  unsigned int flags = (int) bfd_h_get_16 (abfd, ihdr->f_flags);
+  printf (_("  Flags:         0x%04x\t\t- "), flags);
+  dump_flags (file_flag_xlat, flags);
+  putchar ('\n');
+
+  if (opt_header_size == PEPAOUTSZ)
+    {
+      PEPAOUTHDR xhdr;
+
+      printf (_("\nOptional PE+ Header (at offset %#lx):\n"),
+	      ihdr_off + sizeof (* ihdr));
+
+      if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0
+	  || bfd_bread (& xhdr, sizeof (xhdr), abfd) != sizeof (xhdr))
+	printf ("error: unable to read PE+ header\n");
+      else
+	{
+	  /* FIXME: Check that the magic number is 0x020b ?  */
+	  printf (_("  Magic:         %x\n"),
+		  (int) bfd_h_get_16 (abfd, xhdr.standard.magic));
+	  printf (_("  Image Base:    %lx\n"),
+		  (long) bfd_h_get_64 (abfd, xhdr.ImageBase));
+	  /* FIXME: Print more fields.  */
+	}
+    }
+  else if (opt_header_size == AOUTSZ)
+    {
+      PEAOUTHDR xhdr;
+
+      printf (_("\nOptional PE Header (at offset %#lx):\n"),
+	      ihdr_off + sizeof (* ihdr));
+
+      if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0
+	  || bfd_bread (& xhdr, sizeof (xhdr), abfd) != sizeof (xhdr))
+	printf ("error: unable to read PE+ header\n");
+      else
+	{
+	  /* FIXME: Check that the magic number is 0x010b ?  */
+	  printf (_("  Magic:         %x\n"),
+		  (int) bfd_h_get_16 (abfd, xhdr.standard.magic));
+	  printf (_("  Image Base:    %lx\n"),
+		  (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
+	  /* FIXME: Print more fields.  */
+	}
+    }
+  else if (opt_header_size != 0)
+    {
+      printf (_("\nUnsupported size of Optional Header\n"));
+    }
+}
+
+/* Dump the sections header.  */
+
+static void
+dump_pe_sections_header (bfd *                            abfd,
+			 struct external_PEI_filehdr *    fhdr,
+			 struct external_PEI_IMAGE_hdr *  ihdr)
+{
+  unsigned int opthdr = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
+  unsigned int n_scns = (int) bfd_h_get_16 (abfd, ihdr->f_nscns);
+  unsigned int off;
+
+  /* The section header starts after the file, image and optional headers.  */  
+  if (fhdr == NULL)
+    off = sizeof (struct external_filehdr) + opthdr;
+  else
+    off = (int) bfd_h_get_16 (abfd, fhdr->e_lfanew) + sizeof (* ihdr) + opthdr;
+
+  printf (_("\nSection headers (at offset 0x%08x):\n"), off);
+
+  if (n_scns == 0)
+    {
+      printf (_("  No section headers\n"));
+      return;
+    }
+  if (bfd_seek (abfd, off, SEEK_SET) != 0)
+    {
+      non_fatal (_("cannot seek to section headers start\n"));
+      return;
+    }
+
+  /* We don't translate this string as it consists of field names.  */
+  if (wide_output)
+    printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno   Flags\n");
+  else
+    printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno\n");
+
+  unsigned int i;
+  for (i = 0; i < n_scns; i++)
+    {
+      struct external_scnhdr scn;
+      unsigned int flags;
+
+      if (bfd_bread (& scn, sizeof (scn), abfd) != sizeof (scn))
+        {
+          non_fatal (_("cannot read section header"));
+          return;
+        }
+
+      printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %5d %5d",
+              i + 1, scn.s_name,
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_paddr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_vaddr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_size),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_scnptr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_relptr),
+              (unsigned int) bfd_h_get_32 (abfd, scn.s_lnnoptr),
+              (unsigned int) bfd_h_get_16 (abfd, scn.s_nreloc),
+              (unsigned int) bfd_h_get_16 (abfd, scn.s_nlnno));
+
+      flags = bfd_h_get_32 (abfd, scn.s_flags);
+      if (wide_output)
+	printf (_("   %08x "), flags);
+      else
+	printf (_("\n            Flags: %08x: "), flags);
+
+      if (flags != 0)
+        {
+	  /* Skip the alignment bits.  */
+	  flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK;
+          dump_flags (section_flag_xlat, flags);
+        }
+
+      putchar ('\n');
+    }
+}
+
+/* Handle a PE format file.  */
+
+static void
+dump_pe (bfd *                            abfd,
+	 struct external_PEI_filehdr *    fhdr,
+	 struct external_PEI_IMAGE_hdr *  ihdr)
+{
+  if (options[OPT_FILE_HEADER].selected)
+    dump_pe_file_header (abfd, fhdr, ihdr);
+  
+  if (options[OPT_SECTIONS].selected)
+    dump_pe_sections_header (abfd, fhdr, ihdr);
+}
+
+static bool
+is_pe_object_magic (unsigned short magic)
+{
+  switch (magic)
+    {
+    case IMAGE_FILE_MACHINE_ALPHA:
+    case IMAGE_FILE_MACHINE_ARM:
+    case IMAGE_FILE_MACHINE_ARM64:
+    case IMAGE_FILE_MACHINE_I386:
+    case IMAGE_FILE_MACHINE_IA64:
+    case IMAGE_FILE_MACHINE_POWERPC:
+    case IMAGE_FILE_MACHINE_LOONGARCH64:
+    case IMAGE_FILE_MACHINE_AMD64:
+      // FIXME: Add more machine numbers.
+      return true;
+    case 0x0500: /* SH_ARCH_MAGIC_BIG */
+    case 0x0550: /* SH_ARCH_MAGIC_LITTLE */
+    case 0x0b00: /* MCore */
+    case 0x0093: /* TI C4x */
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Dump ABFD (according to the options[] array).  */
+
+static void
+pe_dump_obj (bfd *abfd)
+{
+  struct external_PEI_filehdr fhdr;
+
+  /* Read file header.  */
+  if (bfd_seek (abfd, 0, SEEK_SET) != 0
+      || bfd_bread (& fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
+    {
+      non_fatal (_("cannot seek to/read file header"));
+      return;
+    }
+
+  unsigned short magic = bfd_h_get_16 (abfd, fhdr.e_magic);
+
+  /* PE format executable files have a full external_PEI_filehdr structure
+     at the start.  PE format object files just have an external_filehdr
+     structure at the start.  */
+  if (magic == IMAGE_DOS_SIGNATURE)
+    {
+      unsigned int ihdr_offset = (int) bfd_h_get_16 (abfd, fhdr.e_lfanew);
+
+      /* FIXME: We could reuse the fields in fhdr, but that might
+	 confuse various sanitization and memory checker tools.  */
+      struct external_PEI_IMAGE_hdr ihdr;
+
+      if (bfd_seek (abfd, ihdr_offset, SEEK_SET) != 0
+	  || bfd_bread (& ihdr, sizeof (ihdr), abfd) != sizeof (ihdr))
+	{
+	  non_fatal (_("cannot seek to/read image header at offset %#x"),
+		     ihdr_offset);
+	  return;
+	}
+
+      unsigned int signature = (int) bfd_h_get_16 (abfd, ihdr.nt_signature);
+      if (signature != IMAGE_NT_SIGNATURE)
+	{
+	  non_fatal ("file does not have an NT format signature: %#x",
+		     signature);
+	  return;
+	}
+  
+      dump_pe (abfd, & fhdr, & ihdr);
+    }
+  else if (is_pe_object_magic (magic))
+    {
+      struct external_filehdr ehdr;
+
+      if (bfd_seek (abfd, 0, SEEK_SET) != 0
+	  || bfd_bread (& ehdr, sizeof (ehdr), abfd) != sizeof (ehdr))
+	{
+	  non_fatal (_("cannot seek to/read image header"));
+	  return;
+	}
+
+      struct external_PEI_IMAGE_hdr ihdr;
+      memcpy (& ihdr.f_magic, & ehdr, sizeof (ehdr));
+      dump_pe (abfd, NULL, & ihdr);
+    }
+  else
+    {
+      non_fatal ("not a PE format binary - unexpected magic number: %#x",
+		 magic);
+      return;
+    }
+}
+
+/* Dump a PE file.  */
+
+static void
+pe_dump (bfd *abfd)
+{
+  /* We rely on BFD to decide if the file is a core file.  Note that core
+     files are only supported on native environment by BFD.  */
+  switch (bfd_get_format (abfd))
+    {
+    case bfd_core:
+      // FIXME: Handle PE format core files ?
+      break;
+    default:
+      pe_dump_obj (abfd);
+      break;
+    }
+}
+
+/* Vector for pe.  */
+
+const struct objdump_private_desc objdump_private_desc_pe =
+{
+  pe_help,
+  pe_filter,
+  pe_dump,
+  options
+};

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-26  6:20 ` Jan Beulich
@ 2023-05-26 15:44   ` Fangrui Song
       [not found]   ` <DS7PR12MB5765E0FC436669802ABB76ABCB479@DS7PR12MB5765.namprd12.prod.outlook.com>
  1 sibling, 0 replies; 9+ messages in thread
From: Fangrui Song @ 2023-05-26 15:44 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Jan Beulich, binutils

On Thu, May 25, 2023 at 11:20 PM Jan Beulich via Binutils
<binutils@sourceware.org> wrote:
>
> Nick,
>
> On 25.05.2023 18:21, Nick Clifton via Binutils wrote:
> >   Whilst looking at PR 310145, I realised that we currently do not have
> >   a way to display the contents of PE type files in their native
> >   format.  Since objdump does have a --private option which provides
> >   this kind of functionality for other file format types, I thought that
> >   it would be helpful if objdump could also handle PE files.  Hence this
> >   patch.
> >
> >   At the moment it only dumps the file header and section headers, but
> >   this could be extended in the future.  (Especially if someone else is
> >   interested in doing the work...).  The output looks something like
> >   this:
> >
> >     $ objdump -P header,sections test-section-flags.exe --wide
> >
> >     test-section-flags.exe:     file format pei-x86-64
> >
> >     PEI File Header:
> >       Magic:         0x5a4d           - IMAGE_DOS_SIGNATURE
> >       Machine Num:   0x8664           - AMD64
> >       Num sections:  6
> >       Time and date: 0x646f522d               - Thu May 25 13:18:53 2023
> >       Symbols off:   0x00001000
> >       Num symbols:   60
> >       Opt hdr sz:    240
> >       flags:         0x0226           - EXECUTABLE,LINE NUMS STRIPPED,LARGE ADDRESS AWARE,DEBUG STRIPPED
> >
> >     Section headers (at 152+240=0x00000188 to 0x00000278):
> >      # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr  nrel  nlnno   Flags
> >      1 .text    00000030 00001000 00000200 00000400 00000000 00000000 0     0       60000020 EXECUTE,READ,CODE
> >      2 my_sect  00000004 00002000 00000200 00000600 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA
> >      3 .rdata   00000040 00003000 00000200 00000800 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
> >      4 .pdata   0000000c 00004000 00000200 00000a00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
> >      5 .xdata   00000008 00005000 00000200 00000c00 00000000 00000000 0     0       40000040 READ,INITIALIZED DATA
> >      6 .idata   00000014 00006000 00000200 00000e00 00000000 00000000 0     0       c0000040 READ,WRITE,INITIALIZED DATA
> >
> >   Thoughts, comments ?
>
> thanks for doing this; I had been wondering several times in the past
> whether I simply didn't know the right option to pass to have such
> information printed. Just one remark: I don't think printing the
> signature (Magic:) at the beginning of the file is useful here either,
> as without that signature no output would appear anyway (for the file
> being unrecognized), and afaik there are no alternative signatures
> that could be in use. Instead what may be of interest to print is the
> file offset of the PE header/signature, as especially in older
> (bi-modal) binaries this may not be near the beginning of the file. I
> don't see this information being printed by any other option.
>
> Another minor aspect: The nrel and nlnno fields of the section dump
> may read better (if any are non-zero) when padded to the left, not to
> the right.
>
> Jan

objdump -p a.exe also dumps the PE header (enabled by default without
selecting a PE triple in --enable-targets=), but in a different
format.
I wonder whether the -P header output can be made similar to the
existing output...

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-26 14:40 ` Nick Clifton
@ 2023-05-28  3:13   ` Alan Modra
  2023-05-30 10:48     ` Nick Clifton
  0 siblings, 1 reply; 9+ messages in thread
From: Alan Modra @ 2023-05-28  3:13 UTC (permalink / raw)
  To: Nick Clifton; +Cc: binutils

On Fri, May 26, 2023 at 03:40:59PM +0100, Nick Clifton via Binutils wrote:
> 	* testsuite/binutils-all/objdump.exp: Add a test of the new feature.

arm-pe  +FAIL: objdump -P (dump headers)
arm-pe  +FAIL: objdump -P (dump sections)

tmpdir/bintest.o:     file format pe-arm-little
/build/gas/arm-pe/binutils/objdump: not a PE format binary - unexpected magic number: 0xa00

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-28  3:13   ` Alan Modra
@ 2023-05-30 10:48     ` Nick Clifton
  0 siblings, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2023-05-30 10:48 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

Hi Alan,

> arm-pe  +FAIL: objdump -P (dump headers)
> arm-pe  +FAIL: objdump -P (dump sections)

> tmpdir/bintest.o:     file format pe-arm-little
> /build/gas/arm-pe/binutils/objdump: not a PE format binary - unexpected magic number: 0xa00

Ah - thanks for letting me know, and fixing this problem.
I had checked the results for an arm-wince-pe target, but I had
forgotten that the arm-pe target is different.

I have checked in a small additional patch so that the 0xa00
value is now reported as an ARM magic number, rather than just
an unknown machine type.

Cheers
   Nick




^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
       [not found]   ` <DS7PR12MB5765E0FC436669802ABB76ABCB479@DS7PR12MB5765.namprd12.prod.outlook.com>
@ 2023-05-30 10:50     ` Nick Clifton
  2023-05-30 14:50     ` Nick Clifton
  1 sibling, 0 replies; 9+ messages in thread
From: Nick Clifton @ 2023-05-30 10:50 UTC (permalink / raw)
  To: Fangrui Song; +Cc: Jan Beulich, binutils

Hi Fangrui,

> objdump -p a.exe also dumps the PE header (enabled by default without
> selecting a PE triple in --enable-targets=), but in a different
> format.

True.

> I wonder whether the -P header output can be made similar to the
> existing output...

Either that, or just omitted since it seems wasteful to dump the same
information twice.  But of course the information would only be shown
twice if both the -p and -P options were used.  Hmmm.  Conformity is
probably better.

OK - I will try to make the output similar.

Cheers
   Nick



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
       [not found]   ` <DS7PR12MB5765E0FC436669802ABB76ABCB479@DS7PR12MB5765.namprd12.prod.outlook.com>
  2023-05-30 10:50     ` Nick Clifton
@ 2023-05-30 14:50     ` Nick Clifton
  2023-05-30 15:50       ` Fangrui Song
  1 sibling, 1 reply; 9+ messages in thread
From: Nick Clifton @ 2023-05-30 14:50 UTC (permalink / raw)
  To: Fangrui Song; +Cc: Jan Beulich, binutils

Hi Fangrui,

> I wonder whether the -P header output can be made similar to the
> existing output...

OK, I have pushed an update which makes the output similar to that
from "objdump -p", but not quite the same:

   $ objdump -P header tests/test-section-flags.exe

tests/test-section-flags.exe:     file format pei-x86-64

   File Header (at offset 0):
Bytes on Last Page:		144
Pages In File:			3
Relocations:			0
Size of header in paragraphs:	4
Min extra paragraphs needed:	0
Max extra paragraphs needed:	65535
Initial (relative) SS value:	0
Initial SP value:		184
Checksum:			0
Initial IP value:		0
Initial (relative) CS value:	0
File address of reloc table:	64
Overlay number:			0
OEM identifier:			0
OEM information:		0
File address of new exe header:	0x80
Stub message:			!This program cannot be run in DOS mode.

   Image Header (at offset 0x80):
Machine Number:			0x8664		- AMD64
Number of sections:		6
Time/Date:			0x646f522d	- Thu May 25 13:18:53 2023
Symbol table offset:		0x001000
Number of symbols:		60
Optional header size:		0xf0
Flags:				0x0226		- EXECUTABLE,LINE NUMS STRIPPED,LARGE ADDRESS AWARE,DEBUG STRIPPED

   Optional 64-bit AOUT Header (at offset 0x98):
Magic:				20b		- PE32+
Version:			2702
Text Size:			0x200
Data Size:			0xa00
BSS Size:			0
Entry Point:			0x1000
Text Start:			0x1000

   Optional PE+ Header (at offset 0xb0):
Image Base:			0x40000000
Section Alignment:		0x1000
File Alignment:			0x200
Major OS Version:		4
Minor OS ersion:		0
Major Image Version:		0
Minor Image Version:		0
Major Subsystem Version:	5
Minor Subsystem Version:	2
Size Of Image:			0x7000
Size Of Headers:		0x400
CheckSum:			0xc0d7
Subsystem:			3
DllCharacteristics:		0x160
Size Of Stack Reserve:		0x200000
Size Of Stack Commit:		0x1000
Size Of Heap Reserve:		0x100000
Size Of Heap Commit:		0x1000
Loader Flags:			0
Number Of Rva and Sizes:	0x10


   The update also adds support for some more PE machine numbers,
   and support for AOUT headers that are larger than 28 bytes.
   (Although I have not actually tested this feature as I could
   not find any sample executables use target specific AOUT headers).

Cheers
   Nick


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: RFC: Objdump: Dumping PE specific headers
  2023-05-30 14:50     ` Nick Clifton
@ 2023-05-30 15:50       ` Fangrui Song
  0 siblings, 0 replies; 9+ messages in thread
From: Fangrui Song @ 2023-05-30 15:50 UTC (permalink / raw)
  To: Nick Clifton; +Cc: Jan Beulich, binutils

On Tue, May 30, 2023 at 7:50 AM Nick Clifton <nickc@redhat.com> wrote:
>
> Hi Fangrui,
>
> > I wonder whether the -P header output can be made similar to the
> > existing output...
>
> OK, I have pushed an update which makes the output similar to that
> from "objdump -p", but not quite the same:
>
>    $ objdump -P header tests/test-section-flags.exe
>
> tests/test-section-flags.exe:     file format pei-x86-64
>
>    File Header (at offset 0):
> Bytes on Last Page:             144
> Pages In File:                  3
> Relocations:                    0
> Size of header in paragraphs:   4
> Min extra paragraphs needed:    0
> Max extra paragraphs needed:    65535
> Initial (relative) SS value:    0
> Initial SP value:               184
> Checksum:                       0
> Initial IP value:               0
> Initial (relative) CS value:    0
> File address of reloc table:    64
> Overlay number:                 0
> OEM identifier:                 0
> OEM information:                0
> File address of new exe header: 0x80
> Stub message:                   !This program cannot be run in DOS mode.
>
>    Image Header (at offset 0x80):
> Machine Number:                 0x8664          - AMD64
> Number of sections:             6
> Time/Date:                      0x646f522d      - Thu May 25 13:18:53 2023
> Symbol table offset:            0x001000
> Number of symbols:              60
> Optional header size:           0xf0
> Flags:                          0x0226          - EXECUTABLE,LINE NUMS STRIPPED,LARGE ADDRESS AWARE,DEBUG STRIPPED
>
>    Optional 64-bit AOUT Header (at offset 0x98):
> Magic:                          20b             - PE32+
> Version:                        2702
> Text Size:                      0x200
> Data Size:                      0xa00
> BSS Size:                       0
> Entry Point:                    0x1000
> Text Start:                     0x1000
>
>    Optional PE+ Header (at offset 0xb0):
> Image Base:                     0x40000000
> Section Alignment:              0x1000
> File Alignment:                 0x200
> Major OS Version:               4
> Minor OS ersion:                0
> Major Image Version:            0
> Minor Image Version:            0
> Major Subsystem Version:        5
> Minor Subsystem Version:        2
> Size Of Image:                  0x7000
> Size Of Headers:                0x400
> CheckSum:                       0xc0d7
> Subsystem:                      3
> DllCharacteristics:             0x160
> Size Of Stack Reserve:          0x200000
> Size Of Stack Commit:           0x1000
> Size Of Heap Reserve:           0x100000
> Size Of Heap Commit:            0x1000
> Loader Flags:                   0
> Number Of Rva and Sizes:        0x10
>
>
>    The update also adds support for some more PE machine numbers,
>    and support for AOUT headers that are larger than 28 bytes.
>    (Although I have not actually tested this feature as I could
>    not find any sample executables use target specific AOUT headers).
>
> Cheers
>    Nick
>

Thanks for the update!

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2023-05-30 15:51 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-25 16:21 RFC: Objdump: Dumping PE specific headers Nick Clifton
2023-05-26  6:20 ` Jan Beulich
2023-05-26 15:44   ` Fangrui Song
     [not found]   ` <DS7PR12MB5765E0FC436669802ABB76ABCB479@DS7PR12MB5765.namprd12.prod.outlook.com>
2023-05-30 10:50     ` Nick Clifton
2023-05-30 14:50     ` Nick Clifton
2023-05-30 15:50       ` Fangrui Song
2023-05-26 14:40 ` Nick Clifton
2023-05-28  3:13   ` Alan Modra
2023-05-30 10:48     ` Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).