Patchwork [gccgo] Use simple-object instead of elfpp

login
register
mail settings
Submitter Ian Taylor
Date Nov. 2, 2010, 10:59 p.m.
Message ID <mcry69bqqld.fsf@google.com>
Download mbox | patch
Permalink /patch/69929/
State New
Headers show

Comments

Ian Taylor - Nov. 2, 2010, 10:59 p.m.
This patch changes gccgo to use the new simple-object interface instead
of elfcpp.  This lets it work with PE/COFF and Mach-O as well as ELF.
Full support for Mach-O will also requiring adding a segment name when
generating the .go_export section.  Committed to gccgo branch.

Ian

Patch

diff -r d84d3a63e9ca go/Make-lang.in
--- a/go/Make-lang.in	Sun Oct 31 11:15:12 2010 -0700
+++ b/go/Make-lang.in	Tue Nov 02 15:56:27 2010 -0700
@@ -58,7 +58,6 @@ 
 	go/gogo.o \
 	go/import.o \
 	go/import-archive.o \
-	go/import-elf.o \
 	go/lex.o \
 	go/parse.o \
 	go/statements.o \
@@ -165,10 +164,9 @@ 
 	$(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) go/dataflow.h $(GO_IMPORT_H) \
 	go/export.h $(GO_GOGO_H)
 go/import.o: go/import.cc $(GO_SYSTEM_H) $(srcdir)/../include/filenames.h \
-	$(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/export.h $(GO_IMPORT_H)
+	../include/simple-object.h $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) \
+	go/export.h $(GO_IMPORT_H)
 go/import-archive.o: go/import-archive.cc $(GO_SYSTEM_H) $(GO_IMPORT_H)
-go/import-elf.o: go/import-elf.cc $(GO_SYSTEM_H) intl.h $(DIAGNOSTIC_H) \
-	$(ELFCPP_H) $(srcdir)/../elfcpp/elfcpp_file.h $(GO_IMPORT_H)
 go/lex.o: go/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H)
 go/parse.o: go/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) $(GO_TYPES_H) \
 	$(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H)
diff -r d84d3a63e9ca go/gogo.cc
--- a/go/gogo.cc	Sun Oct 31 11:15:12 2010 -0700
+++ b/go/gogo.cc	Tue Nov 02 15:56:27 2010 -0700
@@ -320,6 +320,8 @@ 
   Package* package = imp.import(this, local_name, is_local_name_exported);
   this->imports_.insert(std::make_pair(filename, package));
   package->set_is_imported();
+
+  delete stream;
 }
 
 // Return whether we are at the global binding level.
diff -r d84d3a63e9ca go/import-archive.cc
--- a/go/import-archive.cc	Sun Oct 31 11:15:12 2010 -0700
+++ b/go/import-archive.cc	Tue Nov 02 15:56:27 2010 -0700
@@ -642,10 +642,10 @@ 
 				     &member_fd, &member_off, &member_name))
 	return NULL;
 
