[lldb-dev] [Reproducers] SBReproducer RFC

Pavel Labath via lldb-dev lldb-dev at lists.llvm.org
Wed Jan 9 05:06:03 PST 2019


On 08/01/2019 21:57, Jonas Devlieghere wrote:
> Before I got around to coding this up I realized you can't take the 
> address of constructors in C++, so the function address won't work as an 
> identifier.
> 

You gave up way too easily. :P

I realized that constructors are going to be tricky, but I didn't want 
to dive into those details until I knew if you liked the general idea. 
The most important thing to realize here is that for the identifier 
thingy to work, you don't actually need to use the address of that 
method/constructor as the identifier. It is sufficient to have something 
that can be deterministically computed from the function. Then you can 
use the address of *that* as the identifier.

I've created a very simple prototype <https://godbolt.org/z/_xDt5r>, 
where I do just that. The way I handle constructors there is that I 
create a special class template (construct), whose instantiations are 
going to be unique for each constructor (I achieve that by making the 
class name and the constructor argument types the template parameters of 
that function). Then I can take the address of the static member 
function inside this class (&construct<class, arguments...>::doit), and 
use *that* as the ID.

As a nice side-effect, the "doit" method actually does invoke the 
constructor in question, so I can also use that in the replay code to 
treat constructors like any other method that returns an object.

I also do the same thing for (non-static) member functions via the 
"invoke" template, because even though it is possible to take the 
address of those, it is very hard to do anything else with the retrieved 
pointer. So the effect of this that in the rest of the code, I only have 
to work with free functions, as both constructors and member functions 
are converted into equivalent free functions. I haven't tried to handle 
destructors yet, but I don't think those should pose any problems that 
we haven't encountered already.

The example also show how you can use templates to automatically 
generate replay code for "simple" (i.e. those where you can 
(de)serialize each argument independently) functions, and then uses that 
to record/replay a very simple API.

You can see it in action like this:
$ g++ a.cc  # compile
$ ./a.out 2>/tmp/recording # generate the recording
SBFoo 47 42
Method 1 2
Static 10 11
$ cat /tmp/recording
0  # ID of the constructor
47 # constructor arg 1
42 # constructor arg 2
0x7ffd74d9a0f7 # constructor result
1  # id of SBFoo::Method
0x7ffd74d9a0f7 # this
1  # arg 1
2  # arg 2
2  # id of SBFoo::Static
10 # arg 1
11 # arg 2
$ ./a.out 1 < /tmp/recording # replay the recording
SBFoo 47 42
SBFoo 42 47
Method 1 2
Static 10 11

Note that when replaying the SBFoo constructor is called twice. This is 
because this code does not attempt to track the object instances in any 
way... it just creates a new one each time. This obviously needs to be 
fixed, but that's independent of the function ID issue.

hope you find that useful,
pl


More information about the lldb-dev mailing list