[lto] PATCH: Locate DWARF information in ELF files

Mark Mitchell mark@codesourcery.com
Sun Jun 18 20:47:00 GMT 2006


This patch makes the LTO front end open ELF files and locate the DWARF
sections required for building LTO information.  The ELF-specific bits
are segreated into a separate file so that platforms using other
object file formats can be supported in future.  We will probably also
need some autoconf bits to detect libelf; for now, we'll just assume
its available.  

The next step is to begin reading the DWARF information and generating
trees.

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-06-18  Mark Mitchell  <mark@codesourcery.com>

	* lto.h: New file.
	* lto.c: New file.
	* lto-elf.c: New file.
	* lto-lang.c (flags.h): Include it.
	(lto.h): Likewise.
	(lto_init): New function.
	(lto_write_globals): Remove.
	(LANG_HOOKS_WRITE_GLOBALS): Define to lhd_do_nothing. 
	(LANG_HOOKS_INIT): Define.
	(LANG_HOOKS_PARSE_FILE): Likewise.
	* Make-lang.in (LTO_OBJS): Add lto.o and lto-elf.o.
	(LTO_EXE): Link with libelf.
	(lto/lto-lang.o): Update dependencies.
	(lto/lto.o): New target.
	(lto/lto-elf.o): Likewise.

Index: lto.c
===================================================================
--- lto.c	(revision 0)
+++ lto.c	(revision 0)
@@ -0,0 +1,62 @@
+/* Top-level LTO routines.
+   Copyright 2006 Free Software Foundation, Inc.
+   Contributed by CodeSourcery, Inc.
+
+This file is part of GCC.
+
+GCC 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 2, or (at your option)
+any later version.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "opts.h"
+#include "lto.h"
+
+void
+lto_file_init (lto_file *file, const char *filename)
+{
+  file->debug_info = NULL;
+  file->debug_info_length = 0;
+  file->debug_abbrev = NULL;
+  file->debug_abbrev_length = 0;
+  file->filename = filename;
+}
+
+bool
+lto_file_read (lto_file *file)
+{
+  return true;
+}
+
+void
+lto_main (int debug_p ATTRIBUTE_UNUSED)
+{
+  unsigned i;
+
+  /* Read all of the object files specified on the command line.  */
+  for (i = 0; i < num_in_fnames; ++i)
+    {
+      lto_file *file;
+
+      file = lto_elf_file_open (in_fnames[i]);
+      if (!file)
+	break;
+      gcc_assert (file->debug_info);
+      gcc_assert (file->debug_abbrev);
+      if (!lto_file_read (file))
+	return;
+      lto_elf_file_close (file);
+    }
+}
Index: Make-lang.in
===================================================================
--- Make-lang.in	(revision 114758)
+++ Make-lang.in	(working copy)
@@ -26,7 +26,7 @@
 # The name of the LTO compiler.
 LTO_EXE = lto1$(exeext)
 # The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o
 
 ########################################################################
 # Rules
@@ -68,12 +68,15 @@ lto.stagefeedback:
 
 $(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS)
 	$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
-		$(LTO_OBJS) $(BACKEND) $(LIBS)
+		$(LTO_OBJS) $(BACKEND) $(LIBS) -lelf
 
 ########################################################################
 # Dependencies
 ########################################################################
 
 lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
