DWARF Standard


HOME
SPECIFICATIONS
FAQ
ISSUES



100909.2 Jakub Jelinek DW_TAG_call_site Enhancement Accepted with modifications Jakub Jelinek


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_call_column
DW_AT_call_file
DW_AT_call_line
DW_AT_call_site_origin
DW_AT_call_site_pc
DW_AT_call_site_return_pc
DW_AT_call_site_target
DW_AT_call_site_target_clobbered
DW_AT_sibling
DW_AT_tail_call
DW_AT_type

DW_TAG_call_site_parameter	0x45

Allowable attributes:

DW_AT_call_site_data_location
DW_AT_call_site_data_value
DW_AT_call_site_parameter
DW_AT_call_site_value
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_data_location		0x71	exprloc
DW_AT_call_site_target			0x72	exprloc
DW_AT_call_site_target_clobbered	0x73	exprloc
DW_AT_call_site_pc			0x74	address
DW_AT_call_site_return_pc		0x75	address
DW_AT_call_site_origin			0x76	reference
DW_AT_call_site_parameter		0x77	reference
DW_AT_tail_call				0x78	flag
DW_AT_all_tail_call_sites		0x79	flag
DW_AT_all_call_sites			0x7a	flag
DW_AT_all_source_call_sites		0x7b	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_data_location		Address of the 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_call_site_pc			The address of the call instruction
DW_AT_call_site_return_pc		The return address from the call
DW_AT_call_site_origin			The called subprogram
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 the corresponding
subprogram entry.  The DW_AT_all_call_sites flag indicates that no
DW_TAG_call_site entries are missing for the subprogram entry.  If the
DW_AT_all_call_sites 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
the subprogram entry.  If the DW_AT_all_source_call_sites 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.

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.

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.

Tracking call sites and values of parameters passed to the callees in
the debugging information can be useful for tools that would like to analyze
the callgraph of the whole program.  Together with DW_OP_entry_value opcode
it can be also useful for computing values of variables and expressions
where some value is no longer present in the current function's registers
or local stack frame, but it is known that the values are equal to some
parameter passed to the function.  Then the consumer can use unwind
information to find the caller and in the call site information sometimes
find how to compute the value passed in a particular parameter.

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.

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.

The call site entry has a DW_AT_call_site_return_pc attribute which is the return
address after the call.  The value of this attribute corresponds to the return
address computed by CFI in the called function (6.4).

On many architectures the return address 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.

The call site entry may have a DW_AT_call_site_pc attribute which is the
address of the call instruction.

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_call_site_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 the DW_AT_call_site_target_clobbered
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_call_site_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).
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.

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.  If it is not
possible to avoid registers or memory locations that might be clobbered by
the call in the expression, then the DW_TAG_call_site_value attribute should
not be provided.

The reason for the restriction is that the value of the parameter may be
needed in the middle of the callee, where the call clobbered registers or
memory might be already clobbered, and if the consumer was not assured by
the producer it can safely use those values, the consumer could not safely
use the values at all.

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_call_site_data_location
which is a location expression and DW_AT_call_site_data_value attribute
which is a DWARF expression.  The DW_AT_call_site_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_call_site_parameter
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_call_site_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_call_site_return_pc
				DW_AT_sibling
				DW_AT_tail_call
				DW_AT_type

DW_TAG_call_site_parameter	DW_AT_call_site_parameter
				DW_AT_call_site_data_value
				DW_AT_call_site_value
				DW_AT_call_site_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.


Example 1 -- 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 ! Load the 3rd argument to fn1.
  %reg1 = 6 ! Load the 2nd argument to fn1.
  %reg0 = 5 ! Load the 1st argument to fn1.
L2:
  call fn1
  %reg0 = 0 ! Load the return value from the function.
  return
L3:

fn3:
  ! Decrease stack pointer to reserve local stack frame.
  %reg3 = %reg3 - 32
  [%reg3] = %reg4 ! Save the call preserved register to stack.
  [%reg3 + 8] = %reg0 ! Preserve the x argument value.
  [%reg3 + 16] = %reg1 ! Preserve the fn4 argument value.
  %reg0 = %reg3 + 24 ! Load address of w2 as argument.
  call %reg1 ! Call fn4 (indirect call).
L6:
  %reg2 = [%reg3 + 16] ! Load the fn4 argument value.
  [%reg3 + 16] = %reg0 ! Save the result of the first call (w).
  %reg0 = %reg3 + 24 ! Load address of w2 as argument.
  call %reg2 ! Call fn4 (indirect call).
L7:
  %reg4 = %reg0 ! Save the result of the second call (v) into register.
  %reg2 = [%reg3 + 16] ! Load 3rd argument to fn2 (w).
  %reg1 = %reg4 + 1 ! Compute 2nd argument to fn2 (v + 1).
  %reg0 = 1 ! Load 1st argument to fn2.
  call fn2
L4:
  %reg2 = [%reg3 + 8] ! Load the 3rd argument to fn2 (x).
  [%reg3 + 8] = %reg0 ! Save the result of the 3rd call (z).
  %reg0 = [%reg3 + 16] ! Load the 1st argument to fn2 (w).
  %reg1 = %reg4 + %reg4 ! Compute the 2nd argument to fn2 (v * 2).
  call fn2
L5:
  %reg2 = [%reg3 + 8] ! Load the value of z from the stack.
  %reg0 = %reg0 + %reg2 ! Add result from the 4th call to it.
L8:
  %reg4 = [%reg3] ! Restore original value of call preserved register.
  %reg3 = %reg3 + 32 ! Leave stack frame.
  return

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

! Before the call to fn1 the argument a is live in the register 0.
<L1, L2> DW_OP_reg0
! Afterwards it is not, the call could have clobbered the register,
! and it is not saved in the fn2 function stack frame either, but perhaps
! can be looked up in the caller.
<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:

! Before the call to fn1 the value of q can be computed as two times
! the value of register 0.
<L1, L2> DW_OP_lit2 DW_OP_breg0 0 DW_OP_mul DW_OP_stack_value
! Afterwards it can be computed from the original value of the first
! parameter, multiplied by two.
<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_call_site_return_pc(L6) ! First indirect call to (*fn4) in fn3.
  ! The address of the call is preserved across the call in memory at
  ! stack pointer + 16 bytes.
  DW_AT_call_site_target(DW_OP_breg3 16 DW_OP_deref)
  DW_TAG_call_site_parameter
    DW_AT_location(DW_OP_reg0)
    ! Value of the first parameter is equal to stack pointer + 24 bytes.
    DW_AT_call_site_value(DW_OP_breg3 24)
