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.
next prev parent 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