-      Import::Stream* is = Import::find_elf_export_data(member_name,
-							member_fd,
-							member_off,
-							location);
+      Import::Stream* is = Import::find_object_export_data(member_name,
+							   member_fd,
+							   member_off,
+							   location);
       if (is != NULL)
 	{
 	  ret->add(is);
diff -r d84d3a63e9ca go/import-elf.cc
--- a/go/import-elf.cc	Sun Oct 31 11:15:12 2010 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@ 
-// import-elf.cc -- Go frontend read import data from an ELF file.
-
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "go-system.h"
-
-#include <cerrno>
-#include <cstring>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-extern "C"
-{
-#include "intl.h"
-#include "diagnostic.h"
-}
-
-#include "elfcpp.h"
-#include "elfcpp_file.h"
-#include "import.h"
-
-// The functions in this file extract Go export data from an ELF
-// object file or shared library.
-
-const int Import::elf_magic_len;
-
-// Return true if BYTES, which are from the start of the file, are an
-// ELF magic number.
-
-bool
-Import::is_elf_magic(const char* bytes)
-{
-  const char elfmagic[Import::elf_magic_len] =
-    {
-      elfcpp::ELFMAG0, elfcpp::ELFMAG1, elfcpp::ELFMAG2, elfcpp::ELFMAG3
-    };
-  return memcmp(bytes, elfmagic, Import::elf_magic_len) == 0;
-}
-
-// The base of the template class used to read the ELF file.
-
-class Elf_object
-{
- public:
-  Elf_object(const std::string& name, const unsigned char* contents,
-	     off_t file_size, source_location location)
-    : name_(name), contents_(contents), file_size_(file_size),
-      location_(location), reported_error_(false)
-  { }
-
-  virtual ~Elf_object()
-  { }
-
-  // Look for a .go.export section.  If found, store the section
-  // contents in *CONTENTS and return true.  Otherwise, return false.
-  bool
-  find_export_section(std::string* contents)
-  { return this->do_find_export_section(contents); }
-
-  // A view into the file.  This is used by elfcpp::Elf_file.
-  class View
-  {
-   public:
-    View(const unsigned char* data)
-      : data_(data)
-    { }
-
-    const unsigned char*
-    data() const
-    { return this->data_; }
-
-   private:
-    const unsigned char* data_;
-  };
-
-  // Return a view into the file.  This is called by elfcpp::Elf_file.
-  View
-  view(off_t file_offset, off_t data_size);
-
-  // A location in the file.
-  class Location
-  {
-   public:
-    Location(off_t file_offset, off_t data_size)
-      : file_offset_(file_offset), data_size_(data_size)
-    { }
-
-    off_t
-    file_offset() const
-    { return this->file_offset_; }
-
-    off_t
-    data_size() const
-    { return this->data_size_; }
-
-   private:
-    off_t file_offset_;
-    off_t data_size_;
-  };
-
-  View
-  view(const Location& loc);
-
-  // Report an error and do not return.
-  void
-  error(const char* format, ...) ATTRIBUTE_GCC_DIAG(2, 3);
-
- protected:
-  // Implemented by size/endian specific child class.
-  virtual bool
-  do_find_export_section(std::string* contents) = 0;
-
- private:
-  // Report a truncation error.
-  void
-  report_error();
-
-  // File name.
-  std::string name_;
-  // File contents.
-  const unsigned char* contents_;
-  // File size.
-  off_t file_size_;
-  // Source location of import statement.
-  source_location location_;
-  // Whether we have reported an error about this file.
-  bool reported_error_;
-};
-
-// Report an error and do not return.
-
-void
-Elf_object::error(const char* format, ...)
-{
-  va_list ap;
-  va_start(ap, format);
-  diagnostic_info diagnostic;
-  diagnostic_set_info(&diagnostic, format, &ap, this->location_, DK_ERROR);
-  // FIXME: Can't return.
-  sorry("can't continue");
-}
-
-// Report a truncation error.
-
-void
-Elf_object::report_error()
-{
-  if (!this->reported_error_)
-    {
-      error_at(this->location_, "%s: truncated ELF file", this->name_.c_str());
-      this->reported_error_ = true;
-    }
-}
-
-// Return a view into the file.  This is called by elfcpp::Elf_file.
-
-Elf_object::View
-Elf_object::view(off_t file_offset, off_t data_size)
-{
-  const unsigned char* data;
-  if (file_offset + data_size <= this->file_size_)
-    data = this->contents_ + file_offset;
-  else
-    {
-      this->report_error();
-      data = new unsigned char[data_size];
-    }
-  return View(data);
-}
-
-// Return a view given a location.
-
-Elf_object::View
-Elf_object::view(const Location& loc)
-{
-  const unsigned char* data;
-  if (loc.file_offset() + loc.data_size() <= this->file_size_)
-    data = this->contents_ + loc.file_offset();
-  else
-    {
-      this->report_error();
-      data = new unsigned char[loc.data_size()];
-    }
-  return View(data);
-}
-
-// This version of Elf_object is specific to the size and endianness
-// of the ELF file.
-
-template<int size, bool big_endian>
-class Sized_elf_object : public Elf_object
-{
- public:
-  Sized_elf_object(const std::string& name, const unsigned char* contents,
-		   off_t file_size, source_location location,
-		   const elfcpp::Ehdr<size, big_endian>& ehdr)
-    : Elf_object(name, contents, file_size, location),
-      elf_file_(this, ehdr)
-  { }
-
- protected:
-  // Return the contents of the .go.export section.
-  bool
-  do_find_export_section(std::string* contents);
-
- private:
-  // The ELF file accessor.
-  elfcpp::Elf_file<size, big_endian, Elf_object> elf_file_;
-};
-
-// Look for a section named .go.export.  If we find it, return true
-// and set *CONTENTS to its contents.
-
-template<int size, bool big_endian>
-bool
-Sized_elf_object<size, big_endian>::do_find_export_section(
-    std::string* contents)
-{
-  unsigned int shnum = this->elf_file_.shnum();
-  for (unsigned int i = 0; i < shnum; ++i)
-    {
-      if (this->elf_file_.section_name(i) == ".go_export")
-	{
-	  Elf_object::Location l = this->elf_file_.section_contents(i);
-	  Elf_object::View v = this->view(l);
-	  contents->assign(reinterpret_cast<const char*>(v.data()),
-			   l.data_size());
-	  return true;
-	}
-    }
-  return false;
-}
-
-// This function extracts Go export data from an ELF object file.  If
-// it finds any, it returns an Import::Stream object for it.  NAME is
-// the name of the file.  The object file has already been opened: FD
-// is the file descriptor and FILE_SIZE is the size of the file.
-// OFFSET is the offset at which to start reading from the file; this
-// is to support archives.  LOCATION is the location of the import
-// statement.
-
-Import::Stream*
-Import::find_elf_export_data(const std::string& name, int fd, off_t offset,
-			     source_location location)
-{
-  struct stat st;
-  if (fstat(fd, &st) < 0)
-    {
-      error_at(location, "%s: %s", name.c_str(), strerror(errno));
-      return NULL;
-    }
-  const off_t file_size = st.st_size;
-
-  // For now we assume that the host system support mmap.  This could
-  // be changed to support reading the bytes directly.  FIXME.
-  void* map = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
-  if (map == MAP_FAILED)
-    {
-      error_at(location, "%s: mmap failed: %s", name.c_str(),
-	       strerror(errno));
-      return NULL;
-    }
-
-  const unsigned char* contents = static_cast<const unsigned char*>(map);
-  contents += offset;
-
-  int c = contents[elfcpp::EI_CLASS];
-  if (c != elfcpp::ELFCLASS32 && c != elfcpp::ELFCLASS64)
-    {
-      error_at(location, "%s: unsupported ELF class %d", name.c_str(), c);
-      munmap(map, file_size);
-      return NULL;
-    }
-
-  int d = contents[elfcpp::EI_DATA];
-  if (d != elfcpp::ELFDATA2LSB && d != elfcpp::ELFDATA2MSB)
-    {
-      error_at(location, "%s: unsupported ELF data encoding %d",
-	       name.c_str(), d);
-      munmap(map, file_size);
-      return NULL;
-    }
-
-  bool is_big_endian = d == elfcpp::ELFDATA2MSB;
-
-  Elf_object* object;
-  if (c == elfcpp::ELFCLASS32)
-    {
-      if (is_big_endian)
-	{
-	  elfcpp::Ehdr<32, true> ehdr(contents);
-	  object = new Sized_elf_object<32, true>(name, contents, file_size,
-						  location, ehdr);
-	}
-      else
-	{
-	  elfcpp::Ehdr<32, false> ehdr(contents);
-	  object = new Sized_elf_object<32, false>(name, contents, file_size,
-						   location, ehdr);
-	}
-    }
-  else
-    {
-      if (is_big_endian)
-	{
-	  elfcpp::Ehdr<64, true> ehdr(contents);
-	  object = new Sized_elf_object<64, true>(name, contents, file_size,
-						  location, ehdr);
-	}
-      else
-	{
-	  elfcpp::Ehdr<64, false> ehdr(contents);
-	  object = new Sized_elf_object<64, false>(name, contents, file_size,
-						   location, ehdr);
-	}
-    }
-
-  std::string export_data;
-  bool ret = object->find_export_section(&export_data);
-
-  delete object;
-  munmap(map, file_size);
-
-  if (ret)
-    return new Stream_from_string(export_data);
-  else
-    return NULL;
-}
diff -r d84d3a63e9ca go/import.cc
--- a/go/import.cc	Sun Oct 31 11:15:12 2010 -0700
+++ b/go/import.cc	Tue Nov 02 15:56:27 2010 -0700
@@ -15,6 +15,8 @@ 
 #include "filenames.h"
 }
 
