This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils 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]

RFC: PR 990: "nm -l" doesn't work well on relocatable files


_bfd_dwarf2_find_nearest_line only works on functions in executable. It
doesn't work on symbols nor relocatable files where multiple functons
can have the same address in different sections. This patch introduces
_bfd_dwarf2_find_line for finding location for symbols. It may not
handle all cases, e.g., local symbols with the same name in different
files may have the same address in a relocatable file generated by
"ld -r".


H.J.
----
bfd/

2005-06-05  H.J. Lu  <hongjiu.lu@intel.com>

	PR 990
	* bfd.c (bfd_find_line): New.

	* dwarf2.c (comp_unit): Add variable_table.
	(funcinfo): Add file and line.
	(varinfo): New.
	(lookup_symbol_in_function_table): New.
	(lookup_symbol_in_variable_table): New.
	(scan_unit_for_functions): Renamed to ...
	(scan_unit_for_symbols): This. Handle DW_TAG_entry_point and
	DW_TAG_variable.
	(comp_unit_find_nearest_line): Updated.
	(comp_unit_find_line): New.
	(_bfd_dwarf2_find_line): New.

	* elf-bfd.h (_bfd_elf_find_line): New.
	(_bfd_generic_find_line): New. Defined.

	* elf.c (_bfd_elf_find_line): New.

	* libbfd-in.h (_bfd_dwarf2_find_line): New.
	(_bfd_generic_find_line): New.

	* bfd-in2.h: Regenerated.
	* libbfd.h: Likewise.

	* libbfd.c (_bfd_generic_find_line): New.

	* targets.c (BFD_JUMP_TABLE_SYMBOLS): Initialize _bfd_find_line
	with _bfd_generic_find_line.
	(bfd_target): Add _bfd_find_line.

binutils/

2005-06-05  H.J. Lu  <hongjiu.lu@intel.com>

	PR 990
	* nm.c (print_symbol): Call bfd_find_line before
	bfd_find_nearest_line.

--- binutils/bfd/bfd.c.line	2005-06-05 11:12:28.000000000 -0700
+++ binutils/bfd/bfd.c	2005-06-05 11:12:29.000000000 -0700
@@ -1161,6 +1161,10 @@ DESCRIPTION
 .       BFD_SEND (abfd, _bfd_find_nearest_line, \
 .                 (abfd, sec, syms, off, file, func, line))
 .
+.#define bfd_find_line(abfd, syms, sym, file, line) \
+.       BFD_SEND (abfd, _bfd_find_line, \
+.                 (abfd, syms, sym, file, line))
+.
 .#define bfd_find_inliner_info(abfd, file, func, line) \
 .       BFD_SEND (abfd, _bfd_find_inliner_info, \
 .                 (abfd, file, func, line))
--- binutils/bfd/dwarf2.c.line	2005-06-05 11:12:29.000000000 -0700
+++ binutils/bfd/dwarf2.c	2005-06-05 11:33:31.000000000 -0700
@@ -182,6 +182,9 @@ struct comp_unit
   /* A list of the functions found in this comp. unit.  */
   struct funcinfo *function_table;
 
+  /* A list of the variables found in this comp. unit.  */
+  struct varinfo *variable_table;
+
   /* Pointer to dwarf2_debug structure.  */
   struct dwarf2_debug *stash;
 
@@ -697,12 +700,31 @@ struct funcinfo
   struct funcinfo *caller_func;		/* Pointer to function one scope higher */
   char *caller_file;			/* Source location file name where caller_func inlines this func */
   int caller_line;			/* Source location line number where caller_func inlines this func */
+  /* Source location file name */
+  char *file;
+  /* Source location line number */
+  int line;
   int tag;
   int nesting_level;
   char *name;
   struct arange arange;
 };
 
