This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PATCH: new DWARF-2 reader


>>>>> "Casey" == Casey Marshall <csm@gnu.org> writes:

Revised again, fixing a few remaining problems with the implementation
(the DWARF-2 spec is really hard to interpret! I hope now that it is
accurate) and fit it into the Throwable machinery.

2005-03-26  Casey Marshall  <csm@gnu.org>

	* gnu/gcj/runtime/NameFinder.java (use_dwarf2): new constant.
        (<clinit>): new method, fill in boolean config variables with
        GetPropertyAction.
        (dwarf2finders): new field.
        (lookup): try DWARF-2 finder before addr2line.
        * gnu/gcj/runtime/Dwarf2NameFinder.java: new file.
        * gnu/gcj/runtime/SectionFinderELF32.java: new file.
        * gnu/gcj/runtime/SectionFinderUnknown.java: new file.
        * Makefile.am (built_java_source_files): add
        'SectionFinder.java'
        (ordinary_java_source_files): add 'Dwarf2NameFinder.java'
        (configure.ac): link the appropriate SectionFinder class to
        SectionFinder.java

-- 
Casey Marshall || csm@gnu.org
Index: gnu/gcj/runtime/NameFinder.java
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/gnu/gcj/runtime/NameFinder.java,v
retrieving revision 1.9
diff -u -b -B -r1.9 NameFinder.java
--- gnu/gcj/runtime/NameFinder.java	10 Mar 2005 19:02:17 -0000	1.9
+++ gnu/gcj/runtime/NameFinder.java	27 Mar 2005 00:40:59 -0000
@@ -11,6 +11,7 @@
 
 import gnu.classpath.Configuration;
 import gnu.gcj.RawData;
+import gnu.java.security.action.GetPropertyAction;
 
 import java.lang.StringBuffer;
 
@@ -20,8 +21,11 @@
 import java.io.OutputStreamWriter;
 import java.io.IOException;
 import java.io.File;
