AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
const ModuleSP &objc_module_sp)
: AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp),
- m_class_info_extractor(*this), m_get_shared_cache_class_info_code(),
- m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS),
- m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_up(),
+ m_dynamic_class_info_extractor(*this),
+ m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),
m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),
m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(),
m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),
ExecutionContext &exe_ctx, Helper helper) {
switch (helper) {
case gdb_objc_realized_classes: {
- if (!m_get_class_info_code)
- m_get_class_info_code = GetClassInfoUtilityFunctionImpl(
- exe_ctx, g_get_dynamic_class_info_body,
- g_get_dynamic_class_info_name);
- return m_get_class_info_code.get();
+ if (!m_gdb_objc_realized_classes_helper.utility_function)
+ m_gdb_objc_realized_classes_helper.utility_function =
+ GetClassInfoUtilityFunctionImpl(exe_ctx,
+ g_get_dynamic_class_info_body,
+ g_get_dynamic_class_info_name);
+ return m_gdb_objc_realized_classes_helper.utility_function.get();
}
case objc_copyRealizedClassList: {
- if (!m_get_class_info2_code)
- m_get_class_info2_code = GetClassInfoUtilityFunctionImpl(
- exe_ctx, g_get_dynamic_class_info2_body,
- g_get_dynamic_class_info2_name);
- return m_get_class_info2_code.get();
+ if (!m_objc_copyRealizedClassList_helper.utility_function)
+ m_objc_copyRealizedClassList_helper.utility_function =
+ GetClassInfoUtilityFunctionImpl(exe_ctx,
+ g_get_dynamic_class_info2_body,
+ g_get_dynamic_class_info2_name);
+ return m_objc_copyRealizedClassList_helper.utility_function.get();
}
};
}
AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) {
switch (helper) {
case gdb_objc_realized_classes:
- return m_get_class_info_args;
+ return m_gdb_objc_realized_classes_helper.args;
case objc_copyRealizedClassList:
- return m_get_class_info2_args;
+ return m_objc_copyRealizedClassList_helper.args;
}
}
return DynamicClassInfoExtractor::gdb_objc_realized_classes;
}
+std::unique_ptr<UtilityFunction>
+AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
+ GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) {
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
+
+ LLDB_LOG(log, "Creating utility function {0}",
+ g_get_shared_cache_class_info_name);
+
+ TypeSystemClang *ast =
+ ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());
+ if (!ast)
+ return {};
+
+ // If the inferior objc.dylib has the class_getNameRaw function, use that in
+ // our jitted expression. Else fall back to the old class_getName.
+ static ConstString g_class_getName_symbol_name("class_getName");
+ static ConstString g_class_getNameRaw_symbol_name(
+ "objc_debug_class_getNameRaw");
+
+ ConstString class_name_getter_function_name =
+ m_runtime.HasSymbol(g_class_getNameRaw_symbol_name)
+ ? g_class_getNameRaw_symbol_name
+ : g_class_getName_symbol_name;
+
+ // Substitute in the correct class_getName / class_getNameRaw function name,
+ // concatenate the two parts of our expression text. The format string has
+ // two %s's, so provide the name twice.
+ std::string shared_class_expression;
+ llvm::raw_string_ostream(shared_class_expression)
+ << llvm::format(g_shared_cache_class_name_funcptr,
+ class_name_getter_function_name.AsCString(),
+ class_name_getter_function_name.AsCString());
+
+ shared_class_expression += g_get_shared_cache_class_info_body;
+
+ auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
+ std::move(shared_class_expression), g_get_shared_cache_class_info_name,
+ eLanguageTypeC, exe_ctx);
+
+ if (!utility_fn_or_error) {
+ LLDB_LOG_ERROR(
+ log, utility_fn_or_error.takeError(),
+ "Failed to get utility function for implementation lookup: {0}");
+ return nullptr;
+ }
+
+ // Make some types for our arguments.
+ CompilerType clang_uint32_t_type =
+ ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+ CompilerType clang_void_pointer_type =
+ ast->GetBasicType(eBasicTypeVoid).GetPointerType();
+
+ // Next make the function caller for our implementation utility function.
+ ValueList arguments;
+ Value value;
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_void_pointer_type);
+ arguments.PushValue(value);
+ arguments.PushValue(value);
+
+ value.SetValueType(Value::ValueType::Scalar);
+ value.SetCompilerType(clang_uint32_t_type);
+ arguments.PushValue(value);
+ arguments.PushValue(value);
+
+ std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
+
+ Status error;
+ utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,
+ exe_ctx.GetThreadSP(), error);
+
+ if (error.Fail()) {
+ LLDB_LOG(log,
+ "Failed to make function caller for implementation lookup: {0}.",
+ error.AsCString());
+ return {};
+ }
+
+ return utility_fn;
+}
+
+UtilityFunction *
+AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction(
+ ExecutionContext &exe_ctx) {
+ if (!m_utility_function)
+ m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx);
+ return m_utility_function.get();
+}
+
AppleObjCRuntimeV2::DescriptorMapUpdateResult
AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(
RemoteNXMapTable &hash_table) {
// Compute which helper we're going to use for this update.
const DynamicClassInfoExtractor::Helper helper =
- m_class_info_extractor.ComputeHelper();
+ m_dynamic_class_info_extractor.ComputeHelper();
// Read the total number of classes from the hash table
const uint32_t num_classes =
}
UtilityFunction *get_class_info_code =
- m_class_info_extractor.GetClassInfoUtilityFunction(exe_ctx, helper);
+ m_dynamic_class_info_extractor.GetClassInfoUtilityFunction(exe_ctx,
+ helper);
if (!get_class_info_code) {
// The callee will have already logged a useful error message.
return DescriptorMapUpdateResult::Fail();
return DescriptorMapUpdateResult::Fail();
}
- std::lock_guard<std::mutex> guard(m_class_info_extractor.GetMutex());
+ std::lock_guard<std::mutex> guard(m_dynamic_class_info_extractor.GetMutex());
// Fill in our function argument values
arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
// Write our function arguments into the process so we can run our function
if (get_class_info_function->WriteFunctionArguments(
- exe_ctx, m_class_info_extractor.GetClassInfoArgs(helper), arguments,
- diagnostics)) {
+ exe_ctx, m_dynamic_class_info_extractor.GetClassInfoArgs(helper),
+ arguments, diagnostics)) {
EvaluateExpressionOptions options;
options.SetUnwindOnError(true);
options.SetTryAllThreads(false);
// Run the function
ExpressionResults results = get_class_info_function->ExecuteFunction(
- exe_ctx, &m_class_info_extractor.GetClassInfoArgs(helper), options,
- diagnostics, return_value);
+ exe_ctx, &m_dynamic_class_info_extractor.GetClassInfoArgs(helper),
+ options, diagnostics, return_value);
if (results == eExpressionCompleted) {
// The result is the number of ClassInfo structures that were filled in
const uint32_t num_classes = 128 * 1024;
- // Make some types for our arguments
- CompilerType clang_uint32_t_type =
- ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
- CompilerType clang_void_pointer_type =
- ast->GetBasicType(eBasicTypeVoid).GetPointerType();
-
- ValueList arguments;
- FunctionCaller *get_shared_cache_class_info_function = nullptr;
-
- if (!m_get_shared_cache_class_info_code) {
- Status error;
-
- // If the inferior objc.dylib has the class_getNameRaw function,
- // use that in our jitted expression. Else fall back to the old
- // class_getName.
- static ConstString g_class_getName_symbol_name("class_getName");
- static ConstString g_class_getNameRaw_symbol_name(
- "objc_debug_class_getNameRaw");
-
- ConstString class_name_getter_function_name =
- HasSymbol(g_class_getNameRaw_symbol_name)
- ? g_class_getNameRaw_symbol_name
- : g_class_getName_symbol_name;
-
- // Substitute in the correct class_getName / class_getNameRaw function name,
- // concatenate the two parts of our expression text. The format string
- // has two %s's, so provide the name twice.
- std::string shared_class_expression;
- llvm::raw_string_ostream(shared_class_expression)
- << llvm::format(g_shared_cache_class_name_funcptr,
- class_name_getter_function_name.AsCString(),
- class_name_getter_function_name.AsCString());
-
- shared_class_expression += g_get_shared_cache_class_info_body;
-
- auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
- std::move(shared_class_expression), g_get_shared_cache_class_info_name,
- eLanguageTypeC, exe_ctx);
- if (!utility_fn_or_error) {
- LLDB_LOG_ERROR(
- log, utility_fn_or_error.takeError(),
- "Failed to get utility function for implementation lookup: {0}");
- return DescriptorMapUpdateResult::Fail();
- }
-
- m_get_shared_cache_class_info_code = std::move(*utility_fn_or_error);
-
- // Next make the function caller for our implementation utility function.
- Value value;
- value.SetValueType(Value::ValueType::Scalar);
- value.SetCompilerType(clang_void_pointer_type);
- arguments.PushValue(value);
- arguments.PushValue(value);
-
- value.SetValueType(Value::ValueType::Scalar);
- value.SetCompilerType(clang_uint32_t_type);
- arguments.PushValue(value);
- arguments.PushValue(value);
-
- get_shared_cache_class_info_function =
- m_get_shared_cache_class_info_code->MakeFunctionCaller(
- clang_uint32_t_type, arguments, thread_sp, error);
-
- if (get_shared_cache_class_info_function == nullptr)
- return DescriptorMapUpdateResult::Fail();
+ UtilityFunction *get_class_info_code =
+ m_shared_cache_class_info_extractor.GetClassInfoUtilityFunction(exe_ctx);
+ FunctionCaller *get_shared_cache_class_info_function =
+ get_class_info_code->GetFunctionCaller();
- } else {
- get_shared_cache_class_info_function =
- m_get_shared_cache_class_info_code->GetFunctionCaller();
- if (get_shared_cache_class_info_function == nullptr)
- return DescriptorMapUpdateResult::Fail();
- arguments = get_shared_cache_class_info_function->GetArgumentValues();
+ if (!get_shared_cache_class_info_function) {
+ LLDB_LOGF(log, "Failed to get implementation lookup function caller.");
+ return DescriptorMapUpdateResult::Fail();
}
+ ValueList arguments =
+ get_shared_cache_class_info_function->GetArgumentValues();
+
DiagnosticManager diagnostics;
const uint32_t class_info_byte_size = addr_size + 4;
return DescriptorMapUpdateResult::Fail();
}
- std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex);
+ std::lock_guard<std::mutex> guard(
+ m_shared_cache_class_info_extractor.GetMutex());
// Fill in our function argument values
arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
// Write our function arguments into the process so we can run our function
if (get_shared_cache_class_info_function->WriteFunctionArguments(
- exe_ctx, m_get_shared_cache_class_info_args, arguments,
- diagnostics)) {
+ exe_ctx, m_shared_cache_class_info_extractor.GetClassInfoArgs(),
+ arguments, diagnostics)) {
EvaluateExpressionOptions options;
options.SetUnwindOnError(true);
options.SetTryAllThreads(false);
options.SetTimeout(process->GetUtilityExpressionTimeout());
options.SetIsForUtilityExpr(true);
+ CompilerType clang_uint32_t_type =
+ ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
+
Value return_value;
return_value.SetValueType(Value::ValueType::Scalar);
return_value.SetCompilerType(clang_uint32_t_type);
// Run the function
ExpressionResults results =
get_shared_cache_class_info_function->ExecuteFunction(
- exe_ctx, &m_get_shared_cache_class_info_args, options, diagnostics,
- return_value);
+ exe_ctx, &m_shared_cache_class_info_extractor.GetClassInfoArgs(),
+ options, diagnostics, return_value);
if (results == eExpressionCompleted) {
// The result is the number of ClassInfo structures that were filled in
}
};
+ /// Abstraction to read the Objective-C class info.
+ class ClassInfoExtractor {
+ public:
+ ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}
+ std::mutex &GetMutex() { return m_mutex; }
+
+ protected:
+ /// The lifetime of this object is tied to that of the runtime.
+ AppleObjCRuntimeV2 &m_runtime;
+ std::mutex m_mutex;
+ };
+
/// We can read the class info from the Objective-C runtime using
/// gdb_objc_realized_classes or objc_copyRealizedClassList. The latter is
/// preferred because it includes lazily named classes, but it's not always
/// available or safe to call.
///
- /// We potentially need both for the same process,
- /// because we may need to use gdb_objc_realized_classes until dyld is
- /// initialized and then switch over to objc_copyRealizedClassList for lazily
- /// named classes.
- class DynamicClassInfoExtractor {
+ /// We potentially need both for the same process, because we may need to use
+ /// gdb_objc_realized_classes until dyld is initialized and then switch over
+ /// to objc_copyRealizedClassList for lazily named classes.
+ class DynamicClassInfoExtractor : public ClassInfoExtractor {
public:
DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
- : m_runtime(runtime) {}
+ : ClassInfoExtractor(runtime) {}
enum Helper { gdb_objc_realized_classes, objc_copyRealizedClassList };
UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
Helper helper);
lldb::addr_t &GetClassInfoArgs(Helper helper);
- std::mutex &GetMutex() { return m_mutex; }
private:
std::unique_ptr<UtilityFunction>
GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, std::string code,
std::string name);
- /// The lifetime of this object is tied to that of the runtime.
- AppleObjCRuntimeV2 &m_runtime;
- std::mutex m_mutex;
+ /// Helper to read class info using the gdb_objc_realized_classes.
+ struct gdb_objc_realized_classes_helper {
+ std::unique_ptr<UtilityFunction> utility_function;
+ lldb::addr_t args = LLDB_INVALID_ADDRESS;
+ };
+
+ /// Helper to read class info using objc_copyRealizedClassList.
+ struct objc_copyRealizedClassList_helper {
+ std::unique_ptr<UtilityFunction> utility_function;
+ lldb::addr_t args = LLDB_INVALID_ADDRESS;
+ };
+
+ gdb_objc_realized_classes_helper m_gdb_objc_realized_classes_helper;
+ objc_copyRealizedClassList_helper m_objc_copyRealizedClassList_helper;
+ };
+
+ /// Abstraction to read the Objective-C class info from the shared cache.
+ class SharedCacheClassInfoExtractor : public ClassInfoExtractor {
+ public:
+ SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
+ : ClassInfoExtractor(runtime) {}
- /// Utility function to read class info using gdb_objc_realized_classes.
- std::unique_ptr<UtilityFunction> m_get_class_info_code;
- lldb::addr_t m_get_class_info_args = LLDB_INVALID_ADDRESS;
+ UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);
+ lldb::addr_t &GetClassInfoArgs() { return m_args; }
+ std::mutex &GetMutex() { return m_mutex; }
+
+ private:
+ std::unique_ptr<UtilityFunction>
+ GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);
- /// Utility function to read class info using objc_copyRealizedClassList.
- std::unique_ptr<UtilityFunction> m_get_class_info2_code;
- lldb::addr_t m_get_class_info2_args = LLDB_INVALID_ADDRESS;
+ std::unique_ptr<UtilityFunction> m_utility_function;
+ lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
+ std::mutex m_mutex;
};
AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
lldb::ModuleSP m_objc_module_sp;
- DynamicClassInfoExtractor m_class_info_extractor;
-
- std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code;
- lldb::addr_t m_get_shared_cache_class_info_args;
- std::mutex m_get_shared_cache_class_info_args_mutex;
+ DynamicClassInfoExtractor m_dynamic_class_info_extractor;
+ SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;
std::unique_ptr<DeclVendor> m_decl_vendor_up;
lldb::addr_t m_tagged_pointer_obfuscator;