diff mbox

Debug info extensions to support optimized out parameters

Message ID 20100819170030.GY702@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek Aug. 19, 2010, 5 p.m. UTC
Hi!

This is an implementation of something I've sent earlier this week to
Dwarf-Discuss.
I'm attaching patch, two small testcases that can show what are these
extensions useful for and the two proposals sent to Dwarf-Discuss.
The patch implements this as vendor extension instead, as DWARF5 is
probably quite far away.  If possible, it would be nice if the
vendor codes just matched what will end up in DWARF5, then we'd just
switch to using the standard codes.

The DW_OP_GNU_entry_value special location op can be useful either
together with the DW_TAG_GNU_call_site DIEs, or e.g. for non-interactive
debugging (e.g. systemtap, where you know beforehand you'll need to query
value at some PC, and can insert breakpoint at the start of routine and
remember the value there).
DW_TAG_GNU_call_site can be useful also for more useful backtraces (where
the debugger can print you the values that were actually passed to
the function, rather than whatever the parameters contain now), for
virtual backtraces when tail calls are involved, for doing static call graph
analysis etc.

The patch is on top of the DW_OP_GNU_implicit_pointer patch.

Bootstrapped/regtested on x86_64-linux and i686-linux.

	Jakub
2010-08-19  Jakub Jelinek  <jakub@redhat.com>

	* final.c (final_scan_insn): Handle NOTE_INSN_CALL_ARG_LOCATION.
	Call var_location debug hook even on CALL_INSNs.
	(rest_of_clean_state): Don't print NOTE_INSN_CALL_ARG_LOCATION.
	* rtl.def (ENTRY_VALUE): New.
	* dwarf2out.c: Include cfglayout.h.
	(dwarf_stack_op_name, size_of_loc_descr, output_loc_operands,
	output_loc_operands_raw): Handle DW_OP_GNU_entry_value.
	(struct call_arg_loc_node): New type.
	(call_arg_locations, call_arg_loc_last, block_map, call_site_count,
	tail_call_site_count): New variables.
	(dwarf_tag_name): Handle DW_TAG_GNU_call_site and
	DW_TAG_GNU_call_site_parameter.
	(dwarf_attr_name): Handle DW_AT_GNU_call_site_value,
	DW_AT_GNU_call_site_data_value, DW_AT_GNU_call_site_target,
	DW_AT_GNU_call_site_target_clobbered, DW_AT_GNU_tail_call,
	DW_AT_GNU_all_tail_call_sites, DW_AT_GNU_all_call_sites
	and DW_AT_GNU_all_source_call_sites.
	(const_ok_for_output_1): Don't complain about TLS UNSPECs.
	(mem_loc_descriptor): Handle ENTRY_VALUE.
	(add_src_coords_attributes): Don't add enything if
	DECL_SOURCE_LOCATION is UNKNOWN_LOCATION.
	(dwarf2out_abstract_function): Save and clear call_arg_location,
	call_site_count and tail_call_site_count around dwarf2out_decl call.
	(gen_call_site_die): New function.
	(gen_subprogram_die): Emit DW_TAG_GNU_call_site DIEs for call sites.
	(gen_lexical_block_die, gen_inlined_subroutine_die): Update block_map.
	(dwarf2out_function_decl): Clear call_arg_locations,
	call_arg_loc_last, set call_site_count and tail_call_site_count
	to -1 and free block_map.
	(dwarf2out_var_location): Handle NOTE_INSN_CALL_ARG_LOCATION and
	CALL_INSNs.  Add NOTE_DURING_CALL_P var location notes even when not
	followed by any real instructions.
	(dwarf2out_begin_function): Set call_site_count and
	tail_call_site_count to 0.
	(resolve_addr): If DW_AT_abstract_origin of DW_TAG_GNU_call_site
	is dw_val_class_addr, attempt to look it up again, for DECL_EXTERNAL
	attempt to force a DIE for it and worst case remove the attribute.
	(resolve_one_addr): For TREE_CONSTANT_POOL_ADDRESS_P SYMBOL_REFs
	check TREE_ASM_WRITTEN of DECL_INITIAL of the decl instead of
	the decl itself.
	* var-tracking.c: Include tm_p.h.
	(vt_stack_adjustments): For calls call note_register_arguments.
	(argument_reg_set): New variable.
	(add_stores): For MO_VAL_SET of non-tracked regs from argument_reg_set
	ensure the VALUE is resolved.
	(call_arguments): New variable.
	(prepare_call_arguments): New function.
	(add_with_sets): For MO_CALL set u.loc from call_arguments and clear it.
	(struct expand_loc_callback_data): Add ignore_cur_loc field.
	(vt_expand_loc_callback): If ignore_cur_loc, don't look at cur_loc and
	always use the best expression.
	(vt_expand_loc): Add ignore_cur_loc argument.
	(vt_expand_loc_dummy): Clear ignore_cur_loc field.
	(emit_note_insn_var_location): Adjust vt_expand_loc callers.
	(emit_notes_in_bb) <case MO_CALL>: Add NOTE_INSN_CALL_ARG_LOCATION
	note for all calls.
	(vt_add_function_parameters): Use cselib_lookup_from_insn.
	If dv is a VALUE, enter into hash table also ENTRY_VALUE for the
	argument.  Don't call cselib_preserve_only_values and
	cselib_reset_table.
	(note_register_arguments): New function.
	(vt_initialize): Compute argument_reg_set.  Call
	vt_add_function_parameters before processing basic blocks instead of
	afterwards.  For calls call prepare_call_arguments before calling
	cselib_process_insn.
	* print-rtl.c (print_rtx): Handle NOTE_INSN_CALL_ARG_LOCATION.
	* Makefile.in (dwarf2out.o): Depend on $(CFGLAYOUT_H).
	(var-tracking.o): Depend on $(TM_P_H).
	* cfglayout.h (insn_scope): New prototype.
	* gengtype.c (adjust_field_rtx_def): Handle NOTE_INSN_CALL_ARG_LOCATION.
	* cfglayout.c (insn_scope): No longer static.
	* insn-notes.def (CALL_ARG_LOCATION): New.
	* calls.c (expand_call, emit_library_call_value_1): Put USEs for
	MEM arguments into CALL_INSN_FUNCTION_USAGE unconditionally.
cp/
	* cp-objcp-common.c (cp_function_decl_explicit_p): Don't crash if
	DECL_LANG_SPECIFIC is NULL.
include/
	* dwarf2.h (DW_TAG_GNU_call_site, DW_TAG_GNU_call_site_parameter,
	DW_AT_GNU_call_site_value, DW_AT_GNU_call_site_data_value,
	DW_AT_GNU_call_site_target, DW_AT_GNU_call_site_target_clobbered,
	DW_AT_GNU_tail_call, DW_AT_GNU_all_tail_call_sites,
	DW_AT_GNU_all_call_sites,, DW_AT_GNU_all_source_call_sites,
	DW_OP_GNU_entry_value): New.
extern void fn1 (long int, long int, long int);

__attribute__((noinline)) long int
fn2 (long int a, long int b, long int c) 
{
  long int q = 2 * a;
  fn1 (5, 6, 7); 
  return 0;
}
 
long int
fn3 (long int x, long int (*fn4) (long int *))
{
  long int v, w, w2, z;
  w = (*fn4) (&w2);
  v = (*fn4) (&w2);
  z = fn2 (1, v + 1, w);
  {
    int v1 = v + 4;
    z += fn2 (w, v * 2, x);
  }
  return z;
}
subroutine foo (i, j)
  integer :: i, j, k, l
  k = i
  l = j
  i = i * 10
  i = i + j
  call baz (i)
  i = i + j
end subroutine
subroutine bar (i, j)
  integer :: i, j, k, l
  k = i
  l = j
  i = i * 10
  i = i + j
  call baz (i)
  i = i + j
end subroutine
program entryval
  interface bar
    subroutine bar (i, j)
      integer :: i, j
    end subroutine
  end interface
  integer :: i
  i = 6
  call foo (i, 7)
  i = 8
  call bar (i, 7)
  i = 10
  call foo (i, 7)
  i = 12
  call bar (i, 7)
end
Tracking of values passed as arguments to functions in debug information
========================================================================

Overview
--------

Many architectures pass arguments in registers and quite often
the register in which an argument has been passed is quickly reused
for something else. In that case all the debugger can say is that
a value has been optimized out.  If the argument is never modified
in the function, often the value can be discovered through extra
effort.  This could be by setting preemptive breakpoints to collect
argument values at function entry, or by unwinding in the debugger
to the caller and seeing what value has been passed to the function.
A companion proposal addresses unwinding to a caller to determine
argument values for such cases.

Proposed changes to DWARF
-------------------------

New DWARF expression operation

DW_OP_entry_value	0xa1	2	ULEB128 size followed by
					DWARF expression block
					of that size

2.5.1.6

Change "one special operation" into "two special operations".

Add

2. DW_OP_entry_value

The DW_OP_entry_value operation pushes a value that had a known location
upon entering the current subprogram.  It uses two operands: an unsigned
LEB128 length, followed by a block containing a DWARF expression or
a simple register location description.  The length gives the length
in bytes of the block.  If the block contains a register location
description, DW_OP_entry_value pushes the value that register had upon
entering the current subprogram.  If the block contains a DWARF expression,
the DWARF expression is evaluated in a separate DWARF stack from the
currently used one as if it has been evaluated upon entering the current
subprogram.  The new DWARF stack is initially empty.  DW_OP_push_object_address
is not meaningful inside of this DWARF expression.  The DW_OP_entry_value
operation then pushes the value from the top of the new stack to the
previous stack, everything from the separate DWARF stack is afterwards
discarded.

2.6.1.3

Add

DW_OP_entry_value 1 DW_OP_reg5 DW_OP_stack_value
DW_OP_entry_value 2 DW_OP_breg5 0 DW_OP_stack_value

  Both of these location descriptions mean the value register 5 had upon
  entering of the current subprogram.

DW_OP_breg2 0 DW_OP_entry_value 1 DW_OP_reg5 DW_OP_add DW_OP_stack_value

  The value register 5 had upon entering of the current subprogram
  plus the value register 2 currently has.

DW_OP_entry_value 3 DW_OP_breg4 16 DW_OP_deref DW_OP_stack_value
DW_OP_entry_value 6 DW_OP_entry_value 1 DW_OP_reg4 DW_OP_plus_uconst 16 DW_OP_deref DW_OP_stack_value

  These two location expressions do the same thing, push the value
  memory location with size of an address pointed to by value of
  register 4 upon entering current subprogram plus 16 had upon 
  entering of the current subprogram.

7.7.1

Add

DW_OP_entry_value	0xa1	2	ULEB128 size followed by
					DWARF expression block
					of that size

to figure 24.

Change History
--------------

Aug   11, 2010 - use 0xa1 instead of 0xa0, as 0xa0 is in
		 DW_OP_implicit_pointer proposal
May    4, 2010 - change DW_OP_entry_value argument to DWARF expression
		 from location description, add simple register location
		 description as more compact alternative (similar to
		 DW_AT_frame_base)
April 28, 2010 - the whole location expression in DW_OP_entry_value is
		 to be evaluated in the context upon entry of current
		 subprogram.
April 27, 2010 - split into separate DW_OP_entry_value and DW_TAG_call_site
		 proposals.
April 26, 2010 - remove DW_AT_tail_call_count, add instead
		 DW_AT_call_site_count.
April 15, 2010 - add optimized out parameters that aren't passed at all.
April 13, 2010 - initial draft.
Representation of call sites in the debugging information
=========================================================

Overview
--------

Many architectures pass arguments in registers and quite often
the register in which an argument has been passed is quickly reused
for something else, in that case all the debugger can say is that
a value has been optimized out.  If the argument is never modified
in the function, often the value can be discovered through extra
effort, by unwinding in the debugger to the caller and seeing what
value has been passed to the function.  If a constant is passed
to the function, or the argument is loaded from a call preserved
register or call preserved memory, then that is the value of
the argument in the callee.  For arguments passed in stack slots
this is needed less often, as the stack slot in which the value
has been passed is usually not reused for something else, but
it could be in some cases.

For backtraces it is often worthwhile to print what value has been
passed to an argument at the time a function has been called, rather
than what the argument currently has.  E.g. for
void foo (char *p)
{
  /* some code */
  p = strchr (p, '\0');
  bar ();
  /* some further code */
}
if a backtrace is done from within bar, argument p will be printed
as "", which isn't much useful, more interesting is the string before
it.  The debugger then could annotate the values in the backtrace
whether they mean the value passed to the function on function entry,
the current value of the parameter, that the value is known to be
the same in both places, print both values, etc.

