Conversation
jonschz
left a comment
There was a problem hiding this comment.
Very nice overall! The logic change looks sound to me. This really would have benefitted from unit tests back when I wrote the code.
I really like the cvdump + source code approach. Not sure if there's a good way of keeping them in sync, but the current setting (i.e. try to remember to update both when changing any one of them) will work for me. Building the cvdump files dynamically feels overkill to me.
There was a problem hiding this comment.
Maybe add a short README.md to the cvdump_sample directory, including
- how to compile these (toolchain etc.)
- how to make the
.txtfiles out of them (doesn't need to duplicate the documentation in__init__.py, but should link to it and maybe enhance it)
Co-authored-by: jonschz <17198703+jonschz@users.noreply.github.com>
Co-authored-by: jonschz <17198703+jonschz@users.noreply.github.com>
|
I rewrote a lot of the docstrings to try and express that:
Let me know what you think. There's one reference to "sibling" still in there. By that I only meant that it is another base class at the same level, as opposed to a grandparent class. |
jonschz
left a comment
There was a problem hiding this comment.
Looks good! Feel free to merge after addressing the final comments, no second re-review needed.
|
|
||
| Parent classes are embedded in the struct for the derived class instead of | ||
| copying their members instead. | ||
| By convention, the `vftable` pointer appears at offset 0 of a class with virtual functions. |
| To represent inheritance, we create the base class struct (or use one created earlier in the run) | ||
| and set its position to the offset given in the PDB fieldlist. The other option is to copy members | ||
| from the base classes with new offsets, but we don't do it this way. |
There was a problem hiding this comment.
It's good to explain that, maybe also mention why? From the top of my head, polymorphism is one of the arguments (e.g. calling void f(A a) when you have an instance of class B: A), and also that it's easier to track where each property comes from
There was a problem hiding this comment.
In terms of Ghidra, though, does it make a difference to the decompiler output? (copying the members versus embedding the structs)
| structs get the member. The effect is that C's virtual function is "merged" into A's vtable. | ||
| (This may or may not be correct and we should revisit when we create a vtable struct during import.) |
There was a problem hiding this comment.
Off-topic - I believe the way it works is that C has two vftables:
- The one inherited from A: This is where A's functions are inherited / overwritten and where C's newly introduced virtual functions go
- The one inherited from B (at offset 12): This is where B's functions are inherited / overwritten
Let's say I have a function void f(B b). If I call f(c), then a vtordisp is inserted into that function call which introduces an offset of 12. But if f calls any of B's virtual functions, it has to call the one that's overridden by C, so the overrides must take place in B's vftable within C.
In any case, let's not dwell on it, the comment is perfectly fine
Part of #106. The Ghidra importer uses the structures from the types db directly. I want to push these behind an API so we can swap out the mechanism that loads debug artifacts. But we need more tests first.
Claude created these sample .cpp files with various inheritance patterns. I compiled each one and generated the cvdump
TYPESoutput with both MSVC 4.2 and 6. (They were identical.) The docstrings and comments are all mine. One of my goals for doing this was to understand how this works and why we can't assume the location of the indirect virtual base class without reading thevbtable. (Certainly doable in a follow-up.)This corrects an "issue" where we created slim copies of base classes where this was not necessary. (I say "issue" because there was not an observable difference.) For example: if class D has base classes B and C, but only B uses virtual inheritance, we do not need a slim copy of C.