[davidm@hpl.hp.com: .debug_line patch]

Richard Henderson rth@cygnus.com
Sat May 8 15:18:00 GMT 1999


----- Forwarded message from David Mosberger <davidm@hpl.hp.com> -----

Date: Sat, 8 May 1999 14:49:15 -0700
Message-Id: <199905082149.OAA28668@napali.hpl.hp.com>
From: David Mosberger <davidm@hpl.hp.com>
To: rth@cygnus.com
Subject: .debug_line patch
X-URL: http://www.hpl.hp.com/personal/David_Mosberger/
Reply-to: davidm@hpl.hp.com

Hi Richard,

This took a bit longer to debug than expected, but here it is: the
patch is relative to the gas-990404 snapshot (unfortunately, this
includes the 32-bit cleanups I sent you earlier, but I hope it won't
be too much trouble to filter those out).  What it does:

	- fix some bugs in bfd/dwarf2.c and makes it more robust
	  against bad .debug_line sections

	- add the necessary machinery for generating .debug_line in
	  the assembler

	- modifies egcs/gcc/dwarf2out.c so that it leaves .debug_line
	  generation to the assembler (via .file & .loc) if
	  macro ASM_DWARF2_LINE_DEBUG_INFO is defined

Perhaps dwarf2dbg.c is too big a change to accept without an
assignment form, but at least you can take a look at it and let me
know what you think.  The other changes are hopefully small enough not
to require an assignment (I'm still waiting for the final version of
the corporate assignment).

Some caveats:

	o egcs currently passes the line info to the assembler in
	  a very naive (space-wasting) way: one .file/.loc directive
	  per line! ;-)   Easy to fix, but I just wanted something
	  that's simple and reliable for now

	o disassembling handcrafted assembly files that were
	  translated with -gdwarf2 still doesn't work; I think the
	  best way to fix this is to change
	  dwarf2dbg.c:dwarf2_finish() to check if .debug_info exists
	  and, if not, generate a small .debug_info section good
	  enough for bfd/dwarf2.c to do its job

	o disassembling object files (as opposed to executables) still
	  doesn't work perfectly (though better than before); as
	  the comment in bfd/dwarf2.c suggests, fixing this would
	  require looking at the relocs

Note that with dwarf2dbg.c, You can invoke the assembler with -D to
get some statistics on the effectiveness of the .debug_line info.  For
the IA-64 GNU libc, the size of .debug_line dropped from 1,223 KB to
143 KB so it's definitely worthwhile! ;-)

I didn't test this on anything but IA-64.  It would be interesting to
see how the assembler holds up when used with another compiler that
has DWARF2 support.

	--david

---------------------------------------------------------------------
gas-990404-lia/gas/ChangeLog	Fri May  7 17:41:43 1999

1999-05-07  David Mosberger  <davidm@hpl.hp.com>

	* as.c (parse_args): Add option -gdwarf2 to allow requesting
	DWARF2 debug info (line information only, at this point).

	* as.h: Update comment about supported debug formats.

	* dwarf2dbg.h: New file.

	* dwarf2dbg.c: New file.
	
---------------------------------------------------------------------
gas-990404-lia/bfd/ChangeLog	Fri May  7 16:48:22 1999

1999-05-07  David Mosberger  <davidm@hpl.hp.com>

	* dwarf2.c (decode_line_info): Initialize table->files and
	table->last_line to NULL to avoid segfaults due to random
	values in these members.
	(concat_filename): Check for out-of-range file number before
	indexing filename table.  Segfaults suck.

---------------------------------------------------------------------
egcs-1.1.2-lia/gcc/ChangeLog      Fri May  7 15:04:30 1999

Sat May  8 14:36:43 1999  David Mosberger  <davidm@hpl.hp.com>

        * dwarf2out.c (print_dwarf_line_table, size_of_line_prolog,
        sizeof_of_line_info, output_line_info): Declare and define only if
        macro ASM_DWARF2_LINE_DEBUG_INFO is not defined.
        (debug_dwarf): Call print_dwarf_line_table()
        only if ASM_DWARF2_LINE_DEBUG_INFO is not defined.
        (dwarf2out_line) [ASM_DWARF2_LINE_DEBUG_INFO]: Use
        .file and .loc directives to pass line information
        to assembler (current implementation is naive and
        not very compact...).
        (dwarf2out_finish) [ASM_DWARF2_LINE_DEBUG_INFO]: Instead of
        generating full .debug_line section, only generate DW_AT_stmt_list
        entry if .debug_line is non-empty.