+struct varinfo
+{
+  /* Pointer to previous variable in list of all variables */
+  struct varinfo *prev_var;
+  /* Source location file name */
+  char *file;
+  /* Source location line number */
+  int line;
+  int tag;
+  char *name;
+  unsigned int global: 1;
+  /* Is this a stack variable.  */
+  unsigned int stack: 1;
+};
+
 /* Adds a new entry to the line_info list in the line_info_table, ensuring
    that the list is sorted.  Note that the line_info list is sorted from
    highest to lowest VMA (with possible duplicates); that is,
@@ -1424,6 +1446,78 @@ lookup_address_in_function_table (struct
     }
 }
 
+/* If SYM at ADDR is within function table of UNIT, set FILENAME_PTR
+   and LINENUMBER_PTR, and return TRUE. */
+
+static bfd_boolean
+lookup_symbol_in_function_table (struct comp_unit *unit,
+				 asymbol *sym,
+				 bfd_vma addr,
+				 const char **filename_ptr,
+				 unsigned int *linenumber_ptr)
+{
+  struct funcinfo* each_func;
+  struct funcinfo* best_fit = NULL;
+  struct arange *arange;
+  const char *name = bfd_asymbol_name (sym);
+
+  for (each_func = unit->function_table;
+       each_func;
+       each_func = each_func->prev_func)
+    {
+      for (arange = &each_func->arange;
+	   arange;
+	   arange = arange->next)
+	{
+	  if (addr >= arange->low
+	      && addr < arange->high
+	      && strcmp (name, each_func->name) == 0)
+	    {
+	      if (!best_fit ||
+		  ((arange->high - arange->low) < (best_fit->arange.high - best_fit->arange.low)))
+		best_fit = each_func;
+	    }
+	}
+    }
+
+  if (best_fit)
+    {
+      *filename_ptr = best_fit->file;
+      *linenumber_ptr = best_fit->line;
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/* Variable table functions.  */
+
+/* If SYM is within variable table of UNIT, set FILENAME_PTR and
+   LINENUMBER_PTR, and return TRUE. */
+
+static bfd_boolean
+lookup_symbol_in_variable_table (struct comp_unit *unit,
+				 asymbol *sym,
+				 const char **filename_ptr,
+				 unsigned int *linenumber_ptr)
+{
+  const char *name = bfd_asymbol_name (sym);
+  struct varinfo* each;
+
+  for (each = unit->variable_table; each; each = each->prev_var)
+    if (each->stack == 0 && strcmp (name, each->name) == 0)
+      break;
+
+  if (each)
+    {
+      *filename_ptr = each->file;
+      *linenumber_ptr = each->line;
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
 static char *
 find_abstract_instance_name (struct comp_unit *unit, bfd_uint64_t die_ref)
 {
@@ -1513,10 +1607,10 @@ read_rangelist (struct comp_unit *unit, 
 /* DWARF2 Compilation unit functions.  */
 
 /* Scan over each die in a comp. unit looking for functions to add
-   to the function table.  */
+   to the function table and variables to the variable table.  */
 
 static bfd_boolean
-scan_unit_for_functions (struct comp_unit *unit)
+scan_unit_for_symbols (struct comp_unit *unit)
 {
   bfd *abfd = unit->abfd;
   bfd_byte *info_ptr = unit->first_child_die_ptr;
@@ -1528,6 +1622,7 @@ scan_unit_for_functions (struct comp_uni
       struct abbrev_info *abbrev;
       struct attribute attr;
       struct funcinfo *func;
+      struct varinfo *var;
       bfd_vma low_pc = 0;
       bfd_vma high_pc = 0;
 
@@ -1549,7 +1644,9 @@ scan_unit_for_functions (struct comp_uni
 	  return FALSE;
 	}
 
+      var = NULL;
       if (abbrev->tag == DW_TAG_subprogram
+	  || abbrev->tag == DW_TAG_entry_point
 	  || abbrev->tag == DW_TAG_inlined_subroutine)
 	{
 	  bfd_size_type amt = sizeof (struct funcinfo);
@@ -1560,7 +1657,18 @@ scan_unit_for_functions (struct comp_uni
 	  unit->function_table = func;
 	}
       else
-	func = NULL;
+	{
+	  func = NULL;
+	  if (abbrev->tag == DW_TAG_variable)
+	    {
+	      bfd_size_type amt = sizeof (struct varinfo);
+	      var = bfd_zalloc (abfd, amt);
+	      var->tag = abbrev->tag;
+	      var->stack = 1;
+	      var->prev_var = unit->variable_table;
+	      unit->variable_table = var;
+	    }
+	}
 
       for (i = 0; i < abbrev->num_attrs; ++i)
 	{
@@ -1604,6 +1712,63 @@ scan_unit_for_functions (struct comp_uni
 		  read_rangelist (unit, &func->arange, attr.u.val);
 		  break;
 
+		case DW_AT_decl_file:
+		  func->file = concat_filename (unit->line_table,
+						attr.u.val);
+		  break;
+
+		case DW_AT_decl_line:
+		  func->line = attr.u.val;
+		  break;
+
+		default:
+		  break;
+		}
+	    }
+	  else if (var)
+	    {
+	      switch (attr.name)
+		{
+		case DW_AT_name:
+		  var->name = attr.u.str;
+		  break;
+
+		case DW_AT_decl_file:
+		  var->file = concat_filename (unit->line_table,
+					       attr.u.val);
+		  break;
+
+		case DW_AT_decl_line:
+		  var->line = attr.u.val;
+		  break;
+
+		case DW_AT_external:
+		  if (attr.u.val != 0)
+		    {
+		      var->global = 1;
+		      var->stack = 0;
+		    }
+		  break;
+
+		case DW_AT_location:
+		  if (!var->global && var->stack)
+		    {
+		      switch (attr.form)
+			{
+			case DW_FORM_block:
+			case DW_FORM_block1:
+			case DW_FORM_block2:
+			case DW_FORM_block4:
+			  if (*attr.u.blk->data == DW_OP_addr)
+			    var->stack = 0;
+			  break;
+
+			default:
+			  break;
+			}
+		    }
+		  break;
+
 		default:
 		  break;
 		}
@@ -1844,7 +2009,7 @@ comp_unit_find_nearest_line (struct comp
 	}
 
       if (unit->first_child_die_ptr < unit->end_ptr
-	  && ! scan_unit_for_functions (unit))
+	  && ! scan_unit_for_symbols (unit))
 	{
 	  unit->error = 1;
 	  return FALSE;
@@ -1862,6 +2027,58 @@ comp_unit_find_nearest_line (struct comp
   return line_p || func_p;
 }
 
+/* If UNIT contains SYM at ADDR, set the output parameters to the
+   values for the line containing SYM.  The output parameters,
+   FILENAME_PTR, and LINENUMBER_PTR, are pointers to the objects to be
+   filled in.
+
+   Return TRUE if UNIT contains SYM, and no errors were encountered;
+   FALSE otherwise.  */
+
+static bfd_boolean
+comp_unit_find_line (struct comp_unit *unit,
+		     asymbol *sym,
+		     bfd_vma addr,
+		     const char **filename_ptr,
+		     unsigned int *linenumber_ptr,
+		     struct dwarf2_debug *stash)
+{
+  if (unit->error)
+    return FALSE;
+
+  if (! unit->line_table)
+    {
+      if (! unit->stmtlist)
+	{
+	  unit->error = 1;
+	  return FALSE;
+	}
+
+      unit->line_table = decode_line_info (unit, stash);
+
+      if (! unit->line_table)
+	{
+	  unit->error = 1;
+	  return FALSE;
+	}
+
+      if (unit->first_child_die_ptr < unit->end_ptr
+	  && ! scan_unit_for_symbols (unit))
+	{
+	  unit->error = 1;
+	  return FALSE;
+	}
+    }
+
+  if (sym->flags & BSF_FUNCTION)
+    return lookup_symbol_in_function_table (unit, sym, addr,
+					    filename_ptr,
+					    linenumber_ptr);
+  else
+    return lookup_symbol_in_variable_table (unit, sym, filename_ptr,
+					    linenumber_ptr);
+}
+
 /* Locate a section in a BFD containing debugging info.  The search starts
    from the section after AFTER_SEC, or from the first section in the BFD if
    AFTER_SEC is NULL.  The search works by examining the names of the
@@ -2107,6 +2324,210 @@ _bfd_dwarf2_find_nearest_line (bfd *abfd
   return FALSE;
 }
 
+/* The DWARF2 version of find_line.  Return TRUE if the line is found
+   without error.  */
+
+bfd_boolean
+_bfd_dwarf2_find_line (bfd *abfd,
+		       asymbol **symbols,
+		       asymbol *symbol,
+		       const char **filename_ptr,
+		       unsigned int *linenumber_ptr,
+		       unsigned int addr_size,
+		       void **pinfo)
+{
+  /* Read each compilation unit from the section .debug_info, and check
+     to see if it contains the address we are searching for.  If yes,
+     lookup the address, and return the line number info.  If no, go
+     on to the next compilation unit.
+
+     We keep a list of all the previously read compilation units, and
+     a pointer to the next un-read compilation unit.  Check the
+     previously read units before reading more.  */
+  struct dwarf2_debug *stash;
+
+  /* What address are we looking for?  */
+  bfd_vma addr;
+
+  struct comp_unit* each;
+
+  asection *section;
+
+  bfd_boolean found;
+
+  section = bfd_get_section (symbol);
+
+  addr = symbol->value;
+  if (section->output_section)
+    addr += section->output_section->vma + section->output_offset;
+  else
+    addr += section->vma;
+
+  *filename_ptr = NULL;
+  stash = *pinfo;
+  *filename_ptr = NULL;
+  *linenumber_ptr = 0;
+
+  if (! stash)
+    {
+      bfd_size_type total_size;
+      asection *msec;
+      bfd_size_type amt = sizeof (struct dwarf2_debug);
+
+      stash = bfd_zalloc (abfd, amt);
+      if (! stash)
+	return FALSE;
+
+      *pinfo = stash;
+
+      msec = find_debug_info (abfd, NULL);
+      if (! msec)
+	/* No dwarf2 info.  Note that at this point the stash
+	   has been allocated, but contains zeros, this lets
+	   future calls to this function fail quicker.  */
+	 return FALSE;
+
+      /* There can be more than one DWARF2 info section in a BFD these days.
+	 Read them all in and produce one large stash.  We do this in two
+	 passes - in the first pass we just accumulate the section sizes.
+	 In the second pass we read in the section's contents.  The allows
+	 us to avoid reallocing the data as we add sections to the stash.  */
+      for (total_size = 0; msec; msec = find_debug_info (abfd, msec))
+	total_size += msec->size;
+
+      stash->info_ptr = bfd_alloc (abfd, total_size);
+      if (stash->info_ptr == NULL)
+	return FALSE;
+
+      stash->info_ptr_end = stash->info_ptr;
+
+      for (msec = find_debug_info (abfd, NULL);
+	   msec;
+	   msec = find_debug_info (abfd, msec))
+	{
+	  bfd_size_type size;
+	  bfd_size_type start;
+
+	  size = msec->size;
+	  if (size == 0)
+	    continue;
+
+	  start = stash->info_ptr_end - stash->info_ptr;
+
+	  if ((bfd_simple_get_relocated_section_contents
+	       (abfd, msec, stash->info_ptr + start, symbols)) == NULL)
+	    continue;
+
+	  stash->info_ptr_end = stash->info_ptr + start + size;
+	}
+
+      BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size);
+
+      stash->sec = find_debug_info (abfd, NULL);
+      stash->sec_info_ptr = stash->info_ptr;
+      stash->syms = symbols;
+    }
+
+  /* A null info_ptr indicates that there is no dwarf2 info
+     (or that an error occured while setting up the stash).  */
+  if (! stash->info_ptr)
+    return FALSE;
+
+  stash->inliner_chain = NULL;
+
+  /* Check the previously read comp. units first.  */
+  for (each = stash->all_comp_units; each; each = each->next_unit)
+    if ((symbol->flags & BSF_FUNCTION) == 0
+	|| comp_unit_contains_address (each, addr))
+      {
+	found = comp_unit_find_line (each, symbol, addr, filename_ptr,
+				     linenumber_ptr, stash);
+	if (found)
+	  return found;
+      }
+
+  /* The DWARF2 spec says that the initial length field, and the
+     offset of the abbreviation table, should both be 4-byte values.
+     However, some compilers do things differently.  */
+  if (addr_size == 0)
+    addr_size = 4;
+  BFD_ASSERT (addr_size == 4 || addr_size == 8);
+
+  /* Read each remaining comp. units checking each as they are read.  */
+  while (stash->info_ptr < stash->info_ptr_end)
+    {
+      bfd_vma length;
+      unsigned int offset_size = addr_size;
+      bfd_byte *info_ptr_unit = stash->info_ptr;
+
+      length = read_4_bytes (abfd, stash->info_ptr);
+      /* A 0xffffff length is the DWARF3 way of indicating we use
+	 64-bit offsets, instead of 32-bit offsets.  */
+      if (length == 0xffffffff)
+	{
+	  offset_size = 8;
+	  length = read_8_bytes (abfd, stash->info_ptr + 4);
+	  stash->info_ptr += 12;
+	}
+      /* A zero length is the IRIX way of indicating 64-bit offsets,
+	 mostly because the 64-bit length will generally fit in 32
+	 bits, and the endianness helps.  */
+      else if (length == 0)
+	{
+	  offset_size = 8;
+	  length = read_4_bytes (abfd, stash->info_ptr + 4);
+	  stash->info_ptr += 8;
+	}
+      /* In the absence of the hints above, we assume addr_size-sized
+	 offsets, for backward-compatibility with pre-DWARF3 64-bit
+	 platforms.  */
+      else if (addr_size == 8)
+	{
+	  length = read_8_bytes (abfd, stash->info_ptr);
+	  stash->info_ptr += 8;
+	}
+      else
+	stash->info_ptr += 4;
+
+      if (length > 0)
+	{
+	  each = parse_comp_unit (abfd, stash, length, info_ptr_unit,
+				  offset_size);
+	  stash->info_ptr += length;
+
+	  if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr)
+	      == stash->sec->size)
+	    {
+	      stash->sec = find_debug_info (abfd, stash->sec);
+	      stash->sec_info_ptr = stash->info_ptr;
+	    }
+
+	  if (each)
+	    {
+	      each->next_unit = stash->all_comp_units;
+	      stash->all_comp_units = each;
+
+	      /* 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.  */
+	      found = (((symbol->flags & BSF_FUNCTION) == 0
+			|| each->arange.high <= 0
+			|| comp_unit_contains_address (each, addr))
+		       && comp_unit_find_line (each, symbol, addr,
+					       filename_ptr,
+					       linenumber_ptr,
+					       stash));
+	      if (found)
+		return TRUE;
+	    }
+	}
+    }
+
+  return FALSE;
+}
+
 bfd_boolean
 _bfd_dwarf2_find_inliner_info (bfd *abfd ATTRIBUTE_UNUSED,
 			       const char **filename_ptr,
--- binutils/bfd/elf-bfd.h.line	2005-06-05 11:12:28.000000000 -0700
+++ binutils/bfd/elf-bfd.h	2005-06-05 11:12:29.000000000 -0700
@@ -1500,6 +1500,9 @@ extern bfd_boolean _bfd_elf_set_arch_mac
 extern bfd_boolean _bfd_elf_find_nearest_line
   (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **,
    unsigned int *);
+extern bfd_boolean _bfd_elf_find_line
+  (bfd *, asymbol **, asymbol *, const char **, unsigned int *);
+#define _bfd_generic_find_line _bfd_elf_find_line
 extern bfd_boolean _bfd_elf_find_inliner_info
   (bfd *, const char **, const char **, unsigned int *);
 #define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols
--- binutils/bfd/elf.c.line	2005-06-05 11:12:28.000000000 -0700
+++ binutils/bfd/elf.c	2005-06-05 11:12:29.000000000 -0700
@@ -6675,6 +6675,17 @@ _bfd_elf_find_nearest_line (bfd *abfd,
   return TRUE;
 }
 
+/* Find the line for a symbol.  */
+
+bfd_boolean
+_bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol,
+		    const char **filename_ptr, unsigned int *line_ptr)
+{
+  return _bfd_dwarf2_find_line (abfd, symbols, symbol,
+				filename_ptr, line_ptr, 0,
+				&elf_tdata (abfd)->dwarf2_find_line_info);
+}
+
 /* After a call to bfd_find_nearest_line, successive calls to
    bfd_find_inliner_info can be used to get source information about
    each level of function inlining that terminated at the address
--- binutils/bfd/libbfd-in.h.line	2005-05-24 07:13:20.000000000 -0700
+++ binutils/bfd/libbfd-in.h	2005-06-05 11:12:29.000000000 -0700
@@ -428,6 +428,14 @@ extern bfd_boolean _bfd_dwarf2_find_near
   (bfd *, asection *, asymbol **, bfd_vma, const char **, const char **,
    unsigned int *, unsigned int, void **);
 
+/* Find the line using DWARF 2 debugging information.  */
+extern bfd_boolean _bfd_dwarf2_find_line
+  (bfd *, asymbol **, asymbol *, const char **,
+   unsigned int *, unsigned int, void **);
+
+bfd_boolean _bfd_generic_find_line
+  (bfd *, asymbol **, asymbol *, const char **, unsigned int *);
+
 /* Find inliner info after calling bfd_find_nearest_line. */
 extern bfd_boolean _bfd_dwarf2_find_inliner_info
   (bfd *, const char **, const char **, unsigned int *, void **);
--- binutils/bfd/libbfd.c.line	2005-05-05 09:07:02.000000000 -0700
+++ binutils/bfd/libbfd.c	2005-06-05 11:12:29.000000000 -0700
@@ -918,3 +918,13 @@ read_signed_leb128 (bfd *abfd ATTRIBUTE_
   *bytes_read_ptr = num_read;
   return result;
 }
+
+bfd_boolean
+_bfd_generic_find_line (bfd *abfd ATTRIBUTE_UNUSED,
+		       asymbol **symbols ATTRIBUTE_UNUSED,
+		       asymbol *symbol ATTRIBUTE_UNUSED,
+		       const char **filename_ptr ATTRIBUTE_UNUSED,
+		       unsigned int *linenumber_ptr ATTRIBUTE_UNUSED)
+{
+  return FALSE;
+}
--- binutils/bfd/targets.c.line	2005-05-24 07:13:21.000000000 -0700
+++ binutils/bfd/targets.c	2005-06-05 11:12:29.000000000 -0700
@@ -349,6 +349,7 @@ BFD_JUMP_TABLE macros.
 .  NAME##_bfd_is_target_special_symbol, \
 .  NAME##_get_lineno, \
 .  NAME##_find_nearest_line, \
+.  _bfd_generic_find_line, \
 .  NAME##_find_inliner_info, \
 .  NAME##_bfd_make_debug_symbol, \
 .  NAME##_read_minisymbols, \
@@ -371,6 +372,9 @@ BFD_JUMP_TABLE macros.
 .  bfd_boolean (*_bfd_find_nearest_line)
 .    (bfd *, struct bfd_section *, struct bfd_symbol **, bfd_vma,
 .     const char **, const char **, unsigned int *);
+.  bfd_boolean (*_bfd_find_line)
+.    (bfd *, struct bfd_symbol **, struct bfd_symbol *,
+.     const char **, unsigned int *);
 .  bfd_boolean (*_bfd_find_inliner_info)
 .    (bfd *, const char **, const char **, unsigned int *);
 . {* Back-door to allow format-aware applications to create debug symbols
--- binutils/binutils/nm.c.line	2005-05-09 06:18:24.000000000 -0700
+++ binutils/binutils/nm.c	2005-06-05 11:12:29.000000000 -0700
@@ -907,9 +907,10 @@ print_symbol (bfd *abfd, asymbol *sym, b
 	}
       else if (bfd_get_section (sym)->owner == abfd)
 	{
-	  if (bfd_find_nearest_line (abfd, bfd_get_section (sym), syms,
-				     sym->value, &filename, &functionname,
-				     &lineno)
+	  if ((bfd_find_line (abfd, syms, sym, &filename, &lineno)
+	       || bfd_find_nearest_line (abfd, bfd_get_section (sym),
+					 syms, sym->value, &filename,
+					 &functionname, &lineno))
 	      && filename != NULL
 	      && lineno != 0)
 	    printf ("\t%s:%u", filename, lineno);


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