BPF List
 help / color / mirror / Atom feed
From: Eduard Zingerman <eddyz87@gmail.com>
To: Alan Maguire <alan.maguire@oracle.com>, dwarves@vger.kernel.org
Cc: andrii@kernel.org, ast@kernel.org, daniel@iogearbox.net,
	martin.lau@linux.dev, 	acme@kernel.org, ttreyer@meta.com,
	yonghong.song@linux.dev, song@kernel.org,
		john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me,
	haoluo@google.com, 	jolsa@kernel.org, qmo@kernel.org,
	ihor.solodrai@linux.dev, david.faust@oracle.com,
	 jose.marchesi@oracle.com, bpf@vger.kernel.org
Subject: Re: [RFC dwarves 3/5] dwarf_loader: Collect inline expansion location information
Date: Wed, 29 Oct 2025 11:32:22 -0700	[thread overview]
Message-ID: <9bb6431321c4fb91602e5260ef0b5989ec6e1ee8.camel@gmail.com> (raw)
In-Reply-To: <1a8cc336-f6e6-4908-aae1-ed3189219ec4@oracle.com>

On Wed, 2025-10-29 at 17:40 +0000, Alan Maguire wrote:

[...]

> > > -/* For DW_AT_location 'attr':
> > > - * - if first location is DW_OP_regXX with expected number, return the register;
> > > - *   otherwise save the register for later return
> > > - * - if location DW_OP_entry_value(DW_OP_regXX) with expected number is in the
> > > - *   list, return the register; otherwise save register for later return
> > > - * - otherwise if no register was found for locations, return -1.
> > > +/* Retrieve location information for parameter; focus on simple locations
> > > + * like constants and register values.  Support multiple registers as
> > > + * it is possible for a value (struct) to be passed via multiple registers.
> > > + * Handle edge cases like multiple instances of same location value, but
> > > + * avoid cases with large (>1 size) expressions to keep things simple.
> > > + * This covers the vast majority of cases.  The only unhandled atom is
> > > + * DW_OP_GNU_parameter_ref; future work could add that and improve
> > > + * location handling.  In practice the below supports the majority
> > > + * of parameter locations.
> > >   */
> > > -static int parameter__reg(Dwarf_Attribute *attr, int expected_reg)
> > > +static int parameter__locs(Dwarf_Die *die, Dwarf_Attribute *attr, struct parameter *parm)
> > >  {
> > > -	Dwarf_Addr base, start, end;
> > > -	Dwarf_Op *expr, *entry_ops;
> > > -	Dwarf_Attribute entry_attr;
> > > -	size_t exprlen, entry_len;
> > > +	Dwarf_Addr base, start, end, first = -1;
> > > +	Dwarf_Attribute next_attr;
> > >  	ptrdiff_t offset = 0;
> > > -	int loc_num = -1;
> > > +	Dwarf_Op *expr;
> > > +	size_t exprlen;
> > >  	int ret = -1;
> > >
> > > +	/* parameter__locs() can be called recursively, but at toplevel
> > > +	 * die is non-NULL signalling we need to look up loc/const attrs.
> > > +	 */
> > > +	if (die) {
> > > +		if (dwarf_attr(die, DW_AT_const_value, attr) != NULL) {
> > > +			parm->has_loc = 1;
> > > +			parm->optimized = 1;
> > > +			parm->locs[0].is_const = 1;
> > > +			parm->nlocs = 1;
> > > +			parm->locs[0].size = 8;
> > > +			parm->locs[0].value = attr_numeric(die, DW_AT_const_value);
> > > +			return 0;
> > > +		}
> > > +		if (dwarf_attr(die, DW_AT_location, attr) == NULL)
> > > +			return 0;
> > > +	}
> > > +
> > >  	/* use libdw__lock as dwarf_getlocation(s) has concurrency issues
> > >  	 * when libdw is not compiled with experimental --enable-thread-safety
> > >  	 */
> > >  	pthread_mutex_lock(&libdw__lock);
> > >  	while ((offset = __dwarf_getlocations(attr, offset, &base, &start, &end, &expr, &exprlen)) > 0) {
> > > -		loc_num++;
> > > +		/* We only want location info referring to start of function;
> > > +		 * assumes we get location info in address order; empirically
> > > +		 * this is the case.  Only exception is DW_OP_*entry_value
> > > +		 * location info which always refers to the value on entry.
> > > +		 */
> > > +		if (first == -1)
> >
> > <moving comments from github>
> >
> > Note: an alternative is to check that address range associated with
> > location corresponds to the starting address of the inline expansion,
> > e.g. like in [1]. I think it is a more correct approach.
> >
> > [1] https://github.com/eddyz87/inline-address-printer/blob/master/main.c#L184
> >
>
> thanks for this; I'll try tweaking it to work like this. The only thing
> I was worried about missing was DW_OP_entry_value exprs since they can I
> think be referred to from later location addresses within the function.

(I needed a few iterations to get the base address calculation right)

>
> > > +			first = start;
> > >
> > >  		/* Convert expression list (XX DW_OP_stack_value) -> (XX).
> > >  		 * DW_OP_stack_value instructs interpreter to pop current value from
> > > @@ -1216,33 +1241,154 @@ static int parameter__reg(Dwarf_Attribute *attr, int expected_reg)
> > >  		if (exprlen > 1 && expr[exprlen - 1].atom == DW_OP_stack_value)
> > >  			exprlen--;
> > >
> > > -		if (exprlen != 1)
> > > -			continue;
> > > +		if (exprlen > 1) {
> > > +			/* ignore complex exprs not at start of function,
> > > +			 * but bail if we hit a complex loc expr at the start.
> > > +			 */
> > > +			if (start != first)
> > > +				continue;
> > > +			ret = -1;
> > > +			goto out;
> > > +		}
> > >
> > >  		switch (expr->atom) {
> > > -		/* match DW_OP_regXX at first location */
> > > +		case DW_OP_deref:
> > > +			if (parm->nlocs > 0)
> > > +				parm->locs[parm->nlocs - 1].is_deref = 1;
> > > +			else
> > > +				ret = -1;
> > > +			break;
> > >  		case DW_OP_reg0 ... DW_OP_reg31:
> > > -			if (loc_num != 0)
> > > +			if (start != first || parm->nlocs > 1)
> > > +				break;
> > > +			/* avoid duplicate location value */
> > > +			if (parm->nlocs > 0 && parm->locs[parm->nlocs - 1].reg ==
> > > +					       (expr->atom - DW_OP_reg0))
> > > +				break;
> > > +			parm->locs[parm->nlocs].reg = expr->atom - DW_OP_reg0;
> > > +			parm->locs[parm->nlocs].is_deref = 0;
> > > +			parm->locs[parm->nlocs].size = 8;
> > > +			parm->locs[parm->nlocs++].offset = 0;
> > > +			ret = 0;
> > > +			break;
> > > +		case DW_OP_fbreg:
> > > +		case DW_OP_breg0 ... DW_OP_breg31:
> > > +			if (start != first || parm->nlocs > 1)
> > >  				break;
> > > -			ret = expr->atom;
> > > -			if (ret == expected_reg)
> > > -				goto out;
> > > +			/* avoid duplicate location value */
> > > +			if (parm->nlocs > 0 && parm->locs[parm->nlocs - 1].reg ==
> > > +					       (expr->atom - DW_OP_breg0)) {
> > > +				if (parm->locs[parm->nlocs - 1].offset != expr->offset)
> > > +					ret = -1;
> > > +				break;
> > > +			}
> > > +			parm->locs[parm->nlocs].reg = expr->atom - DW_OP_breg0;
> > > +			parm->locs[parm->nlocs].is_deref = 1;
> > > +			parm->locs[parm->nlocs].size = 8;
> > > +			parm->locs[parm->nlocs++].offset = expr->offset;
> >
> > I think this should be `expr->number`:
> >
>
> Hmm, I thought the bregN values signified register + offset
> dereferences? Or are you saying the offset is stored in expr->number?

The way I read docstrings in libdw.h:

  /* One operation in a DWARF location expression.
     A location expression is an array of these.  */
  typedef struct
  {
    uint8_t atom;                 /* Operation */
    Dwarf_Word number;            /* Operand */
    Dwarf_Word number2;           /* Possible second operand */
    Dwarf_Word offset;            /* Offset in location expression */
  } Dwarf_Op;

Is that `offset` is within location expression in DWARF, and is about
format bookkeeping, not the underlying program.

Double checking this with my tool, modified to print offsets:

./include/trace/events/initcall.h:trace_initcall_start                            0xffffffff81257f15 rsp+8
  die 0x19a62 origin 0x195d1
    formal 'func'       location (breg7 0x8 (off 0x0))

Here is llvm-dwarfdump result:

0x00019a62:     DW_TAG_inlined_subroutine
                  DW_AT_abstract_origin (0x000195d1 "trace_initcall_start")
                  DW_AT_ranges  (indexed (0x22) rangelist = 0x000002ec
                     [0xffffffff81257f15, 0xffffffff81257f58)
                     [0xffffffff812580bb, 0xffffffff812580d5)
                     [0xffffffff812580f4, 0xffffffff8125817e))
                  DW_AT_call_file       ("/home/ezingerman/bpf-next/init/main.c")
                  DW_AT_call_line       (1282)
                  DW_AT_call_column     (2)

So these seem to agree.

  reply	other threads:[~2025-10-29 18:32 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-24  7:33 [RFC dwarves 0/5] pahole: support BTF inline encoding Alan Maguire
2025-10-24  7:33 ` [RFC dwarves 1/5] dwarf_loader: Add parameters list to inlined expansion Alan Maguire
2025-10-24  7:33 ` [RFC dwarves 2/5] dwarf_loader: Add name to inline expansion Alan Maguire
2025-10-24  7:33 ` [RFC dwarves 3/5] dwarf_loader: Collect inline expansion location information Alan Maguire
2025-10-24 17:55   ` Eduard Zingerman
2025-10-29 17:40     ` Alan Maguire
2025-10-29 18:32       ` Eduard Zingerman [this message]
2025-10-29 18:46         ` Alan Maguire
2025-10-24  7:33 ` [RFC dwarves 4/5] btf_encoder: Support encoding of inline " Alan Maguire
2025-10-24 18:04   ` Eduard Zingerman
2025-10-24  7:33 ` [RFC dwarves 5/5] pahole: Support inline encoding with inline[.extra] BTF feature Alan Maguire

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9bb6431321c4fb91602e5260ef0b5989ec6e1ee8.camel@gmail.com \
    --to=eddyz87@gmail.com \
    --cc=acme@kernel.org \
    --cc=alan.maguire@oracle.com \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=david.faust@oracle.com \
    --cc=dwarves@vger.kernel.org \
    --cc=haoluo@google.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=john.fastabend@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=jose.marchesi@oracle.com \
    --cc=kpsingh@kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=qmo@kernel.org \
    --cc=sdf@fomichev.me \
    --cc=song@kernel.org \
    --cc=ttreyer@meta.com \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox