Live data from Hacker News

rr – record and replay debugger for C/C++

rr-project.org

101–110 of 134 posts

Re: rr – record and replay debugger for C/C++

#101

Is it truly only for C/C++? My limited understanding says a debugger needs: a list of symbols (.pdb files on windows, can't remember what they are on linux), understanding of syscalls and a few other similar things. I thought they don't care too much what generated the binaries they are debugging (obviously as long as it's native code). Doesn't rr work with other languages like rust, zig, odin, nim, and similar ones?…

I use it with Zig. It's pretty handy in conjunction with Zig's allocator because it writes 0xaa bytes upon free and doesn't reuse addresses, so it very likely causes a crash, then you can put a watchpoint on the memory and rewind to the point where it got freed.

Re: rr – record and replay debugger for C/C++

#102
post #94

GDBs built-in reverse debugging: https://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial I assume rr provides more features and flexibility. Anyway I want to mention that GDB itself can already reverse debug for some time now.

rr predates the one in gdb if I am not mistaken

Actually the gdb implementation predates rr, but (as an rr maintainer) I have to say that it is vastly inferior to rr. It's about 1000x slower than rr, and can't record across system calls or multiple threads or processes. It's so limited it's really a different feature.

Re: rr – record and replay debugger for C/C++

#103
post #15
post #10

Earlier quoted context omitted.

Chaos mode is an option when invoking rr that can expose some concurrency issues. Basically it switches which thread is executing a bunch to try and simulate multiple cores executing. It has found some race conditions for me but it’s of course limited

Unfortunately that only works for large-scale races, and not, say, one instruction interleaving with another one on another thread without proper synchronization. -fsanitize=thread probably works for that though (and of course you could then combine said sanitizer with rr to some effect probably).

One option would be to combine chaos mode with a dynamic race detector to try to focus chaos mode on specific fine-grained races. Someone should try that as a research project. Not really the same thing as rr + TSAN.

There's still the fundamental limitation that rr won't help you with weak memory orderings.

Re: rr – record and replay debugger for C/C++

#104
post #94

GDBs built-in reverse debugging: https://www.sourceware.org/gdb/wiki/ProcessRecord/Tutorial I assume rr provides more features and flexibility. Anyway I want to mention that GDB itself can already reverse debug for some time now.

rr predates the one in gdb if I am not mistaken

rr was introduced in 2014 [1].

gdb reverse debugging was introduced in 2009 [2].

You can see a fairly comprehensive history of time travel debugging here [3].

Not to say the built-in gdb reverse debugging was any good. It had (has?) like 1,000,000% overhead which is basically unusable. At least some implementations in the history that were introduced earlier only had ~1,000% overhead or less in general. Yes, a literal 1,000x overhead difference.

[1] https://robert.ocallahan.org/2014/03/introducing-rr.html

[2] https://www.sourceware.org/gdb/wiki/ReverseDebug

[3] https://jakob.engbloms.se/archives/1564

Re: rr – record and replay debugger for C/C++

#105
post #86

Earlier quoted context omitted.

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 em…

It's probably mean for me to say "empty type" to C++ people because of course just as std::move doesn't move likewise std::is_empty doesn't detect empty types. It can't because C++ doesn't have any. You may need to sit down. An empty type has no values. Not one value, like the unit type which C++ makes a poor job of as you explain, but no values. None at all. Because it has no values we will never be called upon to s…

Help me out here.

What is this empty type for? Could you provide an old man with a nice concrete example of this in action? I've used empty types in C++ to mark the end of recursive templates - which I used implement typelists before variadic templates were available.

But then you mention being unable to call functions which take an empty type as a parameter. At which point I cease to understand the purpose.

Re: rr – record and replay debugger for C/C++

#106

Is it truly only for C/C++? My limited understanding says a debugger needs: a list of symbols (.pdb files on windows, can't remember what they are on linux), understanding of syscalls and a few other similar things. I thought they don't care too much what generated the binaries they are debugging (obviously as long as it's native code). Doesn't rr work with other languages like rust, zig, odin, nim, and similar ones?…

I use it with Zig. It's pretty handy in conjunction with Zig's allocator because it writes 0xaa bytes upon free and doesn't reuse addresses, so it very likely causes a crash, then you can put a watchpoint on the memory and rewind to the point where it got freed.

That sounds really neat, is there more information on this?

*Edit

Found this, https://zig.news/david_vanderson/using-rr-to-quickly-debug-m...

Re: rr – record and replay debugger for C/C++

#108
post #86

Earlier quoted context omitted.

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 em…

It's probably mean for me to say "empty type" to C++ people because of course just as std::move doesn't move likewise std::is_empty doesn't detect empty types. It can't because C++ doesn't have any. You may need to sit down. An empty type has no values. Not one value, like the unit type which C++ makes a poor job of as you explain, but no values. None at all. Because it has no values we will never be called upon to s…

void is an empty type in C++. It's less useful than it could be, but it does exist.

Re: rr – record and replay debugger for C/C++

#109

Earlier quoted context omitted.

It's probably mean for me to say "empty type" to C++ people because of course just as std::move doesn't move likewise std::is_empty doesn't detect empty types. It can't because C++ doesn't have any. You may need to sit down. An empty type has no values. Not one value, like the unit type which C++ makes a poor job of as you explain, but no values. None at all. Because it has no values we will never be called upon to s…

Help me out here. What is this empty type for? Could you provide an old man with a nice concrete example of this in action? I've used empty types in C++ to mark the end of recursive templates - which I used implement typelists before variadic templates were available. But then you mention being unable to call functions which take an empty type as a parameter. At which point I cease to understand the purpose.

[deleted]

Re: rr – record and replay debugger for C/C++

#110

Earlier quoted context omitted.

It's probably mean for me to say "empty type" to C++ people because of course just as std::move doesn't move likewise std::is_empty doesn't detect empty types. It can't because C++ doesn't have any. You may need to sit down. An empty type has no values. Not one value, like the unit type which C++ makes a poor job of as you explain, but no values. None at all. Because it has no values we will never be called upon to s…

Help me out here. What is this empty type for? Could you provide an old man with a nice concrete example of this in action? I've used empty types in C++ to mark the end of recursive templates - which I used implement typelists before variadic templates were available. But then you mention being unable to call functions which take an empty type as a parameter. At which point I cease to understand the purpose.

I don't know that I'll be able to convince you but I'll give a couple of examples.

What is the type of the expression "return x" ? Rust says that's ! pronounced Never, an empty type. This expression never had a value, control flow diverges.

So this means we can just use simple type arithmetic to decide that a branch which returns contributed nothing to the type of the expression - it has no possible value. This wasn't a special case, it's just type arithmetic.

Ok, lets introduce another. Rust has a suite of conversion traits. From, Into, TryFrom and TryInto. They're chained, so if I implement From for Doodad, everybody gets the three other implied conversions. But the Try conversions are potentially fallible, hence the word Try. So they have an error type. Generic Code handling the Error type of potentially failing conversion will thus be written, even if in some cases the conversion undertaken chained back to my From code. But wait, that conversation can't fail! Sure enough the chained TryFrom and TryInto produced will have the error type Infallible, which is an Empty Type.

So the compiler can trim all the error handling code, it depends upon this value which we know can't exist, therefore it never executes.

Post reply on HN