| Message ID | c1c24bc3-2507-40ea-a03d-c24c6ca96021@app.fastmail.com |
|---|---|
| State | Superseded |
| Headers |
Return-Path: <elfutils-devel-bounces~patchwork=sourceware.org@sourceware.org> X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B33243857B9E for <patchwork@sourceware.org>; Wed, 20 Aug 2025 22:13:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B33243857B9E Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=serhei.io header.i=@serhei.io header.a=rsa-sha256 header.s=fm3 header.b=IyzZ8N5+; dkim=pass (2048-bit key, unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.a=rsa-sha256 header.s=fm3 header.b=dsygQCcx X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from fout-b6-smtp.messagingengine.com (fout-b6-smtp.messagingengine.com [202.12.124.149]) by sourceware.org (Postfix) with ESMTPS id 52F203858D38 for <elfutils-devel@sourceware.org>; Wed, 20 Aug 2025 22:12:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 52F203858D38 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=serhei.io Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=serhei.io ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 52F203858D38 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=202.12.124.149 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1755727970; cv=none; b=l53TclK1Za+smcNepRfcAKyvkdVTtevF3S6IcNc4I37BIs1iFxTSYvXYaPlhcikxbVEedw5oa7Ab0LSuwdK1pE/tDMOc6lUk1o6VI0InTg2eM4is1lFxkoC+Er9tf30DWG3DT+BmguSKJl/7JUQkqo/NuatMiO3soy8SlW4wgLI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1755727970; c=relaxed/simple; bh=O9EANnhmL0rGbiqSiRMQwRdyGVZW1zoZYW+MpsqW5JI=; h=DKIM-Signature:DKIM-Signature:MIME-Version:Date:From:To: Message-Id:Subject; b=JTb0cga7nvZcUDpAvfPhHOsRqd0Htq6G/e/FdjBW6i5Ua9fcZJ9JEN2rA9izDUlMAbSGTJCLj28bFMgWGwQj4YZUWSG3Ivrl8fHRy75xzTTt2K+yQxKbql0rPuvjg3PkfkyCN2FK87Ka+SR7/ATRhMjHf2zndZ9GN+7S3C5gHew= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 52F203858D38 Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id CC8961D000C0; Wed, 20 Aug 2025 18:12:49 -0400 (EDT) Received: from phl-imap-06 ([10.202.2.83]) by phl-compute-05.internal (MEProxy); Wed, 20 Aug 2025 18:12:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=serhei.io; h=cc :cc:content-transfer-encoding:content-type:content-type:date :date:from:from:in-reply-to:message-id:mime-version:reply-to :subject:subject:to:to; s=fm3; t=1755727969; x=1755814369; bh=A1 akpF76T71ns7KvJEXWHuFtLk/Nbv64X4cgwGw2lUQ=; b=IyzZ8N5+sc49JoqwV3 26TvQlO05nwQezxkRIFNkFqBd36gVpVZbcULPx6sNuEc+/Qq4nNDkN/rf2LGxR39 Te7Q2EcDvWPdHGshYlTEhABU0khNqYhwxy/+vmmmql7KWZ9UA3qkWih3ZTW2W4cB uOKBlrAQgNoq0BdfRxsfIyhh8TF3PV+NPcPI88Z0+haGVZQ1AxxdLo+s/hbq4n4f aXb/m2Nko6hBOy2/Ku1tBxelM9kw6eu9ZoGQusZB3UIH1xFhYFFnmKV/n/61TJgg YnX14U33MrZuEILu5RiRT+93/cl/CBBLsxghYQMrgVYGVLqMc3zS8E4K6n9H9gbE N+QQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-transfer-encoding :content-type:content-type:date:date:feedback-id:feedback-id :from:from:in-reply-to:message-id:mime-version:reply-to:subject :subject:to:to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; t=1755727969; x=1755814369; bh=A1akpF76T71ns7KvJEXWHuFtLk/N bv64X4cgwGw2lUQ=; b=dsygQCcx3pmjIYUNfA7d6npTohXO07QRE2naVpCd8QVR xBxqHN+HCDkkQn2+5W7bOylj8lhOo/RvcGH4kqD72yDJJFTQO/XT8MG9Cxpsg0fe Xp9q4hGMfWv4FuJN50eP7p2CgybHA6s/ziGg9y+/Cr+tfvNHuO8q/L+9XwsIbAkQ Ix20SIcA70GB2rxvcG9RcCzJR90h88trH/IkrAEWViGN7qA2HKDE4aRQEBL1YUS0 Dig5MHXS8Y4iE3S2zyWDmqnzjDBr1Hx79gk4FOqpt2/cV5g+pvIRpAFU3ujCnc50 ANWSqwXrqPZnlHQ3r52u7uXdbsQL6e9hAHYmYEwPvA== X-ME-Sender: <xms:YEimaPSk1iMt0bdpCoV92PaLHrKJLZD8ApABM6RLrzXH0BlHtLEJNQ> <xme:YEimaAyQfQu4-jZBeaJFmTmLpo0zKWjo0FtF9En8stebpLnK-biGHnC29iAZK7yHQ 6W0Lb149ymDSykYcA> X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdduheelhedvucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvfevkffutgfgsehtjeertdertddtnecuhfhrohhmpedfufgvrhhhvghi ucforghkrghrohhvfdcuoehsvghrhhgvihesshgvrhhhvghirdhioheqnecuggftrfgrth htvghrnhepfeelleeukedujefhuddutdeffeekiefgtdetfffgkedvgfegueejvdfgleff udelnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepsh gvrhhhvghisehsvghrhhgvihdrihhopdhnsggprhgtphhtthhopeegpdhmohguvgepshhm thhpohhuthdprhgtphhtthhopehmrghrkheskhhlohhmphdrohhrghdprhgtphhtthhope grmhgvrhgvhiesrhgvughhrghtrdgtohhmpdhrtghpthhtohepfhgthhgvsehrvgguhhgr thdrtghomhdprhgtphhtthhopegvlhhfuhhtihhlshdquggvvhgvlhesshhouhhrtggvfi grrhgvrdhorhhg X-ME-Proxy: <xmx:YEimaPQiB6PX24IeQfkCuK3ERM-xSBDFnae21JyFmx9r1NTYSvBJjg> <xmx:YUimaLUnSxJ0XPXEsLFJm5VdoQaOjMoApKzrrWRsVBND4L7wJH1-2A> <xmx:YUimaBaUqLnFPMsDQXBDWX1BSu2cmHfXBRCKMuUzroWZP5QMewj2tw> <xmx:YUimaB0HXMemg9dosMNLT2frPQuQmrRzmS-WsrdPDspoeTa86hvnVQ> <xmx:YUimaJ-aZ0mmQHA-QD58h9P6--i1tYEXAQdDwnQBBqpIFx8yVcJFpFj7> Feedback-ID: i572946fc:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id DCFA42400098; Wed, 20 Aug 2025 18:12:48 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface MIME-Version: 1.0 X-ThreadId: A8EubkXAj6I3 Date: Wed, 20 Aug 2025 18:12:27 -0400 From: "Serhei Makarov" <serhei@serhei.io> To: "Mark Wielaard" <mark@klomp.org>, elfutils-devel <elfutils-devel@sourceware.org> Cc: "Aaron Merey" <amerey@redhat.com>, "Frank Ch. Eigler" <fche@redhat.com> Message-Id: <c1c24bc3-2507-40ea-a03d-c24c6ca96021@app.fastmail.com> Subject: [RFC] updated api for libdwfl_stacktrace Content-Type: text/plain Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, JMQ_SPF_NEUTRAL, RCVD_IN_DNSWL_LOW, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Elfutils-devel mailing list <elfutils-devel.sourceware.org> List-Unsubscribe: <https://sourceware.org/mailman/options/elfutils-devel>, <mailto:elfutils-devel-request@sourceware.org?subject=unsubscribe> List-Archive: <https://sourceware.org/pipermail/elfutils-devel/> List-Post: <mailto:elfutils-devel@sourceware.org> List-Help: <mailto:elfutils-devel-request@sourceware.org?subject=help> List-Subscribe: <https://sourceware.org/mailman/listinfo/elfutils-devel>, <mailto:elfutils-devel-request@sourceware.org?subject=subscribe> Errors-To: elfutils-devel-bounces~patchwork=sourceware.org@sourceware.org |
| Series |
[RFC] updated api for libdwfl_stacktrace
|
|
Commit Message
Serhei Makarov
Aug. 20, 2025, 10:12 p.m. UTC
Hello,
I've been concerned to get libdwfl_stacktrace out of the weird 'experimental' limbo we put it in for the last elfutils release. To do that, we need to stabilize the API.
My full prototype of a more mature API is delayed for reasons beyond my control, but sometime in September is the likely ETA. For now I want to get people's opinions (mjw? amerey?) on the most crucial change. To avoid depending on the Linux kernel specific perf_events API, we need a dwflst_sample_getframes() function that doesn't take perf_events formatted data.
The header-only patch below illustrates the planned API change.
The base solution is for dwflst_sample_getframes() to take a pointer to regs_mapping, which, for each item in regs[] array, specifies its position in the full register file expected by the DWARF functionality. (This avoids the need to take a perf_events regs bitmap that can only be interpreted with the aid of a weird enum header buried in the linux kernel tree.)
The regs_mapping array is most likely to stay constant for an entire profiling session, so this is not a high-overhead interface.
(A bit controversially, I'm allowing n_regs_mapping != n_regs, which might smoothly deal with cases where dwflst_sample_getframes is passed a profiling data packet with malformed or truncated regs array.)
We *keep* the existing dwflst_perf_sample_getframes as a convenience variant of dwflst_sample_getframes. It clearly says 'perf', and I think it's fine to have this perf-specific API as long as it's not the *only* API.
I believe this is the most significant obstacle to turning libdwfl_stacktrace into a stable API.
mjw, do any other major issues come to mind?
(I'm sure we will find minor things to fix when we bikeshed this header, of course.)
I could add functions to generate a plausible regs_mapping for various architectures,
though I'd like a non perf_events test case for that. I've looked at BSD PmcTools,
for one example, but not 100% sure yet how to bolt libdwfl_stacktrace into it.
All the best,
Serhei
const void *stack, size_t stack_size,
const Dwarf_Word *regs, uint32_t n_regs,
Comments
Hi Serhei, On Wed, 2025-08-20 at 18:12 -0400, Serhei Makarov wrote: > The header-only patch below illustrates the planned API change. > The base solution is for dwflst_sample_getframes() to take a pointer > to regs_mapping, which, for each item in regs[] array, specifies its > position in the full register file expected by the DWARF functionality. > (This avoids the need to take a perf_events regs bitmap that can only > be interpreted with the aid of a weird enum header buried in the linux > kernel tree.) > > The regs_mapping array is most likely to stay constant for an entire > profiling session, so this is not a high-overhead interface. > (A bit controversially, I'm allowing n_regs_mapping != n_regs, which > might smoothly deal with cases where dwflst_sample_getframes is passed > a profiling data packet with malformed or truncated regs array.) > > We *keep* the existing dwflst_perf_sample_getframes as a convenience > variant of dwflst_sample_getframes. It clearly says 'perf', and I > think it's fine to have this perf-specific API as long as it's not > the *only* API. > > I believe this is the most significant obstacle to turning > libdwfl_stacktrace into a stable API. > mjw, do any other major issues come to mind? > (I'm sure we will find minor things to fix when we bikeshed this header, of course.) > > I could add functions to generate a plausible regs_mapping for various architectures, > though I'd like a non perf_events test case for that. I've looked at BSD PmcTools, > for one example, but not 100% sure yet how to bolt libdwfl_stacktrace into it. I have to admit I had to reread things for the above to make sense. So for libdwfl_stacktrace we have a Dwflst_Process_Tracker. You create a Dwflst_Process_Tracker with a set of Dwfl_Callbacks (from libdwfl.h) which sets up the find_elf, find_debuginfo and debuginfo_path. Then from this Dwflst_Process_Tracker you create new Dwfls with dwflst_tracker_dwfl_begin instead of calling dwfl_begin with a new set of callbacks yourself. You would still setup the Dwfl with dwfl_[linux_proc]_report[_*] calls. But not attach Dwfl_Thread_Callbacks state because that is done dynamically by the dwflst_*_getframes functions. Alternatively you use dwflst_tracker_find_pid to get or create a new Dwflst_Process_Tracker owned Dwfl. Then finally you call dwflst_perf_sample_getframes or the new dwflst_sample_getframes to iterate to the frames of a specific Dwfl. Which finally brings us to the topic of this email :) Could you explain again why we have the first set of arguments? Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid Some of this seems a little repetitive. Ideally I think you would just provide a Dwflst_Process_Tracker and a tid. Assuming you can easily get the pid from a tid (maybe not?). At least giving both Dwfl and pid seems redundant. Also which Elf would you provide? A Dwfl can contain multiple Dwfl_Modules each with their own associated Elf. Side note, there is dwfl_getthreads, but I assume that isn't how you iterate through threads with an Dwflst_Process_Tracker derived Dwfl? Then you get the stack (and size) and registers (as Dwarf_Words and number of regs). So we just assume this is provided by some external mechanism. And finally the n_regs_mapping which for each DWARF register number maps it to an index in the regs array. So that the callback can get a register value from the given Dwfl_Frame. I think this works, but do note that some arches have gaps in the DWARF register numbers and so might have > 100 nregs. Should the regmapping maybe be stored or set with the Dwfl or Dwflst_Process_Tracker once? Cheers, Mark > diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h b/libdwfl_stacktrace/libdw\ > fl_stacktrace.h > index b236ddc4..b8987c6f 100644 > --- a/libdwfl_stacktrace/libdwfl_stacktrace.h > +++ b/libdwfl_stacktrace/libdwfl_stacktrace.h > @@ -113,14 +113,28 @@ extern int dwflst_tracker_linux_proc_find_elf (Dwfl_Modul\ > e *mod, void **userdata > const char *module_name, Dwarf_A\ > ddr base, > char **file_name, Elf **); > > - > /* Like dwfl_thread_getframes, but iterates through the frames for a > - linux perf_events stack sample rather than a live thread. Calls > - dwfl_attach_state on DWFL, with architecture specified by ELF, ELF > - must remain valid during Dwfl lifetime. Returns zero if all frames > - have been processed by the callback, returns -1 on error, or the > - value of the callback when not DWARF_CB_OK. -1 returned on error > - will set dwfl_errno (). */ > + stack sample rather than a live thread. Calls dwfl_attach_state on > + DWFL, with architecture specified by ELF, ELF must remain vaild > + during Dwfl lifetime. Returns zero if all frames have been > + processed by the callback, returns -1 on error, or the value of the > + callback when not DWARF_CB_OK. -1 returned on error will set > + dwfl_errno (). */ > +int dwflst_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid, > + const void *stack, size_t stack_size, > + const Dwarf_Word *regs, uint32_t n_regs, > + const int *regs_mapping, uint32_t n_regs_mapping, > + int (*callback) (Dwfl_Frame *state, void *arg), > + void *arg) > + __nonnull_attribute__ (1, 5, 7, 9, 11); > + > +/* Adapts dwflst_sample_getframes to linux perf_events stack sample > + and register file data format. Calls dwfl_attach_state on DWFL, > + with architecture specified by ELF, ELF must remain valid during > + Dwfl lifetime. Returns zero if all frames have been processed by > + the callback, returns -1 on error, or the value of the callback > + when not DWARF_CB_OK. -1 returned on error will set dwfl_errno > + (). */ > int dwflst_perf_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid, > const void *stack, size_t stack_size, > const Dwarf_Word *regs, uint32_t n_regs,
Initial response from what I know, pending being actually sure about the answers. On Wed, Sep 3, 2025, at 9:51 AM, Mark Wielaard wrote: > Could you explain again why we have the first set of arguments? > Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid > Some of this seems a little repetitive. Ideally I think you would just > provide a Dwflst_Process_Tracker and a tid. Assuming you can easily get > the pid from a tid (maybe not?). At least giving both Dwfl and pid > seems redundant. Also which Elf would you provide? A Dwfl can contain > multiple Dwfl_Modules each with their own associated Elf. I'm not sure if these args should be reduced. I do know that pid is wanted by dwfl_attach_state whereas tid is wanted by dwfl_getthread_frames. Pretty sure pid is not derivable from tid, so we end up wanting both. For now the questions reduce to: * Can we drop pid and derive it from dwfl? Pretty sure no -- the Dwfl would not have that info pre-dwfl_attach_state, surely? * Does this make sense for Dwfl with multiple Dwfl_Module/Elf? Has worked perfectly well in my testing, but I'm willing to pretzel my brain to come up with the explanation why. What I really need to think about, I guess, is whether the design with dwflst_sample_getframes calling dwfl_attach_state() dynamically can be improved on, since it's quite different from the ordinary Dwfl workflow. > Side note, there is dwfl_getthreads, but I assume that isn't how you > iterate through threads with an Dwflst_Process_Tracker derived Dwfl? Correct, we're dealing with one sample at a time, and the sample corresponds to one thread at a time. So there isn't really a need to use dwfl_getthreads() iteration at any point. > Then you get the stack (and size) and registers (as Dwarf_Words and > number of regs). So we just assume this is provided by some external > mechanism. > > And finally the n_regs_mapping which for each DWARF register number > maps it to an index in the regs array. So that the callback can get a > register value from the given Dwfl_Frame. > > I think this works, but do note that some arches have gaps in the DWARF > register numbers and so might have > 100 nregs. I think it is not a problem: regs_mapping is meant to map from the small contiguous register sample to the (large, noncontiguous) DWARF register numbers, so it is a compact array of potentially large DWARF register numbers, rather than a large sparse array of small numbers. I do need to make ebl_set_initial_registers_sample work efficiently for the architectures that have a large/noncontiguous DWARF layout, but the ebl/backends setup makes this trivial to handle. > Should the regmapping maybe be stored or set with the Dwfl or > Dwflst_Process_Tracker once? That's an option. The current design allows handling a stream of data with a mix of different register files, which is a fairly theoretical need as of now.
Hi Serhei, On Wed, Aug 20, 2025 at 6:12 PM Serhei Makarov <serhei@serhei.io> wrote: > > Hello, > > I've been concerned to get libdwfl_stacktrace out of the weird 'experimental' limbo we put it in for the last elfutils release. To do that, we need to stabilize the API. > > My full prototype of a more mature API is delayed for reasons beyond my control, but sometime in September is the likely ETA. For now I want to get people's opinions (mjw? amerey?) on the most crucial change. To avoid depending on the Linux kernel specific perf_events API, we need a dwflst_sample_getframes() function that doesn't take perf_events formatted data. > > The header-only patch below illustrates the planned API change. > The base solution is for dwflst_sample_getframes() to take a pointer to regs_mapping, which, for each item in regs[] array, specifies its position in the full register file expected by the DWARF functionality. (This avoids the need to take a perf_events regs bitmap that can only be interpreted with the aid of a weird enum header buried in the linux kernel tree.) > > The regs_mapping array is most likely to stay constant for an entire profiling session, so this is not a high-overhead interface. > > (A bit controversially, I'm allowing n_regs_mapping != n_regs, which might smoothly deal with cases where dwflst_sample_getframes is passed a profiling data packet with malformed or truncated regs array.) > > We *keep* the existing dwflst_perf_sample_getframes as a convenience variant of dwflst_sample_getframes. It clearly says 'perf', and I think it's fine to have this perf-specific API as long as it's not the *only* API. I would still be concerned about needing dwflst_perf_sample_getframes_v2, _v3, etc. if the perf sample format or dwflst needs change in ways that would require API/ABI changes. The same concern also applies to the generic dwflst_sample_getframes if we decide to support a sample type that needs a different set of parameters. Instead of specifying the sample parameters as arguments to dwflst_sample_getframes, what do you think about adding an API for setting key/value pairs for the Dwflst_Process_Tracker (or related object)? Then we can always add more key/value pairs without API/ABI consequences. Something like the following: dwflst_set_tracker_attr (Dwflst_Process_tracker *tracker, dwflst_attr_type type, void *value); where dwflst_attr_type is an enum of every parameter dwflst might need and we can easily add more types over time. This would eliminate the need for dwflst_perf_sample_getframes and dwflst_sample_getframes can adapt to any future changes we might want to make. Aaron
Hi Serhei, On Wed, 2025-09-03 at 10:14 -0400, Serhei Makarov wrote: > Initial response from what I know, pending being actually sure about the answers. > > On Wed, Sep 3, 2025, at 9:51 AM, Mark Wielaard wrote: > > Could you explain again why we have the first set of arguments? > > Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid > > Some of this seems a little repetitive. Ideally I think you would just > > provide a Dwflst_Process_Tracker and a tid. Assuming you can easily get > > the pid from a tid (maybe not?). At least giving both Dwfl and pid > > seems redundant. Also which Elf would you provide? A Dwfl can contain > > multiple Dwfl_Modules each with their own associated Elf. > I'm not sure if these args should be reduced. I do know that pid is wanted by dwfl_attach_state whereas tid is wanted by dwfl_getthread_frames. Pretty sure pid is not derivable from tid, so we end up wanting both. Maybe Aaron's suggestion to use a key/value pairs like API makes sense here? > For now the questions reduce to: > * Can we drop pid and derive it from dwfl? > Pretty sure no -- the Dwfl would not have that info pre-dwfl_attach_state, surely? But if the Dwfl isn't attached, are we even interested in the samples? This might be my confusion on the ordering of events. Who/what triggers a dwflst_perf_sample_getframes call? What prevents us from requiring it is only called DWfl's with attached state? If it doesn't have a state/pid, then we just ignore it? > * Does this make sense for Dwfl with multiple Dwfl_Module/Elf? > Has worked perfectly well in my testing, but I'm willing to pretzel my brain to come up with the explanation why. My point is more that it looks like you are interested in the Elf just for the architecture. But all Dwfl_Modules in a Dwfl map to Elf with the same architecture. So normally just having the Dwfl is enough. > > And finally the n_regs_mapping which for each DWARF register number > > maps it to an index in the regs array. So that the callback can get a > > register value from the given Dwfl_Frame. > > > > I think this works, but do note that some arches have gaps in the DWARF > > register numbers and so might have > 100 nregs. > I think it is not a problem: regs_mapping is meant to map from the small contiguous register sample to the (large, noncontiguous) DWARF register numbers, > so it is a compact array of potentially large DWARF register numbers, rather than a large sparse array of small numbers. Ah, OK, I had it reverse in my head. But that makes sense, map from the register numbers to the DWARF register numbers. > > Should the regmapping maybe be stored or set with the Dwfl or > > Dwflst_Process_Tracker once? > That's an option. > The current design allows handling a stream of data with a mix of different register files, which is a fairly theoretical need as of now. I guess it is possible for 32-on-64bit arches. And I guess you could use it for emulation/jits/interpreters, but this is probably the wrong level to do that kind translation. Cheers, Mark
Hi - > [...] > Maybe Aaron's suggestion to use a key/value pairs like API makes sense > here? Or a struct containing properly named and **typed** parameters. (Coercing everything into general key/value is kind of papering over the compatibility / width / usability problem. Both caller and callee side need as much or more code that way.) - FChE
diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h b/libdwfl_stacktrace/libdw\ fl_stacktrace.h index b236ddc4..b8987c6f 100644 --- a/libdwfl_stacktrace/libdwfl_stacktrace.h +++ b/libdwfl_stacktrace/libdwfl_stacktrace.h @@ -113,14 +113,28 @@ extern int dwflst_tracker_linux_proc_find_elf (Dwfl_Modul\ e *mod, void **userdata const char *module_name, Dwarf_A\ ddr base, char **file_name, Elf **); - /* Like dwfl_thread_getframes, but iterates through the frames for a - linux perf_events stack sample rather than a live thread. Calls - dwfl_attach_state on DWFL, with architecture specified by ELF, ELF - must remain valid during Dwfl lifetime. Returns zero if all frames - have been processed by the callback, returns -1 on error, or the - value of the callback when not DWARF_CB_OK. -1 returned on error - will set dwfl_errno (). */ + stack sample rather than a live thread. Calls dwfl_attach_state on + DWFL, with architecture specified by ELF, ELF must remain vaild + during Dwfl lifetime. Returns zero if all frames have been + processed by the callback, returns -1 on error, or the value of the + callback when not DWARF_CB_OK. -1 returned on error will set + dwfl_errno (). */ +int dwflst_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid, + const void *stack, size_t stack_size, + const Dwarf_Word *regs, uint32_t n_regs, + const int *regs_mapping, uint32_t n_regs_mapping, + int (*callback) (Dwfl_Frame *state, void *arg), + void *arg) + __nonnull_attribute__ (1, 5, 7, 9, 11); + +/* Adapts dwflst_sample_getframes to linux perf_events stack sample + and register file data format. Calls dwfl_attach_state on DWFL, + with architecture specified by ELF, ELF must remain valid during + Dwfl lifetime. Returns zero if all frames have been processed by + the callback, returns -1 on error, or the value of the callback + when not DWARF_CB_OK. -1 returned on error will set dwfl_errno + (). */ int dwflst_perf_sample_getframes (Dwfl *dwfl, Elf *elf, pid_t pid, pid_t tid,