---------------------------------------------------------------------
diff -urN gas-990404/bfd/dwarf2.c gas-990404-lia/bfd/dwarf2.c
--- gas-990404/bfd/dwarf2.c	Sun Apr  4 01:12:58 1999
+++ gas-990404-lia/bfd/dwarf2.c	Sat May  8 13:35:03 1999
@@ -677,7 +677,16 @@
      struct line_info_table* table;
      unsigned int file;
 {
-  char* filename = table->files[file - 1].name;
+  char* filename;
+
+  if (file - 1 >= table->num_files)
+    {
+      (*_bfd_error_handler) (_("Dwarf Error: mangled line number "
+			       "section (bad file number)."));
+      return "<unknown>";
+    }
+
+  filename = table->files[file - 1].name;
   if (*filename == '/')
     return filename;
 
@@ -708,6 +717,7 @@
   unsigned int i, bytes_read;
   char *cur_file, *cur_dir;
   unsigned char op_code, extended_op, adj_opcode;
+  bfd_vma hi_pc = 0, lo_pc = ~ (bfd_vma) 0;
 
   if (! dwarf_line_buffer)
     {
@@ -747,6 +757,9 @@
   table->num_dirs = 0;
   table->dirs = NULL;
 
+  table->files = NULL;
+  table->last_line = NULL;
+
   line_ptr = dwarf_line_buffer + unit->line_offset;
 
   /* read in the prologue */
@@ -831,6 +844,7 @@
       int is_stmt = lh.default_is_stmt;
       int basic_block = 0;
       int end_sequence = 0;
+      boolean first_time = true;
 
       /* Decode the table. */
       while (! end_sequence)
@@ -851,7 +865,6 @@
 		  break;
 		case DW_LNE_set_address:
 		  address = read_address (unit, line_ptr);
-		  address &= 0xffffffff;
 		  line_ptr += unit->addr_size;
 		  break;
 		case DW_LNE_define_file:
@@ -919,7 +932,8 @@
 	      basic_block = 1;
 	      break;
 	    case DW_LNS_const_add_pc:
-	      address += (255 - lh.opcode_base) / lh.line_range;
+	      address += lh.minimum_instruction_length
+		      * ((255 - lh.opcode_base) / lh.line_range);
 	      break;
 	    case DW_LNS_fixed_advance_pc:
 	      address += read_2_bytes (abfd, line_ptr);
@@ -934,8 +948,20 @@
 	      add_line_info (table, address, filename, line, column);
 	      basic_block = 1;
 	    }
+	  if (unit->high == 0)
+	    {
+	      if (address > hi_pc)
+		hi_pc = address;
+	      if (address < lo_pc)
+		lo_pc = address;
+	    }
 	}
     }
+  if (unit->high == 0 && hi_pc != 0)
+    {
+      unit->high = hi_pc;
+      unit->low = lo_pc;
+    }
 
   return table;
 }
@@ -1005,8 +1031,7 @@
        each_func;
        each_func = each_func->prev_func)
     {
-      if (addr >= (each_func->low & 0xffffffff)
-	  && addr < (each_func->high & 0xffffffff))
+      if (addr >= each_func->low && addr < each_func->high)
 	{
 	  *functionname_ptr = each_func->name;
 	  return true;
@@ -1274,8 +1299,7 @@
      bfd_vma addr;
 {
   return ! unit->error
-    && ( addr >= (unit->low & 0xffffffff)
-	&& addr <= (unit->high & 0xffffffff));
+    && (addr >= unit->low && addr <= unit->high);
 }
 
 
@@ -1366,6 +1390,8 @@
 
   struct comp_unit* each;
   
+  boolean found;
+
   *filename_ptr = NULL;
   *functionname_ptr = NULL;
   *linenumber_ptr = 0;
@@ -1407,14 +1433,20 @@
 
       stash->info_ptr_end = stash->info_ptr + size;
 
-      /* FIXME:  There is a problem with the contents of the .debug_info section.
-	 The 'low' and 'high' addresses of the comp_units are computed by relocs
-	 against symbols in the .text segment.  We need these addresses in
-	 order to determine the nearest line number, and so we have to resolve
-	 the relocs.  There is a similar problem when the .debug_line section is
-	 processed as well.
+      /* FIXME: There is a problem with the contents of the
+	 .debug_info section.  The 'low' and 'high' addresses of the
+	 comp_units are computed by relocs against symbols in the
+	 .text segment.  We need these addresses in order to determine
+	 the nearest line number, and so we have to resolve the
+	 relocs.  There is a similar problem when the .debug_line
+	 section is processed as well (e.g., there may be relocs
+	 against the operand of the DW_LNE_set_address operator).
 	 
-	 Unfortunately getting hold of the reloc information is hard... */
+	 Unfortunately getting hold of the reloc information is hard...
+
+	 For now, this means that disassembling object files (as
+	 opposed to fully executables) does not always work as well as
+	 we would like.  */
     }
   
   /* A null info_ptr indicates that there is no dwarf2 info 
@@ -1454,11 +1486,28 @@
 	      each->next_unit = stash->all_comp_units;
 	      stash->all_comp_units = each;
 
-	      if (comp_unit_contains_address (each, addr))
-		return comp_unit_find_nearest_line (each, addr,
-						    filename_ptr, 
-						    functionname_ptr, 
-						    linenumber_ptr);
+	      /* DW_AT_low_pc and DW_AT_high_pc are optional for
+		 compilation units.  If we don't have them (i.e.,
+		 unit->high == 0), we need to consult the line info
+		 table to see if a compilation unit contains the given
+		 address. */
+	      if (each->high > 0)
+		{
+		  if (comp_unit_contains_address (each, addr))
+		    return comp_unit_find_nearest_line (each, addr,
+						       filename_ptr,
+						       functionname_ptr,
+						       linenumber_ptr);
+		}
+	      else
+		{
+		  found = comp_unit_find_nearest_line (each, addr,
+						       filename_ptr,
+						       functionname_ptr,
+						       linenumber_ptr);
+		  if (found)
+		    return true;
+		}
 	    }
 	}
     }
