public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* readelf: report DF_1_PIE as "Position Independent Executable"
@ 2021-06-11 14:43 Alan Modra
  2021-06-11 14:48 ` Simon Marchi
  0 siblings, 1 reply; 3+ messages in thread
From: Alan Modra @ 2021-06-11 14:43 UTC (permalink / raw)
  To: binutils; +Cc: gdb-patches

I finally found time to teach readelf to identify PIEs in the file
header display and program header display.  So in place of
"DYN (Shared object file)" which isn't completely true, show
"DYN (Position Independent Executable file)".

It requires a little bit of untangling code in readelf due to
process_program_headers setting up dynamic_addr and dynamic_size,
needed to scan .dynamic for the DT_FLAGS_1 entry, and
process_program_headers itself wanting to display the file type in
some cases.  At first I modified process_program_header using a
"probe" parameter similar to get_section_headers in order to inhibit
output, but decided it was cleaner to separate out
locate_dynamic_sections instead.

It looks like the toolchain doesn't have too many places that require
tweaking due to the change in readelf.  Hopefully this won't break
other package builds.

I won't commit this immediately, to give people time to comment.

binutils/
	* readelf.c (locate_dynamic_section, is_pie): New functions.
	(get_file_type): Replace e_type parameter with filedata.  Call
	is_pie for ET_DYN.  Update all callers.
	(process_program_headers): Use local variables dynamic_addr and
	dynamic_size, updating filedata on exit from function.  Set
	dynamic_size of 1 to indicate no dynamic section or segment.
	Update tests of dynamic_size throughout.
	* testsuite/binutils-all/x86-64/pr27708.dump: Update expected output.
ld/
	* testsuite/ld-pie/vaddr-0.d: Update expected output.
gdb/
	* testsuite/lib/gdb.exp (exec_is_pie): Match new PIE readelf output.

diff --git a/binutils/readelf.c b/binutils/readelf.c
index 1456c03a073..43f614d1770 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2339,9 +2339,96 @@ get_dynamic_type (Filedata * filedata, unsigned long type)
     }
 }
 
+static bool get_program_headers (Filedata *);
+static bool get_dynamic_section (Filedata *);
+
+static void
+locate_dynamic_section (Filedata *filedata)
+{
+  unsigned long dynamic_addr = 0;
+  bfd_size_type dynamic_size = 0;
+
+  if (filedata->file_header.e_phnum != 0
+      && get_program_headers (filedata))
+    {
+      Elf_Internal_Phdr *segment;
+      unsigned int i;
+
+      for (i = 0, segment = filedata->program_headers;
+	   i < filedata->file_header.e_phnum;
+	   i++, segment++)
+	{
+	  if (segment->p_type == PT_DYNAMIC)
+	    {
+	      dynamic_addr = segment->p_offset;
+	      dynamic_size = segment->p_filesz;
+
+	      if (filedata->section_headers != NULL)
+		{
+		  Elf_Internal_Shdr *sec;
+
+		  sec = find_section (filedata, ".dynamic");
+		  if (sec != NULL)
+		    {
+		      if (sec->sh_size == 0
+			  || sec->sh_type == SHT_NOBITS)
+			{
+			  dynamic_addr = 0;
+			  dynamic_size = 0;
+			}
+		      else
+			{
+			  dynamic_addr = sec->sh_offset;
+			  dynamic_size = sec->sh_size;
+			}
+		    }
+		}
+
+	      if (dynamic_addr > filedata->file_size
+		  || (dynamic_size > filedata->file_size - dynamic_addr))
+		{
+		  dynamic_addr = 0;
+		  dynamic_size = 0;
+		}
+	      break;
+	    }
+	}
+    }
+  filedata->dynamic_addr = dynamic_addr;
+  filedata->dynamic_size = dynamic_size ? dynamic_size : 1;
+}
+
+static bool
+is_pie (Filedata *filedata)
+{
+  Elf_Internal_Dyn *entry;
+
+  if (filedata->dynamic_size == 0)
+    locate_dynamic_section (filedata);
+  if (filedata->dynamic_size <= 1)
+    return false;
+
+  if (!get_dynamic_section (filedata))
+    return false;
+
+  for (entry = filedata->dynamic_section;
+       entry < filedata->dynamic_section + filedata->dynamic_nent;
+       entry++)
+    {
+      if (entry->d_tag == DT_FLAGS_1)
+	{
+	  if ((entry->d_un.d_val & DF_1_PIE) != 0)
+	    return true;
+	  break;
+	}
+    }
+  return false;
+}
+
 static char *
-get_file_type (unsigned e_type)
+get_file_type (Filedata *filedata)
 {
+  unsigned e_type = filedata->file_header.e_type;
   static char buff[64];
 
   switch (e_type)
@@ -2349,7 +2436,11 @@ get_file_type (unsigned e_type)
     case ET_NONE: return _("NONE (None)");
     case ET_REL:  return _("REL (Relocatable file)");
     case ET_EXEC: return _("EXEC (Executable file)");
-    case ET_DYN:  return _("DYN (Shared object file)");
+    case ET_DYN:
+      if (is_pie (filedata))
+	return _("DYN (Position Independent Executable file)");
+      else
+	return _("DYN (Shared object file)");
     case ET_CORE: return _("CORE (Core file)");
 
     default:
@@ -5168,7 +5259,7 @@ process_file_header (Filedata * filedata)
       printf (_("  ABI Version:                       %d\n"),
 	      header->e_ident[EI_ABIVERSION]);
       printf (_("  Type:                              %s\n"),
-	      get_file_type (header->e_type));
+	      get_file_type (filedata));
       printf (_("  Machine:                           %s\n"),
 	      get_machine_name (header->e_machine));
       printf (_("  Version:                           0x%lx\n"),
@@ -5381,27 +5472,21 @@ get_program_headers (Filedata * filedata)
   return false;
 }
 
-/* Returns TRUE if the program headers were loaded.  */
+/* Print program header info and locate dynamic section.  */
 
-static bool
+static void
 process_program_headers (Filedata * filedata)
 {
   Elf_Internal_Phdr * segment;
   unsigned int i;
   Elf_Internal_Phdr * previous_load = NULL;
 
-  filedata->dynamic_addr = 0;
-  filedata->dynamic_size = 0;
-
   if (filedata->file_header.e_phnum == 0)
     {
       /* PR binutils/12467.  */
       if (filedata->file_header.e_phoff != 0)
-	{
-	  warn (_("possibly corrupt ELF header - it has a non-zero program"
-		  " header offset, but no program headers\n"));
-	  return false;
-	}
+	warn (_("possibly corrupt ELF header - it has a non-zero program"
+		" header offset, but no program headers\n"));
       else if (do_segments)
 	{
 	  if (filedata->is_separate)
@@ -5410,17 +5495,16 @@ process_program_headers (Filedata * filedata)
 	  else
 	    printf (_("\nThere are no program headers in this file.\n"));
 	}
-      return true;
+      goto no_headers;
     }
 
   if (do_segments && !do_header)
     {
       if (filedata->is_separate)
 	printf ("\nIn linked file '%s' the ELF file type is %s\n",
-		filedata->file_name,
-		get_file_type (filedata->file_header.e_type));
+		filedata->file_name, get_file_type (filedata));
       else
-	printf (_("\nElf file type is %s\n"), get_file_type (filedata->file_header.e_type));
+	printf (_("\nElf file type is %s\n"), get_file_type (filedata));
       printf (_("Entry point 0x%s\n"), bfd_vmatoa ("x", filedata->file_header.e_entry));
       printf (ngettext ("There is %d program header, starting at offset %s\n",
 			"There are %d program headers, starting at offset %s\n",
@@ -5430,7 +5514,7 @@ process_program_headers (Filedata * filedata)
     }
 
   if (! get_program_headers (filedata))
-    return true;
+    goto no_headers;
 
   if (do_segments)
     {
@@ -5454,6 +5538,8 @@ process_program_headers (Filedata * filedata)
 	}
     }
 
+  unsigned long dynamic_addr = 0;
+  bfd_size_type dynamic_size = 0;
   for (i = 0, segment = filedata->program_headers;
        i < filedata->file_header.e_phnum;
        i++, segment++)
@@ -5579,13 +5665,13 @@ process_program_headers (Filedata * filedata)
 	  break;
 
 	case PT_DYNAMIC:
-	  if (filedata->dynamic_addr)
+	  if (dynamic_addr)
 	    error (_("more than one dynamic segment\n"));
 
 	  /* By default, assume that the .dynamic section is the first
 	     section in the DYNAMIC segment.  */
-	  filedata->dynamic_addr = segment->p_offset;
-	  filedata->dynamic_size = segment->p_filesz;
+	  dynamic_addr = segment->p_offset;
+	  dynamic_size = segment->p_filesz;
 
 	  /* Try to locate the .dynamic section. If there is
 	     a section header table, we can easily locate it.  */
@@ -5596,27 +5682,28 @@ process_program_headers (Filedata * filedata)
 	      sec = find_section (filedata, ".dynamic");
 	      if (sec == NULL || sec->sh_size == 0)
 		{
-                  /* A corresponding .dynamic section is expected, but on
-                     IA-64/OpenVMS it is OK for it to be missing.  */
-                  if (!is_ia64_vms (filedata))
-                    error (_("no .dynamic section in the dynamic segment\n"));
+		  /* A corresponding .dynamic section is expected, but on
+		     IA-64/OpenVMS it is OK for it to be missing.  */
+		  if (!is_ia64_vms (filedata))
+		    error (_("no .dynamic section in the dynamic segment\n"));
 		  break;
 		}
 
 	      if (sec->sh_type == SHT_NOBITS)
 		{
-		  filedata->dynamic_size = 0;
+		  dynamic_addr = 0;
+		  dynamic_size = 0;
 		  break;
 		}
 
-	      filedata->dynamic_addr = sec->sh_offset;
-	      filedata->dynamic_size = sec->sh_size;
+	      dynamic_addr = sec->sh_offset;
+	      dynamic_size = sec->sh_size;
 
 	      /* The PT_DYNAMIC segment, which is used by the run-time
 		 loader,  should exactly match the .dynamic section.  */
 	      if (do_checks
-		  && (filedata->dynamic_addr != segment->p_offset
-		      || filedata->dynamic_size != segment->p_filesz))
+		  && (dynamic_addr != segment->p_offset
+		      || dynamic_size != segment->p_filesz))
 		warn (_("\
 the .dynamic section is not the same as the dynamic segment\n"));
 	    }
@@ -5625,12 +5712,12 @@ the .dynamic section is not the same as the dynamic segment\n"));
 	     segment.  Check this after matching against the section headers
 	     so we don't warn on debuginfo file (which have NOBITS .dynamic
 	     sections).  */
-	  if (filedata->dynamic_addr > filedata->file_size
-	      || (filedata->dynamic_size
-		  > filedata->file_size - filedata->dynamic_addr))
+	  if (dynamic_addr > filedata->file_size
+	      || (dynamic_size > filedata->file_size - dynamic_addr))
 	    {
 	      error (_("the dynamic segment offset + size exceeds the size of the file\n"));
-	      filedata->dynamic_addr = filedata->dynamic_size = 0;
+	      dynamic_addr = 0;
+	      dynamic_size = 0;
 	    }
 	  break;
 
@@ -5687,7 +5774,13 @@ the .dynamic section is not the same as the dynamic segment\n"));
 	}
     }
 
-  return true;
+  filedata->dynamic_addr = dynamic_addr;
+  filedata->dynamic_size = dynamic_size ? dynamic_size : 1;
+  return;
+
+ no_headers:
+  filedata->dynamic_addr = 0;
+  filedata->dynamic_size = 1;
 }
 
 
@@ -10615,7 +10708,7 @@ process_dynamic_section (Filedata * filedata)
 {
   Elf_Internal_Dyn * entry;
 
-  if (filedata->dynamic_size == 0)
+  if (filedata->dynamic_size <= 1)
     {
       if (do_dynamic)
 	{
@@ -21374,9 +21467,9 @@ process_object (Filedata * filedata)
     /* Without loaded section groups we cannot process unwind.  */
     do_unwind = false;
 
-  res = process_program_headers (filedata);
-  if (res)
-    res = process_dynamic_section (filedata);
+  process_program_headers (filedata);
+
+  res = process_dynamic_section (filedata);
 
   if (! process_relocs (filedata))
     res = false;
@@ -21422,8 +21515,7 @@ process_object (Filedata * filedata)
 	    {
 	      if (! process_section_groups (d->handle))
 		res = false;
-	      if (! process_program_headers (d->handle))
-		res = false;
+	      process_program_headers (d->handle);
 	      if (! process_dynamic_section (d->handle))
 		res = false;
 	      if (! process_relocs (d->handle))
diff --git a/binutils/testsuite/binutils-all/x86-64/pr27708.dump b/binutils/testsuite/binutils-all/x86-64/pr27708.dump
index e9123df9c42..ef3e9a9b5fd 100644
--- a/binutils/testsuite/binutils-all/x86-64/pr27708.dump
+++ b/binutils/testsuite/binutils-all/x86-64/pr27708.dump
@@ -1,5 +1,5 @@
 
-Elf file type is DYN (Shared object file)
+Elf file type is DYN (Position Independent Executable file)
 Entry point 0x5f0
 There are 11 program headers, starting at offset 64
 
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index d8c684c7238..a317781dafe 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -6078,7 +6078,7 @@ proc exec_is_pie { executable } {
     if { $res != 0 } {
 	return -1
     }
-    set res [regexp -line {^[ \t]*Type:[ \t]*DYN \(Shared object file\)$} \
+    set res [regexp -line {^[ \t]*Type:[ \t]*DYN \((Position Independent Executable|Shared object) file\)$} \
 		 $output]
     if { $res == 1 } {
 	return 1
diff --git a/ld/testsuite/ld-pie/vaddr-0.d b/ld/testsuite/ld-pie/vaddr-0.d
index e0722226b2c..a13248a9985 100644
--- a/ld/testsuite/ld-pie/vaddr-0.d
+++ b/ld/testsuite/ld-pie/vaddr-0.d
@@ -5,5 +5,5 @@
 
 ELF Header:
 #...
-  Type:                              DYN \(Shared object file\)
+  Type:                              DYN \(Position Independent Executable file\)
 #pass

-- 
Alan Modra
Australia Development Lab, IBM

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

* Re: readelf: report DF_1_PIE as "Position Independent Executable"
  2021-06-11 14:43 readelf: report DF_1_PIE as "Position Independent Executable" Alan Modra
@ 2021-06-11 14:48 ` Simon Marchi
  2021-06-12  0:24   ` Alan Modra
  0 siblings, 1 reply; 3+ messages in thread
From: Simon Marchi @ 2021-06-11 14:48 UTC (permalink / raw)
  To: Alan Modra, binutils; +Cc: gdb-patches

> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index d8c684c7238..a317781dafe 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -6078,7 +6078,7 @@ proc exec_is_pie { executable } {
>      if { $res != 0 } {
>  	return -1
>      }
> -    set res [regexp -line {^[ \t]*Type:[ \t]*DYN \(Shared object file\)$} \
> +    set res [regexp -line {^[ \t]*Type:[ \t]*DYN \((Position Independent Executable|Shared object) file\)$} \
>  		 $output]
>      if { $res == 1 } {
>  	return 1

Props for finding this place that needed to be updated.  That change is
ok on the GDB side.

Grammar nit: I'm not a native english speaker and I don't know how that
rule would be called, but I think that an hyphen would technically be
required between Position and Independent (Position-Independent)?

Simon

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

* Re: readelf: report DF_1_PIE as "Position Independent Executable"
  2021-06-11 14:48 ` Simon Marchi
@ 2021-06-12  0:24   ` Alan Modra
  0 siblings, 0 replies; 3+ messages in thread
From: Alan Modra @ 2021-06-12  0:24 UTC (permalink / raw)
  To: Simon Marchi; +Cc: binutils, gdb-patches

On Fri, Jun 11, 2021 at 10:48:02AM -0400, Simon Marchi wrote:
> Grammar nit: I'm not a native english speaker

Which probably means you know English grammar better than many native
speakers.  :-)

> and I don't know how that
> rule would be called, but I think that an hyphen would technically be
> required between Position and Independent (Position-Independent)?

Yes, "position-independent" is forming a compound adjective from a
noun plus adjective.  A hyphen should normally be used here according
to references like https://www.lexico.com/grammar/hyphen.  It just
looks a little odd to me when capitalised.  Maybe that's because I've
seen the phrase written wrongly too many times.  (The capitalisation
is of course to spell out the common PIE acronym.)

I'll correct the grammar, thanks!

-- 
Alan Modra
Australia Development Lab, IBM

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

end of thread, other threads:[~2021-06-12  0:24 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-11 14:43 readelf: report DF_1_PIE as "Position Independent Executable" Alan Modra
2021-06-11 14:48 ` Simon Marchi
2021-06-12  0:24   ` Alan Modra

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).