![]() |
|
![]() |
| Ok yeah, of course. I'd even argue that cross platform debuggers are not a thing to be desired. Too much low level integration with the operating system is needed when implementing one. |
![]() |
| Interestingly gdb (and in turn rr) has some limited support for debugging python. At least you can get a python backtrace, but I didn't have success in setting pyhton breakpoints. |
![]() |
| From the perspective of an rr maintainer, Sid's work was good and we were supportive of it. The main issues with migrating to that as the "blessed" version are that 1) rr has accumulated a decade of very hairy fixes for crazy kernel/process behavior that we feared could be lost during a port and 2) there's a closed source project (remix[0]) built on top of rr that would have needed to be ported too.
[0] https://robert.ocallahan.org/2020/12/rr-remix-efficient-repl... |
![]() |
| C++20 added `[[no_unique_address]]`, which lets a `std::is_empty` field alias another field, so long as there is only 1 field of that `is_empty` type.
https://godbolt.org/z/soczz4c76
That is, example 0 shows 8 bytes, for an `int` plus an empty field.
Example 1 shows two empty fields with the `int`, but only 4 bytes thanks to `[[no_unique_address]]`.
Example 2 unfortunately is back up to 8 bytes because we have two empty fields of the same type...
`[[no_unique_address]]` is far from perfect, and inherited the same limitations that inheriting from an empty base class had (which was the trick you had to use prior to C++20). The "no more than 1 of the same type" limitation actually forced me to keep using CRTP instead of making use of "deducing this" after adopting c++23: a `static_assert` on object size failed, because an object grew larger once an inherited instance, plus an instance inherited by a field, no longer had different template types. So, I agree that it is annoying and seems totally unnecessary, and has wasted my time; a heavy cost for a "feature" (empty objects having addresses) I have never wanted. But, I still make a lot of use of empty objects in C++ without increasing the size of any of my non-empty objects. C++20 concepts are nice for writing generic code, but (from what I have seen, not experienced) Rust traits look nice, too. |
![]() |
| Sounds like a perfect situation for a strangler pattern? Wrap or transpile the original code into a language with stronger refactoring support and the rest should become incrementally easier. |
![]() |
| umm, embedded devices without active cooling f.e. those node-b’s sitting on cellphone towers come to mind here, there can be quite a few other similar examples i can think of. |
![]() |
| I believe rr should support other languages exactly as well as gdb does; I've looked at some Rust in it once or twice at least, and IIRC even some Go; though I'm happy enough with doing assembly-level breakpoints/whatnot so I can't comment on more fancy things. Even some OpenJDK JIT! (though there of course source-mapping/stacktraces are non-existent, never mind reading variables, but even then I managed to hack together some basic source-mapping at https://github.com/dzaima/grr#java-jit; though it's rather unusable with rr due to OpenJDK's machine code dumping going directly to stdout, and general slowness).
That said, it would be very neat to have a more complete standard debugging interface across ahead-of-time-compiled code, interpreters, and JITs. And it does have some aarch64 support by now, though it'll still require a suitable CPU with necessary perf counters. |
![]() |
| It is sometimes useful with concurreny bugs, especially when used in "chaos" mode. Altough it probably masks some classes of concurrency bugs. I wonder if rr + TSAN works. |
![]() |
| This is true, but for at least some race conditions the rr "chaos mode" can help in tracking them down. Chaos mode basically randomly adjusts its thread scheduling so that it sometimes doesn't run a thread at all for a few seconds, so you run it a bunch of times until it hits the timing window for the race condition; and then when it does you debug the recording. IME it works at least sometimes but it does require that the thing you're testing doesn't take too long to fall over, since you need to do multiple recordings of it.
https://robert.ocallahan.org/2016/02/introducing-rr-chaos-mo... |
![]() |
| I havent tried Tsan with rr but msan and asan work quite well with it (it’s quite slow when doing this) but seeing the sanitizer trigger then following back what caused it to trigger is very useful. |
![]() |
| See also https://pernos.co/ which is based on rr but adds a queryable database of the whole program execution, which allows you to do things like this:
> [...] just click on the incorrect value. With full program history Pernosco can immediately explain where this value came from. The value is tracked backwards through events such as memcpys or moves in and out of registers until we reach a point where the value "originated" from, and each step in this process is displayed in the "Dataflow" panel that opens automatically. There is no need to read or understand the code and think about what might have happened, we can simply ask the debugger what did happen. |
![]() |
| And, I guess, before that, there was AMD SymNow, which was plug-in extendable and gave a plugin full control over CPU being emulated. I wonder if something like that is available somewhere? |
I've used rr very sucessfully for reverse engineering a large code base using a break on variable change combined with reverse-continue. Took the time to extract critical logic way down.