This is an archive of the discontinued LLVM Phabricator instance.

[lldb] Support lazily named classes in the Objective-C classes
ClosedPublic

Authored by JDevlieghere on Mar 24 2021, 8:14 PM.

Details

Summary

Generic classes in Swift have their name instantiated on request, since
the vast majority never need it, and it just wastes time and memory.
This results in LLDB being unable to determine the dynamic type of these
Swift objects.

The main issues is that lazily named classes are not added to the
gdb_objc_realized_classes hashtable. This means the class count in the
table doesn't change when a class is realized and LLDB doesn't know it
needs to re-parse the class info. But even if it did, the classes are
not in the hash table.

The first change in this patch is that we read
objc_debug_realized_class_generation_count and re-parse the class info
when the count changes.

The second change in this patch is that we use
objc_copyRealizedClassList (if available) to get all realized classes
from the runtime.

Unfortunately, objc_copyRealizedClassList calls _dyld_objc_class_count
in its implementation. As we know, the Objective-C parsing code might
get called before dyld is fully initialized, resulting in crashes or
even a stranded lock. Therefore we only use objc_copyRealizedClassList
when we know it's safe to do so by checking libSystemInitialized in
dyld_all_image_infos.

As a result, it's possible that the first time we read the Objective-C
runtime we are forced to use gdb_objc_realized_classes. This should be
fine, as there should be no lazily named classes at this point.
Subsequent queries will detect the change in realized class generation
count and use objc_copyRealizedClassList.

This patch keeps the old behavior when objc_copyRealizedClassList or
objc_debug_realized_class_generation_count are not available.

Diff Detail

Event Timeline

JDevlieghere requested review of this revision.Mar 24 2021, 8:14 PM
JDevlieghere created this revision.
shafik added a subscriber: shafik.Mar 25 2021, 11:15 AM
shafik added inline comments.
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
199

Is this pointer and realized_class_list always non-NULL?

201

You use unsigned int here, uint32_t next and then unsigned in the for loop. We should pick one for consistency, probably uint32_t since it is fixed width.

1589

For uint32_t we should use PRIu32 for the format.

1870–1871

For uint32_t we need to use PRIu32

JDevlieghere marked 4 inline comments as done.

Address @shafik's code review comments.

JDevlieghere added inline comments.Mar 25 2021, 12:34 PM
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
199

Yep, LLDB allocates the space and passes the pointer to the utility function.

aprantl added inline comments.Mar 25 2021, 3:33 PM
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
305

GetClassInfo is an odd name for a class. It sounds more like a function. I'm also not suggesting ClassInfoFactory :-p

309

Can this return a nullptr? If not, then this should return a reference.

317

Why does this need to be public? I thought the idea of the helper class was to hide the actual implementation?

331

Any better naming ideas?

JDevlieghere marked 4 inline comments as done.Mar 25 2021, 4:55 PM
JDevlieghere added inline comments.
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
305

I went with DynamicClassInfoExtractor. I'm planning on moving the corresponding 3 instance variables for the shared cache into a SharedCacheClassInfoExtractor in a follow up patch.

309

Yes, if we fail to create the utility function, we'll log the error and return a nullptr.

317

We need to make sure we stick to one way of updating the class info. At some point I want to move most of UpdateISAToDescriptorMapDynamic into this class, at which this no longer needs to be private. For this patch I tried to keep unrelated refactorings to a minimum.

331

Not proud of this, but I found that gdb_objc_realized_classes and objc_copyRealizedClassList are looked so similar that it was choosing between the pest and the cholera.

JDevlieghere marked 4 inline comments as done.

Address @aprantl's comments.

aprantl accepted this revision.Mar 26 2021, 12:01 PM

I'm planning on moving the corresponding 3 instance variables for the shared cache into a SharedCacheClassInfoExtractor in a follow up patch.

LGTM as an intermediate step.

This revision is now accepted and ready to land.Mar 26 2021, 12:01 PM
This revision was landed with ongoing or failed builds.Mar 26 2021, 1:34 PM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptMar 26 2021, 1:34 PM