diff -urN gas-990404/gas/as.c gas-990404-lia/gas/as.c
--- gas-990404/gas/as.c	Sun Apr  4 01:10:22 1999
+++ gas-990404-lia/gas/as.c	Fri May  7 17:58:39 1999
@@ -365,7 +366,9 @@
 #define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 15)
     {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE},
 #define OPTION_TRADITIONAL_FORMAT (OPTION_STD_BASE + 16)
-    {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT}
+    {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT},
+#define OPTION_GDWARF2 (OPTION_STD_BASE + 17)
+    {"gdwarf2", no_argument, NULL, OPTION_GDWARF2}
   };
 
   /* Construct the option lists from the standard list and the
@@ -546,6 +549,10 @@
 	  debug_type = DEBUG_STABS;
 	  break;
  
+	case OPTION_GDWARF2:
+	  debug_type = DEBUG_DWARF2;
+	  break;
+
 	case 'J':
 	  flag_signed_overflow_ok = 1;
 	  break;
diff -urN gas-990404/gas/as.h gas-990404-lia/gas/as.h
--- gas-990404/gas/as.h	Sun Apr  4 01:10:22 1999
+++ gas-990404-lia/gas/as.h	Fri May  7 17:35:37 1999
@@ -454,7 +454,7 @@
 extern int listing;
 
 /* Type of debugging information we should generate.  We currently
-   only support stabs and ECOFF.  */
+   support stabs, ECOFF, and DWARF2.  */
 
 enum debug_info_type
   {
diff -urN gas-990404/gas/dwarf2dbg.c gas-990404-lia/gas/dwarf2dbg.c
--- gas-990404/gas/dwarf2dbg.c	Wed Dec 31 16:00:00 1969
+++ gas-990404-lia/gas/dwarf2dbg.c	Sat May  8 13:30:29 1999
@@ -0,0 +1,612 @@
+/* dwarf2dbg.c - DWARF2 debug support
+   Copyright (C) 1999 Hewlett-Packard Co
+   Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+   This file is part of GAS, the GNU Assembler.
+
+   GAS 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.
+
+   GAS 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 GAS; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Logical line numbers can be controlled by the compiler via the
+   following two directives:
+
+	.file FILENO "file.c"
+	.loc  FILENO LINENO [COLUMN]
+
+   FILENO is the filenumber.  */
+
+#include "ansidecl.h"
+
+#include "as.h"
+#include "dwarf2dbg.h"
+#include "subsegs.h"
+
+#include <elf/dwarf2.h>
+
+#define BYTES_PER_ADDRESS	(BFD_ARCH_SIZE / 8)
+
+/* Since we can't generate the prolog until the body is complete, we
+   use three different subsegments for .debug_line: one holding the
+   prolog, one for the directory and filename info, and one for the
+   body ("statement program").  */
+#define DL_PROLOG	0
+#define DL_FILES	1
+#define DL_BODY		2
+
+/* First special line opcde - leave room for the standard opcodes.
+   Note: If you want to change this, you'll have to update the
+   "standard_opcode_lengths" table that is emitted below in
+   dwarf2_finish().  */
+#define DWARF2_LINE_OPCODE_BASE		10
+
+#ifndef DWARF2_LINE_BASE
+  /* Minimum line offset in a special line info. opcode.  This value
+     was chosen to give a reasonable range of values.  */
+# define DWARF2_LINE_BASE		-5
+#endif
+
+/* Range of line offsets in a special line info. opcode.  */
+#ifndef DWARF2_LINE_RANGE
+# define DWARF2_LINE_RANGE		14
+#endif
+
+#ifndef DWARF2_LINE_MIN_INSN_LENGTH
+  /* Define the architecture-dependent minimum instruction length (in
+     bytes).  This value should be rather too small than too big.  */
+# define DWARF2_LINE_MIN_INSN_LENGTH	4
+#endif
+
+/* Flag that indicates the initial value of the is_stmt_start flag.
+   In the present implementation, we do not mark any lines as
+   the beginning of a source statement, because that information
+   is not made available by the GCC front-end.  */
+#define	DWARF2_LINE_DEFAULT_IS_STMT	1
+
+/* Flag that indicates the initial value of the is_stmt_start flag.
+   In the present implementation, we do not mark any lines as
+   the beginning of a source statement, because that information
+   is not made available by the GCC front-end.  */
+#define	DWARF2_LINE_DEFAULT_IS_STMT	1
+
+/* Given a special op, return the line skip amount: */
+#define SPECIAL_LINE(op) \
+	(((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE)
+
+/* Given a special op, return the address skip amount (in units of
+   DWARF2_LINE_MIN_INSN_LENGTH.  */
+#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)
+
+/* The maximum address skip amont that can be encoded with a special op: */
+#define MAX_SPECIAL_ADDR_DELTA		SPECIAL_ADDR(255)
+
+static struct
+  {
+    /* state machine state as per DWARF2 manual: */
+    bfd_vma addr;
+    segT text_seg;	/* text segment "addr" is relative to */
+    subsegT text_subseg;
+    unsigned int filenum;
+    unsigned int line;
+    unsigned int column;
+    unsigned int
+      is_stmt : 1,
+      basic_block : 1,
+      any_dwarf2_directives : 1;
+
+    segT line_seg;	/* ".debug_line" segment */
+    int last_filename;	/* index of last filename that was used */
+    int num_filenames;	/* index of last filename in use */
+    int filename_len;	/* length of the filename array */
+    struct
+      {
+	int dir;	/* valid after gen_dir_list() only */
+	char *name; /* full path before gen_dir_list(), filename afterwards */
+      }
+    *file;
+
+    struct dwarf2_line_info current;	/* current source info: */
+
+    /* counters for statistical purposes: */
+    unsigned int num_line_entries;
+    unsigned int opcode_hist[256];	/* histogram of opcode frequencies */
+  }
+ls =
+  {
+    /* initialize as per DWARF2.0 standard: */
+    0,					/* address */
+    NULL,				/* text_seg */
+    0,					/* text_subseg */
+    1,					/* file */
+    1,					/* line */
+    0,					/* column */
+    DWARF2_LINE_DEFAULT_IS_STMT,	/* is_stmt */
+    0,					/* basic_block */
+  };
+
+#define out_byte(byte)	FRAG_APPEND_1_CHAR(byte)
+#define out_opcode(opc)	(out_byte ((opc)), ++ls.opcode_hist[(opc) & 0xff])
+
+/* Output an unsigned "little-endian base 128" number.  */
+static void
+out_uleb128 (bfd_vma value)
+{
+  unsigned char byte, more = 0x80;
+
+  do
+    {
+      byte = value & 0x7f;
+      value >>= 7;
+      if (value == 0)
+	more = 0;
+      out_byte (more | byte);
+    }
+  while (more);
+}
+
+/* Output a signed "little-endian base 128" number.  */
+static void
+out_sleb128 (bfd_signed_vma value)
+{
+  unsigned char byte, more = 0x80;
+
+  do
+    {
+      byte = value & 0x7f;
+      value >>= 7;
+      if (((value == 0) && ((byte & 0x40) == 0))
+	  || ((value == -1) && ((byte & 0x40) != 0)))
+	more = 0;
+      out_byte (more | byte);
+    }
+  while (more);
+}
+
+/* Set an absolute address (may results in a relocation entry): */
+static void
+out_set_addr (bfd_vma addr)
+{
+  subsegT saved_subseg;
+  segT saved_seg;
+  expressionS expr;
+  symbolS *sym;
+
+  saved_seg = now_seg;
+  saved_subseg = now_subseg;
+  subseg_set (ls.text_seg, ls.text_subseg);
+
+  sym = symbol_new (".L0\001", now_seg, addr, frag_now);
+
+  subseg_set (saved_seg, saved_subseg);
+
+  out_opcode (DW_LNS_extended_op);
+  out_uleb128 (BYTES_PER_ADDRESS + 1);
+
+  out_opcode (DW_LNE_set_address);
+  expr.X_op = O_symbol;
+  expr.X_add_symbol = sym;
+  expr.X_add_number = 0;
+  emit_expr (&expr, BYTES_PER_ADDRESS);
+}
+
+/* Look up a filenumber either by filename or by filenumber.  If both
+   a filenumber and a filename are specified, lookup by filename takes
+   precedence.  If the filename cannot be found, it is added to the
+   filetable the filenumber for the new entry is returned.  */
+static int
+get_filenum (int filenum, char *file)
+{
+  int i, last = filenum - 1;
+  char char0 = file[0];
+
+  if ((unsigned) last >= ls.num_filenames)
+    last = ls.last_filename;
+
+  /* do a quick check against the previously used filename: */
+  if (ls.num_filenames > 0 && ls.file[last].name[0] == char0
+      && strcmp (ls.file[last].name + 1, file + 1) == 0)
+    return last + 1;
+
+  /* no match, fall back to simple linear scan: */
+  for (i = 0; i < ls.num_filenames; ++i)
+    {
+      if (ls.file[i].name[0] == char0
+	  && strcmp (ls.file[i].name + 1, file + 1) == 0)
+	{
+	  ls.last_filename = i;
+	  return i + 1;
+	}
+    }
+
+  /* no match: enter new filename */
+  if (ls.num_filenames >= ls.filename_len)
+    {
+      ls.filename_len += 13;
+      ls.file = xrealloc (ls.file, ls.filename_len * sizeof (ls.file[0]));
+    }
+  ls.file[ls.num_filenames].dir = 0;
+  ls.file[ls.num_filenames].name = file;
+  return ++ls.num_filenames;
+}
+
+/* Encode a pair of line and address skips as efficiently as possible.
+   Note that the line skip is signed, whereas the address skip is
+   unsigned.  */
+static void
+gen_addr_line (int line_delta, bfd_vma addr_delta)
+{
+  unsigned int tmp, opcode;
+
+  tmp = line_delta - DWARF2_LINE_BASE;
+
+  if (tmp >= DWARF2_LINE_RANGE)
+    {
+      out_opcode (DW_LNS_advance_line);
+      out_sleb128 (line_delta);
+      tmp = 0 - DWARF2_LINE_BASE;
+      line_delta = 0;
+    }
+
+  tmp += DWARF2_LINE_OPCODE_BASE;
+
+  /* try using a special opcode: */
+  opcode = tmp + addr_delta*DWARF2_LINE_RANGE;
+  if (opcode <= 255)
+    {
+      out_opcode (opcode);
+      return;
+    }
+
+  /* try using DW_LNS_const_add_pc followed by special op: */
+  opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA)*DWARF2_LINE_RANGE;
+  if (opcode <= 255)
+    {
+      out_opcode (DW_LNS_const_add_pc);
+      out_opcode (opcode);
+      return;
+    }
+
+  out_opcode (DW_LNS_advance_pc);
+  out_uleb128 (addr_delta);
+
+  if (line_delta)
+    out_opcode (tmp);		/* output line-delta */
+  else
+    out_opcode (DW_LNS_copy);	/* append new row with current info */
+}
+
+void
+dwarf2_gen_line_info (bfd_vma addr, struct dwarf2_line_info *l)
+{
+  unsigned int filenum = l->filenum;
+  unsigned int any_output = 0;
+  subsegT saved_subseg;
+  segT saved_seg;
+  char *frag;
+
+  if (flag_debug)
+    fprintf (stderr, "line: addr %llx file `%s' line %u col %u flags %lx\n",
+	     (long long) addr, l->filename, l->line, l->column, l->flags);
+
+  if (filenum > 0 && !l->filename)
+    {
+      if (filenum >= ls.num_filenames)
+	{
+	  as_warn ("Encountered bad file number in line number debug info!");
+	  return;
+	}
+    }
+  else if (l->filename)
+    filenum = get_filenum (filenum, l->filename);
+  else
+    return;	/* no filename, no filnum => no play */
+
+  if (!ls.line_seg)
+    {
+      symbolS *secsym;
+
+      ls.line_seg = subseg_get (".debug_line", DL_BODY);
+      bfd_set_section_flags (stdoutput, ls.line_seg, SEC_READONLY);
+      secsym = symbol_find (".debug_line");
+      if (secsym)
+	secsym->bsym = ls.line_seg->symbol;
+      else
+	symbol_table_insert (section_symbol (ls.line_seg));
+    }
+
+  saved_seg = now_seg;
+  saved_subseg = now_subseg;
+  subseg_set (ls.line_seg, DL_BODY);
+
+  if (ls.text_seg != saved_seg || ls.text_subseg != saved_subseg)
+    {
+      any_output = 1;
+      ls.text_seg = saved_seg;
+      ls.text_subseg = saved_subseg;
+      out_set_addr (addr);
+    }
+
+  if (ls.filenum != filenum)
+    {
+      any_output = 1;
+      out_opcode (DW_LNS_set_file);
+      out_uleb128 (filenum);
+      ls.filenum = filenum;
+    }
+
+  if (ls.column != l->column)
+    {
+      any_output = 1;
+      out_opcode (DW_LNS_set_column);
+      out_uleb128 (l->column);
+      ls.column = l->column;
+    }
+
+  if (((l->flags & DWARF2_FLAG_BEGIN_STMT) != 0) != ls.is_stmt)
+    {
+      any_output = 1;
+      out_opcode (DW_LNS_negate_stmt);
+    }
+
+  if (l->flags & DWARF2_FLAG_BEGIN_BLOCK)
+    {
+      any_output = 1;
+      out_opcode (DW_LNS_set_basic_block);
+    }
+
+  if (ls.line != l->line)
+    {
+      any_output = 1;
+      if (addr < ls.addr)
+	{
+	  out_set_addr (addr);
+	  ls.addr = addr;
+	}
+      gen_addr_line (l->line - ls.line,
+		     (addr - ls.addr) / DWARF2_LINE_MIN_INSN_LENGTH);
+      ls.basic_block = 0;
+      ls.line = l->line;
+      ls.addr = addr;
+    }
+
+  subseg_set (saved_seg, saved_subseg);
+
+  ls.num_line_entries += any_output;
+}
+
+static void
+gen_dir_list (void)
+{
+  char *str, *slash, *dir_list, *dp, *cp;
+  int i, j, num_dirs;
+
+  dir_list = frag_more (0);
+  num_dirs = 0;
+
+  for (i = 0; i < ls.num_filenames; ++i)
+    {
+      str = ls.file[i].name;
+      slash = strrchr (str, '/');
+      if (slash)
+	{
+	  *slash = '\0';
+	  for (j = 0, dp = dir_list; j < num_dirs; ++j)
+	    {
+	      if (strcmp (str, dp) == 0)
+		{
+		  ls.file[i].dir = j;
+		  break;
+		}
+	      dp += strlen (dp);
+	    }
+	  if (j >= num_dirs)
+	    {
+	      /* didn't find this directory: append it to the list */
+	      size_t size = strlen (str) + 1;
+	      cp = frag_more (size);
+	      memcpy (cp, str, size);
+	      ls.file[i].dir = ++num_dirs;
+	    }
+	  *slash = '/';
+	  ls.file[i].name = slash + 1;
+	}
+    }
+  out_byte ('\0');	/* terminate directory list */
+}
+
+static void
+gen_file_list (void)
+{
+  size_t size;
+  char *cp;
+  int i;
+
+  for (i = 0; i < ls.num_filenames; ++i)
+    {
+      size = strlen (ls.file[i].name) + 1;
+      cp = frag_more (size);
+      memcpy (cp, ls.file[i].name, size);
+
+      out_uleb128 (ls.file[i].dir);	/* directory number */
+      out_uleb128 (0);			/* last modification timestamp */
+      out_uleb128 (0);			/* filesize */
+    }
+  out_byte (0);		/* terminate filename list */
+}
+
+void
+print_stats (unsigned long total_size)
+{
+  static const char *opc_name[] =
+    {
+      "extended", "copy", "advance_pc", "advance_line", "set_file",
+      "set_column", "negate_stmt", "set_basic_block", "const_add_pc",
+      "fixed_advance_pc"
+    };
+  int i, j;
+
+  fprintf (stderr, "Average size: %g bytes/line\n",
+	   total_size / (double) ls.num_line_entries);
+
+  fprintf (stderr, "\nStandard opcode histogram:\n");
+
+  for (i = 0; i < sizeof (opc_name)/sizeof (opc_name[0]); ++i)
+    {
+      fprintf (stderr, "%s", opc_name[i]);
+      for (j = strlen (opc_name[i]); j < 16; ++j)
+	fprintf (stderr, " ");
+      fprintf (stderr, ": %u\n", ls.opcode_hist[i]);
+    }
+
+  fprintf (stderr, "\nSpecial opcodes:\naddr\t\t\t\tline skip\n");
+
+  fprintf (stderr, "skip: ");
+  for (j = DWARF2_LINE_BASE; j < DWARF2_LINE_BASE + DWARF2_LINE_RANGE; ++j)
+    fprintf (stderr, "%3d", j);
+  fprintf (stderr, "\n-----");
+
+  for (; i < 256; ++i)
+    {
+      j = SPECIAL_LINE (i);
+      if (j == DWARF2_LINE_BASE)
+	fprintf (stderr, "\n%4u: ",
+		 DWARF2_LINE_MIN_INSN_LENGTH*SPECIAL_ADDR (i));
+      fprintf (stderr, " %2u", ls.opcode_hist[i]);
+    }
+  fprintf (stderr, "\n");
+}
+
+void
+dwarf2_finish (void)
+{
+  bfd_vma addr, body_size, total_size, prolog_size;
+  subsegT saved_subseg, line_prolog;
+  segT saved_seg;
+  char *cp;
+
+  if (!ls.line_seg)
+    /* no .debug_line segment, no work to do... */
+    return;
+
+  saved_seg = now_seg;
+  saved_subseg = now_subseg;
+
+  /* end .debug_line with end_sequence: */
+  if (ls.text_seg)
+    {
+      subseg_set (ls.text_seg, ls.text_subseg);
+      addr = frag_now_fix ();
+      subseg_set (ls.line_seg, DL_BODY);
+      gen_addr_line (0, (addr - ls.addr) / DWARF2_LINE_MIN_INSN_LENGTH);
+    }
+  subseg_set (ls.line_seg, DL_BODY);
+  out_opcode (DW_LNS_extended_op);
+  out_uleb128 (1);
+  out_byte (DW_LNE_end_sequence);
+  total_size = body_size = frag_now_fix ();
+
+  /* now generate the directory and file lists: */
+  subseg_set (ls.line_seg, DL_FILES);
+  gen_dir_list ();
+  gen_file_list ();
+  total_size += frag_now_fix ();
+
+  /* and now the header ("statement program prolog", in DWARF2 lingo...) */
+  subseg_set (ls.line_seg, DL_PROLOG);
+
+  cp = frag_more (15 + DWARF2_LINE_OPCODE_BASE - 1);
+
+  total_size += frag_now_fix ();
+  prolog_size = total_size - body_size - 10;
+
+# define STUFF(val,size)	md_number_to_chars (cp, val, size); cp += size;
+  STUFF (total_size - 4, 4);	/* length */
+  STUFF (2, 2);			/* version */
+  STUFF (prolog_size, 4);	/* prologue_length */
+  STUFF (DWARF2_LINE_MIN_INSN_LENGTH, 1);
+  STUFF (DWARF2_LINE_DEFAULT_IS_STMT, 1);
+  STUFF (DWARF2_LINE_BASE, 1);
+  STUFF (DWARF2_LINE_RANGE, 1);
+  STUFF (DWARF2_LINE_OPCODE_BASE, 1);
+
+  /* standard_opcode_lengths: */
+  STUFF (0, 1);			/* DW_LNS_copy */
+  STUFF (1, 1);			/* DW_LNS_advance_pc */
+  STUFF (1, 1);			/* DW_LNS_advance_line */
+  STUFF (1, 1);			/* DW_LNS_set_file */
+  STUFF (1, 1);			/* DW_LNS_set_column */
+  STUFF (0, 1);			/* DW_LNS_negate_stmt */
+  STUFF (0, 1);			/* DW_LNS_set_basic_block */
+  STUFF (0, 1);			/* DW_LNS_const_add_pc */
+  STUFF (1, 1);			/* DW_LNS_fixed_advance_pc */
+
+  subseg_set (saved_seg, saved_subseg);
+
+  if (flag_debug)
+    print_stats (total_size);
+}
+
+void
+dwarf2_directive_file (int dummy)
+{
+  int len;
+
+  ls.any_dwarf2_directives = 1;
+
+  if (debug_type == DEBUG_NONE)
+    /* Automatically turn on DWARF2 debug info unless something else
+       has been selected.  */
+    debug_type = DEBUG_DWARF2;
+
+  ls.current.filenum = get_absolute_expression ();
+  ls.current.filename = demand_copy_C_string (&len);
+
+  demand_empty_rest_of_line ();
+}
+
+void
+dwarf2_directive_loc (int dummy)
+{
+  ls.any_dwarf2_directives = 1;
+
+  ls.current.filenum = get_absolute_expression ();
+  SKIP_WHITESPACE ();
+  ls.current.line = get_absolute_expression ();
+  SKIP_WHITESPACE ();
+  ls.current.column = get_absolute_expression ();
+  demand_empty_rest_of_line ();
+
+  ls.current.flags = DWARF2_FLAG_BEGIN_STMT;
+
+#ifndef NO_LISTING
+  if (listing)
+    listing_source_line (ls.current.line);
+#endif
+}
+
+void
+dwarf2_where (struct dwarf2_line_info *line)
+{
+  if (ls.any_dwarf2_directives)
+    *line = ls.current;
+  else
+    {
+      char *filename;
+
+      as_where (&line->filename, &line->line);
+      line->filenum = 0;
+      line->column = 0;
+      line->flags = DWARF2_FLAG_BEGIN_STMT;
+    }
+}
diff -urN gas-990404/gas/dwarf2dbg.h gas-990404-lia/gas/dwarf2dbg.h
--- gas-990404/gas/dwarf2dbg.h	Wed Dec 31 16:00:00 1969
+++ gas-990404-lia/gas/dwarf2dbg.h	Sat May  8 10:27:15 1999
@@ -0,0 +1,48 @@
+#ifndef AS_DWARF2DBG_H
+#define AS_DWARF2DBG_H
+
+#include "as.h"
+
+#define DWARF2_FLAG_BEGIN_STMT	(1 << 0)	/* beginning of statement */
+#define DWARF2_FLAG_BEGIN_BLOCK	(1 << 1)	/* beginning of basic block */
+
+struct dwarf2_line_info
+  {
+    char *filename;
+    unsigned int filenum;
+    unsigned int line;
+    unsigned int column;
+    unsigned int flags;
+  };
+
+/* Implements the .file FILENO "FILENAME" directive.  FILENO can be 0
+   to indicate that no file number has been assigned.  All real file
+   number must be >0.  */
+extern void dwarf2_directive_file (int dummy);
+
+/* Implements the .loc FILENO LINENO [COLUMN] directive.  FILENO is
+   the file number, LINENO the line number and the (optional) COLUMN
+   the column of the source code that the following instruction
+   corresponds to.  FILENO can be 0 to indicate that the filename
+   specified by the textually most recent .file directive should be
+   used.  */
+extern void dwarf2_directive_loc (int dummy);
+
+/* Returns the current source information.  If .file directives have
+   been encountered, the info for the corresponding source file is
+   returned.  Otherwise, the info for the assembly source file is
+   returned.  */
+extern void dwarf2_where (struct dwarf2_line_info *l);
+
+/* This function generates .debug_line info based on the address and
+   source information passed in the arguments.  ADDR should be the
+   frag-relative offset of the instruction the information is for and
+   L is the source information that should be associated with that
+   address. */
+extern void dwarf2_gen_line_info (bfd_vma addr, struct dwarf2_line_info *l);
+
+/* Must be called after all other input is processed to finish up the
+   .debug_line section.  */
+extern void dwarf2_finish (void);
+
+#endif /* AS_DWARF2DBG_H */
--- egcs-1.1.2/gcc/dwarf2out.c	Thu Jul 30 05:52:18 1998
+++ egcs-1.1.2-lia/gcc/dwarf2out.c	Fri May  7 15:04:30 1999
@@ -2450,7 +2450,9 @@
 					       dw_loc_descr_ref));
 static void print_spaces		PROTO((FILE *));
 static void print_die			PROTO((dw_die_ref, FILE *));
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
 static void print_dwarf_line_table	PROTO((FILE *));