+#include "simple-object.h"
+
 #include "go-c.h"
 #include "gogo.h"
 #include "types.h"
@@ -176,9 +178,13 @@ 
 Import::find_export_data(const std::string& filename, int fd,
 			 source_location location)
 {
-  const int len = MAX(Export::v1_magic_len,
-		      MAX(Import::elf_magic_len,
-			  Import::archive_magic_len));
+  // See if we can read this as an object file.
+  Import::Stream* stream = Import::find_object_export_data(filename, fd, 0,
+							   location);
+  if (stream != NULL)
+    return stream;
+
+  const int len = MAX(Export::v1_magic_len, Import::archive_magic_len);
 
   char buf[len];
   ssize_t c = read(fd, buf, len);
@@ -189,16 +195,63 @@ 
   if (memcmp(buf, Export::v1_magic, Export::v1_magic_len) == 0)
     return new Stream_from_file(fd);
 
-  // Check for export data in a section of an ELF file.
-  if (Import::is_elf_magic(buf))
-    return Import::find_elf_export_data(filename, fd, 0, location);
-
+  // See if we can read this as an archive.
   if (Import::is_archive_magic(buf))
     return Import::find_archive_export_data(filename, fd, location);
 
   return NULL;
 }
 
+// Look for export data in a simple_object.
+
+Import::Stream*
+Import::find_object_export_data(const std::string& filename,
+				int fd,
+				off_t offset,
+				source_location location)
+{
+  const char* errmsg;
+  int err;
+  simple_object_read* sobj = simple_object_start_read(fd, offset,
+						      "__GNU_GO",
+						      &errmsg, &err);
+  if (sobj == NULL)
+    return NULL;
+
+  off_t sec_offset;
+  off_t sec_length;
+  int found = simple_object_find_section(sobj, ".go_export", &sec_offset,
+					 &sec_length, &errmsg, &err);
+
+  simple_object_release_read(sobj);
+
+  if (!found)
+    return NULL;
+
+  if (lseek(fd, offset + sec_offset, SEEK_SET) < 0)
+    {
+      error_at(location, "lseek %s failed: %s", filename.c_str(),
+	       strerror(errno));
+      return NULL;
+    }
+
+  char* buf = new char[sec_length];
+  ssize_t c = read(fd, buf, sec_length);
+  if (c < 0)
+    {
+      error_at(location, "read %s failed: %s", filename.c_str(),
+	       strerror(errno));
+      return NULL;
+    }
+  if (c < sec_length)
+    {
+      error_at(location, "%s: short read", filename.c_str());
+      return NULL;
+    }
+
+  return new Stream_from_buffer(buf, sec_length);
+}
+
 // Class Import.
 
 // Construct an Import object.  We make the builtin_types_ vector
