-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a C API nwind_backtrace
around the local unwind API
#37
base: master
Are you sure you want to change the base?
Conversation
See also: koute/not-perf#37 This is supposedly faster. tst_trace works, which is good, but trying to use a heaptrack build with this API on the multi threaded test crashes: ``` RUST_BACKTRACE=full ./bin/heaptrack --debug --record-only --raw ./tests/manual/threaded heaptrack output will be written to "/home/milian/projects/src/heaptrack/build-nwind/heaptrack.threaded.68148.raw.zst" starting application in GDB, this might take some time... Reading symbols from ./tests/manual/threaded... Starting program: /home/milian/projects/src/heaptrack/build-nwind/tests/manual/threaded [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". [New Thread 0x7ffff73ff6c0 (LWP 68207)] thread '<unnamed>' panicked at 'assertion failed: !duplicate_matches', nwind/src/address_space.rs:929:5 stack backtrace: 0: 0x7ffff7676e0a - std::backtrace_rs::backtrace::libunwind::trace::h9a6b80bbf328ba5d at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5 1: 0x7ffff7676e0a - std::backtrace_rs::backtrace::trace_unsynchronized::hd162ec543a11886b at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 2: 0x7ffff7676e0a - std::sys_common::backtrace::_print_fmt::h78a5099be12f51a6 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:65:5 3: 0x7ffff7676e0a - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::ha1c5390454d74f71 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:44:22 4: 0x7ffff7696e6f - core::fmt::write::h9ffde816c577717b at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/fmt/mod.rs:1254:17 5: 0x7ffff7674745 - std::io::Write::write_fmt::h88186074961638e4 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/io/mod.rs:1698:15 6: 0x7ffff7676bd5 - std::sys_common::backtrace::_print::h184198273ed08d59 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:47:5 7: 0x7ffff7676bd5 - std::sys_common::backtrace::print::h1b4d8e7add699453 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:34:9 8: 0x7ffff7677f6e - std::panicking::default_hook::{{closure}}::h393bcea75423915a at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:269:22 9: 0x7ffff7677d15 - std::panicking::default_hook::h48c64f31d8b3fd03 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:288:9 10: 0x7ffff767852e - std::panicking::rust_panic_with_hook::hafdc493a79370062 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:691:13 11: 0x7ffff76783e2 - std::panicking::begin_panic_handler::{{closure}}::h0a64bc82e36bedc7 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:580:13 12: 0x7ffff7677276 - std::sys_common::backtrace::__rust_end_short_backtrace::hc203444fb7416a16 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:150:18 13: 0x7ffff7678182 - rust_begin_unwind at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5 14: 0x7ffff76946d3 - core::panicking::panic_fmt::h0f6ef0178afce4f2 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14 15: 0x7ffff769476d - core::panicking::panic::h0ead933cb8f56d66 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:117:5 16: 0x7ffff750c587 - nwind::address_space::match_mapping::h571f20ecd5df2ae9 at /home/milian/projects/src/not-perf/nwind/src/address_space.rs:929:5 17: 0x7ffff74f8703 - nwind::address_space::reload::h7bdbef3c4ecee369 at /home/milian/projects/src/not-perf/nwind/src/address_space.rs:1098:34 18: 0x7ffff759a769 - nwind::local_unwinding::LocalAddressSpace::reload::h3b5f5e2abb8bcbde at /home/milian/projects/src/not-perf/nwind/src/local_unwinding.rs:738:9 19: 0x7ffff759a399 - nwind::local_unwinding::LocalAddressSpace::new_with_opts::hc3923e5b6a30003f at /home/milian/projects/src/not-perf/nwind/src/local_unwinding.rs:715:9 20: 0x7ffff749c633 - nwind_create_address_space at /home/milian/projects/src/not-perf/nwind-capi/src/lib.rs:58:29 21: 0x7ffff7fbe84a - AddressSpace at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:21:44 22: 0x7ffff7fbe84a - addressSpace at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:36:25 23: 0x7ffff7fbe916 - _ZN5Trace6unwindEPPv at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:87:27 24: 0x7ffff7fbda1a - _ZN5Trace4fillEi at /home/milian/projects/src/heaptrack/src/track/trace.h:47:26 25: 0x7ffff7fbda1a - heaptrack_malloc at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:879:19 26: 0x7ffff7fb9d98 - malloc at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:214:21 27: 0x7ffff7cac4fb - pool at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:235:30 28: 0x7ffff7cac4fb - __static_initialization_and_destruction_0 at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:373:8 29: 0x7ffff7cac4fb - _GLOBAL__sub_I_eh_alloc.cc at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:456:1 30: 0x7ffff7fcf0fe - <unknown> 31: 0x7ffff7fcf1ec - <unknown> 32: 0x7ffff7fe5560 - <unknown> terminate called without an active exception ```
This seems to work in simple tests, but when I integrate the library into heaptrack and run it on a multi threaded application, I get a panic. Any clue what I'm doing wrong? see https://invent.kde.org/sdk/heaptrack/-/commit/56cada696feefe9b3dc7c4f0abeda7f824f29277 I'll paste the panic backtrace here again too:
|
and here with the mappings it tries to load:
|
That triggers because it finds two or more PT_LOAD matches for the same memory mapping, so it's confused as to which one to pick. It may or may not indicate a problem. In general I'm not 100% sure that I got the heuristics to match these together right in every case, and honestly there might be a better way to do this altogether, but in general it tends to work so I wasn't too motivated to dig deeper. You can try compiling in release mode, which should remove that assertion, and then it'll just pick the first match and that should probably work anyway. Until now the way I've been handling this is to add a new test every time this assertion hits, and update the heuristics so that the correct mapping is always picked, and the tests I've added in the past ensure that I haven't broken other corner cases. Could you also paste the |
2c3cb93
to
0d5abd9
Compare
In a release build, unwinding just crashes:
That's why I thought the assertion in debug mode would help to fix this. Here is the requested log for when I run into the assertion:
|
Ah, disabling the assertion and continuing in debug mode, I get a bit further and this is where it actually crashes:
|
So, the second patch fixes the crash for me, though I'm unsure if that's enough or the correct fix. With that, tracing of simple c applications seems to work. But in real-world C++ applications, I'm still seeing other crashes, such as now this one, which is less obvious to me:
Furthermore, at least in the simple benchmark I use for heaptrack (https://invent.kde.org/sdk/heaptrack/-/blob/master/tests/manual/threaded.cpp?ref_type=heads), using the
compared to the following with
I guess this example is bad for assessing the unwinding performance, as the backtraces are so easy to cache, and |
Could it be that |
I don't really have a public benchmark, but I used it on big C++ and Rust projects with hundreds of thousands lines of code and stack trace hundreds of frames deep, on multiple architectures, and it was significantly faster.
This is a very short benchmark. I do a lot of preprocessing work, and this crate is optimized for profiling long-running real-world programs with potentially deep stack traces, so for really short programs it might be slower. Also, to get the most performance benefit the
It assumes the unwinding tables are correct, and that the stack isn't smashed in any way. If either is not true then it will crash.
AFAIK that method should never actually have a null pointer passed to it, and this is probably just fixing the symptom rather than the cause.
This backtrace suggest that it's trying to access the stack slot on the stack where the return address of the frame is supposed to be stored. In general the unwinding here works; I'm using it right now to profile a Rust program, which is, like ~600k lines of code big, and it's been running for... let's see, something like ~24 days non-stop. So there must be something either with how you use the crate, or with the program you're running that's making it crash. Maybe you could try profiling some bigger Rust app and see whether this is maybe due some funny business that your C++ compiler is doing? It's often also possible to debug these kinds of problems if you enable all of the logs (with the crate feature flag) and enable trace logs, and analyze that. But that spews out a lot of logs and it usually takes quite a bit of time and effort to analyze them. Also, make sure you wrap the address space object in a read-write lock and always call |
See also: koute/not-perf#37 This is supposedly faster. tst_trace works, which is good, but trying to use a heaptrack build with this API on the multi threaded test crashes: ``` RUST_BACKTRACE=full ./bin/heaptrack --debug --record-only --raw ./tests/manual/threaded heaptrack output will be written to "/home/milian/projects/src/heaptrack/build-nwind/heaptrack.threaded.68148.raw.zst" starting application in GDB, this might take some time... Reading symbols from ./tests/manual/threaded... Starting program: /home/milian/projects/src/heaptrack/build-nwind/tests/manual/threaded [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". [New Thread 0x7ffff73ff6c0 (LWP 68207)] thread '<unnamed>' panicked at 'assertion failed: !duplicate_matches', nwind/src/address_space.rs:929:5 stack backtrace: 0: 0x7ffff7676e0a - std::backtrace_rs::backtrace::libunwind::trace::h9a6b80bbf328ba5d at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5 1: 0x7ffff7676e0a - std::backtrace_rs::backtrace::trace_unsynchronized::hd162ec543a11886b at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 2: 0x7ffff7676e0a - std::sys_common::backtrace::_print_fmt::h78a5099be12f51a6 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:65:5 3: 0x7ffff7676e0a - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::ha1c5390454d74f71 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:44:22 4: 0x7ffff7696e6f - core::fmt::write::h9ffde816c577717b at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/fmt/mod.rs:1254:17 5: 0x7ffff7674745 - std::io::Write::write_fmt::h88186074961638e4 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/io/mod.rs:1698:15 6: 0x7ffff7676bd5 - std::sys_common::backtrace::_print::h184198273ed08d59 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:47:5 7: 0x7ffff7676bd5 - std::sys_common::backtrace::print::h1b4d8e7add699453 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:34:9 8: 0x7ffff7677f6e - std::panicking::default_hook::{{closure}}::h393bcea75423915a at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:269:22 9: 0x7ffff7677d15 - std::panicking::default_hook::h48c64f31d8b3fd03 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:288:9 10: 0x7ffff767852e - std::panicking::rust_panic_with_hook::hafdc493a79370062 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:691:13 11: 0x7ffff76783e2 - std::panicking::begin_panic_handler::{{closure}}::h0a64bc82e36bedc7 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:580:13 12: 0x7ffff7677276 - std::sys_common::backtrace::__rust_end_short_backtrace::hc203444fb7416a16 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/sys_common/backtrace.rs:150:18 13: 0x7ffff7678182 - rust_begin_unwind at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5 14: 0x7ffff76946d3 - core::panicking::panic_fmt::h0f6ef0178afce4f2 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14 15: 0x7ffff769476d - core::panicking::panic::h0ead933cb8f56d66 at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:117:5 16: 0x7ffff750c587 - nwind::address_space::match_mapping::h571f20ecd5df2ae9 at /home/milian/projects/src/not-perf/nwind/src/address_space.rs:929:5 17: 0x7ffff74f8703 - nwind::address_space::reload::h7bdbef3c4ecee369 at /home/milian/projects/src/not-perf/nwind/src/address_space.rs:1098:34 18: 0x7ffff759a769 - nwind::local_unwinding::LocalAddressSpace::reload::h3b5f5e2abb8bcbde at /home/milian/projects/src/not-perf/nwind/src/local_unwinding.rs:738:9 19: 0x7ffff759a399 - nwind::local_unwinding::LocalAddressSpace::new_with_opts::hc3923e5b6a30003f at /home/milian/projects/src/not-perf/nwind/src/local_unwinding.rs:715:9 20: 0x7ffff749c633 - nwind_create_address_space at /home/milian/projects/src/not-perf/nwind-capi/src/lib.rs:58:29 21: 0x7ffff7fbe84a - AddressSpace at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:21:44 22: 0x7ffff7fbe84a - addressSpace at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:36:25 23: 0x7ffff7fbe916 - _ZN5Trace6unwindEPPv at /home/milian/projects/src/heaptrack/src/track/trace_nwind_capi.cpp:87:27 24: 0x7ffff7fbda1a - _ZN5Trace4fillEi at /home/milian/projects/src/heaptrack/src/track/trace.h:47:26 25: 0x7ffff7fbda1a - heaptrack_malloc at /home/milian/projects/src/heaptrack/src/track/libheaptrack.cpp:879:19 26: 0x7ffff7fb9d98 - malloc at /home/milian/projects/src/heaptrack/src/track/heaptrack_preload.cpp:214:21 27: 0x7ffff7cac4fb - pool at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:235:30 28: 0x7ffff7cac4fb - __static_initialization_and_destruction_0 at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:373:8 29: 0x7ffff7cac4fb - _GLOBAL__sub_I_eh_alloc.cc at /usr/src/debug/gcc/gcc/libstdc++-v3/libsupc++/eh_alloc.cc:456:1 30: 0x7ffff7fcf0fe - <unknown> 31: 0x7ffff7fcf1ec - <unknown> 32: 0x7ffff7fe5560 - <unknown> terminate called without an active exception ```
Thanks, I'll withhold benchmarking until it works reliably on real world applications.
I don't believe the stack is smashed, rather experience over the years has shown that unwinding tables are not correct I do not think
Do you have an idea what the cause might be then? Maybe it's related to the second crash down below in some way?
To make this clear: I'm not debating whether your unwinding works for you. I'm simply sharing my experience with
I'm new to the rust world, do you have a suggestion for a rust app to use? I have now tried it with But preload
Thanks, for the reminder. I think I already do that, but in my case I rely on For good measure, I will now also experimented with reloading the address space every time I unwind to see if One way or another - the C API I'm proposing here should - I hope - be acceptable on its own, or what do you think? Thanks for your input so far. |
I'm not saying that it isn't there for no reason, it's just I'm not really interested in supporting such use case for in-process local unwinding. (: If the compiler emits broken unwinding tables or the program has broken unwinding tables because e.g. there's an assembly snippet which doesn't emit them correctly then, ideally, that should be fixed. If the program is compiled with Note that essentially I'm using the same unwinding tables as C++ exception handling uses, so if the C++ exception handling works then my unwinding should always work too if it's called from within the process (so it's kinda similar to throwing an exception). And if my unwinding is broken because of broken unwinding tables then C++ exception handling will also be broken.
Sorry, no idea. They're probably related. You'd really have to dig into the logs to understand why it happens.
Yeah, I just wanted to clarify that it should work and has not e.g. bitrotted. :P (In general the project might seem dead, but that's because it's stable and it works for what I need it for, so there's no need to change it. I don't have much time and I don't get paid to work on this stuff just for the sake of it. :P)
A very random shot in the dark - maybe try comparing the compile flags between a program which crashes and one which doesn't?
Yeah, looks mostly fine. It doesn't particularly make much difference to me what the C API exactly looks like as I won't be using it myself, so whatever works for you is fine. (Although I guess there are a few nits I can post.) |
nwind-capi/include/nwind_capi.h
Outdated
*/ | ||
int nwind_backtrace(nwind_address_space *address_space, | ||
nwind_unwind_context *unwind_context, | ||
void **buffer, int size); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why int
and not size_t
?
This makes this unwinder unusable on a lot of applications that are not using Rust. To expand on that: I was mistakenly referring to I wouldn't be surprised if this is a non-issue when you are looking only on the rust world. But even there it might be problematic if you call into crates that wrap system libraries, no? Just to re-iterate: This is not about broken unwinding tables here I believe, but rather about blindly trying to do frame pointer unwinding on code that wasn't compiled with frame pointers?
🤷 all I see is
Same for me with heaptrack, except for the 10% edu time rule we have at work :)
I think it's rather the above - trying to do frame pointer unwinding in a system library for which I don't have any debug information installed.
Great, thanks for the review, I'll attend that later. |
There are two fallbacks there:
If the unwinding tables are correct (and assuming there are no other bugs) then the fallback should never trigger, I think. I used this on a big C++ application with hundreds of lines of code before I even added the fallback. Or to reiterate: I'm not assuming that frame pointers are always present. (: I'm assuming that either a) there are proper unwinding tables, or 2) frame pointers are present. Either of the two must be true. So basically the requirement is: it must be possible to always unwind to the very root of the stack (ideally through unwind tables, and if that's missing through frame pointers), or there must be a relevant entry in the unwinding table that will stop the unwinding beforehand.
One of the apps I'm regularly profiling with this has rocksdb compiled in it, which is a big C++ dependency. Works fine. Again, not saying that there are no bugs; there might as well be bugs here. But it's not necessarily a Rust vs C++ thing. If we can figure out why it crashes then of course I'd like to fix it, but it would need to be a proper fix which doesn't just make it ignore the underlying problem. Anyway, maybe you can also check if commenting out the frame pointer based unwinding makes it not crash anymore? (Because then it'll just give up instead of trying to continue.) |
This is not necessarily true for all system libraries. In my work on Another, if contrived, yet possible scenario, is some third party library that is compiled without exceptions, async unwind tables, debug info nor frame pointers. As soon as that would be encountered, the unwinder could crash - right?
Are you actively opposed to making the unwinder more fail safe in scenarios like the above? Considering that the local address space already knows the valid regions, can it not validate addresses before dereferencing them e.g.? That should be a relatively fast binary search, but obviously it would lead to a slow down for all applications. Maybe guard it behind a feature flag that I could enable only for the C-API then?
I don't think the issue is related to C++. I'll try to get some better logging in place to see if I can better pin point the exact places where it goes wrong. Also see below - this only applies to situations where the normal unwinding fails, so if your rocksdb is compiled "properly" it won't exhibit this issue.
Agreed. But I fear the "proper fix" is adding additional safety checks into the frame pointer unwinder, or not enabling that by default as a fallback. My test run where I reload the address space on every unwind finally has hit the crash too, meaning I can safely claim that it's not due to missing a reload. I'm attaching my terminal scroll back buffer as a log file, for reference
Yes, that fixes the crashes I'm seeing. For my purposes that should be another viable approach, better broken backtraces for fringe thirdparty code, rather than crashing at least :) |
This allows other projects not written in Rust to consume this unwinding library. The API is pretty basic and only offers the fundamental building blocks required for an external consumer to drive the unwinding. There is no fancy lazy global static address space, nor any thread local unwind context - configuring that is left to the consumer of this API.
In my case this seems to happen, leading to panics such as: ``` thread '<unnamed>' panicked at 'attempt to subtract with overflow', not-perf/nwind/src/frame_descriptions.rs:463:125 stack backtrace: 0: rust_begin_unwind at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/std/src/panicking.rs:578:5 1: core::panicking::panic_fmt at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:67:14 2: core::panicking::panic at /rustc/90c541806f23a127002de5b4038be731ba1458ca/library/core/src/panicking.rs:117:5 3: nwind::frame_descriptions::FrameDescriptions<E>::find_unwind_info at not-perf/nwind/src/frame_descriptions.rs:463:125 ```
This way one can opt-in to get extended debug logs when using the library, i.e. `cargo build --features "env_logger"`
I'm not convinced it should be necessary, or at least I don't have enough evidence that would convince me. Considering I use the same unwinding tables which C++ uses for exception handling let's try to enumerate the scenarios where it would be broken:
Usually when I see crashes like this it's for the last reason, where either there's a bug or I'm not handling something properly. Fundamentally I'm not opposed to handling corner cases where reasonable, but I do not want to just silently ignore buggy behavior, especially if the bug is in my code. And in this case it is probably a bug in my code. You're seeing "Cannot find a binary corresponding to address" errors, which means that it wasn't able to match a given memory mapping to a binary, which is why it didn't find any unwinding tables, which is why it was trying the fallback, which is why it crashed. So, again, the proper fix is not to gracefully handle this, but to actually fix it so that it can find the binary and access the unwinding tables, then it won't crash. Also, please remember that this is not a general purpose unwinder. Its only purpose is to be used in profiling tools. That's it. So handling every corner case under the sun is out of scope, and the number one priority is performance, and the number two priority is that it tries very hard to always return full backtraces. The only situation where I'm willing to compromise on these two is when it's unambiguously necessary, and the lack of defensive checks (like general purpose unwinders have) is very much deliberate. |
Thanks for your explanation. This is your project and you can dictate the rules. If this really turns out to be a bug somewhere else, all the better - let's see. Based on what you wrote, it sounds like the "Cannot find a binary corresponding to address" should actually be an error then, and stop the unwinding (and emit an error, not just a debug message) as it might otherwise just crash, or what do you propose? Basically: I'd rather see explicit panics / asserts instead of this kind of silent and hard to debug crashes due to invalid memory accesses. And what do you say to a mode that - optionally, via a feature flag - disables the frame pointer unwinding fallback? On all current linux distros they won't be available anyways, and your unwinder isn't used to unwindg through kernel space either, or? Hmm though potentially FP unwinding is needed for JIT frames. Actually, thinking about JIT - that could be another area where your assumptions don't hold, no? I.e. no JIT frame will have corresponding |
Ping? |
This allows other projects not written in Rust to consume this unwinding library. The API is pretty basic and only offers the fundamental building blocks required for an external consumer to drive the unwinding. There is no fancy lazy global static address space, nor any thread local unwind context - configuring that is left to the consumer of this API.
Fixes: koute/bytehound#8