+#endif
 static void add_sibling_attributes	PROTO((dw_die_ref));
 static void build_abbrev_table		PROTO((dw_die_ref));
 static unsigned long size_of_string	PROTO((char *));
@@ -2459,8 +2461,10 @@
 static int constant_size		PROTO((long unsigned));
 static unsigned long size_of_die	PROTO((dw_die_ref));
 static void calc_die_sizes		PROTO((dw_die_ref));
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
 static unsigned long size_of_line_prolog	PROTO((void));
 static unsigned long size_of_line_info	PROTO((void));
+#endif
 static unsigned long size_of_pubnames	PROTO((void));
 static unsigned long size_of_aranges	PROTO((void));
 static enum dwarf_form value_format	PROTO((dw_val_ref));
@@ -2475,7 +2479,9 @@
 static void output_pubnames		PROTO((void));
 static void add_arange			PROTO((tree, dw_die_ref));
 static void output_aranges		PROTO((void));
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
 static void output_line_info		PROTO((void));
+#endif
 static int is_body_block		PROTO((tree));
 static dw_die_ref base_type_die		PROTO((tree));
 static tree root_type			PROTO((tree));
@@ -4308,6 +4321,8 @@
     }
 }
 
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
+
 /* Print the contents of the source code line number correspondence table.
    This routine is a debugging aid only.  */
 