DW_TAG_call_site
  DW_AT_call_site_return_pc(L7) ! Second indirect call to (*fn4) in fn3.
  ! The address of the call is not preserved across the call anywhere, but
  ! could be perhaps looked up in fn3's caller.
  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_call_site_return_pc(L4) ! 3rd call in fn3, direct call to fn2.
  DW_AT_call_site_origin(reference to fn2 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter a in fn2 subprogram)
    DW_AT_location(DW_OP_reg0)
    ! First parameter to fn2 is constant 1.
    DW_AT_call_site_value(DW_OP_lit1)
  DW_TAG_call_site_parameter
    DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter b in fn2 subprogram)
    DW_AT_location(DW_OP_reg1)
    ! Second parameter to fn2 can be computed as value of the call
    ! preserved register 4 in the fn3 function plus one.
    DW_AT_call_site_value(DW_OP_breg4 1)
  DW_TAG_call_site_parameter
    DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter c in fn2 subprogram)
    DW_AT_location(DW_OP_reg2)
    ! Third parameter's value is preserved in memory at fn3's stack pointer + 16 bytes.
    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)
    ! Value of the v1 variable can be computed as value of register 4 plus 4.
    DW_AT_location(DW_OP_breg4 4 DW_OP_stack_value)
  DW_TAG_call_site
    DW_AT_call_site_return_pc(L5) ! 4th call in fn3, direct call to fn2.
    DW_AT_call_site_target(reference to fn2 DW_TAG_subprogram)
    DW_TAG_call_site_parameter
      DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter a in fn2 subprogram)
      DW_AT_location(DW_OP_reg0)
      ! Value of the 1st argument is preserved in memory at fn3's stack pointer + 16 bytes.
      DW_AT_call_site_value(DW_OP_breg3 16 DW_OP_deref)
    DW_TAG_call_site_parameter
      DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter b in fn2 subprogram)
      DW_AT_location(DW_OP_reg1)
      ! Value of the 2nd argument can be computed using the preserved register 4 multiplied by 2.
      DW_AT_call_site_value(DW_OP_lit2 DW_OP_breg4 0 DW_OP_mul)
    DW_TAG_call_site_parameter
      DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter c in fn2 subprogram)
      DW_AT_location(DW_OP_reg2)
      ! Value of the 3rd argument is not preserved, but could be perhaps computed
      ! from the value passed fn3's caller.
      DW_AT_call_site_value(DW_OP_entry_value 1 DW_OP_reg0)


-----------------

Example 2 -- 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] ! Load value of n (passed by reference).
  %reg2 = %reg2 / 2 ! Divide by 2.
  [%reg0] = %reg2 ! Update value of n.
  call fn6 ! Call some other function.
  return

fn5:
  %reg3 = %reg3 - 8 ! Decrease stack pointer to create stack frame.
  call fn4 ! Call fn4 with the same argument by reference as fn5 has been called with.
L9:
  [%reg3] = 5 ! Pass value of 5 by reference to fn4.
  %reg0 = %reg3 ! Put address of the value 5 on the stack into 1st argument register.
  call fn4
L10:
  %reg3 = %reg3 + 8 ! Leave stack frame.
  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_call_site_return_pc(L9) ! First call to fn4.
  DW_AT_call_site_origin(reference to fn4 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter n in fn4 subprogram)
    DW_AT_location(DW_OP_reg0)
    ! The value of register 0 at the time of the call can be perhaps looked up in
    ! fn5's caller.
    DW_AT_call_site_value(DW_OP_entry_value 1 DW_OP_reg0)
    ! DW_AT_call_site_data_location(DW_OP_push_object_address) ! left out, implicit
    ! And the actual value of the parameter can be also perhaps looked up in
    ! the fn5's caller.
    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_call_site_return_pc(L10) ! Second call to fn4.
  DW_AT_call_site_origin(reference to fn4 DW_TAG_subprogram)
  DW_TAG_call_site_parameter
    DW_AT_call_site_parameter(reference to DW_TAG_formal_parameter n in fn4 subprogram)
    DW_AT_location(DW_OP_reg0)
    ! The value of register 0 at the time of the call is equal to the stack
    ! pointer value in fn5.
    DW_AT_call_site_value(DW_OP_breg3 0)
    ! DW_AT_call_site_data_location(DW_OP_push_object_address) ! left out, implicit
    ! And the value passed by reference is constant 5.
    DW_AT_call_site_data_value(DW_OP_lit5)

--

Revised: 11/19/2013
Revised: 1/21/2014
3/19/2014 -- Accepted with modifications:
  Several editorial issues will be addressed: 
    Reword section 3.8 "consumer ... sometimes ...".
    Call site attributes begine with the prefix "DW_AT_call".
    Reword use of "respectively".
    Clarify who owns TAG, inline functions.
    Add non-normative text re Return PC vs Call Site PC.
    Clarify call clobbered.
  



All logos and trademarks in this site are property of their respective owner.
The comments are property of their posters, all the rest © 2007-2013 by DWARF Standards Committee.