-	$(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(SYSTEM_H) \
-	lto/lto-tree.h gtype-lto.h
+	flags.h $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(SYSTEM_H) \
+	$(TM_H) lto/lto-tree.h lto/lto.h gtype-lto.h
+lto/lto.o: lto/lto.c $(CONFIG_H) opts.h $(SYSTEM_H) lto/lto.h
+lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H)\
+	toplev.h lto/lto.h
Index: lto-elf.c
===================================================================
--- lto-elf.c	(revision 0)
+++ lto-elf.c	(revision 0)
@@ -0,0 +1,253 @@
+/* LTO routines for ELF object files.
+   Copyright 2006 Free Software Foundation, Inc.
+   Contributed by CodeSourcery, Inc.
+
+This file is part of GCC.
+
+GCC 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 2, or (at your option)
+any later version.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "toplev.h"
+#include "lto.h"
+#include "libelf.h"
+
+/* An ELF input file.  */
+struct lto_elf_file 
+{
+  /* The base information.  */
+  lto_file base;
+  /* The system file descriptor for the file.  */
+  int fd;
+  /* The libelf descriptor for the file.  */
+  Elf *elf;
+};
+typedef struct lto_elf_file lto_elf_file;
+
+lto_file *
+lto_elf_file_open (const char *filename)
+{
+  lto_elf_file *elf_file;
+  size_t bits;
+  const char *elf_ident;
+  size_t string_table_section_index;
+  Elf_Scn *string_table_section;
+  Elf_Scn *section;
+  lto_file *result;
+
+  /* Set up.  */
+  elf_file = (lto_elf_file *) xmalloc (sizeof (lto_elf_file));
+  result = &elf_file->base;
+  lto_file_init (result, filename);
+  elf_file->fd = -1;
+  elf_file->elf = NULL;
+
+  /* Open the file.  */
+  elf_file->fd = open (filename, O_RDONLY);
+  if (elf_file->fd == -1)
+    {
+      error ("could not open");
+      goto fail;
+    }
+
+  /* Initialize the ELF library.  */
+  if (elf_version (EV_CURRENT) == EV_NONE)
+    {
+      error ("ELF library is older than that used when building GCC");
+      goto fail;
+    }
+
+  /* Open the ELF file descriptor.  */
+  elf_file->elf = elf_begin (elf_file->fd, ELF_C_READ, NULL);
+  if (!elf_file->elf)
+    {
+      error ("could not open ELF file: %s", elf_errmsg (0));
+      goto fail;
+    }
+
+  /* Some aspects of the libelf API are dependent on whether the
+     object file is a 32-bit or 64-bit file.  Determine which kind of
+     file this is now.  */
+  elf_ident = elf_getident (elf_file->elf, NULL);
+  if (!elf_ident)
+    {
+      error ("could not read ELF identification information: %s",
+	      elf_errmsg (0));
+      goto fail;
+	     
+    }
+  switch (elf_ident[EI_CLASS])
+    {
+    case ELFCLASS32:
+      bits = 32;
+      break;
+    case ELFCLASS64:
+      bits = 64;
+      break;
+    default:
+      error ("unsupported ELF file class");
+      goto fail;
+    }
+
+  /* Check that the input file is a relocatable object file.  */
+#define ELF_CHECK_FILE_TYPE(N)						\
+  do {									\
+    Elf##N##_Ehdr *elf_header;						\
+    elf_header = elf##N##_getehdr (elf_file->elf);			\
+    if (!elf_header)							\
+      {									\
+	error ("could not read ELF header: %s", elf_errmsg (0));	\
+        goto fail;							\
+      }									\
+   if (elf_header->e_type != ET_REL)					\
+     {									\
+        error ("not a relocatable ELF object file");			\
+        goto fail;							\
+     }									\
+  } while (false)
+
+  switch (bits)
+    {
+    case 32:
+      ELF_CHECK_FILE_TYPE (32);
+      break;
+    case 64:
+      ELF_CHECK_FILE_TYPE (64);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+#undef ELF_CHECK_FILE_TYPE
+
+  /* Read the string table used for section header names.  */
+  if (elf_getshstrndx (elf_file->elf, &string_table_section_index) == -1)
+    {
+      error ("could not locate ELF string table", elf_errmsg (0));
+      goto fail;
+    }
+  string_table_section = elf_getscn (elf_file->elf, 
+				     string_table_section_index);
+
+  /* Find the .debug_info and .debug_abbrev sections.  */
+  for (section = elf_getscn (elf_file->elf, 0);
+       section;
+       section = elf_nextscn (elf_file->elf, section)) 
+    {
+      size_t offset;
+      const char *name;
+      const void **datap;
+      size_t *lengthp;
+      Elf_Data *data;
+
+      if (!section)
+	{
+	  error ("could not read section information: %s", elf_errmsg (0));
+	  goto fail;
+	}
+
+#define ELF_GET_SECTION_HEADER_NAME(N)					 \
+      do {								 \
+	Elf##N##_Shdr *section_header;					 \
+	section_header = elf##N##_getshdr (section);			 \
+	if (!section_header)						 \
+	  {								 \
+	    error ("could not read section header: %s", elf_errmsg (0)); \
+	    goto fail;							 \
+	  }								 \
+	offset = section_header->sh_name;				 \
+      } while (false)
+
+      switch (bits)
+	{
+	case 32:
+	  ELF_GET_SECTION_HEADER_NAME(32); 
+	  break;
+	case 64:
+	  ELF_GET_SECTION_HEADER_NAME(64);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+
+#undef ELF_GET_SECTION_HEADER_NAME
+
+      /* Get the name of this section.  */
+      name = elf_strptr (elf_file->elf, string_table_section_index, 
+			 offset);
+      if (!name)
+	{
+	  error ("could not read section name: %s", elf_errmsg (0));
+	  goto fail;
+	}
+      
+      /* Check to see if this is one of the sections of interest.  */
+      if (strcmp (name, ".debug_info") == 0)
+	{
+	  datap = &result->debug_info;
+	  lengthp = &result->debug_info_length;
+	}
+      else if (strcmp (name, ".debug_abbrev") == 0)
+	{
+	  datap = &result->debug_abbrev;
+	  lengthp = &result->debug_abbrev_length;
+	}
+      else
+	continue;
+
+      /* There should not be two debugging sections with the same
+	 name.  */
+      if (*datap)
+	{
+	  error ("duplicate %qs section", name);
+	  goto fail;
+	}
+
+      /* Read the data from the section.  */
+      data = elf_getdata (section, NULL);
+      if (!data)
+	{
+	  error ("could not read data", elf_errmsg (0));
+	  goto fail;
+	}
+      *datap = data->d_buf;
+      *lengthp = data->d_size;
+    }
+
+  if (!result->debug_info || !result->debug_abbrev)
+    {
+      error ("could not read DWARF debugging information");
+      goto fail;
+    }
+
+  return result;
+
+ fail:
+  lto_elf_file_close (result);
+  return NULL;
+}
+
+void
+lto_elf_file_close (lto_file *file)
+{
+  lto_elf_file *elf_file = (lto_elf_file *) file;
+  if (elf_file->elf)
+    elf_end (elf_file->elf);
+  if (elf_file->fd != -1)
+    close (elf_file->fd);
+  free (file);
+}
Index: lto.h
===================================================================
--- lto.h	(revision 0)
+++ lto.h	(revision 0)
@@ -0,0 +1,65 @@
+/* LTO declarations.
+   Copyright 2006 Free Software Foundation, Inc.
+   Contributed by CodeSourcery, Inc.
+
+This file is part of GCC.
+
+GCC 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 2, or (at your option)
+any later version.
+
+GCC 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 GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#ifndef LTO_H
+#define LTO_H
+
+/* An input file.  */
+typedef struct lto_file
+{
+  /* The name of the file.  */
+  const char *filename;
+  /* The contents of the .debug_info section.  */
+  const void *debug_info;
+  /* The number of bytes pointed to by DEBUG_INFO.  */ 
+  size_t debug_info_length;
+  /* The contents of the .debug_abbrev section.  */
+  const void *debug_abbrev;
+  /* The number of bytes pointed to by DEBUG_ABBREV.  */
+  size_t debug_abbrev_length;
+} lto_file;
+
+/* lto.c */
+ 
+/* Read all of the input object files, generate a TREE representation
+   of the combined program, and provide that combined representation
+   to the middle end.  */
+extern void lto_main (int debug_p);
+
+/* Initialize the newly allocated FILE, which corresponds to
+   FILENAME.  */
+extern void lto_file_init (lto_file *file, const char *filename);
+
+/* Generate a TREE representation for all entities in FILE.  If an
+   entity in FILE has already been read (from another object file),
+   merge the two entities.  Returns TRUE iff FILE was successfully
+   processed.  */
+extern bool lto_file_read (lto_file *file);
+
+/* lto-elf.c */
+
+/* Open the ELF input file indicated by FILENAME.  Return */
+extern lto_file *lto_elf_file_open (const char *filename);
+
+/* Close an ELF input file.  */
+extern void lto_elf_file_close (lto_file *file);
+
+#endif /* LTO_H */
Index: lto-lang.c
===================================================================
--- lto-lang.c	(revision 114758)
+++ lto-lang.c	(working copy)
@@ -22,11 +22,14 @@ Boston, MA 02110-1301, USA.  */
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "flags.h"
+#include "tm.h"
 #include "tree.h"
 #include "langhooks.h"
 #include "langhooks-def.h"
 #include "debug.h"
 #include "lto-tree.h"
+#include "lto.h"
 
 /* Tables of information about tree codes.  */
 
@@ -113,12 +116,6 @@ lto_getdecls (void)
   gcc_unreachable ();
 }
 
-static void
-lto_write_globals (void)
-{
-  gcc_unreachable ();
-}
-
 static tree
 lto_builtin_function (const char *name ATTRIBUTE_UNUSED,
 		      tree type ATTRIBUTE_UNUSED,
@@ -130,6 +127,27 @@ lto_builtin_function (const char *name A
   gcc_unreachable ();
 }
 
+/* Perform LTO-specific initialization.  */
+
+static bool
+lto_init (void)
+{
+  /* Create the basic integer types.  */
+  build_common_tree_nodes (flag_signed_char, 
+			   /*signed_sizetype=*/false);
+  /* Tell the middle end what type to use for the size of objects.  */
+  if (strcmp (SIZE_TYPE, "unsigned int") == 0)
+    set_sizetype (unsigned_type_node);
+  else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
+    set_sizetype (long_unsigned_type_node);
+  else
+    gcc_unreachable();
+  /* Create other basic types.  */
+  build_common_tree_nodes_2 (/*short_double=*/false);
+
+  return true;
+}
+
 #define LANG_HOOKS_MARK_ADDRESSABLE lto_mark_addressable
 #define LANG_HOOKS_TYPE_FOR_MODE lto_type_for_mode
 #define LANG_HOOKS_TYPE_FOR_SIZE lto_type_for_size
@@ -145,9 +163,13 @@ lto_builtin_function (const char *name A
 #undef LANG_HOOKS_GETDECLS
 #define LANG_HOOKS_GETDECLS lto_getdecls
 #undef LANG_HOOKS_WRITE_GLOBALS
-#define LANG_HOOKS_WRITE_GLOBALS lto_write_globals
+#define LANG_HOOKS_WRITE_GLOBALS lhd_do_nothing
 #undef LANG_HOOKS_BUILTIN_FUNCTION
 #define LANG_HOOKS_BUILTIN_FUNCTION lto_builtin_function
+#undef LANG_HOOKS_INIT
+#define LANG_HOOKS_INIT lto_init
+#undef LANG_HOOKS_PARSE_FILE
+#define LANG_HOOKS_PARSE_FILE lto_main
 
 const struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
 



More information about the Gcc-patches mailing list