+import java.security.AccessController;
 import java.util.Iterator;
 import java.util.HashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 
 /**
@@ -51,11 +55,21 @@
   private String sourceFile;
   private int lineNum;
   private HashMap procs = new HashMap();
+  private HashMap dwarf2finders = new HashMap();
 
-  private static final boolean use_addr2line
-          = Boolean.valueOf(System.getProperty
-                ("gnu.gcj.runtime.NameFinder.use_addr2line", "true")
-            ).booleanValue();
+  private static final boolean use_addr2line;
+  private static final boolean use_dwarf2;
+
+  private static final Logger logger = Logger.getLogger (NameFinder.class.getName ());
+
+  static
+  {
+    GetPropertyAction gpa = new GetPropertyAction
+      ("gnu.gcj.runtime.NameFinder.use_addr2line", "true");
+    use_addr2line = Boolean.valueOf ((String) AccessController.doPrivileged (gpa)).booleanValue ();
+    gpa.setParameters ("gnu.gcj.runtime.NameFinder.use_dwarf2", "true");
+    use_dwarf2 = Boolean.valueOf ((String) AccessController.doPrivileged (gpa)).booleanValue ();
+  }
 
   class Addr2Line
   {
@@ -129,10 +143,31 @@
   
   public void lookup (String file, long addr)
   {
+    if (Configuration.DEBUG)
+      logger.log (Level.FINE, "looking up 0x{0} in {1}", new Object[]
+        { Long.toHexString (addr), file });
+
     binaryFile = file;
     sourceFile = null;
     lineNum = -1;
     
+    if (use_dwarf2)
+      {
+        Dwarf2NameFinder dw2 = (Dwarf2NameFinder) dwarf2finders.get (file);
+        if (dw2 == null)
+          {
+            dw2 = new Dwarf2NameFinder (file);
+            dwarf2finders.put (file, dw2);
+          }
+
+        dw2.lookup (addr);
+        sourceFile = dw2.getSourceFile ();
+        lineNum = dw2.getLineNumber ();
+
+        if (sourceFile != null && lineNum > 0) // means it worked
+          return;
+      }
+
     if (! use_addr2line)
       return;
     Addr2Line addr2line = (Addr2Line) procs.get(file);
Index: gnu/gcj/runtime/Dwarf2NameFinder.java
===================================================================
RCS file: gnu/gcj/runtime/Dwarf2NameFinder.java
diff -N gnu/gcj/runtime/Dwarf2NameFinder.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/gcj/runtime/Dwarf2NameFinder.java	27 Mar 2005 00:40:59 -0000
@@ -0,0 +1,480 @@
+/* Dwarf2NameFinder.java -- decodes the DWARF-2 debug_line section.
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+// Written by Casey Marshall <csm@gnu.org>
+
+
+package gnu.gcj.runtime;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An interpreter for DWARF-2 "debug_line" byte codes, which, if given
+ * the program counter of a running program, can determine the source
+ * file and line number (and column number, but that information is not
+ * currently emitted by GCC) of that statement.
+ */
+public class Dwarf2NameFinder
+{
+  private static final Logger logger = Logger.getLogger (Dwarf2NameFinder.class.getName ());
+  private static final String DEBUG_LINE = ".debug_line";
+
+  private String binaryFile;
+  private String sourceFile = null;
+  private int lineNumber = -1;
+
+  /**
+   * This is the '.debug_line' section of 'binaryFile', mapped into
+   * memory. It contains the DWARF-2 byte codes for the file and line
+   * number information.
+   */
+  private MappedByteBuffer dw2;
+
+  private static final int DW_LNS_extended_op = 0;
+  private static final int DW_LNS_copy = 1;
+  private static final int DW_LNS_advance_pc = 2;
+  private static final int DW_LNS_advance_line = 3;
+  private static final int DW_LNS_set_file = 4;
+  private static final int DW_LNS_set_column = 5;
+  private static final int DW_LNS_negate_stmt = 6;
+  private static final int DW_LNS_set_basic_block = 7;
+  private static final int DW_LNS_const_add_pc = 8;
+  private static final int DW_LNS_fixed_advance_pc = 9;
+  private static final int DW_LNE_end_sequence = 1;
+  private static final int DW_LNE_set_address = 2;
+  private static final int DW_LNE_define_file = 3;
+
+  private static final debug DEBUG = new debug ();
+  private static final class debug extends Level
+  {
+    private debug () { super ("DWARF-2", Level.FINEST.intValue ()); }
+  }
+
+  private static class dw2_debug_line
+  {
+    private long total_length;
+    private int version;
+    private long prologue_length;
+    private int minimum_instruction_length;
+    private boolean default_is_stmt;
+    private byte line_base;
+    private int line_range;
+    private int opcode_base;
+    private final byte[] standard_opcode_lengths = new byte[9];
+
+    private void get (ByteBuffer b)
+    {
+      total_length = (long) b.getInt () & 0xFFFFFFFFL;
+      version = b.getShort () & 0xFFFF;
+      prologue_length = (long) b.getInt () & 0xFFFFFFFFL;
+      minimum_instruction_length = b.get () & 0xFF;
+      default_is_stmt = b.get () != 0;
+      line_base = b.get ();
+      line_range = b.get () & 0xFF;
+      opcode_base = b.get () & 0xFF;
+      b.get (standard_opcode_lengths);
+    }
+
+    public String toString ()
+    {
+      java.lang.StringBuffer str = new java.lang.StringBuffer (super.toString ());
+      str.append (" [ total_length: ").append (total_length);
+      str.append ("; version: ").append (version);
+      str.append ("; prologue_length: ").append (prologue_length);
+      str.append ("; minimum_instruction_length: ").append (minimum_instruction_length);
+      str.append ("; default_is_stmt: ").append (default_is_stmt);
+      str.append ("; line_base: ").append (line_base);
+      str.append ("; line_range: ").append (line_range);
+      str.append ("; opcode_base: ").append (opcode_base);
+      str.append ("; standard_opcode_lengths: { ");
+      str.append (standard_opcode_lengths[0]).append (", ");
+      str.append (standard_opcode_lengths[1]).append (", ");
+      str.append (standard_opcode_lengths[2]).append (", ");
+      str.append (standard_opcode_lengths[3]).append (", ");
+      str.append (standard_opcode_lengths[4]).append (", ");
+      str.append (standard_opcode_lengths[5]).append (", ");
+      str.append (standard_opcode_lengths[6]).append (", ");
+      str.append (standard_opcode_lengths[7]).append (", ");
+      str.append (standard_opcode_lengths[8]).append (" } ]");
+      return str.toString ();
+    }
+  }
+
+  public Dwarf2NameFinder (final String binaryFile)
+  {
+    try
+      {
+        dw2 = SectionFinder.mapSection (binaryFile, DEBUG_LINE);
+        this.binaryFile = binaryFile;
+      }
+    catch (IOException ioe)
+      {
+        if (Configuration.DEBUG)
+          logger.log (DEBUG, "can't map .debug_line in {0}: {1}", new Object[]
+            { binaryFile, ioe.getMessage () });
+        dw2 = null;
+        this.binaryFile = null;
+        return;
+      }
+  }
+
+  public void lookup (final long target)
+  {
+    if (Configuration.DEBUG)
+      logger.log (DEBUG, "Dwarf2NameFinder.lookup: {0} 0x{1}",
+                  new Object[] { binaryFile, Long.toHexString (target) });
+
+    lineNumber = -1;
+    sourceFile = null;
+
+    if (dw2 == null)
+      return;
+
+    dw2.position (0);
+    dw2.limit (dw2.capacity ());
+
+    if (Configuration.DEBUG)
+      logger.log (DEBUG, "Mapped .debug_line section is {0} bytes", new Integer (dw2.capacity ()));
+
+    while (dw2.hasRemaining ())
+      {
+        final int begin = dw2.position ();
+        dw2_debug_line header = new dw2_debug_line ();
+        header.get (dw2);
+        if (Configuration.DEBUG)
+          logger.log (DEBUG, "read debug_line header: {0}", header);
+        final int end = (int) (begin + header.total_length + 4);
+        final int prologue_end = (int) (begin + header.prologue_length + 9);
+
+        if (Configuration.DEBUG)
+          logger.log (DEBUG, "this section starts at {0}, ends at {1}, and the prologue ends at {2}",
+                      new Object[] { new Integer (begin), new Integer (end),
+                                     new Integer (prologue_end) });
+
+        if (header.version != 2 || header.opcode_base != 10)
+          {
+            if (Configuration.DEBUG)
+              logger.log (DEBUG, "skipping this section; not DWARF-2 (version={0}, opcode_base={1})",
+                          new Object[] { new Integer (header.version),
+                                         new Integer (header.opcode_base) });
+            dw2.position (end);
+            continue;
+          }
+
+        final int const_pc_add = 245 / header.line_range;
+
+        dw2.limit (prologue_end);
+        ByteBuffer prologue = dw2.slice ();
+
+        // Skip the directories; they end with a single null byte.
+        String s;
+        while ((s = getString (prologue)).length () > 0)
+          {
+            if (Configuration.DEBUG)
+              logger.log (DEBUG, "Skipped directory: {0}", s);
+          }
+
+        // Read the file names.
+        LinkedList fnames = new LinkedList ();
+        while (prologue.hasRemaining ())
+          {
+            String fname = getString (prologue);
+            if (Configuration.DEBUG)
+              logger.log (DEBUG, "File name: {0}", fname);
+            fnames.add (fname);
+
+            long u1 = getUleb128 (prologue);
+            long u2 = getUleb128 (prologue);
+            long u3 = getUleb128 (prologue);
+            if (Configuration.DEBUG)
+              logger.log (DEBUG, "dir: {0}, time: {1}, len: {2}", new Object[]
+                { new Long (u1), new Long (u2), new Long (u3) });
+          }
+        prologue = null;
+
+        dw2.limit (end);
+        dw2.position (prologue_end + 1);
+        ByteBuffer section = dw2.slice ();
+        dw2.limit (dw2.capacity ());
+        dw2.position (end);
+
+        long address = 0;
+        long base_address = 0;
+        String define_file = null;
+        int fileno = 0;
+        int lineno = 1;
+        int prev_fileno = 0;
+        int prev_lineno = 1;
+
+        interpret: while (section.hasRemaining ())
+          {
+            int opcode = section.get () & 0xFF;
+
+            if (opcode < header.opcode_base)
+              {
+                switch (opcode)
+                  {
+                  case DW_LNS_extended_op:
+                    {
+                      long insn_len = getUleb128 (section);
+                      opcode = section.get ();
+                      if (Configuration.DEBUG)
+                        logger.log (DEBUG, "special opcode {0}, insn_len={1}",
+                                    new Object[] { new Integer (opcode), new Long (insn_len) });
+
+                      switch (opcode)
+                        {
+                        case DW_LNE_end_sequence:
+                          if (Configuration.DEBUG)
+                            logger.log (DEBUG, "End of sequence");
+                          if (base_address <= target && address > target)
+                            {
+                              lineNumber = prev_lineno;
+                              sourceFile = (String) ((prev_fileno >= 0 && prev_fileno < fnames.size ())
+                                                     ? fnames.get (prev_fileno) : define_file);
+                              logger.log (DEBUG, "found {0}:{1} for {2}", new Object[]
+                                { sourceFile, new Integer (lineNumber), Long.toHexString (target) });
+                              return;
+                            }
+                          prev_lineno = lineno = 1;
+                          prev_fileno = fileno = 0;
+                          base_address = address = 0;
+                          break;
+
+                        case DW_LNE_set_address:
+                          base_address = section.get () & 0xFF;
+                          base_address |= (section.get () & 0xFFL) << 8;
+                          base_address |= (section.get () & 0xFFL) << 16;
+                          base_address |= (section.get () & 0xFFL) << 24;
+                          address = base_address;
+                          if (Configuration.DEBUG)
+                            logger.log (DEBUG, "Set address to 0x{0}", Long.toHexString (address));
+
+                          // XXX this might not be correct, as there can be more
+                          // than one of these instructions in a single compilation
+                          // unit.
+                          if (address > target)
+                            {
+                              if (Configuration.DEBUG)
+                                logger.log (DEBUG, "not in this unit base=0x{0}, target=0x{1}",
+                                            new Object[] { Long.toHexString (address),
+                                                           Long.toHexString (target) });
+                              break interpret;
+                            }
+                          break;
+
+                        case DW_LNE_define_file:
+                          define_file = getString (section);
+                          if (Configuration.DEBUG)
+                            logger.log (DEBUG, "Define file: {0}", define_file);
+                          getUleb128 (section);
+                          getUleb128 (section);
+                          getUleb128 (section);
+                          break;
+
+                        default:
+                          if (Configuration.DEBUG)
+                            logger.log (DEBUG, "Unsupported extended opcode {0}",
+                                        new Integer (opcode));
+                          section.position (section.position () + (int) insn_len);
+                          break;
+                        }
+
+                    }
+                  case DW_LNS_copy:
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Copy");
+                    if (base_address <= target && address > target)
+                      {
+                        lineNumber = prev_lineno;
+                        sourceFile = (String) ((prev_fileno >= 0 && prev_fileno < fnames.size ())
+                                               ? fnames.get (prev_fileno) : define_file);
+                        logger.log (DEBUG, "found {0}:{1} for {2}", new Object[]
+                          { sourceFile, new Integer (lineNumber), Long.toHexString (target) });
+                        return;
+                      }
+                    prev_lineno = lineno;
+                    prev_fileno = fileno;
+                    break;
+
+                  case DW_LNS_advance_pc:
+                    {
+                      long amt = getUleb128 (section);
+                      address += amt * header.minimum_instruction_length;
+                      if (Configuration.DEBUG)
+                        logger.log (DEBUG, "Advance PC by {0} to 0x{1}",
+                                    new Object[] { new Long (amt),
+                                                   Long.toHexString (address) });
+                    }
+                    break;
+
+                  case DW_LNS_advance_line:
+                    {
+                      long amt = getSleb128 (section);
+                      prev_lineno = lineno;
+                      lineno += (int) amt;
+                      if (Configuration.DEBUG)
+                        logger.log (DEBUG, "Advance line by {0} to {1}", new Object[]
+                          { new Long (amt), new Integer (lineno) });
+                    }
+                    break;
+
+                  case DW_LNS_set_file:
+                    prev_fileno = fileno;
+                    fileno = (int) getUleb128 (section) - 1;
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Set file to {0}", new Integer (fileno));
+                    break;
+
+                  case DW_LNS_set_column:
+                    getUleb128 (section);
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Set column (ignored)");
+                    break;
+
+                  case DW_LNS_negate_stmt:
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Negate statement (ignored)");
+                    break;
+
+                  case DW_LNS_set_basic_block:
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Set basic block (ignored)");
+                    break;
+
+                  case DW_LNS_const_add_pc:
+                    address += const_pc_add;
+                    if (Configuration.DEBUG)
+                      logger.log (DEBUG, "Advance PC by (constant) {0} to 0x{1}",
+                                  new Object[] { new Integer (const_pc_add),
+                                                 Long.toHexString (address) });
+                    break;
+
+                  case DW_LNS_fixed_advance_pc:
+                    {
+                      int amt = section.getShort () & 0xFFFF;
+                      address += amt;
+                      if (Configuration.DEBUG)
+                        logger.log (DEBUG, "Advance PC by (fixed) {0} to 0x{1}",
+                                    new Object[] { new Integer (amt),
+                                                   Long.toHexString (address) });
+                    }
+                    break;
+                  }
+              }
+            else
+              {
+                int adj = (opcode & 0xFF) - header.opcode_base;
+                int addr_adv = adj / header.line_range;
+                int line_adv = header.line_base + (adj % header.line_range);
+                long new_addr = address + addr_adv;
+                int new_line = lineno + line_adv;
+                if (Configuration.DEBUG)
+                  logger.log (DEBUG,
+                              "Special opcode {0} advance line by {1} to {2} and address by {3} to 0x{4}",
+                              new Object[] { new Integer (opcode & 0xFF),
+                                             new Integer (line_adv),
+                                             new Integer (new_line),
+                                             new Integer (addr_adv),
+                                             Long.toHexString (new_addr) });
+                if (base_address <= target && new_addr >= target)
+                  {
+                    lineNumber = new_addr == target ? new_line : lineno;
+                    sourceFile = (String) ((fileno >= 0 && fileno < fnames.size ())
+                                           ? fnames.get (fileno) : define_file);
+                    logger.log (DEBUG, "found {0}:{1} for {2}", new Object[]
+                      { sourceFile, new Integer (lineNumber), Long.toHexString (target) });
+                    return;
+                  }
+
+                prev_lineno = lineno;
+                prev_fileno = fileno;
+                lineno = new_line;
+                address = new_addr;
+              }
+          }
+      }
+  }
+
+  public void close ()
+  {
+    dw2 = null;
+    binaryFile = null;
+  }
+
+  public String getSourceFile ()
+  {
+    return sourceFile;
+  }
+
+  public int getLineNumber ()
+  {
+    return lineNumber;
+  }
+
+  private static String getString (ByteBuffer buf)
+  {
+    int pos = buf.position ();
+    int len = 0;
+    byte b;
+    while (buf.get () != 0) len++;
+    byte[] bytes = new byte[len];
+    buf.position (pos);
+    buf.get (bytes);
+    buf.get ();
+    return new String (bytes);
+  }
+
+  private static long getUleb128 (ByteBuffer buf)
+  {
+    long val = 0;
+    byte b;
+    int shift = 0;
+
+    while (true)
+      {
+        b = buf.get ();
+        val |= (b & 0x7f) << shift;
+        if ((b & 0x80) == 0)
+          break;
+        shift += 7;
+      }
+
+    return val;
+  }
+
+  private static long getSleb128 (ByteBuffer buf)
+  {
+    long val = 0;
+    int shift = 0;
+    byte b;
+    int size = 8 << 3;
+
+    while (true)
+      {
+        b = buf.get ();
+        val |= (b & 0x7f) << shift;
+        shift += 7;
+        if ((b & 0x80) == 0)
+          break;
+      }
+
+    if (shift < size && (b & 0x40) != 0)
+      val |= -(1 << shift);
+
+    return val;
+  }
+}
Index: gnu/gcj/runtime/SectionFinderELF32.java
===================================================================
RCS file: gnu/gcj/runtime/SectionFinderELF32.java
diff -N gnu/gcj/runtime/SectionFinderELF32.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/gcj/runtime/SectionFinderELF32.java	27 Mar 2005 00:41:00 -0000
@@ -0,0 +1,288 @@
+/* SectionFinderELF32.java -- finds sections by name in 32-bit ELF files.
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+// Written by Casey Marshall <csm@gnu.org>
+
+
+package gnu.gcj.runtime;
+
+import gnu.classpath.Configuration;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteOrder;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A utility class to find, and map, named sections in executable files.
+ *
+ * This version is for the Executable and Linking Format, ELF, for 32-bit
+ * machines.
+ */
+class SectionFinder
+{
+
+  private static final Logger logger = Logger.getLogger (SectionFinder.class.getName ());
+  private static final debug DEBUG = new debug ();
+
+  private static final byte ELFMAG0 = 0x7f;
+  private static final byte ELFMAG1 = (byte) 'E';
+  private static final byte ELFMAG2 = (byte) 'L';
+  private static final byte ELFMAG3 = (byte) 'F';
+
+  private static final class debug extends Level
+  {
+    private debug () { super ("DWARF-2(ELF-32)", Level.FINEST.intValue()); }
+  }
+
+  private static final boolean WORDS_BIGENDIAN =
+    ByteOrder.nativeOrder ().equals (ByteOrder.BIG_ENDIAN);
+
+  /**
+   * This class is similar to the 'struct Elf32_Ehdr' in the GNU C
+   * library.
+   */
+  private static class Elf32_Ehdr
+  {
+    private static final int EI_NIDENT = 16;
+
+    private final byte[] e_ident   /* Magic number and other info. */
+      = new byte[EI_NIDENT];
+    private int e_type;            /* Object file type. */
+    private int e_machine;         /* Architecture type. */
+    private int e_version;         /* Object file version. */
+    private long e_entry;          /* Entry point virtual address. */
+    private long e_phoff;          /* Program header table file offset. */
+    private long e_shoff;          /* Section header table file offset. */
+    private int e_flags;           /* Processor-specific flags. */
+    private int e_ehsize;          /* ELF header size in bytes. */
+    private int e_phentsize;       /* Program header table entry size. */
+    private int e_phentnum;        /* Program header table entry count. */
+    private int e_shentsize;       /* Section header table entry size. */
+    private int e_shnum;           /* Section header table entry count. */
+    private int e_shstrndx;        /* Section header string table index. */
+
+    private Elf32_Ehdr () { }
+
+    private void read (RandomAccessFile f) throws IOException
+    {
+      f.readFully (e_ident);
+      e_type = readUHalf (f);
+      e_machine = readUHalf (f);
+      e_version = readWord (f);
+      e_entry = readUWord (f);
+      e_phoff = readUWord (f);
+      e_shoff = readUWord (f);
+      e_flags = readWord (f);
+      e_ehsize = readUHalf (f);
+      e_phentsize = readUHalf (f);
+      e_phentnum = readUHalf (f);
+      e_shentsize = readUHalf (f);
+      e_shnum = readUHalf (f);
+      e_shstrndx = readUHalf (f);
+    }
+
+    public String toString ()
+    {
+      java.lang.StringBuffer str = new java.lang.StringBuffer (super.toString ());
+      str.append (" [ e_ident: ");
+      for (int i = 0; i < EI_NIDENT; i++)
+	{
+	  if (e_ident[i] < 0x10 && e_ident[i] >= 0)
+	    str.append ('0');
+	  str.append (Integer.toHexString (e_ident[i] & 0xFF));
+	}
+      str.append ("; e_type: ").append (e_type & 0xFFFF);
+      str.append ("; e_machine: ").append (e_machine & 0xFFFF);
+      str.append ("; e_version: ").append (e_version & 0xFFFF);
+      str.append ("; e_entry: 0x").append (Long.toHexString (e_entry));
+      str.append ("; e_phoff: ").append ((long) e_phoff & 0xFFFFFFFFL);
+      str.append ("; e_shoff: ").append ((long) e_shoff & 0xFFFFFFFFL);
+      str.append ("; e_flags: 0x").append (Integer.toHexString (e_flags));
+      str.append ("; e_ehsize: ").append (e_ehsize & 0xFFFF);
+      str.append ("; e_phentsize: ").append (e_phentsize & 0xFFFF);
+      str.append ("; e_phentnum: ").append (e_phentnum & 0xFFFF);
+      str.append ("; e_shentsize: ").append (e_shentsize & 0xFFFF);
+      str.append ("; e_shnum: ").append (e_shnum & 0xFFFF);
+      str.append ("; e_shstrndx: ").append (e_shstrndx & 0xFFFF);
+      str.append (" ]");
+      return str.toString ();
+    }
+  }
+
+  private static class Elf32_Shdr
+  {
+    private long sh_name;
+    private int sh_type;
+    private int sh_flags;
+    private long sh_addr;
+    private long sh_offset;
+    private long sh_size;
+    private int sh_link;
+    private int sh_info;
+    private int sh_addralign;
+    private long sh_entsize;
+
+    private Elf32_Shdr () { }
+
+    private static int sizeof () { return 40; }
+
+    private void read (RandomAccessFile f) throws IOException
+    {
+      sh_name = readUWord (f);
+      sh_type = readWord (f);
+      sh_flags = readWord (f);
+      sh_addr = readUWord (f);
+      sh_offset = readUWord (f);
+      sh_size = readUWord (f);
+      sh_link = readWord (f);
+      sh_info = readWord (f);
+      sh_addralign = readWord (f);
+      sh_entsize = readWord (f);
+    }
+
+    public String toString ()
+    {
+      java.lang.StringBuffer str = new java.lang.StringBuffer (super.toString ());
+      str.append (" [ sh_name: ").append (sh_name);
+      str.append ("; sh_type: ").append (sh_type);
+      str.append ("; sh_flags: 0x").append (Long.toHexString (sh_flags));
+      str.append ("; sh_addr: 0x").append (Long.toHexString (sh_addr));
+      str.append ("; sh_offset: ").append (sh_offset);
+      str.append ("; sh_size: ").append (sh_size);
+      str.append ("; sh_link: ").append (sh_link);
+      str.append ("; sh_info: ").append (sh_info);
+      str.append ("; sh_addralgin: ").append (sh_addralign);
+      str.append ("; sh_entsize: ").append (sh_entsize);
+      str.append (" ]");
+      return str.toString ();
+    }
+  }
+
+  /**
+   * Map the named section from the given ELF file.
+   *
+   * @param file The file to look in.
+   * @param section The name of the section to map.
+   * @return The mapped byte buffer of the named section.
+   * @throws IOException If the named section cannot be found, or if
+   *  some other IO error occurs.
+   */
+  static MappedByteBuffer mapSection (String file, String section)
+    throws IOException
+  {
+    if (Configuration.DEBUG)
+      logger.log (DEBUG, "mapSection {0}", file);
+    RandomAccessFile f = new RandomAccessFile (file, "r");
+
+    /** Read the ELF header. */
+    Elf32_Ehdr ehdr = new Elf32_Ehdr ();
+    ehdr.read (f);
+    if (ehdr.e_ident[0] != ELFMAG0 || ehdr.e_ident[1] != ELFMAG1
+	|| ehdr.e_ident[2] != ELFMAG2 || ehdr.e_ident[3] != ELFMAG3)
+      {
+	f.close ();
+	throw new IOException (file + ": not an ELF file");
+      }
+    if (Configuration.DEBUG)
+      logger.log (DEBUG, "read ELF header: {0}", ehdr);
+
+    /* Read the string table section header. */
+    Elf32_Shdr strtabhdr = new Elf32_Shdr ();
+    f.seek (ehdr.e_shoff + (ehdr.e_shstrndx * Elf32_Shdr.sizeof ()));
+    strtabhdr.read (f);
+    if (Configuration.DEBUG)
+      logger.log (DEBUG, "read string table section header: {0}", strtabhdr);
+
+    Elf32_Shdr shdr = new Elf32_Shdr ();
+    byte[] target_bytes = section.getBytes ("ISO8859-1");
+    byte[] buf = new byte[target_bytes.length + 1];
+    boolean found = false;
+
+    outer: for (int i = 0; i < ehdr.e_shnum; i++)
+      {
+	// Read information about this section.
+	f.seek (ehdr.e_shoff + (i * Elf32_Shdr.sizeof ()));
+	shdr.read (f);
+	if (Configuration.DEBUG)
+	  logger.log (DEBUG, "checking section: {0}", shdr);
+
+	// Read the section name from the string table.
+	f.seek (strtabhdr.sh_offset + shdr.sh_name);
+	f.readFully (buf);
+	if (Configuration.DEBUG)
+	  logger.log (DEBUG, "this section is \"{0}\"", new String (buf));
+	for (int j = 0; j < target_bytes.length; j++)
+	  if (target_bytes[j] != buf[j])
+	    continue outer;
+	if (buf[buf.length - 1] != '\0')
+	  continue;
+
+	if (Configuration.DEBUG)
+	  logger.log (DEBUG, "found section {0}: {1}", new Object[]
+	    { section, shdr });
+	found = true;
+	break;
+      }
+
+    if (!found)
+      {
+	f.close ();
+	throw new IOException ("no section " + section + " found in " + file);
+      }
+
+    try
+      {
+	FileChannel chan = f.getChannel ();
+	MappedByteBuffer buffer = chan.map (FileChannel.MapMode.READ_ONLY,
+					    shdr.sh_offset, shdr.sh_size);
+	buffer.order (ByteOrder.nativeOrder ());
+	chan.close ();
+	return buffer;
+      }
+    finally
+      {
+	f.close ();
+      }
+  }
+
+  private static int readUHalf (RandomAccessFile f) throws IOException
+  {
+    if (WORDS_BIGENDIAN)
+      return f.readUnsignedShort ();
+    else
+      return f.readUnsignedByte () | (f.readUnsignedByte () << 8);
+  }
+
+  private static int readWord (RandomAccessFile f) throws IOException
+  {
+    if (WORDS_BIGENDIAN)
+      return f.readInt ();
+    else
+      return (f.readUnsignedByte () | (f.readUnsignedByte () << 8)
+	      | (f.readUnsignedByte () << 16) | (f.readUnsignedByte () << 24));
+  }
+
+  private static long readUWord (RandomAccessFile f) throws IOException
+  {
+    if (WORDS_BIGENDIAN)
+      return (long) f.readInt () & 0xFFFFFFFFL;
+    else
+      {
+	long l = (f.readUnsignedByte () | (f.readUnsignedByte () << 8)
+		  | (f.readUnsignedByte () << 16) | (f.readUnsignedByte () << 24));
+	return (l & 0xFFFFFFFFL);
+      }
+  }
+}
Index: gnu/gcj/runtime/SectionFinderUnknown.java
===================================================================
RCS file: gnu/gcj/runtime/SectionFinderUnknown.java
diff -N gnu/gcj/runtime/SectionFinderUnknown.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/gcj/runtime/SectionFinderUnknown.java	27 Mar 2005 00:41:00 -0000
@@ -0,0 +1,22 @@
+/* SectionFinderUnknown.java -- SectionFinder for unsupported file formats.
+   Copyright (C) 2005  Free Software Foundation, Inc.
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+
+package gnu.gcj.runtime;
+
+import java.io.IOException;
+import java.nio.MappedByteBuffer;
+
+class SectionFinder
+{
+  static MappedByteBuffer mapSection (String file, String section) throws IOException
+  {
+    throw new IOException ("finding sections by name not supported on this platform");
+  }
+}
Index: configure.ac
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/configure.ac,v
retrieving revision 1.22
diff -u -b -B -r1.22 configure.ac
--- configure.ac	21 Mar 2005 18:12:21 -0000	1.22
+++ configure.ac	27 Mar 2005 00:41:01 -0000
@@ -468,6 +468,19 @@
 AC_CONFIG_LINKS(gnu/java/nio/channels/natFileChannelImpl.cc:gnu/java/nio/channels/natFileChannel${FILE-${PLATFORM}}.cc)
 
 case "${host}" in
+    i?86*-linux*)
+      PLATFORMEXE=ELF32
+      ;;
+    *)
+      PLATFORMEXE=Unknown
+      ;;
+esac
+
+test -d gnu/gcj || mkdir gnu/gcj
+test -d gnu/gcj/runtime || mkdir gnu/gcj/runtime
+AC_CONFIG_LINKS(gnu/gcj/runtime/SectionFinder.java:gnu/gcj/runtime/SectionFinder${PLATFORMEXE}.java)
+
+case "${host}" in
     *mingw*)
       SYSTEMSPEC="-lgdi32 -lws2_32"
       if test "${with_win32_nlsapi}" = "unicows"; then
Index: Makefile.am
===================================================================
RCS file: /cvsroot/gcc/gcc/libjava/Makefile.am,v
retrieving revision 1.464
diff -u -b -B -r1.464 Makefile.am
--- Makefile.am	21 Mar 2005 18:11:40 -0000	1.464
+++ Makefile.am	27 Mar 2005 00:41:04 -0000
@@ -2651,7 +2651,8 @@
 ## Java files which are created by configure and thus are in the build
 ## directory.
 built_java_source_files = java/lang/ConcreteProcess.java \
-                          gnu/classpath/Configuration.java
+                          gnu/classpath/Configuration.java \
+                          gnu/gcj/runtime/SectionFinder.java
 
 ## Java files in the core packages java.lang, java.io, and java.util.
 ## These are built before the other source files, in order to reduce 
@@ -2919,6 +2920,7 @@
 gnu/gcj/io/DefaultMimeTypes.java \
 gnu/gcj/io/MimeTypes.java \
 gnu/gcj/io/SimpleSHSStream.java	\
+gnu/gcj/runtime/Dwarf2NameFinder.java \
 gnu/gcj/runtime/FileDeleter.java \
 gnu/gcj/runtime/FinalizerThread.java \
 gnu/gcj/runtime/JNIWeakRef.java \

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