astrelsky / Ghidra-Cpp-Class-Analyzer

Ghidra C++ Class and Run Time Type Information Analyzer
MIT License
633 stars 46 forks source link

`UnresolvedClassTypeInfoException`: Unable to locate archived data #58

Closed kevinhartman closed 2 years ago

kevinhartman commented 2 years ago
Unable to locate archived data for MWF::ObjActiveBase::typeinfo
ghidra.app.cmd.data.rtti.gcc.UnresolvedClassTypeInfoException: Unable to locate archived data for MWF::ObjActiveBase::typeinfo
    at cppclassanalyzer.plugin.ClassTypeInfoManagerPlugin.getExternalClassTypeInfo(ClassTypeInfoManagerPlugin.java:331)
    at cppclassanalyzer.data.manager.ItaniumAbiClassTypeInfoManager.getExternalClassTypeInfo(ItaniumAbiClassTypeInfoManager.java:77)
    at ghidra.app.cmd.data.rtti.gcc.typeinfo.AbstractSiClassTypeInfoModel.getParentModels(AbstractSiClassTypeInfoModel.java:42)
    at ghidra.app.cmd.data.rtti.gcc.typeinfo.SiClassTypeInfoModel.getParentModels(SiClassTypeInfoModel.java:15)
    at ghidra.app.cmd.data.rtti.gcc.typeinfo.AbstractSiClassTypeInfoModel.getVirtualParents(AbstractSiClassTypeInfoModel.java:47)
    at ghidra.app.cmd.data.rtti.gcc.typeinfo.SiClassTypeInfoModel.getVirtualParents(SiClassTypeInfoModel.java:15)
    at cppclassanalyzer.data.typeinfo.GnuClassTypeInfoDB.fillModelData(GnuClassTypeInfoDB.java:272)
    at cppclassanalyzer.data.typeinfo.AbstractClassTypeInfoDB.<init>(AbstractClassTypeInfoDB.java:67)
    at cppclassanalyzer.data.typeinfo.GnuClassTypeInfoDB.<init>(GnuClassTypeInfoDB.java:49)
    at cppclassanalyzer.data.manager.ItaniumAbiClassTypeInfoManager$GnuRttiRecordWorker.buildType(ItaniumAbiClassTypeInfoManager.java:308)
    at cppclassanalyzer.data.manager.ItaniumAbiClassTypeInfoManager$GnuRttiRecordWorker.buildType(ItaniumAbiClassTypeInfoManager.java:295)
    at cppclassanalyzer.data.manager.AbstractRttiRecordWorker.resolve(AbstractRttiRecordWorker.java:143)
    at cppclassanalyzer.data.manager.ClassTypeInfoManagerDB.resolve(ClassTypeInfoManagerDB.java:401)
    at cppclassanalyzer.data.manager.ItaniumAbiClassTypeInfoManager.getTypeInfo(ItaniumAbiClassTypeInfoManager.java:59)
    at cppclassanalyzer.data.manager.ClassTypeInfoManagerDB.getType(ClassTypeInfoManagerDB.java:336)
    at cppclassanalyzer.data.manager.ClassTypeInfoManagerDB.getType(ClassTypeInfoManagerDB.java:353)
    at cppclassanalyzer.data.manager.ClassTypeInfoManagerDB.getType(ClassTypeInfoManagerDB.java:369)
    at cppclassanalyzer.decompiler.action.FillOutClassAction.isEnabledForDecompilerContext(FillOutClassAction.java:36)
    at ghidra.app.plugin.core.decompile.actions.AbstractDecompilerAction.lambda$isEnabledForContext$0(AbstractDecompilerAction.java:68)
    at ghidra.app.plugin.core.decompile.DecompilerActionContext.checkActionEnablement(DecompilerActionContext.java:147)
    at ghidra.app.plugin.core.decompile.actions.AbstractDecompilerAction.isEnabledForContext(AbstractDecompilerAction.java:67)
    at docking.ComponentPlaceholder.contextChanged(ComponentPlaceholder.java:532)
    at docking.DockingWindowManager.contextChanged(DockingWindowManager.java:2232)
    at docking.AbstractDockingTool.contextChanged(AbstractDockingTool.java:208)
    at ghidra.framework.plugintool.PluginTool.contextChanged(PluginTool.java:1433)
    at ghidra.app.plugin.core.decompile.DecompilerProvider.contextChanged(DecompilerProvider.java:675)
    at ghidra.app.plugin.core.decompile.DecompilerProvider.decompileDataChanged(DecompilerProvider.java:505)
    at ghidra.app.decompiler.component.DecompilerController.setDecompileData(DecompilerController.java:181)
    at ghidra.app.decompiler.component.DecompilerController.loadFromCache(DecompilerController.java:128)
    at ghidra.app.decompiler.component.DecompilerController.display(DecompilerController.java:105)
    at ghidra.app.plugin.core.decompile.DecompilerProvider.setLocation(DecompilerProvider.java:422)
    at ghidra.app.plugin.core.decompile.DecompilePlugin.lambda$new$0(DecompilePlugin.java:75)
    at ghidra.util.task.SwingUpdateManager.swingDoWork(SwingUpdateManager.java:108)
    at ghidra.util.task.AbstractSwingUpdateManager.swingExecutePendingWork(AbstractSwingUpdateManager.java:338)
    at ghidra.util.task.AbstractSwingUpdateManager.timerCallback(AbstractSwingUpdateManager.java:287)
    at ghidra.util.task.AbstractSwingUpdateManager.lambda$new$0(AbstractSwingUpdateManager.java:131)
    at java.desktop/javax.swing.Timer.fireActionPerformed(Timer.java:317)
    at java.desktop/javax.swing.Timer$DoPostEvent.run(Timer.java:249)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