@@ -4331,6 +4346,8 @@
   fprintf (outfile, "\n\n");
 }
 
+#endif /* ASM_DWARF2_LINE_DEBUG_INFO */
+
 /* Print the information collected for a given DIE.  */
 
 void
@@ -4348,7 +4365,9 @@
 {
   print_indent = 0;
   print_die (comp_unit_die, stderr);
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
   print_dwarf_line_table (stderr);
+#endif
 }
 
 /* Traverse the DIE, and add a sibling attribute if it may have the
@@ -4684,6 +4703,8 @@
     next_die_offset += 1;
 }
 
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
+
 /* Return the size of the line information prolog generated for the
    compilation unit.  */
 
@@ -4875,6 +4896,8 @@
   return size;
 }
 
+#endif /* ASM_DWARF2_LINE_DEBUG_INFO */
+
 /* Return the size of the .debug_pubnames table  generated for the
    compilation unit.  */
 
@@ -5625,6 +5648,8 @@
   fputc ('\n', asm_out_file);
 }
 
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
+
 /* Output the source line number correspondence information.  This
    information goes into the .debug_line section.
 
@@ -6072,6 +6097,7 @@
 	}
     }
 }
+#endif /* ASM_DWARF2_LINE_DEBUG_INFO */
 
 /* Given a pointer to a BLOCK node return non-zero if (and only if) the node
    in question represents the outermost pair of curly braces (i.e. the "body
@@ -9612,6 +9638,11 @@
 {
   if (debug_info_level >= DINFO_LEVEL_NORMAL)
     {
+#ifdef ASM_DWARF2_LINE_DEBUG_INFO
+      ++line_info_table_in_use;
+      fprintf (asm_out_file, "\t.file 0 \"%s\"; .loc 0 %u 0\n",
+	       filename, line);
+#else
       function_section (current_function_decl);
 
       if (DECL_SECTION_NAME (current_function_decl))
@@ -9664,6 +9695,7 @@
 	  line_info->dw_file_num = lookup_filename (filename);
 	  line_info->dw_line_num = line;
 	}
+#endif /* !ASM_DWARF2_LINE_DEBUG_INFO */
     }
 }
 
@@ -9831,6 +9863,7 @@
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
 #endif
 
+#ifndef ASM_DWARF2_LINE_DEBUG_INFO
   /* Output the source line correspondence table.  */
   if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
     {
@@ -9848,6 +9881,12 @@
 
       add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION);
     }
+#else
+  /* line_info_table_in_use > 1 => at least one.file/.loc pair has
+     been generated */
+  if (line_info_table_in_use > 1)
+    add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION);
+#endif /* ASM_DWARF2_LINE_DEBUG_INFO */
 
   /* Output the abbreviation table.  */
   fputc ('\n', asm_out_file);

----- End forwarded message -----


More information about the Gas2 mailing list