The proposed extensions involve adding optional information about
call sites in the programs which say at which location what other
function (if known which one) is called and what values are passed
to its arguments and also a new DWARF expression opcode that
can be used to push the value a register argument or some memory location
had on entry of the current function.

If tail calls are involved, the proposed extensions allow this fact to
be detected.  In that case the return address of a callee is not the
function that actually called it, but a caller of the function that did the
tail call and call target in the call site at return address doesn't match
the current subprogram.  In some cases where the tail call sequence reaching
current subprogram is unambiguous, the debug information consumer might
print a virtual backtrace including the tail calls.  Even when the call site
target matches the current subprogram tail calls still might be involved -
if the current function could possibly indirectly tail call itself.
The extensions allow that case to be detected.  The debugging information
consumer should be conservative with that check and assume that is possible
unless proven otherwise.

Proposed changes to DWARF
-------------------------

New DWARF tags

DW_TAG_call_site		0x44

Allowable attributes:

DW_AT_abstract_origin
DW_AT_call_column
DW_AT_call_file
DW_AT_call_line
DW_AT_call_site_target
DW_AT_call_site_target_clobbered
DW_AT_low_pc
DW_AT_sibling
DW_AT_tail_call
DW_AT_type

DW_TAG_call_site_parameter	0x45

Allowable attributes:

DW_AT_abstract_origin
DW_AT_call_site_data_value
DW_AT_call_site_value
DW_AT_data_location
DW_AT_location
DW_AT_name
DW_AT_sibling
DW_AT_type

New DWARF attributes

DW_AT_call_site_value			0x6f	exprloc
DW_AT_call_site_data_value		0x70	exprloc
DW_AT_call_site_target			0x71	exprloc
DW_AT_call_site_target_clobbered	0x72	exprloc
DW_AT_tail_call				0x73	flag
DW_AT_all_tail_call_sites		0x74	flag
DW_AT_all_call_sites			0x75	flag
DW_AT_all_source_call_sites		0x76	flag

2.2

Add DW_TAG_call_site and DW_TAG_call_site_parameter to figure 1.

Add:

DW_AT_call_site_value			Value passed to a function argument
DW_AT_call_site_data_value		Value pointed to by passed function argument
DW_AT_call_site_target			Address of called subroutine
DW_AT_call_site_target_clobbered	Callee address value, which may
					use call clobbered registers or
					memory locations
DW_AT_tail_call				Call site is a tail call
DW_AT_all_tail_call_sites		All tail call sites in a subprogram
					have corresponding DW_TAG_call_site entries
DW_AT_all_call_sites			All normal and tail call sites in a
					subprogram have corresponding
					DW_TAG_call_site entries
DW_AT_all_source_call_sites		All normal and tail call sites and all
					inline calls have DW_TAG_call_site
					resp. DW_TAG_inlined_subroutine entries

to figure 2.

3.3.1

Add:

A subprogram entry may have DW_AT_all_tail_call_sites, DW_AT_all_call_sites
or DW_AT_all_source_call_sites attributes which are flags.
The DW_AT_all_tail_call_sites flag indicates that no DW_TAG_call_site
entries with DW_AT_tail_call flag set are missing for this subprogram entry.
The DW_AT_all_call_sites flag indicates that no DW_TAG_call_site entries
are missing for this subprogram entry.  If this attribute is set, the
DW_AT_all_tail_call_sites attribute is superfluous.
The DW_AT_all_source_call_sites attribute indicates that no DW_TAG_call_site
nor DW_TAG_inlined_subroutine entries are missing for this subprogram entry.
If this attribute is set, the DW_AT_all_tail_call_sites and
DW_AT_all_call_sites attributes are superfluous.
DW_TAG_call_site entries represent normal and tail call sites in the
subprogram or subroutines inlined into it, the flags cover entries owned
by the subroutine and entry point entries.
If the flags aren't set, some or all DW_TAG_call_site resp.
DW_TAG_inlined_subroutines entries might be missing.
<i>Entries owned by subroutine or entry point entries are children of
the subprogram or entry point entry they are attributes of and any of
its DW_TAG_lexical_block, DW_TAG_inlined_subroutine, DW_TAG_try_block
or DW_TAG_catch_block child entries, but not children of other nested
DW_TAG_subprogram or DW_TAG_entry_point entries.</i>

New section:

3.8 Call site entries

A call site is a way to represent the static or dynamic call graph in
the debugging information.


A call site is represented by a debugging information entry with the tag
DW_TAG_call_site.  The entry for a call site should be owned by the
debugging information entry representing the scope within which the
call is present in the source program.

<i>A source call can be compiled into different types of machine code:
Normal calls are call-like instructions which transfer control to the start
of some subprogram and leave the call site location address somewhere where
unwind information sees it.
Tail calls are jump-like instructions which transfer control to the start
of some subprogram, but the call site location address isn't visible in
the unwind information.
Tail recursion is a call to the current function which is compiled as a loop
into the middle of the current function.
Optimized out call is a call that is in unreachable code that hasn't been
emitted, like if (0) foo ();.
Inline call is a call to inlined subprogram, where at least one instruction
has the location of the inlined subprogram or any of its blocks or inlined
subprograms.
Optimized out inline call is a call to inlined subprogram which either
didn't expand to any instructions or only parts of instructions belong to it
and for debug information those instructions are given location in the
caller.
The DW_TAG_call_site entries describe normal and tail calls.</i>

The call site entry has a DW_AT_low_pc attribute which is the return
address after the call.  This corresponds to the return address
computed by CFI in the called function (6.4).
<i>On many architectures this is the address immediately following the
call instruction, but e.g. on architectures with delay slots it might
be an address after the delay slot of the call.</i>

If the call site is a tail call optimized through tail call optimization
into a jump instead of call, that doesn't leave traces of the function call
in the unwind information, it should have the DW_AT_tail_call attribute,
which is a flag.

The call site may have a DW_AT_abstract_origin attribute which is
a reference.  For direct calls or jumps where the called subprogram is
known it should be a reference to the called subprogram's debugging
information entry.  For indirect calls it may be a reference to a
DW_TAG_variable, DW_TAG_formal_parameter or DW_TAG_member entry representing
the subroutine pointer that is called.

The call site may have a DW_AT_call_site_target attribute which is
a DWARF expression.  For indirect calls or jumps where it is unknown at
compile time which subprogram will be called the expression computes the
address of the subprogram that will be called.  The DWARF expression should
not use register or memory locations that might be clobbered by the call.

The call site may have a DW_AT_call_site_target_clobbered attribute
which is a DWARF expression.  For indirect calls or jumps where the
address is not computable without use of registers or memory locations that
might be clobbered by the call this attribute may be used instead of
the DW_AT_call_site_target attribute.

The call site entry may have a DW_AT_type attribute referencing
a debugging information entry of the type of the called
function.  When DW_AT_abstract_origin is present, DW_AT_type is
usually omitted.

The call site entry may have DW_AT_call_file, DW_AT_call_line and
DW_AT_call_column attributes, each of whose value is an integer constant.
These attributes represent the source file, source line number, and source
column number, respectively, of the first character of the call statement or
expression.  The call file, call line, and call column attributes are
interpreted in the same way as the declaration file, declaration
line, and declaration column attributes, respectively (see Section 2.14).
<i>The call file, call line and call column coordinates do not describe the
coordinates of the subroutine declaration that was inlined, rather they describe
the coordinates of the call.</i>

The call site entry may own DW_TAG_call_site_parameter debugging information
entries representing the parameters passed to the call.

Each such DW_TAG_call_site_parameter debugging information entry should
have a DW_AT_location attribute which is a location expression.
This location expression shall describe where the parameter is passed
in (usually either some register, or a memory at stack register plus some
offset).

Each DW_TAG_call_site_parameter entry may have a DW_AT_call_site_value
attribute which is a DWARF expression.  This expression computes the value
passed to that parameter.  The expression should not use registers or memory
locations that might be clobbered by the call, as it might be evaluated after
unwinding from the called function back to the caller.

For parameters passed by reference, where the code passes a pointer to
a location which contains the parameter, or for reference type parameters
the DW_TAG_call_site_parameter entry may also have DW_AT_data_location
which is a location expression and DW_AT_call_site_data_value attribute
which is a DWARF expression.  The DW_AT_data_location attribute describes where
the referenced value lives during the call.  If it is just
DW_OP_push_object_address, it may be left out.  The
DW_AT_call_site_data_value attribute describes the value in that location.
The expression should not use registers or memory locations that might be
clobbered by the call, as it might be evaluated after unwinding from the
called function back to the caller.

Each DW_TAG_call_site_parameter entry may also have a DW_AT_abstract_origin
attribute which contains a reference to a DW_TAG_formal_parameter entry,
DW_AT_type attribute referencing the type of the parameter and/or DW_AT_name
attribute describing the parameter's name.

7.5.4

Add

DW_TAG_call_site		0x44
DW_TAG_call_site_parameter	0x45

to figure 18.

Add

DW_AT_call_site_value			0x6f	exprloc
DW_AT_call_site_data_value		0x70	exprloc
DW_AT_call_site_target			0x71	exprloc
DW_AT_call_site_target_clobbered	0x72	exprloc
DW_AT_tail_call				0x73	flag
DW_AT_all_tail_call_sites		0x74	flag
DW_AT_all_call_sites			0x75	flag
DW_AT_all_source_call_sites		0x76	flag

to figure 20.

Appendix A

Add DW_AT_all_tail_call_sites, DW_AT_all_call_sites and
DW_AT_all_source_call_sites as allowable attribute to DW_TAG_subprogram
and DW_TAG_entry_point.
Add:

DW_TAG_call_site		DW_AT_abstract_origin
				DW_AT_call_column
				DW_AT_call_file
				DW_AT_call_line
				DW_AT_call_site_target
				DW_AT_call_site_target_clobbered
				DW_AT_low_pc
				DW_AT_sibling
				DW_AT_tail_call
				DW_AT_type

DW_TAG_call_site_parameter	DW_AT_abstract_origin
				DW_AT_call_site_data_value
				DW_AT_call_site_value
				DW_AT_data_location
				DW_AT_location
				DW_AT_name
				DW_AT_sibling
				DW_AT_type

entries.

New section:

D.13  Call Site Examples

The following examples use a hypothetical machine which passes first
argument in register 0, second in register 1, third in register 2,
the stack pointer is register 3 and the machine has one call preserved
register 4.  Return value from function is passed in register 0.

/* C source */

extern void fn1 (long int, long int, long int);

long int
fn2 (long int a, long int b, long int c) 
{
  long int q = 2 * a;
  fn1 (5, 6, 7); 
  return 0;
}
 
long int
fn3 (long int x, long int (*fn4) (long int *))
{
  long int v, w, w2, z;
  w = (*fn4) (&w2);
  v = (*fn4) (&w2);
  z = fn2 (1, v + 1, w);
  {
    int v1 = v + 4;
    z += fn2 (w, v * 2, x);
  }
  return z;
}

/* Assembly */

fn2:
L1:
  %reg2 = 7
  %reg1 = 6
  %reg0 = 5
L2:
  call fn1
  %reg0 = 0
  return
L3:

fn3:
  %reg3 = %reg3 - 32
  [%reg3] = %reg4
  [%reg3 + 8] = %reg0
  [%reg3 + 16] = %reg1
  %reg0 = %reg3 + 24
  call %reg1
L6:
  %reg2 = [%reg3 + 16]
  [%reg3 + 16] = %reg0
  %reg0 = %reg3 + 24
  call %reg2
L7:
  %reg4 = %reg0
  %reg2 = [%reg3 + 16]
  %reg1 = %reg4 + 1
  %reg0 = 1
  call fn2
L4:
  %reg2 = [%reg3 + 8]
  [%reg3 + 8] = %reg0
  %reg0 = [%reg3 + 16]
  %reg1 = %reg4 + %reg4
  call fn2
L5:
  %reg2 = [%reg3 + 8]
  %reg0 = %reg0 + %reg2
L8:
  %reg4 = [%reg3]
  %reg3 = %reg3 + 32
  return

The location list for variable a in fn2 then might be:

<L1, L2> DW_OP_reg0
<L2, L3> DW_OP_entry_value 1 DW_OP_reg0 DW_OP_stack_value
<0, 0>

variable q in fn2 then might have location list:

