This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: PATCH: new DWARF-2 reader
- From: Casey Marshall <csm at gnu dot org>
- To: java-patches at gcc dot gnu dot org
- Date: Sat, 26 Mar 2005 17:13:29 -0800
- Subject: Re: PATCH: new DWARF-2 reader
- References: <87k6o14jra.fsf@gnu.org>
>>>>> "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 \