fix for scan_unit_for_symbols abort

James E Wilson
Wed Aug 10 01:23:00 GMT 2005

I ran into this problem while looking at the fixes for the recent IA-64
LTOFF22X reloc problem.  I accidentally compiled a glibc with a
mismatched gcc, and ended up with linker errors and a linker core dump.

The problem here is with code that HJ added last month, that reads
variable addresses from the dwarf2 debug info, in order to improve
linker error messages.  This code assumes that if we have a DW_OP_addr,
then it must be the only opcode in a location.  This is normally the
case.  When this is true, the location block length will be 9 bytes on a
machine with 8 byte addresses.

However, for a TLS variable, gcc will emit DW_OP_addr <addr>
DW_OP_GNU_push_tls_address.  This is a 10 byte sequence.  In this case,
we end up calling bfd_get (72, ...) which calls abort.  Also, in this
case, just using <addr> is wrong, because it isn't an absolute address,
rather it is a relative address within the TLS variable block for this
thread.  We would have to add special code to handle this properly.

The attached fix just checks to see if DW_OP_addr is the only opcode in
the location, and ignores the location info if it isn't.  Unless someone
objects, or wants to handle this correctly, I plan to check this in.

I made a feeble attempt to write a small testcase, but wasn't
successful.  I'm not sure what exact conditions are necessary to trigger
the scan_unit_for_symbols call.

This was tested with make check on an ia64-linux machine.
Jim Wilson, GNU Tools Support,
-------------- next part --------------
2005-08-09  James E. Wilson  <>

	* dwarf2.c (scan_unit_for_symbols, case DT_AT_location): Verify that
	DW_OP_addr is only opcode in location before using it.

Index: dwarf2.c
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.77
diff -p -p -r1.77 dwarf2.c
*** dwarf2.c	7 Aug 2005 14:47:02 -0000	1.77
--- dwarf2.c	10 Aug 2005 01:02:24 -0000
*************** scan_unit_for_symbols (struct comp_unit 
*** 1782,1790 ****
  		      if (*attr.u.blk->data == DW_OP_addr)
  			  var->stack = 0;
! 			  var->addr = bfd_get ((attr.u.blk->size - 1) * 8,
! 					       unit->abfd,
! 					       attr.u.blk->data + 1);
--- 1782,1798 ----
  		      if (*attr.u.blk->data == DW_OP_addr)
  			  var->stack = 0;
! 			  /* Verify that DW_OP_addr is the only opcode in the
! 			     location, in which case the block size will be 1
! 			     plus the address size.  */
! 			  /* ??? For TLS variables, gcc can emit
! 			     DW_OP_addr <addr> DW_OP_GNU_push_tls_address
! 			     which we don't handle here yet.  */
! 			  if (attr.u.blk->size == unit->addr_size + 1U)
! 			    var->addr = bfd_get (unit->addr_size * 8,
! 						 unit->abfd,
! 						 attr.u.blk->data + 1);

More information about the Binutils mailing list