diff -r d84d3a63e9ca go/import.h
--- a/go/import.h	Sun Oct 31 11:15:12 2010 -0700
+++ b/go/import.h	Tue Nov 02 15:56:27 2010 -0700
@@ -200,14 +200,9 @@ 
   static Stream*
   find_export_data(const std::string& filename, int fd, source_location);
 
-  static const int elf_magic_len = 4;
-
-  static bool
-  is_elf_magic(const char*);
-
   static Stream*
-  find_elf_export_data(const std::string& filename, int fd, off_t offset,
-		       source_location);
+  find_object_export_data(const std::string& filename, int fd,
+			  off_t offset, source_location);
 
   static const int archive_magic_len = 8;
 
@@ -289,6 +284,41 @@ 
   size_t pos_;
 };
 
+// Read import data from an allocated buffer.
+
+class Stream_from_buffer : public Import::Stream
+{
+ public:
+  Stream_from_buffer(char* buf, size_t length)
+    : buf_(buf), length_(length), pos_(0)
+  { }
+
+  ~Stream_from_buffer()
+  { delete[] this->buf_; }
+
+ protected:
+  bool
+  do_peek(size_t length, const char** bytes)
+  {
+    if (this->pos_ + length > this->length_)
+      return false;
+    *bytes = this->buf_ + this->pos_;
+    return true;
+  }
+
+  void
+  do_advance(size_t len)
+  { this->pos_ += len; }
+
+ private:
+  // The data we are reading.
+  char* buf_;
+  // The length of the buffer.
+  size_t length_;
+  // The current position within the buffer.
+  size_t pos_;
+};
+
 // Read import data from an open file descriptor.
 
 class Stream_from_file : public Import::Stream