<L1, L2> DW_OP_lit2 DW_OP_breg0 0 DW_OP_mul DW_OP_stack_value
<L2, L3> DW_OP_lit2 DW_OP_entry_value 1 DW_OP_reg0 DW_OP_mul DW_OP_stack_value
<0, 0>

Variables b and c would be similar location list to variable a,
except for different label in between the two ranges and would
use DW_OP_reg1 resp. DW_OP_reg2 instead of DW_OP_reg0
and DW_OP_breg1 resp. DW_OP_breg2 instead of DW_OP_breg0.

The call sites for all the calls in fn3 would be children of the
DW_TAG_subprogram (or its DW_TAG_lexical_block if it has any for the whole
function):

DW_TAG_call_site
  DW_AT_low_pc(L6)
  DW_AT_call_site_target(DW_OP_breg3 16 DW_OP_deref)
  DW_TAG_call_site_parameter
    DW_AT_location(DW_OP_reg0)
    DW_AT_call_site_value(DW_OP_breg3 24)
DW_TAG_call_site
  DW_AT_low_pc(L7)
  DW_AT_call_site_target(DW_OP_entry_value 1 DW_OP_reg1)
  DW_TAG_call_site_parameter
    DW_AT_location(DW_OP_reg0)
    DW_AT_call_site_value(DW_OP_breg3 24)
DW_TAG_call_site
  DW_AT_low_pc(L4)
  DW_AT_abstract_origin(reference to fn2 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter a in fn2 subprogram)
    DW_AT_location(DW_OP_reg0)
    DW_AT_call_site_value(DW_OP_lit1)
  DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter b in fn2 subprogram)
    DW_AT_location(DW_OP_reg1)
    DW_AT_call_site_value(DW_OP_breg4 1)
  DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter c in fn2 subprogram)
    DW_AT_location(DW_OP_reg2)
    DW_AT_call_site_value(DW_OP_breg3 16 DW_OP_deref)
DW_TAG_lexical_block
  DW_AT_low_pc(L4)
  DW_AT_high_pc(L8)
  DW_TAG_variable
    DW_AT_name("v1")
    DW_AT_type(reference to int)
    DW_AT_location(DW_OP_breg4 4)
  DW_TAG_call_site
    DW_AT_low_pc(L5)
    DW_AT_call_site_target(reference to fn2 DW_TAG_subprogram)
    DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter a in fn2 subprogram)
      DW_AT_location(DW_OP_reg0)
      DW_AT_call_site_value(DW_OP_breg3 16 DW_OP_deref)
    DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter b in fn2 subprogram)
      DW_AT_location(DW_OP_reg1)
      DW_AT_call_site_value(DW_OP_lit2 DW_OP_breg4 0 DW_OP_mul)
    DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter c in fn2 subprogram)
      DW_AT_location(DW_OP_reg2)
      DW_AT_call_site_value(DW_OP_entry_value 1 DW_OP_reg0)

! Fortran source to show passing parameters by reference.
subroutine fn4 (n)
  integer :: n, x
  x = n
  n = n / 2
  call fn6
end subroutine
subroutine fn5 (n)
  interface fn4
    subroutine fn4 (n)
      integer :: n
    end subroutine
  end interface fn4
  integer :: n, x
  call fn4 (n)
  x = 5
  call fn4 (x)
end subroutine fn5

/* Assembly */

fn4:
  %reg2 = [%reg0]
  %reg2 = %reg2 / 2
  [%reg0] = %reg2
  call fn6
  return

fn5:
  %reg3 = %reg3 - 8
  call fn4
L9:
  [%reg3] = 5
  %reg0 = %reg3
  call fn4
L10:
  %reg3 = %reg3 + 8
  return

The location description for x in fn4 might be
DW_OP_entry_value 4 DW_OP_breg0 0 DW_OP_deref_size 4 DW_OP_stack_value.

The call sites in fn5 might be:

DW_TAG_call_site
  DW_AT_low_pc(L9)
  DW_AT_abstract_origin(reference to fn4 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter n in fn4 subprogram)
    DW_AT_location(DW_OP_reg0)
    DW_AT_call_site_value(DW_OP_entry_value 1 DW_OP_reg0)
    ! DW_AT_data_location(DW_OP_push_object_address) ! left out
    DW_AT_call_site_data_value(DW_OP_entry_value 4 DW_OP_breg0 0 DW_OP_deref_size 4)
