Skip to content

Commit 1a7362f

Browse files
committed
When reading ObjC class table, use new SPI if it is avail
In the latest OS betas, the objc runtime has a special interface for the debugger, class_getNameRaw(), instead of the existing class_getName(), which will return class names in their raw, unmangled (in the case of swift) form. When lldb can access the unmangled names of classes, it won't need to fetch them out of the inferior process after we run our "get the objc class table" expression. If the new interface is absent (debugging a process on an older target), lldb will fall back to class_getName and reading any class names that it got back in demangled form, at a bit of a performance cost on the first expression. <rdar://problem/50688054> llvm-svn: 363103
1 parent eb2e0c3 commit 1a7362f

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr
157157
158158
)";
159159

160+
// We'll substitute in class_getName or class_getNameRaw depending
161+
// on which is present.
162+
static const char *g_shared_cache_class_name_funcptr = R"(
163+
extern "C"
164+
{
165+
const char *%s(void *objc_class);
166+
const char *(*class_name_lookup_func)(void *) = %s;
167+
}
168+
)";
169+
160170
static const char *g_get_shared_cache_class_info_name =
161171
"__lldb_apple_objc_v2_get_shared_cache_class_info";
162172
// Testing using the new C++11 raw string literals. If this breaks GCC then we
@@ -165,7 +175,6 @@ static const char *g_get_shared_cache_class_info_body = R"(
165175
166176
extern "C"
167177
{
168-
const char *class_getName(void *objc_class);
169178
size_t strlen(const char *);
170179
char *strncpy (char * s1, const char * s2, size_t n);
171180
int printf(const char * format, ...);
@@ -286,7 +295,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
286295
if (class_infos && idx < max_class_infos)
287296
{
288297
class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
289-
const char *name = class_getName (class_infos[idx].isa);
298+
const char *name = class_name_lookup_func (class_infos[idx].isa);
290299
DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
291300
// Hash the class name so we don't have to read it
292301
const char *s = name;
@@ -329,7 +338,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
329338
if (class_infos && idx < max_class_infos)
330339
{
331340
class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
332-
const char *name = class_getName (class_infos[idx].isa);
341+
const char *name = class_name_lookup_func (class_infos[idx].isa);
333342
DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
334343
// Hash the class name so we don't have to read it
335344
const char *s = name;
@@ -1589,9 +1598,46 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() {
15891598

15901599
if (!m_get_shared_cache_class_info_code) {
15911600
Status error;
1601+
1602+
// If the inferior objc.dylib has the class_getNameRaw function,
1603+
// use that in our jitted expression. Else fall back to the old
1604+
// class_getName.
1605+
static ConstString g_class_getName_symbol_name("class_getName");
1606+
static ConstString g_class_getNameRaw_symbol_name("class_getNameRaw");
1607+
ConstString class_name_getter_function_name = g_class_getName_symbol_name;
1608+
1609+
ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
1610+
if (objc_runtime) {
1611+
const ModuleList &images = process->GetTarget().GetImages();
1612+
std::lock_guard<std::recursive_mutex> guard(images.GetMutex());
1613+
for (size_t i = 0; i < images.GetSize(); ++i) {
1614+
lldb::ModuleSP mod_sp = images.GetModuleAtIndexUnlocked(i);
1615+
if (objc_runtime->IsModuleObjCLibrary(mod_sp)) {
1616+
const Symbol *symbol =
1617+
mod_sp->FindFirstSymbolWithNameAndType(g_class_getNameRaw_symbol_name,
1618+
lldb::eSymbolTypeCode);
1619+
if (symbol &&
1620+
(symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) {
1621+
class_name_getter_function_name = g_class_getNameRaw_symbol_name;
1622+
}
1623+
}
1624+
}
1625+
}
1626+
1627+
// Substitute in the correct class_getName / class_getNameRaw function name,
1628+
// concatenate the two parts of our expression text. The format string
1629+
// has two %s's, so provide the name twice.
1630+
char *class_name_func_ptr_expr = nullptr;
1631+
asprintf (&class_name_func_ptr_expr, g_shared_cache_class_name_funcptr,
1632+
class_name_getter_function_name.AsCString(),
1633+
class_name_getter_function_name.AsCString());
1634+
std::string shared_class_expression = class_name_func_ptr_expr;
1635+
shared_class_expression += g_get_shared_cache_class_info_body;
1636+
free (class_name_func_ptr_expr);
1637+
15921638
m_get_shared_cache_class_info_code.reset(
15931639
GetTargetRef().GetUtilityFunctionForLanguage(
1594-
g_get_shared_cache_class_info_body, eLanguageTypeObjC,
1640+
shared_class_expression.c_str(), eLanguageTypeObjC,
15951641
g_get_shared_cache_class_info_name, error));
15961642
if (error.Fail()) {
15971643
if (log)

0 commit comments

Comments
 (0)