I'm getting this exception when clicking anywhere in a particular function, which comes up as a modal dialog. This unfortunately makes it impossible to work on the function.

Any ideas for how I can work around this?

I'm also wondering if I'm doing something wrong with my workflow that may have led to this. I have multiple .so files that are all part of the same Ghidra project. These libraries inherit classes from each other in some cases, so presumably there's RTTI dependencies between them. I saw a note about this in the readme, but I don't quite understand how to handle this. Am I to open all .so files in the project and analyze them with the RTTI analyzers in dependency order?

Also, what happens if you rerun the RTTI analyzers? Will they overwrite data types you've already worked on? Under what circumstances should they be rerun?

Let me know if there's any more info I can provide to help. Thanks!

astrelsky commented 2 years ago

That exception is really just there to punt in a situation where I can't proceed and need to go pretty far back. It's not supposed to show the stack trace and should just warn you about it. It looks like I forgot about this situation when I added the decompiler actions. In this case it won't even warn you as it is the same warning you should have seen after analysis.

Rerunning rtti-analysis will modify datatypes you've working on. It occurs when the structure is repaired to include the base types and virtual base classes. Special care was taken to not remove/replace any user defined fields but I think it can still happen if a field actually belongs in a base class.

The RTTI dependency problem was a real headache to solve. The only other solution I could come up with was to open the file if it was in the ghidra project and grab the needed data but I felt like that was just a really bad idea. The most commonly seen culprit is std::exception because it is in the libstdc++*.so (I don't remember where I was going with that...).

I don't think you need to run them in dependency order, specially since you are repeatedly encountering this exception. Once the necessary data is resolved it gets stored in the database.

I'll put in a patch for the decompiler action in a bit. I feel like there is a question I still haven't answered and if there was I'll come back to it.

7cd11f73795d1bed18f75241cd612054945445f4 should fix the exception problem.

kevinhartman commented 2 years ago

Okay great, thanks a lot for the help! I'll have to build from source and reinstall the plugin.

Good to know that the types are not just simply deleted and recreated if the analyzer is re-run. Hopefully a base class of incomplete size (e.g. size 0) won't overwrite a fleshed-out subclass type's fields.

I think I still don't understand exactly what the approach is we should take to handle dynamic RTTI. I have around 20 .so files I'm analyzing that share types, each of which have some base classes that are subclassed from others. What would I need to do to get the RTTI analyzer to see everything at once? Perhaps this is further complicated by the demangler adding class types as well.

astrelsky commented 2 years ago

I think I still don't understand exactly what the approach is we should take to handle dynamic RTTI. I have around 20 .so files I'm analyzing that share types, each of which have some base classes that are subclassed from others. What would I need to do to get the RTTI analyzer to see everything at once? Perhaps this is further complicated by the demangler adding class types as well.

Create a project archive in the ClassTypeInfo tree (the tree that appears when clicking the c++ toolbar icon). Then analyze the libraries and copy the libraries program node into the project archive node. I've never had more than one rtti dependency before. It's definitely going to be tedious.

I think it explicitly handles the empty base optimization cases and it shouldn't replace anything with an empty class. If it does please let me know. Most of the problems due to ebo will go away with 10.2 as the decompiler finally has union support and I can cram all the base classes and the correct vptr into a union.

kevinhartman commented 2 years ago

Most of the problems due to ebo will go away with 10.2 as the decompiler finally has union support

That should be nice! Fingers crossed that there will be an easy way to rerun analysis to unionize the vtable types. I see there is currently some union support in Ghidra. What exactly is coming in 10.2?

Create a project archive in the ClassTypeInfo tree (the tree that appears when clicking the c++ toolbar icon).

I noticed that when I open multiple programs in one Ghidra session, all of the programs already show up in the ClassTypeInfo tree. I tried doing this and then rerunning analysis, but it didn't seem to pick up the dynamic classes. I believe some of my types were overwritten as well, so I ended up restoring to a backup I made just beforehand.

This issue can probably be closed FWIW, since the fix for the original issue is merged. Perhaps you might consider enabling GitHub Discussions for this project, but I imagine you've already considered this.

astrelsky commented 2 years ago

Most of the problems due to ebo will go away with 10.2 as the decompiler finally has union support

That should be nice! Fingers crossed that there will be an easy way to rerun analysis to unionize the vtable types. I see there is currently some union support in Ghidra. What exactly is coming in 10.2?

Create a project archive in the ClassTypeInfo tree (the tree that appears when clicking the c++ toolbar icon).

I noticed that when I open multiple programs in one Ghidra session, all of the programs already show up in the ClassTypeInfo tree. I tried doing this and then rerunning analysis, but it didn't seem to pick up the dynamic classes. I believe some of my types were overwritten as well, so I ended up restoring to a backup I made just beforehand.

This issue can probably be closed FWIW, since the fix for the original issue is merged. Perhaps you might consider enabling GitHub Discussions for this project, but I imagine you've already considered this.

I'm aware of the multiple archives showing, I just haven't figured out or bothered figuring out how to hide the archive node. Each manager for a program is directly tied to it just like a DataTypeManager and analysis on another program shouldn't have any effect on it.

As for discussions... 🤦‍♂️ I saw the tab available and didn't realize I had to enable them. Mentioning it prompted me to click into the tab and I do indeed need to enable it. It should be enabled now even though I canceled the stupid announcement one it wanted me to make.

I tend to avoid closing issues myself because I've been informed that when I close it manually or by auto linking the issue author can't re-open it.