DW_TAG_call_site
  DW_AT_low_pc(L10)
  DW_AT_abstract_origin(reference to fn4 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_abstract_origin(reference to DW_TAG_formal_parameter n in fn4 subprogram)
    DW_AT_location(DW_OP_reg0)
    DW_AT_call_site_value(DW_OP_breg3 0)
    ! DW_AT_data_location(DW_OP_push_object_address) ! left out
    DW_AT_call_site_data_value(DW_OP_lit5)

Change History
--------------

May   28, 2010 - allow DW_AT_call_{file,line,column} instead of
		 DW_AT_decl_{file,line,column} on DW_TAG_call_site, disallow
		 the latter on DW_TAG_call_site_parameter, other minor
		 changes
May   21, 2010 - introduced DW_TAG_call_site_parameter, removed
		 DW_AT_call_site_count, added DW_AT_call_site_target_clobbered,
		 DW_AT_all_tail_call_sites, DW_AT_all_call_sites,
		 DW_AT_all_source_call_sites.  Further additions to appendix D
May    6, 2010 - add assembly code for the appendix D example
April 27, 2010 - split into separate DW_OP_entry_value and DW_TAG_call_site
		 proposals.
April 26, 2010 - remove DW_AT_tail_call_count, add instead
		 DW_AT_call_site_count.
April 15, 2010 - add optimized out parameters that aren't passed at all.
April 13, 2010 - initial draft.

Comments

Jan Kratochvil Sept. 5, 2010, 10:10 a.m. UTC | #1
Hi,

there is a patch for GDB for DW_OP_GNU_entry_value and DW_TAG_GNU_call_site.
	http://sourceware.org/gdb/wiki/ArcherBranchManagement
	branch: archer-jankratochvil-entryval

Jakub's idea came from a reported bug (Fedora #556975) by Dave Malcolm for
Python where an essential variable `f' is not visible in the backtrace:

#13 0x00007ff14faf9e14 in PyEval_EvalFrameEx (f=<value optimized out>, throwflag=<value optimized out>) at /usr/src/debug/Python-2.7/Python/ceval.c:2552
2552                x = (*v->ob_type->tp_iternext)(v);

Now with the GCC+GDB patches:
#13 0x00007f225828172e in PyEval_EvalFrameEx (f=0x29aeb70, throwflag=0) at /home/jkratoch/redhat/fedora/python/f14/Python-2.7/Python/ceval.c:2552
2552                x = (*v->ob_type->tp_iternext)(v);
(gdb) info addr f
[...]
  Range 0x7f2258281417-0x7f2258286e93: a complex DWARF expression:
     1: DW_OP_GNU_entry_value
       3: DW_OP_reg5 [$rdi]
     4: DW_OP_stack_value


Some other artificial testcases show more benefits for the -O2 -g backtraces
and debugging of production code:

Attached testcase with unpatched GCC+GDB:
#0  d (i=<value optimized out>) at tailcall3.c:6
#1  0x00000000004004d4 in main () at tailcall3.c:15

while with patched GCC+GDB:
#0  d (i=70) at tailcall3.c:6
#1  0x000000000040049a in c (i=7) at tailcall3.c:8
#2  0x00000000004004b8 in b (i=5) at tailcall3.c:12
#3  0x00000000004004d4 in main () at tailcall3.c:15


Or entryval.c from Jakub's mail with unpatched GCC+GDB:
(gdb) bt
#0  fn1 (a=5, b=6, c=7) at entryval-main.c:3
#1  0x0000000000400478 in fn2 (a=<value optimized out>, b=<value optimized out>, c=<value optimized out>) at entryval.c:7
#2  0x00000000004004c3 in fn3 (x=1, fn4=<value optimized out>) at entryval.c:17
#3  0x0000000000400533 in main () at entryval-main.c:16

and patched GCC+GDB:
(gdb) bt
#0  fn1 (a=5, b=6, c=7) at entryval-main.c:3
#1  0x0000000000400478 in fn2 (a=1, b=11, c=10) at entryval.c:7
#2  0x00000000004004c3 in fn3 (x=1, fn4=0x400500 <fn4>) at entryval.c:17
#3  0x0000000000400533 in main () at entryval-main.c:16


For entryval2.f90 from Jakub's mail with unpatched GCC+GDB:
#0  baz (i=67) at entryval2b.f90:4
No locals.
#1  0x0000000000400607 in foo (i=67, j=7) at entryval2.f90:7
        k = <value optimized out>
        l = <value optimized out>
#2  0x000000000040064f in entryval (argc=<value optimized out>, argv=<value optimized out>) at entryval2.f90:27
        i = 67

and patched GCC+GDB:
#0  baz (i=67) at entryval2b.f90:4
No locals.
#1  0x0000000000400607 in foo (i=67, j=7) at entryval2.f90:7
        k = 6
        l = 7
#2  0x000000000040064f in entryval (argc=<value optimized out>, argv=<value optimized out>) at entryval2.f90:27
        i = 67


On Thu, 19 Aug 2010 19:00:30 +0200, Jakub Jelinek wrote:
> DW_TAG_GNU_call_site can be useful also for more useful backtraces (where
> the debugger can print you the values that were actually passed to
> the function, rather than whatever the parameters contain now),

This part is not yet implemented for GDB.


Thanks,
Jan
/* line  1 */ int v;
/* line  2 */ void __attribute__((noinline))
/* line  3 */ e (int i) { v = 0; }
/* line  4 */ int __attribute__((noinline))
/* line  5 */ d (int i) { e (i); e (v);
/* line  6 */             return 0; }
/* line  7 */ int __attribute__((noinline))
/* line  8 */ c (int i) { return d (i * 10); }
/* line  9 */ int __attribute__((noinline))
/* line 10 */ a (int i) { return c (i + 1); }
/* line 11 */ int __attribute__((noinline))
/* line 12 */ b (int i) { return c (i + 2); }
/* line 13 */ int main (void)
/* line 14 */ { if (v) return a (1) + 1;
/* line 15 */   else   return b (5) + 1; }
Gary Funck Sept. 27, 2010, 2:04 p.m. UTC | #2
On 08/19/10 19:00:30, Jakub Jelinek wrote:
> This is an implementation of something I've sent earlier this week to
> Dwarf-Discuss.
> I'm attaching patch, two small testcases that can show what are these
> extensions useful for and the two proposals sent to Dwarf-Discuss.
> The patch implements this as vendor extension instead, as DWARF5 is
> probably quite far away.  If possible, it would be nice if the
> vendor codes just matched what will end up in DWARF5, then we'd just
> switch to using the standard codes.
[...]

Recently, we merged GCC 4.5.1 into a version of GCC/UPC that we are testing.
While running tests (with compiler checks enabled), we see the following
(on an i686 running CentOS release 5.5):

../../gcc/xupc  -O1  -fupc-pthreads-model-tls -g test19.upc -o test19
test19.upc: In function 'test19':
test19.upc:80:1: note: non-delegitimized UNSPEC 5 found in variable location
test19.upc:80:1: note: non-delegitimized UNSPEC 5 found in variable location

Apart from the notes above, the test passes.

In the GCC/UPC implementation, UPC threads are usually implemented as
Unix processes, but with the -fupc-pthreads-model-tls switch asserted,
a UPC thread will be mapped to a pthread, and further all
normal "C" static/global variable references will be translated
into TLS references.  This mapping is done so that the global
variables will be "per-thread" as they would be when a UPC
thread is implemented as a full process.  This mapping will result
in programs that have quite a few more TLS references than is typical.
In the past, we have seen this extensive use of TLS variables "stress"
the linker and the operating system/runtime library.

Debugging the program above, the first note is issued here:

#1  0x0829cc24 in const_ok_for_output_1 (rtlp=0xb7a29f7c, data=0x0)
    at /eng/upc/dev/gary/gcc-upc-dev/gccupc/src/gcc/dwarf2out.c:12918
12918         inform (current_function_decl
(gdb) l
12913     if (GET_CODE (rtl) == UNSPEC)
12914       {
12915         /* If delegitimize_address couldn't do anything with the UNSPEC,
assume
12916            we can't express it in the debug info.  */
12917   #ifdef ENABLE_CHECKING
12918         inform (current_function_decl
12919                 ? DECL_SOURCE_LOCATION (current_function_decl)
12920                 : UNKNOWN_LOCATION,
12921                 "non-delegitimized UNSPEC %d found in variable location",
12922                 XINT (rtl, 1));
12923   #endif
12924         expansion_failed (NULL_TREE, rtl,
12925                           "UNSPEC hasn't been delegitimized.\n");
12926         return 1;
12927       }

(We have made some patches to dwarf2out.c that *should* be unrelated.
The line numbers above are likely different than in the original 4.5.1
release.)

The relevant values are:

(gdb) p rtl
$1 = (rtx) 0xb7a425b8
(gdb) pr
(unspec:SI [
        (symbol_ref:SI ("sizes") [flags 0x2a] <var_decl 0xb7c48ba0 sizes>)
    ] 5)
(gdb) p 0xb7c48ba0
$2 = 3083111328
(gdb) pt
 <var_decl 0xb7c48ba0 sizes
    type <array_type 0xb7ca1680
        type <integer_type 0xb7d6d820 size_t sizes-gimplified asm_written
public unsigned SI
            size <integer_cst 0xb7cf14b4 constant 32>
            unit size <integer_cst 0xb7cf12a0 constant 4>
            align 32 symtab -1210682528 alias set -1 canonical type 0xb7d02340
precision 32 min <integer_cst 0xb7cf14d0 0> max <integer_cst 0xb7cf1498
4294967295>
            pointer_to_this <pointer_type 0xb7c096e8>>
        BLK
        size <integer_cst 0xb7ca22bc constant 67136>
        unit size <integer_cst 0xb7ca2310 constant 8392>
        align 32 symtab 0 alias set -1 canonical type 0xb7ca16e8
        domain <integer_type 0xb7ca1410 type <integer_type 0xb7d02000 unsigned
int>
            SI size <integer_cst 0xb7cf14b4 32> unit size <integer_cst
0xb7cf12a0 4>
            align 32 symtab 0 alias set -1 canonical type 0xb7ca1410 precision
32 min <integer_cst 0xb7cf12bc 0> max <integer_cst 0xb7ca2230 2097>>
        pointer_to_this <pointer_type 0xb79de000>>
    addressable used public static tls-local-exec BLK file test19.upc line 61
col 8 size <integer_cst 0xb7ca22bc 67136> unit size <integer_cst 0xb7ca2310
8392>
    align 32
    (mem/s/c:BLK (symbol_ref:SI ("sizes") [flags 0x2a] <var_decl 0xb7c48ba0
sizes>) [0 sizes+0 S8392 A32]) chain <var_decl 0xb7c48c00 N>>

Please let me know if there is some additional information that you
would like for me to supply.  The full source code of the compiler
can obviously be provided if you want to try and duplicate the
problem yourself.

thanks,
- Gary
Gary Funck Oct. 3, 2010, 2:26 p.m. UTC | #3
I converted the UPC test into a "C" program
that reproduces the problem:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45870
diff mbox

Patch

--- gcc/cp/cp-objcp-common.c.jj	2010-07-28 10:35:56.000000000 +0200
+++ gcc/cp/cp-objcp-common.c	2010-08-13 12:44:17.000000000 +0200
@@ -161,6 +161,7 @@  cp_function_decl_explicit_p (tree decl)
 {
   return (decl
 	  && FUNCTION_FIRST_USER_PARMTYPE (decl) != void_list_node
+	  && DECL_LANG_SPECIFIC (STRIP_TEMPLATE (decl))
 	  && DECL_NONCONVERTING_P (decl));
 }
 
--- gcc/Makefile.in.jj	2010-08-13 10:15:19.000000000 +0200
+++ gcc/Makefile.in	2010-08-16 14:53:24.000000000 +0200
@@ -2951,7 +2951,7 @@  dwarf2out.o : dwarf2out.c $(CONFIG_H) $(
    $(LIBFUNCS_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) dwarf2out.h reload.h \
    $(GGC_H) $(EXCEPT_H) dwarf2asm.h $(TM_P_H) langhooks.h $(HASHTAB_H) \
    gt-dwarf2out.h $(TARGET_H) $(CGRAPH_H) $(MD5_H) $(INPUT_H) $(FUNCTION_H) \
-   $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) tree-pretty-print.h
+   $(GIMPLE_H) $(TREE_PASS_H) $(TREE_FLOW_H) $(CFGLAYOUT_H) tree-pretty-print.h
 dwarf2asm.o : dwarf2asm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
    $(FLAGS_H) $(RTL_H) $(TREE_H) output.h dwarf2asm.h $(TM_P_H) $(GGC_H) \
    gt-dwarf2asm.h $(DWARF2_H) $(SPLAY_TREE_H) $(TARGET_H)
@@ -3178,7 +3178,7 @@  var-tracking.o : var-tracking.c $(CONFIG
    $(BASIC_BLOCK_H) output.h sbitmap.h alloc-pool.h $(FIBHEAP_H) $(HASHTAB_H) \
    $(REGS_H) $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(TREE_FLOW_H) \
    cselib.h $(TARGET_H) $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(PARAMS_H) $(DIAGNOSTIC_H) pointer-set.h \
-   $(RECOG_H) tree-pretty-print.h
+   $(RECOG_H) $(TM_P_H) tree-pretty-print.h
 profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
    $(TREE_H) $(FLAGS_H) output.h $(REGS_H) $(EXPR_H) $(FUNCTION_H) $(BASIC_BLOCK_H) \
    $(TOPLEV_H) $(DIAGNOSTIC_CORE_H) $(COVERAGE_H) $(TREE_FLOW_H) value-prof.h cfghooks.h \
--- gcc/print-rtl.c.jj	2010-08-13 10:18:21.000000000 +0200
+++ gcc/print-rtl.c	2010-08-13 12:44:17.000000000 +0200
@@ -297,6 +297,7 @@  print_rtx (const_rtx in_rtx)
 		}
 
 	      case NOTE_INSN_VAR_LOCATION:
+	      case NOTE_INSN_CALL_ARG_LOCATION:
 #ifndef GENERATOR_FILE
 		fputc (' ', outfile);
 		print_rtx (NOTE_VAR_LOCATION (in_rtx));
--- gcc/rtl.def.jj	2010-08-13 10:18:21.000000000 +0200
+++ gcc/rtl.def	2010-08-13 12:44:17.000000000 +0200
@@ -715,6 +715,10 @@  DEF_RTL_EXPR(VAR_LOCATION, "var_location
    addressable.  */
 DEF_RTL_EXPR(DEBUG_IMPLICIT_PTR, "debug_implicit_ptr", "t", RTX_OBJ)
 
+/* Represents value that argument had on function entry.  Should
+   be only used in VAR_LOCATION location expression.  */
+DEF_RTL_EXPR(ENTRY_VALUE, "entry_value", "e", RTX_OBJ)
+
 /* All expressions from this point forward appear only in machine
    descriptions.  */
 #ifdef GENERATOR_FILE
--- gcc/final.c.jj	2010-08-13 10:15:19.000000000 +0200
+++ gcc/final.c	2010-08-13 12:44:17.000000000 +0200
@@ -1999,6 +1999,7 @@  final_scan_insn (rtx insn, FILE *file, i
 	  break;
 
 	case NOTE_INSN_VAR_LOCATION:
+	case NOTE_INSN_CALL_ARG_LOCATION:
 	  if (!DECL_IGNORED_P (current_function_decl))
 	    debug_hooks->var_location (insn);
 	  break;
@@ -2670,6 +2671,8 @@  final_scan_insn (rtx insn, FILE *file, i
 		if (t)
 		  assemble_external (t);
 	      }
+	    if (!DECL_IGNORED_P (current_function_decl))
+	      debug_hooks->var_location (insn);
 	  }
 
 	/* Output assembler code from the template.  */
@@ -4395,6 +4398,7 @@  rest_of_clean_state (void)
       if (final_output
 	  && (!NOTE_P (insn) ||
 	      (NOTE_KIND (insn) != NOTE_INSN_VAR_LOCATION
+	       && NOTE_KIND (insn) != NOTE_INSN_CALL_ARG_LOCATION
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_BEG
 	       && NOTE_KIND (insn) != NOTE_INSN_BLOCK_END
 	       && NOTE_KIND (insn) != NOTE_INSN_CFA_RESTORE_STATE)))
--- gcc/var-tracking.c.jj	2010-07-22 11:35:37.000000000 +0200
+++ gcc/var-tracking.c	2010-08-16 17:37:38.000000000 +0200
@@ -115,6 +115,7 @@ 
 #include "tree-pretty-print.h"
 #include "pointer-set.h"
 #include "recog.h"
+#include "tm_p.h"
 
 /* var-tracking.c assumes that tree code with the same value as VALUE rtx code
    has no chance to appear in REG_EXPR/MEM_EXPRs and isn't a decl.
@@ -408,6 +409,7 @@  static void stack_adjust_offset_pre_post
 static void insn_stack_adjust_offset_pre_post (rtx, HOST_WIDE_INT *,
 					       HOST_WIDE_INT *);
 static bool vt_stack_adjustments (void);
+static void note_register_arguments (rtx);
 static rtx compute_cfa_pointer (HOST_WIDE_INT);
 static hashval_t variable_htab_hash (const void *);
 static int variable_htab_eq (const void *, const void *);
@@ -660,11 +662,15 @@  vt_stack_adjustments (void)
 	    for (insn = BB_HEAD (dest);
 		 insn != NEXT_INSN (BB_END (dest));
 		 insn = NEXT_INSN (insn))
-	      if (INSN_P (insn))
-		{
-		  insn_stack_adjust_offset_pre_post (insn, &pre, &post);
-		  offset += pre + post;
-		}
+	      {
+		if (INSN_P (insn))
+		  {
+		    insn_stack_adjust_offset_pre_post (insn, &pre, &post);
+		    offset += pre + post;
+		  }
+		if (CALL_P (insn))
+		  note_register_arguments (insn);
+	      }
 
 	  VTI (dest)->out.stack_adjust = offset;
 
@@ -4993,6 +4999,9 @@  log_op_type (rtx x, basic_block bb, rtx 
 /* All preserved VALUEs.  */
 static VEC (rtx, heap) *preserved_values;
 
+/* Registers used in the current function for passing parameters.  */
+static HARD_REG_SET argument_reg_set;
+
 /* Ensure VAL is preserved and remember it in a vector for vt_emit_notes.  */
 
 static void
@@ -5342,6 +5351,15 @@  add_stores (rtx loc, const_rtx expr, voi
 	{
 	  mo.type = MO_CLOBBER;
 	  mo.u.loc = loc;
+	  if (GET_CODE (expr) == SET
+	      && SET_DEST (expr) == loc
+	      && REGNO (loc) < FIRST_PSEUDO_REGISTER
+	      && TEST_HARD_REG_BIT (argument_reg_set, REGNO (loc))
+	      && find_use_val (loc, mode, cui))
+	    {
+	      gcc_checking_assert (type == MO_VAL_SET);
+	      mo.u.loc = gen_rtx_SET (VOIDmode, loc, SET_SRC (expr));
+	    }
 	}
       else
 	{
@@ -5558,6 +5576,195 @@  add_stores (rtx loc, const_rtx expr, voi
   VEC_safe_push (micro_operation, heap, VTI (bb)->mos, &mo);
 }
 
+/* Arguments to the call.  */
+static rtx call_arguments;
+
+/* Compute call_arguments.  */
+
+static void
+prepare_call_arguments (basic_block bb, rtx insn)
+{
+  rtx link, x;
+  rtx prev, cur, next;
+  rtx call = PATTERN (insn);
+  tree type = NULL_TREE, t;
+  CUMULATIVE_ARGS args_so_far;
+
+  memset (&args_so_far, 0, sizeof (args_so_far));
+  if (GET_CODE (call) == PARALLEL)
+    call = XVECEXP (call, 0, 0);
+  if (GET_CODE (call) == SET)
+    call = SET_SRC (call);
+  if (GET_CODE (call) == CALL
+      && MEM_P (XEXP (call, 0))
+      && GET_CODE (XEXP (XEXP (call, 0), 0)) == SYMBOL_REF)
+    {
+      rtx symbol = XEXP (XEXP (call, 0), 0);
+      if (SYMBOL_REF_DECL (symbol)
+	  && TREE_CODE (SYMBOL_REF_DECL (symbol)) == FUNCTION_DECL
+	  && TYPE_ARG_TYPES (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
+	{
+	  type = TREE_TYPE (SYMBOL_REF_DECL (symbol));
+	  for (t = TYPE_ARG_TYPES (type); t && t != void_list_node;
+	       t = TREE_CHAIN (t))
+	    if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+		&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t))))
+	      break;
+	  if (t == NULL || t == void_list_node)
+	    type = NULL;
+	  else
+	    INIT_CUMULATIVE_ARGS (args_so_far, type, NULL_RTX,
+				  SYMBOL_REF_DECL (symbol),
+				  list_length (TYPE_ARG_TYPES (type)));
+	}
+    }
+  t = type ? TYPE_ARG_TYPES (type) : NULL_TREE;
+
+  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+    if (GET_CODE (XEXP (link, 0)) == USE)
+      {
+	rtx item = NULL_RTX;
+	x = XEXP (XEXP (link, 0), 0);
+	if (REG_P (x))
+	  {
+	    cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+	    if (val && cselib_preserved_value_p (val))
+	      item = gen_rtx_CONCAT (GET_MODE (x), x, val->val_rtx);
+	    else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
+	      {
+		enum machine_mode mode = GET_MODE (x);
+
+		while ((mode = GET_MODE_WIDER_MODE (mode)) != VOIDmode
+		       && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD)
+		  {
+		    rtx reg = simplify_subreg (mode, x, GET_MODE (x), 0);
+
+		    if (reg == NULL_RTX || !REG_P (reg))
+		      continue;
+		    val = cselib_lookup (reg, mode, 0);
+		    if (val && cselib_preserved_value_p (val))
+		      {
+			item = gen_rtx_CONCAT (GET_MODE (x), x,
+					       lowpart_subreg (GET_MODE (x),
+							       val->val_rtx,
+							       mode));
+			break;
+		      }
+		  }
+	      }
+	  }
+	else if (MEM_P (x))
+	  {
+	    rtx mem = x;
+	    cselib_val *val;
+
+	    if (!frame_pointer_needed)
+	      {
+		struct adjust_mem_data amd;
+		amd.mem_mode = VOIDmode;
+		amd.stack_adjust = -VTI (bb)->out.stack_adjust;
+		amd.side_effects = NULL_RTX;
+		amd.store = true;
+		mem = simplify_replace_fn_rtx (mem, NULL_RTX, adjust_mems,
+					       &amd);
+		gcc_assert (amd.side_effects == NULL_RTX);
+	      }
+	    val = cselib_lookup (mem, GET_MODE (mem), 0);
+	    if (val && cselib_preserved_value_p (val))
+	      item = gen_rtx_CONCAT (GET_MODE (x), copy_rtx (x), val->val_rtx);
+	  }
+	if (item)
+	  call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item, call_arguments);
+	if (t && t != void_list_node)
+	  {
+	    enum machine_mode mode = TYPE_MODE (TREE_VALUE (t));
+	    rtx reg = targetm.calls.function_arg (&args_so_far, mode,
+						  TREE_VALUE (t), true);
+	    if (TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+		&& INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (t)))
+		&& reg
+		&& REG_P (reg)
+		&& GET_MODE (reg) == mode
+		&& GET_MODE_CLASS (mode) == MODE_INT
+		&& REG_P (x)
+		&& REGNO (x) == REGNO (reg)
+		&& GET_MODE (x) == mode
+		&& item)
+	      {
+		enum machine_mode indmode
+		  = TYPE_MODE (TREE_TYPE (TREE_VALUE (t)));
+		rtx mem = gen_rtx_MEM (indmode, x);
+		cselib_val *val = cselib_lookup (mem, indmode, 0);
+		if (val && cselib_preserved_value_p (val))
+		  {
+		    item = gen_rtx_CONCAT (indmode, mem, val->val_rtx);
+		    call_arguments = gen_rtx_EXPR_LIST (VOIDmode, item,
+							call_arguments);
+		  }
+		else
+		  {
+		    struct elt_loc_list *l;
+		    tree initial;
+
+		    /* Try harder, when passing address of a constant
+		       pool integer it can be easily read back.  */
+		    val = CSELIB_VAL_PTR (XEXP (item, 1));
+		    for (l = val->locs; l; l = l->next)
+		      if (GET_CODE (l->loc) == SYMBOL_REF
+			  && TREE_CONSTANT_POOL_ADDRESS_P (l->loc)
+			  && SYMBOL_REF_DECL (l->loc)
+			  && DECL_INITIAL (SYMBOL_REF_DECL (l->loc)))
+			{
+			  initial = DECL_INITIAL (SYMBOL_REF_DECL (l->loc));
+			  if (host_integerp (initial, 0))
+			    {
+			      item = GEN_INT (tree_low_cst (initial, 0));
+			      item = gen_rtx_CONCAT (indmode, mem, item);
+			      call_arguments
+				= gen_rtx_EXPR_LIST (VOIDmode, item,
+						     call_arguments);
+			    }
+			  break;
+			}
+		  }
+	      }
+	    targetm.calls.function_arg_advance (&args_so_far, mode,
+						TREE_VALUE (t), true);
+	    t = TREE_CHAIN (t);
+	  }
+      }
+
+  /* Reverse call_arguments chain.  */
+  prev = NULL_RTX;
+  for (cur = call_arguments; cur; cur = next)
+    {
+      next = XEXP (cur, 1);
+      XEXP (cur, 1) = prev;
+      prev = cur;
+    }
+  call_arguments = prev;
+
+  x = PATTERN (insn);
+  if (GET_CODE (x) == PARALLEL)
+    x = XVECEXP (x, 0, 0);
+  if (GET_CODE (x) == SET)
+    x = SET_SRC (x);
+  if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+    {
+      x = XEXP (XEXP (x, 0), 0);
+      if (GET_CODE (x) != SYMBOL_REF)
+	{
+	  cselib_val *val = cselib_lookup (x, GET_MODE (x), 0);
+	  if (val && cselib_preserved_value_p (val))
+	    {
+	      x = gen_rtx_CONCAT (GET_MODE (x), pc_rtx, val->val_rtx);
+	      call_arguments
+		= gen_rtx_EXPR_LIST (VOIDmode, x, call_arguments);
+	    }
+	}
+    }
+}
+
 /* Callback for cselib_record_sets_hook, that records as micro
    operations uses and stores in an insn after cselib_record_sets has
    analyzed the sets in an insn, but before it modifies the stored
@@ -5627,7 +5834,8 @@  add_with_sets (rtx insn, struct cselib_s
 
       mo.type = MO_CALL;
       mo.insn = insn;
-      mo.u.loc = NULL_RTX;
+      mo.u.loc = call_arguments;
+      call_arguments = NULL_RTX;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
 	log_op_type (PATTERN (insn), bb, insn, mo.type, dump_file);
@@ -6943,6 +7151,10 @@  struct expand_loc_callback_data
      whose cur_loc has been already recomputed during current
      emit_notes_for_changes call.  */
   bool cur_loc_changed;
+
+  /* True if cur_loc should be ignored and any possible location
+     returned.  */
+  bool ignore_cur_loc;
 };
 
 /* Callback for cselib_expand_value, that looks for expressions
@@ -6956,6 +7168,7 @@  vt_expand_loc_callback (rtx x, bitmap re
     = (struct expand_loc_callback_data *) data;
   bool dummy = elcd->dummy;
   bool cur_loc_changed = elcd->cur_loc_changed;
+  rtx cur_loc;
   decl_or_value dv;
   variable var;
   location_chain loc;
@@ -7030,7 +7243,7 @@  vt_expand_loc_callback (rtx x, bitmap re
   VALUE_RECURSED_INTO (x) = true;
   result = NULL;
 
-  if (var->var_part[0].cur_loc)
+  if (var->var_part[0].cur_loc && !elcd->ignore_cur_loc)
     {
       if (dummy)
 	{
@@ -7045,12 +7258,16 @@  vt_expand_loc_callback (rtx x, bitmap re
 					     vt_expand_loc_callback, data);
       if (result)
 	set_dv_changed (dv, false);
+      cur_loc = var->var_part[0].cur_loc;
     }
-  if (!result && dv_changed_p (dv))
+  else
+    cur_loc = NULL_RTX;
+  if (!result && (dv_changed_p (dv) || elcd->ignore_cur_loc))
     {
-      set_dv_changed (dv, false);
+      if (!elcd->ignore_cur_loc)
+	set_dv_changed (dv, false);
       for (loc = var->var_part[0].loc_chain; loc; loc = loc->next)
-	if (loc->loc == var->var_part[0].cur_loc)
+	if (loc->loc == cur_loc)
 	  continue;
 	else if (dummy)
 	  {
@@ -7072,7 +7289,8 @@  vt_expand_loc_callback (rtx x, bitmap re
 	  }
       if (dummy && (result || var->var_part[0].cur_loc))
 	var->cur_loc_changed = true;
-      var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
+      if (!elcd->ignore_cur_loc)
+	var->var_part[0].cur_loc = loc ? loc->loc : NULL_RTX;
     }
   if (dummy)
     {
@@ -7093,7 +7311,7 @@  vt_expand_loc_callback (rtx x, bitmap re
    tables.  */
 
 static rtx
-vt_expand_loc (rtx loc, htab_t vars)
+vt_expand_loc (rtx loc, htab_t vars, bool ignore_cur_loc)
 {
   struct expand_loc_callback_data data;
 
@@ -7103,6 +7321,7 @@  vt_expand_loc (rtx loc, htab_t vars)
   data.vars = vars;
   data.dummy = false;
   data.cur_loc_changed = false;
+  data.ignore_cur_loc = ignore_cur_loc;
   loc = cselib_expand_value_rtx_cb (loc, scratch_regs, 8,
 				    vt_expand_loc_callback, &data);
 
@@ -7124,6 +7343,7 @@  vt_expand_loc_dummy (rtx loc, htab_t var
   data.vars = vars;
   data.dummy = true;
   data.cur_loc_changed = false;
+  data.ignore_cur_loc = false;
   ret = cselib_dummy_expand_value_rtx_cb (loc, scratch_regs, 8,
 					  vt_expand_loc_callback, &data);
   *pcur_loc_changed = data.cur_loc_changed;
@@ -7201,7 +7421,7 @@  emit_note_insn_var_location (void **varp
 	  complete = false;
 	  continue;
 	}
-      loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars);
+      loc2 = vt_expand_loc (var->var_part[i].cur_loc, vars, false);
       if (!loc2)
 	{
 	  complete = false;
@@ -7231,7 +7451,7 @@  emit_note_insn_var_location (void **varp
 	  && mode == GET_MODE (var->var_part[j].cur_loc)
 	  && (REG_P (loc[n_var_parts]) || MEM_P (loc[n_var_parts]))
 	  && last_limit == var->var_part[j].offset
-	  && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars))
+	  && (loc2 = vt_expand_loc (var->var_part[j].cur_loc, vars, false))
 	  && GET_CODE (loc[n_var_parts]) == GET_CODE (loc2))
 	{
 	  rtx new_loc = NULL;
@@ -7692,6 +7912,34 @@  emit_notes_in_bb (basic_block bb, datafl
 	  case MO_CALL:
 	    dataflow_set_clear_at_call (set);
 	    emit_notes_for_changes (insn, EMIT_NOTE_AFTER_CALL_INSN, set->vars);
+	    {
+	      rtx arguments = mo->u.loc, *p = &arguments, note;
+	      while (*p)
+		{
+		  XEXP (XEXP (*p, 0), 1)
+		    = vt_expand_loc (XEXP (XEXP (*p, 0), 1),
+				     shared_hash_htab (set->vars), true);
+		  /* If expansion is successful, keep it in the list.  */
+		  if (XEXP (XEXP (*p, 0), 1))
+		    p = &XEXP (*p, 1);
+		  /* Otherwise, if the following item is data_value for it,
+		     drop it too too.  */
+		  else if (XEXP (*p, 1)
+			   && REG_P (XEXP (XEXP (*p, 0), 0))
+			   && MEM_P (XEXP (XEXP (XEXP (*p, 1), 0), 0))
+			   && REG_P (XEXP (XEXP (XEXP (XEXP (*p, 1), 0), 0),
+					   0))
+			   && REGNO (XEXP (XEXP (*p, 0), 0))
+			      == REGNO (XEXP (XEXP (XEXP (XEXP (*p, 1), 0),
+						    0), 0)))
+		    *p = XEXP (XEXP (*p, 1), 1);
+		  /* Just drop this item.  */
+		  else
+		    *p = XEXP (*p, 1);
+		}
+	      note = emit_note_after (NOTE_INSN_CALL_ARG_LOCATION, insn);
+	      NOTE_VAR_LOCATION (note) = arguments;
+	    }
 	    break;
 
 	  case MO_USE:
@@ -8139,7 +8387,8 @@  vt_add_function_parameters (void)
 	  if (offset)
 	    continue;
 
-	  val = cselib_lookup (var_lowpart (mode, incoming), mode, true);
+	  val = cselib_lookup_from_insn (var_lowpart (mode, incoming), mode,
+					 true, get_insns ());
 
 	  /* ??? Float-typed values in memory are not handled by
 	     cselib.  */
@@ -8160,6 +8409,36 @@  vt_add_function_parameters (void)
 			     incoming);
 	  set_variable_part (out, incoming, dv, offset,
 			     VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
+	  if (dv_is_value_p (dv))
+	    {
+	      cselib_val *val = CSELIB_VAL_PTR (dv_as_value (dv));
+	      struct elt_loc_list *el;
+	      el = (struct elt_loc_list *)
+		   ggc_alloc_cleared_atomic (sizeof (*el));
+	      el->next = val->locs;
+	      el->loc = gen_rtx_ENTRY_VALUE (GET_MODE (incoming), incoming);
+	      el->setting_insn = get_insns ();
+	      val->locs = el;
+	      if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE
+		  && INTEGRAL_TYPE_P (TREE_TYPE (TREE_TYPE (parm))))
+		{
+		  enum machine_mode indmode
+		    = TYPE_MODE (TREE_TYPE (TREE_TYPE (parm)));
+		  rtx mem = gen_rtx_MEM (indmode, incoming);
+		  val = cselib_lookup_from_insn (mem, indmode, true,
+						 get_insns ());
+		  if (val)
+		    {
+		      preserve_value (val);
+		      el = (struct elt_loc_list *)
+			ggc_alloc_cleared_atomic (sizeof (*el));
+		      el->next = val->locs;
+		      el->loc = gen_rtx_ENTRY_VALUE (indmode, mem);
+		      el->setting_insn = get_insns ();
+		      val->locs = el;
+		    }
+		}
+	    }
 	}
       else if (MEM_P (incoming))
 	{
@@ -8168,13 +8447,6 @@  vt_add_function_parameters (void)
 			     VAR_INIT_STATUS_INITIALIZED, NULL, INSERT);
 	}
     }
-
-  if (MAY_HAVE_DEBUG_INSNS)
-    {
-      cselib_preserve_only_values ();
-      cselib_reset_table (cselib_get_next_uid ());
-    }
-
 }
 
 /* Return true if INSN in the prologue initializes hard_frame_pointer_rtx.  */
@@ -8202,6 +8474,23 @@  fp_setter (rtx insn)
   return false;
 }
 
+/* Gather all registers used for passing arguments to other functions
+   called from the current routine.  */
+
+static void
+note_register_arguments (rtx insn)
+{
+  rtx link, x;
+
+  for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+    if (GET_CODE (XEXP (link, 0)) == USE)
+      {
+	x = XEXP (XEXP (link, 0), 0);
+	if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
+	  SET_HARD_REG_BIT (argument_reg_set, REGNO (x));
+      }
+}
+
 /* Initialize cfa_base_rtx, create a preserved VALUE for it and
    ensure it isn't flushed during cselib_reset_table.
    Can be called only if frame_pointer_rtx resp. arg_pointer_rtx
@@ -8297,6 +8586,8 @@  vt_initialize (void)
       valvar_pool = NULL;
     }
 
+  CLEAR_HARD_REG_SET (argument_reg_set);
+
   if (!frame_pointer_needed)
     {
       rtx reg, elim;
@@ -8343,9 +8634,18 @@  vt_initialize (void)
 	    prologue_bb = single_succ (ENTRY_BLOCK_PTR);
 	}
     }
+  if (frame_pointer_needed)
+    {
+      rtx insn;
+      for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+	if (CALL_P (insn))
+	  note_register_arguments (insn);
+    }
 
   hard_frame_pointer_adjustment = -1;
 
+  vt_add_function_parameters ();
+
   FOR_EACH_BB (bb)
     {
       rtx insn;
@@ -8406,6 +8706,8 @@  vt_initialize (void)
 		  adjust_insn (bb, insn);
 		  if (MAY_HAVE_DEBUG_INSNS)
 		    {
+		      if (CALL_P (insn))
+			prepare_call_arguments (bb, insn);
 		      cselib_process_insn (insn);
 		      if (dump_file && (dump_flags & TDF_DETAILS))
 			{
@@ -8456,7 +8758,6 @@  vt_initialize (void)
 
   hard_frame_pointer_adjustment = -1;
   VTI (ENTRY_BLOCK_PTR)->flooded = true;
-  vt_add_function_parameters ();
   cfa_base_rtx = NULL_RTX;
   return true;
 }
--- gcc/calls.c.jj	2010-07-22 11:35:37.000000000 +0200
+++ gcc/calls.c	2010-08-13 12:44:17.000000000 +0200
@@ -2756,9 +2756,7 @@  expand_call (tree exp, rtx target, int i
 		sibcall_failure = 1;
 	      }
 
-	  if (((flags & ECF_CONST)
-	       || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
-	      && args[i].stack)
+	  if (args[i].stack)
 	    call_fusage = gen_rtx_EXPR_LIST (VOIDmode,
 					     gen_rtx_USE (VOIDmode,
 							  args[i].stack),
@@ -3647,6 +3645,8 @@  emit_library_call_value_1 (int retval, r
 
       if (! (reg != 0 && partial == 0))
 	{
+	  rtx use;
+
 	  if (ACCUMULATE_OUTGOING_ARGS)
 	    {
 	      /* If this is being stored into a pre-allocated, fixed-size,
@@ -3717,28 +3717,22 @@  emit_library_call_value_1 (int retval, r
 
 	  NO_DEFER_POP;
 
-	  if ((flags & ECF_CONST)
-	      || ((flags & ECF_PURE) && ACCUMULATE_OUTGOING_ARGS))
-	    {
-	      rtx use;
-
-	      /* Indicate argument access so that alias.c knows that these
-		 values are live.  */
-	      if (argblock)
-		use = plus_constant (argblock,
-				     argvec[argnum].locate.offset.constant);
-	      else
-		/* When arguments are pushed, trying to tell alias.c where
-		   exactly this argument is won't work, because the
-		   auto-increment causes confusion.  So we merely indicate
-		   that we access something with a known mode somewhere on
-		   the stack.  */
-		use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
-				    gen_rtx_SCRATCH (Pmode));
-	      use = gen_rtx_MEM (argvec[argnum].mode, use);
-	      use = gen_rtx_USE (VOIDmode, use);
-	      call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
-	    }
+	  /* Indicate argument access so that alias.c knows that these
+	     values are live.  */
+	  if (argblock)
+	    use = plus_constant (argblock,
+				 argvec[argnum].locate.offset.constant);
+	  else
+	    /* When arguments are pushed, trying to tell alias.c where
+	       exactly this argument is won't work, because the
+	       auto-increment causes confusion.  So we merely indicate
+	       that we access something with a known mode somewhere on
+	       the stack.  */
+	    use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
+				gen_rtx_SCRATCH (Pmode));
+	  use = gen_rtx_MEM (argvec[argnum].mode, use);
+	  use = gen_rtx_USE (VOIDmode, use);
+	  call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage);
 	}
     }
 
--- gcc/cfglayout.h.jj	2010-03-31 13:11:56.000000000 +0200
+++ gcc/cfglayout.h	2010-08-13 12:44:17.000000000 +0200
@@ -27,6 +27,7 @@  extern GTY(()) rtx cfg_layout_function_h
 
 extern void cfg_layout_initialize (unsigned int);
 extern void cfg_layout_finalize (void);
+extern tree insn_scope (const_rtx);
 extern void reemit_insn_block_notes (void);
 extern bool can_copy_bbs_p (basic_block *, unsigned);
 extern void copy_bbs (basic_block *, unsigned, basic_block *,
--- gcc/insn-notes.def.jj	2010-03-31 13:11:55.000000000 +0200
+++ gcc/insn-notes.def	2010-08-13 12:44:17.000000000 +0200
@@ -61,6 +61,9 @@  INSN_NOTE (EH_REGION_END)
 /* The location of a variable.  */
 INSN_NOTE (VAR_LOCATION)
 
+/* The values passed to callee.  */
+INSN_NOTE (CALL_ARG_LOCATION)
+
 /* Record the struct for the following basic block.  Uses
    NOTE_BASIC_BLOCK.  FIXME: Redundant with the basic block pointer
    now included in every insn.  */
--- gcc/gengtype.c.jj	2010-08-11 21:08:06.000000000 +0200
+++ gcc/gengtype.c	2010-08-13 12:44:17.000000000 +0200
@@ -1047,6 +1047,7 @@  adjust_field_rtx_def (type_p t, options_
 	    break;
 
 	  case NOTE_INSN_VAR_LOCATION:
+	  case NOTE_INSN_CALL_ARG_LOCATION:
 	    note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
 	    break;
 
--- gcc/dwarf2out.c.jj	2010-08-13 10:18:21.000000000 +0200
+++ gcc/dwarf2out.c	2010-08-16 17:51:53.000000000 +0200
@@ -92,6 +92,7 @@  along with GCC; see the file COPYING3.  
 #include "gimple.h"
 #include "tree-pass.h"
 #include "tree-flow.h"
+#include "cfglayout.h"
 
 static void dwarf2out_source_line (unsigned int, const char *, int, bool);
 static rtx last_var_location_insn;
@@ -4700,6 +4701,8 @@  dwarf_stack_op_name (unsigned int op)
       return "DW_OP_GNU_encoded_addr";
     case DW_OP_GNU_implicit_pointer:
       return "DW_OP_GNU_implicit_pointer";
+    case DW_OP_GNU_entry_value:
+      return "DW_OP_GNU_entry_value";
 
     default:
       return "OP_<unknown>";
@@ -4806,6 +4809,8 @@  loc_list_plus_const (dw_loc_list_ref lis
 #define DWARF_REF_SIZE	\
   (dwarf_version == 2 ? DWARF2_ADDR_SIZE : DWARF_OFFSET_SIZE)
 
+static unsigned long size_of_locs (dw_loc_descr_ref);
+
 /* Return the size of a location descriptor.  */
 
 static unsigned long
@@ -4921,6 +4926,12 @@  size_of_loc_descr (dw_loc_descr_ref loc)
     case DW_OP_GNU_implicit_pointer:
       size += DWARF_REF_SIZE + size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
       break;
+    case DW_OP_GNU_entry_value:
+      {
+	unsigned long op_size = size_of_locs (loc->dw_loc_oprnd1.v.val_loc);
+	size += size_of_uleb128 (op_size) + op_size;
+	break;
+      }
     default:
       break;
     }
@@ -4959,6 +4970,8 @@  size_of_locs (dw_loc_descr_ref loc)
 static HOST_WIDE_INT extract_int (const unsigned char *, unsigned);
 static void get_ref_die_offset_label (char *, dw_die_ref);
 
+static void output_loc_sequence (dw_loc_descr_ref);
+
 /* Output location description stack opcode's operands (if any).  */
 
 static void
@@ -5188,6 +5201,11 @@  output_loc_operands (dw_loc_descr_ref lo
       }
       break;
 
+    case DW_OP_GNU_entry_value:
+      dw2_asm_output_data_uleb128 (size_of_locs (val1->v.val_loc), NULL);
+      output_loc_sequence (val1->v.val_loc);
+      break;
+
     default:
       /* Other codes have no operands.  */
       break;
@@ -5327,6 +5345,7 @@  output_loc_operands_raw (dw_loc_descr_re
       break;
 
     case DW_OP_GNU_implicit_pointer:
+    case DW_OP_GNU_entry_value:
       gcc_unreachable ();
       break;
 
@@ -5932,10 +5951,33 @@  struct GTY (()) var_loc_list_def {
 };
 typedef struct var_loc_list_def var_loc_list;
 
+/* Call argument location list.  */
+struct GTY ((chain_next ("%h.next"))) call_arg_loc_node {
+  rtx GTY (()) call_arg_loc_note;
+  const char * GTY (()) label;
+  tree GTY (()) block;
+  bool tail_call_p;
+  rtx GTY (()) symbol_ref;
+  struct call_arg_loc_node * GTY (()) next;
+};
+
 
 /* Table of decl location linked lists.  */
 static GTY ((param_is (var_loc_list))) htab_t decl_loc_table;
 
+/* Head and tail of call_arg_loc chain.  */
+static GTY (()) struct call_arg_loc_node *call_arg_locations;
+static struct call_arg_loc_node *call_arg_loc_last;
+
+/* Number of call sites in the current function.  */
+static int call_site_count = -1;
+/* Number of tail call sites in the current function.  */
+static int tail_call_site_count = -1;
+
+/* Vector mapping block numbers to DW_TAG_{lexical_block,inlined_subroutine}
+   DIEs.  */
+static VEC (dw_die_ref, heap) *block_map;
+
 /* A pointer to the base of a list of references to DIE's that
    are uniquely identified by their tag, presence/absence of
    children DIE's, and list of attribute/value pairs.  */
@@ -6700,6 +6742,10 @@  dwarf_tag_name (unsigned int tag)
       return "DW_TAG_GNU_EINCL";
     case DW_TAG_GNU_template_template_param:
       return "DW_TAG_GNU_template_template_param";
+    case DW_TAG_GNU_call_site:
+      return "DW_TAG_GNU_call_site";
+    case DW_TAG_GNU_call_site_parameter:
+      return "DW_TAG_GNU_call_site_parameter";
     default:
       return "DW_TAG_<unknown>";
     }
@@ -6944,6 +6990,22 @@  dwarf_attr_name (unsigned int attr)
       return "DW_AT_GNU_odr_signature";
     case DW_AT_GNU_template_name:
       return "DW_AT_GNU_template_name";
+    case DW_AT_GNU_call_site_value:
+      return "DW_AT_GNU_call_site_value";
+    case DW_AT_GNU_call_site_data_value:
+      return "DW_AT_GNU_call_site_data_value";
+    case DW_AT_GNU_call_site_target:
+      return "DW_AT_GNU_call_site_target";
+    case DW_AT_GNU_call_site_target_clobbered:
+      return "DW_AT_GNU_call_site_target_clobbered";
+    case DW_AT_GNU_tail_call:
+      return "DW_AT_GNU_tail_call";
+    case DW_AT_GNU_all_tail_call_sites:
+      return "DW_AT_GNU_all_tail_call_sites";
+    case DW_AT_GNU_all_call_sites:
+      return "DW_AT_GNU_all_call_sites";
+    case DW_AT_GNU_all_source_call_sites:
+      return "DW_AT_GNU_all_source_call_sites";
 
     case DW_AT_VMS_rtnbeg_pd_address:
       return "DW_AT_VMS_rtnbeg_pd_address";
@@ -13441,11 +13503,18 @@  const_ok_for_output_1 (rtx *rtlp, void *
       /* If delegitimize_address couldn't do anything with the UNSPEC, assume
 	 we can't express it in the debug info.  */
 #ifdef ENABLE_CHECKING
-      inform (current_function_decl
-	      ? DECL_SOURCE_LOCATION (current_function_decl)
-	      : UNKNOWN_LOCATION,
-	      "non-delegitimized UNSPEC %d found in variable location",
-	      XINT (rtl, 1));
+      if (XVECLEN (rtl, 0) != 1
+	  || GET_CODE (XVECEXP (rtl, 0, 0)) != SYMBOL_REF
+	  || SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0)) == NULL
+	  || TREE_CODE (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))) != VAR_DECL
+	  || !DECL_THREAD_LOCAL_P (SYMBOL_REF_DECL (XVECEXP (rtl, 0, 0))))
+	/* Don't complain about TLS UNSPECs, those are just too hard to
+	   delegitimize.  */
+	inform (current_function_decl
+		? DECL_SOURCE_LOCATION (current_function_decl)
+		: UNKNOWN_LOCATION,
+		"non-delegitimized UNSPEC %d found in variable location",
+		XINT (rtl, 1));
 #endif
       expansion_failed (NULL_TREE, rtl,
 			"UNSPEC hasn't been delegitimized.\n");
@@ -13695,6 +13764,26 @@  mem_loc_descriptor (rtx rtl, enum machin
 			"CONCAT/CONCATN/VAR_LOCATION is handled only by loc_descriptor");
       return 0;
 
+    case ENTRY_VALUE:
+      mem_loc_result = new_loc_descr (DW_OP_GNU_entry_value, 0, 0);
+      mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_loc;
+      if (REG_P (XEXP (rtl, 0)))
+	mem_loc_result->dw_loc_oprnd1.v.val_loc
+	  = one_reg_loc_descriptor (dbx_reg_number (XEXP (rtl, 0)),
+				    VAR_INIT_STATUS_INITIALIZED);
+      else if (MEM_P (XEXP (rtl, 0)) && REG_P (XEXP (XEXP (rtl, 0), 0)))
+	{
+	  dw_loc_descr_ref ref
+	    = mem_loc_descriptor (XEXP (rtl, 0), GET_MODE (rtl),
+				  VAR_INIT_STATUS_INITIALIZED);
+	  if (ref == NULL)
+	    return NULL;
+	  mem_loc_result->dw_loc_oprnd1.v.val_loc = ref;
+	}
+      else
+	gcc_unreachable ();
+      return mem_loc_result;
+
     case PRE_MODIFY:
       /* Extract the PLUS expression nested inside and fall into
 	 PLUS code below.  */
@@ -17531,8 +17620,11 @@  add_linkage_attr (dw_die_ref die, tree d
 static void
 add_src_coords_attributes (dw_die_ref die, tree decl)
 {
-  expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+  expanded_location s;
 
+  if (DECL_SOURCE_LOCATION (decl) == UNKNOWN_LOCATION)
+    return;
+  s = expand_location (DECL_SOURCE_LOCATION (decl));
   add_AT_file (die, DW_AT_decl_file, lookup_filename (s.file));
   add_AT_unsigned (die, DW_AT_decl_line, s.line);
 }
@@ -18545,6 +18637,8 @@  dwarf2out_abstract_function (tree decl)
   tree context;
   int was_abstract;
   htab_t old_decl_loc_table;
+  int old_call_site_count, old_tail_call_site_count;
+  struct call_arg_loc_node *old_call_arg_locations;
 
   /* Make sure we have the actual abstract inline, not a clone.  */
   decl = DECL_ORIGIN (decl);
@@ -18559,6 +18653,12 @@  dwarf2out_abstract_function (tree decl)
      get locations in abstract instantces.  */
   old_decl_loc_table = decl_loc_table;
   decl_loc_table = NULL;
+  old_call_arg_locations = call_arg_locations;
+  call_arg_locations = NULL;
+  old_call_site_count = call_site_count;
+  call_site_count = -1;
+  old_tail_call_site_count = tail_call_site_count;
+  tail_call_site_count = -1;
 
   /* Be sure we've emitted the in-class declaration DIE (if any) first, so
      we don't get confused by DECL_ABSTRACT.  */
@@ -18583,6 +18683,9 @@  dwarf2out_abstract_function (tree decl)
 
   current_function_decl = save_fn;
   decl_loc_table = old_decl_loc_table;
+  call_arg_locations = old_call_arg_locations;
+  call_site_count = old_call_site_count;
+  tail_call_site_count = old_tail_call_site_count;
   pop_cfun ();
 }
 
@@ -18658,6 +18761,43 @@  premark_types_used_by_global_vars (void)
 		   premark_types_used_by_global_vars_helper, NULL);
 }
 
+/* Generate a DW_TAG_GNU_call_site DIE in function DECL under SUBR_DIE
+   for CA_LOC call arg loc node.  */
+
+static dw_die_ref
+gen_call_site_die (tree decl, dw_die_ref subr_die,
+		   struct call_arg_loc_node *ca_loc)
+{
+  dw_die_ref stmt_die = NULL, die;
+  tree block = ca_loc->block;
+
+  while (block
+	 && block != DECL_INITIAL (decl)
+	 && TREE_CODE (block) == BLOCK)
+    {
+      if (VEC_length (dw_die_ref, block_map) > BLOCK_NUMBER (block))
+	stmt_die = VEC_index (dw_die_ref, block_map, BLOCK_NUMBER (block));
+      if (stmt_die)
+	break;
+      block = BLOCK_SUPERCONTEXT (block);
+    }
+  if (stmt_die == NULL)
+    stmt_die = subr_die;
+  die = new_die (DW_TAG_GNU_call_site, stmt_die, NULL_TREE);
+  add_AT_lbl_id (die, DW_AT_low_pc, ca_loc->label);
+  if (ca_loc->tail_call_p)
+    add_AT_flag (die, DW_AT_GNU_tail_call, 1);
+  if (ca_loc->symbol_ref)
+    {
+      dw_die_ref tdie = lookup_decl_die (SYMBOL_REF_DECL (ca_loc->symbol_ref));
+      if (tdie)
+	add_AT_die_ref (die, DW_AT_abstract_origin, tdie);
+      else
+	add_AT_addr (die, DW_AT_abstract_origin, ca_loc->symbol_ref);
+    }
+  return die;
+}
+
 /* Generate a DIE to represent a declared function (either file-scope or
    block-local).  */
 
@@ -19036,6 +19176,9 @@  gen_subprogram_die (tree decl, dw_die_re
      constructor function.  */
   if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
     {
+      int call_site_note_count = 0;
+      int tail_call_site_note_count = 0;
+
       /* Emit a DW_TAG_variable DIE for a named return value.  */
       if (DECL_NAME (DECL_RESULT (decl)))
 	gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
@@ -19054,6 +19197,104 @@  gen_subprogram_die (tree decl, dw_die_re
 	    }
 	}
 #endif
+
+      if (call_arg_locations)
+	{
+	  struct call_arg_loc_node *ca_loc;
+	  for (ca_loc = call_arg_locations; ca_loc; ca_loc = ca_loc->next)
+	    {
+	      dw_die_ref die = NULL;
+	      rtx tloc = NULL_RTX;
+	      rtx arg, next_arg;
+
+	      for (arg = NOTE_VAR_LOCATION (ca_loc->call_arg_loc_note);
+		   arg; arg = next_arg)
+		{
+		  dw_loc_descr_ref reg, val;
+		  enum machine_mode mode = GET_MODE (XEXP (XEXP (arg, 0), 1));
+		  dw_die_ref cdie;
+
+		  next_arg = XEXP (arg, 1);
+		  if (REG_P (XEXP (XEXP (arg, 0), 0))
+		      && next_arg
+		      && MEM_P (XEXP (XEXP (next_arg, 0), 0))
+		      && REG_P (XEXP (XEXP (XEXP (next_arg, 0), 0), 0))
+		      && REGNO (XEXP (XEXP (arg, 0), 0))
+			 == REGNO (XEXP (XEXP (XEXP (next_arg, 0), 0), 0)))
+		    next_arg = XEXP (next_arg, 1);
+		  if (mode == VOIDmode)
+		    mode = GET_MODE (XEXP (XEXP (arg, 0), 0));
+		  if (GET_MODE_CLASS (mode) != MODE_INT
+		      || GET_MODE_SIZE (mode) > DWARF2_ADDR_SIZE)
+		    continue;
+		  if (XEXP (XEXP (arg, 0), 0) == pc_rtx)
+		    {
+		      gcc_assert (ca_loc->symbol_ref == NULL_RTX);
+		      tloc = XEXP (XEXP (arg, 0), 1);
+		      continue;
+		    }
+		  if (REG_P (XEXP (XEXP (arg, 0), 0)))
+		    reg = reg_loc_descriptor (XEXP (XEXP (arg, 0), 0),
+					      VAR_INIT_STATUS_INITIALIZED);
+		  else if (MEM_P (XEXP (XEXP (arg, 0), 0)))
+		    reg = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 0),
+							  0), 0), mode,
+					      VAR_INIT_STATUS_INITIALIZED);
+		  else
+		    continue;
+		  if (reg == NULL)
+		    continue;
+		  val = mem_loc_descriptor (XEXP (XEXP (arg, 0), 1), VOIDmode,
+					    VAR_INIT_STATUS_INITIALIZED);
+		  if (val == NULL)
+		    continue;
+		  if (die == NULL)
+		    die = gen_call_site_die (decl, subr_die, ca_loc);
+		  cdie = new_die (DW_TAG_GNU_call_site_parameter, die,
+				  NULL_TREE);		
+		  add_AT_loc (cdie, DW_AT_location, reg);
+		  add_AT_loc (cdie, DW_AT_GNU_call_site_value, val);
+		  if (next_arg != XEXP (arg, 1))
+		    {
+		      val = mem_loc_descriptor (XEXP (XEXP (XEXP (arg, 1),
+							    0), 1), VOIDmode,
+						VAR_INIT_STATUS_INITIALIZED);
+		      if (val != NULL)
+			add_AT_loc (cdie, DW_AT_GNU_call_site_data_value, val);
+		    }
+		}
+	      if (die == NULL
+		  && (ca_loc->symbol_ref || tloc))
+		die = gen_call_site_die (decl, subr_die, ca_loc);
+	      if (die != NULL && tloc != NULL_RTX)
+		{
+		  dw_loc_descr_ref tval
+		    = mem_loc_descriptor (tloc, VOIDmode,
+					  VAR_INIT_STATUS_INITIALIZED);
+		  if (tval)
+		    add_AT_loc (die, DW_AT_GNU_call_site_target, tval);
+		}
+	      if (die != NULL)
+		{
+		  call_site_note_count++;
+		  if (ca_loc->tail_call_p)
+		    tail_call_site_note_count++;
+		}
+	    }
+	  call_arg_locations = NULL;
+	  call_arg_loc_last = NULL;
+	}
+      if (tail_call_site_count >= 0
+	  && tail_call_site_count == tail_call_site_note_count)
+	{
+	  if (call_site_count >= 0
+	      && call_site_count == call_site_note_count)
+	    add_AT_flag (subr_die, DW_AT_GNU_all_call_sites, 1);
+	  else
+	    add_AT_flag (subr_die, DW_AT_GNU_all_tail_call_sites, 1);
+	}
+      call_site_count = -1;
+      tail_call_site_count = -1;
     }
   /* Add the calling convention attribute if requested.  */
   add_calling_convention_attribute (subr_die, decl);
@@ -19442,6 +19683,14 @@  gen_lexical_block_die (tree stmt, dw_die
 {
   dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
 
+  if (call_arg_locations)
+    {
+      if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+	VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+			       BLOCK_NUMBER (stmt) + 1);
+      VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), stmt_die);
+    }
+
   if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
     add_high_low_attributes (stmt, stmt_die);
 
@@ -19472,6 +19721,13 @@  gen_inlined_subroutine_die (tree stmt, d
       dw_die_ref subr_die
 	= new_die (DW_TAG_inlined_subroutine, context_die, stmt);
 
+      if (call_arg_locations)
+	{
+	  if (VEC_length (dw_die_ref, block_map) <= BLOCK_NUMBER (stmt))
+	    VEC_safe_grow_cleared (dw_die_ref, heap, block_map,
+				   BLOCK_NUMBER (stmt) + 1);
+	  VEC_replace (dw_die_ref, block_map, BLOCK_NUMBER (stmt), subr_die);
+	}
       add_abstract_origin_attribute (subr_die, decl);
       if (TREE_ASM_WRITTEN (stmt))
         add_high_low_attributes (stmt, subr_die);
@@ -21027,7 +21283,11 @@  static void
 dwarf2out_function_decl (tree decl)
 {
   dwarf2out_decl (decl);
-
+  call_arg_locations = NULL;
+  call_arg_loc_last = NULL;
+  call_site_count = -1;
+  tail_call_site_count = -1;
+  VEC_free (dw_die_ref, heap, block_map);
   htab_empty (decl_loc_table);
 }
 
@@ -21381,16 +21641,35 @@  dwarf2out_var_location (rtx loc_note)
   static const char *last_postcall_label;
   static bool last_in_cold_section_p;
   tree decl;
+  bool var_loc_p;
+
+  if (!NOTE_P (loc_note))
+    {
+      if (CALL_P (loc_note))
+	{
+	  call_site_count++;
+	  if (SIBLING_CALL_P (loc_note))
+	    tail_call_site_count++;
+	}
+      return;
+    }
 
-  if (!DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
+  var_loc_p = NOTE_KIND (loc_note) == NOTE_INSN_VAR_LOCATION;
+  if (var_loc_p && !DECL_P (NOTE_VAR_LOCATION_DECL (loc_note)))
     return;
 
   next_real = next_real_insn (loc_note);
+
   /* If there are no instructions which would be affected by this note,
      don't do anything.  */
-  if (next_real == NULL_RTX && !NOTE_DURING_CALL_P (loc_note))
+  if (var_loc_p
+      && next_real == NULL_RTX
+      && !NOTE_DURING_CALL_P (loc_note))
     return;
 
+  if (next_real == NULL_RTX)
+    next_real = get_last_insn ();
+
   /* If there were any real insns between note we processed last time
      and this note (or if it is the first note), clear
      last_{,postcall_}label so that they are not reused this time.  */
@@ -21402,12 +21681,20 @@  dwarf2out_var_location (rtx loc_note)
       last_postcall_label = NULL;
     }
 
-  decl = NOTE_VAR_LOCATION_DECL (loc_note);
-  newloc = add_var_loc_to_decl (decl, loc_note,
-				NOTE_DURING_CALL_P (loc_note)
-				? last_postcall_label : last_label);
-  if (newloc == NULL)
-    return;
+  if (var_loc_p)
+    {
+      decl = NOTE_VAR_LOCATION_DECL (loc_note);
+      newloc = add_var_loc_to_decl (decl, loc_note,
+				    NOTE_DURING_CALL_P (loc_note)
+				    ? last_postcall_label : last_label);
+      if (newloc == NULL)
+	return;
+    }
+  else
+    {
+      decl = NULL_TREE;
+      newloc = NULL;
+    }
 
   /* If there were no real insns between note we processed last time
      and this note, use the label we emitted last time.  Otherwise
@@ -21420,7 +21707,43 @@  dwarf2out_var_location (rtx loc_note)
       last_label = ggc_strdup (loclabel);
     }
 
-  if (!NOTE_DURING_CALL_P (loc_note))
+  if (!var_loc_p)
+    {
+      struct call_arg_loc_node *ca_loc
+	= ggc_alloc_cleared_call_arg_loc_node ();
+      rtx prev = prev_real_insn (loc_note), x;
+      ca_loc->call_arg_loc_note = loc_note;
+      ca_loc->next = NULL;
+      ca_loc->label = last_label;
+      gcc_assert (prev
+		  && (CALL_P (prev)
+		      || (NONJUMP_INSN_P (prev)
+			  && GET_CODE (PATTERN (prev)) == SEQUENCE
+			  && CALL_P (XVECEXP (PATTERN (prev), 0, 0)))));
+      if (!CALL_P (prev))
+	prev = XVECEXP (PATTERN (prev), 0, 0);
+      ca_loc->tail_call_p = SIBLING_CALL_P (prev);
+      x = PATTERN (prev);
+      if (GET_CODE (x) == PARALLEL)
+	x = XVECEXP (x, 0, 0);
+      if (GET_CODE (x) == SET)
+	x = SET_SRC (x);
+      if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
+	{
+	  x = XEXP (XEXP (x, 0), 0);
+	  if (GET_CODE (x) == SYMBOL_REF
+	      && SYMBOL_REF_DECL (x)
+	      && TREE_CODE (SYMBOL_REF_DECL (x)) == FUNCTION_DECL)
+	    ca_loc->symbol_ref = x;
+	}
+      ca_loc->block = insn_scope (prev);
+      if (call_arg_locations)
+	call_arg_loc_last->next = ca_loc;
+      else
+	call_arg_locations = ca_loc;
+      call_arg_loc_last = ca_loc;
+    }
+  else if (!NOTE_DURING_CALL_P (loc_note))
     newloc->label = last_label;
   else
     {
@@ -21448,6 +21771,8 @@  dwarf2out_begin_function (tree fun)
     have_multiple_function_sections = true;
 
   dwarf2out_note_section_used ();
+  call_site_count = 0;
+  tail_call_site_count = 0;
 }
 
 /* Output a label to mark the beginning of a source code line entry
@@ -22225,9 +22550,16 @@  resolve_one_addr (rtx *addr, void *data 
     }
 
   if (GET_CODE (rtl) == SYMBOL_REF
-      && SYMBOL_REF_DECL (rtl)
-      && !TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
-    return 1;
+      && SYMBOL_REF_DECL (rtl))
+    {
+      if (TREE_CONSTANT_POOL_ADDRESS_P (rtl))
+	{
+	  if (!TREE_ASM_WRITTEN (DECL_INITIAL (SYMBOL_REF_DECL (rtl))))
+	    return 1;
+	}
+      else if (!TREE_ASM_WRITTEN (SYMBOL_REF_DECL (rtl)))
+	return 1;
+    }
 
   if (GET_CODE (rtl) == CONST
       && for_each_rtx (&XEXP (rtl, 0), resolve_one_addr, NULL))
@@ -22319,6 +22651,28 @@  resolve_addr (dw_die_ref die)
 	    remove_AT (die, a->dw_attr);
 	    ix--;
 	  }
+	if (die->die_tag == DW_TAG_GNU_call_site
+	    && a->dw_attr == DW_AT_abstract_origin)
+	  {
+	    tree tdecl = SYMBOL_REF_DECL (a->dw_attr_val.v.val_addr);
+	    dw_die_ref tdie = lookup_decl_die (tdecl);
+	    if (tdie == NULL && DECL_EXTERNAL (tdecl))
+	      {
+		force_decl_die (tdecl);
+		tdie = lookup_decl_die (tdecl);
+	      }
+	    if (tdie)
+	      {
+		a->dw_attr_val.val_class = dw_val_class_die_ref;
+		a->dw_attr_val.v.val_die_ref.die = tdie;
+		a->dw_attr_val.v.val_die_ref.external = 0;
+	      }
+	    else
+	      {
+		remove_AT (die, a->dw_attr);
+		ix--;
+	      }
+	  }
 	break;
       default:
 	break;
--- gcc/cfglayout.c.jj	2010-06-07 11:25:05.000000000 +0200
+++ gcc/cfglayout.c	2010-08-13 12:44:17.000000000 +0200
@@ -54,7 +54,6 @@  static void change_scope (rtx, tree, tre
 
 void verify_insn_chain (void);
 static void fixup_fallthru_exit_predecessor (void);
-static tree insn_scope (const_rtx);
 
 rtx
 unlink_insn_chain (rtx first, rtx last)
@@ -499,7 +498,7 @@  locator_scope (int loc)
 }
 
 /* Return lexical scope block insn belongs to.  */
-static tree
+tree
 insn_scope (const_rtx insn)
 {
   return locator_scope (INSN_LOCATOR (insn));
--- include/dwarf2.h.jj	2010-08-13 10:18:27.000000000 +0200
+++ include/dwarf2.h	2010-08-13 12:44:22.000000000 +0200
@@ -228,6 +228,8 @@  enum dwarf_tag
        are properly part of DWARF 5.  */
     DW_TAG_GNU_template_parameter_pack = 0x4107,
     DW_TAG_GNU_formal_parameter_pack = 0x4108,
+    DW_TAG_GNU_call_site = 0x4109,
+    DW_TAG_GNU_call_site_parameter = 0x410a,
     /* Extensions for UPC.  See: http://upc.gwu.edu/~upc.  */
     DW_TAG_upc_shared_type = 0x8765,
     DW_TAG_upc_strict_type = 0x8766,
@@ -438,6 +440,14 @@  enum dwarf_attribute
     /* Template template argument name.
        See http://gcc.gnu.org/wiki/TemplateParmsDwarf .  */
     DW_AT_GNU_template_name = 0x2110,
+    DW_AT_GNU_call_site_value = 0x2111,
+    DW_AT_GNU_call_site_data_value = 0x2112,
+    DW_AT_GNU_call_site_target = 0x2113,
+    DW_AT_GNU_call_site_target_clobbered = 0x2114,
+    DW_AT_GNU_tail_call = 0x2115,
+    DW_AT_GNU_all_tail_call_sites = 0x2116,
+    DW_AT_GNU_all_call_sites = 0x2117,
+    DW_AT_GNU_all_source_call_sites = 0x2118,
     /* VMS extensions.  */
     DW_AT_VMS_rtnbeg_pd_address = 0x2201,
     /* GNAT extensions.  */
@@ -623,6 +633,7 @@  enum dwarf_location_atom
     DW_OP_GNU_uninit     = 0xf0,
     DW_OP_GNU_encoded_addr = 0xf1,
     DW_OP_GNU_implicit_pointer = 0xf2,
+    DW_OP_GNU_entry_value = 0xf3,
     /* HP extensions.  */
     DW_OP_HP_unknown     = 0xe0, /* Ouch, the same as GNU_push_tls_address.  */
     DW_OP_HP_is_value    = 0xe1,