diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Plugins/LanguageRuntime | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
Diffstat (limited to 'lldb/source/Plugins/LanguageRuntime')
28 files changed, 11218 insertions, 12116 deletions
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index c49feb07200..c5fe21c6eab 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -1,4 +1,5 @@ -//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- C++ -*-===// +//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- +//C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -40,579 +41,535 @@ using namespace lldb_private; static const char *vtable_demangled_prefix = "vtable for "; -bool -ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value) -{ - const bool check_cxx = true; - const bool check_objc = false; - return in_value.GetCompilerType().IsPossibleDynamicType (NULL, check_cxx, check_objc); +bool ItaniumABILanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + const bool check_cxx = true; + const bool check_objc = false; + return in_value.GetCompilerType().IsPossibleDynamicType(NULL, check_cxx, + check_objc); } -TypeAndOrName -ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr, - lldb::addr_t vtable_load_addr) -{ - if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) - { - // Find the symbol that contains the "vtable_load_addr" address - Address vtable_addr; - Target &target = m_process->GetTarget(); - if (!target.GetSectionLoadList().IsEmpty()) - { - if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, vtable_addr)) - { - // See if we have cached info for this type already - TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); - if (type_info) - return type_info; - - SymbolContext sc; - target.GetImages().ResolveSymbolContextForAddress(vtable_addr, eSymbolContextSymbol, sc); - Symbol *symbol = sc.symbol; - if (symbol != NULL) - { - const char *name = symbol->GetMangled().GetDemangledName(lldb::eLanguageTypeC_plus_plus).AsCString(); - if (name && strstr(name, vtable_demangled_prefix) == name) - { - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n", - original_ptr, - in_value.GetTypeName().GetCString(), - name); - // We are a C++ class, that's good. Get the class name and look it up: - const char *class_name = name + strlen(vtable_demangled_prefix); - type_info.SetName(class_name); - const bool exact_match = true; - TypeList class_types; - - uint32_t num_matches = 0; - // First look in the module that the vtable symbol came from - // and look for a single exact match. - llvm::DenseSet<SymbolFile *> searched_symbol_files; - if (sc.module_sp) - { - num_matches = sc.module_sp->FindTypes (sc, - ConstString(class_name), - exact_match, - 1, - searched_symbol_files, - class_types); - } - - // If we didn't find a symbol, then move on to the entire - // module list in the target and get as many unique matches - // as possible - if (num_matches == 0) - { - num_matches = target.GetImages().FindTypes(sc, ConstString(class_name), exact_match, - UINT32_MAX, searched_symbol_files, class_types); - } - - lldb::TypeSP type_sp; - if (num_matches == 0) - { - if (log) - log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr); - return TypeAndOrName(); - } - if (num_matches == 1) - { - type_sp = class_types.GetTypeAtIndex(0); - if (type_sp) - { - if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType())) - { - if (log) - log->Printf("0x%16.16" PRIx64 - ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 - "}, type-name='%s'\n", - original_ptr, in_value.GetTypeName().AsCString(), type_sp->GetID(), - type_sp->GetName().GetCString()); - type_info.SetTypeSP(type_sp); - } - } - } - else if (num_matches > 1) - { - size_t i; - if (log) - { - for (i = 0; i < num_matches; i++) - { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) - { - if (log) - log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n", - original_ptr, - in_value.GetTypeName().AsCString(), - type_sp->GetID(), - type_sp->GetName().GetCString()); - } - } - } - - for (i = 0; i < num_matches; i++) - { - type_sp = class_types.GetTypeAtIndex(i); - if (type_sp) - { - if (ClangASTContext::IsCXXClassType(type_sp->GetForwardCompilerType())) - { - if (log) - log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n", - original_ptr, - in_value.GetTypeName().AsCString(), - type_sp->GetID(), - type_sp->GetName().GetCString()); - type_info.SetTypeSP(type_sp); - } - } - } - - if (log && i == num_matches) - { - log->Printf("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic " - "types, didn't find a C++ match\n", - original_ptr, in_value.GetTypeName().AsCString()); - } - } - if (type_info) - SetDynamicTypeInfo(vtable_addr, type_info); - return type_info; - } +TypeAndOrName ItaniumABILanguageRuntime::GetTypeInfoFromVTableAddress( + ValueObject &in_value, lldb::addr_t original_ptr, + lldb::addr_t vtable_load_addr) { + if (m_process && vtable_load_addr != LLDB_INVALID_ADDRESS) { + // Find the symbol that contains the "vtable_load_addr" address + Address vtable_addr; + Target &target = m_process->GetTarget(); + if (!target.GetSectionLoadList().IsEmpty()) { + if (target.GetSectionLoadList().ResolveLoadAddress(vtable_load_addr, + vtable_addr)) { + // See if we have cached info for this type already + TypeAndOrName type_info = GetDynamicTypeInfo(vtable_addr); + if (type_info) + return type_info; + + SymbolContext sc; + target.GetImages().ResolveSymbolContextForAddress( + vtable_addr, eSymbolContextSymbol, sc); + Symbol *symbol = sc.symbol; + if (symbol != NULL) { + const char *name = + symbol->GetMangled() + .GetDemangledName(lldb::eLanguageTypeC_plus_plus) + .AsCString(); + if (name && strstr(name, vtable_demangled_prefix) == name) { + Log *log( + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("0x%16.16" PRIx64 + ": static-type = '%s' has vtable symbol '%s'\n", + original_ptr, in_value.GetTypeName().GetCString(), + name); + // We are a C++ class, that's good. Get the class name and look it + // up: + const char *class_name = name + strlen(vtable_demangled_prefix); + type_info.SetName(class_name); + const bool exact_match = true; + TypeList class_types; + + uint32_t num_matches = 0; + // First look in the module that the vtable symbol came from + // and look for a single exact match. + llvm::DenseSet<SymbolFile *> searched_symbol_files; + if (sc.module_sp) { + num_matches = sc.module_sp->FindTypes( + sc, ConstString(class_name), exact_match, 1, + searched_symbol_files, class_types); + } + + // If we didn't find a symbol, then move on to the entire + // module list in the target and get as many unique matches + // as possible + if (num_matches == 0) { + num_matches = target.GetImages().FindTypes( + sc, ConstString(class_name), exact_match, UINT32_MAX, + searched_symbol_files, class_types); + } + + lldb::TypeSP type_sp; + if (num_matches == 0) { + if (log) + log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", + original_ptr); + return TypeAndOrName(); + } + if (num_matches == 1) { + type_sp = class_types.GetTypeAtIndex(0); + if (type_sp) { + if (ClangASTContext::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + if (log) + log->Printf( + "0x%16.16" PRIx64 + ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 + "}, type-name='%s'\n", + original_ptr, in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); + } + } + } else if (num_matches > 1) { + size_t i; + if (log) { + for (i = 0; i < num_matches; i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + if (log) + log->Printf( + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types: uid={0x%" PRIx64 "}, type-name='%s'\n", + original_ptr, in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); + } } + } + + for (i = 0; i < num_matches; i++) { + type_sp = class_types.GetTypeAtIndex(i); + if (type_sp) { + if (ClangASTContext::IsCXXClassType( + type_sp->GetForwardCompilerType())) { + if (log) + log->Printf( + "0x%16.16" PRIx64 ": static-type = '%s' has multiple " + "matching dynamic types, picking " + "this one: uid={0x%" PRIx64 + "}, type-name='%s'\n", + original_ptr, in_value.GetTypeName().AsCString(), + type_sp->GetID(), type_sp->GetName().GetCString()); + type_info.SetTypeSP(type_sp); + } + } + } + + if (log && i == num_matches) { + log->Printf( + "0x%16.16" PRIx64 + ": static-type = '%s' has multiple matching dynamic " + "types, didn't find a C++ match\n", + original_ptr, in_value.GetTypeName().AsCString()); + } } + if (type_info) + SetDynamicTypeInfo(vtable_addr, type_info); + return type_info; + } } + } } - return TypeAndOrName(); + } + return TypeAndOrName(); } -bool -ItaniumABILanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &dynamic_address, - Value::ValueType &value_type) -{ - // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 - // in the object. That will point to the "address point" within the vtable (not the beginning of the - // vtable.) We can then look up the symbol containing this "address point" and that symbol's name - // demangled will contain the full class name. - // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the - // start of the value object which holds the dynamic type. - // - - class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; - - // Only a pointer or reference type can have a different dynamic and static type: - if (CouldHaveDynamicValue(in_value)) - { - // First job, pull out the address at 0 offset from the object. - AddressType address_type; - lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); - if (original_ptr == LLDB_INVALID_ADDRESS) - return false; - - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - - if (process == nullptr) - return false; - - Error error; - const lldb::addr_t vtable_address_point = process->ReadPointerFromMemory(original_ptr, error); - - if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) - { - return false; - } +bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type) { + // For Itanium, if the type has a vtable pointer in the object, it will be at + // offset 0 + // in the object. That will point to the "address point" within the vtable + // (not the beginning of the + // vtable.) We can then look up the symbol containing this "address point" + // and that symbol's name + // demangled will contain the full class name. + // The second pointer above the "address point" is the "offset_to_top". We'll + // use that to get the + // start of the value object which holds the dynamic type. + // + + class_type_or_name.Clear(); + value_type = Value::ValueType::eValueTypeScalar; + + // Only a pointer or reference type can have a different dynamic and static + // type: + if (CouldHaveDynamicValue(in_value)) { + // First job, pull out the address at 0 offset from the object. + AddressType address_type; + lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type); + if (original_ptr == LLDB_INVALID_ADDRESS) + return false; + + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + + if (process == nullptr) + return false; + + Error error; + const lldb::addr_t vtable_address_point = + process->ReadPointerFromMemory(original_ptr, error); + + if (!error.Success() || vtable_address_point == LLDB_INVALID_ADDRESS) { + return false; + } - class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, vtable_address_point); - - if (class_type_or_name) - { - TypeSP type_sp = class_type_or_name.GetTypeSP(); - // There can only be one type with a given name, - // so we've just found duplicate definitions, and this - // one will do as well as any other. - // We don't consider something to have a dynamic type if - // it is the same as the static type. So compare against - // the value we were handed. - if (type_sp) - { - if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), type_sp->GetForwardCompilerType())) - { - // The dynamic type we found was the same type, - // so we don't have a dynamic type here... - return false; - } + class_type_or_name = GetTypeInfoFromVTableAddress(in_value, original_ptr, + vtable_address_point); + + if (class_type_or_name) { + TypeSP type_sp = class_type_or_name.GetTypeSP(); + // There can only be one type with a given name, + // so we've just found duplicate definitions, and this + // one will do as well as any other. + // We don't consider something to have a dynamic type if + // it is the same as the static type. So compare against + // the value we were handed. + if (type_sp) { + if (ClangASTContext::AreTypesSame(in_value.GetCompilerType(), + type_sp->GetForwardCompilerType())) { + // The dynamic type we found was the same type, + // so we don't have a dynamic type here... + return false; + } - // The offset_to_top is two pointers above the vtable pointer. - const uint32_t addr_byte_size = process->GetAddressByteSize(); - const lldb::addr_t offset_to_top_location = vtable_address_point - 2 * addr_byte_size; - // Watch for underflow, offset_to_top_location should be less than vtable_address_point - if (offset_to_top_location >= vtable_address_point) - return false; - const int64_t offset_to_top = - process->ReadSignedIntegerFromMemory(offset_to_top_location, addr_byte_size, INT64_MIN, error); - - if (offset_to_top == INT64_MIN) - return false; - // So the dynamic type is a value that starts at offset_to_top - // above the original address. - lldb::addr_t dynamic_addr = original_ptr + offset_to_top; - if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress(dynamic_addr, dynamic_address)) - { - dynamic_address.SetRawAddress(dynamic_addr); - } - return true; - } + // The offset_to_top is two pointers above the vtable pointer. + const uint32_t addr_byte_size = process->GetAddressByteSize(); + const lldb::addr_t offset_to_top_location = + vtable_address_point - 2 * addr_byte_size; + // Watch for underflow, offset_to_top_location should be less than + // vtable_address_point + if (offset_to_top_location >= vtable_address_point) + return false; + const int64_t offset_to_top = process->ReadSignedIntegerFromMemory( + offset_to_top_location, addr_byte_size, INT64_MIN, error); + + if (offset_to_top == INT64_MIN) + return false; + // So the dynamic type is a value that starts at offset_to_top + // above the original address. + lldb::addr_t dynamic_addr = original_ptr + offset_to_top; + if (!process->GetTarget().GetSectionLoadList().ResolveLoadAddress( + dynamic_addr, dynamic_address)) { + dynamic_address.SetRawAddress(dynamic_addr); } + return true; + } } + } - return class_type_or_name.IsEmpty() == false; + return class_type_or_name.IsEmpty() == false; } -TypeAndOrName -ItaniumABILanguageRuntime::FixUpDynamicType(const TypeAndOrName& type_and_or_name, - ValueObject& static_value) -{ - CompilerType static_type(static_value.GetCompilerType()); - Flags static_type_flags(static_type.GetTypeInfo()); - - TypeAndOrName ret(type_and_or_name); - if (type_and_or_name.HasType()) - { - // The type will always be the type of the dynamic object. If our parent's type was a pointer, - // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type - // should be okay... - CompilerType orig_type = type_and_or_name.GetCompilerType(); - CompilerType corrected_type = orig_type; - if (static_type_flags.AllSet(eTypeIsPointer)) - corrected_type = orig_type.GetPointerType (); - else if (static_type_flags.AllSet(eTypeIsReference)) - corrected_type = orig_type.GetLValueReferenceType(); - ret.SetCompilerType(corrected_type); - } - else - { - // If we are here we need to adjust our dynamic type name to include the correct & or * symbol - std::string corrected_name (type_and_or_name.GetName().GetCString()); - if (static_type_flags.AllSet(eTypeIsPointer)) - corrected_name.append(" *"); - else if (static_type_flags.AllSet(eTypeIsReference)) - corrected_name.append(" &"); - // the parent type should be a correctly pointer'ed or referenc'ed type - ret.SetCompilerType(static_type); - ret.SetName(corrected_name.c_str()); - } - return ret; +TypeAndOrName ItaniumABILanguageRuntime::FixUpDynamicType( + const TypeAndOrName &type_and_or_name, ValueObject &static_value) { + CompilerType static_type(static_value.GetCompilerType()); + Flags static_type_flags(static_type.GetTypeInfo()); + + TypeAndOrName ret(type_and_or_name); + if (type_and_or_name.HasType()) { + // The type will always be the type of the dynamic object. If our parent's + // type was a pointer, + // then our type should be a pointer to the type of the dynamic object. If + // a reference, then the original type + // should be okay... + CompilerType orig_type = type_and_or_name.GetCompilerType(); + CompilerType corrected_type = orig_type; + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_type = orig_type.GetPointerType(); + else if (static_type_flags.AllSet(eTypeIsReference)) + corrected_type = orig_type.GetLValueReferenceType(); + ret.SetCompilerType(corrected_type); + } else { + // If we are here we need to adjust our dynamic type name to include the + // correct & or * symbol + std::string corrected_name(type_and_or_name.GetName().GetCString()); + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_name.append(" *"); + else if (static_type_flags.AllSet(eTypeIsReference)) + corrected_name.append(" &"); + // the parent type should be a correctly pointer'ed or referenc'ed type + ret.SetCompilerType(static_type); + ret.SetName(corrected_name.c_str()); + } + return ret; } -bool -ItaniumABILanguageRuntime::IsVTableName (const char *name) -{ - if (name == NULL) - return false; - - // Can we maybe ask Clang about this? - if (strstr (name, "_vptr$") == name) - return true; - else - return false; +bool ItaniumABILanguageRuntime::IsVTableName(const char *name) { + if (name == NULL) + return false; + + // Can we maybe ask Clang about this? + if (strstr(name, "_vptr$") == name) + return true; + else + return false; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ LanguageRuntime * -ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language) -{ - // FIXME: We have to check the process and make sure we actually know that this process supports - // the Itanium ABI. - if (language == eLanguageTypeC_plus_plus || - language == eLanguageTypeC_plus_plus_03 || - language == eLanguageTypeC_plus_plus_11 || - language == eLanguageTypeC_plus_plus_14) - return new ItaniumABILanguageRuntime (process); - else - return NULL; +ItaniumABILanguageRuntime::CreateInstance(Process *process, + lldb::LanguageType language) { + // FIXME: We have to check the process and make sure we actually know that + // this process supports + // the Itanium ABI. + if (language == eLanguageTypeC_plus_plus || + language == eLanguageTypeC_plus_plus_03 || + language == eLanguageTypeC_plus_plus_11 || + language == eLanguageTypeC_plus_plus_14) + return new ItaniumABILanguageRuntime(process); + else + return NULL; } -class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed -{ +class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed { public: - CommandObjectMultiwordItaniumABI_Demangle (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "demangle", - "Demangle a C++ mangled name.", - "language cplusplus demangle") - { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeSymbol; - index_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } - - ~CommandObjectMultiwordItaniumABI_Demangle() override = default; - + CommandObjectMultiwordItaniumABI_Demangle(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "demangle", + "Demangle a C++ mangled name.", + "language cplusplus demangle") { + CommandArgumentEntry arg; + CommandArgumentData index_arg; + + // Define the first (and only) variant of this arg. + index_arg.arg_type = eArgTypeSymbol; + index_arg.arg_repetition = eArgRepeatPlus; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectMultiwordItaniumABI_Demangle() override = default; + protected: - bool - DoExecute(Args& command, CommandReturnObject &result) override - { - bool demangled_any = false; - bool error_any = false; - for (size_t i = 0; i < command.GetArgumentCount(); i++) - { - auto arg = command.GetArgumentAtIndex(i); - if (arg && *arg) - { - ConstString mangled_cs(arg); - - // the actual Mangled class should be strict about this, but on the command line - // if you're copying mangled names out of 'nm' on Darwin, they will come out with - // an extra underscore - be willing to strip this on behalf of the user - // This is the moral equivalent of the -_/-n options to c++filt - if (mangled_cs.GetStringRef().startswith("__Z")) - mangled_cs.SetCString(arg+1); - - Mangled mangled(mangled_cs, true); - if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) - { - ConstString demangled(mangled.GetDisplayDemangledName(lldb::eLanguageTypeC_plus_plus)); - demangled_any = true; - result.AppendMessageWithFormat("%s ---> %s\n", arg, demangled.GetCString()); - } - else - { - error_any = true; - result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", arg); - } - } + bool DoExecute(Args &command, CommandReturnObject &result) override { + bool demangled_any = false; + bool error_any = false; + for (size_t i = 0; i < command.GetArgumentCount(); i++) { + auto arg = command.GetArgumentAtIndex(i); + if (arg && *arg) { + ConstString mangled_cs(arg); + + // the actual Mangled class should be strict about this, but on the + // command line + // if you're copying mangled names out of 'nm' on Darwin, they will come + // out with + // an extra underscore - be willing to strip this on behalf of the user + // This is the moral equivalent of the -_/-n options to c++filt + if (mangled_cs.GetStringRef().startswith("__Z")) + mangled_cs.SetCString(arg + 1); + + Mangled mangled(mangled_cs, true); + if (mangled.GuessLanguage() == lldb::eLanguageTypeC_plus_plus) { + ConstString demangled( + mangled.GetDisplayDemangledName(lldb::eLanguageTypeC_plus_plus)); + demangled_any = true; + result.AppendMessageWithFormat("%s ---> %s\n", arg, + demangled.GetCString()); + } else { + error_any = true; + result.AppendErrorWithFormat("%s is not a valid C++ mangled name\n", + arg); } - - result.SetStatus(error_any ? lldb::eReturnStatusFailed : - (demangled_any ? lldb::eReturnStatusSuccessFinishResult : lldb::eReturnStatusSuccessFinishNoResult)); - return result.Succeeded(); + } } + + result.SetStatus( + error_any ? lldb::eReturnStatusFailed + : (demangled_any ? lldb::eReturnStatusSuccessFinishResult + : lldb::eReturnStatusSuccessFinishNoResult)); + return result.Succeeded(); + } }; -class CommandObjectMultiwordItaniumABI : public CommandObjectMultiword -{ +class CommandObjectMultiwordItaniumABI : public CommandObjectMultiword { public: - CommandObjectMultiwordItaniumABI(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "cplusplus", "Commands for operating on the C++ language runtime.", - "cplusplus <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("demangle", CommandObjectSP (new CommandObjectMultiwordItaniumABI_Demangle (interpreter))); - } - - ~CommandObjectMultiwordItaniumABI() override = default; + CommandObjectMultiwordItaniumABI(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "cplusplus", + "Commands for operating on the C++ language runtime.", + "cplusplus <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "demangle", + CommandObjectSP( + new CommandObjectMultiwordItaniumABI_Demangle(interpreter))); + } + + ~CommandObjectMultiwordItaniumABI() override = default; }; -void -ItaniumABILanguageRuntime::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Itanium ABI for the C++ language", - CreateInstance, - [] (CommandInterpreter& interpreter) -> lldb::CommandObjectSP { - return CommandObjectSP(new CommandObjectMultiwordItaniumABI(interpreter)); - }); +void ItaniumABILanguageRuntime::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "Itanium ABI for the C++ language", CreateInstance, + [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP { + return CommandObjectSP( + new CommandObjectMultiwordItaniumABI(interpreter)); + }); } -void -ItaniumABILanguageRuntime::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void ItaniumABILanguageRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -ItaniumABILanguageRuntime::GetPluginNameStatic() -{ - static ConstString g_name("itanium"); - return g_name; +lldb_private::ConstString ItaniumABILanguageRuntime::GetPluginNameStatic() { + static ConstString g_name("itanium"); + return g_name; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -ItaniumABILanguageRuntime::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString ItaniumABILanguageRuntime::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -ItaniumABILanguageRuntime::GetPluginVersion() -{ - return 1; +uint32_t ItaniumABILanguageRuntime::GetPluginVersion() { return 1; } + +BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( + Breakpoint *bkpt, bool catch_bp, bool throw_bp) { + return CreateExceptionResolver(bkpt, catch_bp, throw_bp, false); } -BreakpointResolverSP -ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) -{ - return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false); +BreakpointResolverSP ItaniumABILanguageRuntime::CreateExceptionResolver( + Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions) { + // One complication here is that most users DON'T want to stop at + // __cxa_allocate_expression, but until we can do + // anything better with predicting unwinding the expression parser does. So + // we have two forms of the exception + // breakpoints, one for expressions that leaves out __cxa_allocate_exception, + // and one that includes it. + // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint + // in the runtime the former. + static const char *g_catch_name = "__cxa_begin_catch"; + static const char *g_throw_name1 = "__cxa_throw"; + static const char *g_throw_name2 = "__cxa_rethrow"; + static const char *g_exception_throw_name = "__cxa_allocate_exception"; + std::vector<const char *> exception_names; + exception_names.reserve(4); + if (catch_bp) + exception_names.push_back(g_catch_name); + + if (throw_bp) { + exception_names.push_back(g_throw_name1); + exception_names.push_back(g_throw_name2); + } + + if (for_expressions) + exception_names.push_back(g_exception_throw_name); + + BreakpointResolverSP resolver_sp(new BreakpointResolverName( + bkpt, exception_names.data(), exception_names.size(), + eFunctionNameTypeBase, eLanguageTypeUnknown, 0, eLazyBoolNo)); + + return resolver_sp; } -BreakpointResolverSP -ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions) -{ - // One complication here is that most users DON'T want to stop at __cxa_allocate_expression, but until we can do - // anything better with predicting unwinding the expression parser does. So we have two forms of the exception - // breakpoints, one for expressions that leaves out __cxa_allocate_exception, and one that includes it. - // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in the runtime the former. - static const char *g_catch_name = "__cxa_begin_catch"; - static const char *g_throw_name1 = "__cxa_throw"; - static const char *g_throw_name2 = "__cxa_rethrow"; - static const char *g_exception_throw_name = "__cxa_allocate_exception"; - std::vector<const char *> exception_names; - exception_names.reserve(4); - if (catch_bp) - exception_names.push_back(g_catch_name); - - if (throw_bp) - { - exception_names.push_back(g_throw_name1); - exception_names.push_back(g_throw_name2); - } +lldb::SearchFilterSP ItaniumABILanguageRuntime::CreateExceptionSearchFilter() { + Target &target = m_process->GetTarget(); - if (for_expressions) - exception_names.push_back(g_exception_throw_name); - - BreakpointResolverSP resolver_sp (new BreakpointResolverName (bkpt, - exception_names.data(), - exception_names.size(), - eFunctionNameTypeBase, - eLanguageTypeUnknown, - 0, - eLazyBoolNo)); - - return resolver_sp; + if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) { + // Limit the number of modules that are searched for these breakpoints for + // Apple binaries. + FileSpecList filter_modules; + filter_modules.Append(FileSpec("libc++abi.dylib", false)); + filter_modules.Append(FileSpec("libSystem.B.dylib", false)); + return target.GetSearchFilterForModuleList(&filter_modules); + } else { + return LanguageRuntime::CreateExceptionSearchFilter(); + } } +lldb::BreakpointSP ItaniumABILanguageRuntime::CreateExceptionBreakpoint( + bool catch_bp, bool throw_bp, bool for_expressions, bool is_internal) { + Target &target = m_process->GetTarget(); + FileSpecList filter_modules; + BreakpointResolverSP exception_resolver_sp = + CreateExceptionResolver(NULL, catch_bp, throw_bp, for_expressions); + SearchFilterSP filter_sp(CreateExceptionSearchFilter()); + const bool hardware = false; + const bool resolve_indirect_functions = false; + return target.CreateBreakpoint(filter_sp, exception_resolver_sp, is_internal, + hardware, resolve_indirect_functions); +} +void ItaniumABILanguageRuntime::SetExceptionBreakpoints() { + if (!m_process) + return; -lldb::SearchFilterSP -ItaniumABILanguageRuntime::CreateExceptionSearchFilter () -{ - Target &target = m_process->GetTarget(); + const bool catch_bp = false; + const bool throw_bp = true; + const bool is_internal = true; + const bool for_expressions = true; - if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) - { - // Limit the number of modules that are searched for these breakpoints for - // Apple binaries. - FileSpecList filter_modules; - filter_modules.Append(FileSpec("libc++abi.dylib", false)); - filter_modules.Append(FileSpec("libSystem.B.dylib", false)); - return target.GetSearchFilterForModuleList(&filter_modules); - } - else - { - return LanguageRuntime::CreateExceptionSearchFilter(); - } -} - -lldb::BreakpointSP -ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp, - bool throw_bp, - bool for_expressions, - bool is_internal) -{ - Target &target = m_process->GetTarget(); - FileSpecList filter_modules; - BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions); - SearchFilterSP filter_sp (CreateExceptionSearchFilter ()); - const bool hardware = false; - const bool resolve_indirect_functions = false; - return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal, hardware, resolve_indirect_functions); -} + // For the exception breakpoints set by the Expression parser, we'll be a + // little more aggressive and + // stop at exception allocation as well. -void -ItaniumABILanguageRuntime::SetExceptionBreakpoints () -{ - if (!m_process) - return; - - const bool catch_bp = false; - const bool throw_bp = true; - const bool is_internal = true; - const bool for_expressions = true; - - // For the exception breakpoints set by the Expression parser, we'll be a little more aggressive and - // stop at exception allocation as well. - + if (m_cxx_exception_bp_sp) { + m_cxx_exception_bp_sp->SetEnabled(true); + } else { + m_cxx_exception_bp_sp = CreateExceptionBreakpoint( + catch_bp, throw_bp, for_expressions, is_internal); if (m_cxx_exception_bp_sp) - { - m_cxx_exception_bp_sp->SetEnabled (true); - } - else - { - m_cxx_exception_bp_sp = CreateExceptionBreakpoint (catch_bp, throw_bp, for_expressions, is_internal); - if (m_cxx_exception_bp_sp) - m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); - } - + m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception"); + } } -void -ItaniumABILanguageRuntime::ClearExceptionBreakpoints () -{ - if (!m_process) - return; - - if (m_cxx_exception_bp_sp) - { - m_cxx_exception_bp_sp->SetEnabled (false); - } +void ItaniumABILanguageRuntime::ClearExceptionBreakpoints() { + if (!m_process) + return; + + if (m_cxx_exception_bp_sp) { + m_cxx_exception_bp_sp->SetEnabled(false); + } } -bool -ItaniumABILanguageRuntime::ExceptionBreakpointsAreSet () -{ - return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled(); +bool ItaniumABILanguageRuntime::ExceptionBreakpointsAreSet() { + return m_cxx_exception_bp_sp && m_cxx_exception_bp_sp->IsEnabled(); } -bool -ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) -{ - if (!m_process) - return false; - - if (!stop_reason || - stop_reason->GetStopReason() != eStopReasonBreakpoint) - return false; - - uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id, - m_cxx_exception_bp_sp->GetID()); - +bool ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop( + lldb::StopInfoSP stop_reason) { + if (!m_process) + return false; + + if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint) + return false; + + uint64_t break_site_id = stop_reason->GetValue(); + return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + break_site_id, m_cxx_exception_bp_sp->GetID()); } -TypeAndOrName -ItaniumABILanguageRuntime::GetDynamicTypeInfo(const lldb_private::Address &vtable_addr) -{ - std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); - DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); - if (pos == m_dynamic_type_map.end()) - return TypeAndOrName(); - else - return pos->second; +TypeAndOrName ItaniumABILanguageRuntime::GetDynamicTypeInfo( + const lldb_private::Address &vtable_addr) { + std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); + DynamicTypeCache::const_iterator pos = m_dynamic_type_map.find(vtable_addr); + if (pos == m_dynamic_type_map.end()) + return TypeAndOrName(); + else + return pos->second; } -void -ItaniumABILanguageRuntime::SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) -{ - std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); - m_dynamic_type_map[vtable_addr] = type_info; +void ItaniumABILanguageRuntime::SetDynamicTypeInfo( + const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info) { + std::lock_guard<std::mutex> locker(m_dynamic_type_map_mutex); + m_dynamic_type_map[vtable_addr] = type_info; } diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index 86bd728d6c6..480c32691c8 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h @@ -18,116 +18,98 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Core/Value.h" #include "lldb/Symbol/Type.h" -#include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/CPPLanguageRuntime.h" -#include "lldb/Core/Value.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { - - class ItaniumABILanguageRuntime : - public lldb_private::CPPLanguageRuntime - { - public: - ~ItaniumABILanguageRuntime() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance (Process *process, lldb::LanguageType language); - - static lldb_private::ConstString - GetPluginNameStatic(); - - bool - IsVTableName(const char *name) override; - - bool - GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - TypeAndOrName - FixUpDynamicType(const TypeAndOrName& type_and_or_name, - ValueObject& static_value) override; - - bool - CouldHaveDynamicValue(ValueObject &in_value) override; - - void - SetExceptionBreakpoints() override; - - void - ClearExceptionBreakpoints() override; - - bool - ExceptionBreakpointsAreSet() override; - - bool - ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; - - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override; - - lldb::SearchFilterSP - CreateExceptionSearchFilter() override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - protected: - lldb::BreakpointResolverSP - CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions); - - lldb::BreakpointSP - CreateExceptionBreakpoint(bool catch_bp, - bool throw_bp, - bool for_expressions, - bool is_internal); - - private: - typedef std::map<lldb_private::Address, TypeAndOrName> DynamicTypeCache; - - ItaniumABILanguageRuntime(Process *process) - : // Call CreateInstance instead. - lldb_private::CPPLanguageRuntime(process), - m_cxx_exception_bp_sp(), - m_dynamic_type_map(), - m_dynamic_type_map_mutex() - { - } - - lldb::BreakpointSP m_cxx_exception_bp_sp; - DynamicTypeCache m_dynamic_type_map; - std::mutex m_dynamic_type_map_mutex; - - TypeAndOrName - GetTypeInfoFromVTableAddress(ValueObject &in_value, lldb::addr_t original_ptr, lldb::addr_t vtable_addr); - - TypeAndOrName - GetDynamicTypeInfo(const lldb_private::Address &vtable_addr); - - void - SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, const TypeAndOrName &type_info); - }; - + +class ItaniumABILanguageRuntime : public lldb_private::CPPLanguageRuntime { +public: + ~ItaniumABILanguageRuntime() override = default; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); + + static lldb_private::ConstString GetPluginNameStatic(); + + bool IsVTableName(const char *name) override; + + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; + + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; + + bool CouldHaveDynamicValue(ValueObject &in_value) override; + + void SetExceptionBreakpoints() override; + + void ClearExceptionBreakpoints() override; + + bool ExceptionBreakpointsAreSet() override; + + bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; + + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override; + + lldb::SearchFilterSP CreateExceptionSearchFilter() override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + +protected: + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp, + bool for_expressions); + + lldb::BreakpointSP CreateExceptionBreakpoint(bool catch_bp, bool throw_bp, + bool for_expressions, + bool is_internal); + +private: + typedef std::map<lldb_private::Address, TypeAndOrName> DynamicTypeCache; + + ItaniumABILanguageRuntime(Process *process) + : // Call CreateInstance instead. + lldb_private::CPPLanguageRuntime(process), + m_cxx_exception_bp_sp(), m_dynamic_type_map(), + m_dynamic_type_map_mutex() {} + + lldb::BreakpointSP m_cxx_exception_bp_sp; + DynamicTypeCache m_dynamic_type_map; + std::mutex m_dynamic_type_map_mutex; + + TypeAndOrName GetTypeInfoFromVTableAddress(ValueObject &in_value, + lldb::addr_t original_ptr, + lldb::addr_t vtable_addr); + + TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr); + + void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr, + const TypeAndOrName &type_info); +}; + } // namespace lldb_private #endif // liblldb_ItaniumABILanguageRuntime_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp index c752971e7a0..1450835298e 100644 --- a/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp @@ -1,4 +1,5 @@ -//===-- GoLanguageRuntime.cpp --------------------------------------*- C++ -*-===// +//===-- GoLanguageRuntime.cpp --------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -36,206 +37,179 @@ using namespace lldb; using namespace lldb_private; namespace { -ValueObjectSP GetChild(ValueObject& obj, const char* name, bool dereference = true) { - ConstString name_const_str(name); - ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true); - if (dereference && result && result->IsPointerType()) { - Error err; - result = result->Dereference(err); - if (err.Fail()) - result.reset(); - } - return result; +ValueObjectSP GetChild(ValueObject &obj, const char *name, + bool dereference = true) { + ConstString name_const_str(name); + ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true); + if (dereference && result && result->IsPointerType()) { + Error err; + result = result->Dereference(err); + if (err.Fail()) + result.reset(); + } + return result; } -ConstString ReadString(ValueObject& str, Process* process) { - ConstString result; - ValueObjectSP data = GetChild(str, "str", false); - ValueObjectSP len = GetChild(str, "len"); - if (len && data) - { - Error err; - lldb::addr_t addr = data->GetPointerValue(); - if (addr == LLDB_INVALID_ADDRESS) - return result; - uint64_t byte_size = len->GetValueAsUnsigned(0); - char* buf = new char[byte_size + 1]; - buf[byte_size] = 0; - size_t bytes_read = process->ReadMemory (addr, - buf, - byte_size, - err); - if (!(err.Fail() || bytes_read != byte_size)) - result = ConstString(buf, bytes_read); - delete[] buf; - } - return result; +ConstString ReadString(ValueObject &str, Process *process) { + ConstString result; + ValueObjectSP data = GetChild(str, "str", false); + ValueObjectSP len = GetChild(str, "len"); + if (len && data) { + Error err; + lldb::addr_t addr = data->GetPointerValue(); + if (addr == LLDB_INVALID_ADDRESS) + return result; + uint64_t byte_size = len->GetValueAsUnsigned(0); + char *buf = new char[byte_size + 1]; + buf[byte_size] = 0; + size_t bytes_read = process->ReadMemory(addr, buf, byte_size, err); + if (!(err.Fail() || bytes_read != byte_size)) + result = ConstString(buf, bytes_read); + delete[] buf; + } + return result; } -ConstString -ReadTypeName(ValueObjectSP type, Process* process) -{ - if (ValueObjectSP uncommon = GetChild(*type, "x")) - { - ValueObjectSP name = GetChild(*uncommon, "name"); - ValueObjectSP package = GetChild(*uncommon, "pkgpath"); - if (name && name->GetPointerValue() != 0 && package && package->GetPointerValue() != 0) - { - ConstString package_const_str = ReadString(*package, process); - ConstString name_const_str = ReadString(*name, process); - if (package_const_str.GetLength() == 0) - return name_const_str; - return ConstString((package_const_str.GetStringRef() + "." + name_const_str.GetStringRef()).str()); - } +ConstString ReadTypeName(ValueObjectSP type, Process *process) { + if (ValueObjectSP uncommon = GetChild(*type, "x")) { + ValueObjectSP name = GetChild(*uncommon, "name"); + ValueObjectSP package = GetChild(*uncommon, "pkgpath"); + if (name && name->GetPointerValue() != 0 && package && + package->GetPointerValue() != 0) { + ConstString package_const_str = ReadString(*package, process); + ConstString name_const_str = ReadString(*name, process); + if (package_const_str.GetLength() == 0) + return name_const_str; + return ConstString((package_const_str.GetStringRef() + "." + + name_const_str.GetStringRef()) + .str()); } - ValueObjectSP name = GetChild(*type, "_string"); - if (name) - return ReadString(*name, process); - return ConstString(""); + } + ValueObjectSP name = GetChild(*type, "_string"); + if (name) + return ReadString(*name, process); + return ConstString(""); } -CompilerType -LookupRuntimeType(ValueObjectSP type, ExecutionContext* exe_ctx, bool* is_direct) -{ - uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0); - *is_direct = GoASTContext::IsDirectIface(kind); - if (GoASTContext::IsPointerKind(kind)) - { - CompilerType type_ptr = type->GetCompilerType().GetPointerType(); - Error err; - ValueObjectSP elem = type->CreateValueObjectFromAddress("elem", type->GetAddressOf() + type->GetByteSize(), *exe_ctx, type_ptr)->Dereference(err); - if (err.Fail()) - return CompilerType(); - bool tmp_direct; - return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType(); - } - Target *target = exe_ctx->GetTargetPtr(); - Process *process = exe_ctx->GetProcessPtr(); - - ConstString const_typename = ReadTypeName(type, process); - if (const_typename.GetLength() == 0) - return CompilerType(); - - SymbolContext sc; - TypeList type_list; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - uint32_t num_matches = target->GetImages().FindTypes (sc, - const_typename, - false, - 2, - searched_symbol_files, - type_list); - if (num_matches > 0) { - return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); - } +CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx, + bool *is_direct) { + uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0); + *is_direct = GoASTContext::IsDirectIface(kind); + if (GoASTContext::IsPointerKind(kind)) { + CompilerType type_ptr = type->GetCompilerType().GetPointerType(); + Error err; + ValueObjectSP elem = + type->CreateValueObjectFromAddress("elem", type->GetAddressOf() + + type->GetByteSize(), + *exe_ctx, type_ptr) + ->Dereference(err); + if (err.Fail()) + return CompilerType(); + bool tmp_direct; + return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType(); + } + Target *target = exe_ctx->GetTargetPtr(); + Process *process = exe_ctx->GetProcessPtr(); + + ConstString const_typename = ReadTypeName(type, process); + if (const_typename.GetLength() == 0) return CompilerType(); -} + SymbolContext sc; + TypeList type_list; + llvm::DenseSet<SymbolFile *> searched_symbol_files; + uint32_t num_matches = target->GetImages().FindTypes( + sc, const_typename, false, 2, searched_symbol_files, type_list); + if (num_matches > 0) { + return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); + } + return CompilerType(); +} } -bool -GoLanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value) -{ - return GoASTContext::IsGoInterface(in_value.GetCompilerType()); +bool GoLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + return GoASTContext::IsGoInterface(in_value.GetCompilerType()); } -bool -GoLanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &dynamic_address, - Value::ValueType &value_type) -{ - value_type = Value::eValueTypeScalar; - class_type_or_name.Clear(); - if (CouldHaveDynamicValue (in_value)) - { - Error err; - ValueObjectSP iface = in_value.GetStaticValue(); - ValueObjectSP data_sp = GetChild(*iface, "data", false); - if (!data_sp) - return false; - - if (ValueObjectSP tab = GetChild(*iface, "tab")) - iface = tab; - ValueObjectSP type = GetChild(*iface, "_type"); - if (!type) - { - return false; - } - - bool direct; - ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); - CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct); - if (!final_type) - return false; - if (direct) - { - class_type_or_name.SetCompilerType(final_type); - } - else - { - // TODO: implement reference types or fix caller to support dynamic types that aren't pointers - // so we don't have to introduce this extra pointer. - class_type_or_name.SetCompilerType(final_type.GetPointerType()); - } - - dynamic_address.SetLoadAddress(data_sp->GetPointerValue(), exe_ctx.GetTargetPtr()); - - return true; +bool GoLanguageRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type) { + value_type = Value::eValueTypeScalar; + class_type_or_name.Clear(); + if (CouldHaveDynamicValue(in_value)) { + Error err; + ValueObjectSP iface = in_value.GetStaticValue(); + ValueObjectSP data_sp = GetChild(*iface, "data", false); + if (!data_sp) + return false; + + if (ValueObjectSP tab = GetChild(*iface, "tab")) + iface = tab; + ValueObjectSP type = GetChild(*iface, "_type"); + if (!type) { + return false; } - return false; + + bool direct; + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct); + if (!final_type) + return false; + if (direct) { + class_type_or_name.SetCompilerType(final_type); + } else { + // TODO: implement reference types or fix caller to support dynamic types + // that aren't pointers + // so we don't have to introduce this extra pointer. + class_type_or_name.SetCompilerType(final_type.GetPointerType()); + } + + dynamic_address.SetLoadAddress(data_sp->GetPointerValue(), + exe_ctx.GetTargetPtr()); + + return true; + } + return false; } TypeAndOrName -GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) -{ - return type_and_or_name; +GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) { + return type_and_or_name; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ LanguageRuntime * -GoLanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language) -{ - if (language == eLanguageTypeGo) - return new GoLanguageRuntime (process); - else - return NULL; +GoLanguageRuntime::CreateInstance(Process *process, + lldb::LanguageType language) { + if (language == eLanguageTypeGo) + return new GoLanguageRuntime(process); + else + return NULL; } -void -GoLanguageRuntime::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Go Language Runtime", - CreateInstance); +void GoLanguageRuntime::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language Runtime", + CreateInstance); } -void -GoLanguageRuntime::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void GoLanguageRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -GoLanguageRuntime::GetPluginNameStatic() -{ - static ConstString g_name("golang"); - return g_name; +lldb_private::ConstString GoLanguageRuntime::GetPluginNameStatic() { + static ConstString g_name("golang"); + return g_name; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -GoLanguageRuntime::GetPluginName() -{ - return GetPluginNameStatic(); -} - -uint32_t -GoLanguageRuntime::GetPluginVersion() -{ - return 1; +lldb_private::ConstString GoLanguageRuntime::GetPluginName() { + return GetPluginNameStatic(); } +uint32_t GoLanguageRuntime::GetPluginVersion() { return 1; } diff --git a/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h index 596d2888dc8..9c2ee15cff6 100644 --- a/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.h @@ -14,80 +14,73 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Breakpoint/BreakpointResolver.h" -#include "lldb/Target/LanguageRuntime.h" #include "lldb/Core/Value.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { - - class GoLanguageRuntime : - public lldb_private::LanguageRuntime - { - public: - ~GoLanguageRuntime() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static lldb_private::ConstString - GetPluginNameStatic(); - - lldb::LanguageType - GetLanguageType() const override - { - return lldb::eLanguageTypeGo; - } - - bool - GetObjectDescription(Stream &str, ValueObject &object) override - { - // TODO(ribrdb): Maybe call String() method? - return false; - } - - bool - GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override - { - return false; - } - - bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &address, - Value::ValueType &value_type) override; - - bool CouldHaveDynamicValue(ValueObject &in_value) override; - - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override - { - return lldb::BreakpointResolverSP(); - } - - TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - private: - GoLanguageRuntime(Process *process) : lldb_private::LanguageRuntime(process) { } // Call CreateInstance instead. - }; - + +class GoLanguageRuntime : public lldb_private::LanguageRuntime { +public: + ~GoLanguageRuntime() override = default; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); + + static lldb_private::ConstString GetPluginNameStatic(); + + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypeGo; + } + + bool GetObjectDescription(Stream &str, ValueObject &object) override { + // TODO(ribrdb): Maybe call String() method? + return false; + } + + bool GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override { + return false; + } + + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; + + bool CouldHaveDynamicValue(ValueObject &in_value) override; + + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override { + return lldb::BreakpointResolverSP(); + } + + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + +private: + GoLanguageRuntime(Process *process) + : lldb_private::LanguageRuntime(process) { + } // Call CreateInstance instead. +}; + } // namespace lldb_private #endif // liblldb_GoLanguageRuntime_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp index 07312a8af0d..36c30a99ff8 100644 --- a/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.cpp @@ -23,154 +23,135 @@ using namespace lldb; using namespace lldb_private; -JavaLanguageRuntime::JavaLanguageRuntime(Process *process) : LanguageRuntime(process) -{ -} +JavaLanguageRuntime::JavaLanguageRuntime(Process *process) + : LanguageRuntime(process) {} LanguageRuntime * -JavaLanguageRuntime::CreateInstance(Process *process, lldb::LanguageType language) -{ - if (language == eLanguageTypeJava) - return new JavaLanguageRuntime(process); - return nullptr; +JavaLanguageRuntime::CreateInstance(Process *process, + lldb::LanguageType language) { + if (language == eLanguageTypeJava) + return new JavaLanguageRuntime(process); + return nullptr; } -void -JavaLanguageRuntime::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), "Java language runtime", CreateInstance); +void JavaLanguageRuntime::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Java language runtime", + CreateInstance); } -void -JavaLanguageRuntime::Terminate() -{ - PluginManager::UnregisterPlugin(CreateInstance); +void JavaLanguageRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -JavaLanguageRuntime::GetPluginNameStatic() -{ - static ConstString g_name("java"); - return g_name; +lldb_private::ConstString JavaLanguageRuntime::GetPluginNameStatic() { + static ConstString g_name("java"); + return g_name; } -lldb_private::ConstString -JavaLanguageRuntime::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString JavaLanguageRuntime::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -JavaLanguageRuntime::GetPluginVersion() -{ - return 1; -} +uint32_t JavaLanguageRuntime::GetPluginVersion() { return 1; } -bool -JavaLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) -{ - return true; +bool JavaLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + return true; } -static ConstString -GetDynamicTypeId(ExecutionContext *exe_ctx, Target *target, ValueObject &in_value) -{ - SymbolContext sc; - TypeList class_types; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - size_t num_matches = target->GetImages().FindTypes(sc, ConstString("Object"), - true, // name_is_fully_qualified - UINT32_MAX, searched_symbol_files, class_types); - for (size_t i = 0; i < num_matches; ++i) - { - TypeSP type_sp = class_types.GetTypeAtIndex(i); - CompilerType compiler_type = type_sp->GetFullCompilerType(); - - if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava || - compiler_type.GetTypeName() != ConstString("java::lang::Object")) - continue; - - if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) - { - uint64_t type_id = JavaASTContext::CalculateDynamicTypeId(exe_ctx, compiler_type, in_value); - if (type_id != UINT64_MAX) - { - char id[32]; - snprintf(id, sizeof(id), "0x%" PRIX64, type_id); - return ConstString(id); - } - } +static ConstString GetDynamicTypeId(ExecutionContext *exe_ctx, Target *target, + ValueObject &in_value) { + SymbolContext sc; + TypeList class_types; + llvm::DenseSet<SymbolFile *> searched_symbol_files; + size_t num_matches = target->GetImages().FindTypes( + sc, ConstString("Object"), + true, // name_is_fully_qualified + UINT32_MAX, searched_symbol_files, class_types); + for (size_t i = 0; i < num_matches; ++i) { + TypeSP type_sp = class_types.GetTypeAtIndex(i); + CompilerType compiler_type = type_sp->GetFullCompilerType(); + + if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava || + compiler_type.GetTypeName() != ConstString("java::lang::Object")) + continue; + + if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) { + uint64_t type_id = JavaASTContext::CalculateDynamicTypeId( + exe_ctx, compiler_type, in_value); + if (type_id != UINT64_MAX) { + char id[32]; + snprintf(id, sizeof(id), "0x%" PRIX64, type_id); + return ConstString(id); + } } - return ConstString(); + } + return ConstString(); } -bool -JavaLanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &dynamic_address, - Value::ValueType &value_type) -{ - class_type_or_name.Clear(); - - // null references don't have a dynamic type - if (in_value.IsNilReference()) - return false; - - ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); - Target *target = exe_ctx.GetTargetPtr(); - if (!target) - return false; - - ConstString linkage_name; - CompilerType in_type = in_value.GetCompilerType(); - if (in_type.IsPossibleDynamicType(nullptr, false, false)) - linkage_name = GetDynamicTypeId(&exe_ctx, target, in_value); - else - linkage_name = JavaASTContext::GetLinkageName(in_type); - - if (!linkage_name) - return false; - - class_type_or_name.SetName(in_type.GetNonReferenceType().GetTypeName()); - - SymbolContext sc; - TypeList class_types; - llvm::DenseSet<SymbolFile *> searched_symbol_files; - size_t num_matches = target->GetImages().FindTypes(sc, linkage_name, - true, // name_is_fully_qualified - UINT32_MAX, searched_symbol_files, class_types); - - for (size_t i = 0; i < num_matches; ++i) - { - TypeSP type_sp = class_types.GetTypeAtIndex(i); - CompilerType compiler_type = type_sp->GetFullCompilerType(); - - if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava) - continue; - - if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) - { - class_type_or_name.SetTypeSP(type_sp); - - Value &value = in_value.GetValue(); - value_type = value.GetValueType(); - dynamic_address.SetRawAddress(value.GetScalar().ULongLong(0)); - return true; - } - } +bool JavaLanguageRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type) { + class_type_or_name.Clear(); + + // null references don't have a dynamic type + if (in_value.IsNilReference()) + return false; + + ExecutionContext exe_ctx(in_value.GetExecutionContextRef()); + Target *target = exe_ctx.GetTargetPtr(); + if (!target) + return false; + + ConstString linkage_name; + CompilerType in_type = in_value.GetCompilerType(); + if (in_type.IsPossibleDynamicType(nullptr, false, false)) + linkage_name = GetDynamicTypeId(&exe_ctx, target, in_value); + else + linkage_name = JavaASTContext::GetLinkageName(in_type); + + if (!linkage_name) return false; + + class_type_or_name.SetName(in_type.GetNonReferenceType().GetTypeName()); + + SymbolContext sc; + TypeList class_types; + llvm::DenseSet<SymbolFile *> searched_symbol_files; + size_t num_matches = target->GetImages().FindTypes( + sc, linkage_name, + true, // name_is_fully_qualified + UINT32_MAX, searched_symbol_files, class_types); + + for (size_t i = 0; i < num_matches; ++i) { + TypeSP type_sp = class_types.GetTypeAtIndex(i); + CompilerType compiler_type = type_sp->GetFullCompilerType(); + + if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava) + continue; + + if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) { + class_type_or_name.SetTypeSP(type_sp); + + Value &value = in_value.GetValue(); + value_type = value.GetValueType(); + dynamic_address.SetRawAddress(value.GetScalar().ULongLong(0)); + return true; + } + } + return false; } TypeAndOrName -JavaLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) -{ - CompilerType static_type(static_value.GetCompilerType()); - - TypeAndOrName ret(type_and_or_name); - if (type_and_or_name.HasType()) - { - CompilerType orig_type = type_and_or_name.GetCompilerType(); - if (static_type.IsReferenceType()) - ret.SetCompilerType(orig_type.GetLValueReferenceType()); - } - return ret; +JavaLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) { + CompilerType static_type(static_value.GetCompilerType()); + + TypeAndOrName ret(type_and_or_name); + if (type_and_or_name.HasType()) { + CompilerType orig_type = type_and_or_name.GetCompilerType(); + if (static_type.IsReferenceType()) + ret.SetCompilerType(orig_type.GetLValueReferenceType()); + } + return ret; } diff --git a/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h index 83ed35dbb59..6eeb4041572 100644 --- a/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h @@ -19,70 +19,58 @@ #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" -namespace lldb_private -{ +namespace lldb_private { -class JavaLanguageRuntime : public LanguageRuntime -{ +class JavaLanguageRuntime : public LanguageRuntime { public: - static void - Initialize(); + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - lldb_private::ConstString - GetPluginName() override; + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; - lldb::LanguageType - GetLanguageType() const override - { - return lldb::eLanguageTypeJava; - } + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypeJava; + } - bool - GetObjectDescription(Stream &str, ValueObject &object) override - { - return false; - } + bool GetObjectDescription(Stream &str, ValueObject &object) override { + return false; + } - bool - GetObjectDescription(Stream &str, Value &value, ExecutionContextScope *exe_scope) override - { - return false; - } + bool GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override { + return false; + } - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override - { - return nullptr; - } + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override { + return nullptr; + } - TypeAndOrName - FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) override; + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; - bool - CouldHaveDynamicValue(ValueObject &in_value) override; + bool CouldHaveDynamicValue(ValueObject &in_value) override; - bool - GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &address, - Value::ValueType &value_type) override; + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; protected: - JavaLanguageRuntime(Process *process); + JavaLanguageRuntime(Process *process); private: - DISALLOW_COPY_AND_ASSIGN(JavaLanguageRuntime); + DISALLOW_COPY_AND_ASSIGN(JavaLanguageRuntime); }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index 5cf99a573d8..477f4df655e 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -1,4 +1,5 @@ -//===-- AppleObjCClassDescriptorV2.cpp -----------------------------*- C++ -*-===// +//===-- AppleObjCClassDescriptorV2.cpp -----------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -15,557 +16,533 @@ using namespace lldb; using namespace lldb_private; -bool -ClassDescriptorV2::Read_objc_class (Process* process, std::unique_ptr<objc_class_t> &objc_class) const -{ - objc_class.reset(new objc_class_t); - - bool ret = objc_class->Read (process, m_objc_class_ptr); - - if (!ret) - objc_class.reset(); - - return ret; +bool ClassDescriptorV2::Read_objc_class( + Process *process, std::unique_ptr<objc_class_t> &objc_class) const { + objc_class.reset(new objc_class_t); + + bool ret = objc_class->Read(process, m_objc_class_ptr); + + if (!ret) + objc_class.reset(); + + return ret; } -bool -ClassDescriptorV2::objc_class_t::Read(Process *process, lldb::addr_t addr) -{ - size_t ptr_size = process->GetAddressByteSize(); - - size_t objc_class_size = ptr_size // uintptr_t isa; - + ptr_size // Class superclass; - + ptr_size // void *cache; - + ptr_size // IMP *vtable; - + ptr_size; // uintptr_t data_NEVER_USE; - - DataBufferHeap objc_class_buf (objc_class_size, '\0'); - Error error; - - process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; - m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; - m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; - m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; - lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; - - m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); - m_data_ptr = data_NEVER_USE & ~(lldb::addr_t)3; - - return true; +bool ClassDescriptorV2::objc_class_t::Read(Process *process, + lldb::addr_t addr) { + size_t ptr_size = process->GetAddressByteSize(); + + size_t objc_class_size = ptr_size // uintptr_t isa; + + ptr_size // Class superclass; + + ptr_size // void *cache; + + ptr_size // IMP *vtable; + + ptr_size; // uintptr_t data_NEVER_USE; + + DataBufferHeap objc_class_buf(objc_class_size, '\0'); + Error error; + + process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, + process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; + m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; + m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; + m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; + lldb::addr_t data_NEVER_USE = + extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; + + m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); + m_data_ptr = data_NEVER_USE & ~(lldb::addr_t)3; + + return true; } -bool -ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) -{ - size_t ptr_size = process->GetAddressByteSize(); - - size_t size = sizeof(uint32_t) // uint32_t flags; - + sizeof(uint32_t) // uint32_t version; - + ptr_size // const class_ro_t *ro; - + ptr_size // union { method_list_t **method_lists; method_list_t *method_list; }; - + ptr_size // struct chained_property_list *properties; - + ptr_size // const protocol_list_t **protocols; - + ptr_size // Class firstSubclass; - + ptr_size; // Class nextSiblingClass; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_flags = extractor.GetU32_unchecked(&cursor); - m_version = extractor.GetU32_unchecked(&cursor); - m_ro_ptr = extractor.GetAddress_unchecked(&cursor); - m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); - m_properties_ptr = extractor.GetAddress_unchecked(&cursor); - m_firstSubclass = extractor.GetAddress_unchecked(&cursor); - m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); - - return true; +bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) { + size_t ptr_size = process->GetAddressByteSize(); + + size_t size = sizeof(uint32_t) // uint32_t flags; + + sizeof(uint32_t) // uint32_t version; + + ptr_size // const class_ro_t *ro; + + ptr_size // union { method_list_t **method_lists; + // method_list_t *method_list; }; + + ptr_size // struct chained_property_list *properties; + + ptr_size // const protocol_list_t **protocols; + + ptr_size // Class firstSubclass; + + ptr_size; // Class nextSiblingClass; + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_flags = extractor.GetU32_unchecked(&cursor); + m_version = extractor.GetU32_unchecked(&cursor); + m_ro_ptr = extractor.GetAddress_unchecked(&cursor); + m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); + m_properties_ptr = extractor.GetAddress_unchecked(&cursor); + m_firstSubclass = extractor.GetAddress_unchecked(&cursor); + m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); + + return true; } -bool -ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) -{ - size_t ptr_size = process->GetAddressByteSize(); - - size_t size = sizeof(uint32_t) // uint32_t flags; - + sizeof(uint32_t) // uint32_t instanceStart; - + sizeof(uint32_t) // uint32_t instanceSize; - + (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only - + ptr_size // const uint8_t *ivarLayout; - + ptr_size // const char *name; - + ptr_size // const method_list_t *baseMethods; - + ptr_size // const protocol_list_t *baseProtocols; - + ptr_size // const ivar_list_t *ivars; - + ptr_size // const uint8_t *weakIvarLayout; - + ptr_size; // const property_list_t *baseProperties; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_flags = extractor.GetU32_unchecked(&cursor); - m_instanceStart = extractor.GetU32_unchecked(&cursor); - m_instanceSize = extractor.GetU32_unchecked(&cursor); - if (ptr_size == 8) - m_reserved = extractor.GetU32_unchecked(&cursor); - else - m_reserved = 0; - m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); - m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); - m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); - m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); - - DataBufferHeap name_buf(1024, '\0'); - - process->ReadCStringFromMemory(m_name_ptr, (char*)name_buf.GetBytes(), name_buf.GetByteSize(), error); - - if (error.Fail()) - { - return false; - } - - m_name.assign((char*)name_buf.GetBytes()); - - return true; +bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) { + size_t ptr_size = process->GetAddressByteSize(); + + size_t size = sizeof(uint32_t) // uint32_t flags; + + sizeof(uint32_t) // uint32_t instanceStart; + + sizeof(uint32_t) // uint32_t instanceSize; + + (ptr_size == 8 ? sizeof(uint32_t) + : 0) // uint32_t reserved; // __LP64__ only + + ptr_size // const uint8_t *ivarLayout; + + ptr_size // const char *name; + + ptr_size // const method_list_t *baseMethods; + + ptr_size // const protocol_list_t *baseProtocols; + + ptr_size // const ivar_list_t *ivars; + + ptr_size // const uint8_t *weakIvarLayout; + + ptr_size; // const property_list_t *baseProperties; + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_flags = extractor.GetU32_unchecked(&cursor); + m_instanceStart = extractor.GetU32_unchecked(&cursor); + m_instanceSize = extractor.GetU32_unchecked(&cursor); + if (ptr_size == 8) + m_reserved = extractor.GetU32_unchecked(&cursor); + else + m_reserved = 0; + m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); + m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); + m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); + m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); + + DataBufferHeap name_buf(1024, '\0'); + + process->ReadCStringFromMemory(m_name_ptr, (char *)name_buf.GetBytes(), + name_buf.GetByteSize(), error); + + if (error.Fail()) { + return false; + } + + m_name.assign((char *)name_buf.GetBytes()); + + return true; } -bool -ClassDescriptorV2::Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr<class_ro_t> &class_ro, std::unique_ptr<class_rw_t> &class_rw) const -{ - class_ro.reset(); - class_rw.reset(); - - Error error; - uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(objc_class.m_data_ptr, sizeof(uint32_t), 0, error); - if (!error.Success()) - return false; - - if (class_row_t_flags & RW_REALIZED) - { - class_rw.reset(new class_rw_t); - - if (!class_rw->Read(process, objc_class.m_data_ptr)) - { - class_rw.reset(); - return false; - } - - class_ro.reset(new class_ro_t); - - if (!class_ro->Read(process, class_rw->m_ro_ptr)) - { - class_rw.reset(); - class_ro.reset(); - return false; - } +bool ClassDescriptorV2::Read_class_row( + Process *process, const objc_class_t &objc_class, + std::unique_ptr<class_ro_t> &class_ro, + std::unique_ptr<class_rw_t> &class_rw) const { + class_ro.reset(); + class_rw.reset(); + + Error error; + uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory( + objc_class.m_data_ptr, sizeof(uint32_t), 0, error); + if (!error.Success()) + return false; + + if (class_row_t_flags & RW_REALIZED) { + class_rw.reset(new class_rw_t); + + if (!class_rw->Read(process, objc_class.m_data_ptr)) { + class_rw.reset(); + return false; } - else - { - class_ro.reset(new class_ro_t); - - if (!class_ro->Read(process, objc_class.m_data_ptr)) - { - class_ro.reset(); - return false; - } + + class_ro.reset(new class_ro_t); + + if (!class_ro->Read(process, class_rw->m_ro_ptr)) { + class_rw.reset(); + class_ro.reset(); + return false; } - - return true; -} + } else { + class_ro.reset(new class_ro_t); -bool -ClassDescriptorV2::method_list_t::Read(Process *process, lldb::addr_t addr) -{ - size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; - + sizeof(uint32_t); // uint32_t count; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; + if (!class_ro->Read(process, objc_class.m_data_ptr)) { + class_ro.reset(); + return false; } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; - m_count = extractor.GetU32_unchecked(&cursor); - m_first_ptr = addr + cursor; - - return true; + } + + return true; } -bool -ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) -{ - size_t size = GetSize(process); - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_types_ptr = extractor.GetAddress_unchecked(&cursor); - m_imp_ptr = extractor.GetAddress_unchecked(&cursor); - - process->ReadCStringFromMemory(m_name_ptr, m_name, error); - if (error.Fail()) - { - return false; - } - - process->ReadCStringFromMemory(m_types_ptr, m_types, error); - if (error.Fail()) - { - return false; - } - - return true; +bool ClassDescriptorV2::method_list_t::Read(Process *process, + lldb::addr_t addr) { + size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; + + sizeof(uint32_t); // uint32_t count; + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; + m_count = extractor.GetU32_unchecked(&cursor); + m_first_ptr = addr + cursor; + + return true; } -bool -ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) -{ - size_t size = sizeof(uint32_t) // uint32_t entsize; - + sizeof(uint32_t); // uint32_t count; - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; - } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_entsize = extractor.GetU32_unchecked(&cursor); - m_count = extractor.GetU32_unchecked(&cursor); - m_first_ptr = addr + cursor; - - return true; +bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) { + size_t size = GetSize(process); + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_types_ptr = extractor.GetAddress_unchecked(&cursor); + m_imp_ptr = extractor.GetAddress_unchecked(&cursor); + + process->ReadCStringFromMemory(m_name_ptr, m_name, error); + if (error.Fail()) { + return false; + } + + process->ReadCStringFromMemory(m_types_ptr, m_types, error); + if (error.Fail()) { + return false; + } + + return true; } -bool -ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) -{ - size_t size = GetSize(process); - - DataBufferHeap buffer (size, '\0'); - Error error; - - process->ReadMemory(addr, buffer.GetBytes(), size, error); - if (error.Fail()) - { - return false; +bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) { + size_t size = sizeof(uint32_t) // uint32_t entsize; + + sizeof(uint32_t); // uint32_t count; + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_entsize = extractor.GetU32_unchecked(&cursor); + m_count = extractor.GetU32_unchecked(&cursor); + m_first_ptr = addr + cursor; + + return true; +} + +bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) { + size_t size = GetSize(process); + + DataBufferHeap buffer(size, '\0'); + Error error; + + process->ReadMemory(addr, buffer.GetBytes(), size, error); + if (error.Fail()) { + return false; + } + + DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), + process->GetAddressByteSize()); + + lldb::offset_t cursor = 0; + + m_offset_ptr = extractor.GetAddress_unchecked(&cursor); + m_name_ptr = extractor.GetAddress_unchecked(&cursor); + m_type_ptr = extractor.GetAddress_unchecked(&cursor); + m_alignment = extractor.GetU32_unchecked(&cursor); + m_size = extractor.GetU32_unchecked(&cursor); + + process->ReadCStringFromMemory(m_name_ptr, m_name, error); + if (error.Fail()) { + return false; + } + + process->ReadCStringFromMemory(m_type_ptr, m_type, error); + if (error.Fail()) { + return false; + } + + return true; +} + +bool ClassDescriptorV2::Describe( + std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, + std::function<bool(const char *, const char *)> const &instance_method_func, + std::function<bool(const char *, const char *)> const &class_method_func, + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)> const &ivar_func) const { + lldb_private::Process *process = m_runtime.GetProcess(); + + std::unique_ptr<objc_class_t> objc_class; + std::unique_ptr<class_ro_t> class_ro; + std::unique_ptr<class_rw_t> class_rw; + + if (!Read_objc_class(process, objc_class)) + return 0; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return 0; + + static ConstString NSObject_name("NSObject"); + + if (m_name != NSObject_name && superclass_func) + superclass_func(objc_class->m_superclass); + + if (instance_method_func) { + std::unique_ptr<method_list_t> base_method_list; + + base_method_list.reset(new method_list_t); + if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) + return false; + + if (base_method_list->m_entsize != method_t::GetSize(process)) + return false; + + std::unique_ptr<method_t> method; + method.reset(new method_t); + + for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) { + method->Read(process, base_method_list->m_first_ptr + + (i * base_method_list->m_entsize)); + + if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) + break; } - - DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); - - lldb::offset_t cursor = 0; - - m_offset_ptr = extractor.GetAddress_unchecked(&cursor); - m_name_ptr = extractor.GetAddress_unchecked(&cursor); - m_type_ptr = extractor.GetAddress_unchecked(&cursor); - m_alignment = extractor.GetU32_unchecked(&cursor); - m_size = extractor.GetU32_unchecked(&cursor); - - process->ReadCStringFromMemory(m_name_ptr, m_name, error); - if (error.Fail()) - { - return false; + } + + if (class_method_func) { + AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass()); + + // We don't care about the metaclass's superclass, or its class methods. + // Its instance methods are + // our class methods. + + if (metaclass) { + metaclass->Describe( + std::function<void(ObjCLanguageRuntime::ObjCISA)>(nullptr), + class_method_func, + std::function<bool(const char *, const char *)>(nullptr), + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)>(nullptr)); } - - process->ReadCStringFromMemory(m_type_ptr, m_type, error); - if (error.Fail()) - { + } + + if (ivar_func) { + if (class_ro->m_ivars_ptr != 0) { + ivar_list_t ivar_list; + if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) return false; + + if (ivar_list.m_entsize != ivar_t::GetSize(process)) + return false; + + ivar_t ivar; + + for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) { + ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); + + if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), + ivar.m_offset_ptr, ivar.m_size)) + break; + } } - - return true; + } + + return true; } -bool -ClassDescriptorV2::Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, - std::function <bool (const char *, const char *)> const &instance_method_func, - std::function <bool (const char *, const char *)> const &class_method_func, - std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const -{ +ConstString ClassDescriptorV2::GetClassName() { + if (!m_name) { lldb_private::Process *process = m_runtime.GetProcess(); - - std::unique_ptr<objc_class_t> objc_class; - std::unique_ptr<class_ro_t> class_ro; - std::unique_ptr<class_rw_t> class_rw; - - if (!Read_objc_class(process, objc_class)) - return 0; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return 0; - - static ConstString NSObject_name("NSObject"); - - if (m_name != NSObject_name && superclass_func) - superclass_func(objc_class->m_superclass); - - if (instance_method_func) - { - std::unique_ptr<method_list_t> base_method_list; - - base_method_list.reset(new method_list_t); - if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) - return false; - - if (base_method_list->m_entsize != method_t::GetSize(process)) - return false; - - std::unique_ptr<method_t> method; - method.reset(new method_t); - - for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) - { - method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize)); - - if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) - break; - } - } - - if (class_method_func) - { - AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass()); - - // We don't care about the metaclass's superclass, or its class methods. Its instance methods are - // our class methods. - - if (metaclass) { - metaclass->Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> (nullptr), - class_method_func, - std::function <bool (const char *, const char *)> (nullptr), - std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)); - } - } - - if (ivar_func) - { - if (class_ro->m_ivars_ptr != 0) - { - ivar_list_t ivar_list; - if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) - return false; - - if (ivar_list.m_entsize != ivar_t::GetSize(process)) - return false; - - ivar_t ivar; - - for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) - { - ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); - - if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), ivar.m_offset_ptr, ivar.m_size)) - break; - } - } + + if (process) { + std::unique_ptr<objc_class_t> objc_class; + std::unique_ptr<class_ro_t> class_ro; + std::unique_ptr<class_rw_t> class_rw; + + if (!Read_objc_class(process, objc_class)) + return m_name; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return m_name; + + m_name = ConstString(class_ro->m_name.c_str()); } - - return true; + } + return m_name; } -ConstString -ClassDescriptorV2::GetClassName () -{ - if (!m_name) - { - lldb_private::Process *process = m_runtime.GetProcess(); - - if (process) - { - std::unique_ptr<objc_class_t> objc_class; - std::unique_ptr<class_ro_t> class_ro; - std::unique_ptr<class_rw_t> class_rw; - - if (!Read_objc_class(process, objc_class)) - return m_name; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return m_name; - - m_name = ConstString(class_ro->m_name.c_str()); - } - } - return m_name; +ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetSuperclass() { + lldb_private::Process *process = m_runtime.GetProcess(); + + if (!process) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + std::unique_ptr<objc_class_t> objc_class; + + if (!Read_objc_class(process, objc_class)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA( + objc_class->m_superclass); } -ObjCLanguageRuntime::ClassDescriptorSP -ClassDescriptorV2::GetSuperclass () -{ - lldb_private::Process *process = m_runtime.GetProcess(); - - if (!process) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - std::unique_ptr<objc_class_t> objc_class; - - if (!Read_objc_class(process, objc_class)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(objc_class->m_superclass); +ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetMetaclass() const { + lldb_private::Process *process = m_runtime.GetProcess(); + + if (!process) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + std::unique_ptr<objc_class_t> objc_class; + + if (!Read_objc_class(process, objc_class)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa); + + return ObjCLanguageRuntime::ClassDescriptorSP( + new ClassDescriptorV2(m_runtime, candidate_isa, nullptr)); } -ObjCLanguageRuntime::ClassDescriptorSP -ClassDescriptorV2::GetMetaclass () const -{ - lldb_private::Process *process = m_runtime.GetProcess(); - - if (!process) - return ObjCLanguageRuntime::ClassDescriptorSP(); - +uint64_t ClassDescriptorV2::GetInstanceSize() { + lldb_private::Process *process = m_runtime.GetProcess(); + + if (process) { std::unique_ptr<objc_class_t> objc_class; - + std::unique_ptr<class_ro_t> class_ro; + std::unique_ptr<class_rw_t> class_rw; + if (!Read_objc_class(process, objc_class)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa); - - return ObjCLanguageRuntime::ClassDescriptorSP(new ClassDescriptorV2(m_runtime, candidate_isa, nullptr)); -} + return 0; + if (!Read_class_row(process, *objc_class, class_ro, class_rw)) + return 0; -uint64_t -ClassDescriptorV2::GetInstanceSize () -{ - lldb_private::Process *process = m_runtime.GetProcess(); - - if (process) - { - std::unique_ptr<objc_class_t> objc_class; - std::unique_ptr<class_ro_t> class_ro; - std::unique_ptr<class_rw_t> class_rw; - - if (!Read_objc_class(process, objc_class)) - return 0; - if (!Read_class_row(process, *objc_class, class_ro, class_rw)) - return 0; - - return class_ro->m_instanceSize; - } - - return 0; -} + return class_ro->m_instanceSize; + } -ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_filled(false), m_ivars(), m_mutex() -{ + return 0; } -size_t -ClassDescriptorV2::iVarsStorage::size () -{ - return m_ivars.size(); -} +ClassDescriptorV2::iVarsStorage::iVarsStorage() + : m_filled(false), m_ivars(), m_mutex() {} -ClassDescriptorV2::iVarDescriptor& -ClassDescriptorV2::iVarsStorage::operator[] (size_t idx) -{ - return m_ivars[idx]; +size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); } + +ClassDescriptorV2::iVarDescriptor &ClassDescriptorV2::iVarsStorage:: +operator[](size_t idx) { + return m_ivars[idx]; } -void -ClassDescriptorV2::iVarsStorage::fill (AppleObjCRuntimeV2& runtime, ClassDescriptorV2& descriptor) -{ - if (m_filled) - return; - std::lock_guard<std::recursive_mutex> guard(m_mutex); - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES | LIBLLDB_LOG_VERBOSE)); +void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime, + ClassDescriptorV2 &descriptor) { + if (m_filled) + return; + std::lock_guard<std::recursive_mutex> guard(m_mutex); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("[ClassDescriptorV2::iVarsStorage::fill] class_name = %s", + descriptor.GetClassName().AsCString("<unknown")); + m_filled = true; + ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp( + runtime.GetEncodingToType()); + Process *process(runtime.GetProcess()); + if (!encoding_to_type_sp) + return; + descriptor.Describe(nullptr, nullptr, nullptr, [this, process, + encoding_to_type_sp, + log](const char *name, + const char *type, + lldb::addr_t offset_ptr, + uint64_t size) -> bool { + const bool for_expression = false; + const bool stop_loop = false; if (log) - log->Printf("[ClassDescriptorV2::iVarsStorage::fill] class_name = %s", descriptor.GetClassName().AsCString("<unknown")); - m_filled = true; - ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(runtime.GetEncodingToType()); - Process* process(runtime.GetProcess()); - if (!encoding_to_type_sp) - return; - descriptor.Describe(nullptr, - nullptr, - nullptr, - [this,process,encoding_to_type_sp,log](const char * name, const char * type, lldb::addr_t offset_ptr, uint64_t size) -> bool { - const bool for_expression = false; - const bool stop_loop = false; - if (log) - log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, encoding = %s, offset_ptr = %" PRIx64 ", size = %" PRIu64, - name,type,offset_ptr,size); - CompilerType ivar_type = encoding_to_type_sp->RealizeType(type, for_expression); - if (ivar_type) - { - if (log) - log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, encoding = %s, offset_ptr = %" PRIx64 ", size = %" PRIu64 " , type_size = %" PRIu64, - name,type,offset_ptr,size,ivar_type.GetByteSize(nullptr)); - Scalar offset_scalar; - Error error; - const int offset_ptr_size = 4; - const bool is_signed = false; - size_t read = process->ReadScalarIntegerFromMemory(offset_ptr, offset_ptr_size, is_signed, offset_scalar, error); - if (error.Success() && 4 == read) - { - if (log) - log->Printf("[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64 " --> %" PRIu32, - offset_ptr, offset_scalar.SInt()); - m_ivars.push_back({ ConstString(name), ivar_type, size, offset_scalar.SInt() }); - } - else if (log) - log->Printf("[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64 " --> read fail, read = %zu", - offset_ptr, read); - } - return stop_loop; - }); + log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, encoding " + "= %s, offset_ptr = %" PRIx64 ", size = %" PRIu64, + name, type, offset_ptr, size); + CompilerType ivar_type = + encoding_to_type_sp->RealizeType(type, for_expression); + if (ivar_type) { + if (log) + log->Printf("[ClassDescriptorV2::iVarsStorage::fill] name = %s, " + "encoding = %s, offset_ptr = %" PRIx64 ", size = %" PRIu64 + " , type_size = %" PRIu64, + name, type, offset_ptr, size, + ivar_type.GetByteSize(nullptr)); + Scalar offset_scalar; + Error error; + const int offset_ptr_size = 4; + const bool is_signed = false; + size_t read = process->ReadScalarIntegerFromMemory( + offset_ptr, offset_ptr_size, is_signed, offset_scalar, error); + if (error.Success() && 4 == read) { + if (log) + log->Printf( + "[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64 + " --> %" PRIu32, + offset_ptr, offset_scalar.SInt()); + m_ivars.push_back( + {ConstString(name), ivar_type, size, offset_scalar.SInt()}); + } else if (log) + log->Printf( + "[ClassDescriptorV2::iVarsStorage::fill] offset_ptr = %" PRIx64 + " --> read fail, read = %zu", + offset_ptr, read); + } + return stop_loop; + }); } -void -ClassDescriptorV2::GetIVarInformation () -{ - m_ivars_storage.fill(m_runtime, *this); +void ClassDescriptorV2::GetIVarInformation() { + m_ivars_storage.fill(m_runtime, *this); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index f5fc8bc0644..787423b5476 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -16,397 +16,320 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "AppleObjCRuntimeV2.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { -class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor -{ +class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor { public: - friend class lldb_private::AppleObjCRuntimeV2; - - ~ClassDescriptorV2() override = default; - - ConstString - GetClassName() override; - - ObjCLanguageRuntime::ClassDescriptorSP - GetSuperclass() override; - - ObjCLanguageRuntime::ClassDescriptorSP - GetMetaclass() const override; - - bool - IsValid() override - { - return true; // any Objective-C v2 runtime class descriptor we vend is valid - } - - // a custom descriptor is used for tagged pointers - bool - GetTaggedPointerInfo(uint64_t* info_bits = nullptr, - uint64_t* value_bits = nullptr, - uint64_t* payload = nullptr) override - { - return false; - } - - uint64_t - GetInstanceSize() override; - - ObjCLanguageRuntime::ObjCISA - GetISA() override - { - return m_objc_class_ptr; - } - - bool - Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, - std::function <bool (const char *, const char *)> const &instance_method_func, - std::function <bool (const char *, const char *)> const &class_method_func, - std::function <bool (const char *, const char *, - lldb::addr_t, uint64_t)> const &ivar_func) const override; - - size_t - GetNumIVars() override - { - GetIVarInformation(); - return m_ivars_storage.size(); - } - - iVarDescriptor - GetIVarAtIndex(size_t idx) override - { - if (idx >= GetNumIVars()) - return iVarDescriptor(); - return m_ivars_storage[idx]; - } - + friend class lldb_private::AppleObjCRuntimeV2; + + ~ClassDescriptorV2() override = default; + + ConstString GetClassName() override; + + ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override; + + ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override; + + bool IsValid() override { + return true; // any Objective-C v2 runtime class descriptor we vend is valid + } + + // a custom descriptor is used for tagged pointers + bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, + uint64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; + } + + uint64_t GetInstanceSize() override; + + ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; } + + bool Describe( + std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, + std::function<bool(const char *, const char *)> const + &instance_method_func, + std::function<bool(const char *, const char *)> const &class_method_func, + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)> const &ivar_func) const override; + + size_t GetNumIVars() override { + GetIVarInformation(); + return m_ivars_storage.size(); + } + + iVarDescriptor GetIVarAtIndex(size_t idx) override { + if (idx >= GetNumIVars()) + return iVarDescriptor(); + return m_ivars_storage[idx]; + } + protected: - void - GetIVarInformation (); - + void GetIVarInformation(); + private: - static const uint32_t RW_REALIZED = (1 << 31); - - struct objc_class_t { - ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. - ObjCLanguageRuntime::ObjCISA m_superclass; - lldb::addr_t m_cache_ptr; - lldb::addr_t m_vtable_ptr; - lldb::addr_t m_data_ptr; - uint8_t m_flags; - - objc_class_t () : - m_isa (0), - m_superclass (0), - m_cache_ptr (0), - m_vtable_ptr (0), - m_data_ptr (0), - m_flags (0) - { - } - - void - Clear() - { - m_isa = 0; - m_superclass = 0; - m_cache_ptr = 0; - m_vtable_ptr = 0; - m_data_ptr = 0; - m_flags = 0; - } - - bool - Read(Process *process, lldb::addr_t addr); - }; - - struct class_ro_t { - uint32_t m_flags; - uint32_t m_instanceStart; - uint32_t m_instanceSize; - uint32_t m_reserved; - - lldb::addr_t m_ivarLayout_ptr; - lldb::addr_t m_name_ptr; - lldb::addr_t m_baseMethods_ptr; - lldb::addr_t m_baseProtocols_ptr; - lldb::addr_t m_ivars_ptr; - - lldb::addr_t m_weakIvarLayout_ptr; - lldb::addr_t m_baseProperties_ptr; - - std::string m_name; - - bool - Read(Process *process, lldb::addr_t addr); - }; - - struct class_rw_t { - uint32_t m_flags; - uint32_t m_version; - - lldb::addr_t m_ro_ptr; - union { - lldb::addr_t m_method_list_ptr; - lldb::addr_t m_method_lists_ptr; - }; - lldb::addr_t m_properties_ptr; - lldb::addr_t m_protocols_ptr; - - ObjCLanguageRuntime::ObjCISA m_firstSubclass; - ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; - - bool - Read(Process *process, lldb::addr_t addr); - }; - - struct method_list_t - { - uint32_t m_entsize; - uint32_t m_count; - lldb::addr_t m_first_ptr; - - bool - Read(Process *process, lldb::addr_t addr); - }; - - struct method_t - { - lldb::addr_t m_name_ptr; - lldb::addr_t m_types_ptr; - lldb::addr_t m_imp_ptr; - - std::string m_name; - std::string m_types; - - static size_t GetSize(Process *process) - { - size_t ptr_size = process->GetAddressByteSize(); - - return ptr_size // SEL name; - + ptr_size // const char *types; - + ptr_size; // IMP imp; - } - - bool - Read(Process *process, lldb::addr_t addr); - }; - - struct ivar_list_t - { - uint32_t m_entsize; - uint32_t m_count; - lldb::addr_t m_first_ptr; - - bool Read(Process *process, lldb::addr_t addr); - }; - - struct ivar_t - { - lldb::addr_t m_offset_ptr; - lldb::addr_t m_name_ptr; - lldb::addr_t m_type_ptr; - uint32_t m_alignment; - uint32_t m_size; - - std::string m_name; - std::string m_type; - - static size_t GetSize(Process *process) - { - size_t ptr_size = process->GetAddressByteSize(); - - return ptr_size // uintptr_t *offset; - + ptr_size // const char *name; - + ptr_size // const char *type; - + sizeof(uint32_t) // uint32_t alignment; - + sizeof(uint32_t); // uint32_t size; - } - - bool - Read(Process *process, lldb::addr_t addr); - }; - - class iVarsStorage - { - public: - iVarsStorage (); - - size_t - size (); - - iVarDescriptor& - operator[] (size_t idx); - - void - fill (AppleObjCRuntimeV2& runtime, ClassDescriptorV2& descriptor); - - private: - bool m_filled; - std::vector<iVarDescriptor> m_ivars; - std::recursive_mutex m_mutex; + static const uint32_t RW_REALIZED = (1 << 31); + + struct objc_class_t { + ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. + ObjCLanguageRuntime::ObjCISA m_superclass; + lldb::addr_t m_cache_ptr; + lldb::addr_t m_vtable_ptr; + lldb::addr_t m_data_ptr; + uint8_t m_flags; + + objc_class_t() + : m_isa(0), m_superclass(0), m_cache_ptr(0), m_vtable_ptr(0), + m_data_ptr(0), m_flags(0) {} + + void Clear() { + m_isa = 0; + m_superclass = 0; + m_cache_ptr = 0; + m_vtable_ptr = 0; + m_data_ptr = 0; + m_flags = 0; + } + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct class_ro_t { + uint32_t m_flags; + uint32_t m_instanceStart; + uint32_t m_instanceSize; + uint32_t m_reserved; + + lldb::addr_t m_ivarLayout_ptr; + lldb::addr_t m_name_ptr; + lldb::addr_t m_baseMethods_ptr; + lldb::addr_t m_baseProtocols_ptr; + lldb::addr_t m_ivars_ptr; + + lldb::addr_t m_weakIvarLayout_ptr; + lldb::addr_t m_baseProperties_ptr; + + std::string m_name; + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct class_rw_t { + uint32_t m_flags; + uint32_t m_version; + + lldb::addr_t m_ro_ptr; + union { + lldb::addr_t m_method_list_ptr; + lldb::addr_t m_method_lists_ptr; }; - - // The constructor should only be invoked by the runtime as it builds its caches - // or populates them. A ClassDescriptorV2 should only ever exist in a cache. - ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name) : - m_runtime (runtime), - m_objc_class_ptr (isa), - m_name (name), - m_ivars_storage() - { + lldb::addr_t m_properties_ptr; + lldb::addr_t m_protocols_ptr; + + ObjCLanguageRuntime::ObjCISA m_firstSubclass; + ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct method_list_t { + uint32_t m_entsize; + uint32_t m_count; + lldb::addr_t m_first_ptr; + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct method_t { + lldb::addr_t m_name_ptr; + lldb::addr_t m_types_ptr; + lldb::addr_t m_imp_ptr; + + std::string m_name; + std::string m_types; + + static size_t GetSize(Process *process) { + size_t ptr_size = process->GetAddressByteSize(); + + return ptr_size // SEL name; + + ptr_size // const char *types; + + ptr_size; // IMP imp; + } + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct ivar_list_t { + uint32_t m_entsize; + uint32_t m_count; + lldb::addr_t m_first_ptr; + + bool Read(Process *process, lldb::addr_t addr); + }; + + struct ivar_t { + lldb::addr_t m_offset_ptr; + lldb::addr_t m_name_ptr; + lldb::addr_t m_type_ptr; + uint32_t m_alignment; + uint32_t m_size; + + std::string m_name; + std::string m_type; + + static size_t GetSize(Process *process) { + size_t ptr_size = process->GetAddressByteSize(); + + return ptr_size // uintptr_t *offset; + + ptr_size // const char *name; + + ptr_size // const char *type; + + sizeof(uint32_t) // uint32_t alignment; + + sizeof(uint32_t); // uint32_t size; } - - bool - Read_objc_class (Process* process, std::unique_ptr<objc_class_t> &objc_class) const; - - bool - Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr<class_ro_t> &class_ro, std::unique_ptr<class_rw_t> &class_rw) const; - - AppleObjCRuntimeV2 &m_runtime; // The runtime, so we can read information lazily. - lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., objects of this class type have this as their ISA) - ConstString m_name; // May be NULL - iVarsStorage m_ivars_storage; + + bool Read(Process *process, lldb::addr_t addr); + }; + + class iVarsStorage { + public: + iVarsStorage(); + + size_t size(); + + iVarDescriptor &operator[](size_t idx); + + void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor); + + private: + bool m_filled; + std::vector<iVarDescriptor> m_ivars; + std::recursive_mutex m_mutex; + }; + + // The constructor should only be invoked by the runtime as it builds its + // caches + // or populates them. A ClassDescriptorV2 should only ever exist in a cache. + ClassDescriptorV2(AppleObjCRuntimeV2 &runtime, + ObjCLanguageRuntime::ObjCISA isa, const char *name) + : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name), + m_ivars_storage() {} + + bool Read_objc_class(Process *process, + std::unique_ptr<objc_class_t> &objc_class) const; + + bool Read_class_row(Process *process, const objc_class_t &objc_class, + std::unique_ptr<class_ro_t> &class_ro, + std::unique_ptr<class_rw_t> &class_rw) const; + + AppleObjCRuntimeV2 + &m_runtime; // The runtime, so we can read information lazily. + lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., + // objects of this class type have this as + // their ISA) + ConstString m_name; // May be NULL + iVarsStorage m_ivars_storage; }; // tagged pointer descriptor -class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor -{ +class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor { public: - ClassDescriptorV2Tagged (ConstString class_name, - uint64_t payload) - { - m_name = class_name; - if (!m_name) - { - m_valid = false; - return; - } - m_valid = true; - m_payload = payload; - m_info_bits = (m_payload & 0xF0ULL) >> 4; - m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; + ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) { + m_name = class_name; + if (!m_name) { + m_valid = false; + return; } - - ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, - uint64_t payload) - { - if (!actual_class_sp) - { - m_valid = false; - return; - } - m_name = actual_class_sp->GetClassName(); - if (!m_name) - { - m_valid = false; - return; - } - m_valid = true; - m_payload = payload; - m_info_bits = (m_payload & 0x0FULL); - m_value_bits = (m_payload & ~0x0FULL) >> 4; - } - - ~ClassDescriptorV2Tagged() override = default; + m_valid = true; + m_payload = payload; + m_info_bits = (m_payload & 0xF0ULL) >> 4; + m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; + } - ConstString - GetClassName() override - { - return m_name; - } - - ObjCLanguageRuntime::ClassDescriptorSP - GetSuperclass() override - { - // tagged pointers can represent a class that has a superclass, but since that information is not - // stored in the object itself, we would have to query the runtime to discover the hierarchy - // for the time being, we skip this step in the interest of static discovery - return ObjCLanguageRuntime::ClassDescriptorSP(); + ClassDescriptorV2Tagged( + ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, + uint64_t payload) { + if (!actual_class_sp) { + m_valid = false; + return; } - - ObjCLanguageRuntime::ClassDescriptorSP - GetMetaclass() const override - { - return ObjCLanguageRuntime::ClassDescriptorSP(); - } - - bool - IsValid() override - { - return m_valid; - } - - bool - IsKVO() override - { - return false; // tagged pointers are not KVO'ed - } - - bool - IsCFType() override - { - return false; // tagged pointers are not CF objects - } - - bool - GetTaggedPointerInfo(uint64_t* info_bits = nullptr, - uint64_t* value_bits = nullptr, - uint64_t* payload = nullptr) override - { - if (info_bits) - *info_bits = GetInfoBits(); - if (value_bits) - *value_bits = GetValueBits(); - if (payload) - *payload = GetPayload(); - return true; - } - - uint64_t - GetInstanceSize() override - { - return (IsValid() ? m_pointer_size : 0); - } - - ObjCLanguageRuntime::ObjCISA - GetISA() override - { - return 0; // tagged pointers have no ISA - } - - // these calls are not part of any formal tagged pointers specification - virtual uint64_t - GetValueBits () - { - return (IsValid() ? m_value_bits : 0); - } - - virtual uint64_t - GetInfoBits () - { - return (IsValid() ? m_info_bits : 0); - } - - virtual uint64_t - GetPayload () - { - return (IsValid() ? m_payload : 0); + m_name = actual_class_sp->GetClassName(); + if (!m_name) { + m_valid = false; + return; } + m_valid = true; + m_payload = payload; + m_info_bits = (m_payload & 0x0FULL); + m_value_bits = (m_payload & ~0x0FULL) >> 4; + } + + ~ClassDescriptorV2Tagged() override = default; + + ConstString GetClassName() override { return m_name; } + + ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override { + // tagged pointers can represent a class that has a superclass, but since + // that information is not + // stored in the object itself, we would have to query the runtime to + // discover the hierarchy + // for the time being, we skip this step in the interest of static discovery + return ObjCLanguageRuntime::ClassDescriptorSP(); + } + + ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override { + return ObjCLanguageRuntime::ClassDescriptorSP(); + } + + bool IsValid() override { return m_valid; } + + bool IsKVO() override { + return false; // tagged pointers are not KVO'ed + } + + bool IsCFType() override { + return false; // tagged pointers are not CF objects + } + + bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, + uint64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + if (info_bits) + *info_bits = GetInfoBits(); + if (value_bits) + *value_bits = GetValueBits(); + if (payload) + *payload = GetPayload(); + return true; + } + + uint64_t GetInstanceSize() override { + return (IsValid() ? m_pointer_size : 0); + } + + ObjCLanguageRuntime::ObjCISA GetISA() override { + return 0; // tagged pointers have no ISA + } + + // these calls are not part of any formal tagged pointers specification + virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); } + + virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); } + + virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); } private: - ConstString m_name; - uint8_t m_pointer_size; - bool m_valid; - uint64_t m_info_bits; - uint64_t m_value_bits; - uint64_t m_payload; + ConstString m_name; + uint8_t m_pointer_size; + bool m_valid; + uint64_t m_info_bits; + uint64_t m_value_bits; + uint64_t m_payload; }; - + } // namespace lldb_private #endif // liblldb_AppleObjCClassDescriptorV2_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 0c0e4f1ce8c..922d192c333 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -23,659 +23,628 @@ using namespace lldb_private; -class lldb_private::AppleObjCExternalASTSource : public ClangExternalASTSourceCommon -{ +class lldb_private::AppleObjCExternalASTSource + : public ClangExternalASTSourceCommon { public: - AppleObjCExternalASTSource (AppleObjCDeclVendor &decl_vendor) : - m_decl_vendor(decl_vendor) - { - } + AppleObjCExternalASTSource(AppleObjCDeclVendor &decl_vendor) + : m_decl_vendor(decl_vendor) {} - bool - FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, clang::DeclarationName name) override - { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; + bool FindExternalVisibleDeclsByName(const clang::DeclContext *decl_ctx, + clang::DeclarationName name) override { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + Log *log(GetLogIfAllCategoriesSet( + LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - if (log) - { - log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p", - current_id, - static_cast<void*>(&decl_ctx->getParentASTContext()), - name.getAsString().c_str(), decl_ctx->getDeclKindName(), - static_cast<const void*>(decl_ctx)); - } + if (log) { + log->Printf("AppleObjCExternalASTSource::FindExternalVisibleDeclsByName[%" + "u] on (ASTContext*)%p Looking for %s in (%sDecl*)%p", + current_id, + static_cast<void *>(&decl_ctx->getParentASTContext()), + name.getAsString().c_str(), decl_ctx->getDeclKindName(), + static_cast<const void *>(decl_ctx)); + } - do - { - const clang::ObjCInterfaceDecl *interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx); + do { + const clang::ObjCInterfaceDecl *interface_decl = + llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl_ctx); - if (!interface_decl) - break; + if (!interface_decl) + break; - clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl); + clang::ObjCInterfaceDecl *non_const_interface_decl = + const_cast<clang::ObjCInterfaceDecl *>(interface_decl); - if (!m_decl_vendor.FinishDecl(non_const_interface_decl)) - break; + if (!m_decl_vendor.FinishDecl(non_const_interface_decl)) + break; - clang::DeclContext::lookup_result result = non_const_interface_decl->lookup(name); + clang::DeclContext::lookup_result result = + non_const_interface_decl->lookup(name); - return (result.size() != 0); - } - while(0); + return (result.size() != 0); + } while (0); - SetNoExternalVisibleDeclsForName(decl_ctx, name); - return false; - } + SetNoExternalVisibleDeclsForName(decl_ctx, name); + return false; + } - void - CompleteType(clang::TagDecl *tag_decl) override - { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; + void CompleteType(clang::TagDecl *tag_decl) override { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + Log *log(GetLogIfAllCategoriesSet( + LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - if (log) - { - log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s", - current_id, - static_cast<void*>(&tag_decl->getASTContext()), - static_cast<void*>(tag_decl), - tag_decl->getName().str().c_str()); - - log->Printf(" AOEAS::CT[%u] Before:", current_id); - ASTDumper dumper((clang::Decl*)tag_decl); - dumper.ToLog(log, " [CT] "); - } + if (log) { + log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on " + "(ASTContext*)%p Completing (TagDecl*)%p named %s", + current_id, static_cast<void *>(&tag_decl->getASTContext()), + static_cast<void *>(tag_decl), + tag_decl->getName().str().c_str()); - if (log) - { - log->Printf(" AOEAS::CT[%u] After:", current_id); - ASTDumper dumper((clang::Decl*)tag_decl); - dumper.ToLog(log, " [CT] "); - } - return; + log->Printf(" AOEAS::CT[%u] Before:", current_id); + ASTDumper dumper((clang::Decl *)tag_decl); + dumper.ToLog(log, " [CT] "); } - void - CompleteType(clang::ObjCInterfaceDecl *interface_decl) override - { - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; + if (log) { + log->Printf(" AOEAS::CT[%u] After:", current_id); + ASTDumper dumper((clang::Decl *)tag_decl); + dumper.ToLog(log, " [CT] "); + } + return; + } - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + void CompleteType(clang::ObjCInterfaceDecl *interface_decl) override { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; - if (log) - { - log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on (ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s", - current_id, - static_cast<void*>(&interface_decl->getASTContext()), - static_cast<void*>(interface_decl), - interface_decl->getName().str().c_str()); - - log->Printf(" AOEAS::CT[%u] Before:", current_id); - ASTDumper dumper((clang::Decl*)interface_decl); - dumper.ToLog(log, " [CT] "); - } + Log *log(GetLogIfAllCategoriesSet( + LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - m_decl_vendor.FinishDecl(interface_decl); + if (log) { + log->Printf("AppleObjCExternalASTSource::CompleteType[%u] on " + "(ASTContext*)%p Completing (ObjCInterfaceDecl*)%p named %s", + current_id, + static_cast<void *>(&interface_decl->getASTContext()), + static_cast<void *>(interface_decl), + interface_decl->getName().str().c_str()); - if (log) - { - log->Printf(" [CT] After:"); - ASTDumper dumper((clang::Decl*)interface_decl); - dumper.ToLog(log, " [CT] "); - } - return; + log->Printf(" AOEAS::CT[%u] Before:", current_id); + ASTDumper dumper((clang::Decl *)interface_decl); + dumper.ToLog(log, " [CT] "); } - bool - layoutRecordType(const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, - llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets, - llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets) override - { - return false; - } + m_decl_vendor.FinishDecl(interface_decl); - void - StartTranslationUnit(clang::ASTConsumer *Consumer) override - { - clang::TranslationUnitDecl *translation_unit_decl = m_decl_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl(); - translation_unit_decl->setHasExternalVisibleStorage(); - translation_unit_decl->setHasExternalLexicalStorage(); + if (log) { + log->Printf(" [CT] After:"); + ASTDumper dumper((clang::Decl *)interface_decl); + dumper.ToLog(log, " [CT] "); } + return; + } + + bool layoutRecordType( + const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &BaseOffsets, + llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits> + &VirtualBaseOffsets) override { + return false; + } + + void StartTranslationUnit(clang::ASTConsumer *Consumer) override { + clang::TranslationUnitDecl *translation_unit_decl = + m_decl_vendor.m_ast_ctx.getASTContext()->getTranslationUnitDecl(); + translation_unit_decl->setHasExternalVisibleStorage(); + translation_unit_decl->setHasExternalLexicalStorage(); + } + private: - AppleObjCDeclVendor &m_decl_vendor; + AppleObjCDeclVendor &m_decl_vendor; }; -AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) : - DeclVendor(), - m_runtime(runtime), - m_ast_ctx(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().getTriple().c_str()), - m_type_realizer_sp(m_runtime.GetEncodingToType()) -{ - m_external_source = new AppleObjCExternalASTSource (*this); - llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr (m_external_source); - m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr); +AppleObjCDeclVendor::AppleObjCDeclVendor(ObjCLanguageRuntime &runtime) + : DeclVendor(), m_runtime(runtime), m_ast_ctx(runtime.GetProcess() + ->GetTarget() + .GetArchitecture() + .GetTriple() + .getTriple() + .c_str()), + m_type_realizer_sp(m_runtime.GetEncodingToType()) { + m_external_source = new AppleObjCExternalASTSource(*this); + llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> external_source_owning_ptr( + m_external_source); + m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr); } -clang::ObjCInterfaceDecl* -AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) -{ - ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa); - - if (iter != m_isa_to_interface.end()) - return iter->second; - - clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); - - ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(isa); - - if (!descriptor) - return NULL; - - const ConstString &name(descriptor->GetClassName()); - - clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef()); - - clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx, - ast_ctx->getTranslationUnitDecl(), - clang::SourceLocation(), - &identifier_info, - nullptr, - nullptr); - - ClangASTMetadata meta_data; - meta_data.SetISAPtr(isa); - m_external_source->SetMetadata(new_iface_decl, meta_data); - - new_iface_decl->setHasExternalVisibleStorage(); - new_iface_decl->setHasExternalLexicalStorage(); - - ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl); - - m_isa_to_interface[isa] = new_iface_decl; - - return new_iface_decl; +clang::ObjCInterfaceDecl * +AppleObjCDeclVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa) { + ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa); + + if (iter != m_isa_to_interface.end()) + return iter->second; + + clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + + ObjCLanguageRuntime::ClassDescriptorSP descriptor = + m_runtime.GetClassDescriptorFromISA(isa); + + if (!descriptor) + return NULL; + + const ConstString &name(descriptor->GetClassName()); + + clang::IdentifierInfo &identifier_info = + ast_ctx->Idents.get(name.GetStringRef()); + + clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create( + *ast_ctx, ast_ctx->getTranslationUnitDecl(), clang::SourceLocation(), + &identifier_info, nullptr, nullptr); + + ClangASTMetadata meta_data; + meta_data.SetISAPtr(isa); + m_external_source->SetMetadata(new_iface_decl, meta_data); + + new_iface_decl->setHasExternalVisibleStorage(); + new_iface_decl->setHasExternalLexicalStorage(); + + ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl); + + m_isa_to_interface[isa] = new_iface_decl; + + return new_iface_decl; } -class ObjCRuntimeMethodType -{ +class ObjCRuntimeMethodType { public: - ObjCRuntimeMethodType (const char *types) : m_is_valid(false) - { - const char *cursor = types; - enum ParserState { - Start = 0, - InType, - InPos - } state = Start; - const char *type = NULL; - int brace_depth = 0; - - uint32_t stepsLeft = 256; - - while (1) - { - if (--stepsLeft == 0) - { - m_is_valid = false; - return; - } - - switch (state) - { - case Start: - { - switch (*cursor) - { - default: - state = InType; - type = cursor; - break; - case '\0': - m_is_valid = true; - return; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - m_is_valid = false; - return; - } - } - break; - case InType: - { - switch (*cursor) - { - default: - ++cursor; - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (!brace_depth) - { - state = InPos; - if (type) - { - m_type_vector.push_back(std::string(type, (cursor - type))); - } - else - { - m_is_valid = false; - return; - } - type = NULL; - } - else - { - ++cursor; - } - break; - case '[': case '{': case '(': - ++brace_depth; - ++cursor; - break; - case ']': case '}': case ')': - if (!brace_depth) - { - m_is_valid = false; - return; - } - --brace_depth; - ++cursor; - break; - case '\0': - m_is_valid = false; - return; - } - } - break; - case InPos: - { - switch (*cursor) - { - default: - state = InType; - type = cursor; - break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - ++cursor; - break; - case '\0': - m_is_valid = true; - return; - } - } - break; - } + ObjCRuntimeMethodType(const char *types) : m_is_valid(false) { + const char *cursor = types; + enum ParserState { Start = 0, InType, InPos } state = Start; + const char *type = NULL; + int brace_depth = 0; + + uint32_t stepsLeft = 256; + + while (1) { + if (--stepsLeft == 0) { + m_is_valid = false; + return; + } + + switch (state) { + case Start: { + switch (*cursor) { + default: + state = InType; + type = cursor; + break; + case '\0': + m_is_valid = true; + return; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + m_is_valid = false; + return; } - } - - clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name, bool instance, ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) - { - if (!m_is_valid || m_type_vector.size() < 3) - return NULL; - - clang::ASTContext &ast_ctx(interface_decl->getASTContext()); - - clang::QualType return_qual_type; - - const bool isInstance = instance; - const bool isVariadic = false; - const bool isSynthesized = false; - const bool isImplicitlyDeclared = true; - const bool isDefined = false; - const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None; - const bool HasRelatedResultType = false; - const bool for_expression = true; - - std::vector <clang::IdentifierInfo *> selector_components; - - const char *name_cursor = name; - bool is_zero_argument = true; - - - while (*name_cursor != '\0') - { - const char *colon_loc = strchr(name_cursor, ':'); - if (!colon_loc) - { - selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor))); - break; - } - else - { - is_zero_argument = false; - selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor))); - name_cursor = colon_loc + 1; + } break; + case InType: { + switch (*cursor) { + default: + ++cursor; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (!brace_depth) { + state = InPos; + if (type) { + m_type_vector.push_back(std::string(type, (cursor - type))); + } else { + m_is_valid = false; + return; } + type = NULL; + } else { + ++cursor; + } + break; + case '[': + case '{': + case '(': + ++brace_depth; + ++cursor; + break; + case ']': + case '}': + case ')': + if (!brace_depth) { + m_is_valid = false; + return; + } + --brace_depth; + ++cursor; + break; + case '\0': + m_is_valid = false; + return; } - - clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data()); - - clang::QualType ret_type = ClangUtil::GetQualType( - type_realizer_sp->RealizeType(interface_decl->getASTContext(), m_type_vector[0].c_str(), for_expression)); - - if (ret_type.isNull()) - return NULL; - - clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx, - clang::SourceLocation(), - clang::SourceLocation(), - sel, - ret_type, - NULL, - interface_decl, - isInstance, - isVariadic, - isSynthesized, - isImplicitlyDeclared, - isDefined, - impControl, - HasRelatedResultType); - - std::vector <clang::ParmVarDecl*> parm_vars; - - for (size_t ai = 3, ae = m_type_vector.size(); - ai != ae; - ++ai) - { - const bool for_expression = true; - clang::QualType arg_type = ClangUtil::GetQualType( - type_realizer_sp->RealizeType(ast_ctx, m_type_vector[ai].c_str(), for_expression)); - - if (arg_type.isNull()) - return NULL; // well, we just wasted a bunch of time. Wish we could delete the stuff we'd just made! - - parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx, - ret, - clang::SourceLocation(), - clang::SourceLocation(), - NULL, - arg_type, - NULL, - clang::SC_None, - NULL)); + } break; + case InPos: { + switch (*cursor) { + default: + state = InType; + type = cursor; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ++cursor; + break; + case '\0': + m_is_valid = true; + return; } - - ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>()); - - return ret; - } - - explicit operator bool () - { - return m_is_valid; + } break; + } } - - size_t - GetNumTypes () - { - return m_type_vector.size(); + } + + clang::ObjCMethodDecl * + BuildMethod(clang::ObjCInterfaceDecl *interface_decl, const char *name, + bool instance, + ObjCLanguageRuntime::EncodingToTypeSP type_realizer_sp) { + if (!m_is_valid || m_type_vector.size() < 3) + return NULL; + + clang::ASTContext &ast_ctx(interface_decl->getASTContext()); + + clang::QualType return_qual_type; + + const bool isInstance = instance; + const bool isVariadic = false; + const bool isSynthesized = false; + const bool isImplicitlyDeclared = true; + const bool isDefined = false; + const clang::ObjCMethodDecl::ImplementationControl impControl = + clang::ObjCMethodDecl::None; + const bool HasRelatedResultType = false; + const bool for_expression = true; + + std::vector<clang::IdentifierInfo *> selector_components; + + const char *name_cursor = name; + bool is_zero_argument = true; + + while (*name_cursor != '\0') { + const char *colon_loc = strchr(name_cursor, ':'); + if (!colon_loc) { + selector_components.push_back( + &ast_ctx.Idents.get(llvm::StringRef(name_cursor))); + break; + } else { + is_zero_argument = false; + selector_components.push_back(&ast_ctx.Idents.get( + llvm::StringRef(name_cursor, colon_loc - name_cursor))); + name_cursor = colon_loc + 1; + } } - - const char* - GetTypeAtIndex (size_t idx) - { - return m_type_vector[idx].c_str(); + + clang::Selector sel = ast_ctx.Selectors.getSelector( + is_zero_argument ? 0 : selector_components.size(), + selector_components.data()); + + clang::QualType ret_type = + ClangUtil::GetQualType(type_realizer_sp->RealizeType( + interface_decl->getASTContext(), m_type_vector[0].c_str(), + for_expression)); + + if (ret_type.isNull()) + return NULL; + + clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create( + ast_ctx, clang::SourceLocation(), clang::SourceLocation(), sel, + ret_type, NULL, interface_decl, isInstance, isVariadic, isSynthesized, + isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); + + std::vector<clang::ParmVarDecl *> parm_vars; + + for (size_t ai = 3, ae = m_type_vector.size(); ai != ae; ++ai) { + const bool for_expression = true; + clang::QualType arg_type = + ClangUtil::GetQualType(type_realizer_sp->RealizeType( + ast_ctx, m_type_vector[ai].c_str(), for_expression)); + + if (arg_type.isNull()) + return NULL; // well, we just wasted a bunch of time. Wish we could + // delete the stuff we'd just made! + + parm_vars.push_back(clang::ParmVarDecl::Create( + ast_ctx, ret, clang::SourceLocation(), clang::SourceLocation(), NULL, + arg_type, NULL, clang::SC_None, NULL)); } - + + ret->setMethodParams(ast_ctx, + llvm::ArrayRef<clang::ParmVarDecl *>(parm_vars), + llvm::ArrayRef<clang::SourceLocation>()); + + return ret; + } + + explicit operator bool() { return m_is_valid; } + + size_t GetNumTypes() { return m_type_vector.size(); } + + const char *GetTypeAtIndex(size_t idx) { return m_type_vector[idx].c_str(); } + private: - typedef std::vector <std::string> TypeVector; - - TypeVector m_type_vector; - bool m_is_valid; + typedef std::vector<std::string> TypeVector; + + TypeVector m_type_vector; + bool m_is_valid; }; -bool -AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - - ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl); - ObjCLanguageRuntime::ObjCISA objc_isa = 0; - if (metadata) - objc_isa = metadata->GetISAPtr(); - - if (!objc_isa) - return false; - - if (!interface_decl->hasExternalVisibleStorage()) - return true; - - interface_decl->startDefinition(); - - interface_decl->setHasExternalVisibleStorage(false); - interface_decl->setHasExternalLexicalStorage(false); - - ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptorFromISA(objc_isa); - - if (!descriptor) - return false; - - auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa) - { - clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa); - - if (!superclass_decl) - return; - - FinishDecl(superclass_decl); - clang::ASTContext *context = m_ast_ctx.getASTContext(); - interface_decl->setSuperClass( - context->getTrivialTypeSourceInfo(context->getObjCInterfaceType(superclass_decl))); - }; - - auto instance_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool - { - if (!name || !types) - return false; // skip this one - - ObjCRuntimeMethodType method_type(types); - - clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, true, m_type_realizer_sp); - - if (log) - log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types); - - if (method_decl) - interface_decl->addDecl(method_decl); - - return false; - }; - - auto class_method_func = [log, interface_decl, this](const char *name, const char *types) -> bool - { - if (!name || !types) - return false; // skip this one - - ObjCRuntimeMethodType method_type(types); - - clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name, false, m_type_realizer_sp); - - if (log) - log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types); - - if (method_decl) - interface_decl->addDecl(method_decl); - - return false; - }; - - auto ivar_func = [log, interface_decl, this](const char *name, const char *type, lldb::addr_t offset_ptr, uint64_t size) -> bool - { - if (!name || !type) - return false; - - const bool for_expression = false; - - if (log) - log->Printf("[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64, name, type, offset_ptr); - - CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType(m_ast_ctx, type, for_expression); - - if (ivar_type.IsValid()) - { - clang::TypeSourceInfo * const type_source_info = nullptr; - const bool is_synthesized = false; - clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create( - *m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(), clang::SourceLocation(), - &m_ast_ctx.getASTContext()->Idents.get(name), ClangUtil::GetQualType(ivar_type), - type_source_info, // TypeSourceInfo * - clang::ObjCIvarDecl::Public, 0, is_synthesized); - - if (ivar_decl) - { - interface_decl->addDecl(ivar_decl); - } - } - - return false; - }; - +bool AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl) { + Log *log(GetLogIfAllCategoriesSet( + LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + ClangASTMetadata *metadata = m_external_source->GetMetadata(interface_decl); + ObjCLanguageRuntime::ObjCISA objc_isa = 0; + if (metadata) + objc_isa = metadata->GetISAPtr(); + + if (!objc_isa) + return false; + + if (!interface_decl->hasExternalVisibleStorage()) + return true; + + interface_decl->startDefinition(); + + interface_decl->setHasExternalVisibleStorage(false); + interface_decl->setHasExternalLexicalStorage(false); + + ObjCLanguageRuntime::ClassDescriptorSP descriptor = + m_runtime.GetClassDescriptorFromISA(objc_isa); + + if (!descriptor) + return false; + + auto superclass_func = [interface_decl, + this](ObjCLanguageRuntime::ObjCISA isa) { + clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa); + + if (!superclass_decl) + return; + + FinishDecl(superclass_decl); + clang::ASTContext *context = m_ast_ctx.getASTContext(); + interface_decl->setSuperClass(context->getTrivialTypeSourceInfo( + context->getObjCInterfaceType(superclass_decl))); + }; + + auto instance_method_func = + [log, interface_decl, this](const char *name, const char *types) -> bool { + if (!name || !types) + return false; // skip this one + + ObjCRuntimeMethodType method_type(types); + + clang::ObjCMethodDecl *method_decl = + method_type.BuildMethod(interface_decl, name, true, m_type_realizer_sp); + if (log) - { - ASTDumper method_dumper ((clang::Decl*)interface_decl); - - log->Printf("[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C interface for %s", descriptor->GetClassName().AsCString()); - } - - - if (!descriptor->Describe(superclass_func, - instance_method_func, - class_method_func, - ivar_func)) - return false; - + log->Printf("[ AOTV::FD] Instance method [%s] [%s]", name, types); + + if (method_decl) + interface_decl->addDecl(method_decl); + + return false; + }; + + auto class_method_func = [log, interface_decl, + this](const char *name, const char *types) -> bool { + if (!name || !types) + return false; // skip this one + + ObjCRuntimeMethodType method_type(types); + + clang::ObjCMethodDecl *method_decl = method_type.BuildMethod( + interface_decl, name, false, m_type_realizer_sp); + if (log) - { - ASTDumper method_dumper ((clang::Decl*)interface_decl); - - log->Printf("[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface"); - - method_dumper.ToLog(log, " [AOTV::FD] "); + log->Printf("[ AOTV::FD] Class method [%s] [%s]", name, types); + + if (method_decl) + interface_decl->addDecl(method_decl); + + return false; + }; + + auto ivar_func = [log, interface_decl, + this](const char *name, const char *type, + lldb::addr_t offset_ptr, uint64_t size) -> bool { + if (!name || !type) + return false; + + const bool for_expression = false; + + if (log) + log->Printf( + "[ AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64, name, + type, offset_ptr); + + CompilerType ivar_type = m_runtime.GetEncodingToType()->RealizeType( + m_ast_ctx, type, for_expression); + + if (ivar_type.IsValid()) { + clang::TypeSourceInfo *const type_source_info = nullptr; + const bool is_synthesized = false; + clang::ObjCIvarDecl *ivar_decl = clang::ObjCIvarDecl::Create( + *m_ast_ctx.getASTContext(), interface_decl, clang::SourceLocation(), + clang::SourceLocation(), &m_ast_ctx.getASTContext()->Idents.get(name), + ClangUtil::GetQualType(ivar_type), + type_source_info, // TypeSourceInfo * + clang::ObjCIvarDecl::Public, 0, is_synthesized); + + if (ivar_decl) { + interface_decl->addDecl(ivar_decl); + } } - - return true; + + return false; + }; + + if (log) { + ASTDumper method_dumper((clang::Decl *)interface_decl); + + log->Printf("[AppleObjCDeclVendor::FinishDecl] Finishing Objective-C " + "interface for %s", + descriptor->GetClassName().AsCString()); + } + + if (!descriptor->Describe(superclass_func, instance_method_func, + class_method_func, ivar_func)) + return false; + + if (log) { + ASTDumper method_dumper((clang::Decl *)interface_decl); + + log->Printf( + "[AppleObjCDeclVendor::FinishDecl] Finished Objective-C interface"); + + method_dumper.ToLog(log, " [AOTV::FD] "); + } + + return true; } uint32_t -AppleObjCDeclVendor::FindDecls (const ConstString &name, - bool append, - uint32_t max_matches, - std::vector <clang::NamedDecl *> &decls) -{ - static unsigned int invocation_id = 0; - unsigned int current_id = invocation_id++; - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? - - if (log) - log->Printf("AppleObjCDeclVendor::FindTypes [%u] ('%s', %s, %u, )", - current_id, - (const char*)name.AsCString(), - append ? "true" : "false", - max_matches); - - if (!append) - decls.clear(); - - uint32_t ret = 0; - - do - { - // See if the type is already in our ASTContext. - - clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); - - clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef()); - clang::DeclarationName decl_name = ast_ctx->DeclarationNames.getIdentifier(&identifier_info); - - clang::DeclContext::lookup_result lookup_result = ast_ctx->getTranslationUnitDecl()->lookup(decl_name); - - if (!lookup_result.empty()) - { - if (clang::ObjCInterfaceDecl *result_iface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) - { - if (log) - { - clang::QualType result_iface_type = ast_ctx->getObjCInterfaceType(result_iface_decl); - ASTDumper dumper(result_iface_type); - - uint64_t isa_value = LLDB_INVALID_ADDRESS; - ClangASTMetadata *metadata = m_external_source->GetMetadata(result_iface_decl); - if (metadata) - isa_value = metadata->GetISAPtr(); - - log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 ") in the ASTContext", - current_id, - dumper.GetCString(), - isa_value); - } - - decls.push_back(result_iface_decl); - ret++; - break; - } - else - { - if (log) - log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but it's not something we know about", - current_id); - break; - } - } - else if(log) - { - log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext", - current_id, - name.AsCString()); - } - - // It's not. If it exists, we have to put it into our ASTContext. - - ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); - - if (!isa) - { - if (log) - log->Printf("AOCTV::FT [%u] Couldn't find the isa", - current_id); - - break; - } - - clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa); - - if (!iface_decl) - { - if (log) - log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%" PRIx64, - current_id, - (uint64_t)isa); - - break; - } - - if (log) - { - clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl); - ASTDumper dumper(new_iface_type); - log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")", - current_id, - dumper.GetCString(), - (uint64_t)isa); +AppleObjCDeclVendor::FindDecls(const ConstString &name, bool append, + uint32_t max_matches, + std::vector<clang::NamedDecl *> &decls) { + static unsigned int invocation_id = 0; + unsigned int current_id = invocation_id++; + + Log *log(GetLogIfAllCategoriesSet( + LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel? + + if (log) + log->Printf("AppleObjCDeclVendor::FindTypes [%u] ('%s', %s, %u, )", + current_id, (const char *)name.AsCString(), + append ? "true" : "false", max_matches); + + if (!append) + decls.clear(); + + uint32_t ret = 0; + + do { + // See if the type is already in our ASTContext. + + clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext(); + + clang::IdentifierInfo &identifier_info = + ast_ctx->Idents.get(name.GetStringRef()); + clang::DeclarationName decl_name = + ast_ctx->DeclarationNames.getIdentifier(&identifier_info); + + clang::DeclContext::lookup_result lookup_result = + ast_ctx->getTranslationUnitDecl()->lookup(decl_name); + + if (!lookup_result.empty()) { + if (clang::ObjCInterfaceDecl *result_iface_decl = + llvm::dyn_cast<clang::ObjCInterfaceDecl>(lookup_result[0])) { + if (log) { + clang::QualType result_iface_type = + ast_ctx->getObjCInterfaceType(result_iface_decl); + ASTDumper dumper(result_iface_type); + + uint64_t isa_value = LLDB_INVALID_ADDRESS; + ClangASTMetadata *metadata = + m_external_source->GetMetadata(result_iface_decl); + if (metadata) + isa_value = metadata->GetISAPtr(); + + log->Printf("AOCTV::FT [%u] Found %s (isa 0x%" PRIx64 + ") in the ASTContext", + current_id, dumper.GetCString(), isa_value); } - - decls.push_back(iface_decl); + + decls.push_back(result_iface_decl); ret++; break; - } while (0); - - return ret; + } else { + if (log) + log->Printf("AOCTV::FT [%u] There's something in the ASTContext, but " + "it's not something we know about", + current_id); + break; + } + } else if (log) { + log->Printf("AOCTV::FT [%u] Couldn't find %s in the ASTContext", + current_id, name.AsCString()); + } + + // It's not. If it exists, we have to put it into our ASTContext. + + ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name); + + if (!isa) { + if (log) + log->Printf("AOCTV::FT [%u] Couldn't find the isa", current_id); + + break; + } + + clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa); + + if (!iface_decl) { + if (log) + log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for " + "isa 0x%" PRIx64, + current_id, (uint64_t)isa); + + break; + } + + if (log) { + clang::QualType new_iface_type = + ast_ctx->getObjCInterfaceType(iface_decl); + ASTDumper dumper(new_iface_type); + log->Printf("AOCTV::FT [%u] Created %s (isa 0x%" PRIx64 ")", current_id, + dumper.GetCString(), (uint64_t)isa); + } + + decls.push_back(iface_decl); + ret++; + break; + } while (0); + + return ret; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index 88789c7b5a8..26824079d94 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -14,40 +14,38 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { class AppleObjCExternalASTSource; - -class AppleObjCDeclVendor : public DeclVendor -{ + +class AppleObjCDeclVendor : public DeclVendor { public: - AppleObjCDeclVendor(ObjCLanguageRuntime &runtime); - - uint32_t - FindDecls(const ConstString &name, - bool append, - uint32_t max_matches, - std::vector <clang::NamedDecl *> &decls) override; - - friend class AppleObjCExternalASTSource; + AppleObjCDeclVendor(ObjCLanguageRuntime &runtime); + + uint32_t FindDecls(const ConstString &name, bool append, uint32_t max_matches, + std::vector<clang::NamedDecl *> &decls) override; + + friend class AppleObjCExternalASTSource; private: - clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa); - bool FinishDecl(clang::ObjCInterfaceDecl *decl); - - ObjCLanguageRuntime &m_runtime; - ClangASTContext m_ast_ctx; - ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp; - AppleObjCExternalASTSource *m_external_source; - - typedef llvm::DenseMap<ObjCLanguageRuntime::ObjCISA, clang::ObjCInterfaceDecl *> ISAToInterfaceMap; - - ISAToInterfaceMap m_isa_to_interface; + clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa); + bool FinishDecl(clang::ObjCInterfaceDecl *decl); + + ObjCLanguageRuntime &m_runtime; + ClangASTContext m_ast_ctx; + ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp; + AppleObjCExternalASTSource *m_external_source; + + typedef llvm::DenseMap<ObjCLanguageRuntime::ObjCISA, + clang::ObjCInterfaceDecl *> + ISAToInterfaceMap; + + ISAToInterfaceMap m_isa_to_interface; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 84d5f81ed04..24eddb51600 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -1,4 +1,5 @@ -//===-- AppleObjCRuntime.cpp -------------------------------------*- C++ -*-===// +//===-- AppleObjCRuntime.cpp -------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -39,516 +40,450 @@ using namespace lldb; using namespace lldb_private; -#define PO_FUNCTION_TIMEOUT_USEC 15*1000*1000 +#define PO_FUNCTION_TIMEOUT_USEC 15 * 1000 * 1000 -AppleObjCRuntime::~AppleObjCRuntime() -{ -} +AppleObjCRuntime::~AppleObjCRuntime() {} -AppleObjCRuntime::AppleObjCRuntime(Process *process) : - ObjCLanguageRuntime (process), - m_read_objc_library (false), - m_objc_trampoline_handler_ap (), - m_Foundation_major() -{ - ReadObjCLibraryIfNeeded (process->GetTarget().GetImages()); +AppleObjCRuntime::AppleObjCRuntime(Process *process) + : ObjCLanguageRuntime(process), m_read_objc_library(false), + m_objc_trampoline_handler_ap(), m_Foundation_major() { + ReadObjCLibraryIfNeeded(process->GetTarget().GetImages()); } -bool -AppleObjCRuntime::GetObjectDescription (Stream &str, ValueObject &valobj) -{ - CompilerType compiler_type(valobj.GetCompilerType()); - bool is_signed; - // ObjC objects can only be pointers (or numbers that actually represents pointers - // but haven't been typecast, because reasons..) - if (!compiler_type.IsIntegerType (is_signed) && !compiler_type.IsPointerType ()) - return false; - - // Make the argument list: we pass one arg, the address of our pointer, to the print function. - Value val; - - if (!valobj.ResolveValue(val.GetScalar())) - return false; - - // Value Objects may not have a process in their ExecutionContextRef. But we need to have one - // in the ref we pass down to eventually call description. Get it from the target if it isn't - // present. - ExecutionContext exe_ctx; - if (valobj.GetProcessSP()) - { - exe_ctx = ExecutionContext(valobj.GetExecutionContextRef()); - } - else - { - exe_ctx.SetContext(valobj.GetTargetSP(), true); - if (!exe_ctx.HasProcessScope()) - return false; - } - return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); - +bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) { + CompilerType compiler_type(valobj.GetCompilerType()); + bool is_signed; + // ObjC objects can only be pointers (or numbers that actually represents + // pointers + // but haven't been typecast, because reasons..) + if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType()) + return false; + + // Make the argument list: we pass one arg, the address of our pointer, to the + // print function. + Value val; + + if (!valobj.ResolveValue(val.GetScalar())) + return false; + + // Value Objects may not have a process in their ExecutionContextRef. But we + // need to have one + // in the ref we pass down to eventually call description. Get it from the + // target if it isn't + // present. + ExecutionContext exe_ctx; + if (valobj.GetProcessSP()) { + exe_ctx = ExecutionContext(valobj.GetExecutionContextRef()); + } else { + exe_ctx.SetContext(valobj.GetTargetSP(), true); + if (!exe_ctx.HasProcessScope()) + return false; + } + return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope()); } -bool -AppleObjCRuntime::GetObjectDescription (Stream &strm, Value &value, ExecutionContextScope *exe_scope) -{ - if (!m_read_objc_library) - return false; - - ExecutionContext exe_ctx; - exe_scope->CalculateExecutionContext(exe_ctx); - Process *process = exe_ctx.GetProcessPtr(); - if (!process) - return false; - - // We need other parts of the exe_ctx, but the processes have to match. - assert (m_process == process); - - // Get the function address for the print function. - const Address *function_address = GetPrintForDebuggerAddr(); - if (!function_address) - return false; - - Target *target = exe_ctx.GetTargetPtr(); - CompilerType compiler_type = value.GetCompilerType(); - if (compiler_type) - { - if (!ClangASTContext::IsObjCObjectPointerType(compiler_type)) - { - strm.Printf ("Value doesn't point to an ObjC object.\n"); - return false; - } - } - else - { - // If it is not a pointer, see if we can make it into a pointer. - ClangASTContext *ast_context = target->GetScratchClangASTContext(); - CompilerType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID); - if (!opaque_type) - opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - //value.SetContext(Value::eContextTypeClangType, opaque_type_ptr); - value.SetCompilerType (opaque_type); - } +bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, + ExecutionContextScope *exe_scope) { + if (!m_read_objc_library) + return false; - ValueList arg_value_list; - arg_value_list.PushValue(value); - - // This is the return value: - ClangASTContext *ast_context = target->GetScratchClangASTContext(); - - CompilerType return_compiler_type = ast_context->GetCStringType(true); - Value ret; -// ret.SetContext(Value::eContextTypeClangType, return_compiler_type); - ret.SetCompilerType (return_compiler_type); - - if (exe_ctx.GetFramePtr() == NULL) - { - Thread *thread = exe_ctx.GetThreadPtr(); - if (thread == NULL) - { - exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread()); - thread = exe_ctx.GetThreadPtr(); - } - if (thread) - { - exe_ctx.SetFrameSP(thread->GetSelectedFrame()); - } - } + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return false; + + // We need other parts of the exe_ctx, but the processes have to match. + assert(m_process == process); - // Now we're ready to call the function: - - DiagnosticManager diagnostics; - lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; - - if (!m_print_object_caller_up) - { - Error error; - m_print_object_caller_up.reset(exe_scope->CalculateTarget()->GetFunctionCallerForLanguage (eLanguageTypeObjC, - return_compiler_type, - *function_address, - arg_value_list, - "objc-object-description", - error)); - if (error.Fail()) - { - m_print_object_caller_up.reset(); - strm.Printf("Could not get function runner to call print for debugger function: %s.", error.AsCString()); - return false; - } - m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr, diagnostics); + // Get the function address for the print function. + const Address *function_address = GetPrintForDebuggerAddr(); + if (!function_address) + return false; + + Target *target = exe_ctx.GetTargetPtr(); + CompilerType compiler_type = value.GetCompilerType(); + if (compiler_type) { + if (!ClangASTContext::IsObjCObjectPointerType(compiler_type)) { + strm.Printf("Value doesn't point to an ObjC object.\n"); + return false; } - else - { - m_print_object_caller_up->WriteFunctionArguments(exe_ctx, wrapper_struct_addr, arg_value_list, diagnostics); + } else { + // If it is not a pointer, see if we can make it into a pointer. + ClangASTContext *ast_context = target->GetScratchClangASTContext(); + CompilerType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID); + if (!opaque_type) + opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + // value.SetContext(Value::eContextTypeClangType, opaque_type_ptr); + value.SetCompilerType(opaque_type); + } + + ValueList arg_value_list; + arg_value_list.PushValue(value); + + // This is the return value: + ClangASTContext *ast_context = target->GetScratchClangASTContext(); + + CompilerType return_compiler_type = ast_context->GetCStringType(true); + Value ret; + // ret.SetContext(Value::eContextTypeClangType, return_compiler_type); + ret.SetCompilerType(return_compiler_type); + + if (exe_ctx.GetFramePtr() == NULL) { + Thread *thread = exe_ctx.GetThreadPtr(); + if (thread == NULL) { + exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread()); + thread = exe_ctx.GetThreadPtr(); } - - EvaluateExpressionOptions options; - options.SetUnwindOnError(true); - options.SetTryAllThreads(true); - options.SetStopOthers(true); - options.SetIgnoreBreakpoints(true); - options.SetTimeoutUsec(PO_FUNCTION_TIMEOUT_USEC); - - ExpressionResults results = - m_print_object_caller_up->ExecuteFunction(exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); - if (results != eExpressionCompleted) - { - strm.Printf("Error evaluating Print Object function: %d.\n", results); - return false; + if (thread) { + exe_ctx.SetFrameSP(thread->GetSelectedFrame()); } - - addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - - char buf[512]; - size_t cstr_len = 0; - size_t full_buffer_len = sizeof (buf) - 1; - size_t curr_len = full_buffer_len; - while (curr_len == full_buffer_len) - { - Error error; - curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf, sizeof(buf), error); - strm.Write (buf, curr_len); - cstr_len += curr_len; + } + + // Now we're ready to call the function: + + DiagnosticManager diagnostics; + lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS; + + if (!m_print_object_caller_up) { + Error error; + m_print_object_caller_up.reset( + exe_scope->CalculateTarget()->GetFunctionCallerForLanguage( + eLanguageTypeObjC, return_compiler_type, *function_address, + arg_value_list, "objc-object-description", error)); + if (error.Fail()) { + m_print_object_caller_up.reset(); + strm.Printf("Could not get function runner to call print for debugger " + "function: %s.", + error.AsCString()); + return false; } - return cstr_len > 0; + m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr, + diagnostics); + } else { + m_print_object_caller_up->WriteFunctionArguments( + exe_ctx, wrapper_struct_addr, arg_value_list, diagnostics); + } + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(true); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(PO_FUNCTION_TIMEOUT_USEC); + + ExpressionResults results = m_print_object_caller_up->ExecuteFunction( + exe_ctx, &wrapper_struct_addr, options, diagnostics, ret); + if (results != eExpressionCompleted) { + strm.Printf("Error evaluating Print Object function: %d.\n", results); + return false; + } + + addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + + char buf[512]; + size_t cstr_len = 0; + size_t full_buffer_len = sizeof(buf) - 1; + size_t curr_len = full_buffer_len; + while (curr_len == full_buffer_len) { + Error error; + curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf, + sizeof(buf), error); + strm.Write(buf, curr_len); + cstr_len += curr_len; + } + return cstr_len > 0; } -lldb::ModuleSP -AppleObjCRuntime::GetObjCModule () -{ - ModuleSP module_sp (m_objc_module_wp.lock()); - if (module_sp) +lldb::ModuleSP AppleObjCRuntime::GetObjCModule() { + ModuleSP module_sp(m_objc_module_wp.lock()); + if (module_sp) + return module_sp; + + Process *process = GetProcess(); + if (process) { + const ModuleList &modules = process->GetTarget().GetImages(); + for (uint32_t idx = 0; idx < modules.GetSize(); idx++) { + module_sp = modules.GetModuleAtIndex(idx); + if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) { + m_objc_module_wp = module_sp; return module_sp; - - Process *process = GetProcess(); - if (process) - { - const ModuleList& modules = process->GetTarget().GetImages(); - for (uint32_t idx = 0; idx < modules.GetSize(); idx++) - { - module_sp = modules.GetModuleAtIndex(idx); - if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) - { - m_objc_module_wp = module_sp; - return module_sp; - } - } + } } - return ModuleSP(); + } + return ModuleSP(); } -Address * -AppleObjCRuntime::GetPrintForDebuggerAddr() -{ - if (!m_PrintForDebugger_addr.get()) - { - const ModuleList &modules = m_process->GetTarget().GetImages(); - - SymbolContextList contexts; - SymbolContext context; - - if ((!modules.FindSymbolsWithNameAndType(ConstString ("_NSPrintForDebugger"), eSymbolTypeCode, contexts)) && - (!modules.FindSymbolsWithNameAndType(ConstString ("_CFPrintForDebugger"), eSymbolTypeCode, contexts))) - return NULL; - - contexts.GetContextAtIndex(0, context); - - m_PrintForDebugger_addr.reset(new Address(context.symbol->GetAddress())); - } - - return m_PrintForDebugger_addr.get(); +Address *AppleObjCRuntime::GetPrintForDebuggerAddr() { + if (!m_PrintForDebugger_addr.get()) { + const ModuleList &modules = m_process->GetTarget().GetImages(); + + SymbolContextList contexts; + SymbolContext context; + + if ((!modules.FindSymbolsWithNameAndType(ConstString("_NSPrintForDebugger"), + eSymbolTypeCode, contexts)) && + (!modules.FindSymbolsWithNameAndType(ConstString("_CFPrintForDebugger"), + eSymbolTypeCode, contexts))) + return NULL; + + contexts.GetContextAtIndex(0, context); + + m_PrintForDebugger_addr.reset(new Address(context.symbol->GetAddress())); + } + + return m_PrintForDebugger_addr.get(); } -bool -AppleObjCRuntime::CouldHaveDynamicValue (ValueObject &in_value) -{ - return in_value.GetCompilerType().IsPossibleDynamicType (NULL, - false, // do not check C++ - true); // check ObjC +bool AppleObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + return in_value.GetCompilerType().IsPossibleDynamicType( + NULL, + false, // do not check C++ + true); // check ObjC } -bool -AppleObjCRuntime::GetDynamicTypeAndAddress (ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) -{ - return false; +bool AppleObjCRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &address, + Value::ValueType &value_type) { + return false; } TypeAndOrName -AppleObjCRuntime::FixUpDynamicType (const TypeAndOrName& type_and_or_name, - ValueObject& static_value) -{ - CompilerType static_type(static_value.GetCompilerType()); - Flags static_type_flags(static_type.GetTypeInfo()); - - TypeAndOrName ret(type_and_or_name); - if (type_and_or_name.HasType()) - { - // The type will always be the type of the dynamic object. If our parent's type was a pointer, - // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type - // should be okay... - CompilerType orig_type = type_and_or_name.GetCompilerType(); - CompilerType corrected_type = orig_type; - if (static_type_flags.AllSet(eTypeIsPointer)) - corrected_type = orig_type.GetPointerType (); - ret.SetCompilerType(corrected_type); - } - else - { - // If we are here we need to adjust our dynamic type name to include the correct & or * symbol - std::string corrected_name (type_and_or_name.GetName().GetCString()); - if (static_type_flags.AllSet(eTypeIsPointer)) - corrected_name.append(" *"); - // the parent type should be a correctly pointer'ed or referenc'ed type - ret.SetCompilerType(static_type); - ret.SetName(corrected_name.c_str()); - } - return ret; +AppleObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) { + CompilerType static_type(static_value.GetCompilerType()); + Flags static_type_flags(static_type.GetTypeInfo()); + + TypeAndOrName ret(type_and_or_name); + if (type_and_or_name.HasType()) { + // The type will always be the type of the dynamic object. If our parent's + // type was a pointer, + // then our type should be a pointer to the type of the dynamic object. If + // a reference, then the original type + // should be okay... + CompilerType orig_type = type_and_or_name.GetCompilerType(); + CompilerType corrected_type = orig_type; + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_type = orig_type.GetPointerType(); + ret.SetCompilerType(corrected_type); + } else { + // If we are here we need to adjust our dynamic type name to include the + // correct & or * symbol + std::string corrected_name(type_and_or_name.GetName().GetCString()); + if (static_type_flags.AllSet(eTypeIsPointer)) + corrected_name.append(" *"); + // the parent type should be a correctly pointer'ed or referenc'ed type + ret.SetCompilerType(static_type); + ret.SetName(corrected_name.c_str()); + } + return ret; } -bool -AppleObjCRuntime::AppleIsModuleObjCLibrary (const ModuleSP &module_sp) -{ - if (module_sp) - { - const FileSpec &module_file_spec = module_sp->GetFileSpec(); - static ConstString ObjCName ("libobjc.A.dylib"); - - if (module_file_spec) - { - if (module_file_spec.GetFilename() == ObjCName) - return true; - } +bool AppleObjCRuntime::AppleIsModuleObjCLibrary(const ModuleSP &module_sp) { + if (module_sp) { + const FileSpec &module_file_spec = module_sp->GetFileSpec(); + static ConstString ObjCName("libobjc.A.dylib"); + + if (module_file_spec) { + if (module_file_spec.GetFilename() == ObjCName) + return true; } - return false; + } + return false; } -// we use the version of Foundation to make assumptions about the ObjC runtime on a target -uint32_t -AppleObjCRuntime::GetFoundationVersion () -{ - if (!m_Foundation_major.hasValue()) - { - const ModuleList& modules = m_process->GetTarget().GetImages(); - uint32_t major = UINT32_MAX; - for (uint32_t idx = 0; idx < modules.GetSize(); idx++) - { - lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); - if (!module_sp) - continue; - if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0) - { - module_sp->GetVersion(&major,1); - m_Foundation_major = major; - return major; - } - } - return LLDB_INVALID_MODULE_VERSION; +// we use the version of Foundation to make assumptions about the ObjC runtime +// on a target +uint32_t AppleObjCRuntime::GetFoundationVersion() { + if (!m_Foundation_major.hasValue()) { + const ModuleList &modules = m_process->GetTarget().GetImages(); + uint32_t major = UINT32_MAX; + for (uint32_t idx = 0; idx < modules.GetSize(); idx++) { + lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); + if (!module_sp) + continue; + if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""), + "Foundation") == 0) { + module_sp->GetVersion(&major, 1); + m_Foundation_major = major; + return major; + } } - else - return m_Foundation_major.getValue(); + return LLDB_INVALID_MODULE_VERSION; + } else + return m_Foundation_major.getValue(); } -void -AppleObjCRuntime::GetValuesForGlobalCFBooleans(lldb::addr_t& cf_true, - lldb::addr_t& cf_false) -{ - cf_true = cf_false = LLDB_INVALID_ADDRESS; +void AppleObjCRuntime::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, + lldb::addr_t &cf_false) { + cf_true = cf_false = LLDB_INVALID_ADDRESS; } -bool -AppleObjCRuntime::IsModuleObjCLibrary (const ModuleSP &module_sp) -{ - return AppleIsModuleObjCLibrary(module_sp); +bool AppleObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) { + return AppleIsModuleObjCLibrary(module_sp); } -bool -AppleObjCRuntime::ReadObjCLibrary (const ModuleSP &module_sp) -{ - // Maybe check here and if we have a handler already, and the UUID of this module is the same as the one in the - // current module, then we don't have to reread it? - m_objc_trampoline_handler_ap.reset(new AppleObjCTrampolineHandler (m_process->shared_from_this(), module_sp)); - if (m_objc_trampoline_handler_ap.get() != NULL) - { - m_read_objc_library = true; - return true; - } - else - return false; +bool AppleObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) { + // Maybe check here and if we have a handler already, and the UUID of this + // module is the same as the one in the + // current module, then we don't have to reread it? + m_objc_trampoline_handler_ap.reset( + new AppleObjCTrampolineHandler(m_process->shared_from_this(), module_sp)); + if (m_objc_trampoline_handler_ap.get() != NULL) { + m_read_objc_library = true; + return true; + } else + return false; } -ThreadPlanSP -AppleObjCRuntime::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) -{ - ThreadPlanSP thread_plan_sp; - if (m_objc_trampoline_handler_ap.get()) - thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan (thread, stop_others); - return thread_plan_sp; +ThreadPlanSP AppleObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) { + ThreadPlanSP thread_plan_sp; + if (m_objc_trampoline_handler_ap.get()) + thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan( + thread, stop_others); + return thread_plan_sp; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ ObjCLanguageRuntime::ObjCRuntimeVersions -AppleObjCRuntime::GetObjCVersion (Process *process, ModuleSP &objc_module_sp) -{ - if (!process) - return ObjCRuntimeVersions::eObjC_VersionUnknown; +AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) { + if (!process) + return ObjCRuntimeVersions::eObjC_VersionUnknown; - Target &target = process->GetTarget(); - if (target.GetArchitecture().GetTriple().getVendor() != llvm::Triple::VendorType::Apple) + Target &target = process->GetTarget(); + if (target.GetArchitecture().GetTriple().getVendor() != + llvm::Triple::VendorType::Apple) + return ObjCRuntimeVersions::eObjC_VersionUnknown; + + const ModuleList &target_modules = target.GetImages(); + std::lock_guard<std::recursive_mutex> gaurd(target_modules.GetMutex()); + + size_t num_images = target_modules.GetSize(); + for (size_t i = 0; i < num_images; i++) { + ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + // One tricky bit here is that we might get called as part of the initial + // module loading, but + // before all the pre-run libraries get winnowed from the module list. So + // there might actually + // be an old and incorrect ObjC library sitting around in the list, and we + // don't want to look at that. + // That's why we call IsLoadedInTarget. + + if (AppleIsModuleObjCLibrary(module_sp) && + module_sp->IsLoadedInTarget(&target)) { + objc_module_sp = module_sp; + ObjectFile *ofile = module_sp->GetObjectFile(); + if (!ofile) return ObjCRuntimeVersions::eObjC_VersionUnknown; - const ModuleList &target_modules = target.GetImages(); - std::lock_guard<std::recursive_mutex> gaurd(target_modules.GetMutex()); - - size_t num_images = target_modules.GetSize(); - for (size_t i = 0; i < num_images; i++) - { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); - // One tricky bit here is that we might get called as part of the initial module loading, but - // before all the pre-run libraries get winnowed from the module list. So there might actually - // be an old and incorrect ObjC library sitting around in the list, and we don't want to look at that. - // That's why we call IsLoadedInTarget. - - if (AppleIsModuleObjCLibrary (module_sp) && module_sp->IsLoadedInTarget(&target)) - { - objc_module_sp = module_sp; - ObjectFile *ofile = module_sp->GetObjectFile(); - if (!ofile) - return ObjCRuntimeVersions::eObjC_VersionUnknown; - - SectionList *sections = module_sp->GetSectionList(); - if (!sections) - return ObjCRuntimeVersions::eObjC_VersionUnknown; - SectionSP v1_telltale_section_sp = sections->FindSectionByName(ConstString ("__OBJC")); - if (v1_telltale_section_sp) - { - return ObjCRuntimeVersions::eAppleObjC_V1; - } - return ObjCRuntimeVersions::eAppleObjC_V2; - } + SectionList *sections = module_sp->GetSectionList(); + if (!sections) + return ObjCRuntimeVersions::eObjC_VersionUnknown; + SectionSP v1_telltale_section_sp = + sections->FindSectionByName(ConstString("__OBJC")); + if (v1_telltale_section_sp) { + return ObjCRuntimeVersions::eAppleObjC_V1; + } + return ObjCRuntimeVersions::eAppleObjC_V2; } - - return ObjCRuntimeVersions::eObjC_VersionUnknown; + } + + return ObjCRuntimeVersions::eObjC_VersionUnknown; } -void -AppleObjCRuntime::SetExceptionBreakpoints () -{ - const bool catch_bp = false; - const bool throw_bp = true; - const bool is_internal = true; - - if (!m_objc_exception_bp_sp) - { - m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint (m_process->GetTarget(), - GetLanguageType(), - catch_bp, - throw_bp, - is_internal); - if (m_objc_exception_bp_sp) - m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception"); - } - else - m_objc_exception_bp_sp->SetEnabled(true); +void AppleObjCRuntime::SetExceptionBreakpoints() { + const bool catch_bp = false; + const bool throw_bp = true; + const bool is_internal = true; + + if (!m_objc_exception_bp_sp) { + m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint( + m_process->GetTarget(), GetLanguageType(), catch_bp, throw_bp, + is_internal); + if (m_objc_exception_bp_sp) + m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception"); + } else + m_objc_exception_bp_sp->SetEnabled(true); } +void AppleObjCRuntime::ClearExceptionBreakpoints() { + if (!m_process) + return; -void -AppleObjCRuntime::ClearExceptionBreakpoints () -{ - if (!m_process) - return; - - if (m_objc_exception_bp_sp.get()) - { - m_objc_exception_bp_sp->SetEnabled (false); - } + if (m_objc_exception_bp_sp.get()) { + m_objc_exception_bp_sp->SetEnabled(false); + } } -bool -AppleObjCRuntime::ExceptionBreakpointsAreSet () -{ - return m_objc_exception_bp_sp && m_objc_exception_bp_sp->IsEnabled(); +bool AppleObjCRuntime::ExceptionBreakpointsAreSet() { + return m_objc_exception_bp_sp && m_objc_exception_bp_sp->IsEnabled(); } -bool -AppleObjCRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason) -{ - if (!m_process) - return false; - - if (!stop_reason || - stop_reason->GetStopReason() != eStopReasonBreakpoint) - return false; - - uint64_t break_site_id = stop_reason->GetValue(); - return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint (break_site_id, - m_objc_exception_bp_sp->GetID()); +bool AppleObjCRuntime::ExceptionBreakpointsExplainStop( + lldb::StopInfoSP stop_reason) { + if (!m_process) + return false; + + if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint) + return false; + + uint64_t break_site_id = stop_reason->GetValue(); + return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + break_site_id, m_objc_exception_bp_sp->GetID()); } -bool -AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing() -{ - if (!m_process) - return false; - - Target &target(m_process->GetTarget()); - - static ConstString s_method_signature("-[NSDictionary objectForKeyedSubscript:]"); - static ConstString s_arclite_method_signature("__arclite_objectForKeyedSubscript"); - - SymbolContextList sc_list; - - if (target.GetImages().FindSymbolsWithNameAndType(s_method_signature, eSymbolTypeCode, sc_list) || - target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature, eSymbolTypeCode, sc_list)) - return true; - else - return false; +bool AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing() { + if (!m_process) + return false; + + Target &target(m_process->GetTarget()); + + static ConstString s_method_signature( + "-[NSDictionary objectForKeyedSubscript:]"); + static ConstString s_arclite_method_signature( + "__arclite_objectForKeyedSubscript"); + + SymbolContextList sc_list; + + if (target.GetImages().FindSymbolsWithNameAndType(s_method_signature, + eSymbolTypeCode, sc_list) || + target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature, + eSymbolTypeCode, sc_list)) + return true; + else + return false; } -lldb::SearchFilterSP -AppleObjCRuntime::CreateExceptionSearchFilter () -{ - Target &target = m_process->GetTarget(); - - if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) - { - FileSpecList filter_modules; - filter_modules.Append(FileSpec("libobjc.A.dylib", false)); - return target.GetSearchFilterForModuleList(&filter_modules); - } - else - { - return LanguageRuntime::CreateExceptionSearchFilter(); - } +lldb::SearchFilterSP AppleObjCRuntime::CreateExceptionSearchFilter() { + Target &target = m_process->GetTarget(); + + if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) { + FileSpecList filter_modules; + filter_modules.Append(FileSpec("libobjc.A.dylib", false)); + return target.GetSearchFilterForModuleList(&filter_modules); + } else { + return LanguageRuntime::CreateExceptionSearchFilter(); + } } -void -AppleObjCRuntime::ReadObjCLibraryIfNeeded (const ModuleList &module_list) -{ - if (!HasReadObjCLibrary ()) - { - std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); - - size_t num_modules = module_list.GetSize(); - for (size_t i = 0; i < num_modules; i++) - { - auto mod = module_list.GetModuleAtIndex (i); - if (IsModuleObjCLibrary (mod)) - { - ReadObjCLibrary (mod); - break; - } - } +void AppleObjCRuntime::ReadObjCLibraryIfNeeded(const ModuleList &module_list) { + if (!HasReadObjCLibrary()) { + std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); + + size_t num_modules = module_list.GetSize(); + for (size_t i = 0; i < num_modules; i++) { + auto mod = module_list.GetModuleAtIndex(i); + if (IsModuleObjCLibrary(mod)) { + ReadObjCLibrary(mod); + break; + } } + } } -void -AppleObjCRuntime::ModulesDidLoad (const ModuleList &module_list) -{ - ReadObjCLibraryIfNeeded (module_list); +void AppleObjCRuntime::ModulesDidLoad(const ModuleList &module_list) { + ReadObjCLibraryIfNeeded(module_list); } - diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index b66700fc516..57d98fbd728 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h @@ -16,137 +16,112 @@ #include "llvm/ADT/Optional.h" // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Target/LanguageRuntime.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" +#include "lldb/Target/LanguageRuntime.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { - -class AppleObjCRuntime : - public lldb_private::ObjCLanguageRuntime -{ + +class AppleObjCRuntime : public lldb_private::ObjCLanguageRuntime { public: - ~AppleObjCRuntime() override; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - // Note there is no CreateInstance, Initialize & Terminate functions here, because - // you can't make an instance of this generic runtime. - - static bool classof(const ObjCLanguageRuntime* runtime) - { - switch (runtime->GetRuntimeVersion()) - { - case ObjCRuntimeVersions::eAppleObjC_V1: - case ObjCRuntimeVersions::eAppleObjC_V2: - return true; - default: - return false; - } - } - - // These are generic runtime functions: - bool - GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) override; - - bool - GetObjectDescription (Stream &str, ValueObject &object) override; - - bool - CouldHaveDynamicValue (ValueObject &in_value) override; - - bool - GetDynamicTypeAndAddress (ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - TypeAndOrName - FixUpDynamicType (const TypeAndOrName& type_and_or_name, - ValueObject& static_value) override; - - // These are the ObjC specific functions. - - bool - IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) override; - - bool - ReadObjCLibrary (const lldb::ModuleSP &module_sp) override; - - bool - HasReadObjCLibrary () override - { - return m_read_objc_library; + ~AppleObjCRuntime() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + // Note there is no CreateInstance, Initialize & Terminate functions here, + // because + // you can't make an instance of this generic runtime. + + static bool classof(const ObjCLanguageRuntime *runtime) { + switch (runtime->GetRuntimeVersion()) { + case ObjCRuntimeVersions::eAppleObjC_V1: + case ObjCRuntimeVersions::eAppleObjC_V2: + return true; + default: + return false; } - - lldb::ThreadPlanSP - GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) override; - - // Get the "libobjc.A.dylib" module from the current target if we can find - // it, also cache it once it is found to ensure quick lookups. - lldb::ModuleSP - GetObjCModule (); - - // Sync up with the target - - void - ModulesDidLoad (const ModuleList &module_list) override; - - void - SetExceptionBreakpoints() override; - - void - ClearExceptionBreakpoints() override; - - bool - ExceptionBreakpointsAreSet() override; - - bool - ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; - - lldb::SearchFilterSP - CreateExceptionSearchFilter() override; - - uint32_t - GetFoundationVersion(); - - virtual void - GetValuesForGlobalCFBooleans(lldb::addr_t& cf_true, - lldb::addr_t& cf_false); - + } + + // These are generic runtime functions: + bool GetObjectDescription(Stream &str, Value &value, + ExecutionContextScope *exe_scope) override; + + bool GetObjectDescription(Stream &str, ValueObject &object) override; + + bool CouldHaveDynamicValue(ValueObject &in_value) override; + + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; + + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; + + // These are the ObjC specific functions. + + bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) override; + + bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) override; + + bool HasReadObjCLibrary() override { return m_read_objc_library; } + + lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, + bool stop_others) override; + + // Get the "libobjc.A.dylib" module from the current target if we can find + // it, also cache it once it is found to ensure quick lookups. + lldb::ModuleSP GetObjCModule(); + + // Sync up with the target + + void ModulesDidLoad(const ModuleList &module_list) override; + + void SetExceptionBreakpoints() override; + + void ClearExceptionBreakpoints() override; + + bool ExceptionBreakpointsAreSet() override; + + bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override; + + lldb::SearchFilterSP CreateExceptionSearchFilter() override; + + uint32_t GetFoundationVersion(); + + virtual void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, + lldb::addr_t &cf_false); + protected: - // Call CreateInstance instead. - AppleObjCRuntime(Process *process); - - bool - CalculateHasNewLiteralsAndIndexing() override; - - static bool - AppleIsModuleObjCLibrary(const lldb::ModuleSP &module_sp); - - static ObjCRuntimeVersions - GetObjCVersion(Process *process, lldb::ModuleSP &objc_module_sp); - - void - ReadObjCLibraryIfNeeded(const ModuleList &module_list); - - Address * - GetPrintForDebuggerAddr(); - - std::unique_ptr<Address> m_PrintForDebugger_addr; - bool m_read_objc_library; - std::unique_ptr<lldb_private::AppleObjCTrampolineHandler> m_objc_trampoline_handler_ap; - lldb::BreakpointSP m_objc_exception_bp_sp; - lldb::ModuleWP m_objc_module_wp; - std::unique_ptr<FunctionCaller> m_print_object_caller_up; - - llvm::Optional<uint32_t> m_Foundation_major; + // Call CreateInstance instead. + AppleObjCRuntime(Process *process); + + bool CalculateHasNewLiteralsAndIndexing() override; + + static bool AppleIsModuleObjCLibrary(const lldb::ModuleSP &module_sp); + + static ObjCRuntimeVersions GetObjCVersion(Process *process, + lldb::ModuleSP &objc_module_sp); + + void ReadObjCLibraryIfNeeded(const ModuleList &module_list); + + Address *GetPrintForDebuggerAddr(); + + std::unique_ptr<Address> m_PrintForDebugger_addr; + bool m_read_objc_library; + std::unique_ptr<lldb_private::AppleObjCTrampolineHandler> + m_objc_trampoline_handler_ap; + lldb::BreakpointSP m_objc_exception_bp_sp; + lldb::ModuleWP m_objc_module_wp; + std::unique_ptr<FunctionCaller> m_print_object_caller_up; + + llvm::Optional<uint32_t> m_Foundation_major; }; - + } // namespace lldb_private #endif // liblldb_AppleObjCRuntime_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 805fca7a31b..83df1fcca9f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -1,4 +1,5 @@ -//===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++ -*-===// +//===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -8,8 +9,8 @@ //===----------------------------------------------------------------------===// #include "AppleObjCRuntimeV1.h" -#include "AppleObjCTrampolineHandler.h" #include "AppleObjCDeclVendor.h" +#include "AppleObjCTrampolineHandler.h" #include "clang/AST/Type.h" @@ -36,425 +37,403 @@ using namespace lldb; using namespace lldb_private; -AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process) : - AppleObjCRuntime (process), - m_hash_signature (), - m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS) -{ -} +AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process) + : AppleObjCRuntime(process), m_hash_signature(), + m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {} -// for V1 runtime we just try to return a class name as that is the minimum level of support +// for V1 runtime we just try to return a class name as that is the minimum +// level of support // required for the data formatters to work -bool -AppleObjCRuntimeV1::GetDynamicTypeAndAddress (ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) -{ - class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; - if (CouldHaveDynamicValue(in_value)) - { - auto class_descriptor(GetClassDescriptor(in_value)); - if (class_descriptor && class_descriptor->IsValid() && class_descriptor->GetClassName()) - { - const addr_t object_ptr = in_value.GetPointerValue(); - address.SetRawAddress(object_ptr); - class_type_or_name.SetName(class_descriptor->GetClassName()); - } +bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &address, + Value::ValueType &value_type) { + class_type_or_name.Clear(); + value_type = Value::ValueType::eValueTypeScalar; + if (CouldHaveDynamicValue(in_value)) { + auto class_descriptor(GetClassDescriptor(in_value)); + if (class_descriptor && class_descriptor->IsValid() && + class_descriptor->GetClassName()) { + const addr_t object_ptr = in_value.GetPointerValue(); + address.SetRawAddress(object_ptr); + class_type_or_name.SetName(class_descriptor->GetClassName()); } - return class_type_or_name.IsEmpty() == false; + } + return class_type_or_name.IsEmpty() == false; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ lldb_private::LanguageRuntime * -AppleObjCRuntimeV1::CreateInstance (Process *process, lldb::LanguageType language) -{ - // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make - // sure we aren't using the V1 runtime. - if (language == eLanguageTypeObjC) - { - ModuleSP objc_module_sp; - - if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == ObjCRuntimeVersions::eAppleObjC_V1) - return new AppleObjCRuntimeV1 (process); - else - return NULL; - } +AppleObjCRuntimeV1::CreateInstance(Process *process, + lldb::LanguageType language) { + // FIXME: This should be a MacOS or iOS process, and we need to look for the + // OBJC section to make + // sure we aren't using the V1 runtime. + if (language == eLanguageTypeObjC) { + ModuleSP objc_module_sp; + + if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) == + ObjCRuntimeVersions::eAppleObjC_V1) + return new AppleObjCRuntimeV1(process); else - return NULL; + return NULL; + } else + return NULL; } - -void -AppleObjCRuntimeV1::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Apple Objective C Language Runtime - Version 1", - CreateInstance); +void AppleObjCRuntimeV1::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 1", + CreateInstance); } -void -AppleObjCRuntimeV1::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void AppleObjCRuntimeV1::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -AppleObjCRuntimeV1::GetPluginNameStatic() -{ - static ConstString g_name("apple-objc-v1"); - return g_name; +lldb_private::ConstString AppleObjCRuntimeV1::GetPluginNameStatic() { + static ConstString g_name("apple-objc-v1"); + return g_name; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -ConstString -AppleObjCRuntimeV1::GetPluginName() -{ - return GetPluginNameStatic(); +ConstString AppleObjCRuntimeV1::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -AppleObjCRuntimeV1::GetPluginVersion() -{ - return 1; -} +uint32_t AppleObjCRuntimeV1::GetPluginVersion() { return 1; } BreakpointResolverSP -AppleObjCRuntimeV1::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) -{ - BreakpointResolverSP resolver_sp; - - if (throw_bp) - resolver_sp.reset (new BreakpointResolverName (bkpt, - "objc_exception_throw", - eFunctionNameTypeBase, - eLanguageTypeUnknown, - Breakpoint::Exact, - 0, - eLazyBoolNo)); - // FIXME: don't do catch yet. - return resolver_sp; +AppleObjCRuntimeV1::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, + bool throw_bp) { + BreakpointResolverSP resolver_sp; + + if (throw_bp) + resolver_sp.reset(new BreakpointResolverName( + bkpt, "objc_exception_throw", eFunctionNameTypeBase, + eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo)); + // FIXME: don't do catch yet. + return resolver_sp; } struct BufStruct { - char contents[2048]; + char contents[2048]; }; -UtilityFunction * -AppleObjCRuntimeV1::CreateObjectChecker(const char *name) -{ - std::unique_ptr<BufStruct> buf(new BufStruct); - - assert(snprintf(&buf->contents[0], sizeof(buf->contents), - "struct __objc_class \n" - "{ \n" - " struct __objc_class *isa; \n" - " struct __objc_class *super_class; \n" - " const char *name; \n" - " // rest of struct elided because unused \n" - "}; \n" - " \n" - "struct __objc_object \n" - "{ \n" - " struct __objc_class *isa; \n" - "}; \n" - " \n" - "extern \"C\" void \n" - "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" - "{ \n" - " struct __objc_object *obj = (struct __objc_object*)$__lldb_arg_obj; \n" - " (int)strlen(obj->isa->name); \n" - "} \n", - name) < (int)sizeof(buf->contents)); - - Error error; - return GetTargetRef().GetUtilityFunctionForLanguage(buf->contents, eLanguageTypeObjC, name, error); +UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) { + std::unique_ptr<BufStruct> buf(new BufStruct); + + assert(snprintf(&buf->contents[0], sizeof(buf->contents), + "struct __objc_class " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + " struct __objc_class *super_class; " + " \n" + " const char *name; " + " \n" + " // rest of struct elided because unused " + " \n" + "}; " + " \n" + " " + " \n" + "struct __objc_object " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + "}; " + " \n" + " " + " \n" + "extern \"C\" void " + " \n" + "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " + " \n" + "{ " + " \n" + " struct __objc_object *obj = (struct " + "__objc_object*)$__lldb_arg_obj; \n" + " (int)strlen(obj->isa->name); " + " \n" + "} " + " \n", + name) < (int)sizeof(buf->contents)); + + Error error; + return GetTargetRef().GetUtilityFunctionForLanguage( + buf->contents, eLanguageTypeObjC, name, error); } -AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer) -{ - Initialize (isa_pointer.GetValueAsUnsigned(0), - isa_pointer.GetProcessSP()); +AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1( + ValueObject &isa_pointer) { + Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP()); } -AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp) -{ - Initialize (isa, process_sp); +AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1( + ObjCISA isa, lldb::ProcessSP process_sp) { + Initialize(isa, process_sp); } -void -AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp) -{ - if (!isa || !process_sp) - { - m_valid = false; - return; - } - - m_valid = true; - - Error error; - - m_isa = process_sp->ReadPointerFromMemory(isa, error); - - if (error.Fail()) - { - m_valid = false; - return; - } - - uint32_t ptr_size = process_sp->GetAddressByteSize(); - - if (!IsPointerValid(m_isa,ptr_size)) - { - m_valid = false; - return; - } +void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize( + ObjCISA isa, lldb::ProcessSP process_sp) { + if (!isa || !process_sp) { + m_valid = false; + return; + } - m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error); - - if (error.Fail()) - { - m_valid = false; - return; - } - - if (!IsPointerValid(m_parent_isa,ptr_size,true)) - { - m_valid = false; - return; - } - - lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error); - - if (error.Fail()) - { - m_valid = false; - return; - } - - lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); - - size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error); - - if (error.Fail()) - { - m_valid = false; - return; - } - - if (count) - m_name = ConstString((char*)buffer_sp->GetBytes()); - else - m_name = ConstString(); - - m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error); - - if (error.Fail()) - { - m_valid = false; - return; - } - - m_process_wp = lldb::ProcessWP(process_sp); + m_valid = true; + + Error error; + + m_isa = process_sp->ReadPointerFromMemory(isa, error); + + if (error.Fail()) { + m_valid = false; + return; + } + + uint32_t ptr_size = process_sp->GetAddressByteSize(); + + if (!IsPointerValid(m_isa, ptr_size)) { + m_valid = false; + return; + } + + m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error); + + if (error.Fail()) { + m_valid = false; + return; + } + + if (!IsPointerValid(m_parent_isa, ptr_size, true)) { + m_valid = false; + return; + } + + lldb::addr_t name_ptr = + process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error); + + if (error.Fail()) { + m_valid = false; + return; + } + + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); + + size_t count = process_sp->ReadCStringFromMemory( + name_ptr, (char *)buffer_sp->GetBytes(), 1024, error); + + if (error.Fail()) { + m_valid = false; + return; + } + + if (count) + m_name = ConstString((char *)buffer_sp->GetBytes()); + else + m_name = ConstString(); + + m_instance_size = process_sp->ReadUnsignedIntegerFromMemory( + m_isa + 5 * ptr_size, ptr_size, 0, error); + + if (error.Fail()) { + m_valid = false; + return; + } + + m_process_wp = lldb::ProcessWP(process_sp); } AppleObjCRuntime::ClassDescriptorSP -AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass () -{ - if (!m_valid) - return AppleObjCRuntime::ClassDescriptorSP(); - ProcessSP process_sp = m_process_wp.lock(); - if (!process_sp) - return AppleObjCRuntime::ClassDescriptorSP(); - return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp)); +AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass() { + if (!m_valid) + return AppleObjCRuntime::ClassDescriptorSP(); + ProcessSP process_sp = m_process_wp.lock(); + if (!process_sp) + return AppleObjCRuntime::ClassDescriptorSP(); + return ObjCLanguageRuntime::ClassDescriptorSP( + new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp)); } AppleObjCRuntime::ClassDescriptorSP -AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass () const -{ - return ClassDescriptorSP(); +AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass() const { + return ClassDescriptorSP(); } -bool -AppleObjCRuntimeV1::ClassDescriptorV1::Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, - std::function <bool (const char *, const char *)> const &instance_method_func, - std::function <bool (const char *, const char *)> const &class_method_func, - std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const -{ - return false; +bool AppleObjCRuntimeV1::ClassDescriptorV1::Describe( + std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, + std::function<bool(const char *, const char *)> const &instance_method_func, + std::function<bool(const char *, const char *)> const &class_method_func, + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)> const &ivar_func) const { + return false; } -lldb::addr_t -AppleObjCRuntimeV1::GetISAHashTablePointer () -{ - if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) - { - ModuleSP objc_module_sp(GetObjCModule()); - - if (!objc_module_sp) - return LLDB_INVALID_ADDRESS; - - static ConstString g_objc_debug_class_hash("_objc_debug_class_hash"); - - const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_objc_debug_class_hash, lldb::eSymbolTypeData); - if (symbol && symbol->ValueIsAddress()) - { - Process *process = GetProcess(); - if (process) - { - - lldb::addr_t objc_debug_class_hash_addr = symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); - - if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) - { - Error error; - lldb::addr_t objc_debug_class_hash_ptr = process->ReadPointerFromMemory(objc_debug_class_hash_addr, error); - if (objc_debug_class_hash_ptr != 0 && - objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) - { - m_isa_hash_table_ptr = objc_debug_class_hash_ptr; - } - } - } +lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() { + if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { + ModuleSP objc_module_sp(GetObjCModule()); + + if (!objc_module_sp) + return LLDB_INVALID_ADDRESS; + + static ConstString g_objc_debug_class_hash("_objc_debug_class_hash"); + + const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( + g_objc_debug_class_hash, lldb::eSymbolTypeData); + if (symbol && symbol->ValueIsAddress()) { + Process *process = GetProcess(); + if (process) { + + lldb::addr_t objc_debug_class_hash_addr = + symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); + + if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) { + Error error; + lldb::addr_t objc_debug_class_hash_ptr = + process->ReadPointerFromMemory(objc_debug_class_hash_addr, error); + if (objc_debug_class_hash_ptr != 0 && + objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) { + m_isa_hash_table_ptr = objc_debug_class_hash_ptr; + } } + } } - return m_isa_hash_table_ptr; + } + return m_isa_hash_table_ptr; } -void -AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() -{ - // TODO: implement HashTableSignature... - Process *process = GetProcess(); - - if (process) - { - // Update the process stop ID that indicates the last time we updated the - // map, whether it was successful or not. - m_isa_to_descriptor_stop_id = process->GetStopID(); - - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - ProcessSP process_sp = process->shared_from_this(); - - ModuleSP objc_module_sp(GetObjCModule()); - - if (!objc_module_sp) - return; - - uint32_t isa_count = 0; - - lldb::addr_t hash_table_ptr = GetISAHashTablePointer (); - if (hash_table_ptr != LLDB_INVALID_ADDRESS) - { - // Read the NXHashTable struct: - // - // typedef struct { - // const NXHashTablePrototype *prototype; - // unsigned count; - // unsigned nbBuckets; - // void *buckets; - // const void *info; - // } NXHashTable; - - Error error; - DataBufferHeap buffer(1024, 0); - if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) == 20) - { - const uint32_t addr_size = m_process->GetAddressByteSize(); - const ByteOrder byte_order = m_process->GetByteOrder(); - DataExtractor data (buffer.GetBytes(), buffer.GetByteSize(), byte_order, addr_size); - lldb::offset_t offset = addr_size; // Skip prototype - const uint32_t count = data.GetU32(&offset); - const uint32_t num_buckets = data.GetU32(&offset); - const addr_t buckets_ptr = data.GetPointer(&offset); - if (m_hash_signature.NeedsUpdate (count, num_buckets, buckets_ptr)) - { - m_hash_signature.UpdateSignature (count, num_buckets, buckets_ptr); - - const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t); - buffer.SetByteSize(data_size); - - if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size, error) == data_size) - { - data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order); - offset = 0; - for (uint32_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx) - { - const uint32_t bucket_isa_count = data.GetU32 (&offset); - const lldb::addr_t bucket_data = data.GetU32 (&offset); - - - if (bucket_isa_count == 0) - continue; - - isa_count += bucket_isa_count; - - ObjCISA isa; - if (bucket_isa_count == 1) - { - // When we only have one entry in the bucket, the bucket data is the "isa" - isa = bucket_data; - if (isa) - { - if (!ISAIsCached(isa)) - { - ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); - - if (log && log->GetVerbose()) - log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa); - - AddClass (isa, descriptor_sp); - } - } - } - else - { - // When we have more than one entry in the bucket, the bucket data is a pointer - // to an array of "isa" values - addr_t isa_addr = bucket_data; - for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; ++isa_idx, isa_addr += addr_size) - { - isa = m_process->ReadPointerFromMemory(isa_addr, error); - - if (isa && isa != LLDB_INVALID_ADDRESS) - { - if (!ISAIsCached(isa)) - { - ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); - - if (log && log->GetVerbose()) - log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa); - - AddClass (isa, descriptor_sp); - } - } - } - } - } +void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { + // TODO: implement HashTableSignature... + Process *process = GetProcess(); + + if (process) { + // Update the process stop ID that indicates the last time we updated the + // map, whether it was successful or not. + m_isa_to_descriptor_stop_id = process->GetStopID(); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + ProcessSP process_sp = process->shared_from_this(); + + ModuleSP objc_module_sp(GetObjCModule()); + + if (!objc_module_sp) + return; + + uint32_t isa_count = 0; + + lldb::addr_t hash_table_ptr = GetISAHashTablePointer(); + if (hash_table_ptr != LLDB_INVALID_ADDRESS) { + // Read the NXHashTable struct: + // + // typedef struct { + // const NXHashTablePrototype *prototype; + // unsigned count; + // unsigned nbBuckets; + // void *buckets; + // const void *info; + // } NXHashTable; + + Error error; + DataBufferHeap buffer(1024, 0); + if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) == + 20) { + const uint32_t addr_size = m_process->GetAddressByteSize(); + const ByteOrder byte_order = m_process->GetByteOrder(); + DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order, + addr_size); + lldb::offset_t offset = addr_size; // Skip prototype + const uint32_t count = data.GetU32(&offset); + const uint32_t num_buckets = data.GetU32(&offset); + const addr_t buckets_ptr = data.GetPointer(&offset); + if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) { + m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr); + + const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t); + buffer.SetByteSize(data_size); + + if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size, + error) == data_size) { + data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order); + offset = 0; + for (uint32_t bucket_idx = 0; bucket_idx < num_buckets; + ++bucket_idx) { + const uint32_t bucket_isa_count = data.GetU32(&offset); + const lldb::addr_t bucket_data = data.GetU32(&offset); + + if (bucket_isa_count == 0) + continue; + + isa_count += bucket_isa_count; + + ObjCISA isa; + if (bucket_isa_count == 1) { + // When we only have one entry in the bucket, the bucket data is + // the "isa" + isa = bucket_data; + if (isa) { + if (!ISAIsCached(isa)) { + ClassDescriptorSP descriptor_sp( + new ClassDescriptorV1(isa, process_sp)); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 + " from _objc_debug_class_hash to " + "isa->descriptor cache", + isa); + + AddClass(isa, descriptor_sp); + } + } + } else { + // When we have more than one entry in the bucket, the bucket + // data is a pointer + // to an array of "isa" values + addr_t isa_addr = bucket_data; + for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; + ++isa_idx, isa_addr += addr_size) { + isa = m_process->ReadPointerFromMemory(isa_addr, error); + + if (isa && isa != LLDB_INVALID_ADDRESS) { + if (!ISAIsCached(isa)) { + ClassDescriptorSP descriptor_sp( + new ClassDescriptorV1(isa, process_sp)); + + if (log && log->GetVerbose()) + log->Printf( + "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 + " from _objc_debug_class_hash to isa->descriptor " + "cache", + isa); + + AddClass(isa, descriptor_sp); } + } } + } } - } - } - else - { - m_isa_to_descriptor_stop_id = UINT32_MAX; + } + } + } } + } else { + m_isa_to_descriptor_stop_id = UINT32_MAX; + } } -DeclVendor * -AppleObjCRuntimeV1::GetDeclVendor() -{ - if (!m_decl_vendor_ap.get()) - m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this)); - - return m_decl_vendor_ap.get(); +DeclVendor *AppleObjCRuntimeV1::GetDeclVendor() { + if (!m_decl_vendor_ap.get()) + m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this)); + + return m_decl_vendor_ap.get(); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index 9f9fcc69b68..3dddf1b094e 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -14,194 +14,148 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "AppleObjCRuntime.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_private { - -class AppleObjCRuntimeV1 : - public AppleObjCRuntime -{ + +class AppleObjCRuntimeV1 : public AppleObjCRuntime { public: - ~AppleObjCRuntimeV1() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static bool classof(const ObjCLanguageRuntime* runtime) - { - switch (runtime->GetRuntimeVersion()) - { - case ObjCRuntimeVersions::eAppleObjC_V1: - return true; - default: - return false; - } + ~AppleObjCRuntimeV1() override = default; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); + + static lldb_private::ConstString GetPluginNameStatic(); + + static bool classof(const ObjCLanguageRuntime *runtime) { + switch (runtime->GetRuntimeVersion()) { + case ObjCRuntimeVersions::eAppleObjC_V1: + return true; + default: + return false; } - - class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor - { - public: - ClassDescriptorV1 (ValueObject &isa_pointer); - ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp); - - ~ClassDescriptorV1() override = default; - - ConstString - GetClassName() override - { - return m_name; - } - - ClassDescriptorSP - GetSuperclass() override; - - ClassDescriptorSP - GetMetaclass() const override; - - bool - IsValid() override - { - return m_valid; - } - - // v1 does not support tagged pointers - bool - GetTaggedPointerInfo(uint64_t* info_bits = nullptr, - uint64_t* value_bits = nullptr, - uint64_t* payload = nullptr) override - { - return false; - } - - uint64_t - GetInstanceSize() override - { - return m_instance_size; - } - - ObjCISA - GetISA() override - { - return m_isa; - } - - bool - Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, - std::function <bool (const char *, const char *)> const &instance_method_func, - std::function <bool (const char *, const char *)> const &class_method_func, - std::function <bool (const char *, const char *, - lldb::addr_t, uint64_t)> const &ivar_func) const override; - - protected: - void - Initialize (ObjCISA isa, lldb::ProcessSP process_sp); - - private: - ConstString m_name; - ObjCISA m_isa; - ObjCISA m_parent_isa; - bool m_valid; - lldb::ProcessWP m_process_wp; - uint64_t m_instance_size; - }; - - // These are generic runtime functions: - bool - GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - UtilityFunction * - CreateObjectChecker(const char *) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - ObjCRuntimeVersions - GetRuntimeVersion() const override - { - return ObjCRuntimeVersions::eAppleObjC_V1; + } + + class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor { + public: + ClassDescriptorV1(ValueObject &isa_pointer); + ClassDescriptorV1(ObjCISA isa, lldb::ProcessSP process_sp); + + ~ClassDescriptorV1() override = default; + + ConstString GetClassName() override { return m_name; } + + ClassDescriptorSP GetSuperclass() override; + + ClassDescriptorSP GetMetaclass() const override; + + bool IsValid() override { return m_valid; } + + // v1 does not support tagged pointers + bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, + uint64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; } - - void - UpdateISAToDescriptorMapIfNeeded() override; - - DeclVendor * - GetDeclVendor() override; + + uint64_t GetInstanceSize() override { return m_instance_size; } + + ObjCISA GetISA() override { return m_isa; } + + bool + Describe(std::function<void(ObjCLanguageRuntime::ObjCISA)> const + &superclass_func, + std::function<bool(const char *, const char *)> const + &instance_method_func, + std::function<bool(const char *, const char *)> const + &class_method_func, + std::function<bool(const char *, const char *, lldb::addr_t, + uint64_t)> const &ivar_func) const override; + + protected: + void Initialize(ObjCISA isa, lldb::ProcessSP process_sp); + + private: + ConstString m_name; + ObjCISA m_isa; + ObjCISA m_parent_isa; + bool m_valid; + lldb::ProcessWP m_process_wp; + uint64_t m_instance_size; + }; + + // These are generic runtime functions: + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; + + UtilityFunction *CreateObjectChecker(const char *) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + ObjCRuntimeVersions GetRuntimeVersion() const override { + return ObjCRuntimeVersions::eAppleObjC_V1; + } + + void UpdateISAToDescriptorMapIfNeeded() override; + + DeclVendor *GetDeclVendor() override; protected: - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override; - - class HashTableSignature - { - public: - HashTableSignature () : - m_count (0), - m_num_buckets (0), - m_buckets_ptr (LLDB_INVALID_ADDRESS) - { - } - - bool - NeedsUpdate (uint32_t count, - uint32_t num_buckets, - lldb::addr_t buckets_ptr) - { - return m_count != count || - m_num_buckets != num_buckets || - m_buckets_ptr != buckets_ptr ; - } - - void - UpdateSignature (uint32_t count, - uint32_t num_buckets, - lldb::addr_t buckets_ptr) - { - m_count = count; - m_num_buckets = num_buckets; - m_buckets_ptr = buckets_ptr; - } - - protected: - uint32_t m_count; - uint32_t m_num_buckets; - lldb::addr_t m_buckets_ptr; - }; - - lldb::addr_t - GetISAHashTablePointer (); - - HashTableSignature m_hash_signature; - lldb::addr_t m_isa_hash_table_ptr; - std::unique_ptr<DeclVendor> m_decl_vendor_ap; + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override; + + class HashTableSignature { + public: + HashTableSignature() + : m_count(0), m_num_buckets(0), m_buckets_ptr(LLDB_INVALID_ADDRESS) {} + + bool NeedsUpdate(uint32_t count, uint32_t num_buckets, + lldb::addr_t buckets_ptr) { + return m_count != count || m_num_buckets != num_buckets || + m_buckets_ptr != buckets_ptr; + } + + void UpdateSignature(uint32_t count, uint32_t num_buckets, + lldb::addr_t buckets_ptr) { + m_count = count; + m_num_buckets = num_buckets; + m_buckets_ptr = buckets_ptr; + } + + protected: + uint32_t m_count; + uint32_t m_num_buckets; + lldb::addr_t m_buckets_ptr; + }; + + lldb::addr_t GetISAHashTablePointer(); + + HashTableSignature m_hash_signature; + lldb::addr_t m_isa_hash_table_ptr; + std::unique_ptr<DeclVendor> m_decl_vendor_ap; private: - AppleObjCRuntimeV1(Process *process); + AppleObjCRuntimeV1(Process *process); }; - + } // namespace lldb_private #endif // liblldb_AppleObjCRuntimeV1_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 6888532f370..afa443f9738 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -19,9 +19,9 @@ #include "clang/AST/DeclObjC.h" // Project includes -#include "lldb/lldb-enumerations.h" #include "lldb/Core/ClangForward.h" #include "lldb/Symbol/CompilerType.h" +#include "lldb/lldb-enumerations.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/ConstString.h" @@ -56,21 +56,22 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" -#include "AppleObjCRuntimeV2.h" #include "AppleObjCClassDescriptorV2.h" -#include "AppleObjCTypeEncodingParser.h" #include "AppleObjCDeclVendor.h" +#include "AppleObjCRuntimeV2.h" #include "AppleObjCTrampolineHandler.h" - +#include "AppleObjCTypeEncodingParser.h" using namespace lldb; using namespace lldb_private; // 2 second timeout when running utility functions -#define UTILITY_FUNCTION_TIMEOUT_USEC 2*1000*1000 +#define UTILITY_FUNCTION_TIMEOUT_USEC 2 * 1000 * 1000 -static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info"; -// Testing using the new C++11 raw string literals. If this breaks GCC then we will +static const char *g_get_dynamic_class_info_name = + "__lldb_apple_objc_v2_get_dynamic_class_info"; +// Testing using the new C++11 raw string literals. If this breaks GCC then we +// will // need to revert to the code above... static const char *g_get_dynamic_class_info_body = R"( @@ -152,8 +153,10 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr )"; -static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info"; -// Testing using the new C++11 raw string literals. If this breaks GCC then we will +static const char *g_get_shared_cache_class_info_name = + "__lldb_apple_objc_v2_get_shared_cache_class_info"; +// Testing using the new C++11 raw string literals. If this breaks GCC then we +// will // need to revert to the code above... static const char *g_get_shared_cache_class_info_body = R"( @@ -334,2287 +337,2110 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, )"; static uint64_t -ExtractRuntimeGlobalSymbol (Process* process, - ConstString name, - const ModuleSP &module_sp, - Error& error, - bool read_value = true, - uint8_t byte_size = 0, - uint64_t default_value = LLDB_INVALID_ADDRESS, - SymbolType sym_type = lldb::eSymbolTypeData) -{ - if (!process) - { - error.SetErrorString("no process"); - return default_value; - } - if (!module_sp) - { - error.SetErrorString("no module"); - return default_value; - } - if (!byte_size) - byte_size = process->GetAddressByteSize(); - const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData); - if (symbol && symbol->ValueIsAddress()) - { - lldb::addr_t symbol_load_addr = symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); - if (symbol_load_addr != LLDB_INVALID_ADDRESS) - { - if (read_value) - return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, default_value, error); - else - return symbol_load_addr; - } - else - { - error.SetErrorString("symbol address invalid"); - return default_value; - } - } - else - { - error.SetErrorString("no symbol"); - return default_value; - } +ExtractRuntimeGlobalSymbol(Process *process, ConstString name, + const ModuleSP &module_sp, Error &error, + bool read_value = true, uint8_t byte_size = 0, + uint64_t default_value = LLDB_INVALID_ADDRESS, + SymbolType sym_type = lldb::eSymbolTypeData) { + if (!process) { + error.SetErrorString("no process"); + return default_value; + } + if (!module_sp) { + error.SetErrorString("no module"); + return default_value; + } + if (!byte_size) + byte_size = process->GetAddressByteSize(); + const Symbol *symbol = + module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData); + if (symbol && symbol->ValueIsAddress()) { + lldb::addr_t symbol_load_addr = + symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); + if (symbol_load_addr != LLDB_INVALID_ADDRESS) { + if (read_value) + return process->ReadUnsignedIntegerFromMemory( + symbol_load_addr, byte_size, default_value, error); + else + return symbol_load_addr; + } else { + error.SetErrorString("symbol address invalid"); + return default_value; + } + } else { + error.SetErrorString("no symbol"); + return default_value; + } } -AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, const ModuleSP &objc_module_sp) - : AppleObjCRuntime(process), - m_get_class_info_code(), +AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, + const ModuleSP &objc_module_sp) + : AppleObjCRuntime(process), m_get_class_info_code(), m_get_class_info_args(LLDB_INVALID_ADDRESS), - m_get_class_info_args_mutex(), - m_get_shared_cache_class_info_code(), + m_get_class_info_args_mutex(), 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_ap(), - m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), - m_hash_signature(), - m_has_object_getClass(false), - m_loaded_objc_opt(false), - m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this, objc_module_sp)), - m_tagged_pointer_vendor_ap(TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)), - m_encoding_to_type_sp(), - m_noclasses_warning_emitted(false), - m_CFBoolean_values() -{ - static const ConstString g_gdb_object_getClass("gdb_object_getClass"); - m_has_object_getClass = - (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL); + m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_ap(), + m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(), + m_has_object_getClass(false), m_loaded_objc_opt(false), + m_non_pointer_isa_cache_ap( + NonPointerISACache::CreateInstance(*this, objc_module_sp)), + m_tagged_pointer_vendor_ap( + TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)), + m_encoding_to_type_sp(), m_noclasses_warning_emitted(false), + m_CFBoolean_values() { + static const ConstString g_gdb_object_getClass("gdb_object_getClass"); + m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType( + g_gdb_object_getClass, eSymbolTypeCode) != NULL); } -bool -AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value, - DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) -{ - // We should never get here with a null process... - assert (m_process != NULL); - - // The Runtime is attached to a particular process, you shouldn't pass in a value from another process. - // Note, however, the process might be NULL (e.g. if the value was made with SBTarget::EvaluateExpression...) - // in which case it is sufficient if the target's match: - - Process *process = in_value.GetProcessSP().get(); - if (process) - assert (process == m_process); - else - assert (in_value.GetTargetSP().get() == m_process->CalculateTarget().get()); - - class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; - - // Make sure we can have a dynamic value before starting... - if (CouldHaveDynamicValue (in_value)) - { - // First job, pull out the address at 0 offset from the object That will be the ISA pointer. - ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor (in_value)); - if (objc_class_sp) - { - const addr_t object_ptr = in_value.GetPointerValue(); - address.SetRawAddress(object_ptr); - - ConstString class_name (objc_class_sp->GetClassName()); - class_type_or_name.SetName(class_name); - TypeSP type_sp (objc_class_sp->GetType()); - if (type_sp) - class_type_or_name.SetTypeSP (type_sp); - else - { - type_sp = LookupInCompleteClassCache (class_name); - if (type_sp) - { - objc_class_sp->SetType (type_sp); - class_type_or_name.SetTypeSP (type_sp); - } - else - { - // try to go for a CompilerType at least - DeclVendor* vendor = GetDeclVendor(); - if (vendor) - { - std::vector<clang::NamedDecl*> decls; - if (vendor->FindDecls(class_name, false, 1, decls) && decls.size()) - class_type_or_name.SetCompilerType(ClangASTContext::GetTypeForDecl(decls[0])); - } - } - } +bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( + ValueObject &in_value, DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &address, + Value::ValueType &value_type) { + // We should never get here with a null process... + assert(m_process != NULL); + + // The Runtime is attached to a particular process, you shouldn't pass in a + // value from another process. + // Note, however, the process might be NULL (e.g. if the value was made with + // SBTarget::EvaluateExpression...) + // in which case it is sufficient if the target's match: + + Process *process = in_value.GetProcessSP().get(); + if (process) + assert(process == m_process); + else + assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get()); + + class_type_or_name.Clear(); + value_type = Value::ValueType::eValueTypeScalar; + + // Make sure we can have a dynamic value before starting... + if (CouldHaveDynamicValue(in_value)) { + // First job, pull out the address at 0 offset from the object That will be + // the ISA pointer. + ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value)); + if (objc_class_sp) { + const addr_t object_ptr = in_value.GetPointerValue(); + address.SetRawAddress(object_ptr); + + ConstString class_name(objc_class_sp->GetClassName()); + class_type_or_name.SetName(class_name); + TypeSP type_sp(objc_class_sp->GetType()); + if (type_sp) + class_type_or_name.SetTypeSP(type_sp); + else { + type_sp = LookupInCompleteClassCache(class_name); + if (type_sp) { + objc_class_sp->SetType(type_sp); + class_type_or_name.SetTypeSP(type_sp); + } else { + // try to go for a CompilerType at least + DeclVendor *vendor = GetDeclVendor(); + if (vendor) { + std::vector<clang::NamedDecl *> decls; + if (vendor->FindDecls(class_name, false, 1, decls) && decls.size()) + class_type_or_name.SetCompilerType( + ClangASTContext::GetTypeForDecl(decls[0])); + } } - } - return class_type_or_name.IsEmpty() == false; + } + } + } + return class_type_or_name.IsEmpty() == false; } //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ -LanguageRuntime * -AppleObjCRuntimeV2::CreateInstance (Process *process, LanguageType language) -{ - // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make - // sure we aren't using the V1 runtime. - if (language == eLanguageTypeObjC) - { - ModuleSP objc_module_sp; - - if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == ObjCRuntimeVersions::eAppleObjC_V2) - return new AppleObjCRuntimeV2 (process, objc_module_sp); - else - return NULL; - } +LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process, + LanguageType language) { + // FIXME: This should be a MacOS or iOS process, and we need to look for the + // OBJC section to make + // sure we aren't using the V1 runtime. + if (language == eLanguageTypeObjC) { + ModuleSP objc_module_sp; + + if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) == + ObjCRuntimeVersions::eAppleObjC_V2) + return new AppleObjCRuntimeV2(process, objc_module_sp); else - return NULL; + return NULL; + } else + return NULL; } -class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed -{ +class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed { public: - class CommandOptions : public Options - { - public: - CommandOptions() : - Options(), - m_verbose(false,false) - {} - - ~CommandOptions() override = default; - - Error - SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - switch (short_option) - { - case 'v': - m_verbose.SetCurrentValue(true); - m_verbose.SetOptionWasSet(); - break; - - default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); - break; - } - - return error; - } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_verbose.Clear(); - } - - const OptionDefinition* - GetDefinitions() override - { - return g_option_table; - } + class CommandOptions : public Options { + public: + CommandOptions() : Options(), m_verbose(false, false) {} - OptionValueBoolean m_verbose; - static OptionDefinition g_option_table[]; - }; - - CommandObjectObjC_ClassTable_Dump (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "dump", - "Dump information on Objective-C classes known to the current process.", - "language objc class-table dump", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused ), - m_options() - { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeRegularExpression; - index_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } + ~CommandOptions() override = default; - ~CommandObjectObjC_ClassTable_Dump() override = default; + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + switch (short_option) { + case 'v': + m_verbose.SetCurrentValue(true); + m_verbose.SetOptionWasSet(); + break; - Options * - GetOptions() override - { - return &m_options; + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose.Clear(); } - + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + OptionValueBoolean m_verbose; + static OptionDefinition g_option_table[]; + }; + + CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "dump", "Dump information on Objective-C classes " + "known to the current process.", + "language objc class-table dump", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused), + m_options() { + CommandArgumentEntry arg; + CommandArgumentData index_arg; + + // Define the first (and only) variant of this arg. + index_arg.arg_type = eArgTypeRegularExpression; + index_arg.arg_repetition = eArgRepeatOptional; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectObjC_ClassTable_Dump() override = default; + + Options *GetOptions() override { return &m_options; } + protected: - bool - DoExecute(Args& command, CommandReturnObject &result) override - { - std::unique_ptr<RegularExpression> regex_up; - switch(command.GetArgumentCount()) - { - case 0: - break; - case 1: - { - regex_up.reset(new RegularExpression()); - if (!regex_up->Compile(command.GetArgumentAtIndex(0))) - { - result.AppendError("invalid argument - please provide a valid regular expression"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; - } - break; - } - default: - { - result.AppendError("please provide 0 or 1 arguments"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; - } - } - - Process *process = m_exe_ctx.GetProcessPtr(); - ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); - if (objc_runtime) - { - auto iterators_pair = objc_runtime->GetDescriptorIteratorPair(); - auto iterator = iterators_pair.first; - auto &std_out = result.GetOutputStream(); - for(; iterator != iterators_pair.second; iterator++) - { - if (iterator->second) - { - const char* class_name = iterator->second->GetClassName().AsCString("<unknown>"); - if (regex_up && class_name && !regex_up->Execute(class_name)) - continue; - std_out.Printf("isa = 0x%" PRIx64, iterator->first); - std_out.Printf(" name = %s", class_name); - std_out.Printf(" instance size = %" PRIu64, iterator->second->GetInstanceSize()); - std_out.Printf(" num ivars = %" PRIuPTR, (uintptr_t)iterator->second->GetNumIVars()); - if (auto superclass = iterator->second->GetSuperclass()) - { - std_out.Printf(" superclass = %s", superclass->GetClassName().AsCString("<unknown>")); - } - std_out.Printf("\n"); - if (m_options.m_verbose) - { - for(size_t i = 0; - i < iterator->second->GetNumIVars(); - i++) - { - auto ivar = iterator->second->GetIVarAtIndex(i); - std_out.Printf(" ivar name = %s type = %s size = %" PRIu64 " offset = %" PRId32 "\n", - ivar.m_name.AsCString("<unknown>"), - ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"), - ivar.m_size, - ivar.m_offset); - } - iterator->second->Describe(nullptr, - [objc_runtime, &std_out] (const char* name, const char* type) -> bool { - std_out.Printf(" instance method name = %s type = %s\n", - name, - type); - return false; - }, - [objc_runtime, &std_out] (const char* name, const char* type) -> bool { - std_out.Printf(" class method name = %s type = %s\n", - name, - type); - return false; - }, - nullptr); - } - } - else - { - if (regex_up && !regex_up->Execute("")) - continue; - std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n", iterator->first); - } + bool DoExecute(Args &command, CommandReturnObject &result) override { + std::unique_ptr<RegularExpression> regex_up; + switch (command.GetArgumentCount()) { + case 0: + break; + case 1: { + regex_up.reset(new RegularExpression()); + if (!regex_up->Compile(command.GetArgumentAtIndex(0))) { + result.AppendError( + "invalid argument - please provide a valid regular expression"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; + } + break; + } + default: { + result.AppendError("please provide 0 or 1 arguments"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; + } + } + + Process *process = m_exe_ctx.GetProcessPtr(); + ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); + if (objc_runtime) { + auto iterators_pair = objc_runtime->GetDescriptorIteratorPair(); + auto iterator = iterators_pair.first; + auto &std_out = result.GetOutputStream(); + for (; iterator != iterators_pair.second; iterator++) { + if (iterator->second) { + const char *class_name = + iterator->second->GetClassName().AsCString("<unknown>"); + if (regex_up && class_name && !regex_up->Execute(class_name)) + continue; + std_out.Printf("isa = 0x%" PRIx64, iterator->first); + std_out.Printf(" name = %s", class_name); + std_out.Printf(" instance size = %" PRIu64, + iterator->second->GetInstanceSize()); + std_out.Printf(" num ivars = %" PRIuPTR, + (uintptr_t)iterator->second->GetNumIVars()); + if (auto superclass = iterator->second->GetSuperclass()) { + std_out.Printf(" superclass = %s", + superclass->GetClassName().AsCString("<unknown>")); + } + std_out.Printf("\n"); + if (m_options.m_verbose) { + for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) { + auto ivar = iterator->second->GetIVarAtIndex(i); + std_out.Printf( + " ivar name = %s type = %s size = %" PRIu64 + " offset = %" PRId32 "\n", + ivar.m_name.AsCString("<unknown>"), + ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"), + ivar.m_size, ivar.m_offset); } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - return true; - } - else - { - result.AppendError("current process has no Objective-C runtime loaded"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; + iterator->second->Describe( + nullptr, + [objc_runtime, &std_out](const char *name, + const char *type) -> bool { + std_out.Printf(" instance method name = %s type = %s\n", + name, type); + return false; + }, + [objc_runtime, &std_out](const char *name, + const char *type) -> bool { + std_out.Printf(" class method name = %s type = %s\n", name, + type); + return false; + }, + nullptr); + } + } else { + if (regex_up && !regex_up->Execute("")) + continue; + std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n", + iterator->first); } + } + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + return true; + } else { + result.AppendError("current process has no Objective-C runtime loaded"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; } - - CommandOptions m_options; -}; + } -OptionDefinition -CommandObjectObjC_ClassTable_Dump::CommandOptions::g_option_table[] = -{ - { LLDB_OPT_SET_ALL, false, "verbose" , 'v', OptionParser::eNoArgument , nullptr, nullptr, 0, eArgTypeNone, "Print ivar and method information in detail"}, - { 0 , false, nullptr , 0, 0 , nullptr, nullptr, 0, eArgTypeNone, nullptr } + CommandOptions m_options; }; -class CommandObjectMultiwordObjC_TaggedPointer_Info : public CommandObjectParsed -{ +OptionDefinition + CommandObjectObjC_ClassTable_Dump::CommandOptions::g_option_table[] = { + {LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument, + nullptr, nullptr, 0, eArgTypeNone, + "Print ivar and method information in detail"}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; + +class CommandObjectMultiwordObjC_TaggedPointer_Info + : public CommandObjectParsed { public: - CommandObjectMultiwordObjC_TaggedPointer_Info (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "info", - "Dump information on a tagged pointer.", - "language objc tagged-pointer info", - eCommandRequiresProcess | - eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused ) - { - CommandArgumentEntry arg; - CommandArgumentData index_arg; - - // Define the first (and only) variant of this arg. - index_arg.arg_type = eArgTypeAddress; - index_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (index_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); - } + CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "info", "Dump information on a tagged pointer.", + "language objc tagged-pointer info", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) { + CommandArgumentEntry arg; + CommandArgumentData index_arg; + + // Define the first (and only) variant of this arg. + index_arg.arg_type = eArgTypeAddress; + index_arg.arg_repetition = eArgRepeatPlus; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(index_arg); - ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default; + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default; protected: - bool - DoExecute(Args& command, CommandReturnObject &result) override - { - if (command.GetArgumentCount() == 0) - { - result.AppendError("this command requires arguments"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; - } - - Process *process = m_exe_ctx.GetProcessPtr(); - ExecutionContext exe_ctx(process); - ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); - if (objc_runtime) - { - ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor = objc_runtime->GetTaggedPointerVendor(); - if (tagged_ptr_vendor) - { - for (size_t i = 0; - i < command.GetArgumentCount(); - i++) - { - const char *arg_str = command.GetArgumentAtIndex(i); - if (!arg_str) - continue; - Error error; - lldb::addr_t arg_addr = Args::StringToAddress(&exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error); - if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) - continue; - auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr); - if (!descriptor_sp) - continue; - uint64_t info_bits = 0; - uint64_t value_bits = 0; - uint64_t payload = 0; - if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) - { - result.GetOutputStream().Printf("0x%" PRIx64 " is tagged.\n\tpayload = 0x%" PRIx64 "\n\tvalue = 0x%" PRIx64 "\n\tinfo bits = 0x%" PRIx64 "\n\tclass = %s\n", - (uint64_t)arg_addr, - payload, - value_bits, - info_bits, - descriptor_sp->GetClassName().AsCString("<unknown>")); - } - else - { - result.GetOutputStream().Printf("0x%" PRIx64 " is not tagged.\n", (uint64_t)arg_addr); - } - } - } - else - { - result.AppendError("current process has no tagged pointer support"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; - } - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - return true; - } - else - { - result.AppendError("current process has no Objective-C runtime loaded"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.GetArgumentCount() == 0) { + result.AppendError("this command requires arguments"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; + } + + Process *process = m_exe_ctx.GetProcessPtr(); + ExecutionContext exe_ctx(process); + ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime(); + if (objc_runtime) { + ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor = + objc_runtime->GetTaggedPointerVendor(); + if (tagged_ptr_vendor) { + for (size_t i = 0; i < command.GetArgumentCount(); i++) { + const char *arg_str = command.GetArgumentAtIndex(i); + if (!arg_str) + continue; + Error error; + lldb::addr_t arg_addr = Args::StringToAddress( + &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error); + if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) + continue; + auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr); + if (!descriptor_sp) + continue; + uint64_t info_bits = 0; + uint64_t value_bits = 0; + uint64_t payload = 0; + if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits, + &payload)) { + result.GetOutputStream().Printf( + "0x%" PRIx64 " is tagged.\n\tpayload = 0x%" PRIx64 + "\n\tvalue = 0x%" PRIx64 "\n\tinfo bits = 0x%" PRIx64 + "\n\tclass = %s\n", + (uint64_t)arg_addr, payload, value_bits, info_bits, + descriptor_sp->GetClassName().AsCString("<unknown>")); + } else { + result.GetOutputStream().Printf("0x%" PRIx64 " is not tagged.\n", + (uint64_t)arg_addr); + } } - } + } else { + result.AppendError("current process has no tagged pointer support"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; + } + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + return true; + } else { + result.AppendError("current process has no Objective-C runtime loaded"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; + } + } }; -class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword -{ +class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword { public: - CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "class-table", "Commands for operating on the Objective-C class table.", - "class-table <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("dump", CommandObjectSP (new CommandObjectObjC_ClassTable_Dump (interpreter))); - } - - ~CommandObjectMultiwordObjC_ClassTable() override = default; + CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "class-table", + "Commands for operating on the Objective-C class table.", + "class-table <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "dump", + CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter))); + } + + ~CommandObjectMultiwordObjC_ClassTable() override = default; }; -class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword -{ +class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword { public: - CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "tagged-pointer", - "Commands for operating on Objective-C tagged pointers.", - "class-table <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("info", CommandObjectSP (new CommandObjectMultiwordObjC_TaggedPointer_Info (interpreter))); - } - - ~CommandObjectMultiwordObjC_TaggedPointer() override = default; + CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "tagged-pointer", + "Commands for operating on Objective-C tagged pointers.", + "class-table <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "info", + CommandObjectSP( + new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter))); + } + + ~CommandObjectMultiwordObjC_TaggedPointer() override = default; }; -class CommandObjectMultiwordObjC : public CommandObjectMultiword -{ +class CommandObjectMultiwordObjC : public CommandObjectMultiword { public: - CommandObjectMultiwordObjC(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "objc", "Commands for operating on the Objective-C language runtime.", - "objc <subcommand> [<subcommand-options>]") - { - LoadSubCommand ("class-table", CommandObjectSP (new CommandObjectMultiwordObjC_ClassTable (interpreter))); - LoadSubCommand ("tagged-pointer", CommandObjectSP (new CommandObjectMultiwordObjC_TaggedPointer (interpreter))); - } - - ~CommandObjectMultiwordObjC() override = default; + CommandObjectMultiwordObjC(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "objc", + "Commands for operating on the Objective-C language runtime.", + "objc <subcommand> [<subcommand-options>]") { + LoadSubCommand("class-table", + CommandObjectSP( + new CommandObjectMultiwordObjC_ClassTable(interpreter))); + LoadSubCommand("tagged-pointer", + CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer( + interpreter))); + } + + ~CommandObjectMultiwordObjC() override = default; }; -void -AppleObjCRuntimeV2::Initialize() -{ - PluginManager::RegisterPlugin (GetPluginNameStatic(), - "Apple Objective C Language Runtime - Version 2", - CreateInstance, - [] (CommandInterpreter& interpreter) -> lldb::CommandObjectSP { - return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter)); - }); +void AppleObjCRuntimeV2::Initialize() { + PluginManager::RegisterPlugin( + GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 2", + CreateInstance, + [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP { + return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter)); + }); } -void -AppleObjCRuntimeV2::Terminate() -{ - PluginManager::UnregisterPlugin (CreateInstance); +void AppleObjCRuntimeV2::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -AppleObjCRuntimeV2::GetPluginNameStatic() -{ - static ConstString g_name("apple-objc-v2"); - return g_name; +lldb_private::ConstString AppleObjCRuntimeV2::GetPluginNameStatic() { + static ConstString g_name("apple-objc-v2"); + return g_name; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -AppleObjCRuntimeV2::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString AppleObjCRuntimeV2::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -AppleObjCRuntimeV2::GetPluginVersion() -{ - return 1; -} +uint32_t AppleObjCRuntimeV2::GetPluginVersion() { return 1; } BreakpointResolverSP -AppleObjCRuntimeV2::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) -{ - BreakpointResolverSP resolver_sp; - - if (throw_bp) - resolver_sp.reset (new BreakpointResolverName (bkpt, - "objc_exception_throw", - eFunctionNameTypeBase, - eLanguageTypeUnknown, - Breakpoint::Exact, - 0, - eLazyBoolNo)); - // FIXME: We don't do catch breakpoints for ObjC yet. - // Should there be some way for the runtime to specify what it can do in this regard? - return resolver_sp; +AppleObjCRuntimeV2::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, + bool throw_bp) { + BreakpointResolverSP resolver_sp; + + if (throw_bp) + resolver_sp.reset(new BreakpointResolverName( + bkpt, "objc_exception_throw", eFunctionNameTypeBase, + eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo)); + // FIXME: We don't do catch breakpoints for ObjC yet. + // Should there be some way for the runtime to specify what it can do in this + // regard? + return resolver_sp; } -UtilityFunction * -AppleObjCRuntimeV2::CreateObjectChecker(const char *name) -{ - char check_function_code[2048]; - - int len = 0; - if (m_has_object_getClass) - { - len = ::snprintf (check_function_code, - sizeof(check_function_code), - "extern \"C\" void *gdb_object_getClass(void *); \n" - "extern \"C\" int printf(const char *format, ...); \n" - "extern \"C\" void \n" - "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" - "{ \n" - " if ($__lldb_arg_obj == (void *)0) \n" - " return; // nil is ok \n" - " if (!gdb_object_getClass($__lldb_arg_obj)) \n" - " *((volatile int *)0) = 'ocgc'; \n" - " else if ($__lldb_arg_selector != (void *)0) \n" - " { \n" - " signed char responds = (signed char) [(id) $__lldb_arg_obj \n" - " respondsToSelector: \n" - " (struct objc_selector *) $__lldb_arg_selector]; \n" - " if (responds == (signed char) 0) \n" - " *((volatile int *)0) = 'ocgc'; \n" - " } \n" - "} \n", - name); - } - else - { - len = ::snprintf (check_function_code, - sizeof(check_function_code), - "extern \"C\" void *gdb_class_getClass(void *); \n" - "extern \"C\" int printf(const char *format, ...); \n" - "extern \"C\" void \n" - "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" - "{ \n" - " if ($__lldb_arg_obj == (void *)0) \n" - " return; // nil is ok \n" - " void **$isa_ptr = (void **)$__lldb_arg_obj; \n" - " if (*$isa_ptr == (void *)0 || !gdb_class_getClass(*$isa_ptr)) \n" - " *((volatile int *)0) = 'ocgc'; \n" - " else if ($__lldb_arg_selector != (void *)0) \n" - " { \n" - " signed char responds = (signed char) [(id) $__lldb_arg_obj \n" - " respondsToSelector: \n" - " (struct objc_selector *) $__lldb_arg_selector]; \n" - " if (responds == (signed char) 0) \n" - " *((volatile int *)0) = 'ocgc'; \n" - " } \n" - "} \n", - name); - } - - assert (len < (int)sizeof(check_function_code)); +UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { + char check_function_code[2048]; + + int len = 0; + if (m_has_object_getClass) { + len = ::snprintf(check_function_code, sizeof(check_function_code), + "extern \"C\" void *gdb_object_getClass(void *); " + " \n" + "extern \"C\" int printf(const char *format, ...); " + " \n" + "extern \"C\" void " + " \n" + "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " + " \n" + "{ " + " \n" + " if ($__lldb_arg_obj == (void *)0) " + " \n" + " return; // nil is ok " + " \n" + " if (!gdb_object_getClass($__lldb_arg_obj)) " + " \n" + " *((volatile int *)0) = 'ocgc'; " + " \n" + " else if ($__lldb_arg_selector != (void *)0) " + " \n" + " { " + " \n" + " signed char responds = (signed char) [(id) " + "$__lldb_arg_obj \n" + " " + "respondsToSelector: \n" + " (struct " + "objc_selector *) $__lldb_arg_selector]; \n" + " if (responds == (signed char) 0) " + " \n" + " *((volatile int *)0) = 'ocgc'; " + " \n" + " } " + " \n" + "} " + " \n", + name); + } else { + len = ::snprintf(check_function_code, sizeof(check_function_code), + "extern \"C\" void *gdb_class_getClass(void *); " + " \n" + "extern \"C\" int printf(const char *format, ...); " + " \n" + "extern \"C\" void " + " \n" + "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " + " \n" + "{ " + " \n" + " if ($__lldb_arg_obj == (void *)0) " + " \n" + " return; // nil is ok " + " \n" + " void **$isa_ptr = (void **)$__lldb_arg_obj; " + " \n" + " if (*$isa_ptr == (void *)0 || " + "!gdb_class_getClass(*$isa_ptr)) \n" + " *((volatile int *)0) = 'ocgc'; " + " \n" + " else if ($__lldb_arg_selector != (void *)0) " + " \n" + " { " + " \n" + " signed char responds = (signed char) [(id) " + "$__lldb_arg_obj \n" + " " + "respondsToSelector: \n" + " (struct " + "objc_selector *) $__lldb_arg_selector]; \n" + " if (responds == (signed char) 0) " + " \n" + " *((volatile int *)0) = 'ocgc'; " + " \n" + " } " + " \n" + "} " + " \n", + name); + } + + assert(len < (int)sizeof(check_function_code)); + + Error error; + return GetTargetRef().GetUtilityFunctionForLanguage( + check_function_code, eLanguageTypeObjC, name, error); +} + +size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, + const char *ivar_name) { + uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET; + + const char *class_name = parent_ast_type.GetConstTypeName().AsCString(); + if (class_name && class_name[0] && ivar_name && ivar_name[0]) { + //---------------------------------------------------------------------- + // Make the objective C V2 mangled name for the ivar offset from the + // class name and ivar name + //---------------------------------------------------------------------- + std::string buffer("OBJC_IVAR_$_"); + buffer.append(class_name); + buffer.push_back('.'); + buffer.append(ivar_name); + ConstString ivar_const_str(buffer.c_str()); + + //---------------------------------------------------------------------- + // Try to get the ivar offset address from the symbol table first using + // the name we created above + //---------------------------------------------------------------------- + SymbolContextList sc_list; + Target &target = m_process->GetTarget(); + target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, + eSymbolTypeObjCIVar, sc_list); + + addr_t ivar_offset_address = LLDB_INVALID_ADDRESS; Error error; - return GetTargetRef().GetUtilityFunctionForLanguage(check_function_code, eLanguageTypeObjC, name, error); + SymbolContext ivar_offset_symbol; + if (sc_list.GetSize() == 1 && + sc_list.GetContextAtIndex(0, ivar_offset_symbol)) { + if (ivar_offset_symbol.symbol) + ivar_offset_address = + ivar_offset_symbol.symbol->GetLoadAddress(&target); + } + + //---------------------------------------------------------------------- + // If we didn't get the ivar offset address from the symbol table, fall + // back to getting it from the runtime + //---------------------------------------------------------------------- + if (ivar_offset_address == LLDB_INVALID_ADDRESS) + ivar_offset_address = LookupRuntimeSymbol(ivar_const_str); + + if (ivar_offset_address != LLDB_INVALID_ADDRESS) + ivar_offset = m_process->ReadUnsignedIntegerFromMemory( + ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error); + } + return ivar_offset; } -size_t -AppleObjCRuntimeV2::GetByteOffsetForIvar (CompilerType &parent_ast_type, const char *ivar_name) -{ - uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET; +// tagged pointers are special not-a-real-pointer values that contain both type +// and value information +// this routine attempts to check with as little computational effort as +// possible whether something +// could possibly be a tagged pointer - false positives are possible but false +// negatives shouldn't +bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) { + if (!m_tagged_pointer_vendor_ap) + return false; + return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr); +} - const char *class_name = parent_ast_type.GetConstTypeName().AsCString(); - if (class_name && class_name[0] && ivar_name && ivar_name[0]) - { - //---------------------------------------------------------------------- - // Make the objective C V2 mangled name for the ivar offset from the - // class name and ivar name - //---------------------------------------------------------------------- - std::string buffer("OBJC_IVAR_$_"); - buffer.append (class_name); - buffer.push_back ('.'); - buffer.append (ivar_name); - ConstString ivar_const_str (buffer.c_str()); - - //---------------------------------------------------------------------- - // Try to get the ivar offset address from the symbol table first using - // the name we created above - //---------------------------------------------------------------------- - SymbolContextList sc_list; - Target &target = m_process->GetTarget(); - target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list); - - addr_t ivar_offset_address = LLDB_INVALID_ADDRESS; +class RemoteNXMapTable { +public: + RemoteNXMapTable() + : m_count(0), m_num_buckets_minus_one(0), + m_buckets_ptr(LLDB_INVALID_ADDRESS), m_process(NULL), + m_end_iterator(*this, -1), m_load_addr(LLDB_INVALID_ADDRESS), + m_map_pair_size(0), m_invalid_key(0) {} + + void Dump() { + printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr); + printf("RemoteNXMapTable.m_count = %u\n", m_count); + printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", + m_num_buckets_minus_one); + printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr); + } + + bool ParseHeader(Process *process, lldb::addr_t load_addr) { + m_process = process; + m_load_addr = load_addr; + m_map_pair_size = m_process->GetAddressByteSize() * 2; + m_invalid_key = + m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX; + Error err; - Error error; - SymbolContext ivar_offset_symbol; - if (sc_list.GetSize() == 1 && sc_list.GetContextAtIndex(0, ivar_offset_symbol)) - { - if (ivar_offset_symbol.symbol) - ivar_offset_address = ivar_offset_symbol.symbol->GetLoadAddress (&target); - } + // This currently holds true for all platforms we support, but we might + // need to change this to use get the actually byte size of "unsigned" + // from the target AST... + const uint32_t unsigned_byte_size = sizeof(uint32_t); + // Skip the prototype as we don't need it (const struct +NXMapTablePrototype + // *prototype) - //---------------------------------------------------------------------- - // If we didn't get the ivar offset address from the symbol table, fall - // back to getting it from the runtime - //---------------------------------------------------------------------- - if (ivar_offset_address == LLDB_INVALID_ADDRESS) - ivar_offset_address = LookupRuntimeSymbol(ivar_const_str); - - if (ivar_offset_address != LLDB_INVALID_ADDRESS) - ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address, - 4, - LLDB_INVALID_IVAR_OFFSET, - error); - } - return ivar_offset; -} + bool success = true; + if (load_addr == LLDB_INVALID_ADDRESS) + success = false; + else { + lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize(); -// tagged pointers are special not-a-real-pointer values that contain both type and value information -// this routine attempts to check with as little computational effort as possible whether something -// could possibly be a tagged pointer - false positives are possible but false negatives shouldn't -bool -AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) -{ - if (!m_tagged_pointer_vendor_ap) - return false; - return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr); -} + // unsigned count; + m_count = m_process->ReadUnsignedIntegerFromMemory( + cursor, unsigned_byte_size, 0, err); + if (m_count) { + cursor += unsigned_byte_size; -class RemoteNXMapTable -{ -public: - RemoteNXMapTable () : - m_count (0), - m_num_buckets_minus_one (0), - m_buckets_ptr (LLDB_INVALID_ADDRESS), - m_process (NULL), - m_end_iterator (*this, -1), - m_load_addr (LLDB_INVALID_ADDRESS), - m_map_pair_size (0), - m_invalid_key (0) - { - } - - void - Dump () - { - printf ("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr); - printf ("RemoteNXMapTable.m_count = %u\n", m_count); - printf ("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", m_num_buckets_minus_one); - printf ("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr); + // unsigned nbBucketsMinusOne; + m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory( + cursor, unsigned_byte_size, 0, err); + cursor += unsigned_byte_size; + + // void *buckets; + m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err); + + success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS; + } } - - bool - ParseHeader (Process* process, lldb::addr_t load_addr) - { - m_process = process; - m_load_addr = load_addr; - m_map_pair_size = m_process->GetAddressByteSize() * 2; - m_invalid_key = m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX; - Error err; - - // This currently holds true for all platforms we support, but we might - // need to change this to use get the actually byte size of "unsigned" - // from the target AST... - const uint32_t unsigned_byte_size = sizeof(uint32_t); - // Skip the prototype as we don't need it (const struct +NXMapTablePrototype *prototype) - - bool success = true; - if (load_addr == LLDB_INVALID_ADDRESS) - success = false; - else - { - lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize(); - - // unsigned count; - m_count = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err); - if (m_count) - { - cursor += unsigned_byte_size; - - // unsigned nbBucketsMinusOne; - m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err); - cursor += unsigned_byte_size; - - // void *buckets; - m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err); - - success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS; - } - } - - if (!success) - { - m_count = 0; - m_num_buckets_minus_one = 0; - m_buckets_ptr = LLDB_INVALID_ADDRESS; - } - return success; + + if (!success) { + m_count = 0; + m_num_buckets_minus_one = 0; + m_buckets_ptr = LLDB_INVALID_ADDRESS; } - - // const_iterator mimics NXMapState and its code comes from NXInitMapState and NXNextMapState. - typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element; + return success; + } - friend class const_iterator; - class const_iterator - { - public: - const_iterator (RemoteNXMapTable &parent, int index) : m_parent(parent), m_index(index) - { - AdvanceToValidIndex(); - } - - const_iterator (const const_iterator &rhs) : m_parent(rhs.m_parent), m_index(rhs.m_index) - { - // AdvanceToValidIndex() has been called by rhs already. - } - - const_iterator &operator=(const const_iterator &rhs) - { - // AdvanceToValidIndex() has been called by rhs already. - assert (&m_parent == &rhs.m_parent); - m_index = rhs.m_index; - return *this; - } - - bool operator==(const const_iterator &rhs) const - { - if (&m_parent != &rhs.m_parent) - return false; - if (m_index != rhs.m_index) - return false; - - return true; - } - - bool operator!=(const const_iterator &rhs) const - { - return !(operator==(rhs)); - } - - const_iterator &operator++() - { - AdvanceToValidIndex(); - return *this; - } - - const element operator*() const - { - if (m_index == -1) - { - // TODO find a way to make this an error, but not an assert - return element(); - } - - lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; - size_t map_pair_size = m_parent.m_map_pair_size; - lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); - - Error err; - - lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); - if (!err.Success()) - return element(); - lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(pair_ptr + m_parent.m_process->GetAddressByteSize(), err); - if (!err.Success()) - return element(); - - std::string key_string; - - m_parent.m_process->ReadCStringFromMemory(key, key_string, err); - if (!err.Success()) - return element(); - - return element(ConstString(key_string.c_str()), (ObjCLanguageRuntime::ObjCISA)value); - } + // const_iterator mimics NXMapState and its code comes from NXInitMapState and + // NXNextMapState. + typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element; - private: - void AdvanceToValidIndex () - { - if (m_index == -1) - return; - - const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; - const size_t map_pair_size = m_parent.m_map_pair_size; - const lldb::addr_t invalid_key = m_parent.m_invalid_key; - Error err; + friend class const_iterator; + class const_iterator { + public: + const_iterator(RemoteNXMapTable &parent, int index) + : m_parent(parent), m_index(index) { + AdvanceToValidIndex(); + } - while (m_index--) - { - lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); - lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); - - if (!err.Success()) - { - m_index = -1; - return; - } - - if (key != invalid_key) - return; - } - } - RemoteNXMapTable &m_parent; - int m_index; - }; - - const_iterator begin () - { - return const_iterator(*this, m_num_buckets_minus_one + 1); + const_iterator(const const_iterator &rhs) + : m_parent(rhs.m_parent), m_index(rhs.m_index) { + // AdvanceToValidIndex() has been called by rhs already. } - - const_iterator end () - { - return m_end_iterator; + + const_iterator &operator=(const const_iterator &rhs) { + // AdvanceToValidIndex() has been called by rhs already. + assert(&m_parent == &rhs.m_parent); + m_index = rhs.m_index; + return *this; } - - uint32_t - GetCount () const - { - return m_count; + + bool operator==(const const_iterator &rhs) const { + if (&m_parent != &rhs.m_parent) + return false; + if (m_index != rhs.m_index) + return false; + + return true; } - - uint32_t - GetBucketCount () const - { - return m_num_buckets_minus_one; + + bool operator!=(const const_iterator &rhs) const { + return !(operator==(rhs)); } - - lldb::addr_t - GetBucketDataPointer () const - { - return m_buckets_ptr; + + const_iterator &operator++() { + AdvanceToValidIndex(); + return *this; } - - lldb::addr_t - GetTableLoadAddress() const - { - return m_load_addr; + + const element operator*() const { + if (m_index == -1) { + // TODO find a way to make this an error, but not an assert + return element(); + } + + lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; + size_t map_pair_size = m_parent.m_map_pair_size; + lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); + + Error err; + + lldb::addr_t key = + m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); + if (!err.Success()) + return element(); + lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory( + pair_ptr + m_parent.m_process->GetAddressByteSize(), err); + if (!err.Success()) + return element(); + + std::string key_string; + + m_parent.m_process->ReadCStringFromMemory(key, key_string, err); + if (!err.Success()) + return element(); + + return element(ConstString(key_string.c_str()), + (ObjCLanguageRuntime::ObjCISA)value); + } + + private: + void AdvanceToValidIndex() { + if (m_index == -1) + return; + + const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; + const size_t map_pair_size = m_parent.m_map_pair_size; + const lldb::addr_t invalid_key = m_parent.m_invalid_key; + Error err; + + while (m_index--) { + lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); + lldb::addr_t key = + m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); + + if (!err.Success()) { + m_index = -1; + return; + } + + if (key != invalid_key) + return; + } } + RemoteNXMapTable &m_parent; + int m_index; + }; + + const_iterator begin() { + return const_iterator(*this, m_num_buckets_minus_one + 1); + } + + const_iterator end() { return m_end_iterator; } + + uint32_t GetCount() const { return m_count; } + + uint32_t GetBucketCount() const { return m_num_buckets_minus_one; } + + lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; } + + lldb::addr_t GetTableLoadAddress() const { return m_load_addr; } private: - // contents of _NXMapTable struct - uint32_t m_count; - uint32_t m_num_buckets_minus_one; - lldb::addr_t m_buckets_ptr; - lldb_private::Process *m_process; - const_iterator m_end_iterator; - lldb::addr_t m_load_addr; - size_t m_map_pair_size; - lldb::addr_t m_invalid_key; + // contents of _NXMapTable struct + uint32_t m_count; + uint32_t m_num_buckets_minus_one; + lldb::addr_t m_buckets_ptr; + lldb_private::Process *m_process; + const_iterator m_end_iterator; + lldb::addr_t m_load_addr; + size_t m_map_pair_size; + lldb::addr_t m_invalid_key; }; -AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() : - m_count (0), - m_num_buckets (0), - m_buckets_ptr (0) -{ -} +AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() + : m_count(0), m_num_buckets(0), m_buckets_ptr(0) {} -void -AppleObjCRuntimeV2::HashTableSignature::UpdateSignature (const RemoteNXMapTable &hash_table) -{ - m_count = hash_table.GetCount(); - m_num_buckets = hash_table.GetBucketCount(); - m_buckets_ptr = hash_table.GetBucketDataPointer(); +void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature( + const RemoteNXMapTable &hash_table) { + m_count = hash_table.GetCount(); + m_num_buckets = hash_table.GetBucketCount(); + m_buckets_ptr = hash_table.GetBucketDataPointer(); } -bool -AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate (Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table) -{ - if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer ())) - { - return false; // Failed to parse the header, no need to update anything - } - - // Check with out current signature and return true if the count, - // number of buckets or the hash table address changes. - if (m_count == hash_table.GetCount() && - m_num_buckets == hash_table.GetBucketCount() && - m_buckets_ptr == hash_table.GetBucketDataPointer()) - { - // Hash table hasn't changed - return false; - } - // Hash table data has changed, we need to update - return true; +bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate( + Process *process, AppleObjCRuntimeV2 *runtime, + RemoteNXMapTable &hash_table) { + if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) { + return false; // Failed to parse the header, no need to update anything + } + + // Check with out current signature and return true if the count, + // number of buckets or the hash table address changes. + if (m_count == hash_table.GetCount() && + m_num_buckets == hash_table.GetBucketCount() && + m_buckets_ptr == hash_table.GetBucketDataPointer()) { + // Hash table hasn't changed + return false; + } + // Hash table data has changed, we need to update + return true; } ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::GetClassDescriptorFromISA (ObjCISA isa) -{ - ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp; - if (m_non_pointer_isa_cache_ap.get()) - class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa); - if (!class_descriptor_sp) - class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa); - return class_descriptor_sp; +AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { + ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp; + if (m_non_pointer_isa_cache_ap.get()) + class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa); + if (!class_descriptor_sp) + class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa); + return class_descriptor_sp; } ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj) -{ - ClassDescriptorSP objc_class_sp; - if (valobj.IsBaseClass()) - { - ValueObject *parent = valobj.GetParent(); - // if I am my own parent, bail out of here fast.. - if (parent && parent != &valobj) - { - ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent); - if (parent_descriptor_sp) - return parent_descriptor_sp->GetSuperclass(); - } - return nullptr; - } - // if we get an invalid VO (which might still happen when playing around - // with pointers returned by the expression parser, don't consider this - // a valid ObjC object) - if (valobj.GetCompilerType().IsValid()) - { - addr_t isa_pointer = valobj.GetPointerValue(); - - // tagged pointer - if (IsTaggedPointer(isa_pointer)) - { - return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer); - } - else - { - ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - Error error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) - { - objc_class_sp = GetClassDescriptorFromISA (isa); - if (isa && !objc_class_sp) - { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was not in class descriptor cache 0x%" PRIx64, - isa_pointer, - isa); - } - } - } +AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { + ClassDescriptorSP objc_class_sp; + if (valobj.IsBaseClass()) { + ValueObject *parent = valobj.GetParent(); + // if I am my own parent, bail out of here fast.. + if (parent && parent != &valobj) { + ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent); + if (parent_descriptor_sp) + return parent_descriptor_sp->GetSuperclass(); + } + return nullptr; + } + // if we get an invalid VO (which might still happen when playing around + // with pointers returned by the expression parser, don't consider this + // a valid ObjC object) + if (valobj.GetCompilerType().IsValid()) { + addr_t isa_pointer = valobj.GetPointerValue(); + + // tagged pointer + if (IsTaggedPointer(isa_pointer)) { + return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer); + } else { + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + Error error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa != LLDB_INVALID_ADDRESS) { + objc_class_sp = GetClassDescriptorFromISA(isa); + if (isa && !objc_class_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("0x%" PRIx64 + ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " + "not in class descriptor cache 0x%" PRIx64, + isa_pointer, isa); + } } + } } - return objc_class_sp; + } + return objc_class_sp; } -lldb::addr_t -AppleObjCRuntimeV2::GetISAHashTablePointer () -{ - if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) - { - Process *process = GetProcess(); +lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() { + if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { + Process *process = GetProcess(); - ModuleSP objc_module_sp(GetObjCModule()); - - if (!objc_module_sp) - return LLDB_INVALID_ADDRESS; + ModuleSP objc_module_sp(GetObjCModule()); - static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes"); - - const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_objc_realized_classes, lldb::eSymbolTypeAny); - if (symbol) - { - lldb::addr_t gdb_objc_realized_classes_ptr = symbol->GetLoadAddress(&process->GetTarget()); - - if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) - { - Error error; - m_isa_hash_table_ptr = process->ReadPointerFromMemory(gdb_objc_realized_classes_ptr, error); - } - } + if (!objc_module_sp) + return LLDB_INVALID_ADDRESS; + + static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes"); + + const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( + g_gdb_objc_realized_classes, lldb::eSymbolTypeAny); + if (symbol) { + lldb::addr_t gdb_objc_realized_classes_ptr = + symbol->GetLoadAddress(&process->GetTarget()); + + if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) { + Error error; + m_isa_hash_table_ptr = process->ReadPointerFromMemory( + gdb_objc_realized_classes_ptr, error); + } } - return m_isa_hash_table_ptr; + } + return m_isa_hash_table_ptr; } AppleObjCRuntimeV2::DescriptorMapUpdateResult -AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table) -{ - Process *process = GetProcess(); - - if (process == NULL) - return DescriptorMapUpdateResult::Fail(); - - uint32_t num_class_infos = 0; - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - - ExecutionContext exe_ctx; - - ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); - - if (!thread_sp) - return DescriptorMapUpdateResult::Fail(); - - thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); - - if (!ast) - return DescriptorMapUpdateResult::Fail(); - - Address function_address; - - DiagnosticManager diagnostics; - - const uint32_t addr_size = process->GetAddressByteSize(); +AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( + RemoteNXMapTable &hash_table) { + Process *process = GetProcess(); - Error err; - - // Read the total number of classes from the hash table - const uint32_t num_classes = hash_table.GetCount(); - if (num_classes == 0) - { - if (log) - log->Printf ("No dynamic classes found in gdb_objc_realized_classes."); - return DescriptorMapUpdateResult::Success(0); - } - - // 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_class_info_function = nullptr; + if (process == NULL) + return DescriptorMapUpdateResult::Fail(); - if (!m_get_class_info_code.get()) - { - Error error; - m_get_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_dynamic_class_info_body, - eLanguageTypeObjC, - g_get_dynamic_class_info_name, - error)); - if (error.Fail()) - { - if (log) - log->Printf ("Failed to get Utility Function for implementation lookup: %s", error.AsCString()); - m_get_class_info_code.reset(); - } - else - { - diagnostics.Clear(); + uint32_t num_class_infos = 0; - if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) - { - if (log) - { - log->Printf("Failed to install implementation lookup"); - diagnostics.Dump(log); - } - m_get_class_info_code.reset(); - } - } - if (!m_get_class_info_code.get()) - return DescriptorMapUpdateResult::Fail(); - - // Next make the runner function for our implementation utility function. - Value value; - value.SetValueType (Value::eValueTypeScalar); - value.SetCompilerType (clang_void_pointer_type); - arguments.PushValue (value); - arguments.PushValue (value); - - value.SetValueType (Value::eValueTypeScalar); - value.SetCompilerType (clang_uint32_t_type); - arguments.PushValue (value); - arguments.PushValue (value); - - get_class_info_function = m_get_class_info_code->MakeFunctionCaller(clang_uint32_t_type, - arguments, - thread_sp, - error); - - if (error.Fail()) - { - if (log) - log->Printf("Failed to make function caller for implementation lookup: %s.", error.AsCString()); - return DescriptorMapUpdateResult::Fail(); - } - } - else - { - get_class_info_function = m_get_class_info_code->GetFunctionCaller(); - if (!get_class_info_function) - { - if (log) - { - log->Printf("Failed to get implementation lookup function caller."); - diagnostics.Dump(log); - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - return DescriptorMapUpdateResult::Fail(); - } - arguments = get_class_info_function->GetArgumentValues(); - } + ExecutionContext exe_ctx; - diagnostics.Clear(); + ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); - const uint32_t class_info_byte_size = addr_size + 4; - const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; - lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size, - ePermissionsReadable | ePermissionsWritable, - err); - - if (class_infos_addr == LLDB_INVALID_ADDRESS) - { - if (log) - log->Printf("unable to allocate %" PRIu32 " bytes in process for shared cache read", class_infos_byte_size); - return DescriptorMapUpdateResult::Fail(); - } + if (!thread_sp) + return DescriptorMapUpdateResult::Fail(); - std::lock_guard<std::mutex> guard(m_get_class_info_args_mutex); + thread_sp->CalculateExecutionContext(exe_ctx); + ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); - // Fill in our function argument values - arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress(); - arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; - arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; - arguments.GetValueAtIndex(3)->GetScalar() = (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1); + if (!ast) + return DescriptorMapUpdateResult::Fail(); - - bool success = false; + Address function_address; - diagnostics.Clear(); + DiagnosticManager diagnostics; - // Write our function arguments into the process so we can run our function - if (get_class_info_function->WriteFunctionArguments(exe_ctx, m_get_class_info_args, arguments, diagnostics)) - { - EvaluateExpressionOptions options; - options.SetUnwindOnError(true); - options.SetTryAllThreads(false); - options.SetStopOthers(true); - options.SetIgnoreBreakpoints(true); - options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC); - - Value return_value; - return_value.SetValueType (Value::eValueTypeScalar); - //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); - return_value.SetCompilerType(clang_uint32_t_type); - return_value.GetScalar() = 0; - - diagnostics.Clear(); - - // Run the function - ExpressionResults results = get_class_info_function->ExecuteFunction(exe_ctx, &m_get_class_info_args, options, - diagnostics, return_value); - - if (results == eExpressionCompleted) - { - // The result is the number of ClassInfo structures that were filled in - num_class_infos = return_value.GetScalar().ULong(); - if (log) - log->Printf("Discovered %u ObjC classes\n",num_class_infos); - if (num_class_infos > 0) - { - // Read the ClassInfo structures - DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0); - if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize()) - { - DataExtractor class_infos_data (buffer.GetBytes(), - buffer.GetByteSize(), - process->GetByteOrder(), - addr_size); - ParseClassInfoArray (class_infos_data, num_class_infos); - } - } - success = true; - } - else - { - if (log) - { - log->Printf("Error evaluating our find class name function."); - diagnostics.Dump(log); - } + const uint32_t addr_size = process->GetAddressByteSize(); + + Error err; + + // Read the total number of classes from the hash table + const uint32_t num_classes = hash_table.GetCount(); + if (num_classes == 0) { + if (log) + log->Printf("No dynamic classes found in gdb_objc_realized_classes."); + return DescriptorMapUpdateResult::Success(0); + } + + // 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_class_info_function = nullptr; + + if (!m_get_class_info_code.get()) { + Error error; + m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage( + g_get_dynamic_class_info_body, eLanguageTypeObjC, + g_get_dynamic_class_info_name, error)); + if (error.Fail()) { + if (log) + log->Printf( + "Failed to get Utility Function for implementation lookup: %s", + error.AsCString()); + m_get_class_info_code.reset(); + } else { + diagnostics.Clear(); + + if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) { + if (log) { + log->Printf("Failed to install implementation lookup"); + diagnostics.Dump(log); } + m_get_class_info_code.reset(); + } } - else - { - if (log) - { - log->Printf("Error writing function arguments."); - diagnostics.Dump(log); + if (!m_get_class_info_code.get()) + return DescriptorMapUpdateResult::Fail(); + + // Next make the runner function for our implementation utility function. + Value value; + value.SetValueType(Value::eValueTypeScalar); + value.SetCompilerType(clang_void_pointer_type); + arguments.PushValue(value); + arguments.PushValue(value); + + value.SetValueType(Value::eValueTypeScalar); + value.SetCompilerType(clang_uint32_t_type); + arguments.PushValue(value); + arguments.PushValue(value); + + get_class_info_function = m_get_class_info_code->MakeFunctionCaller( + clang_uint32_t_type, arguments, thread_sp, error); + + if (error.Fail()) { + if (log) + log->Printf( + "Failed to make function caller for implementation lookup: %s.", + error.AsCString()); + return DescriptorMapUpdateResult::Fail(); + } + } else { + get_class_info_function = m_get_class_info_code->GetFunctionCaller(); + if (!get_class_info_function) { + if (log) { + log->Printf("Failed to get implementation lookup function caller."); + diagnostics.Dump(log); + } + + return DescriptorMapUpdateResult::Fail(); + } + arguments = get_class_info_function->GetArgumentValues(); + } + + diagnostics.Clear(); + + const uint32_t class_info_byte_size = addr_size + 4; + const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; + lldb::addr_t class_infos_addr = process->AllocateMemory( + class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err); + + if (class_infos_addr == LLDB_INVALID_ADDRESS) { + if (log) + log->Printf("unable to allocate %" PRIu32 + " bytes in process for shared cache read", + class_infos_byte_size); + return DescriptorMapUpdateResult::Fail(); + } + + std::lock_guard<std::mutex> guard(m_get_class_info_args_mutex); + + // Fill in our function argument values + arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress(); + arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; + arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; + arguments.GetValueAtIndex(3)->GetScalar() = + (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1); + + bool success = false; + + diagnostics.Clear(); + + // Write our function arguments into the process so we can run our function + if (get_class_info_function->WriteFunctionArguments( + exe_ctx, m_get_class_info_args, arguments, diagnostics)) { + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(false); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC); + + Value return_value; + return_value.SetValueType(Value::eValueTypeScalar); + // return_value.SetContext (Value::eContextTypeClangType, + // clang_uint32_t_type); + return_value.SetCompilerType(clang_uint32_t_type); + return_value.GetScalar() = 0; + + diagnostics.Clear(); + + // Run the function + ExpressionResults results = get_class_info_function->ExecuteFunction( + exe_ctx, &m_get_class_info_args, options, diagnostics, return_value); + + if (results == eExpressionCompleted) { + // The result is the number of ClassInfo structures that were filled in + num_class_infos = return_value.GetScalar().ULong(); + if (log) + log->Printf("Discovered %u ObjC classes\n", num_class_infos); + if (num_class_infos > 0) { + // Read the ClassInfo structures + DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); + if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), + buffer.GetByteSize(), + err) == buffer.GetByteSize()) { + DataExtractor class_infos_data(buffer.GetBytes(), + buffer.GetByteSize(), + process->GetByteOrder(), addr_size); + ParseClassInfoArray(class_infos_data, num_class_infos); } + } + success = true; + } else { + if (log) { + log->Printf("Error evaluating our find class name function."); + diagnostics.Dump(log); + } + } + } else { + if (log) { + log->Printf("Error writing function arguments."); + diagnostics.Dump(log); } + } + + // Deallocate the memory we allocated for the ClassInfo array + process->DeallocateMemory(class_infos_addr); - // Deallocate the memory we allocated for the ClassInfo array - process->DeallocateMemory(class_infos_addr); - - return DescriptorMapUpdateResult(success, num_class_infos); + return DescriptorMapUpdateResult(success, num_class_infos); } -uint32_t -AppleObjCRuntimeV2::ParseClassInfoArray (const DataExtractor &data, uint32_t num_class_infos) -{ - // Parses an array of "num_class_infos" packed ClassInfo structures: - // - // struct ClassInfo - // { - // Class isa; - // uint32_t hash; - // } __attribute__((__packed__)); - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - - uint32_t num_parsed = 0; - - // Iterate through all ClassInfo structures - lldb::offset_t offset = 0; - for (uint32_t i=0; i<num_class_infos; ++i) - { - ObjCISA isa = data.GetPointer(&offset); - - if (isa == 0) - { - if (log) - log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info"); - continue; - } - // Check if we already know about this ISA, if we do, the info will - // never change, so we can just skip it. - if (ISAIsCached(isa)) - { - if (log) - log->Printf("AppleObjCRuntimeV2 found cached isa=0x%" PRIx64 ", ignoring this class info", isa); - offset += 4; - } - else - { - // Read the 32 bit hash for the class name - const uint32_t name_hash = data.GetU32(&offset); - ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL)); - AddClass (isa, descriptor_sp, name_hash); - num_parsed++; - if (log) - log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x, name=%s", isa, name_hash,descriptor_sp->GetClassName().AsCString("<unknown>")); - } - } - if (log) - log->Printf("AppleObjCRuntimeV2 parsed %" PRIu32 " class infos", num_parsed); - return num_parsed; +uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, + uint32_t num_class_infos) { + // Parses an array of "num_class_infos" packed ClassInfo structures: + // + // struct ClassInfo + // { + // Class isa; + // uint32_t hash; + // } __attribute__((__packed__)); + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + + uint32_t num_parsed = 0; + + // Iterate through all ClassInfo structures + lldb::offset_t offset = 0; + for (uint32_t i = 0; i < num_class_infos; ++i) { + ObjCISA isa = data.GetPointer(&offset); + + if (isa == 0) { + if (log) + log->Printf( + "AppleObjCRuntimeV2 found NULL isa, ignoring this class info"); + continue; + } + // Check if we already know about this ISA, if we do, the info will + // never change, so we can just skip it. + if (ISAIsCached(isa)) { + if (log) + log->Printf("AppleObjCRuntimeV2 found cached isa=0x%" PRIx64 + ", ignoring this class info", + isa); + offset += 4; + } else { + // Read the 32 bit hash for the class name + const uint32_t name_hash = data.GetU32(&offset); + ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, NULL)); + AddClass(isa, descriptor_sp, name_hash); + num_parsed++; + if (log) + log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 + ", hash=0x%8.8x, name=%s", + isa, name_hash, + descriptor_sp->GetClassName().AsCString("<unknown>")); + } + } + if (log) + log->Printf("AppleObjCRuntimeV2 parsed %" PRIu32 " class infos", + num_parsed); + return num_parsed; } AppleObjCRuntimeV2::DescriptorMapUpdateResult -AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() -{ - Process *process = GetProcess(); - - if (process == NULL) - return DescriptorMapUpdateResult::Fail(); - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - - ExecutionContext exe_ctx; - - ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); - - if (!thread_sp) - return DescriptorMapUpdateResult::Fail(); - - thread_sp->CalculateExecutionContext(exe_ctx); - ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); - - if (!ast) - return DescriptorMapUpdateResult::Fail(); - - Address function_address; - - DiagnosticManager diagnostics; - - const uint32_t addr_size = process->GetAddressByteSize(); +AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { + Process *process = GetProcess(); - Error err; - - uint32_t num_class_infos = 0; - - const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress(); - - if (objc_opt_ptr == LLDB_INVALID_ADDRESS) - return DescriptorMapUpdateResult::Fail(); - - 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.get()) - { - Error error; - m_get_shared_cache_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_shared_cache_class_info_body, - eLanguageTypeObjC, - g_get_shared_cache_class_info_name, - error)); - if (error.Fail()) - { - if (log) - log->Printf ("Failed to get Utility function for implementation lookup: %s.", error.AsCString()); - m_get_shared_cache_class_info_code.reset(); - } - else - { - diagnostics.Clear(); + if (process == NULL) + return DescriptorMapUpdateResult::Fail(); - if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) - { - if (log) - { - log->Printf("Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_get_shared_cache_class_info_code.reset(); - } - } + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - if (!m_get_shared_cache_class_info_code.get()) - return DescriptorMapUpdateResult::Fail(); - - // Next make the function caller for our implementation utility function. - Value value; - value.SetValueType (Value::eValueTypeScalar); - //value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); - value.SetCompilerType (clang_void_pointer_type); - arguments.PushValue (value); - arguments.PushValue (value); - - value.SetValueType (Value::eValueTypeScalar); - //value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); - 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(); - - } - 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(); - } + ExecutionContext exe_ctx; - diagnostics.Clear(); + ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); - const uint32_t class_info_byte_size = addr_size + 4; - const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; - lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size, - ePermissionsReadable | ePermissionsWritable, - err); - - if (class_infos_addr == LLDB_INVALID_ADDRESS) - { - if (log) - log->Printf("unable to allocate %" PRIu32 " bytes in process for shared cache read", class_infos_byte_size); - return DescriptorMapUpdateResult::Fail(); - } + if (!thread_sp) + return DescriptorMapUpdateResult::Fail(); + + thread_sp->CalculateExecutionContext(exe_ctx); + ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); + + if (!ast) + return DescriptorMapUpdateResult::Fail(); + + Address function_address; - std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex); + DiagnosticManager diagnostics; - // Fill in our function argument values - arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; - arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; - arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; - arguments.GetValueAtIndex(3)->GetScalar() = (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1); - + const uint32_t addr_size = process->GetAddressByteSize(); + + Error err; + + uint32_t num_class_infos = 0; + + const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress(); + + if (objc_opt_ptr == LLDB_INVALID_ADDRESS) + return DescriptorMapUpdateResult::Fail(); + + 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.get()) { + Error error; + m_get_shared_cache_class_info_code.reset( + GetTargetRef().GetUtilityFunctionForLanguage( + g_get_shared_cache_class_info_body, eLanguageTypeObjC, + g_get_shared_cache_class_info_name, error)); + if (error.Fail()) { + if (log) + log->Printf( + "Failed to get Utility function for implementation lookup: %s.", + error.AsCString()); + m_get_shared_cache_class_info_code.reset(); + } else { + diagnostics.Clear(); + + if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) { + if (log) { + log->Printf("Failed to install implementation lookup."); + diagnostics.Dump(log); + } + m_get_shared_cache_class_info_code.reset(); + } + } - bool success = false; + if (!m_get_shared_cache_class_info_code.get()) + return DescriptorMapUpdateResult::Fail(); + + // Next make the function caller for our implementation utility function. + Value value; + value.SetValueType(Value::eValueTypeScalar); + // value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); + value.SetCompilerType(clang_void_pointer_type); + arguments.PushValue(value); + arguments.PushValue(value); + + value.SetValueType(Value::eValueTypeScalar); + // value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); + 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(); + + } 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(); + } + + diagnostics.Clear(); + + const uint32_t class_info_byte_size = addr_size + 4; + const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; + lldb::addr_t class_infos_addr = process->AllocateMemory( + class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err); + + if (class_infos_addr == LLDB_INVALID_ADDRESS) { + if (log) + log->Printf("unable to allocate %" PRIu32 + " bytes in process for shared cache read", + class_infos_byte_size); + return DescriptorMapUpdateResult::Fail(); + } + + std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex); + + // Fill in our function argument values + arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; + arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; + arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; + arguments.GetValueAtIndex(3)->GetScalar() = + (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1); + + bool success = false; + + diagnostics.Clear(); + + // 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)) { + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetTryAllThreads(false); + options.SetStopOthers(true); + options.SetIgnoreBreakpoints(true); + options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC); + + Value return_value; + return_value.SetValueType(Value::eValueTypeScalar); + // return_value.SetContext (Value::eContextTypeClangType, + // clang_uint32_t_type); + return_value.SetCompilerType(clang_uint32_t_type); + return_value.GetScalar() = 0; diagnostics.Clear(); - // 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)) - { - EvaluateExpressionOptions options; - options.SetUnwindOnError(true); - options.SetTryAllThreads(false); - options.SetStopOthers(true); - options.SetIgnoreBreakpoints(true); - options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC); - - Value return_value; - return_value.SetValueType (Value::eValueTypeScalar); - //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); - return_value.SetCompilerType(clang_uint32_t_type); - return_value.GetScalar() = 0; - - diagnostics.Clear(); - - // 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); - - if (results == eExpressionCompleted) - { - // The result is the number of ClassInfo structures that were filled in - num_class_infos = return_value.GetScalar().ULong(); - if (log) - log->Printf("Discovered %u ObjC classes in shared cache\n",num_class_infos); + // 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); + + if (results == eExpressionCompleted) { + // The result is the number of ClassInfo structures that were filled in + num_class_infos = return_value.GetScalar().ULong(); + if (log) + log->Printf("Discovered %u ObjC classes in shared cache\n", + num_class_infos); #ifdef LLDB_CONFIGURATION_DEBUG - assert (num_class_infos <= num_classes); + assert(num_class_infos <= num_classes); #endif - if (num_class_infos > 0) - { - if (num_class_infos > num_classes) - { - num_class_infos = num_classes; - - success = false; - } - else - { - success = true; - } - - // Read the ClassInfo structures - DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0); - if (process->ReadMemory(class_infos_addr, - buffer.GetBytes(), - buffer.GetByteSize(), - err) == buffer.GetByteSize()) - { - DataExtractor class_infos_data (buffer.GetBytes(), - buffer.GetByteSize(), - process->GetByteOrder(), - addr_size); + if (num_class_infos > 0) { + if (num_class_infos > num_classes) { + num_class_infos = num_classes; - ParseClassInfoArray (class_infos_data, num_class_infos); - } - } - else - { - success = true; - } - } - else - { - if (log) - { - log->Printf("Error evaluating our find class name function."); - diagnostics.Dump(log); - } + success = false; + } else { + success = true; } - } - else - { - if (log) - { - log->Printf("Error writing function arguments."); - diagnostics.Dump(log); + + // Read the ClassInfo structures + DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); + if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), + buffer.GetByteSize(), + err) == buffer.GetByteSize()) { + DataExtractor class_infos_data(buffer.GetBytes(), + buffer.GetByteSize(), + process->GetByteOrder(), addr_size); + + ParseClassInfoArray(class_infos_data, num_class_infos); } + } else { + success = true; + } + } else { + if (log) { + log->Printf("Error evaluating our find class name function."); + diagnostics.Dump(log); + } + } + } else { + if (log) { + log->Printf("Error writing function arguments."); + diagnostics.Dump(log); + } + } + + // Deallocate the memory we allocated for the ClassInfo array + process->DeallocateMemory(class_infos_addr); + + return DescriptorMapUpdateResult(success, num_class_infos); +} + +bool AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory( + RemoteNXMapTable &hash_table) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + + Process *process = GetProcess(); + + if (process == NULL) + return false; + + uint32_t num_map_table_isas = 0; + + ModuleSP objc_module_sp(GetObjCModule()); + + if (objc_module_sp) { + for (RemoteNXMapTable::element elt : hash_table) { + ++num_map_table_isas; + + if (ISAIsCached(elt.second)) + continue; + + ClassDescriptorSP descriptor_sp = ClassDescriptorSP( + new ClassDescriptorV2(*this, elt.second, elt.first.AsCString())); + + if (log && log->GetVerbose()) + log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 + " (%s) from dynamic table to isa->descriptor cache", + elt.second, elt.first.AsCString()); + + AddClass(elt.second, descriptor_sp, elt.first.AsCString()); } + } - // Deallocate the memory we allocated for the ClassInfo array - process->DeallocateMemory(class_infos_addr); - - return DescriptorMapUpdateResult(success, num_class_infos); + return num_map_table_isas > 0; } -bool -AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - - Process *process = GetProcess(); +lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() { + Process *process = GetProcess(); - if (process == NULL) - return false; - - uint32_t num_map_table_isas = 0; - + if (process) { ModuleSP objc_module_sp(GetObjCModule()); - - if (objc_module_sp) - { - for (RemoteNXMapTable::element elt : hash_table) - { - ++num_map_table_isas; - - if (ISAIsCached(elt.second)) - continue; - - ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString())); - - if (log && log->GetVerbose()) - log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString()); - - AddClass (elt.second, descriptor_sp, elt.first.AsCString()); - } - } - - return num_map_table_isas > 0; -} -lldb::addr_t -AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() -{ - Process *process = GetProcess(); - - if (process) - { - ModuleSP objc_module_sp(GetObjCModule()); - - if (objc_module_sp) - { - ObjectFile *objc_object = objc_module_sp->GetObjectFile(); - - if (objc_object) - { - SectionList *section_list = objc_module_sp->GetSectionList(); - - if (section_list) - { - SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT"))); - - if (text_segment_sp) - { - SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro"))); - - if (objc_opt_section_sp) - { - return objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget()); - } - } - } - } - } - } - return LLDB_INVALID_ADDRESS; -} + if (objc_module_sp) { + ObjectFile *objc_object = objc_module_sp->GetObjectFile(); -void -AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + if (objc_object) { + SectionList *section_list = objc_module_sp->GetSectionList(); - Timer scoped_timer (LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION); - - // Else we need to check with our process to see when the map was updated. - Process *process = GetProcess(); + if (section_list) { + SectionSP text_segment_sp( + section_list->FindSectionByName(ConstString("__TEXT"))); - if (process) - { - RemoteNXMapTable hash_table; - - // Update the process stop ID that indicates the last time we updated the - // map, whether it was successful or not. - m_isa_to_descriptor_stop_id = process->GetStopID(); - - if (!m_hash_signature.NeedsUpdate(process, this, hash_table)) - return; - - m_hash_signature.UpdateSignature (hash_table); - - // Grab the dynamically loaded objc classes from the hash table in memory - DescriptorMapUpdateResult dynamic_update_result = UpdateISAToDescriptorMapDynamic(hash_table); - - // Now get the objc classes that are baked into the Objective C runtime - // in the shared cache, but only once per process as this data never - // changes - if (!m_loaded_objc_opt) - { - // it is legitimately possible for the shared cache to be empty - in that case, the dynamic hash table - // will contain all the class information we need; the situation we're trying to detect is one where - // we aren't seeing class information from the runtime - in order to detect that vs. just the shared cache - // being empty or sparsely populated, we set an arbitrary (very low) threshold for the number of classes - // that we want to see in a "good" scenario - anything below that is suspicious (Foundation alone has thousands - // of classes) - const uint32_t num_classes_to_warn_at = 500; - - DescriptorMapUpdateResult shared_cache_update_result = UpdateISAToDescriptorMapSharedCache(); - - if (log) - log->Printf("attempted to read objc class data - results: [dynamic_update]: ran: %s, count: %" PRIu32 " [shared_cache_update]: ran: %s, count: %" PRIu32, - dynamic_update_result.m_update_ran ? "yes" : "no", - dynamic_update_result.m_num_found, - shared_cache_update_result.m_update_ran ? "yes" : "no", - shared_cache_update_result.m_num_found); - - // warn if: - // - we could not run either expression - // - we found fewer than num_classes_to_warn_at classes total - if ((false == shared_cache_update_result.m_update_ran) || (false == dynamic_update_result.m_update_ran)) - WarnIfNoClassesCached(SharedCacheWarningReason::eExpressionExecutionFailure); - else if (dynamic_update_result.m_num_found + shared_cache_update_result.m_num_found < num_classes_to_warn_at) - WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead); - else - m_loaded_objc_opt = true; + if (text_segment_sp) { + SectionSP objc_opt_section_sp( + text_segment_sp->GetChildren().FindSectionByName( + ConstString("__objc_opt_ro"))); + + if (objc_opt_section_sp) { + return objc_opt_section_sp->GetLoadBaseAddress( + &process->GetTarget()); + } + } } + } } - else - { - m_isa_to_descriptor_stop_id = UINT32_MAX; - } + } + return LLDB_INVALID_ADDRESS; } -static bool -DoesProcessHaveSharedCache (Process& process) -{ - PlatformSP platform_sp = process.GetTarget().GetPlatform(); - if (!platform_sp) - return true; // this should not happen - - ConstString platform_plugin_name = platform_sp->GetPluginName(); - if (platform_plugin_name) - { - llvm::StringRef platform_plugin_name_sr = platform_plugin_name.GetStringRef(); - if (platform_plugin_name_sr.endswith("-simulator")) - return false; - } - - return true; +void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + + Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION); + + // Else we need to check with our process to see when the map was updated. + Process *process = GetProcess(); + + if (process) { + RemoteNXMapTable hash_table; + + // Update the process stop ID that indicates the last time we updated the + // map, whether it was successful or not. + m_isa_to_descriptor_stop_id = process->GetStopID(); + + if (!m_hash_signature.NeedsUpdate(process, this, hash_table)) + return; + + m_hash_signature.UpdateSignature(hash_table); + + // Grab the dynamically loaded objc classes from the hash table in memory + DescriptorMapUpdateResult dynamic_update_result = + UpdateISAToDescriptorMapDynamic(hash_table); + + // Now get the objc classes that are baked into the Objective C runtime + // in the shared cache, but only once per process as this data never + // changes + if (!m_loaded_objc_opt) { + // it is legitimately possible for the shared cache to be empty - in that + // case, the dynamic hash table + // will contain all the class information we need; the situation we're + // trying to detect is one where + // we aren't seeing class information from the runtime - in order to + // detect that vs. just the shared cache + // being empty or sparsely populated, we set an arbitrary (very low) + // threshold for the number of classes + // that we want to see in a "good" scenario - anything below that is + // suspicious (Foundation alone has thousands + // of classes) + const uint32_t num_classes_to_warn_at = 500; + + DescriptorMapUpdateResult shared_cache_update_result = + UpdateISAToDescriptorMapSharedCache(); + + if (log) + log->Printf("attempted to read objc class data - results: " + "[dynamic_update]: ran: %s, count: %" PRIu32 + " [shared_cache_update]: ran: %s, count: %" PRIu32, + dynamic_update_result.m_update_ran ? "yes" : "no", + dynamic_update_result.m_num_found, + shared_cache_update_result.m_update_ran ? "yes" : "no", + shared_cache_update_result.m_num_found); + + // warn if: + // - we could not run either expression + // - we found fewer than num_classes_to_warn_at classes total + if ((false == shared_cache_update_result.m_update_ran) || + (false == dynamic_update_result.m_update_ran)) + WarnIfNoClassesCached( + SharedCacheWarningReason::eExpressionExecutionFailure); + else if (dynamic_update_result.m_num_found + + shared_cache_update_result.m_num_found < + num_classes_to_warn_at) + WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead); + else + m_loaded_objc_opt = true; + } + } else { + m_isa_to_descriptor_stop_id = UINT32_MAX; + } } -void -AppleObjCRuntimeV2::WarnIfNoClassesCached (SharedCacheWarningReason reason) -{ - if (m_noclasses_warning_emitted) - return; +static bool DoesProcessHaveSharedCache(Process &process) { + PlatformSP platform_sp = process.GetTarget().GetPlatform(); + if (!platform_sp) + return true; // this should not happen - if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) - { - // Simulators do not have the objc_opt_ro class table so don't actually complain to the user - m_noclasses_warning_emitted = true; - return; - } + ConstString platform_plugin_name = platform_sp->GetPluginName(); + if (platform_plugin_name) { + llvm::StringRef platform_plugin_name_sr = + platform_plugin_name.GetStringRef(); + if (platform_plugin_name_sr.endswith("-simulator")) + return false; + } - Debugger &debugger(GetProcess()->GetTarget().GetDebugger()); - if (auto stream = debugger.GetAsyncOutputStream()) - { - switch (reason) - { - case SharedCacheWarningReason::eNotEnoughClassesRead: - stream->PutCString("warning: could not find Objective-C class data in the process. This may reduce the quality of type information available.\n"); - m_noclasses_warning_emitted = true; - break; - case SharedCacheWarningReason::eExpressionExecutionFailure: - stream->PutCString("warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.\n"); - m_noclasses_warning_emitted = true; - break; - default: - break; - } - } + return true; +} + +void AppleObjCRuntimeV2::WarnIfNoClassesCached( + SharedCacheWarningReason reason) { + if (m_noclasses_warning_emitted) + return; + + if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) { + // Simulators do not have the objc_opt_ro class table so don't actually + // complain to the user + m_noclasses_warning_emitted = true; + return; + } + + Debugger &debugger(GetProcess()->GetTarget().GetDebugger()); + if (auto stream = debugger.GetAsyncOutputStream()) { + switch (reason) { + case SharedCacheWarningReason::eNotEnoughClassesRead: + stream->PutCString("warning: could not find Objective-C class data in " + "the process. This may reduce the quality of type " + "information available.\n"); + m_noclasses_warning_emitted = true; + break; + case SharedCacheWarningReason::eExpressionExecutionFailure: + stream->PutCString("warning: could not execute support code to read " + "Objective-C class data in the process. This may " + "reduce the quality of type information available.\n"); + m_noclasses_warning_emitted = true; + break; + default: + break; + } + } } // TODO: should we have a transparent_kvo parameter here to say if we // want to replace the KVO swizzled class with the actual user-level type? ConstString -AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) -{ - if (isa == g_objc_Tagged_ISA) - { - static const ConstString g_objc_tagged_isa_name ("_lldb_Tagged_ObjC_ISA"); - return g_objc_tagged_isa_name; - } - if (isa == g_objc_Tagged_ISA_NSAtom) - { - static const ConstString g_objc_tagged_isa_nsatom_name ("NSAtom"); - return g_objc_tagged_isa_nsatom_name; - } - if (isa == g_objc_Tagged_ISA_NSNumber) - { - static const ConstString g_objc_tagged_isa_nsnumber_name ("NSNumber"); - return g_objc_tagged_isa_nsnumber_name; - } - if (isa == g_objc_Tagged_ISA_NSDateTS) - { - static const ConstString g_objc_tagged_isa_nsdatets_name ("NSDateTS"); - return g_objc_tagged_isa_nsdatets_name; - } - if (isa == g_objc_Tagged_ISA_NSManagedObject) - { - static const ConstString g_objc_tagged_isa_nsmanagedobject_name ("NSManagedObject"); - return g_objc_tagged_isa_nsmanagedobject_name; - } - if (isa == g_objc_Tagged_ISA_NSDate) - { - static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate"); - return g_objc_tagged_isa_nsdate_name; - } - return ObjCLanguageRuntime::GetActualTypeName(isa); +AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { + if (isa == g_objc_Tagged_ISA) { + static const ConstString g_objc_tagged_isa_name("_lldb_Tagged_ObjC_ISA"); + return g_objc_tagged_isa_name; + } + if (isa == g_objc_Tagged_ISA_NSAtom) { + static const ConstString g_objc_tagged_isa_nsatom_name("NSAtom"); + return g_objc_tagged_isa_nsatom_name; + } + if (isa == g_objc_Tagged_ISA_NSNumber) { + static const ConstString g_objc_tagged_isa_nsnumber_name("NSNumber"); + return g_objc_tagged_isa_nsnumber_name; + } + if (isa == g_objc_Tagged_ISA_NSDateTS) { + static const ConstString g_objc_tagged_isa_nsdatets_name("NSDateTS"); + return g_objc_tagged_isa_nsdatets_name; + } + if (isa == g_objc_Tagged_ISA_NSManagedObject) { + static const ConstString g_objc_tagged_isa_nsmanagedobject_name( + "NSManagedObject"); + return g_objc_tagged_isa_nsmanagedobject_name; + } + if (isa == g_objc_Tagged_ISA_NSDate) { + static const ConstString g_objc_tagged_isa_nsdate_name("NSDate"); + return g_objc_tagged_isa_nsdate_name; + } + return ObjCLanguageRuntime::GetActualTypeName(isa); } -DeclVendor * -AppleObjCRuntimeV2::GetDeclVendor() -{ - if (!m_decl_vendor_ap.get()) - m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this)); - - return m_decl_vendor_ap.get(); +DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() { + if (!m_decl_vendor_ap.get()) + m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this)); + + return m_decl_vendor_ap.get(); } -lldb::addr_t -AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name) -{ - lldb::addr_t ret = LLDB_INVALID_ADDRESS; +lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(const ConstString &name) { + lldb::addr_t ret = LLDB_INVALID_ADDRESS; - const char *name_cstr = name.AsCString(); - - if (name_cstr) - { - llvm::StringRef name_strref(name_cstr); - - static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_"); - static const llvm::StringRef class_prefix("OBJC_CLASS_$_"); - - if (name_strref.startswith(ivar_prefix)) - { - llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size()); - std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.'); - - if (class_and_ivar.first.size() && class_and_ivar.second.size()) - { - const ConstString class_name_cs(class_and_ivar.first); - ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs); - - if (descriptor) - { - const ConstString ivar_name_cs(class_and_ivar.second); - const char *ivar_name_cstr = ivar_name_cs.AsCString(); - - auto ivar_func = [&ret, ivar_name_cstr](const char *name, const char *type, lldb::addr_t offset_addr, uint64_t size) -> lldb::addr_t - { - if (!strcmp(name, ivar_name_cstr)) - { - ret = offset_addr; - return true; - } - return false; - }; - - descriptor->Describe(std::function<void (ObjCISA)>(nullptr), - std::function<bool (const char *, const char *)>(nullptr), - std::function<bool (const char *, const char *)>(nullptr), - ivar_func); - } + const char *name_cstr = name.AsCString(); + + if (name_cstr) { + llvm::StringRef name_strref(name_cstr); + + static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_"); + static const llvm::StringRef class_prefix("OBJC_CLASS_$_"); + + if (name_strref.startswith(ivar_prefix)) { + llvm::StringRef ivar_skipped_prefix = + name_strref.substr(ivar_prefix.size()); + std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = + ivar_skipped_prefix.split('.'); + + if (class_and_ivar.first.size() && class_and_ivar.second.size()) { + const ConstString class_name_cs(class_and_ivar.first); + ClassDescriptorSP descriptor = + ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs); + + if (descriptor) { + const ConstString ivar_name_cs(class_and_ivar.second); + const char *ivar_name_cstr = ivar_name_cs.AsCString(); + + auto ivar_func = [&ret, ivar_name_cstr]( + const char *name, const char *type, lldb::addr_t offset_addr, + uint64_t size) -> lldb::addr_t { + if (!strcmp(name, ivar_name_cstr)) { + ret = offset_addr; + return true; } + return false; + }; + + descriptor->Describe( + std::function<void(ObjCISA)>(nullptr), + std::function<bool(const char *, const char *)>(nullptr), + std::function<bool(const char *, const char *)>(nullptr), + ivar_func); } - else if (name_strref.startswith(class_prefix)) - { - llvm::StringRef class_skipped_prefix = name_strref.substr(class_prefix.size()); - const ConstString class_name_cs(class_skipped_prefix); - ClassDescriptorSP descriptor = GetClassDescriptorFromClassName(class_name_cs); - - if (descriptor) - ret = descriptor->GetISA(); - } + } + } else if (name_strref.startswith(class_prefix)) { + llvm::StringRef class_skipped_prefix = + name_strref.substr(class_prefix.size()); + const ConstString class_name_cs(class_skipped_prefix); + ClassDescriptorSP descriptor = + GetClassDescriptorFromClassName(class_name_cs); + + if (descriptor) + ret = descriptor->GetISA(); } - - return ret; + } + + return ret; } -AppleObjCRuntimeV2::NonPointerISACache* -AppleObjCRuntimeV2::NonPointerISACache::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp) -{ - Process* process(runtime.GetProcess()); - - Error error; - - auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_isa_magic_mask"), - objc_module_sp, - error); - if (error.Fail()) - return NULL; +AppleObjCRuntimeV2::NonPointerISACache * +AppleObjCRuntimeV2::NonPointerISACache::CreateInstance( + AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) { + Process *process(runtime.GetProcess()); - auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_isa_magic_value"), - objc_module_sp, - error); - if (error.Fail()) - return NULL; + Error error; - auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_isa_class_mask"), - objc_module_sp, - error); - if (error.Fail()) - return NULL; - - // we might want to have some rules to outlaw these other values (e.g if the mask is zero but the value is non-zero, ...) - - return new NonPointerISACache(runtime, - objc_debug_isa_class_mask, - objc_debug_isa_magic_mask, - objc_debug_isa_magic_value); + auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error); + if (error.Fail()) + return NULL; + + auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_isa_magic_value"), objc_module_sp, + error); + if (error.Fail()) + return NULL; + + auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error); + if (error.Fail()) + return NULL; + + // we might want to have some rules to outlaw these other values (e.g if the + // mask is zero but the value is non-zero, ...) + + return new NonPointerISACache(runtime, objc_debug_isa_class_mask, + objc_debug_isa_magic_mask, + objc_debug_isa_magic_value); } -AppleObjCRuntimeV2::TaggedPointerVendorV2* -AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp) -{ - Process* process(runtime.GetProcess()); - - Error error; - - auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_mask"), - objc_module_sp, - error); +AppleObjCRuntimeV2::TaggedPointerVendorV2 * +AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance( + AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) { + Process *process(runtime.GetProcess()); + + Error error; + + auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp, + error); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_slot_shift"), + objc_module_sp, error, true, 4); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_slot_mask"), + objc_module_sp, error, true, 4); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_payload_lshift"), + objc_module_sp, error, true, 4); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_payload_rshift"), + objc_module_sp, error, true, 4); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp, + error, false); + if (error.Fail()) + return new TaggedPointerVendorLegacy(runtime); + + // try to detect the "extended tagged pointer" variables - if any are missing, + // use the non-extended vendor + do { + auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_mask"), + objc_module_sp, error); if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); - - auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_slot_shift"), - objc_module_sp, - error, - true, - 4); - if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); - - auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_slot_mask"), - objc_module_sp, - error, - true, - 4); + break; + + auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_slot_shift"), + objc_module_sp, error, true, 4); if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); - - auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_payload_lshift"), - objc_module_sp, - error, - true, - 4); + break; + + auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_slot_mask"), + objc_module_sp, error, true, 4); if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); - - auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_payload_rshift"), - objc_module_sp, - error, - true, - 4); + break; + + auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_classes"), + objc_module_sp, error, false); if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); - - auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_classes"), - objc_module_sp, - error, - false); + break; + + auto objc_debug_taggedpointer_ext_payload_lshift = + ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"), + objc_module_sp, error, true, 4); if (error.Fail()) - return new TaggedPointerVendorLegacy(runtime); + break; - // try to detect the "extended tagged pointer" variables - if any are missing, use the non-extended vendor - do - { - auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_mask"), - objc_module_sp, - error); - if (error.Fail()) - break; - - auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_slot_shift"), - objc_module_sp, - error, - true, - 4); - if (error.Fail()) - break; - - auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_slot_mask"), - objc_module_sp, - error, - true, - 4); - if (error.Fail()) - break; - - auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_classes"), - objc_module_sp, - error, - false); - if (error.Fail()) - break; - - auto objc_debug_taggedpointer_ext_payload_lshift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_payload_lshift"), - objc_module_sp, - error, - true, - 4); - if (error.Fail()) - break; - - auto objc_debug_taggedpointer_ext_payload_rshift = ExtractRuntimeGlobalSymbol(process, - ConstString("objc_debug_taggedpointer_ext_payload_rshift"), - objc_module_sp, - error, - true, - 4); - if (error.Fail()) - break; - - return new TaggedPointerVendorExtended(runtime, - objc_debug_taggedpointer_mask, - objc_debug_taggedpointer_ext_mask, - objc_debug_taggedpointer_slot_shift, - objc_debug_taggedpointer_ext_slot_shift, - objc_debug_taggedpointer_slot_mask, - objc_debug_taggedpointer_ext_slot_mask, - objc_debug_taggedpointer_payload_lshift, - objc_debug_taggedpointer_payload_rshift, - objc_debug_taggedpointer_ext_payload_lshift, - objc_debug_taggedpointer_ext_payload_rshift, - objc_debug_taggedpointer_classes, - objc_debug_taggedpointer_ext_classes); - } while(false); - - // we might want to have some rules to outlaw these values (e.g if the table's address is zero) - - return new TaggedPointerVendorRuntimeAssisted(runtime, - objc_debug_taggedpointer_mask, - objc_debug_taggedpointer_slot_shift, - objc_debug_taggedpointer_slot_mask, - objc_debug_taggedpointer_payload_lshift, - objc_debug_taggedpointer_payload_rshift, - objc_debug_taggedpointer_classes); + auto objc_debug_taggedpointer_ext_payload_rshift = + ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"), + objc_module_sp, error, true, 4); + if (error.Fail()) + break; + + return new TaggedPointerVendorExtended( + runtime, objc_debug_taggedpointer_mask, + objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift, + objc_debug_taggedpointer_ext_slot_shift, + objc_debug_taggedpointer_slot_mask, + objc_debug_taggedpointer_ext_slot_mask, + objc_debug_taggedpointer_payload_lshift, + objc_debug_taggedpointer_payload_rshift, + objc_debug_taggedpointer_ext_payload_lshift, + objc_debug_taggedpointer_ext_payload_rshift, + objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes); + } while (false); + + // we might want to have some rules to outlaw these values (e.g if the table's + // address is zero) + + return new TaggedPointerVendorRuntimeAssisted( + runtime, objc_debug_taggedpointer_mask, + objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask, + objc_debug_taggedpointer_payload_lshift, + objc_debug_taggedpointer_payload_rshift, + objc_debug_taggedpointer_classes); } -bool -AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer (lldb::addr_t ptr) -{ - return (ptr & 1); +bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer( + lldb::addr_t ptr) { + return (ptr & 1); } ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor (lldb::addr_t ptr) -{ - if (!IsPossibleTaggedPointer(ptr)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - uint32_t foundation_version = m_runtime.GetFoundationVersion(); - - if (foundation_version == LLDB_INVALID_MODULE_VERSION) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - uint64_t class_bits = (ptr & 0xE) >> 1; - ConstString name; - - // TODO: make a table - if (foundation_version >= 900) - { - switch (class_bits) - { - case 0: - name = ConstString("NSAtom"); - break; - case 3: - name = ConstString("NSNumber"); - break; - case 4: - name = ConstString("NSDateTS"); - break; - case 5: - name = ConstString("NSManagedObject"); - break; - case 6: - name = ConstString("NSDate"); - break; - default: - return ObjCLanguageRuntime::ClassDescriptorSP(); - } - } - else - { - switch (class_bits) - { - case 1: - name = ConstString("NSNumber"); - break; - case 5: - name = ConstString("NSManagedObject"); - break; - case 6: - name = ConstString("NSDate"); - break; - case 7: - name = ConstString("NSDateTS"); - break; - default: - return ObjCLanguageRuntime::ClassDescriptorSP(); - } - } - return ClassDescriptorSP(new ClassDescriptorV2Tagged(name,ptr)); +AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor( + lldb::addr_t ptr) { + if (!IsPossibleTaggedPointer(ptr)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + uint32_t foundation_version = m_runtime.GetFoundationVersion(); + + if (foundation_version == LLDB_INVALID_MODULE_VERSION) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + uint64_t class_bits = (ptr & 0xE) >> 1; + ConstString name; + + // TODO: make a table + if (foundation_version >= 900) { + switch (class_bits) { + case 0: + name = ConstString("NSAtom"); + break; + case 3: + name = ConstString("NSNumber"); + break; + case 4: + name = ConstString("NSDateTS"); + break; + case 5: + name = ConstString("NSManagedObject"); + break; + case 6: + name = ConstString("NSDate"); + break; + default: + return ObjCLanguageRuntime::ClassDescriptorSP(); + } + } else { + switch (class_bits) { + case 1: + name = ConstString("NSNumber"); + break; + case 5: + name = ConstString("NSManagedObject"); + break; + case 6: + name = ConstString("NSDate"); + break; + case 7: + name = ConstString("NSDateTS"); + break; + default: + return ObjCLanguageRuntime::ClassDescriptorSP(); + } + } + return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, ptr)); } -AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_taggedpointer_mask, - uint32_t objc_debug_taggedpointer_slot_shift, - uint32_t objc_debug_taggedpointer_slot_mask, - uint32_t objc_debug_taggedpointer_payload_lshift, - uint32_t objc_debug_taggedpointer_payload_rshift, - lldb::addr_t objc_debug_taggedpointer_classes) : -TaggedPointerVendorV2(runtime), -m_cache(), -m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask), -m_objc_debug_taggedpointer_slot_shift(objc_debug_taggedpointer_slot_shift), -m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask), -m_objc_debug_taggedpointer_payload_lshift(objc_debug_taggedpointer_payload_lshift), -m_objc_debug_taggedpointer_payload_rshift(objc_debug_taggedpointer_payload_rshift), -m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) -{ -} - -bool -AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::IsPossibleTaggedPointer (lldb::addr_t ptr) -{ - return (ptr & m_objc_debug_taggedpointer_mask) != 0; +AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted:: + TaggedPointerVendorRuntimeAssisted( + AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, + uint32_t objc_debug_taggedpointer_slot_shift, + uint32_t objc_debug_taggedpointer_slot_mask, + uint32_t objc_debug_taggedpointer_payload_lshift, + uint32_t objc_debug_taggedpointer_payload_rshift, + lldb::addr_t objc_debug_taggedpointer_classes) + : TaggedPointerVendorV2(runtime), m_cache(), + m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask), + m_objc_debug_taggedpointer_slot_shift( + objc_debug_taggedpointer_slot_shift), + m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask), + m_objc_debug_taggedpointer_payload_lshift( + objc_debug_taggedpointer_payload_lshift), + m_objc_debug_taggedpointer_payload_rshift( + objc_debug_taggedpointer_payload_rshift), + m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {} + +bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted:: + IsPossibleTaggedPointer(lldb::addr_t ptr) { + return (ptr & m_objc_debug_taggedpointer_mask) != 0; } ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor (lldb::addr_t ptr) -{ - ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; - - if (!IsPossibleTaggedPointer(ptr)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & m_objc_debug_taggedpointer_slot_mask; - - CacheIterator iterator = m_cache.find(slot), - end = m_cache.end(); - if (iterator != end) - { - actual_class_descriptor_sp = iterator->second; - } - else - { - Process* process(m_runtime.GetProcess()); - uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_classes; - Error error; - uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); - if (error.Fail() || slot_data == 0 || slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) - return nullptr; - actual_class_descriptor_sp = m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); - if (!actual_class_descriptor_sp) - return ObjCLanguageRuntime::ClassDescriptorSP(); - m_cache[slot] = actual_class_descriptor_sp; - } - - data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift); - - return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload)); +AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( + lldb::addr_t ptr) { + ClassDescriptorSP actual_class_descriptor_sp; + uint64_t data_payload; + + if (!IsPossibleTaggedPointer(ptr)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & + m_objc_debug_taggedpointer_slot_mask; + + CacheIterator iterator = m_cache.find(slot), end = m_cache.end(); + if (iterator != end) { + actual_class_descriptor_sp = iterator->second; + } else { + Process *process(m_runtime.GetProcess()); + uintptr_t slot_ptr = slot * process->GetAddressByteSize() + + m_objc_debug_taggedpointer_classes; + Error error; + uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); + if (error.Fail() || slot_data == 0 || + slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) + return nullptr; + actual_class_descriptor_sp = + m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); + if (!actual_class_descriptor_sp) + return ObjCLanguageRuntime::ClassDescriptorSP(); + m_cache[slot] = actual_class_descriptor_sp; + } + + data_payload = + (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> + m_objc_debug_taggedpointer_payload_rshift); + + return ClassDescriptorSP( + new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); } -AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_taggedpointer_mask, - uint64_t objc_debug_taggedpointer_ext_mask, - uint32_t objc_debug_taggedpointer_slot_shift, - uint32_t objc_debug_taggedpointer_ext_slot_shift, - uint32_t objc_debug_taggedpointer_slot_mask, - uint32_t objc_debug_taggedpointer_ext_slot_mask, - uint32_t objc_debug_taggedpointer_payload_lshift, - uint32_t objc_debug_taggedpointer_payload_rshift, - uint32_t objc_debug_taggedpointer_ext_payload_lshift, - uint32_t objc_debug_taggedpointer_ext_payload_rshift, - lldb::addr_t objc_debug_taggedpointer_classes, - lldb::addr_t objc_debug_taggedpointer_ext_classes) : -TaggedPointerVendorRuntimeAssisted(runtime, - objc_debug_taggedpointer_mask, - objc_debug_taggedpointer_slot_shift, - objc_debug_taggedpointer_slot_mask, - objc_debug_taggedpointer_payload_lshift, - objc_debug_taggedpointer_payload_rshift, - objc_debug_taggedpointer_classes), -m_ext_cache(), -m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask), -m_objc_debug_taggedpointer_ext_slot_shift(objc_debug_taggedpointer_ext_slot_shift), -m_objc_debug_taggedpointer_ext_slot_mask(objc_debug_taggedpointer_ext_slot_mask), -m_objc_debug_taggedpointer_ext_payload_lshift(objc_debug_taggedpointer_ext_payload_lshift), -m_objc_debug_taggedpointer_ext_payload_rshift(objc_debug_taggedpointer_ext_payload_rshift), -m_objc_debug_taggedpointer_ext_classes(objc_debug_taggedpointer_ext_classes) -{ -} +AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended( + AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, + uint64_t objc_debug_taggedpointer_ext_mask, + uint32_t objc_debug_taggedpointer_slot_shift, + uint32_t objc_debug_taggedpointer_ext_slot_shift, + uint32_t objc_debug_taggedpointer_slot_mask, + uint32_t objc_debug_taggedpointer_ext_slot_mask, + uint32_t objc_debug_taggedpointer_payload_lshift, + uint32_t objc_debug_taggedpointer_payload_rshift, + uint32_t objc_debug_taggedpointer_ext_payload_lshift, + uint32_t objc_debug_taggedpointer_ext_payload_rshift, + lldb::addr_t objc_debug_taggedpointer_classes, + lldb::addr_t objc_debug_taggedpointer_ext_classes) + : TaggedPointerVendorRuntimeAssisted( + runtime, objc_debug_taggedpointer_mask, + objc_debug_taggedpointer_slot_shift, + objc_debug_taggedpointer_slot_mask, + objc_debug_taggedpointer_payload_lshift, + objc_debug_taggedpointer_payload_rshift, + objc_debug_taggedpointer_classes), + m_ext_cache(), + m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask), + m_objc_debug_taggedpointer_ext_slot_shift( + objc_debug_taggedpointer_ext_slot_shift), + m_objc_debug_taggedpointer_ext_slot_mask( + objc_debug_taggedpointer_ext_slot_mask), + m_objc_debug_taggedpointer_ext_payload_lshift( + objc_debug_taggedpointer_ext_payload_lshift), + m_objc_debug_taggedpointer_ext_payload_rshift( + objc_debug_taggedpointer_ext_payload_rshift), + m_objc_debug_taggedpointer_ext_classes( + objc_debug_taggedpointer_ext_classes) {} + +bool AppleObjCRuntimeV2::TaggedPointerVendorExtended:: + IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) { + if (!IsPossibleTaggedPointer(ptr)) + return false; -bool -AppleObjCRuntimeV2::TaggedPointerVendorExtended::IsPossibleExtendedTaggedPointer (lldb::addr_t ptr) -{ - if (!IsPossibleTaggedPointer(ptr)) - return false; - - if (m_objc_debug_taggedpointer_ext_mask == 0) - return false; - - return ((ptr & m_objc_debug_taggedpointer_ext_mask) == m_objc_debug_taggedpointer_ext_mask); + if (m_objc_debug_taggedpointer_ext_mask == 0) + return false; + + return ((ptr & m_objc_debug_taggedpointer_ext_mask) == + m_objc_debug_taggedpointer_ext_mask); } ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor (lldb::addr_t ptr) -{ - ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; - - if (!IsPossibleTaggedPointer(ptr)) - return ObjCLanguageRuntime::ClassDescriptorSP(); - - if (!IsPossibleExtendedTaggedPointer(ptr)) - return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr); - - uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) & m_objc_debug_taggedpointer_ext_slot_mask; - - CacheIterator iterator = m_ext_cache.find(slot), - end = m_ext_cache.end(); - if (iterator != end) - { - actual_class_descriptor_sp = iterator->second; - } - else - { - Process* process(m_runtime.GetProcess()); - uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_ext_classes; - Error error; - uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); - if (error.Fail() || slot_data == 0 || slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) - return nullptr; - actual_class_descriptor_sp = m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); - if (!actual_class_descriptor_sp) - return ObjCLanguageRuntime::ClassDescriptorSP(); - m_ext_cache[slot] = actual_class_descriptor_sp; - } - - data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); - - return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload)); +AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( + lldb::addr_t ptr) { + ClassDescriptorSP actual_class_descriptor_sp; + uint64_t data_payload; + + if (!IsPossibleTaggedPointer(ptr)) + return ObjCLanguageRuntime::ClassDescriptorSP(); + + if (!IsPossibleExtendedTaggedPointer(ptr)) + return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr); + + uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) & + m_objc_debug_taggedpointer_ext_slot_mask; + + CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end(); + if (iterator != end) { + actual_class_descriptor_sp = iterator->second; + } else { + Process *process(m_runtime.GetProcess()); + uintptr_t slot_ptr = slot * process->GetAddressByteSize() + + m_objc_debug_taggedpointer_ext_classes; + Error error; + uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); + if (error.Fail() || slot_data == 0 || + slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) + return nullptr; + actual_class_descriptor_sp = + m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); + if (!actual_class_descriptor_sp) + return ObjCLanguageRuntime::ClassDescriptorSP(); + m_ext_cache[slot] = actual_class_descriptor_sp; + } + + data_payload = + (((uint64_t)ptr << m_objc_debug_taggedpointer_ext_payload_lshift) >> + m_objc_debug_taggedpointer_ext_payload_rshift); + + return ClassDescriptorSP( + new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); } -AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_isa_class_mask, - uint64_t objc_debug_isa_magic_mask, - uint64_t objc_debug_isa_magic_value) : -m_runtime(runtime), -m_cache(), -m_objc_debug_isa_class_mask(objc_debug_isa_class_mask), -m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask), -m_objc_debug_isa_magic_value(objc_debug_isa_magic_value) -{ -} +AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache( + AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_isa_class_mask, + uint64_t objc_debug_isa_magic_mask, uint64_t objc_debug_isa_magic_value) + : m_runtime(runtime), m_cache(), + m_objc_debug_isa_class_mask(objc_debug_isa_class_mask), + m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask), + m_objc_debug_isa_magic_value(objc_debug_isa_magic_value) {} ObjCLanguageRuntime::ClassDescriptorSP -AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor (ObjCISA isa) -{ - ObjCISA real_isa = 0; - if (EvaluateNonPointerISA(isa, real_isa) == false) - return ObjCLanguageRuntime::ClassDescriptorSP(); - auto cache_iter = m_cache.find(real_isa); - if (cache_iter != m_cache.end()) - return cache_iter->second; - auto descriptor_sp = m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa); - if (descriptor_sp) // cache only positive matches since the table might grow - m_cache[real_isa] = descriptor_sp; - return descriptor_sp; +AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) { + ObjCISA real_isa = 0; + if (EvaluateNonPointerISA(isa, real_isa) == false) + return ObjCLanguageRuntime::ClassDescriptorSP(); + auto cache_iter = m_cache.find(real_isa); + if (cache_iter != m_cache.end()) + return cache_iter->second; + auto descriptor_sp = + m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa); + if (descriptor_sp) // cache only positive matches since the table might grow + m_cache[real_isa] = descriptor_sp; + return descriptor_sp; } -bool -AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa) -{ - if ( (isa & ~m_objc_debug_isa_class_mask) == 0) - return false; - if ( (isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) - { - ret_isa = isa & m_objc_debug_isa_class_mask; - return (ret_isa != 0); // this is a pointer so 0 is not a valid value - } +bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( + ObjCISA isa, ObjCISA &ret_isa) { + if ((isa & ~m_objc_debug_isa_class_mask) == 0) return false; + if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) { + ret_isa = isa & m_objc_debug_isa_class_mask; + return (ret_isa != 0); // this is a pointer so 0 is not a valid value + } + return false; } -ObjCLanguageRuntime::EncodingToTypeSP -AppleObjCRuntimeV2::GetEncodingToType () -{ - if (!m_encoding_to_type_sp) - m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this)); - return m_encoding_to_type_sp; +ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() { + if (!m_encoding_to_type_sp) + m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this)); + return m_encoding_to_type_sp; } lldb_private::AppleObjCRuntime::ObjCISA -AppleObjCRuntimeV2::GetPointerISA (ObjCISA isa) -{ - ObjCISA ret = isa; - - if (m_non_pointer_isa_cache_ap) - m_non_pointer_isa_cache_ap->EvaluateNonPointerISA(isa, ret); - - return ret; -} +AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) { + ObjCISA ret = isa; -bool -AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded () -{ - if (m_CFBoolean_values) - return true; - - static ConstString g_kCFBooleanFalse("kCFBooleanFalse"); - static ConstString g_kCFBooleanTrue("kCFBooleanTrue"); - - std::function<lldb::addr_t(ConstString)> get_symbol = [this] (ConstString sym) -> lldb::addr_t { - SymbolContextList sc_list; - if (GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(g_kCFBooleanFalse, lldb::eSymbolTypeData, sc_list) == 1) - { - SymbolContext sc; - sc_list.GetContextAtIndex(0, sc); - if (sc.symbol) - return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget()); - } - - return LLDB_INVALID_ADDRESS; - }; - - lldb::addr_t false_addr = get_symbol(g_kCFBooleanFalse); - lldb::addr_t true_addr = get_symbol(g_kCFBooleanTrue); - - return (m_CFBoolean_values = {false_addr,true_addr}).operator bool(); + if (m_non_pointer_isa_cache_ap) + m_non_pointer_isa_cache_ap->EvaluateNonPointerISA(isa, ret); + + return ret; } -void -AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t& cf_true, - lldb::addr_t& cf_false) -{ - if (GetCFBooleanValuesIfNeeded()) - { - cf_true = m_CFBoolean_values->second; - cf_false = m_CFBoolean_values->first; +bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() { + if (m_CFBoolean_values) + return true; + + static ConstString g_kCFBooleanFalse("kCFBooleanFalse"); + static ConstString g_kCFBooleanTrue("kCFBooleanTrue"); + + std::function<lldb::addr_t(ConstString)> get_symbol = + [this](ConstString sym) -> lldb::addr_t { + SymbolContextList sc_list; + if (GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType( + g_kCFBooleanFalse, lldb::eSymbolTypeData, sc_list) == 1) { + SymbolContext sc; + sc_list.GetContextAtIndex(0, sc); + if (sc.symbol) + return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget()); } - else - this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false); + + return LLDB_INVALID_ADDRESS; + }; + + lldb::addr_t false_addr = get_symbol(g_kCFBooleanFalse); + lldb::addr_t true_addr = get_symbol(g_kCFBooleanTrue); + + return (m_CFBoolean_values = {false_addr, true_addr}).operator bool(); +} + +void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, + lldb::addr_t &cf_false) { + if (GetCFBooleanValuesIfNeeded()) { + cf_true = m_CFBoolean_values->second; + cf_false = m_CFBoolean_values->first; + } else + this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 09bb13dd7cd..71807309040 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -18,374 +18,314 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Target/ObjCLanguageRuntime.h" #include "AppleObjCRuntime.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" class RemoteNXMapTable; namespace lldb_private { -class AppleObjCRuntimeV2 : - public AppleObjCRuntime -{ +class AppleObjCRuntimeV2 : public AppleObjCRuntime { public: - ~AppleObjCRuntimeV2() override = default; - - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); - - static void - Terminate(); - - static lldb_private::LanguageRuntime * - CreateInstance (Process *process, lldb::LanguageType language); - - static lldb_private::ConstString - GetPluginNameStatic(); - - static bool classof(const ObjCLanguageRuntime* runtime) - { - switch (runtime->GetRuntimeVersion()) - { - case ObjCRuntimeVersions::eAppleObjC_V2: - return true; - default: - return false; - } - } + ~AppleObjCRuntimeV2() override = default; - // These are generic runtime functions: - bool - GetDynamicTypeAndAddress(ValueObject &in_value, - lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, - Address &address, - Value::ValueType &value_type) override; - - UtilityFunction * - CreateObjectChecker(const char *) override; - - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - ConstString - GetPluginName() override; - - uint32_t - GetPluginVersion() override; - - ObjCRuntimeVersions - GetRuntimeVersion() const override - { - return ObjCRuntimeVersions::eAppleObjC_V2; - } + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); - size_t - GetByteOffsetForIvar(CompilerType &parent_qual_type, const char *ivar_name) override; - - void - UpdateISAToDescriptorMapIfNeeded() override; - - ConstString - GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) override; - - ClassDescriptorSP - GetClassDescriptor(ValueObject& in_value) override; - - ClassDescriptorSP - GetClassDescriptorFromISA(ObjCISA isa) override; - - DeclVendor * - GetDeclVendor() override; - - lldb::addr_t - LookupRuntimeSymbol(const ConstString &name) override; - - EncodingToTypeSP - GetEncodingToType() override; - - TaggedPointerVendor* - GetTaggedPointerVendor() override - { - return m_tagged_pointer_vendor_ap.get(); + static void Terminate(); + + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); + + static lldb_private::ConstString GetPluginNameStatic(); + + static bool classof(const ObjCLanguageRuntime *runtime) { + switch (runtime->GetRuntimeVersion()) { + case ObjCRuntimeVersions::eAppleObjC_V2: + return true; + default: + return false; } - - void - GetValuesForGlobalCFBooleans(lldb::addr_t& cf_true, - lldb::addr_t& cf_false) override; - - // none of these are valid ISAs - we use them to infer the type - // of tagged pointers - if we have something meaningful to say - // we report an actual type - otherwise, we just say tagged - // there is no connection between the values here and the tagged pointers map - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 5; - static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; + } + + // These are generic runtime functions: + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; + + UtilityFunction *CreateObjectChecker(const char *) override; + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + ObjCRuntimeVersions GetRuntimeVersion() const override { + return ObjCRuntimeVersions::eAppleObjC_V2; + } + + size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, + const char *ivar_name) override; + + void UpdateISAToDescriptorMapIfNeeded() override; + + ConstString GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) override; + + ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; + + ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; + + DeclVendor *GetDeclVendor() override; + + lldb::addr_t LookupRuntimeSymbol(const ConstString &name) override; + + EncodingToTypeSP GetEncodingToType() override; + + TaggedPointerVendor *GetTaggedPointerVendor() override { + return m_tagged_pointer_vendor_ap.get(); + } + + void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, + lldb::addr_t &cf_false) override; + + // none of these are valid ISAs - we use them to infer the type + // of tagged pointers - if we have something meaningful to say + // we report an actual type - otherwise, we just say tagged + // there is no connection between the values here and the tagged pointers map + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = + 5; + static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; protected: - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override; + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override; private: - class HashTableSignature - { - public: - HashTableSignature (); - - bool - NeedsUpdate (Process *process, - AppleObjCRuntimeV2 *runtime, + class HashTableSignature { + public: + HashTableSignature(); + + bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table); - - void - UpdateSignature (const RemoteNXMapTable &hash_table); - - protected: - uint32_t m_count; - uint32_t m_num_buckets; - lldb::addr_t m_buckets_ptr; - }; - - class NonPointerISACache - { - public: - static NonPointerISACache* - CreateInstance (AppleObjCRuntimeV2& runtime, - const lldb::ModuleSP& objc_module_sp); - - - ObjCLanguageRuntime::ClassDescriptorSP - GetClassDescriptor (ObjCISA isa); - - private: - NonPointerISACache (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_isa_class_mask, - uint64_t objc_debug_isa_magic_mask, - uint64_t objc_debug_isa_magic_value); - - bool - EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa); - - AppleObjCRuntimeV2& m_runtime; - std::map<ObjCISA,ObjCLanguageRuntime::ClassDescriptorSP> m_cache; - uint64_t m_objc_debug_isa_class_mask; - uint64_t m_objc_debug_isa_magic_mask; - uint64_t m_objc_debug_isa_magic_value; - - friend class AppleObjCRuntimeV2; - - DISALLOW_COPY_AND_ASSIGN(NonPointerISACache); - }; - - class TaggedPointerVendorV2 : public ObjCLanguageRuntime::TaggedPointerVendor - { - public: - ~TaggedPointerVendorV2() override = default; - - static TaggedPointerVendorV2* - CreateInstance (AppleObjCRuntimeV2& runtime, - const lldb::ModuleSP& objc_module_sp); - - protected: - AppleObjCRuntimeV2& m_runtime; - - TaggedPointerVendorV2 (AppleObjCRuntimeV2& runtime) : - TaggedPointerVendor(), - m_runtime(runtime) - { - } - - private: - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorV2); - }; - - class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 - { - public: - bool - IsPossibleTaggedPointer(lldb::addr_t ptr) override; - - ObjCLanguageRuntime::ClassDescriptorSP - GetClassDescriptor(lldb::addr_t ptr) override; - - protected: - TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_taggedpointer_mask, - uint32_t objc_debug_taggedpointer_slot_shift, - uint32_t objc_debug_taggedpointer_slot_mask, - uint32_t objc_debug_taggedpointer_payload_lshift, - uint32_t objc_debug_taggedpointer_payload_rshift, - lldb::addr_t objc_debug_taggedpointer_classes); - - typedef std::map<uint8_t,ObjCLanguageRuntime::ClassDescriptorSP> Cache; - typedef Cache::iterator CacheIterator; - Cache m_cache; - uint64_t m_objc_debug_taggedpointer_mask; - uint32_t m_objc_debug_taggedpointer_slot_shift; - uint32_t m_objc_debug_taggedpointer_slot_mask; - uint32_t m_objc_debug_taggedpointer_payload_lshift; - uint32_t m_objc_debug_taggedpointer_payload_rshift; - lldb::addr_t m_objc_debug_taggedpointer_classes; - - friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted); - }; - - class TaggedPointerVendorExtended : public TaggedPointerVendorRuntimeAssisted - { - public: - ObjCLanguageRuntime::ClassDescriptorSP - GetClassDescriptor(lldb::addr_t ptr) override; - - protected: - TaggedPointerVendorExtended (AppleObjCRuntimeV2& runtime, - uint64_t objc_debug_taggedpointer_mask, - uint64_t objc_debug_taggedpointer_ext_mask, - uint32_t objc_debug_taggedpointer_slot_shift, - uint32_t objc_debug_taggedpointer_ext_slot_shift, - uint32_t objc_debug_taggedpointer_slot_mask, - uint32_t objc_debug_taggedpointer_ext_slot_mask, - uint32_t objc_debug_taggedpointer_payload_lshift, - uint32_t objc_debug_taggedpointer_payload_rshift, - uint32_t objc_debug_taggedpointer_ext_payload_lshift, - uint32_t objc_debug_taggedpointer_ext_payload_rshift, - lldb::addr_t objc_debug_taggedpointer_classes, - lldb::addr_t objc_debug_taggedpointer_ext_classes); - - bool - IsPossibleExtendedTaggedPointer (lldb::addr_t ptr); - - typedef std::map<uint8_t,ObjCLanguageRuntime::ClassDescriptorSP> Cache; - typedef Cache::iterator CacheIterator; - Cache m_ext_cache; - uint64_t m_objc_debug_taggedpointer_ext_mask; - uint32_t m_objc_debug_taggedpointer_ext_slot_shift; - uint32_t m_objc_debug_taggedpointer_ext_slot_mask; - uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; - uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; - lldb::addr_t m_objc_debug_taggedpointer_ext_classes; - - friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorExtended); - }; - - class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 - { - public: - bool - IsPossibleTaggedPointer(lldb::addr_t ptr) override; - - ObjCLanguageRuntime::ClassDescriptorSP - GetClassDescriptor (lldb::addr_t ptr) override; - - protected: - TaggedPointerVendorLegacy (AppleObjCRuntimeV2& runtime) : - TaggedPointerVendorV2 (runtime) - { - } - - friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; - - DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy); - }; - - struct DescriptorMapUpdateResult - { - bool m_update_ran; - uint32_t m_num_found; - - DescriptorMapUpdateResult (bool ran, - uint32_t found) - { - m_update_ran = ran; - m_num_found = found; - } - - static DescriptorMapUpdateResult - Fail () - { - return {false, 0}; - } - - static DescriptorMapUpdateResult - Success (uint32_t found) - { - return {true, found}; - } - }; - - AppleObjCRuntimeV2 (Process *process, - const lldb::ModuleSP &objc_module_sp); - - ObjCISA - GetPointerISA (ObjCISA isa); - - bool - IsTaggedPointer(lldb::addr_t ptr); - - lldb::addr_t - GetISAHashTablePointer (); - - bool - UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table); - - DescriptorMapUpdateResult - UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); - - uint32_t - ParseClassInfoArray (const lldb_private::DataExtractor &data, - uint32_t num_class_infos); - - DescriptorMapUpdateResult - UpdateISAToDescriptorMapSharedCache (); - - enum class SharedCacheWarningReason - { - eExpressionExecutionFailure, - eNotEnoughClassesRead - }; - - void - WarnIfNoClassesCached (SharedCacheWarningReason reason); - - lldb::addr_t - GetSharedCacheReadOnlyAddress(); - - bool - GetCFBooleanValuesIfNeeded (); - - friend class ClassDescriptorV2; - - std::unique_ptr<UtilityFunction> m_get_class_info_code; - lldb::addr_t m_get_class_info_args; - std::mutex m_get_class_info_args_mutex; - - 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; - - std::unique_ptr<DeclVendor> m_decl_vendor_ap; - lldb::addr_t m_isa_hash_table_ptr; - HashTableSignature m_hash_signature; - bool m_has_object_getClass; - bool m_loaded_objc_opt; - std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_ap; - std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_ap; - EncodingToTypeSP m_encoding_to_type_sp; - bool m_noclasses_warning_emitted; - llvm::Optional<std::pair<lldb::addr_t, - lldb::addr_t>> m_CFBoolean_values; + + void UpdateSignature(const RemoteNXMapTable &hash_table); + + protected: + uint32_t m_count; + uint32_t m_num_buckets; + lldb::addr_t m_buckets_ptr; + }; + + class NonPointerISACache { + public: + static NonPointerISACache * + CreateInstance(AppleObjCRuntimeV2 &runtime, + const lldb::ModuleSP &objc_module_sp); + + ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa); + + private: + NonPointerISACache(AppleObjCRuntimeV2 &runtime, + uint64_t objc_debug_isa_class_mask, + uint64_t objc_debug_isa_magic_mask, + uint64_t objc_debug_isa_magic_value); + + bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa); + + AppleObjCRuntimeV2 &m_runtime; + std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache; + uint64_t m_objc_debug_isa_class_mask; + uint64_t m_objc_debug_isa_magic_mask; + uint64_t m_objc_debug_isa_magic_value; + + friend class AppleObjCRuntimeV2; + + DISALLOW_COPY_AND_ASSIGN(NonPointerISACache); + }; + + class TaggedPointerVendorV2 + : public ObjCLanguageRuntime::TaggedPointerVendor { + public: + ~TaggedPointerVendorV2() override = default; + + static TaggedPointerVendorV2 * + CreateInstance(AppleObjCRuntimeV2 &runtime, + const lldb::ModuleSP &objc_module_sp); + + protected: + AppleObjCRuntimeV2 &m_runtime; + + TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime) + : TaggedPointerVendor(), m_runtime(runtime) {} + + private: + DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorV2); + }; + + class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { + public: + bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; + + ObjCLanguageRuntime::ClassDescriptorSP + GetClassDescriptor(lldb::addr_t ptr) override; + + protected: + TaggedPointerVendorRuntimeAssisted( + AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, + uint32_t objc_debug_taggedpointer_slot_shift, + uint32_t objc_debug_taggedpointer_slot_mask, + uint32_t objc_debug_taggedpointer_payload_lshift, + uint32_t objc_debug_taggedpointer_payload_rshift, + lldb::addr_t objc_debug_taggedpointer_classes); + + typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; + typedef Cache::iterator CacheIterator; + Cache m_cache; + uint64_t m_objc_debug_taggedpointer_mask; + uint32_t m_objc_debug_taggedpointer_slot_shift; + uint32_t m_objc_debug_taggedpointer_slot_mask; + uint32_t m_objc_debug_taggedpointer_payload_lshift; + uint32_t m_objc_debug_taggedpointer_payload_rshift; + lldb::addr_t m_objc_debug_taggedpointer_classes; + + friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; + + DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted); + }; + + class TaggedPointerVendorExtended + : public TaggedPointerVendorRuntimeAssisted { + public: + ObjCLanguageRuntime::ClassDescriptorSP + GetClassDescriptor(lldb::addr_t ptr) override; + + protected: + TaggedPointerVendorExtended( + AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, + uint64_t objc_debug_taggedpointer_ext_mask, + uint32_t objc_debug_taggedpointer_slot_shift, + uint32_t objc_debug_taggedpointer_ext_slot_shift, + uint32_t objc_debug_taggedpointer_slot_mask, + uint32_t objc_debug_taggedpointer_ext_slot_mask, + uint32_t objc_debug_taggedpointer_payload_lshift, + uint32_t objc_debug_taggedpointer_payload_rshift, + uint32_t objc_debug_taggedpointer_ext_payload_lshift, + uint32_t objc_debug_taggedpointer_ext_payload_rshift, + lldb::addr_t objc_debug_taggedpointer_classes, + lldb::addr_t objc_debug_taggedpointer_ext_classes); + + bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr); + + typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; + typedef Cache::iterator CacheIterator; + Cache m_ext_cache; + uint64_t m_objc_debug_taggedpointer_ext_mask; + uint32_t m_objc_debug_taggedpointer_ext_slot_shift; + uint32_t m_objc_debug_taggedpointer_ext_slot_mask; + uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; + uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; + lldb::addr_t m_objc_debug_taggedpointer_ext_classes; + + friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; + + DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorExtended); + }; + + class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { + public: + bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; + + ObjCLanguageRuntime::ClassDescriptorSP + GetClassDescriptor(lldb::addr_t ptr) override; + + protected: + TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime) + : TaggedPointerVendorV2(runtime) {} + + friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; + + DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy); + }; + + struct DescriptorMapUpdateResult { + bool m_update_ran; + uint32_t m_num_found; + + DescriptorMapUpdateResult(bool ran, uint32_t found) { + m_update_ran = ran; + m_num_found = found; + } + + static DescriptorMapUpdateResult Fail() { return {false, 0}; } + + static DescriptorMapUpdateResult Success(uint32_t found) { + return {true, found}; + } + }; + + AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); + + ObjCISA GetPointerISA(ObjCISA isa); + + bool IsTaggedPointer(lldb::addr_t ptr); + + lldb::addr_t GetISAHashTablePointer(); + + bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table); + + DescriptorMapUpdateResult + UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); + + uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, + uint32_t num_class_infos); + + DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache(); + + enum class SharedCacheWarningReason { + eExpressionExecutionFailure, + eNotEnoughClassesRead + }; + + void WarnIfNoClassesCached(SharedCacheWarningReason reason); + + lldb::addr_t GetSharedCacheReadOnlyAddress(); + + bool GetCFBooleanValuesIfNeeded(); + + friend class ClassDescriptorV2; + + std::unique_ptr<UtilityFunction> m_get_class_info_code; + lldb::addr_t m_get_class_info_args; + std::mutex m_get_class_info_args_mutex; + + 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; + + std::unique_ptr<DeclVendor> m_decl_vendor_ap; + lldb::addr_t m_isa_hash_table_ptr; + HashTableSignature m_hash_signature; + bool m_has_object_getClass; + bool m_loaded_objc_opt; + std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_ap; + std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_ap; + EncodingToTypeSP m_encoding_to_type_sp; + bool m_noclasses_warning_emitted; + llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values; }; - + } // namespace lldb_private #endif // liblldb_AppleObjCRuntimeV2_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 5fedb80e29a..1dc20c11567 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -1,4 +1,5 @@ -//===-- AppleObjCTrampolineHandler.cpp ----------------------------*- C++ -*-===// +//===-- AppleObjCTrampolineHandler.cpp ----------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -43,8 +44,11 @@ using namespace lldb; using namespace lldb_private; -const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_name = "__lldb_objc_find_implementation_for_selector"; -const char *AppleObjCTrampolineHandler::g_lookup_implementation_with_stret_function_code = " \n\ +const char *AppleObjCTrampolineHandler::g_lookup_implementation_function_name = + "__lldb_objc_find_implementation_for_selector"; +const char *AppleObjCTrampolineHandler:: + g_lookup_implementation_with_stret_function_code = + " \n\ extern \"C\" \n\ { \n\ extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ @@ -159,7 +163,9 @@ extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, return return_struct.impl_addr; \n\ } \n\ "; -const char *AppleObjCTrampolineHandler::g_lookup_implementation_no_stret_function_code = " \n\ +const char * + AppleObjCTrampolineHandler::g_lookup_implementation_no_stret_function_code = + " \n\ extern \"C\" \n\ { \n\ extern void *class_getMethodImplementation(void *objc_class, void *sel); \n\ @@ -266,887 +272,879 @@ extern \"C\" void * __lldb_objc_find_implementation_for_selector (void *object, } \n\ "; -AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr) : - m_valid (true), - m_owner(owner), - m_header_addr (header_addr), - m_code_start_addr(0), - m_code_end_addr (0), - m_next_region (0) -{ - SetUpRegion (); +AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion( + AppleObjCVTables *owner, lldb::addr_t header_addr) + : m_valid(true), m_owner(owner), m_header_addr(header_addr), + m_code_start_addr(0), m_code_end_addr(0), m_next_region(0) { + SetUpRegion(); } -AppleObjCTrampolineHandler::~AppleObjCTrampolineHandler() -{ -} +AppleObjCTrampolineHandler::~AppleObjCTrampolineHandler() {} -void -AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() -{ - // The header looks like: - // - // uint16_t headerSize - // uint16_t descSize - // uint32_t descCount - // void * next - // - // First read in the header: - - char memory_buffer[16]; - ProcessSP process_sp = m_owner->GetProcessSP(); - if (!process_sp) - return; - DataExtractor data(memory_buffer, sizeof(memory_buffer), - process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - size_t actual_size = 8 + process_sp->GetAddressByteSize(); - Error error; - size_t bytes_read = process_sp->ReadMemory (m_header_addr, memory_buffer, actual_size, error); - if (bytes_read != actual_size) - { - m_valid = false; - return; - } - - lldb::offset_t offset = 0; - const uint16_t header_size = data.GetU16(&offset); - const uint16_t descriptor_size = data.GetU16(&offset); - const size_t num_descriptors = data.GetU32(&offset); - - m_next_region = data.GetPointer(&offset); - - // If the header size is 0, that means we've come in too early before this data is set up. - // Set ourselves as not valid, and continue. - if (header_size == 0 || num_descriptors == 0) - { - m_valid = false; - return; - } - - // Now read in all the descriptors: - // The descriptor looks like: - // - // uint32_t offset - // uint32_t flags - // - // Where offset is either 0 - in which case it is unused, or - // it is the offset of the vtable code from the beginning of the descriptor record. - // Below, we'll convert that into an absolute code address, since I don't want to have - // to compute it over and over. - - // Ingest the whole descriptor array: - const lldb::addr_t desc_ptr = m_header_addr + header_size; - const size_t desc_array_size = num_descriptors * descriptor_size; - DataBufferSP data_sp(new DataBufferHeap (desc_array_size, '\0')); - uint8_t* dst = (uint8_t*)data_sp->GetBytes(); - - DataExtractor desc_extractor (dst, desc_array_size, - process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - bytes_read = process_sp->ReadMemory(desc_ptr, dst, desc_array_size, error); - if (bytes_read != desc_array_size) - { - m_valid = false; - return; - } - - // The actual code for the vtables will be laid out consecutively, so I also - // compute the start and end of the whole code block. - - offset = 0; - m_code_start_addr = 0; - m_code_end_addr = 0; - - for (size_t i = 0; i < num_descriptors; i++) - { - lldb::addr_t start_offset = offset; - uint32_t voffset = desc_extractor.GetU32 (&offset); - uint32_t flags = desc_extractor.GetU32 (&offset); - lldb::addr_t code_addr = desc_ptr + start_offset + voffset; - m_descriptors.push_back (VTableDescriptor(flags, code_addr)); - - if (m_code_start_addr == 0 || code_addr < m_code_start_addr) - m_code_start_addr = code_addr; - if (code_addr > m_code_end_addr) - m_code_end_addr = code_addr; - - offset = start_offset + descriptor_size; - } - // Finally, a little bird told me that all the vtable code blocks are the same size. - // Let's compute the blocks and if they are all the same add the size to the code end address: - lldb::addr_t code_size = 0; - bool all_the_same = true; - for (size_t i = 0; i < num_descriptors - 1; i++) - { - lldb::addr_t this_size = m_descriptors[i + 1].code_start - m_descriptors[i].code_start; - if (code_size == 0) - code_size = this_size; - else - { - if (this_size != code_size) - all_the_same = false; - if (this_size > code_size) - code_size = this_size; - } +void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() { + // The header looks like: + // + // uint16_t headerSize + // uint16_t descSize + // uint32_t descCount + // void * next + // + // First read in the header: + + char memory_buffer[16]; + ProcessSP process_sp = m_owner->GetProcessSP(); + if (!process_sp) + return; + DataExtractor data(memory_buffer, sizeof(memory_buffer), + process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + size_t actual_size = 8 + process_sp->GetAddressByteSize(); + Error error; + size_t bytes_read = + process_sp->ReadMemory(m_header_addr, memory_buffer, actual_size, error); + if (bytes_read != actual_size) { + m_valid = false; + return; + } + + lldb::offset_t offset = 0; + const uint16_t header_size = data.GetU16(&offset); + const uint16_t descriptor_size = data.GetU16(&offset); + const size_t num_descriptors = data.GetU32(&offset); + + m_next_region = data.GetPointer(&offset); + + // If the header size is 0, that means we've come in too early before this + // data is set up. + // Set ourselves as not valid, and continue. + if (header_size == 0 || num_descriptors == 0) { + m_valid = false; + return; + } + + // Now read in all the descriptors: + // The descriptor looks like: + // + // uint32_t offset + // uint32_t flags + // + // Where offset is either 0 - in which case it is unused, or + // it is the offset of the vtable code from the beginning of the descriptor + // record. + // Below, we'll convert that into an absolute code address, since I don't want + // to have + // to compute it over and over. + + // Ingest the whole descriptor array: + const lldb::addr_t desc_ptr = m_header_addr + header_size; + const size_t desc_array_size = num_descriptors * descriptor_size; + DataBufferSP data_sp(new DataBufferHeap(desc_array_size, '\0')); + uint8_t *dst = (uint8_t *)data_sp->GetBytes(); + + DataExtractor desc_extractor(dst, desc_array_size, process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + bytes_read = process_sp->ReadMemory(desc_ptr, dst, desc_array_size, error); + if (bytes_read != desc_array_size) { + m_valid = false; + return; + } + + // The actual code for the vtables will be laid out consecutively, so I also + // compute the start and end of the whole code block. + + offset = 0; + m_code_start_addr = 0; + m_code_end_addr = 0; + + for (size_t i = 0; i < num_descriptors; i++) { + lldb::addr_t start_offset = offset; + uint32_t voffset = desc_extractor.GetU32(&offset); + uint32_t flags = desc_extractor.GetU32(&offset); + lldb::addr_t code_addr = desc_ptr + start_offset + voffset; + m_descriptors.push_back(VTableDescriptor(flags, code_addr)); + + if (m_code_start_addr == 0 || code_addr < m_code_start_addr) + m_code_start_addr = code_addr; + if (code_addr > m_code_end_addr) + m_code_end_addr = code_addr; + + offset = start_offset + descriptor_size; + } + // Finally, a little bird told me that all the vtable code blocks are the same + // size. + // Let's compute the blocks and if they are all the same add the size to the + // code end address: + lldb::addr_t code_size = 0; + bool all_the_same = true; + for (size_t i = 0; i < num_descriptors - 1; i++) { + lldb::addr_t this_size = + m_descriptors[i + 1].code_start - m_descriptors[i].code_start; + if (code_size == 0) + code_size = this_size; + else { + if (this_size != code_size) + all_the_same = false; + if (this_size > code_size) + code_size = this_size; } - if (all_the_same) - m_code_end_addr += code_size; + } + if (all_the_same) + m_code_end_addr += code_size; } -bool -AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::AddressInRegion (lldb::addr_t addr, uint32_t &flags) -{ - if (!IsValid()) - return false; - - if (addr < m_code_start_addr || addr > m_code_end_addr) - return false; - - std::vector<VTableDescriptor>::iterator pos, end = m_descriptors.end(); - for (pos = m_descriptors.begin(); pos != end; pos++) - { - if (addr <= (*pos).code_start) - { - flags = (*pos).flags; - return true; - } - } +bool AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion:: + AddressInRegion(lldb::addr_t addr, uint32_t &flags) { + if (!IsValid()) + return false; + + if (addr < m_code_start_addr || addr > m_code_end_addr) return false; -} -void -AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::Dump (Stream &s) -{ - s.Printf ("Header addr: 0x%" PRIx64 " Code start: 0x%" PRIx64 " Code End: 0x%" PRIx64 " Next: 0x%" PRIx64 "\n", - m_header_addr, m_code_start_addr, m_code_end_addr, m_next_region); - size_t num_elements = m_descriptors.size(); - for (size_t i = 0; i < num_elements; i++) - { - s.Indent(); - s.Printf ("Code start: 0x%" PRIx64 " Flags: %d\n", m_descriptors[i].code_start, m_descriptors[i].flags); + std::vector<VTableDescriptor>::iterator pos, end = m_descriptors.end(); + for (pos = m_descriptors.begin(); pos != end; pos++) { + if (addr <= (*pos).code_start) { + flags = (*pos).flags; + return true; } + } + return false; } - -AppleObjCTrampolineHandler::AppleObjCVTables::AppleObjCVTables (const ProcessSP &process_sp, - const ModuleSP &objc_module_sp) : - m_process_wp (), - m_trampoline_header (LLDB_INVALID_ADDRESS), - m_trampolines_changed_bp_id (LLDB_INVALID_BREAK_ID), - m_objc_module_sp (objc_module_sp) -{ - if (process_sp) - m_process_wp = process_sp; + +void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::Dump( + Stream &s) { + s.Printf("Header addr: 0x%" PRIx64 " Code start: 0x%" PRIx64 + " Code End: 0x%" PRIx64 " Next: 0x%" PRIx64 "\n", + m_header_addr, m_code_start_addr, m_code_end_addr, m_next_region); + size_t num_elements = m_descriptors.size(); + for (size_t i = 0; i < num_elements; i++) { + s.Indent(); + s.Printf("Code start: 0x%" PRIx64 " Flags: %d\n", + m_descriptors[i].code_start, m_descriptors[i].flags); + } } -AppleObjCTrampolineHandler::AppleObjCVTables::~AppleObjCVTables() -{ - ProcessSP process_sp = GetProcessSP (); - if (process_sp) - { - if (m_trampolines_changed_bp_id != LLDB_INVALID_BREAK_ID) - process_sp->GetTarget().RemoveBreakpointByID (m_trampolines_changed_bp_id); - } +AppleObjCTrampolineHandler::AppleObjCVTables::AppleObjCVTables( + const ProcessSP &process_sp, const ModuleSP &objc_module_sp) + : m_process_wp(), m_trampoline_header(LLDB_INVALID_ADDRESS), + m_trampolines_changed_bp_id(LLDB_INVALID_BREAK_ID), + m_objc_module_sp(objc_module_sp) { + if (process_sp) + m_process_wp = process_sp; } -bool -AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols () -{ - if (m_trampoline_header != LLDB_INVALID_ADDRESS) - return true; +AppleObjCTrampolineHandler::AppleObjCVTables::~AppleObjCVTables() { + ProcessSP process_sp = GetProcessSP(); + if (process_sp) { + if (m_trampolines_changed_bp_id != LLDB_INVALID_BREAK_ID) + process_sp->GetTarget().RemoveBreakpointByID(m_trampolines_changed_bp_id); + } +} - ProcessSP process_sp = GetProcessSP (); - if (process_sp) - { - Target &target = process_sp->GetTarget(); - - const ModuleList &target_modules = target.GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); - if (!m_objc_module_sp) - { - for (size_t i = 0; i < num_modules; i++) - { - if (process_sp->GetObjCLanguageRuntime()->IsModuleObjCLibrary (target_modules.GetModuleAtIndexUnlocked(i))) - { - m_objc_module_sp = target_modules.GetModuleAtIndexUnlocked(i); - break; - } - } - } - - if (m_objc_module_sp) - { - ConstString trampoline_name ("gdb_objc_trampolines"); - const Symbol *trampoline_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType (trampoline_name, - eSymbolTypeData); - if (trampoline_symbol != NULL) - { - m_trampoline_header = trampoline_symbol->GetLoadAddress(&target); - if (m_trampoline_header == LLDB_INVALID_ADDRESS) - return false; - - // Next look up the "changed" symbol and set a breakpoint on that... - ConstString changed_name ("gdb_objc_trampolines_changed"); - const Symbol *changed_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType (changed_name, - eSymbolTypeCode); - if (changed_symbol != NULL) - { - const Address changed_symbol_addr = changed_symbol->GetAddress(); - if (!changed_symbol_addr.IsValid()) - return false; - - lldb::addr_t changed_addr = changed_symbol_addr.GetOpcodeLoadAddress (&target); - if (changed_addr != LLDB_INVALID_ADDRESS) - { - BreakpointSP trampolines_changed_bp_sp = target.CreateBreakpoint (changed_addr, true, false); - if (trampolines_changed_bp_sp) - { - m_trampolines_changed_bp_id = trampolines_changed_bp_sp->GetID(); - trampolines_changed_bp_sp->SetCallback (RefreshTrampolines, this, true); - trampolines_changed_bp_sp->SetBreakpointKind ("objc-trampolines-changed"); - return true; - } - } - } - } +bool AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols() { + if (m_trampoline_header != LLDB_INVALID_ADDRESS) + return true; + + ProcessSP process_sp = GetProcessSP(); + if (process_sp) { + Target &target = process_sp->GetTarget(); + + const ModuleList &target_modules = target.GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); + size_t num_modules = target_modules.GetSize(); + if (!m_objc_module_sp) { + for (size_t i = 0; i < num_modules; i++) { + if (process_sp->GetObjCLanguageRuntime()->IsModuleObjCLibrary( + target_modules.GetModuleAtIndexUnlocked(i))) { + m_objc_module_sp = target_modules.GetModuleAtIndexUnlocked(i); + break; } + } } - return false; -} - -bool -AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) -{ - AppleObjCVTables *vtable_handler = (AppleObjCVTables *) baton; - if (vtable_handler->InitializeVTableSymbols()) - { - // The Update function is called with the address of an added region. So we grab that address, and - // feed it into ReadRegions. Of course, our friend the ABI will get the values for us. - ExecutionContext exe_ctx (context->exe_ctx_ref); - Process *process = exe_ctx.GetProcessPtr(); - const ABI *abi = process->GetABI().get(); - - ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext(); - ValueList argument_values; - Value input_value; - CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - - input_value.SetValueType (Value::eValueTypeScalar); - //input_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type); - input_value.SetCompilerType (clang_void_ptr_type); - argument_values.PushValue(input_value); - - bool success = abi->GetArgumentValues (exe_ctx.GetThreadRef(), argument_values); - if (!success) + + if (m_objc_module_sp) { + ConstString trampoline_name("gdb_objc_trampolines"); + const Symbol *trampoline_symbol = + m_objc_module_sp->FindFirstSymbolWithNameAndType(trampoline_name, + eSymbolTypeData); + if (trampoline_symbol != NULL) { + m_trampoline_header = trampoline_symbol->GetLoadAddress(&target); + if (m_trampoline_header == LLDB_INVALID_ADDRESS) + return false; + + // Next look up the "changed" symbol and set a breakpoint on that... + ConstString changed_name("gdb_objc_trampolines_changed"); + const Symbol *changed_symbol = + m_objc_module_sp->FindFirstSymbolWithNameAndType(changed_name, + eSymbolTypeCode); + if (changed_symbol != NULL) { + const Address changed_symbol_addr = changed_symbol->GetAddress(); + if (!changed_symbol_addr.IsValid()) return false; - - // Now get a pointer value from the zeroth argument. - Error error; - DataExtractor data; - error = argument_values.GetValueAtIndex(0)->GetValueAsData (&exe_ctx, - data, - 0, - NULL); - lldb::offset_t offset = 0; - lldb::addr_t region_addr = data.GetPointer(&offset); - - if (region_addr != 0) - vtable_handler->ReadRegions(region_addr); + + lldb::addr_t changed_addr = + changed_symbol_addr.GetOpcodeLoadAddress(&target); + if (changed_addr != LLDB_INVALID_ADDRESS) { + BreakpointSP trampolines_changed_bp_sp = + target.CreateBreakpoint(changed_addr, true, false); + if (trampolines_changed_bp_sp) { + m_trampolines_changed_bp_id = trampolines_changed_bp_sp->GetID(); + trampolines_changed_bp_sp->SetCallback(RefreshTrampolines, this, + true); + trampolines_changed_bp_sp->SetBreakpointKind( + "objc-trampolines-changed"); + return true; + } + } + } + } } - return false; + } + return false; } -bool -AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions () -{ - // The no argument version reads the start region from the value of the gdb_regions_header, and - // gets started from there. - - m_regions.clear(); - if (!InitializeVTableSymbols()) - return false; +bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( + void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + AppleObjCVTables *vtable_handler = (AppleObjCVTables *)baton; + if (vtable_handler->InitializeVTableSymbols()) { + // The Update function is called with the address of an added region. So we + // grab that address, and + // feed it into ReadRegions. Of course, our friend the ABI will get the + // values for us. + ExecutionContext exe_ctx(context->exe_ctx_ref); + Process *process = exe_ctx.GetProcessPtr(); + const ABI *abi = process->GetABI().get(); + + ClangASTContext *clang_ast_context = + process->GetTarget().GetScratchClangASTContext(); + ValueList argument_values; + Value input_value; + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + + input_value.SetValueType(Value::eValueTypeScalar); + // input_value.SetContext (Value::eContextTypeClangType, + // clang_void_ptr_type); + input_value.SetCompilerType(clang_void_ptr_type); + argument_values.PushValue(input_value); + + bool success = + abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values); + if (!success) + return false; + + // Now get a pointer value from the zeroth argument. Error error; - ProcessSP process_sp = GetProcessSP (); - if (process_sp) - { - lldb::addr_t region_addr = process_sp->ReadPointerFromMemory (m_trampoline_header, error); - if (error.Success()) - return ReadRegions (region_addr); - } + DataExtractor data; + error = argument_values.GetValueAtIndex(0)->GetValueAsData(&exe_ctx, data, + 0, NULL); + lldb::offset_t offset = 0; + lldb::addr_t region_addr = data.GetPointer(&offset); + + if (region_addr != 0) + vtable_handler->ReadRegions(region_addr); + } + return false; +} + +bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions() { + // The no argument version reads the start region from the value of the + // gdb_regions_header, and + // gets started from there. + + m_regions.clear(); + if (!InitializeVTableSymbols()) return false; + Error error; + ProcessSP process_sp = GetProcessSP(); + if (process_sp) { + lldb::addr_t region_addr = + process_sp->ReadPointerFromMemory(m_trampoline_header, error); + if (error.Success()) + return ReadRegions(region_addr); + } + return false; } -bool -AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions (lldb::addr_t region_addr) -{ - ProcessSP process_sp = GetProcessSP (); - if (!process_sp) - return false; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - // We aren't starting at the trampoline symbol. - InitializeVTableSymbols (); - lldb::addr_t next_region = region_addr; - - // Read in the sizes of the headers. - while (next_region != 0) - { - m_regions.push_back (VTableRegion(this, next_region)); - if (!m_regions.back().IsValid()) - { - m_regions.clear(); - return false; - } - if (log) - { - StreamString s; - m_regions.back().Dump(s); - log->Printf("Read vtable region: \n%s", s.GetData()); - } - - next_region = m_regions.back().GetNextRegionAddr(); +bool AppleObjCTrampolineHandler::AppleObjCVTables::ReadRegions( + lldb::addr_t region_addr) { + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + // We aren't starting at the trampoline symbol. + InitializeVTableSymbols(); + lldb::addr_t next_region = region_addr; + + // Read in the sizes of the headers. + while (next_region != 0) { + m_regions.push_back(VTableRegion(this, next_region)); + if (!m_regions.back().IsValid()) { + m_regions.clear(); + return false; } - - return true; -} - -bool -AppleObjCTrampolineHandler::AppleObjCVTables::IsAddressInVTables (lldb::addr_t addr, uint32_t &flags) -{ - region_collection::iterator pos, end = m_regions.end(); - for (pos = m_regions.begin(); pos != end; pos++) - { - if ((*pos).AddressInRegion (addr, flags)) - return true; + if (log) { + StreamString s; + m_regions.back().Dump(s); + log->Printf("Read vtable region: \n%s", s.GetData()); } - return false; + + next_region = m_regions.back().GetNextRegionAddr(); + } + + return true; +} + +bool AppleObjCTrampolineHandler::AppleObjCVTables::IsAddressInVTables( + lldb::addr_t addr, uint32_t &flags) { + region_collection::iterator pos, end = m_regions.end(); + for (pos = m_regions.begin(); pos != end; pos++) { + if ((*pos).AddressInRegion(addr, flags)) + return true; + } + return false; } const AppleObjCTrampolineHandler::DispatchFunction -AppleObjCTrampolineHandler::g_dispatch_functions[] = -{ - // NAME STRET SUPER SUPER2 FIXUP TYPE - {"objc_msgSend", false, false, false, DispatchFunction::eFixUpNone }, - {"objc_msgSend_fixup", false, false, false, DispatchFunction::eFixUpToFix }, - {"objc_msgSend_fixedup", false, false, false, DispatchFunction::eFixUpFixed }, - {"objc_msgSend_stret", true, false, false, DispatchFunction::eFixUpNone }, - {"objc_msgSend_stret_fixup", true, false, false, DispatchFunction::eFixUpToFix }, - {"objc_msgSend_stret_fixedup", true, false, false, DispatchFunction::eFixUpFixed }, - {"objc_msgSend_fpret", false, false, false, DispatchFunction::eFixUpNone }, - {"objc_msgSend_fpret_fixup", false, false, false, DispatchFunction::eFixUpToFix }, - {"objc_msgSend_fpret_fixedup", false, false, false, DispatchFunction::eFixUpFixed }, - {"objc_msgSend_fp2ret", false, false, true, DispatchFunction::eFixUpNone }, - {"objc_msgSend_fp2ret_fixup", false, false, true, DispatchFunction::eFixUpToFix }, - {"objc_msgSend_fp2ret_fixedup", false, false, true, DispatchFunction::eFixUpFixed }, - {"objc_msgSendSuper", false, true, false, DispatchFunction::eFixUpNone }, - {"objc_msgSendSuper_stret", true, true, false, DispatchFunction::eFixUpNone }, - {"objc_msgSendSuper2", false, true, true, DispatchFunction::eFixUpNone }, - {"objc_msgSendSuper2_fixup", false, true, true, DispatchFunction::eFixUpToFix }, - {"objc_msgSendSuper2_fixedup", false, true, true, DispatchFunction::eFixUpFixed }, - {"objc_msgSendSuper2_stret", true, true, true, DispatchFunction::eFixUpNone }, - {"objc_msgSendSuper2_stret_fixup", true, true, true, DispatchFunction::eFixUpToFix }, - {"objc_msgSendSuper2_stret_fixedup", true, true, true, DispatchFunction::eFixUpFixed }, + AppleObjCTrampolineHandler::g_dispatch_functions[] = { + // NAME STRET SUPER SUPER2 FIXUP TYPE + {"objc_msgSend", false, false, false, DispatchFunction::eFixUpNone}, + {"objc_msgSend_fixup", false, false, false, + DispatchFunction::eFixUpToFix}, + {"objc_msgSend_fixedup", false, false, false, + DispatchFunction::eFixUpFixed}, + {"objc_msgSend_stret", true, false, false, + DispatchFunction::eFixUpNone}, + {"objc_msgSend_stret_fixup", true, false, false, + DispatchFunction::eFixUpToFix}, + {"objc_msgSend_stret_fixedup", true, false, false, + DispatchFunction::eFixUpFixed}, + {"objc_msgSend_fpret", false, false, false, + DispatchFunction::eFixUpNone}, + {"objc_msgSend_fpret_fixup", false, false, false, + DispatchFunction::eFixUpToFix}, + {"objc_msgSend_fpret_fixedup", false, false, false, + DispatchFunction::eFixUpFixed}, + {"objc_msgSend_fp2ret", false, false, true, + DispatchFunction::eFixUpNone}, + {"objc_msgSend_fp2ret_fixup", false, false, true, + DispatchFunction::eFixUpToFix}, + {"objc_msgSend_fp2ret_fixedup", false, false, true, + DispatchFunction::eFixUpFixed}, + {"objc_msgSendSuper", false, true, false, DispatchFunction::eFixUpNone}, + {"objc_msgSendSuper_stret", true, true, false, + DispatchFunction::eFixUpNone}, + {"objc_msgSendSuper2", false, true, true, DispatchFunction::eFixUpNone}, + {"objc_msgSendSuper2_fixup", false, true, true, + DispatchFunction::eFixUpToFix}, + {"objc_msgSendSuper2_fixedup", false, true, true, + DispatchFunction::eFixUpFixed}, + {"objc_msgSendSuper2_stret", true, true, true, + DispatchFunction::eFixUpNone}, + {"objc_msgSendSuper2_stret_fixup", true, true, true, + DispatchFunction::eFixUpToFix}, + {"objc_msgSendSuper2_stret_fixedup", true, true, true, + DispatchFunction::eFixUpFixed}, }; -AppleObjCTrampolineHandler::AppleObjCTrampolineHandler (const ProcessSP &process_sp, - const ModuleSP &objc_module_sp) : - m_process_wp (), - m_objc_module_sp (objc_module_sp), - m_lookup_implementation_function_code(nullptr), - m_impl_fn_addr (LLDB_INVALID_ADDRESS), - m_impl_stret_fn_addr (LLDB_INVALID_ADDRESS), - m_msg_forward_addr (LLDB_INVALID_ADDRESS) -{ - if (process_sp) - m_process_wp = process_sp; - // Look up the known resolution functions: - - ConstString get_impl_name("class_getMethodImplementation"); - ConstString get_impl_stret_name("class_getMethodImplementation_stret"); - ConstString msg_forward_name("_objc_msgForward"); - ConstString msg_forward_stret_name("_objc_msgForward_stret"); - - Target *target = process_sp ? &process_sp->GetTarget() : NULL; - const Symbol *class_getMethodImplementation = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_name, eSymbolTypeCode); - const Symbol *class_getMethodImplementation_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (get_impl_stret_name, eSymbolTypeCode); - const Symbol *msg_forward = m_objc_module_sp->FindFirstSymbolWithNameAndType (msg_forward_name, eSymbolTypeCode); - const Symbol *msg_forward_stret = m_objc_module_sp->FindFirstSymbolWithNameAndType (msg_forward_stret_name, eSymbolTypeCode); - - if (class_getMethodImplementation) - m_impl_fn_addr = class_getMethodImplementation->GetAddress().GetOpcodeLoadAddress (target); - if (class_getMethodImplementation_stret) - m_impl_stret_fn_addr = class_getMethodImplementation_stret->GetAddress().GetOpcodeLoadAddress (target); - if (msg_forward) - m_msg_forward_addr = msg_forward->GetAddress().GetOpcodeLoadAddress(target); - if (msg_forward_stret) - m_msg_forward_stret_addr = msg_forward_stret->GetAddress().GetOpcodeLoadAddress(target); - - // FIXME: Do some kind of logging here. - if (m_impl_fn_addr == LLDB_INVALID_ADDRESS) - { - // If we can't even find the ordinary get method implementation function, then we aren't going to be able to - // step through any method dispatches. Warn to that effect and get out of here. - if (process_sp->CanJIT()) - { - process_sp->GetTarget().GetDebugger().GetErrorFile()->Printf ("Could not find implementation lookup function \"%s\"" - " step in through ObjC method dispatch will not work.\n", - get_impl_name.AsCString()); - } - return; - } - else if (m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS) - { - // It there is no stret return lookup function, assume that it is the same as the straight lookup: - m_impl_stret_fn_addr = m_impl_fn_addr; - // Also we will use the version of the lookup code that doesn't rely on the stret version of the function. - m_lookup_implementation_function_code = g_lookup_implementation_no_stret_function_code; - } - else - { - m_lookup_implementation_function_code = g_lookup_implementation_with_stret_function_code; +AppleObjCTrampolineHandler::AppleObjCTrampolineHandler( + const ProcessSP &process_sp, const ModuleSP &objc_module_sp) + : m_process_wp(), m_objc_module_sp(objc_module_sp), + m_lookup_implementation_function_code(nullptr), + m_impl_fn_addr(LLDB_INVALID_ADDRESS), + m_impl_stret_fn_addr(LLDB_INVALID_ADDRESS), + m_msg_forward_addr(LLDB_INVALID_ADDRESS) { + if (process_sp) + m_process_wp = process_sp; + // Look up the known resolution functions: + + ConstString get_impl_name("class_getMethodImplementation"); + ConstString get_impl_stret_name("class_getMethodImplementation_stret"); + ConstString msg_forward_name("_objc_msgForward"); + ConstString msg_forward_stret_name("_objc_msgForward_stret"); + + Target *target = process_sp ? &process_sp->GetTarget() : NULL; + const Symbol *class_getMethodImplementation = + m_objc_module_sp->FindFirstSymbolWithNameAndType(get_impl_name, + eSymbolTypeCode); + const Symbol *class_getMethodImplementation_stret = + m_objc_module_sp->FindFirstSymbolWithNameAndType(get_impl_stret_name, + eSymbolTypeCode); + const Symbol *msg_forward = m_objc_module_sp->FindFirstSymbolWithNameAndType( + msg_forward_name, eSymbolTypeCode); + const Symbol *msg_forward_stret = + m_objc_module_sp->FindFirstSymbolWithNameAndType(msg_forward_stret_name, + eSymbolTypeCode); + + if (class_getMethodImplementation) + m_impl_fn_addr = + class_getMethodImplementation->GetAddress().GetOpcodeLoadAddress( + target); + if (class_getMethodImplementation_stret) + m_impl_stret_fn_addr = + class_getMethodImplementation_stret->GetAddress().GetOpcodeLoadAddress( + target); + if (msg_forward) + m_msg_forward_addr = msg_forward->GetAddress().GetOpcodeLoadAddress(target); + if (msg_forward_stret) + m_msg_forward_stret_addr = + msg_forward_stret->GetAddress().GetOpcodeLoadAddress(target); + + // FIXME: Do some kind of logging here. + if (m_impl_fn_addr == LLDB_INVALID_ADDRESS) { + // If we can't even find the ordinary get method implementation function, + // then we aren't going to be able to + // step through any method dispatches. Warn to that effect and get out of + // here. + if (process_sp->CanJIT()) { + process_sp->GetTarget().GetDebugger().GetErrorFile()->Printf( + "Could not find implementation lookup function \"%s\"" + " step in through ObjC method dispatch will not work.\n", + get_impl_name.AsCString()); } - - // Look up the addresses for the objc dispatch functions and cache them. For now I'm inspecting the symbol - // names dynamically to figure out how to dispatch to them. If it becomes more complicated than this we can - // turn the g_dispatch_functions char * array into a template table, and populate the DispatchFunction map - // from there. - - for (size_t i = 0; i != llvm::array_lengthof(g_dispatch_functions); i++) - { - ConstString name_const_str(g_dispatch_functions[i].name); - const Symbol *msgSend_symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType (name_const_str, eSymbolTypeCode); - if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) - { - // FixMe: Make g_dispatch_functions static table of DispatchFunctions, and have the map be address->index. - // Problem is we also need to lookup the dispatch function. For now we could have a side table of stret & non-stret - // dispatch functions. If that's as complex as it gets, we're fine. - - lldb::addr_t sym_addr = msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target); - - m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i)); - } + return; + } else if (m_impl_stret_fn_addr == LLDB_INVALID_ADDRESS) { + // It there is no stret return lookup function, assume that it is the same + // as the straight lookup: + m_impl_stret_fn_addr = m_impl_fn_addr; + // Also we will use the version of the lookup code that doesn't rely on the + // stret version of the function. + m_lookup_implementation_function_code = + g_lookup_implementation_no_stret_function_code; + } else { + m_lookup_implementation_function_code = + g_lookup_implementation_with_stret_function_code; + } + + // Look up the addresses for the objc dispatch functions and cache them. For + // now I'm inspecting the symbol + // names dynamically to figure out how to dispatch to them. If it becomes + // more complicated than this we can + // turn the g_dispatch_functions char * array into a template table, and + // populate the DispatchFunction map + // from there. + + for (size_t i = 0; i != llvm::array_lengthof(g_dispatch_functions); i++) { + ConstString name_const_str(g_dispatch_functions[i].name); + const Symbol *msgSend_symbol = + m_objc_module_sp->FindFirstSymbolWithNameAndType(name_const_str, + eSymbolTypeCode); + if (msgSend_symbol && msgSend_symbol->ValueIsAddress()) { + // FixMe: Make g_dispatch_functions static table of DispatchFunctions, and + // have the map be address->index. + // Problem is we also need to lookup the dispatch function. For now we + // could have a side table of stret & non-stret + // dispatch functions. If that's as complex as it gets, we're fine. + + lldb::addr_t sym_addr = + msgSend_symbol->GetAddressRef().GetOpcodeLoadAddress(target); + + m_msgSend_map.insert(std::pair<lldb::addr_t, int>(sym_addr, i)); } - - // Build our vtable dispatch handler here: - m_vtables_ap.reset(new AppleObjCVTables(process_sp, m_objc_module_sp)); - if (m_vtables_ap.get()) - m_vtables_ap->ReadRegions(); + } + + // Build our vtable dispatch handler here: + m_vtables_ap.reset(new AppleObjCVTables(process_sp, m_objc_module_sp)); + if (m_vtables_ap.get()) + m_vtables_ap->ReadRegions(); } lldb::addr_t -AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, ValueList &dispatch_values) -{ - ThreadSP thread_sp(thread.shared_from_this()); - ExecutionContext exe_ctx (thread_sp); - DiagnosticManager diagnostics; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); +AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, + ValueList &dispatch_values) { + ThreadSP thread_sp(thread.shared_from_this()); + ExecutionContext exe_ctx(thread_sp); + DiagnosticManager diagnostics; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; - FunctionCaller *impl_function_caller = nullptr; - - // Scope for mutex locker: - { - std::lock_guard<std::mutex> guard(m_impl_function_mutex); - - // First stage is to make the ClangUtility to hold our injected function: - - if (!m_impl_code.get()) - { - if (m_lookup_implementation_function_code != NULL) - { - Error error; - m_impl_code.reset (exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage (m_lookup_implementation_function_code, - eLanguageTypeObjC, - g_lookup_implementation_function_name, - error)); - if (error.Fail()) - { - if (log) - log->Printf ("Failed to get Utility Function for implementation lookup: %s.", error.AsCString()); - m_impl_code.reset(); - return args_addr; - } - - if (!m_impl_code->Install(diagnostics, exe_ctx)) - { - if (log) - { - log->Printf("Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_impl_code.reset(); - return args_addr; - } - } - else - { - if (log) - log->Printf("No method lookup implementation code."); - return LLDB_INVALID_ADDRESS; - } + lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; + FunctionCaller *impl_function_caller = nullptr; - // Next make the runner function for our implementation utility function. - ClangASTContext *clang_ast_context = thread.GetProcess()->GetTarget().GetScratchClangASTContext(); - CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - Error error; - - impl_function_caller = m_impl_code->MakeFunctionCaller(clang_void_ptr_type, - dispatch_values, - thread_sp, - error); - if (error.Fail()) - { - if (log) - log->Printf ("Error getting function caller for dispatch lookup: \"%s\".", error.AsCString()); - return args_addr; - } - } - else - { - impl_function_caller = m_impl_code->GetFunctionCaller(); - } - } + // Scope for mutex locker: + { + std::lock_guard<std::mutex> guard(m_impl_function_mutex); - diagnostics.Clear(); + // First stage is to make the ClangUtility to hold our injected function: - // Now write down the argument values for this particular call. This looks like it might be a race condition - // if other threads were calling into here, but actually it isn't because we allocate a new args structure for - // this call by passing args_addr = LLDB_INVALID_ADDRESS... + if (!m_impl_code.get()) { + if (m_lookup_implementation_function_code != NULL) { + Error error; + m_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( + m_lookup_implementation_function_code, eLanguageTypeObjC, + g_lookup_implementation_function_name, error)); + if (error.Fail()) { + if (log) + log->Printf( + "Failed to get Utility Function for implementation lookup: %s.", + error.AsCString()); + m_impl_code.reset(); + return args_addr; + } - if (!impl_function_caller->WriteFunctionArguments(exe_ctx, args_addr, dispatch_values, diagnostics)) - { - if (log) - { - log->Printf("Error writing function arguments."); + if (!m_impl_code->Install(diagnostics, exe_ctx)) { + if (log) { + log->Printf("Failed to install implementation lookup."); diagnostics.Dump(log); + } + m_impl_code.reset(); + return args_addr; } + } else { + if (log) + log->Printf("No method lookup implementation code."); + return LLDB_INVALID_ADDRESS; + } + + // Next make the runner function for our implementation utility function. + ClangASTContext *clang_ast_context = + thread.GetProcess()->GetTarget().GetScratchClangASTContext(); + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + Error error; + + impl_function_caller = m_impl_code->MakeFunctionCaller( + clang_void_ptr_type, dispatch_values, thread_sp, error); + if (error.Fail()) { + if (log) + log->Printf( + "Error getting function caller for dispatch lookup: \"%s\".", + error.AsCString()); return args_addr; + } + } else { + impl_function_caller = m_impl_code->GetFunctionCaller(); } + } + diagnostics.Clear(); + + // Now write down the argument values for this particular call. This looks + // like it might be a race condition + // if other threads were calling into here, but actually it isn't because we + // allocate a new args structure for + // this call by passing args_addr = LLDB_INVALID_ADDRESS... + + if (!impl_function_caller->WriteFunctionArguments( + exe_ctx, args_addr, dispatch_values, diagnostics)) { + if (log) { + log->Printf("Error writing function arguments."); + diagnostics.Dump(log); + } return args_addr; + } + + return args_addr; } ThreadPlanSP -AppleObjCTrampolineHandler::GetStepThroughDispatchPlan (Thread &thread, bool stop_others) -{ - ThreadPlanSP ret_plan_sp; - lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); - - DispatchFunction this_dispatch; - bool found_it = false; - - // First step is to look and see if we are in one of the known ObjC dispatch functions. We've already compiled - // a table of same, so consult it. - - MsgsendMap::iterator pos; - pos = m_msgSend_map.find (curr_pc); - if (pos != m_msgSend_map.end()) - { - this_dispatch = g_dispatch_functions[(*pos).second]; - found_it = true; +AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, + bool stop_others) { + ThreadPlanSP ret_plan_sp; + lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); + + DispatchFunction this_dispatch; + bool found_it = false; + + // First step is to look and see if we are in one of the known ObjC dispatch + // functions. We've already compiled + // a table of same, so consult it. + + MsgsendMap::iterator pos; + pos = m_msgSend_map.find(curr_pc); + if (pos != m_msgSend_map.end()) { + this_dispatch = g_dispatch_functions[(*pos).second]; + found_it = true; + } + + // Next check to see if we are in a vtable region: + + if (!found_it) { + uint32_t flags; + if (m_vtables_ap.get()) { + found_it = m_vtables_ap->IsAddressInVTables(curr_pc, flags); + if (found_it) { + this_dispatch.name = "vtable"; + this_dispatch.stret_return = + (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) == + AppleObjCVTables::eOBJC_TRAMPOLINE_STRET; + this_dispatch.is_super = false; + this_dispatch.is_super2 = false; + this_dispatch.fixedup = DispatchFunction::eFixUpFixed; + } } - - // Next check to see if we are in a vtable region: - - if (!found_it) - { - uint32_t flags; - if (m_vtables_ap.get()) - { - found_it = m_vtables_ap->IsAddressInVTables (curr_pc, flags); - if (found_it) - { - this_dispatch.name = "vtable"; - this_dispatch.stret_return - = (flags & AppleObjCVTables::eOBJC_TRAMPOLINE_STRET) == AppleObjCVTables::eOBJC_TRAMPOLINE_STRET; - this_dispatch.is_super = false; - this_dispatch.is_super2 = false; - this_dispatch.fixedup = DispatchFunction::eFixUpFixed; - } - } + } + + if (found_it) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + // We are decoding a method dispatch. + // First job is to pull the arguments out: + + lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); + + const ABI *abi = NULL; + ProcessSP process_sp(thread.CalculateProcess()); + if (process_sp) + abi = process_sp->GetABI().get(); + if (abi == NULL) + return ret_plan_sp; + + TargetSP target_sp(thread.CalculateTarget()); + + ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext(); + ValueList argument_values; + Value void_ptr_value; + CompilerType clang_void_ptr_type = + clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); + void_ptr_value.SetValueType(Value::eValueTypeScalar); + // void_ptr_value.SetContext (Value::eContextTypeClangType, + // clang_void_ptr_type); + void_ptr_value.SetCompilerType(clang_void_ptr_type); + + int obj_index; + int sel_index; + + // If this is a struct return dispatch, then the first argument is the + // return struct pointer, and the object is the second, and the selector is + // the third. + // Otherwise the object is the first and the selector the second. + if (this_dispatch.stret_return) { + obj_index = 1; + sel_index = 2; + argument_values.PushValue(void_ptr_value); + argument_values.PushValue(void_ptr_value); + argument_values.PushValue(void_ptr_value); + } else { + obj_index = 0; + sel_index = 1; + argument_values.PushValue(void_ptr_value); + argument_values.PushValue(void_ptr_value); } - - if (found_it) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - // We are decoding a method dispatch. - // First job is to pull the arguments out: - - lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); - - const ABI *abi = NULL; - ProcessSP process_sp (thread.CalculateProcess()); - if (process_sp) - abi = process_sp->GetABI().get(); - if (abi == NULL) - return ret_plan_sp; - - TargetSP target_sp (thread.CalculateTarget()); - - ClangASTContext *clang_ast_context = target_sp->GetScratchClangASTContext(); - ValueList argument_values; - Value void_ptr_value; - CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - void_ptr_value.SetValueType (Value::eValueTypeScalar); - //void_ptr_value.SetContext (Value::eContextTypeClangType, clang_void_ptr_type); - void_ptr_value.SetCompilerType (clang_void_ptr_type); - - int obj_index; - int sel_index; - - // If this is a struct return dispatch, then the first argument is the - // return struct pointer, and the object is the second, and the selector is the third. - // Otherwise the object is the first and the selector the second. - if (this_dispatch.stret_return) - { - obj_index = 1; - sel_index = 2; - argument_values.PushValue(void_ptr_value); - argument_values.PushValue(void_ptr_value); - argument_values.PushValue(void_ptr_value); - } - else - { - obj_index = 0; - sel_index = 1; - argument_values.PushValue(void_ptr_value); - argument_values.PushValue(void_ptr_value); - } - - bool success = abi->GetArgumentValues (thread, argument_values); - if (!success) - return ret_plan_sp; - - lldb::addr_t obj_addr = argument_values.GetValueAtIndex(obj_index)->GetScalar().ULongLong(); - if (obj_addr == 0x0) - { - if (log) - log->Printf("Asked to step to dispatch to nil object, returning empty plan."); - return ret_plan_sp; - } - - ExecutionContext exe_ctx (thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - // isa_addr will store the class pointer that the method is being dispatched to - so either the class - // directly or the super class if this is one of the objc_msgSendSuper flavors. That's mostly used to - // look up the class/selector pair in our cache. - - lldb::addr_t isa_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t sel_addr = argument_values.GetValueAtIndex(sel_index)->GetScalar().ULongLong(); - - // Figure out the class this is being dispatched to and see if we've already cached this method call, - // If so we can push a run-to-address plan directly. Otherwise we have to figure out where - // the implementation lives. - - if (this_dispatch.is_super) - { - if (this_dispatch.is_super2) - { - // In the objc_msgSendSuper2 case, we don't get the object directly, we get a structure containing - // the object and the class to which the super message is being sent. So we need to dig the super - // out of the class and use that. - - Value super_value(*(argument_values.GetValueAtIndex(obj_index))); - super_value.GetScalar() += process->GetAddressByteSize(); - super_value.ResolveValue (&exe_ctx); - - if (super_value.GetScalar().IsValid()) - { - - // isa_value now holds the class pointer. The second word of the class pointer is the super-class pointer: - super_value.GetScalar() += process->GetAddressByteSize(); - super_value.ResolveValue (&exe_ctx); - if (super_value.GetScalar().IsValid()) - isa_addr = super_value.GetScalar().ULongLong(); - else - { - if (log) - log->Printf("Failed to extract the super class value from the class in objc_super."); - } - } - else - { - if (log) - log->Printf("Failed to extract the class value from objc_super."); - } - } - else - { - // In the objc_msgSendSuper case, we don't get the object directly, we get a two element structure containing - // the object and the super class to which the super message is being sent. So the class we want is - // the second element of this structure. - - Value super_value(*(argument_values.GetValueAtIndex(obj_index))); - super_value.GetScalar() += process->GetAddressByteSize(); - super_value.ResolveValue (&exe_ctx); - - if (super_value.GetScalar().IsValid()) - { - isa_addr = super_value.GetScalar().ULongLong(); - } - else - { - if (log) - log->Printf("Failed to extract the class value from objc_super."); - } - } - } - else - { - // In the direct dispatch case, the object->isa is the class pointer we want. - - // This is a little cheesy, but since object->isa is the first field, - // making the object value a load address value and resolving it will get - // the pointer sized data pointed to by that value... - - // Note, it isn't a fatal error not to be able to get the address from the object, since this might - // be a "tagged pointer" which isn't a real object, but rather some word length encoded dingus. - - Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); - - isa_value.SetValueType(Value::eValueTypeLoadAddress); - isa_value.ResolveValue(&exe_ctx); - if (isa_value.GetScalar().IsValid()) - { - isa_addr = isa_value.GetScalar().ULongLong(); - } - else - { - if (log) - log->Printf("Failed to extract the isa value from object."); - } + bool success = abi->GetArgumentValues(thread, argument_values); + if (!success) + return ret_plan_sp; - } - - // Okay, we've got the address of the class for which we're resolving this, let's see if it's in our cache: - lldb::addr_t impl_addr = LLDB_INVALID_ADDRESS; - - if (isa_addr != LLDB_INVALID_ADDRESS) - { - if (log) - { - log->Printf("Resolving call for class - 0x%" PRIx64 " and selector - 0x%" PRIx64, - isa_addr, sel_addr); - } - ObjCLanguageRuntime *objc_runtime = thread.GetProcess()->GetObjCLanguageRuntime (); - assert(objc_runtime != NULL); - - impl_addr = objc_runtime->LookupInMethodCache (isa_addr, sel_addr); - } - - if (impl_addr != LLDB_INVALID_ADDRESS) - { - // Yup, it was in the cache, so we can run to that address directly. - + lldb::addr_t obj_addr = + argument_values.GetValueAtIndex(obj_index)->GetScalar().ULongLong(); + if (obj_addr == 0x0) { + if (log) + log->Printf( + "Asked to step to dispatch to nil object, returning empty plan."); + return ret_plan_sp; + } + + ExecutionContext exe_ctx(thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + // isa_addr will store the class pointer that the method is being dispatched + // to - so either the class + // directly or the super class if this is one of the objc_msgSendSuper + // flavors. That's mostly used to + // look up the class/selector pair in our cache. + + lldb::addr_t isa_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t sel_addr = + argument_values.GetValueAtIndex(sel_index)->GetScalar().ULongLong(); + + // Figure out the class this is being dispatched to and see if we've already + // cached this method call, + // If so we can push a run-to-address plan directly. Otherwise we have to + // figure out where + // the implementation lives. + + if (this_dispatch.is_super) { + if (this_dispatch.is_super2) { + // In the objc_msgSendSuper2 case, we don't get the object directly, we + // get a structure containing + // the object and the class to which the super message is being sent. + // So we need to dig the super + // out of the class and use that. + + Value super_value(*(argument_values.GetValueAtIndex(obj_index))); + super_value.GetScalar() += process->GetAddressByteSize(); + super_value.ResolveValue(&exe_ctx); + + if (super_value.GetScalar().IsValid()) { + + // isa_value now holds the class pointer. The second word of the + // class pointer is the super-class pointer: + super_value.GetScalar() += process->GetAddressByteSize(); + super_value.ResolveValue(&exe_ctx); + if (super_value.GetScalar().IsValid()) + isa_addr = super_value.GetScalar().ULongLong(); + else { if (log) - log->Printf ("Found implementation address in cache: 0x%" PRIx64, impl_addr); - - ret_plan_sp.reset (new ThreadPlanRunToAddress (thread, impl_addr, stop_others)); + log->Printf("Failed to extract the super class value from the " + "class in objc_super."); + } + } else { + if (log) + log->Printf("Failed to extract the class value from objc_super."); } - else - { - // We haven't seen this class/selector pair yet. Look it up. - StreamString errors; - Address impl_code_address; - - ValueList dispatch_values; - - // We've will inject a little function in the target that takes the object, selector and some flags, - // and figures out the implementation. Looks like: - // void *__lldb_objc_find_implementation_for_selector (void *object, - // void *sel, - // int is_stret, - // int is_super, - // int is_super2, - // int is_fixup, - // int is_fixed, - // int debug) - // So set up the arguments for that call. - - dispatch_values.PushValue (*(argument_values.GetValueAtIndex(obj_index))); - dispatch_values.PushValue (*(argument_values.GetValueAtIndex(sel_index))); - - Value flag_value; - CompilerType clang_int_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingSint, 32); - flag_value.SetValueType (Value::eValueTypeScalar); - //flag_value.SetContext (Value::eContextTypeClangType, clang_int_type); - flag_value.SetCompilerType (clang_int_type); - - if (this_dispatch.stret_return) - flag_value.GetScalar() = 1; - else - flag_value.GetScalar() = 0; - dispatch_values.PushValue (flag_value); - - if (this_dispatch.is_super) - flag_value.GetScalar() = 1; - else - flag_value.GetScalar() = 0; - dispatch_values.PushValue (flag_value); - - if (this_dispatch.is_super2) - flag_value.GetScalar() = 1; - else - flag_value.GetScalar() = 0; - dispatch_values.PushValue (flag_value); - - switch (this_dispatch.fixedup) - { - case DispatchFunction::eFixUpNone: - flag_value.GetScalar() = 0; - dispatch_values.PushValue (flag_value); - dispatch_values.PushValue (flag_value); - break; - case DispatchFunction::eFixUpFixed: - flag_value.GetScalar() = 1; - dispatch_values.PushValue (flag_value); - flag_value.GetScalar() = 1; - dispatch_values.PushValue (flag_value); - break; - case DispatchFunction::eFixUpToFix: - flag_value.GetScalar() = 1; - dispatch_values.PushValue (flag_value); - flag_value.GetScalar() = 0; - dispatch_values.PushValue (flag_value); - break; - } - if (log && log->GetVerbose()) - flag_value.GetScalar() = 1; - else - flag_value.GetScalar() = 0; // FIXME - Set to 0 when debugging is done. - dispatch_values.PushValue (flag_value); - - - // The step through code might have to fill in the cache, so it is not safe to run only one thread. - // So we override the stop_others value passed in to us here: - const bool trampoline_stop_others = false; - ret_plan_sp.reset (new AppleThreadPlanStepThroughObjCTrampoline (thread, - this, - dispatch_values, - isa_addr, - sel_addr, - trampoline_stop_others)); - if (log) - { - StreamString s; - ret_plan_sp->GetDescription(&s, eDescriptionLevelFull); - log->Printf("Using ObjC step plan: %s.\n", s.GetData()); - } + } else { + // In the objc_msgSendSuper case, we don't get the object directly, we + // get a two element structure containing + // the object and the super class to which the super message is being + // sent. So the class we want is + // the second element of this structure. + + Value super_value(*(argument_values.GetValueAtIndex(obj_index))); + super_value.GetScalar() += process->GetAddressByteSize(); + super_value.ResolveValue(&exe_ctx); + + if (super_value.GetScalar().IsValid()) { + isa_addr = super_value.GetScalar().ULongLong(); + } else { + if (log) + log->Printf("Failed to extract the class value from objc_super."); } + } + } else { + // In the direct dispatch case, the object->isa is the class pointer we + // want. + + // This is a little cheesy, but since object->isa is the first field, + // making the object value a load address value and resolving it will get + // the pointer sized data pointed to by that value... + + // Note, it isn't a fatal error not to be able to get the address from the + // object, since this might + // be a "tagged pointer" which isn't a real object, but rather some word + // length encoded dingus. + + Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); + + isa_value.SetValueType(Value::eValueTypeLoadAddress); + isa_value.ResolveValue(&exe_ctx); + if (isa_value.GetScalar().IsValid()) { + isa_addr = isa_value.GetScalar().ULongLong(); + } else { + if (log) + log->Printf("Failed to extract the isa value from object."); + } } - - return ret_plan_sp; + + // Okay, we've got the address of the class for which we're resolving this, + // let's see if it's in our cache: + lldb::addr_t impl_addr = LLDB_INVALID_ADDRESS; + + if (isa_addr != LLDB_INVALID_ADDRESS) { + if (log) { + log->Printf("Resolving call for class - 0x%" PRIx64 + " and selector - 0x%" PRIx64, + isa_addr, sel_addr); + } + ObjCLanguageRuntime *objc_runtime = + thread.GetProcess()->GetObjCLanguageRuntime(); + assert(objc_runtime != NULL); + + impl_addr = objc_runtime->LookupInMethodCache(isa_addr, sel_addr); + } + + if (impl_addr != LLDB_INVALID_ADDRESS) { + // Yup, it was in the cache, so we can run to that address directly. + + if (log) + log->Printf("Found implementation address in cache: 0x%" PRIx64, + impl_addr); + + ret_plan_sp.reset( + new ThreadPlanRunToAddress(thread, impl_addr, stop_others)); + } else { + // We haven't seen this class/selector pair yet. Look it up. + StreamString errors; + Address impl_code_address; + + ValueList dispatch_values; + + // We've will inject a little function in the target that takes the + // object, selector and some flags, + // and figures out the implementation. Looks like: + // void *__lldb_objc_find_implementation_for_selector (void *object, + // void *sel, + // int is_stret, + // int is_super, + // int is_super2, + // int is_fixup, + // int is_fixed, + // int debug) + // So set up the arguments for that call. + + dispatch_values.PushValue(*(argument_values.GetValueAtIndex(obj_index))); + dispatch_values.PushValue(*(argument_values.GetValueAtIndex(sel_index))); + + Value flag_value; + CompilerType clang_int_type = + clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( + lldb::eEncodingSint, 32); + flag_value.SetValueType(Value::eValueTypeScalar); + // flag_value.SetContext (Value::eContextTypeClangType, clang_int_type); + flag_value.SetCompilerType(clang_int_type); + + if (this_dispatch.stret_return) + flag_value.GetScalar() = 1; + else + flag_value.GetScalar() = 0; + dispatch_values.PushValue(flag_value); + + if (this_dispatch.is_super) + flag_value.GetScalar() = 1; + else + flag_value.GetScalar() = 0; + dispatch_values.PushValue(flag_value); + + if (this_dispatch.is_super2) + flag_value.GetScalar() = 1; + else + flag_value.GetScalar() = 0; + dispatch_values.PushValue(flag_value); + + switch (this_dispatch.fixedup) { + case DispatchFunction::eFixUpNone: + flag_value.GetScalar() = 0; + dispatch_values.PushValue(flag_value); + dispatch_values.PushValue(flag_value); + break; + case DispatchFunction::eFixUpFixed: + flag_value.GetScalar() = 1; + dispatch_values.PushValue(flag_value); + flag_value.GetScalar() = 1; + dispatch_values.PushValue(flag_value); + break; + case DispatchFunction::eFixUpToFix: + flag_value.GetScalar() = 1; + dispatch_values.PushValue(flag_value); + flag_value.GetScalar() = 0; + dispatch_values.PushValue(flag_value); + break; + } + if (log && log->GetVerbose()) + flag_value.GetScalar() = 1; + else + flag_value.GetScalar() = 0; // FIXME - Set to 0 when debugging is done. + dispatch_values.PushValue(flag_value); + + // The step through code might have to fill in the cache, so it is not + // safe to run only one thread. + // So we override the stop_others value passed in to us here: + const bool trampoline_stop_others = false; + ret_plan_sp.reset(new AppleThreadPlanStepThroughObjCTrampoline( + thread, this, dispatch_values, isa_addr, sel_addr, + trampoline_stop_others)); + if (log) { + StreamString s; + ret_plan_sp->GetDescription(&s, eDescriptionLevelFull); + log->Printf("Using ObjC step plan: %s.\n", s.GetData()); + } + } + } + + return ret_plan_sp; } FunctionCaller * -AppleObjCTrampolineHandler::GetLookupImplementationFunctionCaller () -{ - return m_impl_code->GetFunctionCaller(); +AppleObjCTrampolineHandler::GetLookupImplementationFunctionCaller() { + return m_impl_code->GetFunctionCaller(); } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index c0d1944a7f2..dc58a8bc1eb 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -18,190 +18,143 @@ // Other libraries and framework includes // Project includes -#include "lldb/lldb-public.h" #include "lldb/Expression/UtilityFunction.h" +#include "lldb/lldb-public.h" + +namespace lldb_private { -namespace lldb_private -{ - class AppleObjCTrampolineHandler { public: - AppleObjCTrampolineHandler (const lldb::ProcessSP &process_sp, - const lldb::ModuleSP &objc_module_sp); - - ~AppleObjCTrampolineHandler(); - - lldb::ThreadPlanSP - GetStepThroughDispatchPlan (Thread &thread, - bool stop_others); - - FunctionCaller * - GetLookupImplementationFunctionCaller (); - - bool - AddrIsMsgForward (lldb::addr_t addr) const - { - return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr); - } - - struct DispatchFunction { - public: - typedef enum - { - eFixUpNone, - eFixUpFixed, - eFixUpToFix - } FixUpState; - - const char *name; - bool stret_return; - bool is_super; - bool is_super2; - FixUpState fixedup; - }; + AppleObjCTrampolineHandler(const lldb::ProcessSP &process_sp, + const lldb::ModuleSP &objc_module_sp); + + ~AppleObjCTrampolineHandler(); + + lldb::ThreadPlanSP GetStepThroughDispatchPlan(Thread &thread, + bool stop_others); + + FunctionCaller *GetLookupImplementationFunctionCaller(); + + bool AddrIsMsgForward(lldb::addr_t addr) const { + return (addr == m_msg_forward_addr || addr == m_msg_forward_stret_addr); + } - lldb::addr_t - SetupDispatchFunction (Thread &thread, ValueList &dispatch_values); + struct DispatchFunction { + public: + typedef enum { eFixUpNone, eFixUpFixed, eFixUpToFix } FixUpState; + + const char *name; + bool stret_return; + bool is_super; + bool is_super2; + FixUpState fixedup; + }; + + lldb::addr_t SetupDispatchFunction(Thread &thread, + ValueList &dispatch_values); private: - static const char *g_lookup_implementation_function_name; - static const char *g_lookup_implementation_with_stret_function_code; - static const char *g_lookup_implementation_no_stret_function_code; + static const char *g_lookup_implementation_function_name; + static const char *g_lookup_implementation_with_stret_function_code; + static const char *g_lookup_implementation_no_stret_function_code; + + class AppleObjCVTables { + public: + // These come from objc-gdb.h. + enum VTableFlags { + eOBJC_TRAMPOLINE_MESSAGE = (1 << 0), // trampoline acts like objc_msgSend + eOBJC_TRAMPOLINE_STRET = (1 << 1), // trampoline is struct-returning + eOBJC_TRAMPOLINE_VTABLE = (1 << 2) // trampoline is vtable dispatcher + }; + + private: + struct VTableDescriptor { + VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start) + : flags(in_flags), code_start(in_code_start) {} - class AppleObjCVTables - { + uint32_t flags; + lldb::addr_t code_start; + }; + + class VTableRegion { public: - // These come from objc-gdb.h. - enum VTableFlags - { - eOBJC_TRAMPOLINE_MESSAGE = (1<<0), // trampoline acts like objc_msgSend - eOBJC_TRAMPOLINE_STRET = (1<<1), // trampoline is struct-returning - eOBJC_TRAMPOLINE_VTABLE = (1<<2) // trampoline is vtable dispatcher - }; - - private: - struct VTableDescriptor - { - VTableDescriptor(uint32_t in_flags, lldb::addr_t in_code_start) : - flags(in_flags), - code_start(in_code_start) {} - - uint32_t flags; - lldb::addr_t code_start; - }; - - class VTableRegion - { - public: - VTableRegion() : - m_valid (false), - m_owner (NULL), - m_header_addr (LLDB_INVALID_ADDRESS), - m_code_start_addr(0), - m_code_end_addr (0), - m_next_region (0) - {} - - VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr); - - void SetUpRegion(); - - lldb::addr_t GetNextRegionAddr () - { - return m_next_region; - } - - lldb::addr_t - GetCodeStart () - { - return m_code_start_addr; - } - - lldb::addr_t - GetCodeEnd () - { - return m_code_end_addr; - } - - uint32_t - GetFlagsForVTableAtAddress (lldb::addr_t address) - { - return 0; - } - - bool - IsValid () - { - return m_valid; - } - - bool - AddressInRegion (lldb::addr_t addr, uint32_t &flags); - - void - Dump (Stream &s); - - public: - bool m_valid; - AppleObjCVTables *m_owner; - lldb::addr_t m_header_addr; - lldb::addr_t m_code_start_addr; - lldb::addr_t m_code_end_addr; - std::vector<VTableDescriptor> m_descriptors; - lldb::addr_t m_next_region; - }; - + VTableRegion() + : m_valid(false), m_owner(NULL), m_header_addr(LLDB_INVALID_ADDRESS), + m_code_start_addr(0), m_code_end_addr(0), m_next_region(0) {} + + VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr); + + void SetUpRegion(); + + lldb::addr_t GetNextRegionAddr() { return m_next_region; } + + lldb::addr_t GetCodeStart() { return m_code_start_addr; } + + lldb::addr_t GetCodeEnd() { return m_code_end_addr; } + + uint32_t GetFlagsForVTableAtAddress(lldb::addr_t address) { return 0; } + + bool IsValid() { return m_valid; } + + bool AddressInRegion(lldb::addr_t addr, uint32_t &flags); + + void Dump(Stream &s); + public: - AppleObjCVTables(const lldb::ProcessSP &process_sp, - const lldb::ModuleSP &objc_module_sp); - - ~AppleObjCVTables(); - - bool - InitializeVTableSymbols (); - - static bool RefreshTrampolines (void *baton, - StoppointCallbackContext *context, - lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); - bool - ReadRegions (); - - bool - ReadRegions (lldb::addr_t region_addr); - - bool - IsAddressInVTables (lldb::addr_t addr, uint32_t &flags); - - lldb::ProcessSP - GetProcessSP () - { - return m_process_wp.lock(); - } - - private: - lldb::ProcessWP m_process_wp; - typedef std::vector<VTableRegion> region_collection; - lldb::addr_t m_trampoline_header; - lldb::break_id_t m_trampolines_changed_bp_id; - region_collection m_regions; - lldb::ModuleSP m_objc_module_sp; + bool m_valid; + AppleObjCVTables *m_owner; + lldb::addr_t m_header_addr; + lldb::addr_t m_code_start_addr; + lldb::addr_t m_code_end_addr; + std::vector<VTableDescriptor> m_descriptors; + lldb::addr_t m_next_region; }; - - static const DispatchFunction g_dispatch_functions[]; - - typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch fn address to the index in g_dispatch_functions - MsgsendMap m_msgSend_map; + + public: + AppleObjCVTables(const lldb::ProcessSP &process_sp, + const lldb::ModuleSP &objc_module_sp); + + ~AppleObjCVTables(); + + bool InitializeVTableSymbols(); + + static bool RefreshTrampolines(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + bool ReadRegions(); + + bool ReadRegions(lldb::addr_t region_addr); + + bool IsAddressInVTables(lldb::addr_t addr, uint32_t &flags); + + lldb::ProcessSP GetProcessSP() { return m_process_wp.lock(); } + + private: lldb::ProcessWP m_process_wp; + typedef std::vector<VTableRegion> region_collection; + lldb::addr_t m_trampoline_header; + lldb::break_id_t m_trampolines_changed_bp_id; + region_collection m_regions; lldb::ModuleSP m_objc_module_sp; - const char *m_lookup_implementation_function_code; - std::unique_ptr<UtilityFunction> m_impl_code; - std::mutex m_impl_function_mutex; - lldb::addr_t m_impl_fn_addr; - lldb::addr_t m_impl_stret_fn_addr; - lldb::addr_t m_msg_forward_addr; - lldb::addr_t m_msg_forward_stret_addr; - std::unique_ptr<AppleObjCVTables> m_vtables_ap; + }; + + static const DispatchFunction g_dispatch_functions[]; + + typedef std::map<lldb::addr_t, int> MsgsendMap; // This table maps an dispatch + // fn address to the index in + // g_dispatch_functions + MsgsendMap m_msgSend_map; + lldb::ProcessWP m_process_wp; + lldb::ModuleSP m_objc_module_sp; + const char *m_lookup_implementation_function_code; + std::unique_ptr<UtilityFunction> m_impl_code; + std::mutex m_impl_function_mutex; + lldb::addr_t m_impl_fn_addr; + lldb::addr_t m_impl_stret_fn_addr; + lldb::addr_t m_msg_forward_addr; + lldb::addr_t m_msg_forward_stret_addr; + std::unique_ptr<AppleObjCVTables> m_vtables_ap; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index d4adc094bc1..ce78d4dccac 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -21,379 +21,377 @@ using namespace lldb_private; using namespace lldb_utility; -AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser (ObjCLanguageRuntime& runtime) : - ObjCLanguageRuntime::EncodingToType(), - m_runtime(runtime) -{ - if (!m_scratch_ast_ctx_ap) - m_scratch_ast_ctx_ap.reset(new ClangASTContext(runtime.GetProcess()->GetTarget().GetArchitecture().GetTriple().str().c_str())); +AppleObjCTypeEncodingParser::AppleObjCTypeEncodingParser( + ObjCLanguageRuntime &runtime) + : ObjCLanguageRuntime::EncodingToType(), m_runtime(runtime) { + if (!m_scratch_ast_ctx_ap) + m_scratch_ast_ctx_ap.reset(new ClangASTContext(runtime.GetProcess() + ->GetTarget() + .GetArchitecture() + .GetTriple() + .str() + .c_str())); } std::string -AppleObjCTypeEncodingParser::ReadStructName(lldb_utility::StringLexer& type) -{ - StreamString buffer; - while (type.HasAtLeast(1) && type.Peek() != '=') - buffer.Printf("%c",type.Next()); - return buffer.GetString(); +AppleObjCTypeEncodingParser::ReadStructName(lldb_utility::StringLexer &type) { + StreamString buffer; + while (type.HasAtLeast(1) && type.Peek() != '=') + buffer.Printf("%c", type.Next()); + return buffer.GetString(); } std::string -AppleObjCTypeEncodingParser::ReadQuotedString(lldb_utility::StringLexer& type) -{ - StreamString buffer; - while (type.HasAtLeast(1) && type.Peek() != '"') - buffer.Printf("%c",type.Next()); - StringLexer::Character next = type.Next(); - UNUSED_IF_ASSERT_DISABLED(next); - assert (next == '"'); - return buffer.GetString(); +AppleObjCTypeEncodingParser::ReadQuotedString(lldb_utility::StringLexer &type) { + StreamString buffer; + while (type.HasAtLeast(1) && type.Peek() != '"') + buffer.Printf("%c", type.Next()); + StringLexer::Character next = type.Next(); + UNUSED_IF_ASSERT_DISABLED(next); + assert(next == '"'); + return buffer.GetString(); } uint32_t -AppleObjCTypeEncodingParser::ReadNumber (lldb_utility::StringLexer& type) -{ - uint32_t total = 0; - while (type.HasAtLeast(1) && isdigit(type.Peek())) - total = 10*total + (type.Next() - '0'); - return total; +AppleObjCTypeEncodingParser::ReadNumber(lldb_utility::StringLexer &type) { + uint32_t total = 0; + while (type.HasAtLeast(1) && isdigit(type.Peek())) + total = 10 * total + (type.Next() - '0'); + return total; } -// as an extension to the published grammar recent runtimes emit structs like this: +// as an extension to the published grammar recent runtimes emit structs like +// this: // "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}" -AppleObjCTypeEncodingParser::StructElement::StructElement() : -name(""), -type(clang::QualType()), -bitfield(0) -{} +AppleObjCTypeEncodingParser::StructElement::StructElement() + : name(""), type(clang::QualType()), bitfield(0) {} AppleObjCTypeEncodingParser::StructElement -AppleObjCTypeEncodingParser::ReadStructElement (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression) -{ - StructElement retval; - if (type.NextIf('"')) - retval.name = ReadQuotedString(type); - if (!type.NextIf('"')) - return retval; - uint32_t bitfield_size = 0; - retval.type = BuildType(ast_ctx, type, for_expression, &bitfield_size); - retval.bitfield = bitfield_size; +AppleObjCTypeEncodingParser::ReadStructElement(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression) { + StructElement retval; + if (type.NextIf('"')) + retval.name = ReadQuotedString(type); + if (!type.NextIf('"')) return retval; + uint32_t bitfield_size = 0; + retval.type = BuildType(ast_ctx, type, for_expression, &bitfield_size); + retval.bitfield = bitfield_size; + return retval; } clang::QualType -AppleObjCTypeEncodingParser::BuildStruct (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression) -{ - return BuildAggregate(ast_ctx, type, for_expression, '{', '}', clang::TTK_Struct); +AppleObjCTypeEncodingParser::BuildStruct(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression) { + return BuildAggregate(ast_ctx, type, for_expression, '{', '}', + clang::TTK_Struct); } clang::QualType -AppleObjCTypeEncodingParser::BuildUnion (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression) -{ - return BuildAggregate(ast_ctx, type, for_expression, '(', ')', clang::TTK_Union); +AppleObjCTypeEncodingParser::BuildUnion(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression) { + return BuildAggregate(ast_ctx, type, for_expression, '(', ')', + clang::TTK_Union); } -clang::QualType -AppleObjCTypeEncodingParser::BuildAggregate (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression, char opener, char closer, uint32_t kind) -{ - if (!type.NextIf(opener)) - return clang::QualType(); - std::string name(ReadStructName(type)); - - // We do not handle templated classes/structs at the moment. - // If the name has a < in it, we are going to abandon this. - // We're still obliged to parse it, so we just set a flag that - // means "Don't actually build anything." - - const bool is_templated = name.find('<') != std::string::npos; - - if (!type.NextIf('=')) - return clang::QualType(); - bool in_union = true; - std::vector<StructElement> elements; - while (in_union && type.HasAtLeast(1)) - { - if (type.NextIf(closer)) - { - in_union = false; - break; - } - else - { - auto element = ReadStructElement(ast_ctx, type, for_expression); - if (element.type.isNull()) - break; - else - elements.push_back(element); - } +clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( + clang::ASTContext &ast_ctx, lldb_utility::StringLexer &type, + bool for_expression, char opener, char closer, uint32_t kind) { + if (!type.NextIf(opener)) + return clang::QualType(); + std::string name(ReadStructName(type)); + + // We do not handle templated classes/structs at the moment. + // If the name has a < in it, we are going to abandon this. + // We're still obliged to parse it, so we just set a flag that + // means "Don't actually build anything." + + const bool is_templated = name.find('<') != std::string::npos; + + if (!type.NextIf('=')) + return clang::QualType(); + bool in_union = true; + std::vector<StructElement> elements; + while (in_union && type.HasAtLeast(1)) { + if (type.NextIf(closer)) { + in_union = false; + break; + } else { + auto element = ReadStructElement(ast_ctx, type, for_expression); + if (element.type.isNull()) + break; + else + elements.push_back(element); } - if (in_union) - return clang::QualType(); - - if (is_templated) - return clang::QualType(); // This is where we bail out. Sorry! - - ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - if (!lldb_ctx) - return clang::QualType(); - CompilerType union_type(lldb_ctx->CreateRecordType(nullptr, lldb::eAccessPublic, name.c_str(), kind, lldb::eLanguageTypeC)); - if (union_type) - { - ClangASTContext::StartTagDeclarationDefinition(union_type); - - unsigned int count = 0; - for (auto element: elements) - { - if (element.name.empty()) - { - StreamString elem_name; - elem_name.Printf("__unnamed_%u",count); - element.name = std::string(elem_name.GetData()); - } - ClangASTContext::AddFieldToRecordType(union_type, element.name.c_str(), CompilerType(&ast_ctx, element.type), lldb::eAccessPublic, element.bitfield); - ++count; - } - ClangASTContext::CompleteTagDeclarationDefinition(union_type); + } + if (in_union) + return clang::QualType(); + + if (is_templated) + return clang::QualType(); // This is where we bail out. Sorry! + + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + CompilerType union_type(lldb_ctx->CreateRecordType( + nullptr, lldb::eAccessPublic, name.c_str(), kind, lldb::eLanguageTypeC)); + if (union_type) { + ClangASTContext::StartTagDeclarationDefinition(union_type); + + unsigned int count = 0; + for (auto element : elements) { + if (element.name.empty()) { + StreamString elem_name; + elem_name.Printf("__unnamed_%u", count); + element.name = std::string(elem_name.GetData()); + } + ClangASTContext::AddFieldToRecordType( + union_type, element.name.c_str(), + CompilerType(&ast_ctx, element.type), lldb::eAccessPublic, + element.bitfield); + ++count; } - return ClangUtil::GetQualType(union_type); + ClangASTContext::CompleteTagDeclarationDefinition(union_type); + } + return ClangUtil::GetQualType(union_type); } clang::QualType -AppleObjCTypeEncodingParser::BuildArray (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression) -{ - if (!type.NextIf('[')) - return clang::QualType(); - uint32_t size = ReadNumber(type); - clang::QualType element_type(BuildType(ast_ctx, type, for_expression)); - if (!type.NextIf(']')) - return clang::QualType(); - ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - if (!lldb_ctx) - return clang::QualType(); - CompilerType array_type(lldb_ctx->CreateArrayType(CompilerType(&ast_ctx, element_type), size, false)); - return ClangUtil::GetQualType(array_type); +AppleObjCTypeEncodingParser::BuildArray(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression) { + if (!type.NextIf('[')) + return clang::QualType(); + uint32_t size = ReadNumber(type); + clang::QualType element_type(BuildType(ast_ctx, type, for_expression)); + if (!type.NextIf(']')) + return clang::QualType(); + ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + if (!lldb_ctx) + return clang::QualType(); + CompilerType array_type(lldb_ctx->CreateArrayType( + CompilerType(&ast_ctx, element_type), size, false)); + return ClangUtil::GetQualType(array_type); } // the runtime can emit these in the form of @"SomeType", giving more specifics -// this would be interesting for expression parser interop, but since we actually try -// to avoid exposing the ivar info to the expression evaluator, consume but ignore the type info -// and always return an 'id'; if anything, dynamic typing will resolve things for us anyway -clang::QualType -AppleObjCTypeEncodingParser::BuildObjCObjectPointerType (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression) -{ - if (!type.NextIf('@')) - return clang::QualType(); - - std::string name; - - if (type.NextIf('"')) - { - // We have to be careful here. We're used to seeing - // @"NSString" - // but in records it is possible that the string following an @ is the name of the next field and @ means "id". - // This is the case if anything unquoted except for "}", the end of the type, or another name follows the quoted string. - // - // E.g. - // - @"NSString"@ means "id, followed by a field named NSString of type id" - // - @"NSString"} means "a pointer to NSString and the end of the struct" - // - @"NSString""nextField" means "a pointer to NSString and a field named nextField" - // - @"NSString" followed by the end of the string means "a pointer to NSString" - // - // As a result, the rule is: If we see @ followed by a quoted string, we peek. - // - If we see }, ), ], the end of the string, or a quote ("), the quoted string is a class name. - // - If we see anything else, the quoted string is a field name and we push it back onto type. - - name = ReadQuotedString(type); - - if (type.HasAtLeast(1)) - { - switch (type.Peek()) - { - default: - // roll back - type.PutBack(name.length() + 2); // undo our consumption of the string and of the quotes - name.clear(); - break; - case '}': - case ')': - case ']': - case '"': - // the quoted string is a class name – see the rule - break; - } - } - else - { - // the quoted string is a class name – see the rule - } +// this would be interesting for expression parser interop, but since we +// actually try +// to avoid exposing the ivar info to the expression evaluator, consume but +// ignore the type info +// and always return an 'id'; if anything, dynamic typing will resolve things +// for us anyway +clang::QualType AppleObjCTypeEncodingParser::BuildObjCObjectPointerType( + clang::ASTContext &ast_ctx, lldb_utility::StringLexer &type, + bool for_expression) { + if (!type.NextIf('@')) + return clang::QualType(); + + std::string name; + + if (type.NextIf('"')) { + // We have to be careful here. We're used to seeing + // @"NSString" + // but in records it is possible that the string following an @ is the name + // of the next field and @ means "id". + // This is the case if anything unquoted except for "}", the end of the + // type, or another name follows the quoted string. + // + // E.g. + // - @"NSString"@ means "id, followed by a field named NSString of type id" + // - @"NSString"} means "a pointer to NSString and the end of the struct" + // - @"NSString""nextField" means "a pointer to NSString and a field named + // nextField" + // - @"NSString" followed by the end of the string means "a pointer to + // NSString" + // + // As a result, the rule is: If we see @ followed by a quoted string, we + // peek. + // - If we see }, ), ], the end of the string, or a quote ("), the quoted + // string is a class name. + // - If we see anything else, the quoted string is a field name and we push + // it back onto type. + + name = ReadQuotedString(type); + + if (type.HasAtLeast(1)) { + switch (type.Peek()) { + default: + // roll back + type.PutBack(name.length() + + 2); // undo our consumption of the string and of the quotes + name.clear(); + break; + case '}': + case ')': + case ']': + case '"': + // the quoted string is a class name – see the rule + break; + } + } else { + // the quoted string is a class name – see the rule + } + } + + if (for_expression && !name.empty()) { + size_t less_than_pos = name.find('<'); + + if (less_than_pos != std::string::npos) { + if (less_than_pos == 0) + return ast_ctx.getObjCIdType(); + else + name.erase(less_than_pos); } - - if (for_expression && !name.empty()) - { - size_t less_than_pos = name.find('<'); - - if (less_than_pos != std::string::npos) - { - if (less_than_pos == 0) - return ast_ctx.getObjCIdType(); - else - name.erase(less_than_pos); - } - - DeclVendor *decl_vendor = m_runtime.GetDeclVendor(); - - assert (decl_vendor); // how are we parsing type encodings for expressions if a type vendor isn't in play? - - const bool append = false; - const uint32_t max_matches = 1; - std::vector<clang::NamedDecl *> decls; - - uint32_t num_types = decl_vendor->FindDecls(ConstString(name), - append, - max_matches, - decls); - - // The user can forward-declare something that has no definition. The runtime doesn't prohibit this at all. - // This is a rare and very weird case. We keep this assert in debug builds so we catch other weird cases. + + DeclVendor *decl_vendor = m_runtime.GetDeclVendor(); + + assert(decl_vendor); // how are we parsing type encodings for expressions if + // a type vendor isn't in play? + + const bool append = false; + const uint32_t max_matches = 1; + std::vector<clang::NamedDecl *> decls; + + uint32_t num_types = + decl_vendor->FindDecls(ConstString(name), append, max_matches, decls); + +// The user can forward-declare something that has no definition. The runtime +// doesn't prohibit this at all. +// This is a rare and very weird case. We keep this assert in debug builds so +// we catch other weird cases. #ifdef LLDB_CONFIGURATION_DEBUG - assert(num_types); + assert(num_types); #else - if (!num_types) - return ast_ctx.getObjCIdType(); + if (!num_types) + return ast_ctx.getObjCIdType(); #endif - return ClangUtil::GetQualType(ClangASTContext::GetTypeForDecl(decls[0]).GetPointerType()); - } - else - { - // We're going to resolve this dynamically anyway, so just smile and wave. - return ast_ctx.getObjCIdType(); - } + return ClangUtil::GetQualType( + ClangASTContext::GetTypeForDecl(decls[0]).GetPointerType()); + } else { + // We're going to resolve this dynamically anyway, so just smile and wave. + return ast_ctx.getObjCIdType(); + } } clang::QualType -AppleObjCTypeEncodingParser::BuildType (clang::ASTContext &ast_ctx, StringLexer& type, bool for_expression, uint32_t *bitfield_bit_size) -{ - if (!type.HasAtLeast(1)) - return clang::QualType(); - - switch (type.Peek()) - { - default: - break; - case '{': - return BuildStruct(ast_ctx, type, for_expression); - case '[': - return BuildArray(ast_ctx, type, for_expression); - case '(': - return BuildUnion(ast_ctx, type, for_expression); - case '@': - return BuildObjCObjectPointerType(ast_ctx, type, for_expression); - } - - switch (type.Next()) - { - default: - type.PutBack(1); +AppleObjCTypeEncodingParser::BuildType(clang::ASTContext &ast_ctx, + StringLexer &type, bool for_expression, + uint32_t *bitfield_bit_size) { + if (!type.HasAtLeast(1)) + return clang::QualType(); + + switch (type.Peek()) { + default: + break; + case '{': + return BuildStruct(ast_ctx, type, for_expression); + case '[': + return BuildArray(ast_ctx, type, for_expression); + case '(': + return BuildUnion(ast_ctx, type, for_expression); + case '@': + return BuildObjCObjectPointerType(ast_ctx, type, for_expression); + } + + switch (type.Next()) { + default: + type.PutBack(1); + return clang::QualType(); + case 'c': + return ast_ctx.CharTy; + case 'i': + return ast_ctx.IntTy; + case 's': + return ast_ctx.ShortTy; + case 'l': + return ast_ctx.getIntTypeForBitwidth(32, true); + // this used to be done like this: + // ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); + // if (!lldb_ctx) + // return clang::QualType(); + // return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); + // which uses one of the constants if one is available, but we don't think all + // this work is necessary. + case 'q': + return ast_ctx.LongLongTy; + case 'C': + return ast_ctx.UnsignedCharTy; + case 'I': + return ast_ctx.UnsignedIntTy; + case 'S': + return ast_ctx.UnsignedShortTy; + case 'L': + return ast_ctx.getIntTypeForBitwidth(32, false); + // see note for 'l' + case 'Q': + return ast_ctx.UnsignedLongLongTy; + case 'f': + return ast_ctx.FloatTy; + case 'd': + return ast_ctx.DoubleTy; + case 'B': + return ast_ctx.BoolTy; + case 'v': + return ast_ctx.VoidTy; + case '*': + return ast_ctx.getPointerType(ast_ctx.CharTy); + case '#': + return ast_ctx.getObjCClassType(); + case ':': + return ast_ctx.getObjCSelType(); + case 'b': { + uint32_t size = ReadNumber(type); + if (bitfield_bit_size) { + *bitfield_bit_size = size; + return ast_ctx.UnsignedIntTy; // FIXME: the spec is fairly vague here. + } else + return clang::QualType(); + } + case 'r': { + clang::QualType target_type = BuildType(ast_ctx, type, for_expression); + if (target_type.isNull()) + return clang::QualType(); + else if (target_type == ast_ctx.UnknownAnyTy) + return ast_ctx.UnknownAnyTy; + else + return ast_ctx.getConstType(target_type); + } + case '^': { + if (!for_expression && type.NextIf('?')) { + // if we are not supporting the concept of unknownAny, but what is being + // created here is an unknownAny*, then + // we can just get away with a void* + // this is theoretically wrong (in the same sense as 'theoretically + // nothing exists') but is way better than outright failure + // in many practical cases + return ast_ctx.VoidPtrTy; + } else { + clang::QualType target_type = BuildType(ast_ctx, type, for_expression); + if (target_type.isNull()) return clang::QualType(); - case 'c': - return ast_ctx.CharTy; - case 'i': - return ast_ctx.IntTy; - case 's': - return ast_ctx.ShortTy; - case 'l': - return ast_ctx.getIntTypeForBitwidth(32, true); - // this used to be done like this: - // ClangASTContext *lldb_ctx = ClangASTContext::GetASTContext(&ast_ctx); - // if (!lldb_ctx) - // return clang::QualType(); - // return lldb_ctx->GetIntTypeFromBitSize(32, true).GetQualType(); - // which uses one of the constants if one is available, but we don't think all this work is necessary. - case 'q': - return ast_ctx.LongLongTy; - case 'C': - return ast_ctx.UnsignedCharTy; - case 'I': - return ast_ctx.UnsignedIntTy; - case 'S': - return ast_ctx.UnsignedShortTy; - case 'L': - return ast_ctx.getIntTypeForBitwidth(32, false); - // see note for 'l' - case 'Q': - return ast_ctx.UnsignedLongLongTy; - case 'f': - return ast_ctx.FloatTy; - case 'd': - return ast_ctx.DoubleTy; - case 'B': - return ast_ctx.BoolTy; - case 'v': - return ast_ctx.VoidTy; - case '*': - return ast_ctx.getPointerType(ast_ctx.CharTy); - case '#': - return ast_ctx.getObjCClassType(); - case ':': - return ast_ctx.getObjCSelType(); - case 'b': - { - uint32_t size = ReadNumber(type); - if (bitfield_bit_size) - { - *bitfield_bit_size = size; - return ast_ctx.UnsignedIntTy; // FIXME: the spec is fairly vague here. - } - else - return clang::QualType(); - } - case 'r': - { - clang::QualType target_type = BuildType(ast_ctx, type, for_expression); - if (target_type.isNull()) - return clang::QualType(); - else if (target_type == ast_ctx.UnknownAnyTy) - return ast_ctx.UnknownAnyTy; - else - return ast_ctx.getConstType(target_type); - } - case '^': - { - if (!for_expression && type.NextIf('?')) - { - // if we are not supporting the concept of unknownAny, but what is being created here is an unknownAny*, then - // we can just get away with a void* - // this is theoretically wrong (in the same sense as 'theoretically nothing exists') but is way better than outright failure - // in many practical cases - return ast_ctx.VoidPtrTy; - } - else - { - clang::QualType target_type = BuildType(ast_ctx, type, for_expression); - if (target_type.isNull()) - return clang::QualType(); - else if (target_type == ast_ctx.UnknownAnyTy) - return ast_ctx.UnknownAnyTy; - else - return ast_ctx.getPointerType(target_type); - } - } - case '?': - return for_expression ? ast_ctx.UnknownAnyTy : clang::QualType(); + else if (target_type == ast_ctx.UnknownAnyTy) + return ast_ctx.UnknownAnyTy; + else + return ast_ctx.getPointerType(target_type); } + } + case '?': + return for_expression ? ast_ctx.UnknownAnyTy : clang::QualType(); + } } -CompilerType -AppleObjCTypeEncodingParser::RealizeType (clang::ASTContext &ast_ctx, const char* name, bool for_expression) -{ - if (name && name[0]) - { - StringLexer lexer(name); - clang::QualType qual_type = BuildType(ast_ctx, lexer, for_expression); - return CompilerType(&ast_ctx, qual_type); - } - return CompilerType(); +CompilerType AppleObjCTypeEncodingParser::RealizeType( + clang::ASTContext &ast_ctx, const char *name, bool for_expression) { + if (name && name[0]) { + StringLexer lexer(name); + clang::QualType qual_type = BuildType(ast_ctx, lexer, for_expression); + return CompilerType(&ast_ctx, qual_type); + } + return CompilerType(); } - diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h index 87c49cbc05b..4da84dd92c3 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -16,66 +16,72 @@ #include "clang/AST/ASTContext.h" // Project includes -#include "lldb/lldb-private.h" #include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/lldb-private.h" namespace lldb_utility { - class StringLexer; +class StringLexer; } namespace lldb_private { - class AppleObjCTypeEncodingParser : public ObjCLanguageRuntime::EncodingToType - { - public: - AppleObjCTypeEncodingParser (ObjCLanguageRuntime& runtime); - ~AppleObjCTypeEncodingParser() override = default; - - CompilerType RealizeType(clang::ASTContext &ast_ctx, const char* name, bool for_expression) override; - - private: - struct StructElement { - std::string name; - clang::QualType type; - uint32_t bitfield; - - StructElement (); - ~StructElement () = default; - }; - - clang::QualType - BuildType (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression, uint32_t *bitfield_bit_size = nullptr); - - clang::QualType - BuildStruct (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression); - - clang::QualType - BuildAggregate (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression, char opener, char closer, uint32_t kind); - - clang::QualType - BuildUnion (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression); - - clang::QualType - BuildArray (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression); - - std::string - ReadStructName(lldb_utility::StringLexer& type); - - StructElement - ReadStructElement (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression); - - clang::QualType - BuildObjCObjectPointerType (clang::ASTContext &ast_ctx, lldb_utility::StringLexer& type, bool for_expression); - - uint32_t - ReadNumber (lldb_utility::StringLexer& type); - - std::string - ReadQuotedString(lldb_utility::StringLexer& type); - - ObjCLanguageRuntime& m_runtime; - }; - +class AppleObjCTypeEncodingParser : public ObjCLanguageRuntime::EncodingToType { +public: + AppleObjCTypeEncodingParser(ObjCLanguageRuntime &runtime); + ~AppleObjCTypeEncodingParser() override = default; + + CompilerType RealizeType(clang::ASTContext &ast_ctx, const char *name, + bool for_expression) override; + +private: + struct StructElement { + std::string name; + clang::QualType type; + uint32_t bitfield; + + StructElement(); + ~StructElement() = default; + }; + + clang::QualType BuildType(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression, + uint32_t *bitfield_bit_size = nullptr); + + clang::QualType BuildStruct(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression); + + clang::QualType BuildAggregate(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression, char opener, char closer, + uint32_t kind); + + clang::QualType BuildUnion(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression); + + clang::QualType BuildArray(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression); + + std::string ReadStructName(lldb_utility::StringLexer &type); + + StructElement ReadStructElement(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression); + + clang::QualType BuildObjCObjectPointerType(clang::ASTContext &ast_ctx, + lldb_utility::StringLexer &type, + bool for_expression); + + uint32_t ReadNumber(lldb_utility::StringLexer &type); + + std::string ReadQuotedString(lldb_utility::StringLexer &type); + + ObjCLanguageRuntime &m_runtime; +}; + } // namespace lldb_private #endif // liblldb_AppleObjCTypeEncodingParser_h_ diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index a2101c927b4..e4926953232 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -1,4 +1,5 @@ -//===-- AppleThreadPlanStepThroughObjCTrampoline.cpp --------------------------*- C++ -*-===// +//===-- AppleThreadPlanStepThroughObjCTrampoline.cpp +//--------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -30,212 +31,183 @@ using namespace lldb_private; //---------------------------------------------------------------------- // ThreadPlanStepThroughObjCTrampoline constructor //---------------------------------------------------------------------- -AppleThreadPlanStepThroughObjCTrampoline::AppleThreadPlanStepThroughObjCTrampoline -( - Thread &thread, - AppleObjCTrampolineHandler *trampoline_handler, - ValueList &input_values, - lldb::addr_t isa_addr, - lldb::addr_t sel_addr, - bool stop_others -) : - ThreadPlan (ThreadPlan::eKindGeneric, - "MacOSX Step through ObjC Trampoline", - thread, - eVoteNoOpinion, - eVoteNoOpinion), - m_trampoline_handler (trampoline_handler), - m_args_addr (LLDB_INVALID_ADDRESS), - m_input_values (input_values), - m_isa_addr(isa_addr), - m_sel_addr(sel_addr), - m_impl_function (NULL), - m_stop_others (stop_others) -{ - -} +AppleThreadPlanStepThroughObjCTrampoline:: + AppleThreadPlanStepThroughObjCTrampoline( + Thread &thread, AppleObjCTrampolineHandler *trampoline_handler, + ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, + bool stop_others) + : ThreadPlan(ThreadPlan::eKindGeneric, + "MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion, + eVoteNoOpinion), + m_trampoline_handler(trampoline_handler), + m_args_addr(LLDB_INVALID_ADDRESS), m_input_values(input_values), + m_isa_addr(isa_addr), m_sel_addr(sel_addr), m_impl_function(NULL), + m_stop_others(stop_others) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -AppleThreadPlanStepThroughObjCTrampoline::~AppleThreadPlanStepThroughObjCTrampoline() -{ +AppleThreadPlanStepThroughObjCTrampoline:: + ~AppleThreadPlanStepThroughObjCTrampoline() {} + +void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { + // Setting up the memory space for the called function text might require + // allocations, + // i.e. a nested function call. This needs to be done as a PreResumeAction. + m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller, + (void *)this); } -void -AppleThreadPlanStepThroughObjCTrampoline::DidPush () -{ - // Setting up the memory space for the called function text might require allocations, - // i.e. a nested function call. This needs to be done as a PreResumeAction. - m_thread.GetProcess()->AddPreResumeAction (PreResumeInitializeFunctionCaller, (void *) this); -} +bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { + if (!m_func_sp) { + DiagnosticManager diagnostics; + m_args_addr = + m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values); -bool -AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller () -{ - if (!m_func_sp) - { - DiagnosticManager diagnostics; - m_args_addr = m_trampoline_handler->SetupDispatchFunction(m_thread, m_input_values); - - if (m_args_addr == LLDB_INVALID_ADDRESS) - { - return false; - } - m_impl_function = m_trampoline_handler->GetLookupImplementationFunctionCaller(); - ExecutionContext exc_ctx; - EvaluateExpressionOptions options; - options.SetUnwindOnError(true); - options.SetIgnoreBreakpoints(true); - options.SetStopOthers(m_stop_others); - m_thread.CalculateExecutionContext(exc_ctx); - m_func_sp = m_impl_function->GetThreadPlanToCallFunction(exc_ctx, m_args_addr, options, diagnostics); - m_func_sp->SetOkayToDiscard(true); - m_thread.QueueThreadPlan(m_func_sp, false); + if (m_args_addr == LLDB_INVALID_ADDRESS) { + return false; } - return true; + m_impl_function = + m_trampoline_handler->GetLookupImplementationFunctionCaller(); + ExecutionContext exc_ctx; + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetStopOthers(m_stop_others); + m_thread.CalculateExecutionContext(exc_ctx); + m_func_sp = m_impl_function->GetThreadPlanToCallFunction( + exc_ctx, m_args_addr, options, diagnostics); + m_func_sp->SetOkayToDiscard(true); + m_thread.QueueThreadPlan(m_func_sp, false); + } + return true; } -bool -AppleThreadPlanStepThroughObjCTrampoline::PreResumeInitializeFunctionCaller(void *void_myself) -{ - AppleThreadPlanStepThroughObjCTrampoline *myself = static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself); - return myself->InitializeFunctionCaller(); +bool AppleThreadPlanStepThroughObjCTrampoline:: + PreResumeInitializeFunctionCaller(void *void_myself) { + AppleThreadPlanStepThroughObjCTrampoline *myself = + static_cast<AppleThreadPlanStepThroughObjCTrampoline *>(void_myself); + return myself->InitializeFunctionCaller(); } -void -AppleThreadPlanStepThroughObjCTrampoline::GetDescription (Stream *s, - lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - s->Printf("Step through ObjC trampoline"); - else - { - s->Printf ("Stepping to implementation of ObjC method - obj: 0x%llx, isa: 0x%" PRIx64 ", sel: 0x%" PRIx64, - m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(), m_isa_addr, m_sel_addr); - } +void AppleThreadPlanStepThroughObjCTrampoline::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) + s->Printf("Step through ObjC trampoline"); + else { + s->Printf("Stepping to implementation of ObjC method - obj: 0x%llx, isa: " + "0x%" PRIx64 ", sel: 0x%" PRIx64, + m_input_values.GetValueAtIndex(0)->GetScalar().ULongLong(), + m_isa_addr, m_sel_addr); + } } - -bool -AppleThreadPlanStepThroughObjCTrampoline::ValidatePlan (Stream *error) -{ - return true; + +bool AppleThreadPlanStepThroughObjCTrampoline::ValidatePlan(Stream *error) { + return true; } -bool -AppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop (Event *event_ptr) -{ - // If we get asked to explain the stop it will be because something went - // wrong (like the implementation for selector function crashed... We're going - // to figure out what to do about that, so we do explain the stop. - return true; +bool AppleThreadPlanStepThroughObjCTrampoline::DoPlanExplainsStop( + Event *event_ptr) { + // If we get asked to explain the stop it will be because something went + // wrong (like the implementation for selector function crashed... We're + // going + // to figure out what to do about that, so we do explain the stop. + return true; } -lldb::StateType -AppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState () -{ - return eStateRunning; +lldb::StateType AppleThreadPlanStepThroughObjCTrampoline::GetPlanRunState() { + return eStateRunning; } -bool -AppleThreadPlanStepThroughObjCTrampoline::ShouldStop (Event *event_ptr) -{ - // First stage: we are still handling the "call a function to get the target of the dispatch" - if (m_func_sp) - { - if (!m_func_sp->IsPlanComplete()) - { - return false; - } - else - { - if (!m_func_sp->PlanSucceeded()) - { - SetPlanComplete(false); - return true; - } - m_func_sp.reset(); - } +bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { + // First stage: we are still handling the "call a function to get the target + // of the dispatch" + if (m_func_sp) { + if (!m_func_sp->IsPlanComplete()) { + return false; + } else { + if (!m_func_sp->PlanSucceeded()) { + SetPlanComplete(false); + return true; + } + m_func_sp.reset(); } - - // Second stage, if all went well with the function calling, then fetch the target address, and - // queue up a "run to that address" plan. - if (!m_run_to_sp) - { - Value target_addr_value; - ExecutionContext exc_ctx; - m_thread.CalculateExecutionContext(exc_ctx); - m_impl_function->FetchFunctionResults (exc_ctx, m_args_addr, target_addr_value); - m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); - lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong(); - Address target_so_addr; - target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr()); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (target_addr == 0) - { - if (log) - log->Printf("Got target implementation of 0x0, stopping."); - SetPlanComplete(); - return true; - } - if (m_trampoline_handler->AddrIsMsgForward(target_addr)) - { - if (log) - log->Printf ("Implementation lookup returned msgForward function: 0x%" PRIx64 ", stopping.", target_addr); - - SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext(eSymbolContextEverything); - const bool abort_other_plans = false; - const bool first_insn = true; - const uint32_t frame_idx = 0; - m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (abort_other_plans, - &sc, - first_insn, - m_stop_others, - eVoteNoOpinion, - eVoteNoOpinion, - frame_idx); - m_run_to_sp->SetPrivate(true); - return false; - } - - if (log) - log->Printf("Running to ObjC method implementation: 0x%" PRIx64, target_addr); - - ObjCLanguageRuntime *objc_runtime = GetThread().GetProcess()->GetObjCLanguageRuntime(); - assert (objc_runtime != NULL); - objc_runtime->AddToMethodCache (m_isa_addr, m_sel_addr, target_addr); - if (log) - log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64 "} = addr=0x%" PRIx64 " to cache.", m_isa_addr, m_sel_addr, target_addr); - - // Extract the target address from the value: - - m_run_to_sp.reset(new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others)); - m_thread.QueueThreadPlan(m_run_to_sp, false); - m_run_to_sp->SetPrivate(true); - return false; + } + + // Second stage, if all went well with the function calling, then fetch the + // target address, and + // queue up a "run to that address" plan. + if (!m_run_to_sp) { + Value target_addr_value; + ExecutionContext exc_ctx; + m_thread.CalculateExecutionContext(exc_ctx); + m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr, + target_addr_value); + m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); + lldb::addr_t target_addr = target_addr_value.GetScalar().ULongLong(); + Address target_so_addr; + target_so_addr.SetOpcodeLoadAddress(target_addr, exc_ctx.GetTargetPtr()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (target_addr == 0) { + if (log) + log->Printf("Got target implementation of 0x0, stopping."); + SetPlanComplete(); + return true; } - else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) - { - // Third stage, work the run to target plan. - SetPlanComplete(); - return true; + if (m_trampoline_handler->AddrIsMsgForward(target_addr)) { + if (log) + log->Printf( + "Implementation lookup returned msgForward function: 0x%" PRIx64 + ", stopping.", + target_addr); + + SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext( + eSymbolContextEverything); + const bool abort_other_plans = false; + const bool first_insn = true; + const uint32_t frame_idx = 0; + m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, + eVoteNoOpinion, frame_idx); + m_run_to_sp->SetPrivate(true); + return false; } + + if (log) + log->Printf("Running to ObjC method implementation: 0x%" PRIx64, + target_addr); + + ObjCLanguageRuntime *objc_runtime = + GetThread().GetProcess()->GetObjCLanguageRuntime(); + assert(objc_runtime != NULL); + objc_runtime->AddToMethodCache(m_isa_addr, m_sel_addr, target_addr); + if (log) + log->Printf("Adding {isa-addr=0x%" PRIx64 ", sel-addr=0x%" PRIx64 + "} = addr=0x%" PRIx64 " to cache.", + m_isa_addr, m_sel_addr, target_addr); + + // Extract the target address from the value: + + m_run_to_sp.reset( + new ThreadPlanRunToAddress(m_thread, target_so_addr, m_stop_others)); + m_thread.QueueThreadPlan(m_run_to_sp, false); + m_run_to_sp->SetPrivate(true); return false; + } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) { + // Third stage, work the run to target plan. + SetPlanComplete(); + return true; + } + return false; } // The base class MischiefManaged does some cleanup - so you have to call it // in your MischiefManaged derived class. -bool -AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged () -{ - if (IsPlanComplete()) - return true; - else - return false; -} - -bool -AppleThreadPlanStepThroughObjCTrampoline::WillStop() -{ +bool AppleThreadPlanStepThroughObjCTrampoline::MischiefManaged() { + if (IsPlanComplete()) return true; + else + return false; } + +bool AppleThreadPlanStepThroughObjCTrampoline::WillStop() { return true; } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h index 8db9963fa51..60c8b92d9cc 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h @@ -14,80 +14,66 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-types.h" -#include "lldb/lldb-enumerations.h" +#include "AppleObjCTrampolineHandler.h" #include "lldb/Core/Value.h" #include "lldb/Target/ThreadPlan.h" -#include "AppleObjCTrampolineHandler.h" +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-types.h" -namespace lldb_private -{ +namespace lldb_private { -class AppleThreadPlanStepThroughObjCTrampoline : public ThreadPlan -{ +class AppleThreadPlanStepThroughObjCTrampoline : public ThreadPlan { public: - AppleThreadPlanStepThroughObjCTrampoline(Thread &thread, - AppleObjCTrampolineHandler *trampoline_handler, - ValueList &values, - lldb::addr_t isa_addr, - lldb::addr_t sel_addr, - bool stop_others); - - ~AppleThreadPlanStepThroughObjCTrampoline() override; - - static bool - PreResumeInitializeFunctionCaller(void *myself); - - void - GetDescription(Stream *s, - lldb::DescriptionLevel level) override; - - bool - ValidatePlan(Stream *error) override; - - lldb::StateType - GetPlanRunState() override; - - bool - ShouldStop(Event *event_ptr) override; - - bool - StopOthers() override - { - return m_stop_others; - } - - // The base class MischiefManaged does some cleanup - so you have to call it - // in your MischiefManaged derived class. - bool - MischiefManaged() override; - - void - DidPush() override; - - bool - WillStop() override; + AppleThreadPlanStepThroughObjCTrampoline( + Thread &thread, AppleObjCTrampolineHandler *trampoline_handler, + ValueList &values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, + bool stop_others); + + ~AppleThreadPlanStepThroughObjCTrampoline() override; + + static bool PreResumeInitializeFunctionCaller(void *myself); + + void GetDescription(Stream *s, lldb::DescriptionLevel level) override; + + bool ValidatePlan(Stream *error) override; + + lldb::StateType GetPlanRunState() override; + + bool ShouldStop(Event *event_ptr) override; + + bool StopOthers() override { return m_stop_others; } + + // The base class MischiefManaged does some cleanup - so you have to call it + // in your MischiefManaged derived class. + bool MischiefManaged() override; + + void DidPush() override; + + bool WillStop() override; protected: - bool - DoPlanExplainsStop(Event *event_ptr) override; - + bool DoPlanExplainsStop(Event *event_ptr) override; + private: - bool - InitializeFunctionCaller (); - - AppleObjCTrampolineHandler *m_trampoline_handler; // FIXME - ensure this doesn't go away on us? SP maybe? - lldb::addr_t m_args_addr; // Stores the address for our step through function result structure. - //lldb::addr_t m_object_addr; // This is only for Description. - ValueList m_input_values; - lldb::addr_t m_isa_addr; // isa_addr and sel_addr are the keys we will use to cache the implementation. - lldb::addr_t m_sel_addr; - lldb::ThreadPlanSP m_func_sp; // This is the function call plan. We fill it at start, then set it - // to NULL when this plan is done. That way we know to go to: - lldb::ThreadPlanSP m_run_to_sp; // The plan that runs to the target. - FunctionCaller *m_impl_function; // This is a pointer to a impl function that - // is owned by the client that pushes this plan. - bool m_stop_others; + bool InitializeFunctionCaller(); + + AppleObjCTrampolineHandler *m_trampoline_handler; // FIXME - ensure this + // doesn't go away on us? + // SP maybe? + lldb::addr_t m_args_addr; // Stores the address for our step through function + // result structure. + // lldb::addr_t m_object_addr; // This is only for Description. + ValueList m_input_values; + lldb::addr_t m_isa_addr; // isa_addr and sel_addr are the keys we will use to + // cache the implementation. + lldb::addr_t m_sel_addr; + lldb::ThreadPlanSP m_func_sp; // This is the function call plan. We fill it + // at start, then set it + // to NULL when this plan is done. That way we know to go to: + lldb::ThreadPlanSP m_run_to_sp; // The plan that runs to the target. + FunctionCaller *m_impl_function; // This is a pointer to a impl function that + // is owned by the client that pushes this plan. + bool m_stop_others; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp index 67850dbbda5..2471f6a71e7 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp @@ -37,165 +37,163 @@ using namespace lldb_private; using namespace lldb_renderscript; // [``slang``](https://android.googlesource.com/platform/frameworks/compile/slang), -// the compiler frontend for RenderScript embeds an ARM specific triple in IR that is shipped in the app, after +// the compiler frontend for RenderScript embeds an ARM specific triple in IR +// that is shipped in the app, after // generating IR that has some assumptions that an ARM device is the target. -// As the IR is then compiled on a device of unknown (at time the IR was generated at least) architecture, -// when calling RenderScript API function as part of debugger expressions, we have to perform a fixup pass that -// removes those assumptions right before the module is sent to be generated by the llvm backend. - -namespace -{ -bool -registerRSDefaultTargetOpts(clang::TargetOptions &proto, const llvm::Triple::ArchType &arch) -{ - switch (arch) - { - case llvm::Triple::ArchType::x86: - proto.Triple = "i686--linux-android"; - proto.CPU = "atom"; - proto.Features.push_back("+long64"); - // Fallthrough for common x86 family features - case llvm::Triple::ArchType::x86_64: - proto.Features.push_back("+mmx"); - proto.Features.push_back("+sse"); - proto.Features.push_back("+sse2"); - proto.Features.push_back("+sse3"); - proto.Features.push_back("+ssse3"); - proto.Features.push_back("+sse4.1"); - proto.Features.push_back("+sse4.2"); - break; - case llvm::Triple::ArchType::mipsel: - // pretend this is `arm' for the front-end - proto.Triple = "armv7-none-linux-android"; - proto.CPU = ""; - proto.Features.push_back("+long64"); - break; - case llvm::Triple::ArchType::mips64el: - // pretend this is `aarch64' for the front-end - proto.Triple = "aarch64-none-linux-android"; - proto.CPU = ""; - break; - default: - return false; - } - return true; +// As the IR is then compiled on a device of unknown (at time the IR was +// generated at least) architecture, +// when calling RenderScript API function as part of debugger expressions, we +// have to perform a fixup pass that +// removes those assumptions right before the module is sent to be generated by +// the llvm backend. + +namespace { +bool registerRSDefaultTargetOpts(clang::TargetOptions &proto, + const llvm::Triple::ArchType &arch) { + switch (arch) { + case llvm::Triple::ArchType::x86: + proto.Triple = "i686--linux-android"; + proto.CPU = "atom"; + proto.Features.push_back("+long64"); + // Fallthrough for common x86 family features + case llvm::Triple::ArchType::x86_64: + proto.Features.push_back("+mmx"); + proto.Features.push_back("+sse"); + proto.Features.push_back("+sse2"); + proto.Features.push_back("+sse3"); + proto.Features.push_back("+ssse3"); + proto.Features.push_back("+sse4.1"); + proto.Features.push_back("+sse4.2"); + break; + case llvm::Triple::ArchType::mipsel: + // pretend this is `arm' for the front-end + proto.Triple = "armv7-none-linux-android"; + proto.CPU = ""; + proto.Features.push_back("+long64"); + break; + case llvm::Triple::ArchType::mips64el: + // pretend this is `aarch64' for the front-end + proto.Triple = "aarch64-none-linux-android"; + proto.CPU = ""; + break; + default: + return false; + } + return true; } } // end anonymous namespace -bool -RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) -{ - bool changed_module = false; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); - - std::string err; - llvm::StringRef real_triple = m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); - const llvm::Target *target_info = llvm::TargetRegistry::lookupTarget(real_triple, err); - if (!target_info) - { - if (log) - log->Warning("couldn't determine real target architecture: '%s'", err.c_str()); - return false; - } - - llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; - assert(m_process_ptr && "no available lldb process"); - switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) - { - case llvm::Triple::ArchType::x86: - changed_module |= fixupX86FunctionCalls(module); - // For some reason this triple gets totally missed by the backend, and must be set manually. - // There a reference in bcc/Main.cpp about auto feature-detection being removed from LLVM3.5, but I can't - // see that discussion anywhere public. - real_triple = "i686--linux-android"; - break; - case llvm::Triple::ArchType::x86_64: - changed_module |= fixupX86_64FunctionCalls(module); - break; - case llvm::Triple::ArchType::mipsel: - case llvm::Triple::ArchType::mips64el: - // No actual IR fixup pass is needed on MIPS, but the datalayout - // and targetmachine do need to be explicitly set. - - // bcc explicitly compiles MIPS code to use the static relocation - // model due to an issue with relocations in mclinker. - // see libbcc/support/CompilerConfig.cpp for details - reloc_model = llvm::Reloc::Static; - changed_module = true; - break; - case llvm::Triple::ArchType::arm: - case llvm::Triple::ArchType::aarch64: - // ARM subtargets need no fixup passes as they are the initial target as generated by the - // slang compiler frontend. - break; - default: - if (log) - log->Warning("Ignoring unknown renderscript target"); - return false; +bool RenderScriptRuntimeModulePass::runOnModule(llvm::Module &module) { + bool changed_module = false; + Log *log( + GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); + + std::string err; + llvm::StringRef real_triple = + m_process_ptr->GetTarget().GetArchitecture().GetTriple().getTriple(); + const llvm::Target *target_info = + llvm::TargetRegistry::lookupTarget(real_triple, err); + if (!target_info) { + if (log) + log->Warning("couldn't determine real target architecture: '%s'", + err.c_str()); + return false; + } + + llvm::Optional<llvm::Reloc::Model> reloc_model = llvm::None; + assert(m_process_ptr && "no available lldb process"); + switch (m_process_ptr->GetTarget().GetArchitecture().GetMachine()) { + case llvm::Triple::ArchType::x86: + changed_module |= fixupX86FunctionCalls(module); + // For some reason this triple gets totally missed by the backend, and must + // be set manually. + // There a reference in bcc/Main.cpp about auto feature-detection being + // removed from LLVM3.5, but I can't + // see that discussion anywhere public. + real_triple = "i686--linux-android"; + break; + case llvm::Triple::ArchType::x86_64: + changed_module |= fixupX86_64FunctionCalls(module); + break; + case llvm::Triple::ArchType::mipsel: + case llvm::Triple::ArchType::mips64el: + // No actual IR fixup pass is needed on MIPS, but the datalayout + // and targetmachine do need to be explicitly set. + + // bcc explicitly compiles MIPS code to use the static relocation + // model due to an issue with relocations in mclinker. + // see libbcc/support/CompilerConfig.cpp for details + reloc_model = llvm::Reloc::Static; + changed_module = true; + break; + case llvm::Triple::ArchType::arm: + case llvm::Triple::ArchType::aarch64: + // ARM subtargets need no fixup passes as they are the initial target as + // generated by the + // slang compiler frontend. + break; + default: + if (log) + log->Warning("Ignoring unknown renderscript target"); + return false; + } + + if (changed_module) { + llvm::TargetOptions options; + llvm::TargetMachine *target_machine = target_info->createTargetMachine( + real_triple, "", "", options, reloc_model); + assert(target_machine && + "failed to identify RenderScriptRuntime target machine"); + // We've been using a triple and datalayout of some ARM variant all along, + // so + // we need to let the backend know that this is no longer the case. + if (log) { + log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, + real_triple.str().c_str()); + log->Printf( + "%s - Changing RS datalayout to '%s'", __FUNCTION__, + target_machine->createDataLayout().getStringRepresentation().c_str()); } - - if (changed_module) - { - llvm::TargetOptions options; - llvm::TargetMachine *target_machine = - target_info->createTargetMachine(real_triple, "", "", options, reloc_model); - assert(target_machine && "failed to identify RenderScriptRuntime target machine"); - // We've been using a triple and datalayout of some ARM variant all along, so - // we need to let the backend know that this is no longer the case. - if (log) - { - log->Printf("%s - Changing RS target triple to '%s'", __FUNCTION__, real_triple.str().c_str()); - log->Printf("%s - Changing RS datalayout to '%s'", __FUNCTION__, - target_machine->createDataLayout().getStringRepresentation().c_str()); - } - module.setTargetTriple(real_triple); - module.setDataLayout(target_machine->createDataLayout()); - } - return changed_module; + module.setTargetTriple(real_triple); + module.setDataLayout(target_machine->createDataLayout()); + } + return changed_module; } char RenderScriptRuntimeModulePass::ID = 0; -namespace lldb_private -{ +namespace lldb_private { -bool -RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) -{ - auto *process = GetProcess(); - assert(process); - return registerRSDefaultTargetOpts(proto, process->GetTarget().GetArchitecture().GetMachine()); +bool RenderScriptRuntime::GetOverrideExprOptions(clang::TargetOptions &proto) { + auto *process = GetProcess(); + assert(process); + return registerRSDefaultTargetOpts( + proto, process->GetTarget().GetArchitecture().GetMachine()); } -bool -RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) -{ - if (!m_ir_passes) - m_ir_passes = new RSIRPasses(GetProcess()); - assert(m_ir_passes); +bool RenderScriptRuntime::GetIRPasses(LLVMUserExpression::IRPasses &passes) { + if (!m_ir_passes) + m_ir_passes = new RSIRPasses(GetProcess()); + assert(m_ir_passes); - passes.EarlyPasses = m_ir_passes->EarlyPasses; - passes.LatePasses = m_ir_passes->LatePasses; + passes.EarlyPasses = m_ir_passes->EarlyPasses; + passes.LatePasses = m_ir_passes->LatePasses; - return true; + return true; } -namespace lldb_renderscript -{ +namespace lldb_renderscript { -RSIRPasses::RSIRPasses(Process *process) -{ - IRPasses(); - assert(process); +RSIRPasses::RSIRPasses(Process *process) { + IRPasses(); + assert(process); - EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); - assert(EarlyPasses); - EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); + EarlyPasses = std::make_shared<llvm::legacy::PassManager>(); + assert(EarlyPasses); + EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); } -RSIRPasses::~RSIRPasses() -{ -} +RSIRPasses::~RSIRPasses() {} } // namespace lldb_renderscript } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h index f998aa46b2c..54d126d1655 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.h @@ -26,34 +26,33 @@ #include "RenderScriptRuntime.h" #include "RenderScriptx86ABIFixups.h" -// RenderScriptRuntimeModulePass is a simple llvm::ModulesPass that is used during expression evaluation to apply +// RenderScriptRuntimeModulePass is a simple llvm::ModulesPass that is used +// during expression evaluation to apply // RenderScript-specific fixes for expression evaluation. -// In particular this is used to make expression IR conformant with the ABI generated by the slang frontend. This -// ModulePass is executed in ClangExpressionParser::PrepareForExecution whenever an expression's DWARF language is +// In particular this is used to make expression IR conformant with the ABI +// generated by the slang frontend. This +// ModulePass is executed in ClangExpressionParser::PrepareForExecution whenever +// an expression's DWARF language is // eLanguageTypeExtRenderscript -class RenderScriptRuntimeModulePass : public llvm::ModulePass -{ +class RenderScriptRuntimeModulePass : public llvm::ModulePass { public: - static char ID; - RenderScriptRuntimeModulePass(const lldb_private::Process *process) : ModulePass(ID), m_process_ptr(process) {} + static char ID; + RenderScriptRuntimeModulePass(const lldb_private::Process *process) + : ModulePass(ID), m_process_ptr(process) {} - bool - runOnModule(llvm::Module &module); + bool runOnModule(llvm::Module &module); private: - const lldb_private::Process *m_process_ptr; + const lldb_private::Process *m_process_ptr; }; -namespace lldb_private -{ -namespace lldb_renderscript -{ -struct RSIRPasses : public lldb_private::LLVMUserExpression::IRPasses -{ - RSIRPasses(lldb_private::Process *process); +namespace lldb_private { +namespace lldb_renderscript { +struct RSIRPasses : public lldb_private::LLVMUserExpression::IRPasses { + RSIRPasses(lldb_private::Process *process); - ~RSIRPasses(); + ~RSIRPasses(); }; } // namespace lldb_renderscript } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index 52991691261..b2a63098c45 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -41,652 +41,596 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_renderscript; -namespace -{ +namespace { // The empirical_type adds a basic level of validation to arbitrary data // allowing us to track if data has been discovered and stored or not. -// An empirical_type will be marked as valid only if it has been explicitly assigned to. -template <typename type_t> class empirical_type -{ +// An empirical_type will be marked as valid only if it has been explicitly +// assigned to. +template <typename type_t> class empirical_type { public: - // Ctor. Contents is invalid when constructed. - empirical_type() : valid(false) {} - - // Return true and copy contents to out if valid, else return false. - bool - get(type_t &out) const - { - if (valid) - out = data; - return valid; - } - - // Return a pointer to the contents or nullptr if it was not valid. - const type_t * - get() const - { - return valid ? &data : nullptr; - } - - // Assign data explicitly. - void - set(const type_t in) - { - data = in; - valid = true; - } - - // Mark contents as invalid. - void - invalidate() - { - valid = false; - } - - // Returns true if this type contains valid data. - bool - isValid() const - { - return valid; - } - - // Assignment operator. - empirical_type<type_t> & - operator=(const type_t in) - { - set(in); - return *this; - } - - // Dereference operator returns contents. - // Warning: Will assert if not valid so use only when you know data is valid. - const type_t &operator*() const - { - assert(valid); - return data; - } + // Ctor. Contents is invalid when constructed. + empirical_type() : valid(false) {} + + // Return true and copy contents to out if valid, else return false. + bool get(type_t &out) const { + if (valid) + out = data; + return valid; + } + + // Return a pointer to the contents or nullptr if it was not valid. + const type_t *get() const { return valid ? &data : nullptr; } + + // Assign data explicitly. + void set(const type_t in) { + data = in; + valid = true; + } + + // Mark contents as invalid. + void invalidate() { valid = false; } + + // Returns true if this type contains valid data. + bool isValid() const { return valid; } + + // Assignment operator. + empirical_type<type_t> &operator=(const type_t in) { + set(in); + return *this; + } + + // Dereference operator returns contents. + // Warning: Will assert if not valid so use only when you know data is valid. + const type_t &operator*() const { + assert(valid); + return data; + } protected: - bool valid; - type_t data; + bool valid; + type_t data; }; -// ArgItem is used by the GetArgs() function when reading function arguments from the target. -struct ArgItem -{ - enum - { - ePointer, - eInt32, - eInt64, - eLong, - eBool - } type; +// ArgItem is used by the GetArgs() function when reading function arguments +// from the target. +struct ArgItem { + enum { ePointer, eInt32, eInt64, eLong, eBool } type; - uint64_t value; + uint64_t value; - explicit operator uint64_t() const { return value; } + explicit operator uint64_t() const { return value; } }; -// Context structure to be passed into GetArgsXXX(), argument reading functions below. -struct GetArgsCtx -{ - RegisterContext *reg_ctx; - Process *process; +// Context structure to be passed into GetArgsXXX(), argument reading functions +// below. +struct GetArgsCtx { + RegisterContext *reg_ctx; + Process *process; }; -bool -GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); +bool GetArgsX86(const GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - Error error; + Error error; - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - - for (size_t i = 0; i < num_args; ++i) - { - ArgItem &arg = arg_list[i]; - // advance up the stack by one argument - sp += sizeof(uint32_t); - // get the argument type size - size_t arg_size = sizeof(uint32_t); - // read the argument from memory - arg.value = 0; - Error error; - size_t read = ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error); - if (read != arg_size || !error.Success()) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64 " '%s'", __FUNCTION__, uint64_t(i), - error.AsCString()); - return false; - } - } - return true; -} - -bool -GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - - // number of arguments passed in registers - static const uint32_t c_args_in_reg = 6; - // register passing order - static const std::array<const char *, c_args_in_reg> c_reg_names{{"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; - // argument type to size mapping - static const std::array<size_t, 5> arg_size{{ - 8, // ePointer, - 4, // eInt32, - 8, // eInt64, - 8, // eLong, - 4, // eBool, - }}; + // get the current stack pointer + uint64_t sp = ctx.reg_ctx->GetSP(); + for (size_t i = 0; i < num_args; ++i) { + ArgItem &arg = arg_list[i]; + // advance up the stack by one argument + sp += sizeof(uint32_t); + // get the argument type size + size_t arg_size = sizeof(uint32_t); + // read the argument from memory + arg.value = 0; Error error; + size_t read = + ctx.process->ReadMemory(sp, &arg.value, sizeof(uint32_t), error); + if (read != arg_size || !error.Success()) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64 " '%s'", + __FUNCTION__, uint64_t(i), error.AsCString()); + return false; + } + } + return true; +} - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); - // step over the return address - sp += sizeof(uint64_t); - - // check the stack alignment was correct (16 byte aligned) - if ((sp & 0xf) != 0x0) - { - if (log) - log->Printf("%s - stack misaligned", __FUNCTION__); - return false; - } - - // find the start of arguments on the stack - uint64_t sp_offset = 0; - for (uint32_t i = c_args_in_reg; i < num_args; ++i) - { - sp_offset += arg_size[arg_list[i].type]; - } - // round up to multiple of 16 - sp_offset = (sp_offset + 0xf) & 0xf; - sp += sp_offset; - - for (size_t i = 0; i < num_args; ++i) - { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < c_args_in_reg) - { - const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]); - RegisterValue rVal; - if (ctx.reg_ctx->ReadRegister(rArg, rVal)) - arg.value = rVal.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else - { - // get the argument type size - const size_t size = arg_size[arg_list[i].type]; - // read the argument from memory - arg.value = 0; - // note: due to little endian layout reading 4 or 8 bytes will give the correct value. - size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error); - success = (error.Success() && read==size); - // advance past this argument - sp -= size; - } - // fail if we couldn't read this argument - if (!success) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64", reason: %s", - __FUNCTION__, uint64_t(i), error.AsCString("n/a")); - return false; - } - } - return true; +bool GetArgsX86_64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + + // number of arguments passed in registers + static const uint32_t c_args_in_reg = 6; + // register passing order + static const std::array<const char *, c_args_in_reg> c_reg_names{ + {"rdi", "rsi", "rdx", "rcx", "r8", "r9"}}; + // argument type to size mapping + static const std::array<size_t, 5> arg_size{{ + 8, // ePointer, + 4, // eInt32, + 8, // eInt64, + 8, // eLong, + 4, // eBool, + }}; + + Error error; + + // get the current stack pointer + uint64_t sp = ctx.reg_ctx->GetSP(); + // step over the return address + sp += sizeof(uint64_t); + + // check the stack alignment was correct (16 byte aligned) + if ((sp & 0xf) != 0x0) { + if (log) + log->Printf("%s - stack misaligned", __FUNCTION__); + return false; + } + + // find the start of arguments on the stack + uint64_t sp_offset = 0; + for (uint32_t i = c_args_in_reg; i < num_args; ++i) { + sp_offset += arg_size[arg_list[i].type]; + } + // round up to multiple of 16 + sp_offset = (sp_offset + 0xf) & 0xf; + sp += sp_offset; + + for (size_t i = 0; i < num_args; ++i) { + bool success = false; + ArgItem &arg = arg_list[i]; + // arguments passed in registers + if (i < c_args_in_reg) { + const RegisterInfo *rArg = + ctx.reg_ctx->GetRegisterInfoByName(c_reg_names[i]); + RegisterValue rVal; + if (ctx.reg_ctx->ReadRegister(rArg, rVal)) + arg.value = rVal.GetAsUInt64(0, &success); + } + // arguments passed on the stack + else { + // get the argument type size + const size_t size = arg_size[arg_list[i].type]; + // read the argument from memory + arg.value = 0; + // note: due to little endian layout reading 4 or 8 bytes will give the + // correct value. + size_t read = ctx.process->ReadMemory(sp, &arg.value, size, error); + success = (error.Success() && read == size); + // advance past this argument + sp -= size; + } + // fail if we couldn't read this argument + if (!success) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", + __FUNCTION__, uint64_t(i), error.AsCString("n/a")); + return false; + } + } + return true; } -bool -GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - // number of arguments passed in registers - static const uint32_t c_args_in_reg = 4; +bool GetArgsArm(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + // number of arguments passed in registers + static const uint32_t c_args_in_reg = 4; - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - Error error; + Error error; - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); + // get the current stack pointer + uint64_t sp = ctx.reg_ctx->GetSP(); - for (size_t i = 0; i < num_args; ++i) - { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < c_args_in_reg) - { - const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); - RegisterValue rVal; - if (ctx.reg_ctx->ReadRegister(rArg, rVal)) - arg.value = rVal.GetAsUInt32(0, &success); - } - // arguments passed on the stack - else - { - // get the argument type size - const size_t arg_size = sizeof(uint32_t); - // clear all 64bits - arg.value = 0; - // read this argument from memory - size_t bytes_read = ctx.process->ReadMemory(sp, &arg.value, arg_size, error); - success = (error.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += sizeof(uint32_t); - } - // fail if we couldn't read this argument - if (!success) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64", reason: %s", - __FUNCTION__, uint64_t(i), error.AsCString("n/a")); - return false; - } - } - return true; + for (size_t i = 0; i < num_args; ++i) { + bool success = false; + ArgItem &arg = arg_list[i]; + // arguments passed in registers + if (i < c_args_in_reg) { + const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); + RegisterValue rVal; + if (ctx.reg_ctx->ReadRegister(rArg, rVal)) + arg.value = rVal.GetAsUInt32(0, &success); + } + // arguments passed on the stack + else { + // get the argument type size + const size_t arg_size = sizeof(uint32_t); + // clear all 64bits + arg.value = 0; + // read this argument from memory + size_t bytes_read = + ctx.process->ReadMemory(sp, &arg.value, arg_size, error); + success = (error.Success() && bytes_read == arg_size); + // advance the stack pointer + sp += sizeof(uint32_t); + } + // fail if we couldn't read this argument + if (!success) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", + __FUNCTION__, uint64_t(i), error.AsCString("n/a")); + return false; + } + } + return true; } -bool -GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - // number of arguments passed in registers - static const uint32_t c_args_in_reg = 8; +bool GetArgsAarch64(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + // number of arguments passed in registers + static const uint32_t c_args_in_reg = 8; - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - for (size_t i = 0; i < num_args; ++i) - { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < c_args_in_reg) - { - const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); - RegisterValue rVal; - if (ctx.reg_ctx->ReadRegister(rArg, rVal)) - arg.value = rVal.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else - { - if (log) - log->Printf("%s - reading arguments spilled to stack not implemented", __FUNCTION__); - } - // fail if we couldn't read this argument - if (!success) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__, - uint64_t(i)); - return false; - } - } - return true; + for (size_t i = 0; i < num_args; ++i) { + bool success = false; + ArgItem &arg = arg_list[i]; + // arguments passed in registers + if (i < c_args_in_reg) { + const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i); + RegisterValue rVal; + if (ctx.reg_ctx->ReadRegister(rArg, rVal)) + arg.value = rVal.GetAsUInt64(0, &success); + } + // arguments passed on the stack + else { + if (log) + log->Printf("%s - reading arguments spilled to stack not implemented", + __FUNCTION__); + } + // fail if we couldn't read this argument + if (!success) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64, __FUNCTION__, + uint64_t(i)); + return false; + } + } + return true; } -bool -GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - // number of arguments passed in registers - static const uint32_t c_args_in_reg = 4; - // register file offset to first argument - static const uint32_t c_reg_offset = 4; +bool GetArgsMipsel(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + // number of arguments passed in registers + static const uint32_t c_args_in_reg = 4; + // register file offset to first argument + static const uint32_t c_reg_offset = 4; - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - Error error; + Error error; - // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space) - uint64_t sp = ctx.reg_ctx->GetSP() + 16; + // find offset to arguments on the stack (+16 to skip over a0-a3 shadow space) + uint64_t sp = ctx.reg_ctx->GetSP() + 16; - for (size_t i = 0; i < num_args; ++i) - { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < c_args_in_reg) - { - const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); - RegisterValue rVal; - if (ctx.reg_ctx->ReadRegister(rArg, rVal)) - arg.value = rVal.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else - { - const size_t arg_size = sizeof(uint32_t); - arg.value = 0; - size_t bytes_read = ctx.process->ReadMemory(sp, &arg.value, arg_size, error); - success = (error.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += arg_size; - } - // fail if we couldn't read this argument - if (!success) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64", reason: %s", - __FUNCTION__, uint64_t(i), error.AsCString("n/a")); - return false; - } - } - return true; + for (size_t i = 0; i < num_args; ++i) { + bool success = false; + ArgItem &arg = arg_list[i]; + // arguments passed in registers + if (i < c_args_in_reg) { + const RegisterInfo *rArg = + ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); + RegisterValue rVal; + if (ctx.reg_ctx->ReadRegister(rArg, rVal)) + arg.value = rVal.GetAsUInt64(0, &success); + } + // arguments passed on the stack + else { + const size_t arg_size = sizeof(uint32_t); + arg.value = 0; + size_t bytes_read = + ctx.process->ReadMemory(sp, &arg.value, arg_size, error); + success = (error.Success() && bytes_read == arg_size); + // advance the stack pointer + sp += arg_size; + } + // fail if we couldn't read this argument + if (!success) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", + __FUNCTION__, uint64_t(i), error.AsCString("n/a")); + return false; + } + } + return true; } -bool -GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) -{ - // number of arguments passed in registers - static const uint32_t c_args_in_reg = 8; - // register file offset to first argument - static const uint32_t c_reg_offset = 4; +bool GetArgsMips64el(GetArgsCtx &ctx, ArgItem *arg_list, size_t num_args) { + // number of arguments passed in registers + static const uint32_t c_args_in_reg = 8; + // register file offset to first argument + static const uint32_t c_reg_offset = 4; - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - Error error; + Error error; - // get the current stack pointer - uint64_t sp = ctx.reg_ctx->GetSP(); + // get the current stack pointer + uint64_t sp = ctx.reg_ctx->GetSP(); - for (size_t i = 0; i < num_args; ++i) - { - bool success = false; - ArgItem &arg = arg_list[i]; - // arguments passed in registers - if (i < c_args_in_reg) - { - const RegisterInfo *rArg = ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); - RegisterValue rVal; - if (ctx.reg_ctx->ReadRegister(rArg, rVal)) - arg.value = rVal.GetAsUInt64(0, &success); - } - // arguments passed on the stack - else - { - // get the argument type size - const size_t arg_size = sizeof(uint64_t); - // clear all 64bits - arg.value = 0; - // read this argument from memory - size_t bytes_read = ctx.process->ReadMemory(sp, &arg.value, arg_size, error); - success = (error.Success() && bytes_read == arg_size); - // advance the stack pointer - sp += arg_size; - } - // fail if we couldn't read this argument - if (!success) - { - if (log) - log->Printf("%s - error reading argument: %" PRIu64", reason: %s", - __FUNCTION__, uint64_t(i), error.AsCString("n/a")); - return false; - } - } - return true; + for (size_t i = 0; i < num_args; ++i) { + bool success = false; + ArgItem &arg = arg_list[i]; + // arguments passed in registers + if (i < c_args_in_reg) { + const RegisterInfo *rArg = + ctx.reg_ctx->GetRegisterInfoAtIndex(i + c_reg_offset); + RegisterValue rVal; + if (ctx.reg_ctx->ReadRegister(rArg, rVal)) + arg.value = rVal.GetAsUInt64(0, &success); + } + // arguments passed on the stack + else { + // get the argument type size + const size_t arg_size = sizeof(uint64_t); + // clear all 64bits + arg.value = 0; + // read this argument from memory + size_t bytes_read = + ctx.process->ReadMemory(sp, &arg.value, arg_size, error); + success = (error.Success() && bytes_read == arg_size); + // advance the stack pointer + sp += arg_size; + } + // fail if we couldn't read this argument + if (!success) { + if (log) + log->Printf("%s - error reading argument: %" PRIu64 ", reason: %s", + __FUNCTION__, uint64_t(i), error.AsCString("n/a")); + return false; + } + } + return true; } -bool -GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) -{ - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); +bool GetArgs(ExecutionContext &context, ArgItem *arg_list, size_t num_args) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - // verify that we have a target - if (!context.GetTargetPtr()) - { - if (log) - log->Printf("%s - invalid target", __FUNCTION__); - return false; - } + // verify that we have a target + if (!context.GetTargetPtr()) { + if (log) + log->Printf("%s - invalid target", __FUNCTION__); + return false; + } - GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()}; - assert(ctx.reg_ctx && ctx.process); + GetArgsCtx ctx = {context.GetRegisterContext(), context.GetProcessPtr()}; + assert(ctx.reg_ctx && ctx.process); - // dispatch based on architecture - switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) - { - case llvm::Triple::ArchType::x86: - return GetArgsX86(ctx, arg_list, num_args); + // dispatch based on architecture + switch (context.GetTargetPtr()->GetArchitecture().GetMachine()) { + case llvm::Triple::ArchType::x86: + return GetArgsX86(ctx, arg_list, num_args); - case llvm::Triple::ArchType::x86_64: - return GetArgsX86_64(ctx, arg_list, num_args); + case llvm::Triple::ArchType::x86_64: + return GetArgsX86_64(ctx, arg_list, num_args); - case llvm::Triple::ArchType::arm: - return GetArgsArm(ctx, arg_list, num_args); + case llvm::Triple::ArchType::arm: + return GetArgsArm(ctx, arg_list, num_args); - case llvm::Triple::ArchType::aarch64: - return GetArgsAarch64(ctx, arg_list, num_args); + case llvm::Triple::ArchType::aarch64: + return GetArgsAarch64(ctx, arg_list, num_args); - case llvm::Triple::ArchType::mipsel: - return GetArgsMipsel(ctx, arg_list, num_args); + case llvm::Triple::ArchType::mipsel: + return GetArgsMipsel(ctx, arg_list, num_args); - case llvm::Triple::ArchType::mips64el: - return GetArgsMips64el(ctx, arg_list, num_args); + case llvm::Triple::ArchType::mips64el: + return GetArgsMips64el(ctx, arg_list, num_args); - default: - // unsupported architecture - if (log) - { - log->Printf("%s - architecture not supported: '%s'", __FUNCTION__, - context.GetTargetRef().GetArchitecture().GetArchitectureName()); - } - return false; + default: + // unsupported architecture + if (log) { + log->Printf( + "%s - architecture not supported: '%s'", __FUNCTION__, + context.GetTargetRef().GetArchitecture().GetArchitectureName()); } + return false; + } } } // anonymous namespace -// The ScriptDetails class collects data associated with a single script instance. -struct RenderScriptRuntime::ScriptDetails -{ - ~ScriptDetails() = default; - - enum ScriptType - { - eScript, - eScriptC - }; - - // The derived type of the script. - empirical_type<ScriptType> type; - // The name of the original source file. - empirical_type<std::string> resName; - // Path to script .so file on the device. - empirical_type<std::string> scriptDyLib; - // Directory where kernel objects are cached on device. - empirical_type<std::string> cacheDir; - // Pointer to the context which owns this script. - empirical_type<lldb::addr_t> context; - // Pointer to the script object itself. - empirical_type<lldb::addr_t> script; +// The ScriptDetails class collects data associated with a single script +// instance. +struct RenderScriptRuntime::ScriptDetails { + ~ScriptDetails() = default; + + enum ScriptType { eScript, eScriptC }; + + // The derived type of the script. + empirical_type<ScriptType> type; + // The name of the original source file. + empirical_type<std::string> resName; + // Path to script .so file on the device. + empirical_type<std::string> scriptDyLib; + // Directory where kernel objects are cached on device. + empirical_type<std::string> cacheDir; + // Pointer to the context which owns this script. + empirical_type<lldb::addr_t> context; + // Pointer to the script object itself. + empirical_type<lldb::addr_t> script; }; // This Element class represents the Element object in RS, // defining the type associated with an Allocation. -struct RenderScriptRuntime::Element -{ - // Taken from rsDefines.h - enum DataKind - { - RS_KIND_USER, - RS_KIND_PIXEL_L = 7, - RS_KIND_PIXEL_A, - RS_KIND_PIXEL_LA, - RS_KIND_PIXEL_RGB, - RS_KIND_PIXEL_RGBA, - RS_KIND_PIXEL_DEPTH, - RS_KIND_PIXEL_YUV, - RS_KIND_INVALID = 100 - }; - - // Taken from rsDefines.h - enum DataType - { - RS_TYPE_NONE = 0, - RS_TYPE_FLOAT_16, - RS_TYPE_FLOAT_32, - RS_TYPE_FLOAT_64, - RS_TYPE_SIGNED_8, - RS_TYPE_SIGNED_16, - RS_TYPE_SIGNED_32, - RS_TYPE_SIGNED_64, - RS_TYPE_UNSIGNED_8, - RS_TYPE_UNSIGNED_16, - RS_TYPE_UNSIGNED_32, - RS_TYPE_UNSIGNED_64, - RS_TYPE_BOOLEAN, - - RS_TYPE_UNSIGNED_5_6_5, - RS_TYPE_UNSIGNED_5_5_5_1, - RS_TYPE_UNSIGNED_4_4_4_4, - - RS_TYPE_MATRIX_4X4, - RS_TYPE_MATRIX_3X3, - RS_TYPE_MATRIX_2X2, - - RS_TYPE_ELEMENT = 1000, - RS_TYPE_TYPE, - RS_TYPE_ALLOCATION, - RS_TYPE_SAMPLER, - RS_TYPE_SCRIPT, - RS_TYPE_MESH, - RS_TYPE_PROGRAM_FRAGMENT, - RS_TYPE_PROGRAM_VERTEX, - RS_TYPE_PROGRAM_RASTER, - RS_TYPE_PROGRAM_STORE, - RS_TYPE_FONT, - - RS_TYPE_INVALID = 10000 - }; - - std::vector<Element> children; // Child Element fields for structs - empirical_type<lldb::addr_t> element_ptr; // Pointer to the RS Element of the Type - empirical_type<DataType> type; // Type of each data pointer stored by the allocation - empirical_type<DataKind> type_kind; // Defines pixel type if Allocation is created from an image - empirical_type<uint32_t> type_vec_size; // Vector size of each data point, e.g '4' for uchar4 - empirical_type<uint32_t> field_count; // Number of Subelements - empirical_type<uint32_t> datum_size; // Size of a single Element with padding - empirical_type<uint32_t> padding; // Number of padding bytes - empirical_type<uint32_t> array_size; // Number of items in array, only needed for strucrs - ConstString type_name; // Name of type, only needed for structs - - static const ConstString & - GetFallbackStructName(); // Print this as the type name of a struct Element - // If we can't resolve the actual struct name - - bool - shouldRefresh() const - { - const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; - const bool valid_type = type.isValid() && type_vec_size.isValid() && type_kind.isValid(); - return !valid_ptr || !valid_type || !datum_size.isValid(); - } +struct RenderScriptRuntime::Element { + // Taken from rsDefines.h + enum DataKind { + RS_KIND_USER, + RS_KIND_PIXEL_L = 7, + RS_KIND_PIXEL_A, + RS_KIND_PIXEL_LA, + RS_KIND_PIXEL_RGB, + RS_KIND_PIXEL_RGBA, + RS_KIND_PIXEL_DEPTH, + RS_KIND_PIXEL_YUV, + RS_KIND_INVALID = 100 + }; + + // Taken from rsDefines.h + enum DataType { + RS_TYPE_NONE = 0, + RS_TYPE_FLOAT_16, + RS_TYPE_FLOAT_32, + RS_TYPE_FLOAT_64, + RS_TYPE_SIGNED_8, + RS_TYPE_SIGNED_16, + RS_TYPE_SIGNED_32, + RS_TYPE_SIGNED_64, + RS_TYPE_UNSIGNED_8, + RS_TYPE_UNSIGNED_16, + RS_TYPE_UNSIGNED_32, + RS_TYPE_UNSIGNED_64, + RS_TYPE_BOOLEAN, + + RS_TYPE_UNSIGNED_5_6_5, + RS_TYPE_UNSIGNED_5_5_5_1, + RS_TYPE_UNSIGNED_4_4_4_4, + + RS_TYPE_MATRIX_4X4, + RS_TYPE_MATRIX_3X3, + RS_TYPE_MATRIX_2X2, + + RS_TYPE_ELEMENT = 1000, + RS_TYPE_TYPE, + RS_TYPE_ALLOCATION, + RS_TYPE_SAMPLER, + RS_TYPE_SCRIPT, + RS_TYPE_MESH, + RS_TYPE_PROGRAM_FRAGMENT, + RS_TYPE_PROGRAM_VERTEX, + RS_TYPE_PROGRAM_RASTER, + RS_TYPE_PROGRAM_STORE, + RS_TYPE_FONT, + + RS_TYPE_INVALID = 10000 + }; + + std::vector<Element> children; // Child Element fields for structs + empirical_type<lldb::addr_t> + element_ptr; // Pointer to the RS Element of the Type + empirical_type<DataType> + type; // Type of each data pointer stored by the allocation + empirical_type<DataKind> + type_kind; // Defines pixel type if Allocation is created from an image + empirical_type<uint32_t> + type_vec_size; // Vector size of each data point, e.g '4' for uchar4 + empirical_type<uint32_t> field_count; // Number of Subelements + empirical_type<uint32_t> datum_size; // Size of a single Element with padding + empirical_type<uint32_t> padding; // Number of padding bytes + empirical_type<uint32_t> + array_size; // Number of items in array, only needed for strucrs + ConstString type_name; // Name of type, only needed for structs + + static const ConstString & + GetFallbackStructName(); // Print this as the type name of a struct Element + // If we can't resolve the actual struct name + + bool shouldRefresh() const { + const bool valid_ptr = element_ptr.isValid() && *element_ptr.get() != 0x0; + const bool valid_type = + type.isValid() && type_vec_size.isValid() && type_kind.isValid(); + return !valid_ptr || !valid_type || !datum_size.isValid(); + } }; // This AllocationDetails class collects data associated with a single // allocation instance. -struct RenderScriptRuntime::AllocationDetails -{ - struct Dimension - { - uint32_t dim_1; - uint32_t dim_2; - uint32_t dim_3; - uint32_t cubeMap; - - Dimension() - { - dim_1 = 0; - dim_2 = 0; - dim_3 = 0; - cubeMap = 0; - } - }; - - // The FileHeader struct specifies the header we use for writing allocations to a binary file. - // Our format begins with the ASCII characters "RSAD", identifying the file as an allocation dump. - // Member variables dims and hdr_size are then written consecutively, immediately followed by an instance of - // the ElementHeader struct. Because Elements can contain subelements, there may be more than one instance - // of the ElementHeader struct. With this first instance being the root element, and the other instances being - // the root's descendants. To identify which instances are an ElementHeader's children, each struct - // is immediately followed by a sequence of consecutive offsets to the start of its child structs. - // These offsets are 4 bytes in size, and the 0 offset signifies no more children. - struct FileHeader - { - uint8_t ident[4]; // ASCII 'RSAD' identifying the file - uint32_t dims[3]; // Dimensions - uint16_t hdr_size; // Header size in bytes, including all element headers - }; - - struct ElementHeader - { - uint16_t type; // DataType enum - uint32_t kind; // DataKind enum - uint32_t element_size; // Size of a single element, including padding - uint16_t vector_size; // Vector width - uint32_t array_size; // Number of elements in array - }; - - // Monotonically increasing from 1 - static uint32_t ID; - - // Maps Allocation DataType enum and vector size to printable strings - // using mapping from RenderScript numerical types summary documentation - static const char *RsDataTypeToString[][4]; - - // Maps Allocation DataKind enum to printable strings - static const char *RsDataKindToString[]; - - // Maps allocation types to format sizes for printing. - static const uint32_t RSTypeToFormat[][3]; - - // Give each allocation an ID as a way - // for commands to reference it. - const uint32_t id; - - RenderScriptRuntime::Element element; // Allocation Element type - empirical_type<Dimension> dimension; // Dimensions of the Allocation - empirical_type<lldb::addr_t> address; // Pointer to address of the RS Allocation - empirical_type<lldb::addr_t> data_ptr; // Pointer to the data held by the Allocation - empirical_type<lldb::addr_t> type_ptr; // Pointer to the RS Type of the Allocation - empirical_type<lldb::addr_t> context; // Pointer to the RS Context of the Allocation - empirical_type<uint32_t> size; // Size of the allocation - empirical_type<uint32_t> stride; // Stride between rows of the allocation - - // Give each allocation an id, so we can reference it in user commands. - AllocationDetails() : id(ID++) {} - - bool - shouldRefresh() const - { - bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; - valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; - return !valid_ptrs || !dimension.isValid() || !size.isValid() || element.shouldRefresh(); - } +struct RenderScriptRuntime::AllocationDetails { + struct Dimension { + uint32_t dim_1; + uint32_t dim_2; + uint32_t dim_3; + uint32_t cubeMap; + + Dimension() { + dim_1 = 0; + dim_2 = 0; + dim_3 = 0; + cubeMap = 0; + } + }; + + // The FileHeader struct specifies the header we use for writing allocations + // to a binary file. + // Our format begins with the ASCII characters "RSAD", identifying the file as + // an allocation dump. + // Member variables dims and hdr_size are then written consecutively, + // immediately followed by an instance of + // the ElementHeader struct. Because Elements can contain subelements, there + // may be more than one instance + // of the ElementHeader struct. With this first instance being the root + // element, and the other instances being + // the root's descendants. To identify which instances are an ElementHeader's + // children, each struct + // is immediately followed by a sequence of consecutive offsets to the start + // of its child structs. + // These offsets are 4 bytes in size, and the 0 offset signifies no more + // children. + struct FileHeader { + uint8_t ident[4]; // ASCII 'RSAD' identifying the file + uint32_t dims[3]; // Dimensions + uint16_t hdr_size; // Header size in bytes, including all element headers + }; + + struct ElementHeader { + uint16_t type; // DataType enum + uint32_t kind; // DataKind enum + uint32_t element_size; // Size of a single element, including padding + uint16_t vector_size; // Vector width + uint32_t array_size; // Number of elements in array + }; + + // Monotonically increasing from 1 + static uint32_t ID; + + // Maps Allocation DataType enum and vector size to printable strings + // using mapping from RenderScript numerical types summary documentation + static const char *RsDataTypeToString[][4]; + + // Maps Allocation DataKind enum to printable strings + static const char *RsDataKindToString[]; + + // Maps allocation types to format sizes for printing. + static const uint32_t RSTypeToFormat[][3]; + + // Give each allocation an ID as a way + // for commands to reference it. + const uint32_t id; + + RenderScriptRuntime::Element element; // Allocation Element type + empirical_type<Dimension> dimension; // Dimensions of the Allocation + empirical_type<lldb::addr_t> + address; // Pointer to address of the RS Allocation + empirical_type<lldb::addr_t> + data_ptr; // Pointer to the data held by the Allocation + empirical_type<lldb::addr_t> + type_ptr; // Pointer to the RS Type of the Allocation + empirical_type<lldb::addr_t> + context; // Pointer to the RS Context of the Allocation + empirical_type<uint32_t> size; // Size of the allocation + empirical_type<uint32_t> stride; // Stride between rows of the allocation + + // Give each allocation an id, so we can reference it in user commands. + AllocationDetails() : id(ID++) {} + + bool shouldRefresh() const { + bool valid_ptrs = data_ptr.isValid() && *data_ptr.get() != 0x0; + valid_ptrs = valid_ptrs && type_ptr.isValid() && *type_ptr.get() != 0x0; + return !valid_ptrs || !dimension.isValid() || !size.isValid() || + element.shouldRefresh(); + } }; -const ConstString & -RenderScriptRuntime::Element::GetFallbackStructName() -{ - static const ConstString FallbackStructName("struct"); - return FallbackStructName; +const ConstString &RenderScriptRuntime::Element::GetFallbackStructName() { + static const ConstString FallbackStructName("struct"); + return FallbackStructName; } uint32_t RenderScriptRuntime::AllocationDetails::ID = 1; const char *RenderScriptRuntime::AllocationDetails::RsDataKindToString[] = { - "User", - "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 + "User", "Undefined", "Undefined", "Undefined", + "Undefined", "Undefined", "Undefined", // Enum jumps from 0 to 7 "L Pixel", "A Pixel", "LA Pixel", "RGB Pixel", "RGBA Pixel", "Pixel Depth", "YUV Pixel"}; @@ -720,54 +664,64 @@ const char *RenderScriptRuntime::AllocationDetails::RsDataTypeToString[][4] = { // Deprecated {"RS Mesh", "RS Mesh", "RS Mesh", "RS Mesh"}, - {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", "RS Program Fragment"}, - {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", "RS Program Vertex"}, - {"RS Program Raster", "RS Program Raster", "RS Program Raster", "RS Program Raster"}, - {"RS Program Store", "RS Program Store", "RS Program Store", "RS Program Store"}, + {"RS Program Fragment", "RS Program Fragment", "RS Program Fragment", + "RS Program Fragment"}, + {"RS Program Vertex", "RS Program Vertex", "RS Program Vertex", + "RS Program Vertex"}, + {"RS Program Raster", "RS Program Raster", "RS Program Raster", + "RS Program Raster"}, + {"RS Program Store", "RS Program Store", "RS Program Store", + "RS Program Store"}, {"RS Font", "RS Font", "RS Font", "RS Font"}}; // Used as an index into the RSTypeToFormat array elements -enum TypeToFormatIndex -{ - eFormatSingle = 0, - eFormatVector, - eElementSize -}; +enum TypeToFormatIndex { eFormatSingle = 0, eFormatVector, eElementSize }; -// { format enum of single element, format enum of element vector, size of element} +// { format enum of single element, format enum of element vector, size of +// element} const uint32_t RenderScriptRuntime::AllocationDetails::RSTypeToFormat[][3] = { - {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE - {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16 - {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32 - {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64 - {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8 - {eFormatDecimal, eFormatVectorOfSInt16, sizeof(int16_t)}, // RS_TYPE_SIGNED_16 - {eFormatDecimal, eFormatVectorOfSInt32, sizeof(int32_t)}, // RS_TYPE_SIGNED_32 - {eFormatDecimal, eFormatVectorOfSInt64, sizeof(int64_t)}, // RS_TYPE_SIGNED_64 - {eFormatDecimal, eFormatVectorOfUInt8, sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8 - {eFormatDecimal, eFormatVectorOfUInt16, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16 - {eFormatDecimal, eFormatVectorOfUInt32, sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32 - {eFormatDecimal, eFormatVectorOfUInt64, sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64 - {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL - {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5 - {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1 - {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3 - {eFormatVectorOfFloat32, eFormatVectorOfFloat32, sizeof(float) * 4} // RS_TYPE_MATRIX_2X2 + {eFormatHex, eFormatHex, 1}, // RS_TYPE_NONE + {eFormatFloat, eFormatVectorOfFloat16, 2}, // RS_TYPE_FLOAT_16 + {eFormatFloat, eFormatVectorOfFloat32, sizeof(float)}, // RS_TYPE_FLOAT_32 + {eFormatFloat, eFormatVectorOfFloat64, sizeof(double)}, // RS_TYPE_FLOAT_64 + {eFormatDecimal, eFormatVectorOfSInt8, sizeof(int8_t)}, // RS_TYPE_SIGNED_8 + {eFormatDecimal, eFormatVectorOfSInt16, + sizeof(int16_t)}, // RS_TYPE_SIGNED_16 + {eFormatDecimal, eFormatVectorOfSInt32, + sizeof(int32_t)}, // RS_TYPE_SIGNED_32 + {eFormatDecimal, eFormatVectorOfSInt64, + sizeof(int64_t)}, // RS_TYPE_SIGNED_64 + {eFormatDecimal, eFormatVectorOfUInt8, + sizeof(uint8_t)}, // RS_TYPE_UNSIGNED_8 + {eFormatDecimal, eFormatVectorOfUInt16, + sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_16 + {eFormatDecimal, eFormatVectorOfUInt32, + sizeof(uint32_t)}, // RS_TYPE_UNSIGNED_32 + {eFormatDecimal, eFormatVectorOfUInt64, + sizeof(uint64_t)}, // RS_TYPE_UNSIGNED_64 + {eFormatBoolean, eFormatBoolean, 1}, // RS_TYPE_BOOL + {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_6_5 + {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_5_5_5_1 + {eFormatHex, eFormatHex, sizeof(uint16_t)}, // RS_TYPE_UNSIGNED_4_4_4_4 + {eFormatVectorOfFloat32, eFormatVectorOfFloat32, + sizeof(float) * 16}, // RS_TYPE_MATRIX_4X4 + {eFormatVectorOfFloat32, eFormatVectorOfFloat32, + sizeof(float) * 9}, // RS_TYPE_MATRIX_3X3 + {eFormatVectorOfFloat32, eFormatVectorOfFloat32, + sizeof(float) * 4} // RS_TYPE_MATRIX_2X2 }; //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ LanguageRuntime * -RenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType language) -{ +RenderScriptRuntime::CreateInstance(Process *process, + lldb::LanguageType language) { - if (language == eLanguageTypeExtRenderScript) - return new RenderScriptRuntime(process); - else - return nullptr; + if (language == eLanguageTypeExtRenderScript) + return new RenderScriptRuntime(process); + else + return nullptr; } // Callback with a module to search for matching symbols. @@ -775,1896 +729,1862 @@ RenderScriptRuntime::CreateInstance(Process *process, lldb::LanguageType languag // Then look for a symbol which matches our kernel name. // The breakpoint address is finally set using the address of this symbol. Searcher::CallbackReturn -RSBreakpointResolver::SearchCallback(SearchFilter &filter, SymbolContext &context, Address *, bool) -{ - ModuleSP module = context.module_sp; - - if (!module) - return Searcher::eCallbackReturnContinue; - - // Is this a module containing renderscript kernels? - if (nullptr == module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData)) - return Searcher::eCallbackReturnContinue; - - // Attempt to set a breakpoint on the kernel name symbol within the module library. - // If it's not found, it's likely debug info is unavailable - try to set a - // breakpoint on <name>.expand. +RSBreakpointResolver::SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *, bool) { + ModuleSP module = context.module_sp; - const Symbol *kernel_sym = module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); - if (!kernel_sym) - { - std::string kernel_name_expanded(m_kernel_name.AsCString()); - kernel_name_expanded.append(".expand"); - kernel_sym = module->FindFirstSymbolWithNameAndType(ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); - } - - if (kernel_sym) - { - Address bp_addr = kernel_sym->GetAddress(); - if (filter.AddressPasses(bp_addr)) - m_breakpoint->AddLocation(bp_addr); - } + if (!module) + return Searcher::eCallbackReturnContinue; + // Is this a module containing renderscript kernels? + if (nullptr == + module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), + eSymbolTypeData)) return Searcher::eCallbackReturnContinue; + + // Attempt to set a breakpoint on the kernel name symbol within the module + // library. + // If it's not found, it's likely debug info is unavailable - try to set a + // breakpoint on <name>.expand. + + const Symbol *kernel_sym = + module->FindFirstSymbolWithNameAndType(m_kernel_name, eSymbolTypeCode); + if (!kernel_sym) { + std::string kernel_name_expanded(m_kernel_name.AsCString()); + kernel_name_expanded.append(".expand"); + kernel_sym = module->FindFirstSymbolWithNameAndType( + ConstString(kernel_name_expanded.c_str()), eSymbolTypeCode); + } + + if (kernel_sym) { + Address bp_addr = kernel_sym->GetAddress(); + if (filter.AddressPasses(bp_addr)) + m_breakpoint->AddLocation(bp_addr); + } + + return Searcher::eCallbackReturnContinue; } -void -RenderScriptRuntime::Initialize() -{ - PluginManager::RegisterPlugin(GetPluginNameStatic(), "RenderScript language support", CreateInstance, - GetCommandObject); +void RenderScriptRuntime::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "RenderScript language support", CreateInstance, + GetCommandObject); } -void -RenderScriptRuntime::Terminate() -{ - PluginManager::UnregisterPlugin(CreateInstance); +void RenderScriptRuntime::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); } -lldb_private::ConstString -RenderScriptRuntime::GetPluginNameStatic() -{ - static ConstString g_name("renderscript"); - return g_name; +lldb_private::ConstString RenderScriptRuntime::GetPluginNameStatic() { + static ConstString g_name("renderscript"); + return g_name; } RenderScriptRuntime::ModuleKind -RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) -{ - if (module_sp) - { - // Is this a module containing renderscript kernels? - const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData); - if (info_sym) - { - return eModuleKindKernelObj; - } +RenderScriptRuntime::GetModuleKind(const lldb::ModuleSP &module_sp) { + if (module_sp) { + // Is this a module containing renderscript kernels? + const Symbol *info_sym = module_sp->FindFirstSymbolWithNameAndType( + ConstString(".rs.info"), eSymbolTypeData); + if (info_sym) { + return eModuleKindKernelObj; + } - // Is this the main RS runtime library - const ConstString rs_lib("libRS.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_lib) - { - return eModuleKindLibRS; - } + // Is this the main RS runtime library + const ConstString rs_lib("libRS.so"); + if (module_sp->GetFileSpec().GetFilename() == rs_lib) { + return eModuleKindLibRS; + } - const ConstString rs_driverlib("libRSDriver.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) - { - return eModuleKindDriver; - } + const ConstString rs_driverlib("libRSDriver.so"); + if (module_sp->GetFileSpec().GetFilename() == rs_driverlib) { + return eModuleKindDriver; + } - const ConstString rs_cpureflib("libRSCpuRef.so"); - if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) - { - return eModuleKindImpl; - } + const ConstString rs_cpureflib("libRSCpuRef.so"); + if (module_sp->GetFileSpec().GetFilename() == rs_cpureflib) { + return eModuleKindImpl; } - return eModuleKindIgnored; + } + return eModuleKindIgnored; } -bool -RenderScriptRuntime::IsRenderScriptModule(const lldb::ModuleSP &module_sp) -{ - return GetModuleKind(module_sp) != eModuleKindIgnored; +bool RenderScriptRuntime::IsRenderScriptModule( + const lldb::ModuleSP &module_sp) { + return GetModuleKind(module_sp) != eModuleKindIgnored; } -void -RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) -{ - std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); +void RenderScriptRuntime::ModulesDidLoad(const ModuleList &module_list) { + std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex()); - size_t num_modules = module_list.GetSize(); - for (size_t i = 0; i < num_modules; i++) - { - auto mod = module_list.GetModuleAtIndex(i); - if (IsRenderScriptModule(mod)) - { - LoadModule(mod); - } + size_t num_modules = module_list.GetSize(); + for (size_t i = 0; i < num_modules; i++) { + auto mod = module_list.GetModuleAtIndex(i); + if (IsRenderScriptModule(mod)) { + LoadModule(mod); } + } } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -lldb_private::ConstString -RenderScriptRuntime::GetPluginName() -{ - return GetPluginNameStatic(); +lldb_private::ConstString RenderScriptRuntime::GetPluginName() { + return GetPluginNameStatic(); } -uint32_t -RenderScriptRuntime::GetPluginVersion() -{ - return 1; -} +uint32_t RenderScriptRuntime::GetPluginVersion() { return 1; } -bool -RenderScriptRuntime::IsVTableName(const char *name) -{ - return false; -} +bool RenderScriptRuntime::IsVTableName(const char *name) { return false; } -bool -RenderScriptRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &address, - Value::ValueType &value_type) -{ - return false; +bool RenderScriptRuntime::GetDynamicTypeAndAddress( + ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &address, + Value::ValueType &value_type) { + return false; } TypeAndOrName -RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) -{ - return type_and_or_name; +RenderScriptRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) { + return type_and_or_name; } -bool -RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) -{ - return false; +bool RenderScriptRuntime::CouldHaveDynamicValue(ValueObject &in_value) { + return false; } lldb::BreakpointResolverSP -RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) -{ - BreakpointResolverSP resolver_sp; - return resolver_sp; +RenderScriptRuntime::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, + bool throw_bp) { + BreakpointResolverSP resolver_sp; + return resolver_sp; } -const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = { - // rsdScript - { - "rsdScriptInit", - "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhjj", - "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_7ScriptCEPKcS7_PKhmj", - 0, - RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureScriptInit - }, - { - "rsdScriptInvokeForEachMulti", - "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", - "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", - 0, - RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti - }, - { - "rsdScriptSetGlobalVar", - "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvj", - "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_6ScriptEjPvm", - 0, - RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar - }, - - // rsdAllocation - { - "rsdAllocationInit", - "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", - "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_10AllocationEb", - 0, - RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureAllocationInit - }, - { - "rsdAllocationRead2D", - "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvjj", - "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_10AllocationEjjj23RsAllocationCubemapFacejjPvmm", - 0, - RenderScriptRuntime::eModuleKindDriver, - nullptr - }, - { - "rsdAllocationDestroy", - "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", - "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_10AllocationE", - 0, - RenderScriptRuntime::eModuleKindDriver, - &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy - }, +const RenderScriptRuntime::HookDefn RenderScriptRuntime::s_runtimeHookDefns[] = + { + // rsdScript + {"rsdScriptInit", "_Z13rsdScriptInitPKN7android12renderscript7ContextEP" + "NS0_7ScriptCEPKcS7_PKhjj", + "_Z13rsdScriptInitPKN7android12renderscript7ContextEPNS0_" + "7ScriptCEPKcS7_PKhmj", + 0, RenderScriptRuntime::eModuleKindDriver, + &lldb_private::RenderScriptRuntime::CaptureScriptInit}, + {"rsdScriptInvokeForEachMulti", + "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" + "_6ScriptEjPPKNS0_10AllocationEjPS6_PKvjPK12RsScriptCall", + "_Z27rsdScriptInvokeForEachMultiPKN7android12renderscript7ContextEPNS0" + "_6ScriptEjPPKNS0_10AllocationEmPS6_PKvmPK12RsScriptCall", + 0, RenderScriptRuntime::eModuleKindDriver, + &lldb_private::RenderScriptRuntime::CaptureScriptInvokeForEachMulti}, + {"rsdScriptSetGlobalVar", "_Z21rsdScriptSetGlobalVarPKN7android12render" + "script7ContextEPKNS0_6ScriptEjPvj", + "_Z21rsdScriptSetGlobalVarPKN7android12renderscript7ContextEPKNS0_" + "6ScriptEjPvm", + 0, RenderScriptRuntime::eModuleKindDriver, + &lldb_private::RenderScriptRuntime::CaptureSetGlobalVar}, + + // rsdAllocation + {"rsdAllocationInit", "_Z17rsdAllocationInitPKN7android12renderscript7C" + "ontextEPNS0_10AllocationEb", + "_Z17rsdAllocationInitPKN7android12renderscript7ContextEPNS0_" + "10AllocationEb", + 0, RenderScriptRuntime::eModuleKindDriver, + &lldb_private::RenderScriptRuntime::CaptureAllocationInit}, + {"rsdAllocationRead2D", + "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" + "10AllocationEjjj23RsAllocationCubemapFacejjPvjj", + "_Z19rsdAllocationRead2DPKN7android12renderscript7ContextEPKNS0_" + "10AllocationEjjj23RsAllocationCubemapFacejjPvmm", + 0, RenderScriptRuntime::eModuleKindDriver, nullptr}, + {"rsdAllocationDestroy", "_Z20rsdAllocationDestroyPKN7android12rendersc" + "ript7ContextEPNS0_10AllocationE", + "_Z20rsdAllocationDestroyPKN7android12renderscript7ContextEPNS0_" + "10AllocationE", + 0, RenderScriptRuntime::eModuleKindDriver, + &lldb_private::RenderScriptRuntime::CaptureAllocationDestroy}, }; -const size_t RenderScriptRuntime::s_runtimeHookCount = sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); +const size_t RenderScriptRuntime::s_runtimeHookCount = + sizeof(s_runtimeHookDefns) / sizeof(s_runtimeHookDefns[0]); -bool -RenderScriptRuntime::HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) -{ - RuntimeHook *hook_info = (RuntimeHook *)baton; - ExecutionContext context(ctx->exe_ctx_ref); +bool RenderScriptRuntime::HookCallback(void *baton, + StoppointCallbackContext *ctx, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id) { + RuntimeHook *hook_info = (RuntimeHook *)baton; + ExecutionContext context(ctx->exe_ctx_ref); - RenderScriptRuntime *lang_rt = - (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); + RenderScriptRuntime *lang_rt = + (RenderScriptRuntime *)context.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); - lang_rt->HookCallback(hook_info, context); + lang_rt->HookCallback(hook_info, context); - return false; + return false; } -void -RenderScriptRuntime::HookCallback(RuntimeHook *hook_info, ExecutionContext &context) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +void RenderScriptRuntime::HookCallback(RuntimeHook *hook_info, + ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (log) - log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name); + if (log) + log->Printf("%s - '%s'", __FUNCTION__, hook_info->defn->name); - if (hook_info->defn->grabber) - { - (this->*(hook_info->defn->grabber))(hook_info, context); - } + if (hook_info->defn->grabber) { + (this->*(hook_info->defn->grabber))(hook_info, context); + } } -void -RenderScriptRuntime::CaptureScriptInvokeForEachMulti(RuntimeHook* hook_info, - ExecutionContext& context) -{ - Log* log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - enum - { - eRsContext = 0, - eRsScript, - eRsSlot, - eRsAIns, - eRsInLen, - eRsAOut, - eRsUsr, - eRsUsrLen, - eRsSc, - }; - - std::array<ArgItem, 9> args{{ - ArgItem{ArgItem::ePointer, 0}, // const Context *rsc - ArgItem{ArgItem::ePointer, 0}, // Script *s - ArgItem{ArgItem::eInt32, 0}, // uint32_t slot - ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns - ArgItem{ArgItem::eInt32, 0}, // size_t inLen - ArgItem{ArgItem::ePointer, 0}, // Allocation *aout - ArgItem{ArgItem::ePointer, 0}, // const void *usr - ArgItem{ArgItem::eInt32, 0}, // size_t usrLen - ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc - }}; - - bool success = GetArgs(context, &args[0], args.size()); - if (!success) - { - if (log) - log->Printf("%s - Error while reading the function parameters", __FUNCTION__); - return; - } - - const uint32_t target_ptr_size = m_process->GetAddressByteSize(); - Error error; - std::vector<uint64_t> allocs; - - // traverse allocation list - for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) - { - // calculate offest to allocation pointer - const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; - - // Note: due to little endian layout, reading 32bits or 64bits into res64 will - // give the correct results. - - uint64_t res64 = 0; - size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error); - if (read != target_ptr_size || !error.Success()) - { - if (log) - log->Printf("%s - Error while reading allocation list argument %" PRIu64, __FUNCTION__, i); - } - else - { - allocs.push_back(res64); - } - } - - // if there is an output allocation track it - if (uint64_t aOut = uint64_t(args[eRsAOut])) - { - allocs.push_back(aOut); - } - - // for all allocations we have found - for (const uint64_t alloc_addr : allocs) - { - AllocationDetails *alloc = LookUpAllocation(alloc_addr); - if (!alloc) - alloc = CreateAllocation(alloc_addr); - - if (alloc) - { - // save the allocation address - if (alloc->address.isValid()) - { - // check the allocation address we already have matches - assert(*alloc->address.get() == alloc_addr); - } - else - { - alloc->address = alloc_addr; - } - - // save the context - if (log) - { - if (alloc->context.isValid() && *alloc->context.get() != addr_t(args[eRsContext])) - log->Printf("%s - Allocation used by multiple contexts", __FUNCTION__); - } - alloc->context = addr_t(args[eRsContext]); - } - } - - // make sure we track this script object - if (lldb_private::RenderScriptRuntime::ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true)) - { - if (log) - { - if (script->context.isValid() && *script->context.get() != addr_t(args[eRsContext])) - log->Printf("%s - Script used by multiple contexts", __FUNCTION__); - } - script->context = addr_t(args[eRsContext]); - } +void RenderScriptRuntime::CaptureScriptInvokeForEachMulti( + RuntimeHook *hook_info, ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + enum { + eRsContext = 0, + eRsScript, + eRsSlot, + eRsAIns, + eRsInLen, + eRsAOut, + eRsUsr, + eRsUsrLen, + eRsSc, + }; + + std::array<ArgItem, 9> args{{ + ArgItem{ArgItem::ePointer, 0}, // const Context *rsc + ArgItem{ArgItem::ePointer, 0}, // Script *s + ArgItem{ArgItem::eInt32, 0}, // uint32_t slot + ArgItem{ArgItem::ePointer, 0}, // const Allocation **aIns + ArgItem{ArgItem::eInt32, 0}, // size_t inLen + ArgItem{ArgItem::ePointer, 0}, // Allocation *aout + ArgItem{ArgItem::ePointer, 0}, // const void *usr + ArgItem{ArgItem::eInt32, 0}, // size_t usrLen + ArgItem{ArgItem::ePointer, 0}, // const RsScriptCall *sc + }}; + + bool success = GetArgs(context, &args[0], args.size()); + if (!success) { + if (log) + log->Printf("%s - Error while reading the function parameters", + __FUNCTION__); + return; + } + + const uint32_t target_ptr_size = m_process->GetAddressByteSize(); + Error error; + std::vector<uint64_t> allocs; + + // traverse allocation list + for (uint64_t i = 0; i < uint64_t(args[eRsInLen]); ++i) { + // calculate offest to allocation pointer + const addr_t addr = addr_t(args[eRsAIns]) + i * target_ptr_size; + + // Note: due to little endian layout, reading 32bits or 64bits into res64 + // will + // give the correct results. + + uint64_t res64 = 0; + size_t read = m_process->ReadMemory(addr, &res64, target_ptr_size, error); + if (read != target_ptr_size || !error.Success()) { + if (log) + log->Printf( + "%s - Error while reading allocation list argument %" PRIu64, + __FUNCTION__, i); + } else { + allocs.push_back(res64); + } + } + + // if there is an output allocation track it + if (uint64_t aOut = uint64_t(args[eRsAOut])) { + allocs.push_back(aOut); + } + + // for all allocations we have found + for (const uint64_t alloc_addr : allocs) { + AllocationDetails *alloc = LookUpAllocation(alloc_addr); + if (!alloc) + alloc = CreateAllocation(alloc_addr); + + if (alloc) { + // save the allocation address + if (alloc->address.isValid()) { + // check the allocation address we already have matches + assert(*alloc->address.get() == alloc_addr); + } else { + alloc->address = alloc_addr; + } + + // save the context + if (log) { + if (alloc->context.isValid() && + *alloc->context.get() != addr_t(args[eRsContext])) + log->Printf("%s - Allocation used by multiple contexts", + __FUNCTION__); + } + alloc->context = addr_t(args[eRsContext]); + } + } + + // make sure we track this script object + if (lldb_private::RenderScriptRuntime::ScriptDetails *script = + LookUpScript(addr_t(args[eRsScript]), true)) { + if (log) { + if (script->context.isValid() && + *script->context.get() != addr_t(args[eRsContext])) + log->Printf("%s - Script used by multiple contexts", __FUNCTION__); + } + script->context = addr_t(args[eRsContext]); + } } -void -RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info, ExecutionContext &context) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - enum - { - eRsContext, - eRsScript, - eRsId, - eRsData, - eRsLength, - }; - - std::array<ArgItem, 5> args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsScript - ArgItem{ArgItem::eInt32, 0}, // eRsId - ArgItem{ArgItem::ePointer, 0}, // eRsData - ArgItem{ArgItem::eInt32, 0}, // eRsLength - }}; - - bool success = GetArgs(context, &args[0], args.size()); - if (!success) - { - if (log) - log->Printf("%s - error reading the function parameters.", __FUNCTION__); - return; - } - +void RenderScriptRuntime::CaptureSetGlobalVar(RuntimeHook *hook_info, + ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + enum { + eRsContext, + eRsScript, + eRsId, + eRsData, + eRsLength, + }; + + std::array<ArgItem, 5> args{{ + ArgItem{ArgItem::ePointer, 0}, // eRsContext + ArgItem{ArgItem::ePointer, 0}, // eRsScript + ArgItem{ArgItem::eInt32, 0}, // eRsId + ArgItem{ArgItem::ePointer, 0}, // eRsData + ArgItem{ArgItem::eInt32, 0}, // eRsLength + }}; + + bool success = GetArgs(context, &args[0], args.size()); + if (!success) { if (log) - { - log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 ":%" PRIu64 "bytes.", __FUNCTION__, - uint64_t(args[eRsContext]), uint64_t(args[eRsScript]), uint64_t(args[eRsId]), - uint64_t(args[eRsData]), uint64_t(args[eRsLength])); - - addr_t script_addr = addr_t(args[eRsScript]); - if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) - { - auto rsm = m_scriptMappings[script_addr]; - if (uint64_t(args[eRsId]) < rsm->m_globals.size()) - { - auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; - log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__, rsg.m_name.AsCString(), - rsm->m_module->GetFileSpec().GetFilename().AsCString()); - } - } - } + log->Printf("%s - error reading the function parameters.", __FUNCTION__); + return; + } + + if (log) { + log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " slot %" PRIu64 " = 0x%" PRIx64 + ":%" PRIu64 "bytes.", + __FUNCTION__, uint64_t(args[eRsContext]), + uint64_t(args[eRsScript]), uint64_t(args[eRsId]), + uint64_t(args[eRsData]), uint64_t(args[eRsLength])); + + addr_t script_addr = addr_t(args[eRsScript]); + if (m_scriptMappings.find(script_addr) != m_scriptMappings.end()) { + auto rsm = m_scriptMappings[script_addr]; + if (uint64_t(args[eRsId]) < rsm->m_globals.size()) { + auto rsg = rsm->m_globals[uint64_t(args[eRsId])]; + log->Printf("%s - Setting of '%s' within '%s' inferred", __FUNCTION__, + rsg.m_name.AsCString(), + rsm->m_module->GetFileSpec().GetFilename().AsCString()); + } + } + } } -void -RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info, ExecutionContext &context) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +void RenderScriptRuntime::CaptureAllocationInit(RuntimeHook *hook_info, + ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - enum - { - eRsContext, - eRsAlloc, - eRsForceZero - }; - - std::array<ArgItem, 3> args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsAlloc - ArgItem{ArgItem::eBool, 0}, // eRsForceZero - }}; - - bool success = GetArgs(context, &args[0], args.size()); - if (!success) // error case - { - if (log) - log->Printf("%s - error while reading the function parameters", __FUNCTION__); - return; // abort - } + enum { eRsContext, eRsAlloc, eRsForceZero }; - if (log) - log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", __FUNCTION__, uint64_t(args[eRsContext]), - uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero])); + std::array<ArgItem, 3> args{{ + ArgItem{ArgItem::ePointer, 0}, // eRsContext + ArgItem{ArgItem::ePointer, 0}, // eRsAlloc + ArgItem{ArgItem::eBool, 0}, // eRsForceZero + }}; - AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); - if (alloc) - alloc->context = uint64_t(args[eRsContext]); + bool success = GetArgs(context, &args[0], args.size()); + if (!success) // error case + { + if (log) + log->Printf("%s - error while reading the function parameters", + __FUNCTION__); + return; // abort + } + + if (log) + log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 ",0x%" PRIx64 " .", + __FUNCTION__, uint64_t(args[eRsContext]), + uint64_t(args[eRsAlloc]), uint64_t(args[eRsForceZero])); + + AllocationDetails *alloc = CreateAllocation(uint64_t(args[eRsAlloc])); + if (alloc) + alloc->context = uint64_t(args[eRsContext]); } -void -RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info, ExecutionContext &context) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +void RenderScriptRuntime::CaptureAllocationDestroy(RuntimeHook *hook_info, + ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - enum - { - eRsContext, - eRsAlloc, - }; + enum { + eRsContext, + eRsAlloc, + }; - std::array<ArgItem, 2> args{{ - ArgItem{ArgItem::ePointer, 0}, // eRsContext - ArgItem{ArgItem::ePointer, 0}, // eRsAlloc - }}; - - bool success = GetArgs(context, &args[0], args.size()); - if (!success) - { - if (log) - log->Printf("%s - error while reading the function parameters.", __FUNCTION__); - return; - } + std::array<ArgItem, 2> args{{ + ArgItem{ArgItem::ePointer, 0}, // eRsContext + ArgItem{ArgItem::ePointer, 0}, // eRsAlloc + }}; + bool success = GetArgs(context, &args[0], args.size()); + if (!success) { if (log) - log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, uint64_t(args[eRsContext]), - uint64_t(args[eRsAlloc])); - - for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) - { - auto &allocation_ap = *iter; // get the unique pointer - if (allocation_ap->address.isValid() && *allocation_ap->address.get() == addr_t(args[eRsAlloc])) - { - m_allocations.erase(iter); - if (log) - log->Printf("%s - deleted allocation entry.", __FUNCTION__); - return; - } - } - - if (log) - log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__); + log->Printf("%s - error while reading the function parameters.", + __FUNCTION__); + return; + } + + if (log) + log->Printf("%s - 0x%" PRIx64 ", 0x%" PRIx64 ".", __FUNCTION__, + uint64_t(args[eRsContext]), uint64_t(args[eRsAlloc])); + + for (auto iter = m_allocations.begin(); iter != m_allocations.end(); ++iter) { + auto &allocation_ap = *iter; // get the unique pointer + if (allocation_ap->address.isValid() && + *allocation_ap->address.get() == addr_t(args[eRsAlloc])) { + m_allocations.erase(iter); + if (log) + log->Printf("%s - deleted allocation entry.", __FUNCTION__); + return; + } + } + + if (log) + log->Printf("%s - couldn't find destroyed allocation.", __FUNCTION__); } -void -RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info, ExecutionContext &context) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +void RenderScriptRuntime::CaptureScriptInit(RuntimeHook *hook_info, + ExecutionContext &context) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - Error error; - Process *process = context.GetProcessPtr(); + Error error; + Process *process = context.GetProcessPtr(); - enum - { - eRsContext, - eRsScript, - eRsResNamePtr, - eRsCachedDirPtr - }; - - std::array<ArgItem, 4> args{{ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, - ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; - bool success = GetArgs(context, &args[0], args.size()); - if (!success) - { - if (log) - log->Printf("%s - error while reading the function parameters.", __FUNCTION__); - return; - } - - std::string resname; - process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error); - if (error.Fail()) - { - if (log) - log->Printf("%s - error reading resname: %s.", __FUNCTION__, error.AsCString()); - } - - std::string cachedir; - process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir, error); - if (error.Fail()) - { - if (log) - log->Printf("%s - error reading cachedir: %s.", __FUNCTION__, error.AsCString()); - } + enum { eRsContext, eRsScript, eRsResNamePtr, eRsCachedDirPtr }; + std::array<ArgItem, 4> args{ + {ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}, + ArgItem{ArgItem::ePointer, 0}, ArgItem{ArgItem::ePointer, 0}}}; + bool success = GetArgs(context, &args[0], args.size()); + if (!success) { if (log) - log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", __FUNCTION__, uint64_t(args[eRsContext]), - uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str()); - - if (resname.size() > 0) - { - StreamString strm; - strm.Printf("librs.%s.so", resname.c_str()); - - ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); - if (script) - { - script->type = ScriptDetails::eScriptC; - script->cacheDir = cachedir; - script->resName = resname; - script->scriptDyLib = strm.GetData(); - script->context = addr_t(args[eRsContext]); - } - - if (log) - log->Printf("%s - '%s' tagged with context 0x%" PRIx64 " and script 0x%" PRIx64 ".", __FUNCTION__, - strm.GetData(), uint64_t(args[eRsContext]), uint64_t(args[eRsScript])); - } - else if (log) - { - log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__); - } -} + log->Printf("%s - error while reading the function parameters.", + __FUNCTION__); + return; + } + + std::string resname; + process->ReadCStringFromMemory(addr_t(args[eRsResNamePtr]), resname, error); + if (error.Fail()) { + if (log) + log->Printf("%s - error reading resname: %s.", __FUNCTION__, + error.AsCString()); + } + + std::string cachedir; + process->ReadCStringFromMemory(addr_t(args[eRsCachedDirPtr]), cachedir, + error); + if (error.Fail()) { + if (log) + log->Printf("%s - error reading cachedir: %s.", __FUNCTION__, + error.AsCString()); + } -void -RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + if (log) + log->Printf("%s - 0x%" PRIx64 ",0x%" PRIx64 " => '%s' at '%s' .", + __FUNCTION__, uint64_t(args[eRsContext]), + uint64_t(args[eRsScript]), resname.c_str(), cachedir.c_str()); - if (!module) - { - return; - } + if (resname.size() > 0) { + StreamString strm; + strm.Printf("librs.%s.so", resname.c_str()); - Target &target = GetProcess()->GetTarget(); - llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine(); - - if (targetArchType != llvm::Triple::ArchType::x86 && - targetArchType != llvm::Triple::ArchType::arm && - targetArchType != llvm::Triple::ArchType::aarch64 && - targetArchType != llvm::Triple::ArchType::mipsel && - targetArchType != llvm::Triple::ArchType::mips64el && - targetArchType != llvm::Triple::ArchType::x86_64) - { - if (log) - log->Printf("%s - unable to hook runtime functions.", __FUNCTION__); - return; + ScriptDetails *script = LookUpScript(addr_t(args[eRsScript]), true); + if (script) { + script->type = ScriptDetails::eScriptC; + script->cacheDir = cachedir; + script->resName = resname; + script->scriptDyLib = strm.GetData(); + script->context = addr_t(args[eRsContext]); } - uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize(); - - for (size_t idx = 0; idx < s_runtimeHookCount; idx++) - { - const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; - if (hook_defn->kind != kind) - { - continue; - } + if (log) + log->Printf("%s - '%s' tagged with context 0x%" PRIx64 + " and script 0x%" PRIx64 ".", + __FUNCTION__, strm.GetData(), uint64_t(args[eRsContext]), + uint64_t(args[eRsScript])); + } else if (log) { + log->Printf("%s - resource name invalid, Script not tagged.", __FUNCTION__); + } +} - const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 : hook_defn->symbol_name_m64; +void RenderScriptRuntime::LoadRuntimeHooks(lldb::ModuleSP module, + ModuleKind kind) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - const Symbol *sym = module->FindFirstSymbolWithNameAndType(ConstString(symbol_name), eSymbolTypeCode); - if (!sym) - { - if (log) - { - log->Printf("%s - symbol '%s' related to the function %s not found", - __FUNCTION__, symbol_name, hook_defn->name); - } - continue; - } + if (!module) { + return; + } - addr_t addr = sym->GetLoadAddress(&target); - if (addr == LLDB_INVALID_ADDRESS) - { - if (log) - log->Printf("%s - unable to resolve the address of hook function '%s' with symbol '%s'.", - __FUNCTION__, hook_defn->name, symbol_name); - continue; - } - else - { - if (log) - log->Printf("%s - function %s, address resolved at 0x%" PRIx64, - __FUNCTION__, hook_defn->name, addr); - } + Target &target = GetProcess()->GetTarget(); + llvm::Triple::ArchType targetArchType = target.GetArchitecture().GetMachine(); - RuntimeHookSP hook(new RuntimeHook()); - hook->address = addr; - hook->defn = hook_defn; - hook->bp_sp = target.CreateBreakpoint(addr, true, false); - hook->bp_sp->SetCallback(HookCallback, hook.get(), true); - m_runtimeHooks[addr] = hook; - if (log) - { - log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64 " at 0x%" PRIx64 ".", - __FUNCTION__, hook_defn->name, module->GetFileSpec().GetFilename().AsCString(), - (uint64_t)hook_defn->version, (uint64_t)addr); - } - } + if (targetArchType != llvm::Triple::ArchType::x86 && + targetArchType != llvm::Triple::ArchType::arm && + targetArchType != llvm::Triple::ArchType::aarch64 && + targetArchType != llvm::Triple::ArchType::mipsel && + targetArchType != llvm::Triple::ArchType::mips64el && + targetArchType != llvm::Triple::ArchType::x86_64) { + if (log) + log->Printf("%s - unable to hook runtime functions.", __FUNCTION__); + return; + } + + uint32_t archByteSize = target.GetArchitecture().GetAddressByteSize(); + + for (size_t idx = 0; idx < s_runtimeHookCount; idx++) { + const HookDefn *hook_defn = &s_runtimeHookDefns[idx]; + if (hook_defn->kind != kind) { + continue; + } + + const char *symbol_name = (archByteSize == 4) ? hook_defn->symbol_name_m32 + : hook_defn->symbol_name_m64; + + const Symbol *sym = module->FindFirstSymbolWithNameAndType( + ConstString(symbol_name), eSymbolTypeCode); + if (!sym) { + if (log) { + log->Printf("%s - symbol '%s' related to the function %s not found", + __FUNCTION__, symbol_name, hook_defn->name); + } + continue; + } + + addr_t addr = sym->GetLoadAddress(&target); + if (addr == LLDB_INVALID_ADDRESS) { + if (log) + log->Printf("%s - unable to resolve the address of hook function '%s' " + "with symbol '%s'.", + __FUNCTION__, hook_defn->name, symbol_name); + continue; + } else { + if (log) + log->Printf("%s - function %s, address resolved at 0x%" PRIx64, + __FUNCTION__, hook_defn->name, addr); + } + + RuntimeHookSP hook(new RuntimeHook()); + hook->address = addr; + hook->defn = hook_defn; + hook->bp_sp = target.CreateBreakpoint(addr, true, false); + hook->bp_sp->SetCallback(HookCallback, hook.get(), true); + m_runtimeHooks[addr] = hook; + if (log) { + log->Printf("%s - successfully hooked '%s' in '%s' version %" PRIu64 + " at 0x%" PRIx64 ".", + __FUNCTION__, hook_defn->name, + module->GetFileSpec().GetFilename().AsCString(), + (uint64_t)hook_defn->version, (uint64_t)addr); + } + } } -void -RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) -{ - if (!rsmodule_sp) - return; +void RenderScriptRuntime::FixupScriptDetails(RSModuleDescriptorSP rsmodule_sp) { + if (!rsmodule_sp) + return; - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - const ModuleSP module = rsmodule_sp->m_module; - const FileSpec &file = module->GetPlatformFileSpec(); + const ModuleSP module = rsmodule_sp->m_module; + const FileSpec &file = module->GetPlatformFileSpec(); - // Iterate over all of the scripts that we currently know of. - // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. - for (const auto &rs_script : m_scripts) - { - // Extract the expected .so file path for this script. - std::string dylib; - if (!rs_script->scriptDyLib.get(dylib)) - continue; + // Iterate over all of the scripts that we currently know of. + // Note: We cant push or pop to m_scripts here or it may invalidate rs_script. + for (const auto &rs_script : m_scripts) { + // Extract the expected .so file path for this script. + std::string dylib; + if (!rs_script->scriptDyLib.get(dylib)) + continue; - // Only proceed if the module that has loaded corresponds to this script. - if (file.GetFilename() != ConstString(dylib.c_str())) - continue; + // Only proceed if the module that has loaded corresponds to this script. + if (file.GetFilename() != ConstString(dylib.c_str())) + continue; - // Obtain the script address which we use as a key. - lldb::addr_t script; - if (!rs_script->script.get(script)) - continue; + // Obtain the script address which we use as a key. + lldb::addr_t script; + if (!rs_script->script.get(script)) + continue; - // If we have a script mapping for the current script. - if (m_scriptMappings.find(script) != m_scriptMappings.end()) - { - // if the module we have stored is different to the one we just received. - if (m_scriptMappings[script] != rsmodule_sp) - { - if (log) - log->Printf("%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", __FUNCTION__, - (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } - } - // We don't have a script mapping for the current script. - else - { - // Obtain the script resource name. - std::string resName; - if (rs_script->resName.get(resName)) - // Set the modules resource name. - rsmodule_sp->m_resname = resName; - // Add Script/Module pair to map. - m_scriptMappings[script] = rsmodule_sp; - if (log) - log->Printf("%s - script %" PRIx64 " associated with rsmodule '%s'.", __FUNCTION__, - (uint64_t)script, rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); - } - } + // If we have a script mapping for the current script. + if (m_scriptMappings.find(script) != m_scriptMappings.end()) { + // if the module we have stored is different to the one we just received. + if (m_scriptMappings[script] != rsmodule_sp) { + if (log) + log->Printf( + "%s - script %" PRIx64 " wants reassigned to new rsmodule '%s'.", + __FUNCTION__, (uint64_t)script, + rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); + } + } + // We don't have a script mapping for the current script. + else { + // Obtain the script resource name. + std::string resName; + if (rs_script->resName.get(resName)) + // Set the modules resource name. + rsmodule_sp->m_resname = resName; + // Add Script/Module pair to map. + m_scriptMappings[script] = rsmodule_sp; + if (log) + log->Printf( + "%s - script %" PRIx64 " associated with rsmodule '%s'.", + __FUNCTION__, (uint64_t)script, + rsmodule_sp->m_module->GetFileSpec().GetFilename().AsCString()); + } + } } -// Uses the Target API to evaluate the expression passed as a parameter to the function -// The result of that expression is returned an unsigned 64 bit int, via the result* parameter. +// Uses the Target API to evaluate the expression passed as a parameter to the +// function +// The result of that expression is returned an unsigned 64 bit int, via the +// result* parameter. // Function returns true on success, and false on failure -bool -RenderScriptRuntime::EvalRSExpression(const char *expression, StackFrame *frame_ptr, uint64_t *result) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::EvalRSExpression(const char *expression, + StackFrame *frame_ptr, + uint64_t *result) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + if (log) + log->Printf("%s(%s)", __FUNCTION__, expression); + + ValueObjectSP expr_result; + EvaluateExpressionOptions options; + options.SetLanguage(lldb::eLanguageTypeC_plus_plus); + // Perform the actual expression evaluation + GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, + expr_result, options); + + if (!expr_result) { if (log) - log->Printf("%s(%s)", __FUNCTION__, expression); - - ValueObjectSP expr_result; - EvaluateExpressionOptions options; - options.SetLanguage(lldb::eLanguageTypeC_plus_plus); - // Perform the actual expression evaluation - GetProcess()->GetTarget().EvaluateExpression(expression, frame_ptr, expr_result, options); - - if (!expr_result) - { - if (log) - log->Printf("%s: couldn't evaluate expression.", __FUNCTION__); - return false; - } + log->Printf("%s: couldn't evaluate expression.", __FUNCTION__); + return false; + } - // The result of the expression is invalid - if (!expr_result->GetError().Success()) + // The result of the expression is invalid + if (!expr_result->GetError().Success()) { + Error err = expr_result->GetError(); + if (err.GetError() == UserExpression::kNoResult) // Expression returned + // void, so this is + // actually a success { - Error err = expr_result->GetError(); - if (err.GetError() == UserExpression::kNoResult) // Expression returned void, so this is actually a success - { - if (log) - log->Printf("%s - expression returned void.", __FUNCTION__); - - result = nullptr; - return true; - } + if (log) + log->Printf("%s - expression returned void.", __FUNCTION__); - if (log) - log->Printf("%s - error evaluating expression result: %s", __FUNCTION__, - err.AsCString()); - return false; + result = nullptr; + return true; } - bool success = false; - *result = expr_result->GetValueAsUnsigned(0, &success); // We only read the result as an uint32_t. + if (log) + log->Printf("%s - error evaluating expression result: %s", __FUNCTION__, + err.AsCString()); + return false; + } - if (!success) - { - if (log) - log->Printf("%s - couldn't convert expression result to uint32_t", __FUNCTION__); - return false; - } + bool success = false; + *result = expr_result->GetValueAsUnsigned( + 0, &success); // We only read the result as an uint32_t. - return true; + if (!success) { + if (log) + log->Printf("%s - couldn't convert expression result to uint32_t", + __FUNCTION__); + return false; + } + + return true; } -namespace -{ +namespace { // Used to index expression format strings -enum ExpressionStrings -{ - eExprGetOffsetPtr = 0, - eExprAllocGetType, - eExprTypeDimX, - eExprTypeDimY, - eExprTypeDimZ, - eExprTypeElemPtr, - eExprElementType, - eExprElementKind, - eExprElementVec, - eExprElementFieldCount, - eExprSubelementsId, - eExprSubelementsName, - eExprSubelementsArrSize, - - _eExprLast // keep at the end, implicit size of the array runtimeExpressions +enum ExpressionStrings { + eExprGetOffsetPtr = 0, + eExprAllocGetType, + eExprTypeDimX, + eExprTypeDimY, + eExprTypeDimZ, + eExprTypeElemPtr, + eExprElementType, + eExprElementKind, + eExprElementVec, + eExprElementFieldCount, + eExprSubelementsId, + eExprSubelementsName, + eExprSubelementsArrSize, + + _eExprLast // keep at the end, implicit size of the array runtimeExpressions }; // max length of an expanded expression const int jit_max_expr_size = 512; // Retrieve the string to JIT for the given expression -const char* -JITTemplate(ExpressionStrings e) -{ - // Format strings containing the expressions we may need to evaluate. - static std::array<const char*, _eExprLast> runtimeExpressions = {{ - // Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) - "(int*)_Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocationCubemapFace" - "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", - - // Type* rsaAllocationGetType(Context*, Allocation*) - "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")", - - // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) - // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ; - // mHal.state.lodCount; mHal.state.faces; mElement; into typeData - // Need to specify 32 or 64 bit for uint_t since this differs between devices - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 6); data[0]", // X dim - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim - "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr - - // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) - // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into elemData - "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 5); data[0]", // Type - "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 5); data[1]", // Kind - "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size - "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count - - // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t *ids, const char **names, - // size_t *arraySizes, uint32_t dataSize) - // Needed for Allocations of structs to gather details about fields/Subelements - // Element* of field - "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", - - // Name of field - "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", - - // Array size of field - "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 "]; size_t arr_size[%" PRIu32 "];" - "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]" - }}; - - return runtimeExpressions[e]; +const char *JITTemplate(ExpressionStrings e) { + // Format strings containing the expressions we may need to evaluate. + static std::array<const char *, _eExprLast> runtimeExpressions = { + {// Mangled GetOffsetPointer(Allocation*, xoff, yoff, zoff, lod, cubemap) + "(int*)_" + "Z12GetOffsetPtrPKN7android12renderscript10AllocationEjjjj23RsAllocation" + "CubemapFace" + "(0x%" PRIx64 ", %" PRIu32 ", %" PRIu32 ", %" PRIu32 ", 0, 0)", + + // Type* rsaAllocationGetType(Context*, Allocation*) + "(void*)rsaAllocationGetType(0x%" PRIx64 ", 0x%" PRIx64 ")", + + // rsaTypeGetNativeData(Context*, Type*, void* typeData, size) + // Pack the data in the following way mHal.state.dimX; mHal.state.dimY; + // mHal.state.dimZ; + // mHal.state.lodCount; mHal.state.faces; mElement; into typeData + // Need to specify 32 or 64 bit for uint_t since this differs between + // devices + "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 6); data[0]", // X dim + "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 6); data[1]", // Y dim + "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 6); data[2]", // Z dim + "uint%" PRIu32 "_t data[6]; (void*)rsaTypeGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 6); data[5]", // Element ptr + + // rsaElementGetNativeData(Context*, Element*, uint32_t* elemData,size) + // Pack mType; mKind; mNormalized; mVectorSize; NumSubElements into + // elemData + "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 5); data[0]", // Type + "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 5); data[1]", // Kind + "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 5); data[3]", // Vector Size + "uint32_t data[5]; (void*)rsaElementGetNativeData(0x%" PRIx64 + ", 0x%" PRIx64 ", data, 5); data[4]", // Field Count + + // rsaElementGetSubElements(RsContext con, RsElement elem, uintptr_t + // *ids, const char **names, + // size_t *arraySizes, uint32_t dataSize) + // Needed for Allocations of structs to gather details about + // fields/Subelements + // Element* of field + "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 + "]; size_t arr_size[%" PRIu32 "];" + "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 + ", ids, names, arr_size, %" PRIu32 "); ids[%" PRIu32 "]", + + // Name of field + "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 + "]; size_t arr_size[%" PRIu32 "];" + "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 + ", ids, names, arr_size, %" PRIu32 "); names[%" PRIu32 "]", + + // Array size of field + "void* ids[%" PRIu32 "]; const char* names[%" PRIu32 + "]; size_t arr_size[%" PRIu32 "];" + "(void*)rsaElementGetSubElements(0x%" PRIx64 ", 0x%" PRIx64 + ", ids, names, arr_size, %" PRIu32 "); arr_size[%" PRIu32 "]"}}; + + return runtimeExpressions[e]; } } // end of the anonymous namespace - // JITs the RS runtime for the internal data pointer of an allocation. // Is passed x,y,z coordinates for the pointer to a specific element. // Then sets the data_ptr member in Allocation with the result. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation, StackFrame *frame_ptr, uint32_t x, - uint32_t y, uint32_t z) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::JITDataPointer(AllocationDetails *allocation, + StackFrame *frame_ptr, uint32_t x, + uint32_t y, uint32_t z) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (!allocation->address.isValid()) - { - if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); - return false; - } + if (!allocation->address.isValid()) { + if (log) + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } - const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); - char buffer[jit_max_expr_size]; + const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); + char buffer[jit_max_expr_size]; - int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), x, y, z); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } + int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, + *allocation->address.get(), x, y, z); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } - uint64_t result = 0; - if (!EvalRSExpression(buffer, frame_ptr, &result)) - return false; + uint64_t result = 0; + if (!EvalRSExpression(buffer, frame_ptr, &result)) + return false; - addr_t mem_ptr = static_cast<lldb::addr_t>(result); - allocation->data_ptr = mem_ptr; + addr_t mem_ptr = static_cast<lldb::addr_t>(result); + allocation->data_ptr = mem_ptr; - return true; + return true; } // JITs the RS runtime for the internal pointer to the RS Type of an allocation // Then sets the type_ptr member in Allocation with the result. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::JITTypePointer(AllocationDetails *allocation, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (!allocation->address.isValid() || !allocation->context.isValid()) - { - if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); - return false; - } + if (!allocation->address.isValid() || !allocation->context.isValid()) { + if (log) + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } - const char *expr_cstr = JITTemplate(eExprAllocGetType); - char buffer[jit_max_expr_size]; + const char *expr_cstr = JITTemplate(eExprAllocGetType); + char buffer[jit_max_expr_size]; - int chars_written = - snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), *allocation->address.get()); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } + int chars_written = + snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->context.get(), + *allocation->address.get()); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } - uint64_t result = 0; - if (!EvalRSExpression(buffer, frame_ptr, &result)) - return false; + uint64_t result = 0; + if (!EvalRSExpression(buffer, frame_ptr, &result)) + return false; - addr_t type_ptr = static_cast<lldb::addr_t>(result); - allocation->type_ptr = type_ptr; + addr_t type_ptr = static_cast<lldb::addr_t>(result); + allocation->type_ptr = type_ptr; - return true; + return true; } -// JITs the RS runtime for information about the dimensions and type of an allocation +// JITs the RS runtime for information about the dimensions and type of an +// allocation // Then sets dimension and element_ptr members in Allocation with the result. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::JITTypePacked(AllocationDetails *allocation, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) - { - if (log) - log->Printf("%s - Failed to find allocation details.", __FUNCTION__); - return false; - } - - // Expression is different depending on if device is 32 or 64 bit - uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - const uint32_t bits = archByteSize == 4 ? 32 : 64; - - // We want 4 elements from packed data - const uint32_t num_exprs = 4; - assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && "Invalid number of expressions"); - - char buffer[num_exprs][jit_max_expr_size]; - uint64_t results[num_exprs]; - - for (uint32_t i = 0; i < num_exprs; ++i) - { - const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); - int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits, *allocation->context.get(), - *allocation->type_ptr.get()); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) - return false; - } + if (!allocation->type_ptr.isValid() || !allocation->context.isValid()) { + if (log) + log->Printf("%s - Failed to find allocation details.", __FUNCTION__); + return false; + } - // Assign results to allocation members - AllocationDetails::Dimension dims; - dims.dim_1 = static_cast<uint32_t>(results[0]); - dims.dim_2 = static_cast<uint32_t>(results[1]); - dims.dim_3 = static_cast<uint32_t>(results[2]); - allocation->dimension = dims; + // Expression is different depending on if device is 32 or 64 bit + uint32_t archByteSize = + GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); + const uint32_t bits = archByteSize == 4 ? 32 : 64; - addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); - allocation->element.element_ptr = elem_ptr; + // We want 4 elements from packed data + const uint32_t num_exprs = 4; + assert(num_exprs == (eExprTypeElemPtr - eExprTypeDimX + 1) && + "Invalid number of expressions"); - if (log) - log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") Element*: 0x%" PRIx64 ".", __FUNCTION__, - dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); + char buffer[num_exprs][jit_max_expr_size]; + uint64_t results[num_exprs]; - return true; + for (uint32_t i = 0; i < num_exprs; ++i) { + const char *expr_cstr = JITTemplate(ExpressionStrings(eExprTypeDimX + i)); + int chars_written = + snprintf(buffer[i], jit_max_expr_size, expr_cstr, bits, + *allocation->context.get(), *allocation->type_ptr.get()); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } + + // Perform expression evaluation + if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) + return false; + } + + // Assign results to allocation members + AllocationDetails::Dimension dims; + dims.dim_1 = static_cast<uint32_t>(results[0]); + dims.dim_2 = static_cast<uint32_t>(results[1]); + dims.dim_3 = static_cast<uint32_t>(results[2]); + allocation->dimension = dims; + + addr_t elem_ptr = static_cast<lldb::addr_t>(results[3]); + allocation->element.element_ptr = elem_ptr; + + if (log) + log->Printf("%s - dims (%" PRIu32 ", %" PRIu32 ", %" PRIu32 + ") Element*: 0x%" PRIx64 ".", + __FUNCTION__, dims.dim_1, dims.dim_2, dims.dim_3, elem_ptr); + + return true; } // JITs the RS runtime for information about the Element of an allocation -// Then sets type, type_vec_size, field_count and type_kind members in Element with the result. +// Then sets type, type_vec_size, field_count and type_kind members in Element +// with the result. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITElementPacked(Element &elem, const lldb::addr_t context, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - if (!elem.element_ptr.isValid()) - { - if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - // We want 4 elements from packed data - const uint32_t num_exprs = 4; - assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && "Invalid number of expressions"); - - char buffer[num_exprs][jit_max_expr_size]; - uint64_t results[num_exprs]; - - for (uint32_t i = 0; i < num_exprs; i++) - { - const char *expr_cstr = JITTemplate(ExpressionStrings(eExprElementType + i)); - int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, context, *elem.element_ptr.get()); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) - return false; - } - - // Assign results to allocation members - elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); - elem.type_kind = static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); - elem.type_vec_size = static_cast<uint32_t>(results[2]); - elem.field_count = static_cast<uint32_t>(results[3]); +bool RenderScriptRuntime::JITElementPacked(Element &elem, + const lldb::addr_t context, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + if (!elem.element_ptr.isValid()) { if (log) - log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32 ", vector size %" PRIu32 ", field count %" PRIu32, - __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), *elem.type_vec_size.get(), *elem.field_count.get()); - - // If this Element has subelements then JIT rsaElementGetSubElements() for details about its fields - if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) - return false; + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } + + // We want 4 elements from packed data + const uint32_t num_exprs = 4; + assert(num_exprs == (eExprElementFieldCount - eExprElementType + 1) && + "Invalid number of expressions"); + + char buffer[num_exprs][jit_max_expr_size]; + uint64_t results[num_exprs]; + + for (uint32_t i = 0; i < num_exprs; i++) { + const char *expr_cstr = + JITTemplate(ExpressionStrings(eExprElementType + i)); + int chars_written = snprintf(buffer[i], jit_max_expr_size, expr_cstr, + context, *elem.element_ptr.get()); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } + + // Perform expression evaluation + if (!EvalRSExpression(buffer[i], frame_ptr, &results[i])) + return false; + } + + // Assign results to allocation members + elem.type = static_cast<RenderScriptRuntime::Element::DataType>(results[0]); + elem.type_kind = + static_cast<RenderScriptRuntime::Element::DataKind>(results[1]); + elem.type_vec_size = static_cast<uint32_t>(results[2]); + elem.field_count = static_cast<uint32_t>(results[3]); + + if (log) + log->Printf("%s - data type %" PRIu32 ", pixel type %" PRIu32 + ", vector size %" PRIu32 ", field count %" PRIu32, + __FUNCTION__, *elem.type.get(), *elem.type_kind.get(), + *elem.type_vec_size.get(), *elem.field_count.get()); + + // If this Element has subelements then JIT rsaElementGetSubElements() for + // details about its fields + if (*elem.field_count.get() > 0 && !JITSubelements(elem, context, frame_ptr)) + return false; - return true; + return true; } -// JITs the RS runtime for information about the subelements/fields of a struct allocation -// This is necessary for infering the struct type so we can pretty print the allocation's contents. +// JITs the RS runtime for information about the subelements/fields of a struct +// allocation +// This is necessary for infering the struct type so we can pretty print the +// allocation's contents. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITSubelements(Element &elem, const lldb::addr_t context, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::JITSubelements(Element &elem, + const lldb::addr_t context, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) - { + if (!elem.element_ptr.isValid() || !elem.field_count.isValid()) { + if (log) + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } + + const short num_exprs = 3; + assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && + "Invalid number of expressions"); + + char expr_buffer[jit_max_expr_size]; + uint64_t results; + + // Iterate over struct fields. + const uint32_t field_count = *elem.field_count.get(); + for (uint32_t field_index = 0; field_index < field_count; ++field_index) { + Element child; + for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) { + const char *expr_cstr = + JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); + int chars_written = + snprintf(expr_buffer, jit_max_expr_size, expr_cstr, field_count, + field_count, field_count, context, *elem.element_ptr.get(), + field_count, field_index); + if (chars_written < 0) { if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); return false; - } - - const short num_exprs = 3; - assert(num_exprs == (eExprSubelementsArrSize - eExprSubelementsId + 1) && "Invalid number of expressions"); - - char expr_buffer[jit_max_expr_size]; - uint64_t results; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } - // Iterate over struct fields. - const uint32_t field_count = *elem.field_count.get(); - for (uint32_t field_index = 0; field_index < field_count; ++field_index) - { - Element child; - for (uint32_t expr_index = 0; expr_index < num_exprs; ++expr_index) - { - const char *expr_cstr = JITTemplate(ExpressionStrings(eExprSubelementsId + expr_index)); - int chars_written = snprintf(expr_buffer, jit_max_expr_size, expr_cstr, - field_count, field_count, field_count, - context, *elem.element_ptr.get(), field_count, field_index); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } - - // Perform expression evaluation - if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) - return false; + // Perform expression evaluation + if (!EvalRSExpression(expr_buffer, frame_ptr, &results)) + return false; - if (log) - log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); - - switch (expr_index) - { - case 0: // Element* of child - child.element_ptr = static_cast<addr_t>(results); - break; - case 1: // Name of child - { - lldb::addr_t address = static_cast<addr_t>(results); - Error err; - std::string name; - GetProcess()->ReadCStringFromMemory(address, name, err); - if (!err.Fail()) - child.type_name = ConstString(name); - else - { - if (log) - log->Printf("%s - warning: Couldn't read field name.", __FUNCTION__); - } - break; - } - case 2: // Array size of child - child.array_size = static_cast<uint32_t>(results); - break; - } + if (log) + log->Printf("%s - expr result 0x%" PRIx64 ".", __FUNCTION__, results); + + switch (expr_index) { + case 0: // Element* of child + child.element_ptr = static_cast<addr_t>(results); + break; + case 1: // Name of child + { + lldb::addr_t address = static_cast<addr_t>(results); + Error err; + std::string name; + GetProcess()->ReadCStringFromMemory(address, name, err); + if (!err.Fail()) + child.type_name = ConstString(name); + else { + if (log) + log->Printf("%s - warning: Couldn't read field name.", + __FUNCTION__); } - - // We need to recursively JIT each Element field of the struct since - // structs can be nested inside structs. - if (!JITElementPacked(child, context, frame_ptr)) - return false; - elem.children.push_back(child); - } - - // Try to infer the name of the struct type so we can pretty print the allocation contents. - FindStructTypeName(elem, frame_ptr); - - return true; + break; + } + case 2: // Array size of child + child.array_size = static_cast<uint32_t>(results); + break; + } + } + + // We need to recursively JIT each Element field of the struct since + // structs can be nested inside structs. + if (!JITElementPacked(child, context, frame_ptr)) + return false; + elem.children.push_back(child); + } + + // Try to infer the name of the struct type so we can pretty print the + // allocation contents. + FindStructTypeName(elem, frame_ptr); + + return true; } // JITs the RS runtime for the address of the last element in the allocation. -// The `elem_size` parameter represents the size of a single element, including padding. +// The `elem_size` parameter represents the size of a single element, including +// padding. // Which is needed as an offset from the last element pointer. -// Using this offset minus the starting address we can calculate the size of the allocation. +// Using this offset minus the starting address we can calculate the size of the +// allocation. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - if (!allocation->address.isValid() || !allocation->dimension.isValid() || !allocation->data_ptr.isValid() || - !allocation->element.datum_size.isValid()) - { - if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); - return false; - } - - // Find dimensions - uint32_t dim_x = allocation->dimension.get()->dim_1; - uint32_t dim_y = allocation->dimension.get()->dim_2; - uint32_t dim_z = allocation->dimension.get()->dim_3; +bool RenderScriptRuntime::JITAllocationSize(AllocationDetails *allocation, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - // Our plan of jitting the last element address doesn't seem to work for struct Allocations - // Instead try to infer the size ourselves without any inter element padding. - if (allocation->element.children.size() > 0) - { - if (dim_x == 0) dim_x = 1; - if (dim_y == 0) dim_y = 1; - if (dim_z == 0) dim_z = 1; + if (!allocation->address.isValid() || !allocation->dimension.isValid() || + !allocation->data_ptr.isValid() || + !allocation->element.datum_size.isValid()) { + if (log) + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } + + // Find dimensions + uint32_t dim_x = allocation->dimension.get()->dim_1; + uint32_t dim_y = allocation->dimension.get()->dim_2; + uint32_t dim_z = allocation->dimension.get()->dim_3; + + // Our plan of jitting the last element address doesn't seem to work for + // struct Allocations + // Instead try to infer the size ourselves without any inter element padding. + if (allocation->element.children.size() > 0) { + if (dim_x == 0) + dim_x = 1; + if (dim_y == 0) + dim_y = 1; + if (dim_z == 0) + dim_z = 1; - allocation->size = dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); + allocation->size = + dim_x * dim_y * dim_z * *allocation->element.datum_size.get(); - if (log) - log->Printf("%s - inferred size of struct allocation %" PRIu32 ".", __FUNCTION__, - *allocation->size.get()); - return true; - } + if (log) + log->Printf("%s - inferred size of struct allocation %" PRIu32 ".", + __FUNCTION__, *allocation->size.get()); + return true; + } - const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); - char buffer[jit_max_expr_size]; + const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); + char buffer[jit_max_expr_size]; - // Calculate last element - dim_x = dim_x == 0 ? 0 : dim_x - 1; - dim_y = dim_y == 0 ? 0 : dim_y - 1; - dim_z = dim_z == 0 ? 0 : dim_z - 1; + // Calculate last element + dim_x = dim_x == 0 ? 0 : dim_x - 1; + dim_y = dim_y == 0 ? 0 : dim_y - 1; + dim_z = dim_z == 0 ? 0 : dim_z - 1; - int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), dim_x, dim_y, dim_z); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } + int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, + *allocation->address.get(), dim_x, dim_y, dim_z); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } - uint64_t result = 0; - if (!EvalRSExpression(buffer, frame_ptr, &result)) - return false; + uint64_t result = 0; + if (!EvalRSExpression(buffer, frame_ptr, &result)) + return false; - addr_t mem_ptr = static_cast<lldb::addr_t>(result); - // Find pointer to last element and add on size of an element - allocation->size = - static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + *allocation->element.datum_size.get(); + addr_t mem_ptr = static_cast<lldb::addr_t>(result); + // Find pointer to last element and add on size of an element + allocation->size = + static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()) + + *allocation->element.datum_size.get(); - return true; + return true; } -// JITs the RS runtime for information about the stride between rows in the allocation. +// JITs the RS runtime for information about the stride between rows in the +// allocation. // This is done to detect padding, since allocated memory is 16-byte aligned. // Returns true on success, false otherwise -bool -RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::JITAllocationStride(AllocationDetails *allocation, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) - { - if (log) - log->Printf("%s - failed to find allocation details.", __FUNCTION__); - return false; - } + if (!allocation->address.isValid() || !allocation->data_ptr.isValid()) { + if (log) + log->Printf("%s - failed to find allocation details.", __FUNCTION__); + return false; + } - const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); - char buffer[jit_max_expr_size]; + const char *expr_cstr = JITTemplate(eExprGetOffsetPtr); + char buffer[jit_max_expr_size]; - int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, *allocation->address.get(), 0, 1, 0); - if (chars_written < 0) - { - if (log) - log->Printf("%s - encoding error in snprintf().", __FUNCTION__); - return false; - } - else if (chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - expression too long.", __FUNCTION__); - return false; - } + int chars_written = snprintf(buffer, jit_max_expr_size, expr_cstr, + *allocation->address.get(), 0, 1, 0); + if (chars_written < 0) { + if (log) + log->Printf("%s - encoding error in snprintf().", __FUNCTION__); + return false; + } else if (chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - expression too long.", __FUNCTION__); + return false; + } - uint64_t result = 0; - if (!EvalRSExpression(buffer, frame_ptr, &result)) - return false; + uint64_t result = 0; + if (!EvalRSExpression(buffer, frame_ptr, &result)) + return false; - addr_t mem_ptr = static_cast<lldb::addr_t>(result); - allocation->stride = static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); + addr_t mem_ptr = static_cast<lldb::addr_t>(result); + allocation->stride = + static_cast<uint32_t>(mem_ptr - *allocation->data_ptr.get()); - return true; + return true; } // JIT all the current runtime info regarding an allocation -bool -RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - // GetOffsetPointer() - if (!JITDataPointer(allocation, frame_ptr)) - return false; +bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *allocation, + StackFrame *frame_ptr) { + // GetOffsetPointer() + if (!JITDataPointer(allocation, frame_ptr)) + return false; - // rsaAllocationGetType() - if (!JITTypePointer(allocation, frame_ptr)) - return false; + // rsaAllocationGetType() + if (!JITTypePointer(allocation, frame_ptr)) + return false; - // rsaTypeGetNativeData() - if (!JITTypePacked(allocation, frame_ptr)) - return false; + // rsaTypeGetNativeData() + if (!JITTypePacked(allocation, frame_ptr)) + return false; - // rsaElementGetNativeData() - if (!JITElementPacked(allocation->element, *allocation->context.get(), frame_ptr)) - return false; + // rsaElementGetNativeData() + if (!JITElementPacked(allocation->element, *allocation->context.get(), + frame_ptr)) + return false; - // Sets the datum_size member in Element - SetElementSize(allocation->element); + // Sets the datum_size member in Element + SetElementSize(allocation->element); - // Use GetOffsetPointer() to infer size of the allocation - if (!JITAllocationSize(allocation, frame_ptr)) - return false; + // Use GetOffsetPointer() to infer size of the allocation + if (!JITAllocationSize(allocation, frame_ptr)) + return false; - return true; + return true; } -// Function attempts to set the type_name member of the paramaterised Element object. +// Function attempts to set the type_name member of the paramaterised Element +// object. // This string should be the name of the struct type the Element represents. // We need this string for pretty printing the Element to users. -void -RenderScriptRuntime::FindStructTypeName(Element &elem, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - if (!elem.type_name.IsEmpty()) // Name already set - return; - else - elem.type_name = Element::GetFallbackStructName(); // Default type name if we don't succeed - - // Find all the global variables from the script rs modules - VariableList variable_list; - for (auto module_sp : m_rsmodules) - module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, UINT32_MAX, variable_list); - - // Iterate over all the global variables looking for one with a matching type to the Element. - // We make the assumption a match exists since there needs to be a global variable to reflect the - // struct type back into java host code. - for (uint32_t var_index = 0; var_index < variable_list.GetSize(); ++var_index) - { - const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); - if (!var_sp) - continue; - - ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); - if (!valobj_sp) - continue; - - // Find the number of variable fields. - // If it has no fields, or more fields than our Element, then it can't be the struct we're looking for. - // Don't check for equality since RS can add extra struct members for padding. - size_t num_children = valobj_sp->GetNumChildren(); - if (num_children > elem.children.size() || num_children == 0) - continue; - - // Iterate over children looking for members with matching field names. - // If all the field names match, this is likely the struct we want. - // - // TODO: This could be made more robust by also checking children data sizes, or array size - bool found = true; - for (size_t child_index = 0; child_index < num_children; ++child_index) - { - ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); - if (!child || (child->GetName() != elem.children[child_index].type_name)) - { - found = false; - break; - } - } - - // RS can add extra struct members for padding in the format '#rs_padding_[0-9]+' - if (found && num_children < elem.children.size()) - { - const uint32_t size_diff = elem.children.size() - num_children; - if (log) - log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__, size_diff); - - for (uint32_t padding_index = 0; padding_index < size_diff; ++padding_index) - { - const ConstString &name = elem.children[num_children + padding_index].type_name; - if (strcmp(name.AsCString(), "#rs_padding") < 0) - found = false; - } - } - - // We've found a global var with matching type - if (found) - { - // Dereference since our Element type isn't a pointer. - if (valobj_sp->IsPointerType()) - { - Error err; - ValueObjectSP deref_valobj = valobj_sp->Dereference(err); - if (!err.Fail()) - valobj_sp = deref_valobj; - } - - // Save name of variable in Element. - elem.type_name = valobj_sp->GetTypeName(); - if (log) - log->Printf("%s - element name set to %s", __FUNCTION__, elem.type_name.AsCString()); - - return; - } - } +void RenderScriptRuntime::FindStructTypeName(Element &elem, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + if (!elem.type_name.IsEmpty()) // Name already set + return; + else + elem.type_name = Element::GetFallbackStructName(); // Default type name if + // we don't succeed + + // Find all the global variables from the script rs modules + VariableList variable_list; + for (auto module_sp : m_rsmodules) + module_sp->m_module->FindGlobalVariables(RegularExpression("."), true, + UINT32_MAX, variable_list); + + // Iterate over all the global variables looking for one with a matching type + // to the Element. + // We make the assumption a match exists since there needs to be a global + // variable to reflect the + // struct type back into java host code. + for (uint32_t var_index = 0; var_index < variable_list.GetSize(); + ++var_index) { + const VariableSP var_sp(variable_list.GetVariableAtIndex(var_index)); + if (!var_sp) + continue; + + ValueObjectSP valobj_sp = ValueObjectVariable::Create(frame_ptr, var_sp); + if (!valobj_sp) + continue; + + // Find the number of variable fields. + // If it has no fields, or more fields than our Element, then it can't be + // the struct we're looking for. + // Don't check for equality since RS can add extra struct members for + // padding. + size_t num_children = valobj_sp->GetNumChildren(); + if (num_children > elem.children.size() || num_children == 0) + continue; + + // Iterate over children looking for members with matching field names. + // If all the field names match, this is likely the struct we want. + // + // TODO: This could be made more robust by also checking children data + // sizes, or array size + bool found = true; + for (size_t child_index = 0; child_index < num_children; ++child_index) { + ValueObjectSP child = valobj_sp->GetChildAtIndex(child_index, true); + if (!child || + (child->GetName() != elem.children[child_index].type_name)) { + found = false; + break; + } + } + + // RS can add extra struct members for padding in the format + // '#rs_padding_[0-9]+' + if (found && num_children < elem.children.size()) { + const uint32_t size_diff = elem.children.size() - num_children; + if (log) + log->Printf("%s - %" PRIu32 " padding struct entries", __FUNCTION__, + size_diff); + + for (uint32_t padding_index = 0; padding_index < size_diff; + ++padding_index) { + const ConstString &name = + elem.children[num_children + padding_index].type_name; + if (strcmp(name.AsCString(), "#rs_padding") < 0) + found = false; + } + } + + // We've found a global var with matching type + if (found) { + // Dereference since our Element type isn't a pointer. + if (valobj_sp->IsPointerType()) { + Error err; + ValueObjectSP deref_valobj = valobj_sp->Dereference(err); + if (!err.Fail()) + valobj_sp = deref_valobj; + } + + // Save name of variable in Element. + elem.type_name = valobj_sp->GetTypeName(); + if (log) + log->Printf("%s - element name set to %s", __FUNCTION__, + elem.type_name.AsCString()); + + return; + } + } } -// Function sets the datum_size member of Element. Representing the size of a single instance including padding. +// Function sets the datum_size member of Element. Representing the size of a +// single instance including padding. // Assumes the relevant allocation information has already been jitted. -void -RenderScriptRuntime::SetElementSize(Element &elem) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - const Element::DataType type = *elem.type.get(); - assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && "Invalid allocation type"); - - const uint32_t vec_size = *elem.type_vec_size.get(); - uint32_t data_size = 0; - uint32_t padding = 0; - - // Element is of a struct type, calculate size recursively. - if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) - { - for (Element &child : elem.children) - { - SetElementSize(child); - const uint32_t array_size = child.array_size.isValid() ? *child.array_size.get() : 1; - data_size += *child.datum_size.get() * array_size; - } - } - // These have been packed already - else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || - type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || - type == Element::RS_TYPE_UNSIGNED_4_4_4_4) - { - data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; - } - else if (type < Element::RS_TYPE_ELEMENT) - { - data_size = vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; - if (vec_size == 3) - padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; - } - else - data_size = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - - elem.padding = padding; - elem.datum_size = data_size + padding; - if (log) - log->Printf("%s - element size set to %" PRIu32, __FUNCTION__, data_size + padding); +void RenderScriptRuntime::SetElementSize(Element &elem) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + const Element::DataType type = *elem.type.get(); + assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && + "Invalid allocation type"); + + const uint32_t vec_size = *elem.type_vec_size.get(); + uint32_t data_size = 0; + uint32_t padding = 0; + + // Element is of a struct type, calculate size recursively. + if ((type == Element::RS_TYPE_NONE) && (elem.children.size() > 0)) { + for (Element &child : elem.children) { + SetElementSize(child); + const uint32_t array_size = + child.array_size.isValid() ? *child.array_size.get() : 1; + data_size += *child.datum_size.get() * array_size; + } + } + // These have been packed already + else if (type == Element::RS_TYPE_UNSIGNED_5_6_5 || + type == Element::RS_TYPE_UNSIGNED_5_5_5_1 || + type == Element::RS_TYPE_UNSIGNED_4_4_4_4) { + data_size = AllocationDetails::RSTypeToFormat[type][eElementSize]; + } else if (type < Element::RS_TYPE_ELEMENT) { + data_size = + vec_size * AllocationDetails::RSTypeToFormat[type][eElementSize]; + if (vec_size == 3) + padding = AllocationDetails::RSTypeToFormat[type][eElementSize]; + } else + data_size = + GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); + + elem.padding = padding; + elem.datum_size = data_size + padding; + if (log) + log->Printf("%s - element size set to %" PRIu32, __FUNCTION__, + data_size + padding); } -// Given an allocation, this function copies the allocation contents from device into a buffer on the heap. +// Given an allocation, this function copies the allocation contents from device +// into a buffer on the heap. // Returning a shared pointer to the buffer containing the data. std::shared_ptr<uint8_t> -RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +RenderScriptRuntime::GetAllocationData(AllocationDetails *allocation, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - // JIT all the allocation details - if (allocation->shouldRefresh()) - { - if (log) - log->Printf("%s - allocation details not calculated yet, jitting info", __FUNCTION__); + // JIT all the allocation details + if (allocation->shouldRefresh()) { + if (log) + log->Printf("%s - allocation details not calculated yet, jitting info", + __FUNCTION__); - if (!RefreshAllocation(allocation, frame_ptr)) - { - if (log) - log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); - return nullptr; - } + if (!RefreshAllocation(allocation, frame_ptr)) { + if (log) + log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); + return nullptr; } + } - assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && - allocation->element.type_vec_size.isValid() && allocation->size.isValid() && - "Allocation information not available"); + assert(allocation->data_ptr.isValid() && allocation->element.type.isValid() && + allocation->element.type_vec_size.isValid() && + allocation->size.isValid() && "Allocation information not available"); - // Allocate a buffer to copy data into - const uint32_t size = *allocation->size.get(); - std::shared_ptr<uint8_t> buffer(new uint8_t[size]); - if (!buffer) - { - if (log) - log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer", __FUNCTION__, size); - return nullptr; - } + // Allocate a buffer to copy data into + const uint32_t size = *allocation->size.get(); + std::shared_ptr<uint8_t> buffer(new uint8_t[size]); + if (!buffer) { + if (log) + log->Printf("%s - couldn't allocate a %" PRIu32 " byte buffer", + __FUNCTION__, size); + return nullptr; + } - // Read the inferior memory - Error error; - lldb::addr_t data_ptr = *allocation->data_ptr.get(); - GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); - if (error.Fail()) - { - if (log) - log->Printf("%s - '%s' Couldn't read %" PRIu32 " bytes of allocation data from 0x%" PRIx64, - __FUNCTION__, error.AsCString(), size, data_ptr); - return nullptr; - } + // Read the inferior memory + Error error; + lldb::addr_t data_ptr = *allocation->data_ptr.get(); + GetProcess()->ReadMemory(data_ptr, buffer.get(), size, error); + if (error.Fail()) { + if (log) + log->Printf("%s - '%s' Couldn't read %" PRIu32 + " bytes of allocation data from 0x%" PRIx64, + __FUNCTION__, error.AsCString(), size, data_ptr); + return nullptr; + } - return buffer; + return buffer; } // Function copies data from a binary file into an allocation. -// There is a header at the start of the file, FileHeader, before the data content itself. -// Information from this header is used to display warnings to the user about incompatibilities -bool -RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, const char *filename, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - // Find allocation with the given id - AllocationDetails *alloc = FindAllocByID(strm, alloc_id); - if (!alloc) - return false; - - if (log) - log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, *alloc->address.get()); - - // JIT all the allocation details - if (alloc->shouldRefresh()) - { - if (log) - log->Printf("%s - allocation details not calculated yet, jitting info.", __FUNCTION__); - - if (!RefreshAllocation(alloc, frame_ptr)) - { - if (log) - log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); - return false; - } - } - - assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && - alloc->size.isValid() && alloc->element.datum_size.isValid() && "Allocation information not available"); - - // Check we can read from file - FileSpec file(filename, true); - if (!file.Exists()) - { - strm.Printf("Error: File %s does not exist", filename); - strm.EOL(); - return false; - } - - if (!file.Readable()) - { - strm.Printf("Error: File %s does not have readable permissions", filename); - strm.EOL(); - return false; - } - - // Read file into data buffer - DataBufferSP data_sp(file.ReadFileContents()); - - // Cast start of buffer to FileHeader and use pointer to read metadata - void *file_buffer = data_sp->GetBytes(); - if (file_buffer == nullptr || - data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + sizeof(AllocationDetails::ElementHeader))) - { - strm.Printf("Error: File %s does not contain enough data for header", filename); - strm.EOL(); - return false; - } - const AllocationDetails::FileHeader *file_header = static_cast<AllocationDetails::FileHeader *>(file_buffer); - - // Check file starts with ascii characters "RSAD" - if (memcmp(file_header->ident, "RSAD", 4)) - { - strm.Printf("Error: File doesn't contain identifier for an RS allocation dump. Are you sure this is the correct file?"); - strm.EOL(); - return false; - } +// There is a header at the start of the file, FileHeader, before the data +// content itself. +// Information from this header is used to display warnings to the user about +// incompatibilities +bool RenderScriptRuntime::LoadAllocation(Stream &strm, const uint32_t alloc_id, + const char *filename, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + // Find allocation with the given id + AllocationDetails *alloc = FindAllocByID(strm, alloc_id); + if (!alloc) + return false; - // Look at the type of the root element in the header - AllocationDetails::ElementHeader root_element_header; - memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) + sizeof(AllocationDetails::FileHeader), - sizeof(AllocationDetails::ElementHeader)); + if (log) + log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, + *alloc->address.get()); + // JIT all the allocation details + if (alloc->shouldRefresh()) { if (log) - log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32, __FUNCTION__, - root_element_header.type, root_element_header.element_size); + log->Printf("%s - allocation details not calculated yet, jitting info.", + __FUNCTION__); - // Check if the target allocation and file both have the same number of bytes for an Element - if (*alloc->element.datum_size.get() != root_element_header.element_size) - { - strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 " bytes, allocation %" PRIu32 " bytes", - root_element_header.element_size, *alloc->element.datum_size.get()); - strm.EOL(); + if (!RefreshAllocation(alloc, frame_ptr)) { + if (log) + log->Printf("%s - couldn't JIT allocation details", __FUNCTION__); + return false; } + } - // Check if the target allocation and file both have the same type - const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); - const uint32_t file_type = root_element_header.type; + assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && + alloc->element.type_vec_size.isValid() && alloc->size.isValid() && + alloc->element.datum_size.isValid() && + "Allocation information not available"); - if (file_type > Element::RS_TYPE_FONT) - { - strm.Printf("Warning: File has unknown allocation type"); - strm.EOL(); - } - else if (alloc_type != file_type) - { - // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array - uint32_t printable_target_type_index = alloc_type; - uint32_t printable_head_type_index = file_type; - if (alloc_type >= Element::RS_TYPE_ELEMENT && alloc_type <= Element::RS_TYPE_FONT) - printable_target_type_index = static_cast<Element::DataType>((alloc_type - Element::RS_TYPE_ELEMENT) + - Element::RS_TYPE_MATRIX_2X2 + 1); - - if (file_type >= Element::RS_TYPE_ELEMENT && file_type <= Element::RS_TYPE_FONT) - printable_head_type_index = static_cast<Element::DataType>((file_type - Element::RS_TYPE_ELEMENT) + - Element::RS_TYPE_MATRIX_2X2 + 1); - - const char *file_type_cstr = AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; - const char *target_type_cstr = AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; - - strm.Printf("Warning: Mismatched Types - file '%s' type, allocation '%s' type", file_type_cstr, - target_type_cstr); - strm.EOL(); - } + // Check we can read from file + FileSpec file(filename, true); + if (!file.Exists()) { + strm.Printf("Error: File %s does not exist", filename); + strm.EOL(); + return false; + } + + if (!file.Readable()) { + strm.Printf("Error: File %s does not have readable permissions", filename); + strm.EOL(); + return false; + } + + // Read file into data buffer + DataBufferSP data_sp(file.ReadFileContents()); + + // Cast start of buffer to FileHeader and use pointer to read metadata + void *file_buffer = data_sp->GetBytes(); + if (file_buffer == nullptr || + data_sp->GetByteSize() < (sizeof(AllocationDetails::FileHeader) + + sizeof(AllocationDetails::ElementHeader))) { + strm.Printf("Error: File %s does not contain enough data for header", + filename); + strm.EOL(); + return false; + } + const AllocationDetails::FileHeader *file_header = + static_cast<AllocationDetails::FileHeader *>(file_buffer); + + // Check file starts with ascii characters "RSAD" + if (memcmp(file_header->ident, "RSAD", 4)) { + strm.Printf("Error: File doesn't contain identifier for an RS allocation " + "dump. Are you sure this is the correct file?"); + strm.EOL(); + return false; + } + + // Look at the type of the root element in the header + AllocationDetails::ElementHeader root_element_header; + memcpy(&root_element_header, static_cast<uint8_t *>(file_buffer) + + sizeof(AllocationDetails::FileHeader), + sizeof(AllocationDetails::ElementHeader)); + + if (log) + log->Printf("%s - header type %" PRIu32 ", element size %" PRIu32, + __FUNCTION__, root_element_header.type, + root_element_header.element_size); + + // Check if the target allocation and file both have the same number of bytes + // for an Element + if (*alloc->element.datum_size.get() != root_element_header.element_size) { + strm.Printf("Warning: Mismatched Element sizes - file %" PRIu32 + " bytes, allocation %" PRIu32 " bytes", + root_element_header.element_size, + *alloc->element.datum_size.get()); + strm.EOL(); + } - // Advance buffer past header - file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size; + // Check if the target allocation and file both have the same type + const uint32_t alloc_type = static_cast<uint32_t>(*alloc->element.type.get()); + const uint32_t file_type = root_element_header.type; - // Calculate size of allocation data in file - size_t length = data_sp->GetByteSize() - file_header->hdr_size; + if (file_type > Element::RS_TYPE_FONT) { + strm.Printf("Warning: File has unknown allocation type"); + strm.EOL(); + } else if (alloc_type != file_type) { + // Enum value isn't monotonous, so doesn't always index RsDataTypeToString + // array + uint32_t printable_target_type_index = alloc_type; + uint32_t printable_head_type_index = file_type; + if (alloc_type >= Element::RS_TYPE_ELEMENT && + alloc_type <= Element::RS_TYPE_FONT) + printable_target_type_index = static_cast<Element::DataType>( + (alloc_type - Element::RS_TYPE_ELEMENT) + + Element::RS_TYPE_MATRIX_2X2 + 1); + + if (file_type >= Element::RS_TYPE_ELEMENT && + file_type <= Element::RS_TYPE_FONT) + printable_head_type_index = static_cast<Element::DataType>( + (file_type - Element::RS_TYPE_ELEMENT) + Element::RS_TYPE_MATRIX_2X2 + + 1); + + const char *file_type_cstr = + AllocationDetails::RsDataTypeToString[printable_head_type_index][0]; + const char *target_type_cstr = + AllocationDetails::RsDataTypeToString[printable_target_type_index][0]; + + strm.Printf( + "Warning: Mismatched Types - file '%s' type, allocation '%s' type", + file_type_cstr, target_type_cstr); + strm.EOL(); + } - // Check if the target allocation and file both have the same total data size. - const uint32_t alloc_size = *alloc->size.get(); - if (alloc_size != length) - { - strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 " bytes, allocation 0x%" PRIx32 " bytes", - (uint64_t)length, alloc_size); - strm.EOL(); - length = alloc_size < length ? alloc_size : length; // Set length to copy to minimum - } + // Advance buffer past header + file_buffer = static_cast<uint8_t *>(file_buffer) + file_header->hdr_size; - // Copy file data from our buffer into the target allocation. - lldb::addr_t alloc_data = *alloc->data_ptr.get(); - Error error; - size_t bytes_written = GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); - if (!error.Success() || bytes_written != length) - { - strm.Printf("Error: Couldn't write data to allocation %s", error.AsCString()); - strm.EOL(); - return false; - } + // Calculate size of allocation data in file + size_t length = data_sp->GetByteSize() - file_header->hdr_size; - strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename, alloc->id); + // Check if the target allocation and file both have the same total data size. + const uint32_t alloc_size = *alloc->size.get(); + if (alloc_size != length) { + strm.Printf("Warning: Mismatched allocation sizes - file 0x%" PRIx64 + " bytes, allocation 0x%" PRIx32 " bytes", + (uint64_t)length, alloc_size); + strm.EOL(); + length = alloc_size < length ? alloc_size + : length; // Set length to copy to minimum + } + + // Copy file data from our buffer into the target allocation. + lldb::addr_t alloc_data = *alloc->data_ptr.get(); + Error error; + size_t bytes_written = + GetProcess()->WriteMemory(alloc_data, file_buffer, length, error); + if (!error.Success() || bytes_written != length) { + strm.Printf("Error: Couldn't write data to allocation %s", + error.AsCString()); strm.EOL(); + return false; + } - return true; + strm.Printf("Contents of file '%s' read into allocation %" PRIu32, filename, + alloc->id); + strm.EOL(); + + return true; } -// Function takes as parameters a byte buffer, which will eventually be written to file as the element header, -// an offset into that buffer, and an Element that will be saved into the buffer at the parametrised offset. +// Function takes as parameters a byte buffer, which will eventually be written +// to file as the element header, +// an offset into that buffer, and an Element that will be saved into the buffer +// at the parametrised offset. // Return value is the new offset after writing the element into the buffer. -// Elements are saved to the file as the ElementHeader struct followed by offsets to the structs of all the element's +// Elements are saved to the file as the ElementHeader struct followed by +// offsets to the structs of all the element's // children. -size_t -RenderScriptRuntime::PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, - const Element &elem) -{ - // File struct for an element header with all the relevant details copied from elem. - // We assume members are valid already. - AllocationDetails::ElementHeader elem_header; - elem_header.type = *elem.type.get(); - elem_header.kind = *elem.type_kind.get(); - elem_header.element_size = *elem.datum_size.get(); - elem_header.vector_size = *elem.type_vec_size.get(); - elem_header.array_size = elem.array_size.isValid() ? *elem.array_size.get() : 0; - const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); - - // Copy struct into buffer and advance offset - // We assume that header_buffer has been checked for nullptr before this method is called - memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); - offset += elem_header_size; - - // Starting offset of child ElementHeader struct - size_t child_offset = offset + ((elem.children.size() + 1) * sizeof(uint32_t)); - for (const RenderScriptRuntime::Element &child : elem.children) - { - // Recursively populate the buffer with the element header structs of children. - // Then save the offsets where they were set after the parent element header. - memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); - offset += sizeof(uint32_t); - - child_offset = PopulateElementHeaders(header_buffer, child_offset, child); - } - - // Zero indicates no more children - memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); - - return child_offset; +size_t RenderScriptRuntime::PopulateElementHeaders( + const std::shared_ptr<uint8_t> header_buffer, size_t offset, + const Element &elem) { + // File struct for an element header with all the relevant details copied from + // elem. + // We assume members are valid already. + AllocationDetails::ElementHeader elem_header; + elem_header.type = *elem.type.get(); + elem_header.kind = *elem.type_kind.get(); + elem_header.element_size = *elem.datum_size.get(); + elem_header.vector_size = *elem.type_vec_size.get(); + elem_header.array_size = + elem.array_size.isValid() ? *elem.array_size.get() : 0; + const size_t elem_header_size = sizeof(AllocationDetails::ElementHeader); + + // Copy struct into buffer and advance offset + // We assume that header_buffer has been checked for nullptr before this + // method is called + memcpy(header_buffer.get() + offset, &elem_header, elem_header_size); + offset += elem_header_size; + + // Starting offset of child ElementHeader struct + size_t child_offset = + offset + ((elem.children.size() + 1) * sizeof(uint32_t)); + for (const RenderScriptRuntime::Element &child : elem.children) { + // Recursively populate the buffer with the element header structs of + // children. + // Then save the offsets where they were set after the parent element + // header. + memcpy(header_buffer.get() + offset, &child_offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + child_offset = PopulateElementHeaders(header_buffer, child_offset, child); + } + + // Zero indicates no more children + memset(header_buffer.get() + offset, 0, sizeof(uint32_t)); + + return child_offset; } -// Given an Element object this function returns the total size needed in the file header to store the element's +// Given an Element object this function returns the total size needed in the +// file header to store the element's // details. -// Taking into account the size of the element header struct, plus the offsets to all the element's children. -// Function is recursive so that the size of all ancestors is taken into account. -size_t -RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) -{ - size_t size = (elem.children.size() + 1) * sizeof(uint32_t); // Offsets to children plus zero terminator - size += sizeof(AllocationDetails::ElementHeader); // Size of header struct with type details - - // Calculate recursively for all descendants - for (const Element &child : elem.children) - size += CalculateElementHeaderSize(child); - - return size; +// Taking into account the size of the element header struct, plus the offsets +// to all the element's children. +// Function is recursive so that the size of all ancestors is taken into +// account. +size_t RenderScriptRuntime::CalculateElementHeaderSize(const Element &elem) { + size_t size = (elem.children.size() + 1) * + sizeof(uint32_t); // Offsets to children plus zero terminator + size += sizeof(AllocationDetails::ElementHeader); // Size of header struct + // with type details + + // Calculate recursively for all descendants + for (const Element &child : elem.children) + size += CalculateElementHeaderSize(child); + + return size; } // Function copies allocation contents into a binary file. // This file can then be loaded later into a different allocation. -// There is a header, FileHeader, before the allocation data containing meta-data. -bool -RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, const char *filename, StackFrame *frame_ptr) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - // Find allocation with the given id - AllocationDetails *alloc = FindAllocByID(strm, alloc_id); - if (!alloc) - return false; - - if (log) - log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, *alloc->address.get()); - - // JIT all the allocation details - if (alloc->shouldRefresh()) - { - if (log) - log->Printf("%s - allocation details not calculated yet, jitting info.", __FUNCTION__); - - if (!RefreshAllocation(alloc, frame_ptr)) - { - if (log) - log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__); - return false; - } - } - - assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && alloc->element.type_vec_size.isValid() && - alloc->element.datum_size.get() && alloc->element.type_kind.isValid() && alloc->dimension.isValid() && - "Allocation information not available"); - - // Check we can create writable file - FileSpec file_spec(filename, true); - File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionTruncate); - if (!file) - { - strm.Printf("Error: Failed to open '%s' for writing", filename); - strm.EOL(); - return false; - } - - // Read allocation into buffer of heap memory - const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); - if (!buffer) - { - strm.Printf("Error: Couldn't read allocation data into buffer"); - strm.EOL(); - return false; - } - - // Create the file header - AllocationDetails::FileHeader head; - memcpy(head.ident, "RSAD", 4); - head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); - head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); - head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); - - const size_t element_header_size = CalculateElementHeaderSize(alloc->element); - assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < UINT16_MAX && "Element header too large"); - head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + element_header_size); - - // Write the file header - size_t num_bytes = sizeof(AllocationDetails::FileHeader); - if (log) - log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, (uint64_t)num_bytes); - - Error err = file.Write(&head, num_bytes); - if (!err.Success()) - { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); - strm.EOL(); - return false; - } - - // Create the headers describing the element type of the allocation. - std::shared_ptr<uint8_t> element_header_buffer(new uint8_t[element_header_size]); - if (element_header_buffer == nullptr) - { - strm.Printf("Internal Error: Couldn't allocate %" PRIu64 " bytes on the heap", (uint64_t)element_header_size); - strm.EOL(); - return false; - } +// There is a header, FileHeader, before the allocation data containing +// meta-data. +bool RenderScriptRuntime::SaveAllocation(Stream &strm, const uint32_t alloc_id, + const char *filename, + StackFrame *frame_ptr) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + // Find allocation with the given id + AllocationDetails *alloc = FindAllocByID(strm, alloc_id); + if (!alloc) + return false; - PopulateElementHeaders(element_header_buffer, 0, alloc->element); + if (log) + log->Printf("%s - found allocation 0x%" PRIx64 ".", __FUNCTION__, + *alloc->address.get()); - // Write headers for allocation element type to file - num_bytes = element_header_size; + // JIT all the allocation details + if (alloc->shouldRefresh()) { if (log) - log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.", __FUNCTION__, (uint64_t)num_bytes); + log->Printf("%s - allocation details not calculated yet, jitting info.", + __FUNCTION__); + + if (!RefreshAllocation(alloc, frame_ptr)) { + if (log) + log->Printf("%s - couldn't JIT allocation details.", __FUNCTION__); + return false; + } + } + + assert(alloc->data_ptr.isValid() && alloc->element.type.isValid() && + alloc->element.type_vec_size.isValid() && + alloc->element.datum_size.get() && + alloc->element.type_kind.isValid() && alloc->dimension.isValid() && + "Allocation information not available"); + + // Check we can create writable file + FileSpec file_spec(filename, true); + File file(file_spec, File::eOpenOptionWrite | File::eOpenOptionCanCreate | + File::eOpenOptionTruncate); + if (!file) { + strm.Printf("Error: Failed to open '%s' for writing", filename); + strm.EOL(); + return false; + } - err = file.Write(element_header_buffer.get(), num_bytes); - if (!err.Success()) - { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); - strm.EOL(); - return false; - } + // Read allocation into buffer of heap memory + const std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); + if (!buffer) { + strm.Printf("Error: Couldn't read allocation data into buffer"); + strm.EOL(); + return false; + } + + // Create the file header + AllocationDetails::FileHeader head; + memcpy(head.ident, "RSAD", 4); + head.dims[0] = static_cast<uint32_t>(alloc->dimension.get()->dim_1); + head.dims[1] = static_cast<uint32_t>(alloc->dimension.get()->dim_2); + head.dims[2] = static_cast<uint32_t>(alloc->dimension.get()->dim_3); + + const size_t element_header_size = CalculateElementHeaderSize(alloc->element); + assert((sizeof(AllocationDetails::FileHeader) + element_header_size) < + UINT16_MAX && + "Element header too large"); + head.hdr_size = static_cast<uint16_t>(sizeof(AllocationDetails::FileHeader) + + element_header_size); + + // Write the file header + size_t num_bytes = sizeof(AllocationDetails::FileHeader); + if (log) + log->Printf("%s - writing File Header, 0x%" PRIx64 " bytes", __FUNCTION__, + (uint64_t)num_bytes); + + Error err = file.Write(&head, num_bytes); + if (!err.Success()) { + strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), + filename); + strm.EOL(); + return false; + } + + // Create the headers describing the element type of the allocation. + std::shared_ptr<uint8_t> element_header_buffer( + new uint8_t[element_header_size]); + if (element_header_buffer == nullptr) { + strm.Printf("Internal Error: Couldn't allocate %" PRIu64 + " bytes on the heap", + (uint64_t)element_header_size); + strm.EOL(); + return false; + } - // Write allocation data to file - num_bytes = static_cast<size_t>(*alloc->size.get()); - if (log) - log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, (uint64_t)num_bytes); + PopulateElementHeaders(element_header_buffer, 0, alloc->element); - err = file.Write(buffer.get(), num_bytes); - if (!err.Success()) - { - strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), filename); - strm.EOL(); - return false; - } + // Write headers for allocation element type to file + num_bytes = element_header_size; + if (log) + log->Printf("%s - writing element headers, 0x%" PRIx64 " bytes.", + __FUNCTION__, (uint64_t)num_bytes); - strm.Printf("Allocation written to file '%s'", filename); + err = file.Write(element_header_buffer.get(), num_bytes); + if (!err.Success()) { + strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), + filename); strm.EOL(); - return true; + return false; + } + + // Write allocation data to file + num_bytes = static_cast<size_t>(*alloc->size.get()); + if (log) + log->Printf("%s - writing 0x%" PRIx64 " bytes", __FUNCTION__, + (uint64_t)num_bytes); + + err = file.Write(buffer.get(), num_bytes); + if (!err.Success()) { + strm.Printf("Error: '%s' when writing to file '%s'", err.AsCString(), + filename); + strm.EOL(); + return false; + } + + strm.Printf("Allocation written to file '%s'", filename); + strm.EOL(); + return true; } -bool -RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); +bool RenderScriptRuntime::LoadModule(const lldb::ModuleSP &module_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (module_sp) - { - for (const auto &rs_module : m_rsmodules) - { - if (rs_module->m_module == module_sp) - { - // Check if the user has enabled automatically breaking on - // all RS kernels. - if (m_breakAllKernels) - BreakOnModuleKernels(rs_module); - - return false; - } - } - bool module_loaded = false; - switch (GetModuleKind(module_sp)) - { - case eModuleKindKernelObj: - { - RSModuleDescriptorSP module_desc; - module_desc.reset(new RSModuleDescriptor(module_sp)); - if (module_desc->ParseRSInfo()) - { - m_rsmodules.push_back(module_desc); - module_loaded = true; - } - if (module_loaded) - { - FixupScriptDetails(module_desc); - } - break; - } - case eModuleKindDriver: - { - if (!m_libRSDriver) - { - m_libRSDriver = module_sp; - LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); - } - break; - } - case eModuleKindImpl: - { - m_libRSCpuRef = module_sp; - break; - } - case eModuleKindLibRS: - { - if (!m_libRS) - { - m_libRS = module_sp; - static ConstString gDbgPresentStr("gDebuggerPresent"); - const Symbol *debug_present = - m_libRS->FindFirstSymbolWithNameAndType(gDbgPresentStr, eSymbolTypeData); - if (debug_present) - { - Error error; - uint32_t flag = 0x00000001U; - Target &target = GetProcess()->GetTarget(); - addr_t addr = debug_present->GetLoadAddress(&target); - GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); - if (error.Success()) - { - if (log) - log->Printf("%s - debugger present flag set on debugee.", __FUNCTION__); - - m_debuggerPresentFlagged = true; - } - else if (log) - { - log->Printf("%s - error writing debugger present flags '%s' ", __FUNCTION__, - error.AsCString()); - } - } - else if (log) - { - log->Printf("%s - error writing debugger present flags - symbol not found", __FUNCTION__); - } - } - break; - } - default: - break; + if (module_sp) { + for (const auto &rs_module : m_rsmodules) { + if (rs_module->m_module == module_sp) { + // Check if the user has enabled automatically breaking on + // all RS kernels. + if (m_breakAllKernels) + BreakOnModuleKernels(rs_module); + + return false; + } + } + bool module_loaded = false; + switch (GetModuleKind(module_sp)) { + case eModuleKindKernelObj: { + RSModuleDescriptorSP module_desc; + module_desc.reset(new RSModuleDescriptor(module_sp)); + if (module_desc->ParseRSInfo()) { + m_rsmodules.push_back(module_desc); + module_loaded = true; + } + if (module_loaded) { + FixupScriptDetails(module_desc); + } + break; + } + case eModuleKindDriver: { + if (!m_libRSDriver) { + m_libRSDriver = module_sp; + LoadRuntimeHooks(m_libRSDriver, RenderScriptRuntime::eModuleKindDriver); + } + break; + } + case eModuleKindImpl: { + m_libRSCpuRef = module_sp; + break; + } + case eModuleKindLibRS: { + if (!m_libRS) { + m_libRS = module_sp; + static ConstString gDbgPresentStr("gDebuggerPresent"); + const Symbol *debug_present = m_libRS->FindFirstSymbolWithNameAndType( + gDbgPresentStr, eSymbolTypeData); + if (debug_present) { + Error error; + uint32_t flag = 0x00000001U; + Target &target = GetProcess()->GetTarget(); + addr_t addr = debug_present->GetLoadAddress(&target); + GetProcess()->WriteMemory(addr, &flag, sizeof(flag), error); + if (error.Success()) { + if (log) + log->Printf("%s - debugger present flag set on debugee.", + __FUNCTION__); + + m_debuggerPresentFlagged = true; + } else if (log) { + log->Printf("%s - error writing debugger present flags '%s' ", + __FUNCTION__, error.AsCString()); + } + } else if (log) { + log->Printf( + "%s - error writing debugger present flags - symbol not found", + __FUNCTION__); } - if (module_loaded) - Update(); - return module_loaded; + } + break; } - return false; + default: + break; + } + if (module_loaded) + Update(); + return module_loaded; + } + return false; } -void -RenderScriptRuntime::Update() -{ - if (m_rsmodules.size() > 0) - { - if (!m_initiated) - { - Initiate(); - } +void RenderScriptRuntime::Update() { + if (m_rsmodules.size() > 0) { + if (!m_initiated) { + Initiate(); } + } } // The maximum line length of an .rs.info packet @@ -2673,501 +2593,477 @@ RenderScriptRuntime::Update() #define MAXLINESTR_(x) "%" STRINGIFY(x) "s" #define MAXLINESTR MAXLINESTR_(MAXLINE) -// The .rs.info symbol in renderscript modules contains a string which needs to be parsed. +// The .rs.info symbol in renderscript modules contains a string which needs to +// be parsed. // The string is basic and is parsed on a line by line basis. -bool -RSModuleDescriptor::ParseRSInfo() -{ - assert(m_module); - const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType(ConstString(".rs.info"), eSymbolTypeData); - if (!info_sym) - return false; - - const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); - if (addr == LLDB_INVALID_ADDRESS) - return false; +bool RSModuleDescriptor::ParseRSInfo() { + assert(m_module); + const Symbol *info_sym = m_module->FindFirstSymbolWithNameAndType( + ConstString(".rs.info"), eSymbolTypeData); + if (!info_sym) + return false; - const addr_t size = info_sym->GetByteSize(); - const FileSpec fs = m_module->GetFileSpec(); + const addr_t addr = info_sym->GetAddressRef().GetFileAddress(); + if (addr == LLDB_INVALID_ADDRESS) + return false; - const DataBufferSP buffer = fs.ReadFileContents(addr, size); - if (!buffer) - return false; + const addr_t size = info_sym->GetByteSize(); + const FileSpec fs = m_module->GetFileSpec(); - // split rs.info. contents into lines - std::vector<std::string> info_lines; - { - const std::string info((const char *)buffer->GetBytes()); - for (size_t tail = 0; tail < info.size();) - { - // find next new line or end of string - size_t head = info.find('\n', tail); - head = (head == std::string::npos) ? info.size() : head; - std::string line = info.substr(tail, head - tail); - // add to line list - info_lines.push_back(line); - tail = head + 1; - } - } - - std::array<char, MAXLINE> name{{'\0'}}; - std::array<char, MAXLINE> value{{'\0'}}; + const DataBufferSP buffer = fs.ReadFileContents(addr, size); + if (!buffer) + return false; - // parse all text lines of .rs.info - for (auto line = info_lines.begin(); line != info_lines.end(); ++line) - { - uint32_t numDefns = 0; - if (sscanf(line->c_str(), "exportVarCount: %" PRIu32 "", &numDefns) == 1) - { - while (numDefns--) - m_globals.push_back(RSGlobalDescriptor(this, (++line)->c_str())); + // split rs.info. contents into lines + std::vector<std::string> info_lines; + { + const std::string info((const char *)buffer->GetBytes()); + for (size_t tail = 0; tail < info.size();) { + // find next new line or end of string + size_t head = info.find('\n', tail); + head = (head == std::string::npos) ? info.size() : head; + std::string line = info.substr(tail, head - tail); + // add to line list + info_lines.push_back(line); + tail = head + 1; + } + } + + std::array<char, MAXLINE> name{{'\0'}}; + std::array<char, MAXLINE> value{{'\0'}}; + + // parse all text lines of .rs.info + for (auto line = info_lines.begin(); line != info_lines.end(); ++line) { + uint32_t numDefns = 0; + if (sscanf(line->c_str(), "exportVarCount: %" PRIu32 "", &numDefns) == 1) { + while (numDefns--) + m_globals.push_back(RSGlobalDescriptor(this, (++line)->c_str())); + } else if (sscanf(line->c_str(), "exportForEachCount: %" PRIu32 "", + &numDefns) == 1) { + while (numDefns--) { + uint32_t slot = 0; + name[0] = '\0'; + static const char *fmt_s = "%" PRIu32 " - " MAXLINESTR; + if (sscanf((++line)->c_str(), fmt_s, &slot, name.data()) == 2) { + if (name[0] != '\0') + m_kernels.push_back(RSKernelDescriptor(this, name.data(), slot)); } - else if (sscanf(line->c_str(), "exportForEachCount: %" PRIu32 "", &numDefns) == 1) - { - while (numDefns--) - { - uint32_t slot = 0; - name[0] = '\0'; - static const char *fmt_s = "%" PRIu32 " - " MAXLINESTR; - if (sscanf((++line)->c_str(), fmt_s, &slot, name.data()) == 2) - { - if (name[0] != '\0') - m_kernels.push_back(RSKernelDescriptor(this, name.data(), slot)); - } - } + } + } else if (sscanf(line->c_str(), "pragmaCount: %" PRIu32 "", &numDefns) == + 1) { + while (numDefns--) { + name[0] = value[0] = '\0'; + static const char *fmt_s = MAXLINESTR " - " MAXLINESTR; + if (sscanf((++line)->c_str(), fmt_s, name.data(), value.data()) != 0) { + if (name[0] != '\0') + m_pragmas[std::string(name.data())] = value.data(); } - else if (sscanf(line->c_str(), "pragmaCount: %" PRIu32 "", &numDefns) == 1) - { - while (numDefns--) - { - name[0] = value[0] = '\0'; - static const char *fmt_s = MAXLINESTR " - " MAXLINESTR; - if (sscanf((++line)->c_str(), fmt_s, name.data(), value.data()) != 0) - { - if (name[0] != '\0') - m_pragmas[std::string(name.data())] = value.data(); - } - } - } - else - { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (log) - { - log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__, line->c_str()); - } - } - } - - // 'root' kernel should always be present - return m_kernels.size() > 0; + } + } else { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + if (log) { + log->Printf("%s - skipping .rs.info field '%s'", __FUNCTION__, + line->c_str()); + } + } + } + + // 'root' kernel should always be present + return m_kernels.size() > 0; } -void -RenderScriptRuntime::Status(Stream &strm) const -{ - if (m_libRS) - { - strm.Printf("Runtime Library discovered."); - strm.EOL(); - } - if (m_libRSDriver) - { - strm.Printf("Runtime Driver discovered."); - strm.EOL(); - } - if (m_libRSCpuRef) - { - strm.Printf("CPU Reference Implementation discovered."); - strm.EOL(); - } +void RenderScriptRuntime::Status(Stream &strm) const { + if (m_libRS) { + strm.Printf("Runtime Library discovered."); + strm.EOL(); + } + if (m_libRSDriver) { + strm.Printf("Runtime Driver discovered."); + strm.EOL(); + } + if (m_libRSCpuRef) { + strm.Printf("CPU Reference Implementation discovered."); + strm.EOL(); + } - if (m_runtimeHooks.size()) - { - strm.Printf("Runtime functions hooked:"); - strm.EOL(); - for (auto b : m_runtimeHooks) - { - strm.Indent(b.second->defn->name); - strm.EOL(); - } - } - else - { - strm.Printf("Runtime is not hooked."); - strm.EOL(); + if (m_runtimeHooks.size()) { + strm.Printf("Runtime functions hooked:"); + strm.EOL(); + for (auto b : m_runtimeHooks) { + strm.Indent(b.second->defn->name); + strm.EOL(); } + } else { + strm.Printf("Runtime is not hooked."); + strm.EOL(); + } } -void -RenderScriptRuntime::DumpContexts(Stream &strm) const -{ - strm.Printf("Inferred RenderScript Contexts:"); - strm.EOL(); - strm.IndentMore(); +void RenderScriptRuntime::DumpContexts(Stream &strm) const { + strm.Printf("Inferred RenderScript Contexts:"); + strm.EOL(); + strm.IndentMore(); - std::map<addr_t, uint64_t> contextReferences; + std::map<addr_t, uint64_t> contextReferences; - // Iterate over all of the currently discovered scripts. - // Note: We cant push or pop from m_scripts inside this loop or it may invalidate script. - for (const auto &script : m_scripts) - { - if (!script->context.isValid()) - continue; - lldb::addr_t context = *script->context; + // Iterate over all of the currently discovered scripts. + // Note: We cant push or pop from m_scripts inside this loop or it may + // invalidate script. + for (const auto &script : m_scripts) { + if (!script->context.isValid()) + continue; + lldb::addr_t context = *script->context; - if (contextReferences.find(context) != contextReferences.end()) - { - contextReferences[context]++; - } - else - { - contextReferences[context] = 1; - } + if (contextReferences.find(context) != contextReferences.end()) { + contextReferences[context]++; + } else { + contextReferences[context] = 1; } + } - for (const auto &cRef : contextReferences) - { - strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", cRef.first, cRef.second); - strm.EOL(); - } - strm.IndentLess(); + for (const auto &cRef : contextReferences) { + strm.Printf("Context 0x%" PRIx64 ": %" PRIu64 " script instances", + cRef.first, cRef.second); + strm.EOL(); + } + strm.IndentLess(); } -void -RenderScriptRuntime::DumpKernels(Stream &strm) const -{ - strm.Printf("RenderScript Kernels:"); +void RenderScriptRuntime::DumpKernels(Stream &strm) const { + strm.Printf("RenderScript Kernels:"); + strm.EOL(); + strm.IndentMore(); + for (const auto &module : m_rsmodules) { + strm.Printf("Resource '%s':", module->m_resname.c_str()); strm.EOL(); - strm.IndentMore(); - for (const auto &module : m_rsmodules) - { - strm.Printf("Resource '%s':", module->m_resname.c_str()); - strm.EOL(); - for (const auto &kernel : module->m_kernels) - { - strm.Indent(kernel.m_name.AsCString()); - strm.EOL(); - } + for (const auto &kernel : module->m_kernels) { + strm.Indent(kernel.m_name.AsCString()); + strm.EOL(); } - strm.IndentLess(); + } + strm.IndentLess(); } RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) -{ - AllocationDetails *alloc = nullptr; - - // See if we can find allocation using id as an index; - if (alloc_id <= m_allocations.size() && alloc_id != 0 && m_allocations[alloc_id - 1]->id == alloc_id) - { - alloc = m_allocations[alloc_id - 1].get(); - return alloc; - } - - // Fallback to searching - for (const auto &a : m_allocations) - { - if (a->id == alloc_id) - { - alloc = a.get(); - break; - } - } - - if (alloc == nullptr) - { - strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, alloc_id); - strm.EOL(); - } +RenderScriptRuntime::FindAllocByID(Stream &strm, const uint32_t alloc_id) { + AllocationDetails *alloc = nullptr; + // See if we can find allocation using id as an index; + if (alloc_id <= m_allocations.size() && alloc_id != 0 && + m_allocations[alloc_id - 1]->id == alloc_id) { + alloc = m_allocations[alloc_id - 1].get(); return alloc; -} - -// Prints the contents of an allocation to the output stream, which may be a file -bool -RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id) -{ - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + } - // Check we can find the desired allocation - AllocationDetails *alloc = FindAllocByID(strm, id); - if (!alloc) - return false; // FindAllocByID() will print error message for us here - - if (log) - log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, *alloc->address.get()); - - // Check we have information about the allocation, if not calculate it - if (alloc->shouldRefresh()) - { - if (log) - log->Printf("%s - allocation details not calculated yet, jitting info.", __FUNCTION__); - - // JIT all the allocation information - if (!RefreshAllocation(alloc, frame_ptr)) - { - strm.Printf("Error: Couldn't JIT allocation details"); - strm.EOL(); - return false; - } + // Fallback to searching + for (const auto &a : m_allocations) { + if (a->id == alloc_id) { + alloc = a.get(); + break; } + } - // Establish format and size of each data element - const uint32_t vec_size = *alloc->element.type_vec_size.get(); - const Element::DataType type = *alloc->element.type.get(); - - assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && "Invalid allocation type"); + if (alloc == nullptr) { + strm.Printf("Error: Couldn't find allocation with id matching %" PRIu32, + alloc_id); + strm.EOL(); + } - lldb::Format format; - if (type >= Element::RS_TYPE_ELEMENT) - format = eFormatHex; - else - format = vec_size == 1 ? static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatSingle]) - : static_cast<lldb::Format>(AllocationDetails::RSTypeToFormat[type][eFormatVector]); + return alloc; +} - const uint32_t data_size = *alloc->element.datum_size.get(); +// Prints the contents of an allocation to the output stream, which may be a +// file +bool RenderScriptRuntime::DumpAllocation(Stream &strm, StackFrame *frame_ptr, + const uint32_t id) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - if (log) - log->Printf("%s - element size %" PRIu32 " bytes, including padding", __FUNCTION__, data_size); + // Check we can find the desired allocation + AllocationDetails *alloc = FindAllocByID(strm, id); + if (!alloc) + return false; // FindAllocByID() will print error message for us here - // Allocate a buffer to copy data into - std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); - if (!buffer) - { - strm.Printf("Error: Couldn't read allocation data"); - strm.EOL(); - return false; - } + if (log) + log->Printf("%s - found allocation 0x%" PRIx64, __FUNCTION__, + *alloc->address.get()); - // Calculate stride between rows as there may be padding at end of rows since - // allocated memory is 16-byte aligned - if (!alloc->stride.isValid()) - { - if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension - alloc->stride = 0; - else if (!JITAllocationStride(alloc, frame_ptr)) - { - strm.Printf("Error: Couldn't calculate allocation row stride"); - strm.EOL(); - return false; - } - } - const uint32_t stride = *alloc->stride.get(); - const uint32_t size = *alloc->size.get(); // Size of whole allocation - const uint32_t padding = alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; + // Check we have information about the allocation, if not calculate it + if (alloc->shouldRefresh()) { if (log) - log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 " bytes, padding %" PRIu32, - __FUNCTION__, stride, size, padding); - - // Find dimensions used to index loops, so need to be non-zero - uint32_t dim_x = alloc->dimension.get()->dim_1; - dim_x = dim_x == 0 ? 1 : dim_x; - - uint32_t dim_y = alloc->dimension.get()->dim_2; - dim_y = dim_y == 0 ? 1 : dim_y; - - uint32_t dim_z = alloc->dimension.get()->dim_3; - dim_z = dim_z == 0 ? 1 : dim_z; - - // Use data extractor to format output - const uint32_t archByteSize = GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); - DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), archByteSize); - - uint32_t offset = 0; // Offset in buffer to next element to be printed - uint32_t prev_row = 0; // Offset to the start of the previous row - - // Iterate over allocation dimensions, printing results to user - strm.Printf("Data (X, Y, Z):"); - for (uint32_t z = 0; z < dim_z; ++z) - { - for (uint32_t y = 0; y < dim_y; ++y) - { - // Use stride to index start of next row. - if (!(y == 0 && z == 0)) - offset = prev_row + stride; - prev_row = offset; - - // Print each element in the row individually - for (uint32_t x = 0; x < dim_x; ++x) - { - strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); - if ((type == Element::RS_TYPE_NONE) && (alloc->element.children.size() > 0) && - (alloc->element.type_name != Element::GetFallbackStructName())) - { - // Here we are dumping an Element of struct type. - // This is done using expression evaluation with the name of the struct type and pointer to element. - - // Don't print the name of the resulting expression, since this will be '$[0-9]+' - DumpValueObjectOptions expr_options; - expr_options.SetHideName(true); - - // Setup expression as derefrencing a pointer cast to element address. - char expr_char_buffer[jit_max_expr_size]; - int chars_written = snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, - alloc->element.type_name.AsCString(), *alloc->data_ptr.get() + offset); - - if (chars_written < 0 || chars_written >= jit_max_expr_size) - { - if (log) - log->Printf("%s - error in snprintf().", __FUNCTION__); - continue; - } - - // Evaluate expression - ValueObjectSP expr_result; - GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, frame_ptr, expr_result); - - // Print the results to our stream. - expr_result->Dump(strm, expr_options); - } - else - { - alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, LLDB_INVALID_ADDRESS, 0, 0); - } - offset += data_size; - } + log->Printf("%s - allocation details not calculated yet, jitting info.", + __FUNCTION__); + + // JIT all the allocation information + if (!RefreshAllocation(alloc, frame_ptr)) { + strm.Printf("Error: Couldn't JIT allocation details"); + strm.EOL(); + return false; + } + } + + // Establish format and size of each data element + const uint32_t vec_size = *alloc->element.type_vec_size.get(); + const Element::DataType type = *alloc->element.type.get(); + + assert(type >= Element::RS_TYPE_NONE && type <= Element::RS_TYPE_FONT && + "Invalid allocation type"); + + lldb::Format format; + if (type >= Element::RS_TYPE_ELEMENT) + format = eFormatHex; + else + format = vec_size == 1 + ? static_cast<lldb::Format>( + AllocationDetails::RSTypeToFormat[type][eFormatSingle]) + : static_cast<lldb::Format>( + AllocationDetails::RSTypeToFormat[type][eFormatVector]); + + const uint32_t data_size = *alloc->element.datum_size.get(); + + if (log) + log->Printf("%s - element size %" PRIu32 " bytes, including padding", + __FUNCTION__, data_size); + + // Allocate a buffer to copy data into + std::shared_ptr<uint8_t> buffer = GetAllocationData(alloc, frame_ptr); + if (!buffer) { + strm.Printf("Error: Couldn't read allocation data"); + strm.EOL(); + return false; + } + + // Calculate stride between rows as there may be padding at end of rows since + // allocated memory is 16-byte aligned + if (!alloc->stride.isValid()) { + if (alloc->dimension.get()->dim_2 == 0) // We only have one dimension + alloc->stride = 0; + else if (!JITAllocationStride(alloc, frame_ptr)) { + strm.Printf("Error: Couldn't calculate allocation row stride"); + strm.EOL(); + return false; + } + } + const uint32_t stride = *alloc->stride.get(); + const uint32_t size = *alloc->size.get(); // Size of whole allocation + const uint32_t padding = + alloc->element.padding.isValid() ? *alloc->element.padding.get() : 0; + if (log) + log->Printf("%s - stride %" PRIu32 " bytes, size %" PRIu32 + " bytes, padding %" PRIu32, + __FUNCTION__, stride, size, padding); + + // Find dimensions used to index loops, so need to be non-zero + uint32_t dim_x = alloc->dimension.get()->dim_1; + dim_x = dim_x == 0 ? 1 : dim_x; + + uint32_t dim_y = alloc->dimension.get()->dim_2; + dim_y = dim_y == 0 ? 1 : dim_y; + + uint32_t dim_z = alloc->dimension.get()->dim_3; + dim_z = dim_z == 0 ? 1 : dim_z; + + // Use data extractor to format output + const uint32_t archByteSize = + GetProcess()->GetTarget().GetArchitecture().GetAddressByteSize(); + DataExtractor alloc_data(buffer.get(), size, GetProcess()->GetByteOrder(), + archByteSize); + + uint32_t offset = 0; // Offset in buffer to next element to be printed + uint32_t prev_row = 0; // Offset to the start of the previous row + + // Iterate over allocation dimensions, printing results to user + strm.Printf("Data (X, Y, Z):"); + for (uint32_t z = 0; z < dim_z; ++z) { + for (uint32_t y = 0; y < dim_y; ++y) { + // Use stride to index start of next row. + if (!(y == 0 && z == 0)) + offset = prev_row + stride; + prev_row = offset; + + // Print each element in the row individually + for (uint32_t x = 0; x < dim_x; ++x) { + strm.Printf("\n(%" PRIu32 ", %" PRIu32 ", %" PRIu32 ") = ", x, y, z); + if ((type == Element::RS_TYPE_NONE) && + (alloc->element.children.size() > 0) && + (alloc->element.type_name != Element::GetFallbackStructName())) { + // Here we are dumping an Element of struct type. + // This is done using expression evaluation with the name of the + // struct type and pointer to element. + + // Don't print the name of the resulting expression, since this will + // be '$[0-9]+' + DumpValueObjectOptions expr_options; + expr_options.SetHideName(true); + + // Setup expression as derefrencing a pointer cast to element address. + char expr_char_buffer[jit_max_expr_size]; + int chars_written = + snprintf(expr_char_buffer, jit_max_expr_size, "*(%s*) 0x%" PRIx64, + alloc->element.type_name.AsCString(), + *alloc->data_ptr.get() + offset); + + if (chars_written < 0 || chars_written >= jit_max_expr_size) { + if (log) + log->Printf("%s - error in snprintf().", __FUNCTION__); + continue; + } + + // Evaluate expression + ValueObjectSP expr_result; + GetProcess()->GetTarget().EvaluateExpression(expr_char_buffer, + frame_ptr, expr_result); + + // Print the results to our stream. + expr_result->Dump(strm, expr_options); + } else { + alloc_data.Dump(&strm, offset, format, data_size - padding, 1, 1, + LLDB_INVALID_ADDRESS, 0, 0); } + offset += data_size; + } } - strm.EOL(); + } + strm.EOL(); - return true; + return true; } -// Function recalculates all our cached information about allocations by jitting the +// Function recalculates all our cached information about allocations by jitting +// the // RS runtime regarding each allocation we know about. // Returns true if all allocations could be recomputed, false otherwise. -bool -RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr) -{ - bool success = true; - for (auto &alloc : m_allocations) - { - // JIT current allocation information - if (!RefreshAllocation(alloc.get(), frame_ptr)) - { - strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 "\n", alloc->id); - success = false; - } - } - - if (success) - strm.Printf("All allocations successfully recomputed"); - strm.EOL(); - - return success; +bool RenderScriptRuntime::RecomputeAllAllocations(Stream &strm, + StackFrame *frame_ptr) { + bool success = true; + for (auto &alloc : m_allocations) { + // JIT current allocation information + if (!RefreshAllocation(alloc.get(), frame_ptr)) { + strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32 + "\n", + alloc->id); + success = false; + } + } + + if (success) + strm.Printf("All allocations successfully recomputed"); + strm.EOL(); + + return success; } // Prints information regarding currently loaded allocations. // These details are gathered by jitting the runtime, which has as latency. -// Index parameter specifies a single allocation ID to print, or a zero value to print them all -void -RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, const uint32_t index) -{ - strm.Printf("RenderScript Allocations:"); +// Index parameter specifies a single allocation ID to print, or a zero value to +// print them all +void RenderScriptRuntime::ListAllocations(Stream &strm, StackFrame *frame_ptr, + const uint32_t index) { + strm.Printf("RenderScript Allocations:"); + strm.EOL(); + strm.IndentMore(); + + for (auto &alloc : m_allocations) { + // index will only be zero if we want to print all allocations + if (index != 0 && index != alloc->id) + continue; + + // JIT current allocation information + if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) { + strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, + alloc->id); + strm.EOL(); + continue; + } + + strm.Printf("%" PRIu32 ":", alloc->id); strm.EOL(); strm.IndentMore(); - for (auto &alloc : m_allocations) - { - // index will only be zero if we want to print all allocations - if (index != 0 && index != alloc->id) - continue; - - // JIT current allocation information - if (alloc->shouldRefresh() && !RefreshAllocation(alloc.get(), frame_ptr)) - { - strm.Printf("Error: Couldn't evaluate details for allocation %" PRIu32, alloc->id); - strm.EOL(); - continue; - } - - strm.Printf("%" PRIu32 ":", alloc->id); - strm.EOL(); - strm.IndentMore(); - - strm.Indent("Context: "); - if (!alloc->context.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); - - strm.Indent("Address: "); - if (!alloc->address.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); - - strm.Indent("Data pointer: "); - if (!alloc->data_ptr.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); + strm.Indent("Context: "); + if (!alloc->context.isValid()) + strm.Printf("unknown\n"); + else + strm.Printf("0x%" PRIx64 "\n", *alloc->context.get()); - strm.Indent("Dimensions: "); - if (!alloc->dimension.isValid()) - strm.Printf("unknown\n"); - else - strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", - alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, alloc->dimension.get()->dim_3); + strm.Indent("Address: "); + if (!alloc->address.isValid()) + strm.Printf("unknown\n"); + else + strm.Printf("0x%" PRIx64 "\n", *alloc->address.get()); - strm.Indent("Data Type: "); - if (!alloc->element.type.isValid() || !alloc->element.type_vec_size.isValid()) - strm.Printf("unknown\n"); - else - { - const int vector_size = *alloc->element.type_vec_size.get(); - Element::DataType type = *alloc->element.type.get(); - - if (!alloc->element.type_name.IsEmpty()) - strm.Printf("%s\n", alloc->element.type_name.AsCString()); - else - { - // Enum value isn't monotonous, so doesn't always index RsDataTypeToString array - if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) - type = static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + - Element::RS_TYPE_MATRIX_2X2 + 1); - - if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / - sizeof(AllocationDetails::RsDataTypeToString[0])) || - vector_size > 4 || vector_size < 1) - strm.Printf("invalid type\n"); - else - strm.Printf("%s\n", AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] - [vector_size - 1]); - } - } + strm.Indent("Data pointer: "); + if (!alloc->data_ptr.isValid()) + strm.Printf("unknown\n"); + else + strm.Printf("0x%" PRIx64 "\n", *alloc->data_ptr.get()); - strm.Indent("Data Kind: "); - if (!alloc->element.type_kind.isValid()) - strm.Printf("unknown\n"); + strm.Indent("Dimensions: "); + if (!alloc->dimension.isValid()) + strm.Printf("unknown\n"); + else + strm.Printf("(%" PRId32 ", %" PRId32 ", %" PRId32 ")\n", + alloc->dimension.get()->dim_1, alloc->dimension.get()->dim_2, + alloc->dimension.get()->dim_3); + + strm.Indent("Data Type: "); + if (!alloc->element.type.isValid() || + !alloc->element.type_vec_size.isValid()) + strm.Printf("unknown\n"); + else { + const int vector_size = *alloc->element.type_vec_size.get(); + Element::DataType type = *alloc->element.type.get(); + + if (!alloc->element.type_name.IsEmpty()) + strm.Printf("%s\n", alloc->element.type_name.AsCString()); + else { + // Enum value isn't monotonous, so doesn't always index + // RsDataTypeToString array + if (type >= Element::RS_TYPE_ELEMENT && type <= Element::RS_TYPE_FONT) + type = + static_cast<Element::DataType>((type - Element::RS_TYPE_ELEMENT) + + Element::RS_TYPE_MATRIX_2X2 + 1); + + if (type >= (sizeof(AllocationDetails::RsDataTypeToString) / + sizeof(AllocationDetails::RsDataTypeToString[0])) || + vector_size > 4 || vector_size < 1) + strm.Printf("invalid type\n"); else - { - const Element::DataKind kind = *alloc->element.type_kind.get(); - if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) - strm.Printf("invalid kind\n"); - else - strm.Printf("%s\n", AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); - } - - strm.EOL(); - strm.IndentLess(); + strm.Printf( + "%s\n", + AllocationDetails::RsDataTypeToString[static_cast<uint32_t>(type)] + [vector_size - 1]); + } + } + + strm.Indent("Data Kind: "); + if (!alloc->element.type_kind.isValid()) + strm.Printf("unknown\n"); + else { + const Element::DataKind kind = *alloc->element.type_kind.get(); + if (kind < Element::RS_KIND_USER || kind > Element::RS_KIND_PIXEL_YUV) + strm.Printf("invalid kind\n"); + else + strm.Printf( + "%s\n", + AllocationDetails::RsDataKindToString[static_cast<uint32_t>(kind)]); } + + strm.EOL(); strm.IndentLess(); + } + strm.IndentLess(); } // Set breakpoints on every kernel found in RS module -void -RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp) -{ - for (const auto &kernel : rsmodule_sp->m_kernels) - { - // Don't set breakpoint on 'root' kernel - if (strcmp(kernel.m_name.AsCString(), "root") == 0) - continue; - - CreateKernelBreakpoint(kernel.m_name); - } +void RenderScriptRuntime::BreakOnModuleKernels( + const RSModuleDescriptorSP rsmodule_sp) { + for (const auto &kernel : rsmodule_sp->m_kernels) { + // Don't set breakpoint on 'root' kernel + if (strcmp(kernel.m_name.AsCString(), "root") == 0) + continue; + + CreateKernelBreakpoint(kernel.m_name); + } } // Method is internally called by the 'kernel breakpoint all' command to @@ -3175,1200 +3071,1191 @@ RenderScriptRuntime::BreakOnModuleKernels(const RSModuleDescriptorSP rsmodule_sp // // When do_break is true we want to enable this functionality. // When do_break is false we want to disable it. -void -RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); +void RenderScriptRuntime::SetBreakAllKernels(bool do_break, TargetSP target) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); - InitSearchFilter(target); + InitSearchFilter(target); - // Set breakpoints on all the kernels - if (do_break && !m_breakAllKernels) - { - m_breakAllKernels = true; + // Set breakpoints on all the kernels + if (do_break && !m_breakAllKernels) { + m_breakAllKernels = true; - for (const auto &module : m_rsmodules) - BreakOnModuleKernels(module); + for (const auto &module : m_rsmodules) + BreakOnModuleKernels(module); - if (log) - log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", __FUNCTION__); - } - else if (!do_break && m_breakAllKernels) // Breakpoints won't be set on any new kernels. - { - m_breakAllKernels = false; + if (log) + log->Printf("%s(True) - breakpoints set on all currently loaded kernels.", + __FUNCTION__); + } else if (!do_break && + m_breakAllKernels) // Breakpoints won't be set on any new kernels. + { + m_breakAllKernels = false; - if (log) - log->Printf("%s(False) - breakpoints no longer automatically set.", __FUNCTION__); - } + if (log) + log->Printf("%s(False) - breakpoints no longer automatically set.", + __FUNCTION__); + } } // Given the name of a kernel this function creates a breakpoint using our // own breakpoint resolver, and returns the Breakpoint shared pointer. BreakpointSP -RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); +RenderScriptRuntime::CreateKernelBreakpoint(const ConstString &name) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); - if (!m_filtersp) - { - if (log) - log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); - return nullptr; - } + if (!m_filtersp) { + if (log) + log->Printf("%s - error, no breakpoint search filter set.", __FUNCTION__); + return nullptr; + } - BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); - BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint(m_filtersp, resolver_sp, false, false, false); + BreakpointResolverSP resolver_sp(new RSBreakpointResolver(nullptr, name)); + BreakpointSP bp = GetProcess()->GetTarget().CreateBreakpoint( + m_filtersp, resolver_sp, false, false, false); - // Give RS breakpoints a specific name, so the user can manipulate them as a group. - Error err; - if (!bp->AddName("RenderScriptKernel", err) && log) - log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, err.AsCString()); + // Give RS breakpoints a specific name, so the user can manipulate them as a + // group. + Error err; + if (!bp->AddName("RenderScriptKernel", err) && log) + log->Printf("%s - error setting break name, '%s'.", __FUNCTION__, + err.AsCString()); - return bp; + return bp; } -// Given an expression for a variable this function tries to calculate the variable's value. -// If this is possible it returns true and sets the uint64_t parameter to the variables unsigned value. +// Given an expression for a variable this function tries to calculate the +// variable's value. +// If this is possible it returns true and sets the uint64_t parameter to the +// variables unsigned value. // Otherwise function returns false. -bool -RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, const char *var_name, uint64_t &val) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - Error error; - VariableSP var_sp; - - // Find variable in stack frame - ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( - var_name, eNoDynamicValues, - StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, - var_sp, error)); - if (!error.Success()) - { - if (log) - log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, var_name); - return false; - } +bool RenderScriptRuntime::GetFrameVarAsUnsigned(const StackFrameSP frame_sp, + const char *var_name, + uint64_t &val) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + Error error; + VariableSP var_sp; + + // Find variable in stack frame + ValueObjectSP value_sp(frame_sp->GetValueForVariableExpressionPath( + var_name, eNoDynamicValues, + StackFrame::eExpressionPathOptionCheckPtrVsMember | + StackFrame::eExpressionPathOptionsAllowDirectIVarAccess, + var_sp, error)); + if (!error.Success()) { + if (log) + log->Printf("%s - error, couldn't find '%s' in frame", __FUNCTION__, + var_name); + return false; + } - // Find the uint32_t value for the variable - bool success = false; - val = value_sp->GetValueAsUnsigned(0, &success); - if (!success) - { - if (log) - log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", __FUNCTION__, var_name); - return false; - } + // Find the uint32_t value for the variable + bool success = false; + val = value_sp->GetValueAsUnsigned(0, &success); + if (!success) { + if (log) + log->Printf("%s - error, couldn't parse '%s' as an uint32_t.", + __FUNCTION__, var_name); + return false; + } - return true; + return true; } -// Function attempts to find the current coordinate of a kernel invocation by investigating the -// values of frame variables in the .expand function. These coordinates are returned via the coord -// array reference parameter. Returns true if the coordinates could be found, and false otherwise. -bool -RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, Thread *thread_ptr) -{ - static const std::string s_runtimeExpandSuffix(".expand"); - static const std::array<const char *, 3> s_runtimeCoordVars{{"rsIndex", "p->current.y", "p->current.z"}}; - - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); - - if (!thread_ptr) - { - if (log) - log->Printf("%s - Error, No thread pointer", __FUNCTION__); +// Function attempts to find the current coordinate of a kernel invocation by +// investigating the +// values of frame variables in the .expand function. These coordinates are +// returned via the coord +// array reference parameter. Returns true if the coordinates could be found, +// and false otherwise. +bool RenderScriptRuntime::GetKernelCoordinate(RSCoordinate &coord, + Thread *thread_ptr) { + static const std::string s_runtimeExpandSuffix(".expand"); + static const std::array<const char *, 3> s_runtimeCoordVars{ + {"rsIndex", "p->current.y", "p->current.z"}}; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE)); + + if (!thread_ptr) { + if (log) + log->Printf("%s - Error, No thread pointer", __FUNCTION__); - return false; - } + return false; + } - // Walk the call stack looking for a function whose name has the suffix '.expand' - // and contains the variables we're looking for. - for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) - { - if (!thread_ptr->SetSelectedFrameByIndex(i)) - continue; + // Walk the call stack looking for a function whose name has the suffix + // '.expand' + // and contains the variables we're looking for. + for (uint32_t i = 0; i < thread_ptr->GetStackFrameCount(); ++i) { + if (!thread_ptr->SetSelectedFrameByIndex(i)) + continue; - StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); - if (!frame_sp) - continue; + StackFrameSP frame_sp = thread_ptr->GetSelectedFrame(); + if (!frame_sp) + continue; - // Find the function name - const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); - const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); - if (!func_name_cstr) - continue; + // Find the function name + const SymbolContext sym_ctx = frame_sp->GetSymbolContext(false); + const char *func_name_cstr = sym_ctx.GetFunctionName().AsCString(); + if (!func_name_cstr) + continue; - if (log) - log->Printf("%s - Inspecting function '%s'", __FUNCTION__, func_name_cstr); + if (log) + log->Printf("%s - Inspecting function '%s'", __FUNCTION__, + func_name_cstr); - // Check if function name has .expand suffix - std::string func_name(func_name_cstr); - const int length_difference = func_name.length() - s_runtimeExpandSuffix.length(); - if (length_difference <= 0) - continue; + // Check if function name has .expand suffix + std::string func_name(func_name_cstr); + const int length_difference = + func_name.length() - s_runtimeExpandSuffix.length(); + if (length_difference <= 0) + continue; - const int32_t has_expand_suffix = func_name.compare(length_difference, - s_runtimeExpandSuffix.length(), - s_runtimeExpandSuffix); + const int32_t has_expand_suffix = + func_name.compare(length_difference, s_runtimeExpandSuffix.length(), + s_runtimeExpandSuffix); - if (has_expand_suffix != 0) - continue; + if (has_expand_suffix != 0) + continue; - if (log) - log->Printf("%s - Found .expand function '%s'", __FUNCTION__, func_name_cstr); - - // Get values for variables in .expand frame that tell us the current kernel invocation - bool found_coord_variables = true; - assert(s_runtimeCoordVars.size() == coord.size()); - - for (uint32_t i = 0; i < coord.size(); ++i) - { - uint64_t value = 0; - if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) - { - found_coord_variables = false; - break; - } - coord[i] = value; - } - - if (found_coord_variables) - return true; - } - return false; + if (log) + log->Printf("%s - Found .expand function '%s'", __FUNCTION__, + func_name_cstr); + + // Get values for variables in .expand frame that tell us the current kernel + // invocation + bool found_coord_variables = true; + assert(s_runtimeCoordVars.size() == coord.size()); + + for (uint32_t i = 0; i < coord.size(); ++i) { + uint64_t value = 0; + if (!GetFrameVarAsUnsigned(frame_sp, s_runtimeCoordVars[i], value)) { + found_coord_variables = false; + break; + } + coord[i] = value; + } + + if (found_coord_variables) + return true; + } + return false; } -// Callback when a kernel breakpoint hits and we're looking for a specific coordinate. -// Baton parameter contains a pointer to the target coordinate we want to break on. -// Function then checks the .expand frame for the current coordinate and breaks to user if it matches. +// Callback when a kernel breakpoint hits and we're looking for a specific +// coordinate. +// Baton parameter contains a pointer to the target coordinate we want to break +// on. +// Function then checks the .expand frame for the current coordinate and breaks +// to user if it matches. // Parameter 'break_id' is the id of the Breakpoint which made the callback. // Parameter 'break_loc_id' is the id for the BreakpointLocation which was hit, // a single logical breakpoint can have multiple addresses. -bool -RenderScriptRuntime::KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, user_id_t break_id, - user_id_t break_loc_id) -{ - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); - - assert(baton && "Error: null baton in conditional kernel breakpoint callback"); - - // Coordinate we want to stop on - const uint32_t *target_coord = static_cast<const uint32_t *>(baton); - +bool RenderScriptRuntime::KernelBreakpointHit(void *baton, + StoppointCallbackContext *ctx, + user_id_t break_id, + user_id_t break_loc_id) { + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_BREAKPOINTS)); + + assert(baton && + "Error: null baton in conditional kernel breakpoint callback"); + + // Coordinate we want to stop on + const uint32_t *target_coord = static_cast<const uint32_t *>(baton); + + if (log) + log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 + ")", + __FUNCTION__, break_id, target_coord[0], target_coord[1], + target_coord[2]); + + // Select current thread + ExecutionContext context(ctx->exe_ctx_ref); + Thread *thread_ptr = context.GetThreadPtr(); + assert(thread_ptr && "Null thread pointer"); + + // Find current kernel invocation from .expand frame variables + RSCoordinate current_coord{}; // Zero initialise array + if (!GetKernelCoordinate(current_coord, thread_ptr)) { if (log) - log->Printf("%s - Break ID %" PRIu64 ", (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", __FUNCTION__, break_id, - target_coord[0], target_coord[1], target_coord[2]); - - // Select current thread - ExecutionContext context(ctx->exe_ctx_ref); - Thread *thread_ptr = context.GetThreadPtr(); - assert(thread_ptr && "Null thread pointer"); + log->Printf("%s - Error, couldn't select .expand stack frame", + __FUNCTION__); + return false; + } - // Find current kernel invocation from .expand frame variables - RSCoordinate current_coord{}; // Zero initialise array - if (!GetKernelCoordinate(current_coord, thread_ptr)) - { - if (log) - log->Printf("%s - Error, couldn't select .expand stack frame", __FUNCTION__); - return false; - } + if (log) + log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, + current_coord[0], current_coord[1], current_coord[2]); + // Check if the current kernel invocation coordinate matches our target + // coordinate + if (current_coord[0] == target_coord[0] && + current_coord[1] == target_coord[1] && + current_coord[2] == target_coord[2]) { if (log) - log->Printf("%s - (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, current_coord[0], current_coord[1], - current_coord[2]); - - // Check if the current kernel invocation coordinate matches our target coordinate - if (current_coord[0] == target_coord[0] && - current_coord[1] == target_coord[1] && - current_coord[2] == target_coord[2]) - { - if (log) - log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", __FUNCTION__, current_coord[0], - current_coord[1], current_coord[2]); - - BreakpointSP breakpoint_sp = context.GetTargetPtr()->GetBreakpointByID(break_id); - assert(breakpoint_sp != nullptr && "Error: Couldn't find breakpoint matching break id for callback"); - breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint should only be hit once. - return true; - } + log->Printf("%s, BREAKING (%" PRIu32 ",%" PRIu32 ",%" PRIu32 ")", + __FUNCTION__, current_coord[0], current_coord[1], + current_coord[2]); + + BreakpointSP breakpoint_sp = + context.GetTargetPtr()->GetBreakpointByID(break_id); + assert(breakpoint_sp != nullptr && + "Error: Couldn't find breakpoint matching break id for callback"); + breakpoint_sp->SetEnabled(false); // Optimise since conditional breakpoint + // should only be hit once. + return true; + } - // No match on coordinate - return false; + // No match on coordinate + return false; } -// Tries to set a breakpoint on the start of a kernel, resolved using the kernel name. -// Argument 'coords', represents a three dimensional coordinate which can be used to specify -// a single kernel instance to break on. If this is set then we add a callback to the breakpoint. -void -RenderScriptRuntime::PlaceBreakpointOnKernel(Stream &strm, const char *name, const std::array<int, 3> coords, - Error &error, TargetSP target) -{ - if (!name) - { - error.SetErrorString("invalid kernel name"); - return; - } - - InitSearchFilter(target); - - ConstString kernel_name(name); - BreakpointSP bp = CreateKernelBreakpoint(kernel_name); - - // We have a conditional breakpoint on a specific coordinate - if (coords[0] != -1) - { - strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 ", %" PRId32 ", %" PRId32, - coords[0], coords[1], coords[2]); - strm.EOL(); +// Tries to set a breakpoint on the start of a kernel, resolved using the kernel +// name. +// Argument 'coords', represents a three dimensional coordinate which can be +// used to specify +// a single kernel instance to break on. If this is set then we add a callback +// to the breakpoint. +void RenderScriptRuntime::PlaceBreakpointOnKernel( + Stream &strm, const char *name, const std::array<int, 3> coords, + Error &error, TargetSP target) { + if (!name) { + error.SetErrorString("invalid kernel name"); + return; + } + + InitSearchFilter(target); + + ConstString kernel_name(name); + BreakpointSP bp = CreateKernelBreakpoint(kernel_name); + + // We have a conditional breakpoint on a specific coordinate + if (coords[0] != -1) { + strm.Printf("Conditional kernel breakpoint on coordinate %" PRId32 + ", %" PRId32 ", %" PRId32, + coords[0], coords[1], coords[2]); + strm.EOL(); - // Allocate memory for the baton, and copy over coordinate - uint32_t *baton = new uint32_t[coords.size()]; - baton[0] = coords[0]; baton[1] = coords[1]; baton[2] = coords[2]; + // Allocate memory for the baton, and copy over coordinate + uint32_t *baton = new uint32_t[coords.size()]; + baton[0] = coords[0]; + baton[1] = coords[1]; + baton[2] = coords[2]; - // Create a callback that will be invoked every time the breakpoint is hit. - // The baton object passed to the handler is the target coordinate we want to break on. - bp->SetCallback(KernelBreakpointHit, baton, true); + // Create a callback that will be invoked every time the breakpoint is hit. + // The baton object passed to the handler is the target coordinate we want + // to break on. + bp->SetCallback(KernelBreakpointHit, baton, true); - // Store a shared pointer to the baton, so the memory will eventually be cleaned up after destruction - m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); - } + // Store a shared pointer to the baton, so the memory will eventually be + // cleaned up after destruction + m_conditional_breaks[bp->GetID()] = std::shared_ptr<uint32_t>(baton); + } - if (bp) - bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); + if (bp) + bp->GetDescription(&strm, lldb::eDescriptionLevelInitial, false); } -void -RenderScriptRuntime::DumpModules(Stream &strm) const -{ - strm.Printf("RenderScript Modules:"); - strm.EOL(); - strm.IndentMore(); - for (const auto &module : m_rsmodules) - { - module->Dump(strm); - } - strm.IndentLess(); +void RenderScriptRuntime::DumpModules(Stream &strm) const { + strm.Printf("RenderScript Modules:"); + strm.EOL(); + strm.IndentMore(); + for (const auto &module : m_rsmodules) { + module->Dump(strm); + } + strm.IndentLess(); } RenderScriptRuntime::ScriptDetails * -RenderScriptRuntime::LookUpScript(addr_t address, bool create) -{ - for (const auto &s : m_scripts) - { - if (s->script.isValid()) - if (*s->script == address) - return s.get(); - } - if (create) - { - std::unique_ptr<ScriptDetails> s(new ScriptDetails); - s->script = address; - m_scripts.push_back(std::move(s)); - return m_scripts.back().get(); - } - return nullptr; +RenderScriptRuntime::LookUpScript(addr_t address, bool create) { + for (const auto &s : m_scripts) { + if (s->script.isValid()) + if (*s->script == address) + return s.get(); + } + if (create) { + std::unique_ptr<ScriptDetails> s(new ScriptDetails); + s->script = address; + m_scripts.push_back(std::move(s)); + return m_scripts.back().get(); + } + return nullptr; } RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::LookUpAllocation(addr_t address) -{ - for (const auto &a : m_allocations) - { - if (a->address.isValid()) - if (*a->address == address) - return a.get(); - } - return nullptr; +RenderScriptRuntime::LookUpAllocation(addr_t address) { + for (const auto &a : m_allocations) { + if (a->address.isValid()) + if (*a->address == address) + return a.get(); + } + return nullptr; } RenderScriptRuntime::AllocationDetails * -RenderScriptRuntime::CreateAllocation(addr_t address) -{ - Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); - - // Remove any previous allocation which contains the same address - auto it = m_allocations.begin(); - while (it != m_allocations.end()) - { - if (*((*it)->address) == address) - { - if (log) - log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64, __FUNCTION__, (*it)->id, address); - - it = m_allocations.erase(it); - } - else - { - it++; - } - } - - std::unique_ptr<AllocationDetails> a(new AllocationDetails); - a->address = address; - m_allocations.push_back(std::move(a)); - return m_allocations.back().get(); +RenderScriptRuntime::CreateAllocation(addr_t address) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); + + // Remove any previous allocation which contains the same address + auto it = m_allocations.begin(); + while (it != m_allocations.end()) { + if (*((*it)->address) == address) { + if (log) + log->Printf("%s - Removing allocation id: %d, address: 0x%" PRIx64, + __FUNCTION__, (*it)->id, address); + + it = m_allocations.erase(it); + } else { + it++; + } + } + + std::unique_ptr<AllocationDetails> a(new AllocationDetails); + a->address = address; + m_allocations.push_back(std::move(a)); + return m_allocations.back().get(); } -void -RSModuleDescriptor::Dump(Stream &strm) const -{ - strm.Indent(); - m_module->GetFileSpec().Dump(&strm); - if (m_module->GetNumCompileUnits()) - { - strm.Indent("Debug info loaded."); - } - else - { - strm.Indent("Debug info does not exist."); - } - strm.EOL(); - strm.IndentMore(); - strm.Indent(); - strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); +void RSModuleDescriptor::Dump(Stream &strm) const { + strm.Indent(); + m_module->GetFileSpec().Dump(&strm); + if (m_module->GetNumCompileUnits()) { + strm.Indent("Debug info loaded."); + } else { + strm.Indent("Debug info does not exist."); + } + strm.EOL(); + strm.IndentMore(); + strm.Indent(); + strm.Printf("Globals: %" PRIu64, static_cast<uint64_t>(m_globals.size())); + strm.EOL(); + strm.IndentMore(); + for (const auto &global : m_globals) { + global.Dump(strm); + } + strm.IndentLess(); + strm.Indent(); + strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); + strm.EOL(); + strm.IndentMore(); + for (const auto &kernel : m_kernels) { + kernel.Dump(strm); + } + strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); + strm.EOL(); + strm.IndentMore(); + for (const auto &key_val : m_pragmas) { + strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); strm.EOL(); - strm.IndentMore(); - for (const auto &global : m_globals) - { - global.Dump(strm); - } - strm.IndentLess(); - strm.Indent(); - strm.Printf("Kernels: %" PRIu64, static_cast<uint64_t>(m_kernels.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &kernel : m_kernels) - { - kernel.Dump(strm); - } - strm.Printf("Pragmas: %" PRIu64, static_cast<uint64_t>(m_pragmas.size())); - strm.EOL(); - strm.IndentMore(); - for (const auto &key_val : m_pragmas) - { - strm.Printf("%s: %s", key_val.first.c_str(), key_val.second.c_str()); - strm.EOL(); - } - strm.IndentLess(4); + } + strm.IndentLess(4); } -void -RSGlobalDescriptor::Dump(Stream &strm) const -{ - strm.Indent(m_name.AsCString()); - VariableList var_list; - m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); - if (var_list.GetSize() == 1) - { - auto var = var_list.GetVariableAtIndex(0); - auto type = var->GetType(); - if (type) - { - strm.Printf(" - "); - type->DumpTypeName(&strm); - } - else - { - strm.Printf(" - Unknown Type"); - } - } - else - { - strm.Printf(" - variable identified, but not found in binary"); - const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType(m_name, eSymbolTypeData); - if (s) - { - strm.Printf(" (symbol exists) "); - } - } - - strm.EOL(); +void RSGlobalDescriptor::Dump(Stream &strm) const { + strm.Indent(m_name.AsCString()); + VariableList var_list; + m_module->m_module->FindGlobalVariables(m_name, nullptr, true, 1U, var_list); + if (var_list.GetSize() == 1) { + auto var = var_list.GetVariableAtIndex(0); + auto type = var->GetType(); + if (type) { + strm.Printf(" - "); + type->DumpTypeName(&strm); + } else { + strm.Printf(" - Unknown Type"); + } + } else { + strm.Printf(" - variable identified, but not found in binary"); + const Symbol *s = m_module->m_module->FindFirstSymbolWithNameAndType( + m_name, eSymbolTypeData); + if (s) { + strm.Printf(" (symbol exists) "); + } + } + + strm.EOL(); } -void -RSKernelDescriptor::Dump(Stream &strm) const -{ - strm.Indent(m_name.AsCString()); - strm.EOL(); +void RSKernelDescriptor::Dump(Stream &strm) const { + strm.Indent(m_name.AsCString()); + strm.EOL(); } -class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeModuleDump : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript module dump", - "Dumps renderscript specific information for all modules.", "renderscript module dump", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeModuleDump() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); - runtime->DumpModules(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeModuleDump(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript module dump", + "Dumps renderscript specific information for all modules.", + "renderscript module dump", + eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeModuleDump() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = + (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); + runtime->DumpModules(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; -class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntimeModule : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript module", "Commands that deal with RenderScript modules.", - nullptr) - { - LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeModule() override = default; + CommandObjectRenderScriptRuntimeModule(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "renderscript module", + "Commands that deal with RenderScript modules.", + nullptr) { + LoadSubCommand( + "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeModuleDump( + interpreter))); + } + + ~CommandObjectRenderScriptRuntimeModule() override = default; }; -class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeKernelList : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript kernel list", - "Lists renderscript kernel names and associated script resources.", - "renderscript kernel list", eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeKernelList() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); - runtime->DumpKernels(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeKernelList(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript kernel list", + "Lists renderscript kernel names and associated script resources.", + "renderscript kernel list", + eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeKernelList() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = + (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); + runtime->DumpKernels(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; -class CommandObjectRenderScriptRuntimeKernelBreakpointSet : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeKernelBreakpointSet + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeKernelBreakpointSet(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript kernel breakpoint set", - "Sets a breakpoint on a renderscript kernel.", - "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused), - m_options() - { + CommandObjectRenderScriptRuntimeKernelBreakpointSet( + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript kernel breakpoint set", + "Sets a breakpoint on a renderscript kernel.", + "renderscript kernel breakpoint set <kernel_name> [-c x,y,z]", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused), + m_options() {} + + ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'c': + if (!ParseCoordinate(option_arg)) + error.SetErrorStringWithFormat( + "Couldn't parse coordinate '%s', should be in format 'x,y,z'.", + option_arg); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + return error; + } + + // -c takes an argument of the form 'num[,num][,num]'. + // Where 'id_cstr' is this argument with the whitespace trimmed. + // Missing coordinates are defaulted to zero. + bool ParseCoordinate(const char *id_cstr) { + RegularExpression regex; + RegularExpression::Match regex_match(3); + + bool matched = false; + if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && + regex.Execute(id_cstr, ®ex_match)) + matched = true; + else if (regex.Compile("^([0-9]+),([0-9]+)$") && + regex.Execute(id_cstr, ®ex_match)) + matched = true; + else if (regex.Compile("^([0-9]+)$") && + regex.Execute(id_cstr, ®ex_match)) + matched = true; + for (uint32_t i = 0; i < 3; i++) { + std::string group; + if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) + m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); + else + m_coord[i] = 0; + } + return matched; } - ~CommandObjectRenderScriptRuntimeKernelBreakpointSet() override = default; - - Options * - GetOptions() override - { - return &m_options; + void OptionParsingStarting(ExecutionContext *execution_context) override { + // -1 means the -c option hasn't been set + m_coord[0] = -1; + m_coord[1] = -1; + m_coord[2] = -1; } - class CommandOptions : public Options - { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Error - SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'c': - if (!ParseCoordinate(option_arg)) - error.SetErrorStringWithFormat("Couldn't parse coordinate '%s', should be in format 'x,y,z'.", - option_arg); - break; - default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return error; - } - - // -c takes an argument of the form 'num[,num][,num]'. - // Where 'id_cstr' is this argument with the whitespace trimmed. - // Missing coordinates are defaulted to zero. - bool - ParseCoordinate(const char *id_cstr) - { - RegularExpression regex; - RegularExpression::Match regex_match(3); - - bool matched = false; - if (regex.Compile("^([0-9]+),([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) - matched = true; - else if (regex.Compile("^([0-9]+),([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) - matched = true; - else if (regex.Compile("^([0-9]+)$") && regex.Execute(id_cstr, ®ex_match)) - matched = true; - for (uint32_t i = 0; i < 3; i++) - { - std::string group; - if (regex_match.GetMatchAtIndex(id_cstr, i + 1, group)) - m_coord[i] = (uint32_t)strtoul(group.c_str(), nullptr, 0); - else - m_coord[i] = 0; - } - return matched; - } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - // -1 means the -c option hasn't been set - m_coord[0] = -1; - m_coord[1] = -1; - m_coord[2] = -1; - } - - const OptionDefinition * - GetDefinitions() override - { - return g_option_table; - } + const OptionDefinition *GetDefinitions() override { return g_option_table; } - static OptionDefinition g_option_table[]; - std::array<int, 3> m_coord; - }; + static OptionDefinition g_option_table[]; + std::array<int, 3> m_coord; + }; - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc < 1) - { - result.AppendErrorWithFormat("'%s' takes 1 argument of kernel name, and an optional coordinate.", - m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc < 1) { + result.AppendErrorWithFormat( + "'%s' takes 1 argument of kernel name, and an optional coordinate.", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } - RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); + RenderScriptRuntime *runtime = + (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); - Error error; - runtime->PlaceBreakpointOnKernel(result.GetOutputStream(), command.GetArgumentAtIndex(0), m_options.m_coord, - error, m_exe_ctx.GetTargetSP()); + Error error; + runtime->PlaceBreakpointOnKernel( + result.GetOutputStream(), command.GetArgumentAtIndex(0), + m_options.m_coord, error, m_exe_ctx.GetTargetSP()); - if (error.Success()) - { - result.AppendMessage("Breakpoint(s) created"); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - result.SetStatus(eReturnStatusFailed); - result.AppendErrorWithFormat("Error: %s", error.AsCString()); - return false; + if (error.Success()) { + result.AppendMessage("Breakpoint(s) created"); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; } + result.SetStatus(eReturnStatusFailed); + result.AppendErrorWithFormat("Error: %s", error.AsCString()); + return false; + } private: - CommandOptions m_options; + CommandOptions m_options; }; -OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet::CommandOptions::g_option_table[] = { - {LLDB_OPT_SET_1, false, "coordinate", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, - "Set a breakpoint on a single invocation of the kernel with specified coordinate.\n" - "Coordinate takes the form 'x[,y][,z] where x,y,z are positive integers representing kernel dimensions. " - "Any unset dimensions will be defaulted to zero."}, - {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; - -class CommandObjectRenderScriptRuntimeKernelBreakpointAll : public CommandObjectParsed -{ +OptionDefinition CommandObjectRenderScriptRuntimeKernelBreakpointSet:: + CommandOptions::g_option_table[] = { + {LLDB_OPT_SET_1, false, "coordinate", 'c', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeValue, + "Set a breakpoint on a single invocation of the kernel with specified " + "coordinate.\n" + "Coordinate takes the form 'x[,y][,z] where x,y,z are positive " + "integers representing kernel dimensions. " + "Any unset dimensions will be defaulted to zero."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; + +class CommandObjectRenderScriptRuntimeKernelBreakpointAll + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeKernelBreakpointAll(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript kernel breakpoint all", - "Automatically sets a breakpoint on all renderscript kernels that are or will be loaded.\n" - "Disabling option means breakpoints will no longer be set on any kernels loaded in the future, " - "but does not remove currently set breakpoints.", - "renderscript kernel breakpoint all <enable/disable>", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) - { - } - - ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc != 1) - { - result.AppendErrorWithFormat("'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - - bool do_break = false; - const char *argument = command.GetArgumentAtIndex(0); - if (strcmp(argument, "enable") == 0) - { - do_break = true; - result.AppendMessage("Breakpoints will be set on all kernels."); - } - else if (strcmp(argument, "disable") == 0) - { - do_break = false; - result.AppendMessage("Breakpoints will not be set on any new kernels."); - } - else - { - result.AppendErrorWithFormat("Argument must be either 'enable' or 'disable'"); - result.SetStatus(eReturnStatusFailed); - return false; - } - - runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); - - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeKernelBreakpointAll( + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript kernel breakpoint all", + "Automatically sets a breakpoint on all renderscript kernels that " + "are or will be loaded.\n" + "Disabling option means breakpoints will no longer be set on any " + "kernels loaded in the future, " + "but does not remove currently set breakpoints.", + "renderscript kernel breakpoint all <enable/disable>", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) {} + + ~CommandObjectRenderScriptRuntimeKernelBreakpointAll() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc != 1) { + result.AppendErrorWithFormat( + "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + + bool do_break = false; + const char *argument = command.GetArgumentAtIndex(0); + if (strcmp(argument, "enable") == 0) { + do_break = true; + result.AppendMessage("Breakpoints will be set on all kernels."); + } else if (strcmp(argument, "disable") == 0) { + do_break = false; + result.AppendMessage("Breakpoints will not be set on any new kernels."); + } else { + result.AppendErrorWithFormat( + "Argument must be either 'enable' or 'disable'"); + result.SetStatus(eReturnStatusFailed); + return false; + } + + runtime->SetBreakAllKernels(do_break, m_exe_ctx.GetTargetSP()); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; -class CommandObjectRenderScriptRuntimeKernelCoordinate : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeKernelCoordinate + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeKernelCoordinate(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript kernel coordinate", - "Shows the (x,y,z) coordinate of the current kernel invocation.", - "renderscript kernel coordinate", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) - { - } - - ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RSCoordinate coord{}; // Zero initialize array - bool success = RenderScriptRuntime::GetKernelCoordinate(coord, m_exe_ctx.GetThreadPtr()); - Stream &stream = result.GetOutputStream(); - - if (success) - { - stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", coord[0], coord[1], coord[2]); - stream.EOL(); - result.SetStatus(eReturnStatusSuccessFinishResult); - } - else - { - stream.Printf("Error: Coordinate could not be found."); - stream.EOL(); - result.SetStatus(eReturnStatusFailed); - } - return true; + CommandObjectRenderScriptRuntimeKernelCoordinate( + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript kernel coordinate", + "Shows the (x,y,z) coordinate of the current kernel invocation.", + "renderscript kernel coordinate", + eCommandRequiresProcess | eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) {} + + ~CommandObjectRenderScriptRuntimeKernelCoordinate() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RSCoordinate coord{}; // Zero initialize array + bool success = RenderScriptRuntime::GetKernelCoordinate( + coord, m_exe_ctx.GetThreadPtr()); + Stream &stream = result.GetOutputStream(); + + if (success) { + stream.Printf("Coordinate: (%" PRIu32 ", %" PRIu32 ", %" PRIu32 ")", + coord[0], coord[1], coord[2]); + stream.EOL(); + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + stream.Printf("Error: Coordinate could not be found."); + stream.EOL(); + result.SetStatus(eReturnStatusFailed); } + return true; + } }; -class CommandObjectRenderScriptRuntimeKernelBreakpoint : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntimeKernelBreakpoint + : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntimeKernelBreakpoint(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript kernel", - "Commands that generate breakpoints on renderscript kernels.", nullptr) - { - LoadSubCommand("set", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet(interpreter))); - LoadSubCommand("all", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; + CommandObjectRenderScriptRuntimeKernelBreakpoint( + CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "renderscript kernel", + "Commands that generate breakpoints on renderscript kernels.", + nullptr) { + LoadSubCommand( + "set", + CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointSet( + interpreter))); + LoadSubCommand( + "all", + CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpointAll( + interpreter))); + } + + ~CommandObjectRenderScriptRuntimeKernelBreakpoint() override = default; }; -class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntimeKernel : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript kernel", "Commands that deal with RenderScript kernels.", - nullptr) - { - LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList(interpreter))); - LoadSubCommand("coordinate", - CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); - LoadSubCommand("breakpoint", - CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeKernel() override = default; + CommandObjectRenderScriptRuntimeKernel(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "renderscript kernel", + "Commands that deal with RenderScript kernels.", + nullptr) { + LoadSubCommand( + "list", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernelList( + interpreter))); + LoadSubCommand( + "coordinate", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeKernelCoordinate(interpreter))); + LoadSubCommand( + "breakpoint", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeKernelBreakpoint(interpreter))); + } + + ~CommandObjectRenderScriptRuntimeKernel() override = default; }; -class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeContextDump : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript context dump", "Dumps renderscript context information.", - "renderscript context dump", eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeContextDump() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); - runtime->DumpContexts(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeContextDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript context dump", + "Dumps renderscript context information.", + "renderscript context dump", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeContextDump() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = + (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); + runtime->DumpContexts(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; -class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntimeContext : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript context", "Commands that deal with RenderScript contexts.", - nullptr) - { - LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeContext() override = default; + CommandObjectRenderScriptRuntimeContext(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "renderscript context", + "Commands that deal with RenderScript contexts.", + nullptr) { + LoadSubCommand( + "dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeContextDump( + interpreter))); + } + + ~CommandObjectRenderScriptRuntimeContext() override = default; }; -class CommandObjectRenderScriptRuntimeAllocationDump : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeAllocationDump + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeAllocationDump(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation dump", - "Displays the contents of a particular allocation", "renderscript allocation dump <ID>", - eCommandRequiresProcess | eCommandProcessMustBeLaunched), - m_options() - { - } - - ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; - - Options * - GetOptions() override - { - return &m_options; - } - - class CommandOptions : public Options - { - public: - CommandOptions() : Options() {} - - ~CommandOptions() override = default; - - Error - SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'f': - m_outfile.SetFile(option_arg, true); - if (m_outfile.Exists()) - { - m_outfile.Clear(); - error.SetErrorStringWithFormat("file already exists: '%s'", option_arg); - } - break; - default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return error; - } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_outfile.Clear(); - } - - const OptionDefinition * - GetDefinitions() override - { - return g_option_table; - } - - static OptionDefinition g_option_table[]; - FileSpec m_outfile; - }; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc < 1) - { - result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. As well as an optional -f argument", - m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - bool convert_complete = false; - const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); - if (!convert_complete) - { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); - return false; + CommandObjectRenderScriptRuntimeAllocationDump( + CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript allocation dump", + "Displays the contents of a particular allocation", + "renderscript allocation dump <ID>", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched), + m_options() {} + + ~CommandObjectRenderScriptRuntimeAllocationDump() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + m_outfile.SetFile(option_arg, true); + if (m_outfile.Exists()) { + m_outfile.Clear(); + error.SetErrorStringWithFormat("file already exists: '%s'", + option_arg); } + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_outfile.Clear(); + } + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + static OptionDefinition g_option_table[]; + FileSpec m_outfile; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc < 1) { + result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " + "As well as an optional -f argument", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + + const char *id_cstr = command.GetArgumentAtIndex(0); + bool convert_complete = false; + const uint32_t id = + StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); + if (!convert_complete) { + result.AppendErrorWithFormat("invalid allocation id argument '%s'", + id_cstr); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Stream *output_strm = nullptr; + StreamFile outfile_stream; + const FileSpec &outfile_spec = + m_options.m_outfile; // Dump allocation to file instead + if (outfile_spec) { + // Open output file + char path[256]; + outfile_spec.GetPath(path, sizeof(path)); + if (outfile_stream.GetFile() + .Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate) + .Success()) { + output_strm = &outfile_stream; + result.GetOutputStream().Printf("Results written to '%s'", path); + result.GetOutputStream().EOL(); + } else { + result.AppendErrorWithFormat("Couldn't open file '%s'", path); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else + output_strm = &result.GetOutputStream(); - Stream *output_strm = nullptr; - StreamFile outfile_stream; - const FileSpec &outfile_spec = m_options.m_outfile; // Dump allocation to file instead - if (outfile_spec) - { - // Open output file - char path[256]; - outfile_spec.GetPath(path, sizeof(path)); - if (outfile_stream.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success()) - { - output_strm = &outfile_stream; - result.GetOutputStream().Printf("Results written to '%s'", path); - result.GetOutputStream().EOL(); - } - else - { - result.AppendErrorWithFormat("Couldn't open file '%s'", path); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - else - output_strm = &result.GetOutputStream(); - - assert(output_strm != nullptr); - bool success = runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); + assert(output_strm != nullptr); + bool success = + runtime->DumpAllocation(*output_strm, m_exe_ctx.GetFramePtr(), id); - if (success) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); + if (success) + result.SetStatus(eReturnStatusSuccessFinishResult); + else + result.SetStatus(eReturnStatusFailed); - return true; - } + return true; + } private: - CommandOptions m_options; + CommandOptions m_options; }; -OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump::CommandOptions::g_option_table[] = { - {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, - "Print results to specified file instead of command line."}, - {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; +OptionDefinition CommandObjectRenderScriptRuntimeAllocationDump:: + CommandOptions::g_option_table[] = { + {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeFilename, + "Print results to specified file instead of command line."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; -class CommandObjectRenderScriptRuntimeAllocationList : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeAllocationList + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeAllocationList(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation list", - "List renderscript allocations and their information.", "renderscript allocation list", - eCommandRequiresProcess | eCommandProcessMustBeLaunched), - m_options() - { - } - - ~CommandObjectRenderScriptRuntimeAllocationList() override = default; - - Options * - GetOptions() override - { - return &m_options; - } - - class CommandOptions : public Options - { - public: - CommandOptions() : Options(), m_id(0) {} - - ~CommandOptions() override = default; - - Error - SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 'i': - bool success; - m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); - if (!success) - error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option); - break; - default: - error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); - break; - } - return error; - } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_id = 0; - } - - const OptionDefinition * - GetDefinitions() override - { - return g_option_table; - } - - static OptionDefinition g_option_table[]; - uint32_t m_id; - }; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), m_options.m_id); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeAllocationList( + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript allocation list", + "List renderscript allocations and their information.", + "renderscript allocation list", + eCommandRequiresProcess | eCommandProcessMustBeLaunched), + m_options() {} + + ~CommandObjectRenderScriptRuntimeAllocationList() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options(), m_id(0) {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'i': + bool success; + m_id = StringConvert::ToUInt32(option_arg, 0, 0, &success); + if (!success) + error.SetErrorStringWithFormat( + "invalid integer value for option '%c'", short_option); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_id = 0; + } + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + static OptionDefinition g_option_table[]; + uint32_t m_id; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + runtime->ListAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr(), + m_options.m_id); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } private: - CommandOptions m_options; + CommandOptions m_options; }; -OptionDefinition CommandObjectRenderScriptRuntimeAllocationList::CommandOptions::g_option_table[] = { - {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeIndex, - "Only show details of a single allocation with specified id."}, - {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; +OptionDefinition CommandObjectRenderScriptRuntimeAllocationList:: + CommandOptions::g_option_table[] = { + {LLDB_OPT_SET_1, false, "id", 'i', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeIndex, + "Only show details of a single allocation with specified id."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; -class CommandObjectRenderScriptRuntimeAllocationLoad : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeAllocationLoad + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeAllocationLoad(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript allocation load", "Loads renderscript allocation contents from a file.", - "renderscript allocation load <ID> <filename>", eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } + CommandObjectRenderScriptRuntimeAllocationLoad( + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "renderscript allocation load", + "Loads renderscript allocation contents from a file.", + "renderscript allocation load <ID> <filename>", + eCommandRequiresProcess | eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc != 2) { + result.AppendErrorWithFormat( + "'%s' takes 2 arguments, an allocation ID and filename to read from.", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + + const char *id_cstr = command.GetArgumentAtIndex(0); + bool convert_complete = false; + const uint32_t id = + StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); + if (!convert_complete) { + result.AppendErrorWithFormat("invalid allocation id argument '%s'", + id_cstr); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char *filename = command.GetArgumentAtIndex(1); + bool success = runtime->LoadAllocation(result.GetOutputStream(), id, + filename, m_exe_ctx.GetFramePtr()); - ~CommandObjectRenderScriptRuntimeAllocationLoad() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc != 2) - { - result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", - m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - bool convert_complete = false; - const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); - if (!convert_complete) - { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - - const char *filename = command.GetArgumentAtIndex(1); - bool success = runtime->LoadAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); - - if (success) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); + if (success) + result.SetStatus(eReturnStatusSuccessFinishResult); + else + result.SetStatus(eReturnStatusFailed); - return true; - } + return true; + } }; -class CommandObjectRenderScriptRuntimeAllocationSave : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeAllocationSave + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeAllocationSave(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "renderscript allocation save", "Write renderscript allocation contents to a file.", - "renderscript allocation save <ID> <filename>", eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - if (argc != 2) - { - result.AppendErrorWithFormat("'%s' takes 2 arguments, an allocation ID and filename to read from.", - m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } + CommandObjectRenderScriptRuntimeAllocationSave( + CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript allocation save", + "Write renderscript allocation contents to a file.", + "renderscript allocation save <ID> <filename>", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeAllocationSave() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + if (argc != 2) { + result.AppendErrorWithFormat( + "'%s' takes 2 arguments, an allocation ID and filename to read from.", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + + const char *id_cstr = command.GetArgumentAtIndex(0); + bool convert_complete = false; + const uint32_t id = + StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); + if (!convert_complete) { + result.AppendErrorWithFormat("invalid allocation id argument '%s'", + id_cstr); + result.SetStatus(eReturnStatusFailed); + return false; + } + + const char *filename = command.GetArgumentAtIndex(1); + bool success = runtime->SaveAllocation(result.GetOutputStream(), id, + filename, m_exe_ctx.GetFramePtr()); - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - - const char *id_cstr = command.GetArgumentAtIndex(0); - bool convert_complete = false; - const uint32_t id = StringConvert::ToUInt32(id_cstr, UINT32_MAX, 0, &convert_complete); - if (!convert_complete) - { - result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - - const char *filename = command.GetArgumentAtIndex(1); - bool success = runtime->SaveAllocation(result.GetOutputStream(), id, filename, m_exe_ctx.GetFramePtr()); - - if (success) - result.SetStatus(eReturnStatusSuccessFinishResult); - else - result.SetStatus(eReturnStatusFailed); + if (success) + result.SetStatus(eReturnStatusSuccessFinishResult); + else + result.SetStatus(eReturnStatusFailed); - return true; - } + return true; + } }; -class CommandObjectRenderScriptRuntimeAllocationRefresh : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeAllocationRefresh + : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeAllocationRefresh(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript allocation refresh", - "Recomputes the details of all allocations.", "renderscript allocation refresh", - eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( - m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript)); - - bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), m_exe_ctx.GetFramePtr()); - - if (success) - { - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } - else - { - result.SetStatus(eReturnStatusFailed); - return false; - } - } + CommandObjectRenderScriptRuntimeAllocationRefresh( + CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript allocation refresh", + "Recomputes the details of all allocations.", + "renderscript allocation refresh", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeAllocationRefresh() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = static_cast<RenderScriptRuntime *>( + m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript)); + + bool success = runtime->RecomputeAllAllocations(result.GetOutputStream(), + m_exe_ctx.GetFramePtr()); + + if (success) { + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } else { + result.SetStatus(eReturnStatusFailed); + return false; + } + } }; -class CommandObjectRenderScriptRuntimeAllocation : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntimeAllocation + : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript allocation", - "Commands that deal with RenderScript allocations.", nullptr) - { - LoadSubCommand("list", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); - LoadSubCommand("dump", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); - LoadSubCommand("save", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); - LoadSubCommand("load", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); - LoadSubCommand("refresh", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh(interpreter))); - } - - ~CommandObjectRenderScriptRuntimeAllocation() override = default; + CommandObjectRenderScriptRuntimeAllocation(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "renderscript allocation", + "Commands that deal with RenderScript allocations.", nullptr) { + LoadSubCommand( + "list", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeAllocationList(interpreter))); + LoadSubCommand( + "dump", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeAllocationDump(interpreter))); + LoadSubCommand( + "save", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeAllocationSave(interpreter))); + LoadSubCommand( + "load", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeAllocationLoad(interpreter))); + LoadSubCommand( + "refresh", + CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocationRefresh( + interpreter))); + } + + ~CommandObjectRenderScriptRuntimeAllocation() override = default; }; -class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed -{ +class CommandObjectRenderScriptRuntimeStatus : public CommandObjectParsed { public: - CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "renderscript status", "Displays current RenderScript runtime status.", - "renderscript status", eCommandRequiresProcess | eCommandProcessMustBeLaunched) - { - } - - ~CommandObjectRenderScriptRuntimeStatus() override = default; - - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - RenderScriptRuntime *runtime = - (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime(eLanguageTypeExtRenderScript); - runtime->Status(result.GetOutputStream()); - result.SetStatus(eReturnStatusSuccessFinishResult); - return true; - } + CommandObjectRenderScriptRuntimeStatus(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "renderscript status", + "Displays current RenderScript runtime status.", + "renderscript status", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched) {} + + ~CommandObjectRenderScriptRuntimeStatus() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + RenderScriptRuntime *runtime = + (RenderScriptRuntime *)m_exe_ctx.GetProcessPtr()->GetLanguageRuntime( + eLanguageTypeExtRenderScript); + runtime->Status(result.GetOutputStream()); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } }; -class CommandObjectRenderScriptRuntime : public CommandObjectMultiword -{ +class CommandObjectRenderScriptRuntime : public CommandObjectMultiword { public: - CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "renderscript", "Commands for operating on the RenderScript runtime.", - "renderscript <subcommand> [<subcommand-options>]") - { - LoadSubCommand("module", CommandObjectSP(new CommandObjectRenderScriptRuntimeModule(interpreter))); - LoadSubCommand("status", CommandObjectSP(new CommandObjectRenderScriptRuntimeStatus(interpreter))); - LoadSubCommand("kernel", CommandObjectSP(new CommandObjectRenderScriptRuntimeKernel(interpreter))); - LoadSubCommand("context", CommandObjectSP(new CommandObjectRenderScriptRuntimeContext(interpreter))); - LoadSubCommand("allocation", CommandObjectSP(new CommandObjectRenderScriptRuntimeAllocation(interpreter))); - } - - ~CommandObjectRenderScriptRuntime() override = default; + CommandObjectRenderScriptRuntime(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "renderscript", + "Commands for operating on the RenderScript runtime.", + "renderscript <subcommand> [<subcommand-options>]") { + LoadSubCommand( + "module", CommandObjectSP( + new CommandObjectRenderScriptRuntimeModule(interpreter))); + LoadSubCommand( + "status", CommandObjectSP( + new CommandObjectRenderScriptRuntimeStatus(interpreter))); + LoadSubCommand( + "kernel", CommandObjectSP( + new CommandObjectRenderScriptRuntimeKernel(interpreter))); + LoadSubCommand("context", + CommandObjectSP(new CommandObjectRenderScriptRuntimeContext( + interpreter))); + LoadSubCommand( + "allocation", + CommandObjectSP( + new CommandObjectRenderScriptRuntimeAllocation(interpreter))); + } + + ~CommandObjectRenderScriptRuntime() override = default; }; -void -RenderScriptRuntime::Initiate() -{ - assert(!m_initiated); -} +void RenderScriptRuntime::Initiate() { assert(!m_initiated); } RenderScriptRuntime::RenderScriptRuntime(Process *process) - : lldb_private::CPPLanguageRuntime(process), - m_initiated(false), - m_debuggerPresentFlagged(false), - m_breakAllKernels(false), - m_ir_passes(nullptr) -{ - ModulesDidLoad(process->GetTarget().GetImages()); + : lldb_private::CPPLanguageRuntime(process), m_initiated(false), + m_debuggerPresentFlagged(false), m_breakAllKernels(false), + m_ir_passes(nullptr) { + ModulesDidLoad(process->GetTarget().GetImages()); } -lldb::CommandObjectSP -RenderScriptRuntime::GetCommandObject(lldb_private::CommandInterpreter &interpreter) -{ - return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); +lldb::CommandObjectSP RenderScriptRuntime::GetCommandObject( + lldb_private::CommandInterpreter &interpreter) { + return CommandObjectSP(new CommandObjectRenderScriptRuntime(interpreter)); } RenderScriptRuntime::~RenderScriptRuntime() = default; diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index 50db2e13bcb..7aad7058d86 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -26,10 +26,8 @@ #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" -namespace lldb_private -{ -namespace lldb_renderscript -{ +namespace lldb_private { +namespace lldb_renderscript { typedef uint32_t RSSlot; class RSModuleDescriptor; @@ -44,383 +42,330 @@ typedef std::array<uint32_t, 3> RSCoordinate; // Breakpoint Resolvers decide where a breakpoint is placed, // so having our own allows us to limit the search scope to RS kernel modules. // As well as check for .expand kernels as a fallback. -class RSBreakpointResolver : public BreakpointResolver -{ +class RSBreakpointResolver : public BreakpointResolver { public: - RSBreakpointResolver(Breakpoint *bkpt, ConstString name) - : BreakpointResolver(bkpt, BreakpointResolver::NameResolver), m_kernel_name(name) - { - } - - void - GetDescription(Stream *strm) override - { - if (strm) - strm->Printf("RenderScript kernel breakpoint for '%s'", m_kernel_name.AsCString()); - } - - void - Dump(Stream *s) const override - { - } - - Searcher::CallbackReturn - SearchCallback(SearchFilter &filter, SymbolContext &context, Address *addr, bool containing) override; - - Searcher::Depth - GetDepth() override - { - return Searcher::eDepthModule; - } - - lldb::BreakpointResolverSP - CopyForBreakpoint(Breakpoint &breakpoint) override - { - lldb::BreakpointResolverSP ret_sp(new RSBreakpointResolver(&breakpoint, m_kernel_name)); - return ret_sp; - } + RSBreakpointResolver(Breakpoint *bkpt, ConstString name) + : BreakpointResolver(bkpt, BreakpointResolver::NameResolver), + m_kernel_name(name) {} + + void GetDescription(Stream *strm) override { + if (strm) + strm->Printf("RenderScript kernel breakpoint for '%s'", + m_kernel_name.AsCString()); + } + + void Dump(Stream *s) const override {} + + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override; + + Searcher::Depth GetDepth() override { return Searcher::eDepthModule; } + + lldb::BreakpointResolverSP + CopyForBreakpoint(Breakpoint &breakpoint) override { + lldb::BreakpointResolverSP ret_sp( + new RSBreakpointResolver(&breakpoint, m_kernel_name)); + return ret_sp; + } protected: - ConstString m_kernel_name; + ConstString m_kernel_name; }; -struct RSKernelDescriptor -{ +struct RSKernelDescriptor { public: - RSKernelDescriptor(const RSModuleDescriptor *module, const char *name, uint32_t slot) - : m_module(module), m_name(name), m_slot(slot) - { - } + RSKernelDescriptor(const RSModuleDescriptor *module, const char *name, + uint32_t slot) + : m_module(module), m_name(name), m_slot(slot) {} - void - Dump(Stream &strm) const; + void Dump(Stream &strm) const; - const RSModuleDescriptor *m_module; - ConstString m_name; - RSSlot m_slot; + const RSModuleDescriptor *m_module; + ConstString m_name; + RSSlot m_slot; }; -struct RSGlobalDescriptor -{ +struct RSGlobalDescriptor { public: - RSGlobalDescriptor(const RSModuleDescriptor *module, const char *name) : m_module(module), m_name(name) {} + RSGlobalDescriptor(const RSModuleDescriptor *module, const char *name) + : m_module(module), m_name(name) {} - void - Dump(Stream &strm) const; + void Dump(Stream &strm) const; - const RSModuleDescriptor *m_module; - ConstString m_name; + const RSModuleDescriptor *m_module; + ConstString m_name; }; -class RSModuleDescriptor -{ +class RSModuleDescriptor { public: - RSModuleDescriptor(const lldb::ModuleSP &module) : m_module(module) {} + RSModuleDescriptor(const lldb::ModuleSP &module) : m_module(module) {} - ~RSModuleDescriptor() = default; + ~RSModuleDescriptor() = default; - bool - ParseRSInfo(); + bool ParseRSInfo(); - void - Dump(Stream &strm) const; + void Dump(Stream &strm) const; - const lldb::ModuleSP m_module; - std::vector<RSKernelDescriptor> m_kernels; - std::vector<RSGlobalDescriptor> m_globals; - std::map<std::string, std::string> m_pragmas; - std::string m_resname; + const lldb::ModuleSP m_module; + std::vector<RSKernelDescriptor> m_kernels; + std::vector<RSGlobalDescriptor> m_globals; + std::map<std::string, std::string> m_pragmas; + std::string m_resname; }; } // namespace lldb_renderscript -class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime -{ +class RenderScriptRuntime : public lldb_private::CPPLanguageRuntime { public: - enum ModuleKind - { - eModuleKindIgnored, - eModuleKindLibRS, - eModuleKindDriver, - eModuleKindImpl, - eModuleKindKernelObj - }; + enum ModuleKind { + eModuleKindIgnored, + eModuleKindLibRS, + eModuleKindDriver, + eModuleKindImpl, + eModuleKindKernelObj + }; - ~RenderScriptRuntime() override; + ~RenderScriptRuntime() override; - //------------------------------------------------------------------ - // Static Functions - //------------------------------------------------------------------ - static void - Initialize(); + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); - static void - Terminate(); + static void Terminate(); - static lldb_private::LanguageRuntime * - CreateInstance(Process *process, lldb::LanguageType language); + static lldb_private::LanguageRuntime * + CreateInstance(Process *process, lldb::LanguageType language); - static lldb::CommandObjectSP - GetCommandObject(CommandInterpreter &interpreter); + static lldb::CommandObjectSP + GetCommandObject(CommandInterpreter &interpreter); - static lldb_private::ConstString - GetPluginNameStatic(); + static lldb_private::ConstString GetPluginNameStatic(); - static bool - IsRenderScriptModule(const lldb::ModuleSP &module_sp); + static bool IsRenderScriptModule(const lldb::ModuleSP &module_sp); - static ModuleKind - GetModuleKind(const lldb::ModuleSP &module_sp); + static ModuleKind GetModuleKind(const lldb::ModuleSP &module_sp); - static void - ModulesDidLoad(const lldb::ProcessSP &process_sp, const ModuleList &module_list); + static void ModulesDidLoad(const lldb::ProcessSP &process_sp, + const ModuleList &module_list); - bool - IsVTableName(const char *name) override; + bool IsVTableName(const char *name) override; - bool - GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, - TypeAndOrName &class_type_or_name, Address &address, - Value::ValueType &value_type) override; + bool GetDynamicTypeAndAddress(ValueObject &in_value, + lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, + Address &address, + Value::ValueType &value_type) override; - TypeAndOrName - FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) override; + TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name, + ValueObject &static_value) override; - bool - CouldHaveDynamicValue(ValueObject &in_value) override; + bool CouldHaveDynamicValue(ValueObject &in_value) override; - lldb::BreakpointResolverSP - CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override; + lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, + bool catch_bp, + bool throw_bp) override; - bool - LoadModule(const lldb::ModuleSP &module_sp); + bool LoadModule(const lldb::ModuleSP &module_sp); - void - DumpModules(Stream &strm) const; + void DumpModules(Stream &strm) const; - void - DumpContexts(Stream &strm) const; + void DumpContexts(Stream &strm) const; - void - DumpKernels(Stream &strm) const; + void DumpKernels(Stream &strm) const; - bool - DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id); + bool DumpAllocation(Stream &strm, StackFrame *frame_ptr, const uint32_t id); - void - ListAllocations(Stream &strm, StackFrame *frame_ptr, const uint32_t index); + void ListAllocations(Stream &strm, StackFrame *frame_ptr, + const uint32_t index); - bool - RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr); + bool RecomputeAllAllocations(Stream &strm, StackFrame *frame_ptr); - void - PlaceBreakpointOnKernel(Stream &strm, const char *name, const std::array<int, 3> coords, Error &error, - lldb::TargetSP target); + void PlaceBreakpointOnKernel(Stream &strm, const char *name, + const std::array<int, 3> coords, Error &error, + lldb::TargetSP target); - void - SetBreakAllKernels(bool do_break, lldb::TargetSP target); + void SetBreakAllKernels(bool do_break, lldb::TargetSP target); - void - Status(Stream &strm) const; + void Status(Stream &strm) const; - void - ModulesDidLoad(const ModuleList &module_list) override; + void ModulesDidLoad(const ModuleList &module_list) override; - bool - LoadAllocation(Stream &strm, const uint32_t alloc_id, const char *filename, StackFrame *frame_ptr); + bool LoadAllocation(Stream &strm, const uint32_t alloc_id, + const char *filename, StackFrame *frame_ptr); - bool - SaveAllocation(Stream &strm, const uint32_t alloc_id, const char *filename, StackFrame *frame_ptr); + bool SaveAllocation(Stream &strm, const uint32_t alloc_id, + const char *filename, StackFrame *frame_ptr); - void - Update(); + void Update(); - void - Initiate(); + void Initiate(); - //------------------------------------------------------------------ - // PluginInterface protocol - //------------------------------------------------------------------ - lldb_private::ConstString - GetPluginName() override; + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + lldb_private::ConstString GetPluginName() override; - uint32_t - GetPluginVersion() override; + uint32_t GetPluginVersion() override; - static bool - GetKernelCoordinate(lldb_renderscript::RSCoordinate &coord, Thread *thread_ptr); + static bool GetKernelCoordinate(lldb_renderscript::RSCoordinate &coord, + Thread *thread_ptr); protected: - struct ScriptDetails; - struct AllocationDetails; - struct Element; - - void - InitSearchFilter(lldb::TargetSP target) - { - if (!m_filtersp) - m_filtersp.reset(new SearchFilterForUnconstrainedSearches(target)); - } - - void - FixupScriptDetails(lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); - - void - LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind); - - bool - RefreshAllocation(AllocationDetails *allocation, StackFrame *frame_ptr); - - bool - EvalRSExpression(const char *expression, StackFrame *frame_ptr, uint64_t *result); - - lldb::BreakpointSP - CreateKernelBreakpoint(const ConstString &name); - - void - BreakOnModuleKernels(const lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); - - struct RuntimeHook; - typedef void (RenderScriptRuntime::*CaptureStateFn)(RuntimeHook *hook_info, - ExecutionContext &context); // Please do this! - - struct HookDefn - { - const char *name; - const char *symbol_name_m32; // mangled name for the 32 bit architectures - const char *symbol_name_m64; // mangled name for the 64 bit archs - uint32_t version; - ModuleKind kind; - CaptureStateFn grabber; - }; - - struct RuntimeHook - { - lldb::addr_t address; - const HookDefn *defn; - lldb::BreakpointSP bp_sp; - }; - - typedef std::shared_ptr<RuntimeHook> RuntimeHookSP; - - lldb::ModuleSP m_libRS; - lldb::ModuleSP m_libRSDriver; - lldb::ModuleSP m_libRSCpuRef; - std::vector<lldb_renderscript::RSModuleDescriptorSP> m_rsmodules; - - std::vector<std::unique_ptr<ScriptDetails>> m_scripts; - std::vector<std::unique_ptr<AllocationDetails>> m_allocations; - - std::map<lldb::addr_t, lldb_renderscript::RSModuleDescriptorSP> m_scriptMappings; - std::map<lldb::addr_t, RuntimeHookSP> m_runtimeHooks; - std::map<lldb::user_id_t, std::shared_ptr<uint32_t>> m_conditional_breaks; - - lldb::SearchFilterSP m_filtersp; // Needed to create breakpoints through Target API - - bool m_initiated; - bool m_debuggerPresentFlagged; - bool m_breakAllKernels; - static const HookDefn s_runtimeHookDefns[]; - static const size_t s_runtimeHookCount; - LLVMUserExpression::IRPasses *m_ir_passes; + struct ScriptDetails; + struct AllocationDetails; + struct Element; + + void InitSearchFilter(lldb::TargetSP target) { + if (!m_filtersp) + m_filtersp.reset(new SearchFilterForUnconstrainedSearches(target)); + } + + void FixupScriptDetails(lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); + + void LoadRuntimeHooks(lldb::ModuleSP module, ModuleKind kind); + + bool RefreshAllocation(AllocationDetails *allocation, StackFrame *frame_ptr); + + bool EvalRSExpression(const char *expression, StackFrame *frame_ptr, + uint64_t *result); + + lldb::BreakpointSP CreateKernelBreakpoint(const ConstString &name); + + void BreakOnModuleKernels( + const lldb_renderscript::RSModuleDescriptorSP rsmodule_sp); + + struct RuntimeHook; + typedef void (RenderScriptRuntime::*CaptureStateFn)( + RuntimeHook *hook_info, + ExecutionContext &context); // Please do this! + + struct HookDefn { + const char *name; + const char *symbol_name_m32; // mangled name for the 32 bit architectures + const char *symbol_name_m64; // mangled name for the 64 bit archs + uint32_t version; + ModuleKind kind; + CaptureStateFn grabber; + }; + + struct RuntimeHook { + lldb::addr_t address; + const HookDefn *defn; + lldb::BreakpointSP bp_sp; + }; + + typedef std::shared_ptr<RuntimeHook> RuntimeHookSP; + + lldb::ModuleSP m_libRS; + lldb::ModuleSP m_libRSDriver; + lldb::ModuleSP m_libRSCpuRef; + std::vector<lldb_renderscript::RSModuleDescriptorSP> m_rsmodules; + + std::vector<std::unique_ptr<ScriptDetails>> m_scripts; + std::vector<std::unique_ptr<AllocationDetails>> m_allocations; + + std::map<lldb::addr_t, lldb_renderscript::RSModuleDescriptorSP> + m_scriptMappings; + std::map<lldb::addr_t, RuntimeHookSP> m_runtimeHooks; + std::map<lldb::user_id_t, std::shared_ptr<uint32_t>> m_conditional_breaks; + + lldb::SearchFilterSP + m_filtersp; // Needed to create breakpoints through Target API + + bool m_initiated; + bool m_debuggerPresentFlagged; + bool m_breakAllKernels; + static const HookDefn s_runtimeHookDefns[]; + static const size_t s_runtimeHookCount; + LLVMUserExpression::IRPasses *m_ir_passes; private: - RenderScriptRuntime(Process *process); // Call CreateInstance instead. + RenderScriptRuntime(Process *process); // Call CreateInstance instead. - static bool - HookCallback(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + static bool HookCallback(void *baton, StoppointCallbackContext *ctx, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); - static bool - KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, lldb::user_id_t break_id, - lldb::user_id_t break_loc_id); + static bool KernelBreakpointHit(void *baton, StoppointCallbackContext *ctx, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); - void - HookCallback(RuntimeHook *hook_info, ExecutionContext &context); + void HookCallback(RuntimeHook *hook_info, ExecutionContext &context); - void - CaptureScriptInit(RuntimeHook *hook_info, ExecutionContext &context); + void CaptureScriptInit(RuntimeHook *hook_info, ExecutionContext &context); - void - CaptureAllocationInit(RuntimeHook *hook_info, ExecutionContext &context); + void CaptureAllocationInit(RuntimeHook *hook_info, ExecutionContext &context); - void - CaptureAllocationDestroy(RuntimeHook *hook_info, ExecutionContext &context); + void CaptureAllocationDestroy(RuntimeHook *hook_info, + ExecutionContext &context); - void - CaptureSetGlobalVar(RuntimeHook *hook_info, ExecutionContext &context); + void CaptureSetGlobalVar(RuntimeHook *hook_info, ExecutionContext &context); - void - CaptureScriptInvokeForEachMulti(RuntimeHook *hook_info, ExecutionContext &context); + void CaptureScriptInvokeForEachMulti(RuntimeHook *hook_info, + ExecutionContext &context); - AllocationDetails * - FindAllocByID(Stream &strm, const uint32_t alloc_id); + AllocationDetails *FindAllocByID(Stream &strm, const uint32_t alloc_id); - std::shared_ptr<uint8_t> - GetAllocationData(AllocationDetails *allocation, StackFrame *frame_ptr); + std::shared_ptr<uint8_t> GetAllocationData(AllocationDetails *allocation, + StackFrame *frame_ptr); - void - SetElementSize(Element &elem); + void SetElementSize(Element &elem); - static bool - GetFrameVarAsUnsigned(const lldb::StackFrameSP, const char *var_name, uint64_t &val); + static bool GetFrameVarAsUnsigned(const lldb::StackFrameSP, + const char *var_name, uint64_t &val); - void - FindStructTypeName(Element &elem, StackFrame *frame_ptr); + void FindStructTypeName(Element &elem, StackFrame *frame_ptr); - size_t - PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, size_t offset, const Element &elem); + size_t PopulateElementHeaders(const std::shared_ptr<uint8_t> header_buffer, + size_t offset, const Element &elem); - size_t - CalculateElementHeaderSize(const Element &elem); + size_t CalculateElementHeaderSize(const Element &elem); - // - // Helper functions for jitting the runtime - // + // + // Helper functions for jitting the runtime + // - bool - JITDataPointer(AllocationDetails *allocation, StackFrame *frame_ptr, - uint32_t x = 0, uint32_t y = 0, uint32_t z = 0); + bool JITDataPointer(AllocationDetails *allocation, StackFrame *frame_ptr, + uint32_t x = 0, uint32_t y = 0, uint32_t z = 0); - bool - JITTypePointer(AllocationDetails *allocation, StackFrame *frame_ptr); + bool JITTypePointer(AllocationDetails *allocation, StackFrame *frame_ptr); - bool - JITTypePacked(AllocationDetails *allocation, StackFrame *frame_ptr); + bool JITTypePacked(AllocationDetails *allocation, StackFrame *frame_ptr); - bool - JITElementPacked(Element &elem, const lldb::addr_t context, StackFrame *frame_ptr); + bool JITElementPacked(Element &elem, const lldb::addr_t context, + StackFrame *frame_ptr); - bool - JITAllocationSize(AllocationDetails *allocation, StackFrame *frame_ptr); + bool JITAllocationSize(AllocationDetails *allocation, StackFrame *frame_ptr); - bool - JITSubelements(Element &elem, const lldb::addr_t context, StackFrame *frame_ptr); + bool JITSubelements(Element &elem, const lldb::addr_t context, + StackFrame *frame_ptr); - bool - JITAllocationStride(AllocationDetails *allocation, StackFrame *frame_ptr); + bool JITAllocationStride(AllocationDetails *allocation, + StackFrame *frame_ptr); - // Search for a script detail object using a target address. - // If a script does not currently exist this function will return nullptr. - // If 'create' is true and there is no previous script with this address, - // then a new Script detail object will be created for this address and returned. - ScriptDetails * - LookUpScript(lldb::addr_t address, bool create); + // Search for a script detail object using a target address. + // If a script does not currently exist this function will return nullptr. + // If 'create' is true and there is no previous script with this address, + // then a new Script detail object will be created for this address and + // returned. + ScriptDetails *LookUpScript(lldb::addr_t address, bool create); - // Search for a previously saved allocation detail object using a target address. - // If an allocation does not exist for this address then nullptr will be returned. - AllocationDetails * - LookUpAllocation(lldb::addr_t address); + // Search for a previously saved allocation detail object using a target + // address. + // If an allocation does not exist for this address then nullptr will be + // returned. + AllocationDetails *LookUpAllocation(lldb::addr_t address); - // Creates a new allocation with the specified address assigning a new ID and removes - // any previous stored allocation which has the same address. - AllocationDetails * - CreateAllocation(lldb::addr_t address); + // Creates a new allocation with the specified address assigning a new ID and + // removes + // any previous stored allocation which has the same address. + AllocationDetails *CreateAllocation(lldb::addr_t address); - bool - GetOverrideExprOptions(clang::TargetOptions &prototype) override; + bool GetOverrideExprOptions(clang::TargetOptions &prototype) override; - bool - GetIRPasses(LLVMUserExpression::IRPasses &passes) override; + bool GetIRPasses(LLVMUserExpression::IRPasses &passes) override; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp index 98022630877..354d5d6c0bb 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.cpp @@ -28,258 +28,271 @@ #include "lldb/Target/Process.h" using namespace lldb_private; -namespace -{ - -bool -isRSAPICall(llvm::Module &module, llvm::CallInst *call_inst) -{ - // TODO get the list of renderscript modules from lldb and check if - // this llvm::Module calls into any of them. - (void)module; - const auto func_name = call_inst->getCalledFunction()->getName(); - if (func_name.startswith("llvm") || func_name.startswith("lldb")) - return false; - - if (call_inst->getCalledFunction()->isIntrinsic()) - return false; - - return true; +namespace { + +bool isRSAPICall(llvm::Module &module, llvm::CallInst *call_inst) { + // TODO get the list of renderscript modules from lldb and check if + // this llvm::Module calls into any of them. + (void)module; + const auto func_name = call_inst->getCalledFunction()->getName(); + if (func_name.startswith("llvm") || func_name.startswith("lldb")) + return false; + + if (call_inst->getCalledFunction()->isIntrinsic()) + return false; + + return true; } -bool -isRSLargeReturnCall(llvm::Module &module, llvm::CallInst *call_inst) -{ - // i686 and x86_64 returns for large vectors in the RenderScript API are not handled as normal - // register pairs, but as a hidden sret type. This is not reflected in the debug info or mangled - // symbol name, and the android ABI for x86 and x86_64, (as well as the emulators) specifies there is - // no AVX, so bcc generates an sret function because we cannot natively return 256 bit vectors. - // This function simply checks whether a function has a > 128bit return type. It is perhaps an - // unreliable heuristic, and relies on bcc not generating AVX code, so if the android ABI one day - // provides for AVX, this function may go out of fashion. - (void)module; - if (!call_inst || !call_inst->getCalledFunction()) - return false; - - return call_inst->getCalledFunction()->getReturnType()->getPrimitiveSizeInBits() > 128; +bool isRSLargeReturnCall(llvm::Module &module, llvm::CallInst *call_inst) { + // i686 and x86_64 returns for large vectors in the RenderScript API are not + // handled as normal + // register pairs, but as a hidden sret type. This is not reflected in the + // debug info or mangled + // symbol name, and the android ABI for x86 and x86_64, (as well as the + // emulators) specifies there is + // no AVX, so bcc generates an sret function because we cannot natively return + // 256 bit vectors. + // This function simply checks whether a function has a > 128bit return type. + // It is perhaps an + // unreliable heuristic, and relies on bcc not generating AVX code, so if the + // android ABI one day + // provides for AVX, this function may go out of fashion. + (void)module; + if (!call_inst || !call_inst->getCalledFunction()) + return false; + + return call_inst->getCalledFunction() + ->getReturnType() + ->getPrimitiveSizeInBits() > 128; } -bool -isRSAllocationPtrTy(const llvm::Type *type) -{ - if (!type->isPointerTy()) - return false; - auto ptr_type = type->getPointerElementType(); +bool isRSAllocationPtrTy(const llvm::Type *type) { + if (!type->isPointerTy()) + return false; + auto ptr_type = type->getPointerElementType(); - return ptr_type->isStructTy() && ptr_type->getStructName().startswith("struct.rs_allocation"); + return ptr_type->isStructTy() && + ptr_type->getStructName().startswith("struct.rs_allocation"); } -bool -isRSAllocationTyCallSite(llvm::Module &module, llvm::CallInst *call_inst) -{ - (void)module; - if (!call_inst->hasByValArgument()) - return false; - for (const auto ¶m : call_inst->operand_values()) - if (isRSAllocationPtrTy(param->getType())) - return true; +bool isRSAllocationTyCallSite(llvm::Module &module, llvm::CallInst *call_inst) { + (void)module; + if (!call_inst->hasByValArgument()) return false; + for (const auto ¶m : call_inst->operand_values()) + if (isRSAllocationPtrTy(param->getType())) + return true; + return false; } -llvm::FunctionType * -cloneToStructRetFnTy(llvm::CallInst *call_inst) -{ - // on x86 StructReturn functions return a pointer to the return value, rather than the return - // value itself [ref](http://www.agner.org/optimize/calling_conventions.pdf section 6). - // We create a return type by getting the pointer type of the old return type, and inserting a new - // initial argument of pointer type of the original return type. - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); - - assert(call_inst && "no CallInst"); - llvm::Function *orig = call_inst->getCalledFunction(); - assert(orig && "CallInst has no called function"); - llvm::FunctionType *orig_type = orig->getFunctionType(); - auto name = orig->getName(); - if (log) - log->Printf("%s - cloning to StructRet function for '%s'", __FUNCTION__, name.str().c_str()); - - unsigned num_params = orig_type->getNumParams(); - std::vector<llvm::Type *> new_params{num_params + 1, nullptr}; - std::vector<llvm::Type *> params{orig_type->param_begin(), orig_type->param_end()}; - - // This may not work if the function is somehow declared void as llvm is strongly typed - // and represents void* with i8* - assert(!orig_type->getReturnType()->isVoidTy() && "Cannot add StructRet attribute to void function"); - llvm::PointerType *return_type_ptr_type = llvm::PointerType::getUnqual(orig->getReturnType()); - assert(return_type_ptr_type && "failed to get function return type PointerType"); - if (!return_type_ptr_type) - return nullptr; - - if (log) - log->Printf("%s - return type pointer type for StructRet clone @ '0x%p':\n", __FUNCTION__, - (void *)return_type_ptr_type); - // put the the sret pointer argument in place at the beginning of the argument list. - params.emplace(params.begin(), return_type_ptr_type); - assert(params.size() == num_params + 1); - return llvm::FunctionType::get(return_type_ptr_type, params, orig->isVarArg()); +llvm::FunctionType *cloneToStructRetFnTy(llvm::CallInst *call_inst) { + // on x86 StructReturn functions return a pointer to the return value, rather + // than the return + // value itself [ref](http://www.agner.org/optimize/calling_conventions.pdf + // section 6). + // We create a return type by getting the pointer type of the old return type, + // and inserting a new + // initial argument of pointer type of the original return type. + Log *log( + GetLogIfAnyCategoriesSet(LIBLLDB_LOG_LANGUAGE | LIBLLDB_LOG_EXPRESSIONS)); + + assert(call_inst && "no CallInst"); + llvm::Function *orig = call_inst->getCalledFunction(); + assert(orig && "CallInst has no called function"); + llvm::FunctionType *orig_type = orig->getFunctionType(); + auto name = orig->getName(); + if (log) + log->Printf("%s - cloning to StructRet function for '%s'", __FUNCTION__, + name.str().c_str()); + + unsigned num_params = orig_type->getNumParams(); + std::vector<llvm::Type *> new_params{num_params + 1, nullptr}; + std::vector<llvm::Type *> params{orig_type->param_begin(), + orig_type->param_end()}; + + // This may not work if the function is somehow declared void as llvm is + // strongly typed + // and represents void* with i8* + assert(!orig_type->getReturnType()->isVoidTy() && + "Cannot add StructRet attribute to void function"); + llvm::PointerType *return_type_ptr_type = + llvm::PointerType::getUnqual(orig->getReturnType()); + assert(return_type_ptr_type && + "failed to get function return type PointerType"); + if (!return_type_ptr_type) + return nullptr; + + if (log) + log->Printf("%s - return type pointer type for StructRet clone @ '0x%p':\n", + __FUNCTION__, (void *)return_type_ptr_type); + // put the the sret pointer argument in place at the beginning of the argument + // list. + params.emplace(params.begin(), return_type_ptr_type); + assert(params.size() == num_params + 1); + return llvm::FunctionType::get(return_type_ptr_type, params, + orig->isVarArg()); } -bool -findRSCallSites(llvm::Module &module, std::set<llvm::CallInst *> &rs_callsites, - bool (*predicate)(llvm::Module &, llvm::CallInst *)) -{ - bool found = false; - - for (auto &func : module.getFunctionList()) - for (auto &block : func.getBasicBlockList()) - for (auto &inst : block) - { - llvm::CallInst *call_inst = llvm::dyn_cast_or_null<llvm::CallInst>(&inst); - if (!call_inst || !call_inst->getCalledFunction()) - // This is not the call-site you are looking for... - continue; - if (isRSAPICall(module, call_inst) && predicate(module, call_inst)) - { - rs_callsites.insert(call_inst); - found = true; - } - } - return found; +bool findRSCallSites(llvm::Module &module, + std::set<llvm::CallInst *> &rs_callsites, + bool (*predicate)(llvm::Module &, llvm::CallInst *)) { + bool found = false; + + for (auto &func : module.getFunctionList()) + for (auto &block : func.getBasicBlockList()) + for (auto &inst : block) { + llvm::CallInst *call_inst = + llvm::dyn_cast_or_null<llvm::CallInst>(&inst); + if (!call_inst || !call_inst->getCalledFunction()) + // This is not the call-site you are looking for... + continue; + if (isRSAPICall(module, call_inst) && predicate(module, call_inst)) { + rs_callsites.insert(call_inst); + found = true; + } + } + return found; } -bool -fixupX86StructRetCalls(llvm::Module &module) -{ - bool changed = false; - // changing a basic block while iterating over it seems to have some undefined behaviour - // going on so we find all RS callsites first, then fix them up after consuming - // the iterator. - std::set<llvm::CallInst *> rs_callsites; - if (!findRSCallSites(module, rs_callsites, isRSLargeReturnCall)) - return false; - - for (auto call_inst : rs_callsites) - { - llvm::FunctionType *new_func_type = cloneToStructRetFnTy(call_inst); - assert(new_func_type && "failed to clone functionType for Renderscript ABI fixup"); - - llvm::CallSite call_site(call_inst); - llvm::Function *func = call_inst->getCalledFunction(); - assert(func && "cannot resolve function in RenderScriptRuntime"); - // Copy the original call arguments - std::vector<llvm::Value *> new_call_args(call_site.arg_begin(), call_site.arg_end()); - - // Allocate enough space to store the return value of the original function - // we pass a pointer to this allocation as the StructRet param, and then copy its - // value into the lldb return value - llvm::AllocaInst *return_value_alloc = - new llvm::AllocaInst(func->getReturnType(), "var_vector_return_alloc", call_inst); - // use the new allocation as the new first argument - new_call_args.emplace(new_call_args.begin(), llvm::cast<llvm::Value>(return_value_alloc)); - llvm::PointerType *new_func_ptr_type = llvm::PointerType::get(new_func_type, 0); - // Create the type cast from the old function type to the new one - llvm::Constant *new_func_cast = - llvm::ConstantExpr::getCast(llvm::Instruction::BitCast, func, new_func_ptr_type); - // create an allocation for a new function pointer - llvm::AllocaInst *new_func_ptr = new llvm::AllocaInst(new_func_ptr_type, "new_func_ptr", call_inst); - // store the new_func_cast to the newly allocated space - (void)new llvm::StoreInst(new_func_cast, new_func_ptr, "new_func_ptr_load_cast", call_inst); - // load the new function address ready for a jump - llvm::LoadInst *new_func_addr_load = new llvm::LoadInst(new_func_ptr, "load_func_pointer", call_inst); - // and create a callinstruction from it - llvm::CallInst *new_call_inst = - llvm::CallInst::Create(new_func_addr_load, new_call_args, "new_func_call", call_inst); - new_call_inst->setCallingConv(call_inst->getCallingConv()); - new_call_inst->setTailCall(call_inst->isTailCall()); - llvm::LoadInst *lldb_save_result_address = new llvm::LoadInst(return_value_alloc, "save_return_val", call_inst); - - // Now remove the old broken call - call_inst->replaceAllUsesWith(lldb_save_result_address); - call_inst->eraseFromParent(); - changed = true; - } - return changed; +bool fixupX86StructRetCalls(llvm::Module &module) { + bool changed = false; + // changing a basic block while iterating over it seems to have some undefined + // behaviour + // going on so we find all RS callsites first, then fix them up after + // consuming + // the iterator. + std::set<llvm::CallInst *> rs_callsites; + if (!findRSCallSites(module, rs_callsites, isRSLargeReturnCall)) + return false; + + for (auto call_inst : rs_callsites) { + llvm::FunctionType *new_func_type = cloneToStructRetFnTy(call_inst); + assert(new_func_type && + "failed to clone functionType for Renderscript ABI fixup"); + + llvm::CallSite call_site(call_inst); + llvm::Function *func = call_inst->getCalledFunction(); + assert(func && "cannot resolve function in RenderScriptRuntime"); + // Copy the original call arguments + std::vector<llvm::Value *> new_call_args(call_site.arg_begin(), + call_site.arg_end()); + + // Allocate enough space to store the return value of the original function + // we pass a pointer to this allocation as the StructRet param, and then + // copy its + // value into the lldb return value + llvm::AllocaInst *return_value_alloc = new llvm::AllocaInst( + func->getReturnType(), "var_vector_return_alloc", call_inst); + // use the new allocation as the new first argument + new_call_args.emplace(new_call_args.begin(), + llvm::cast<llvm::Value>(return_value_alloc)); + llvm::PointerType *new_func_ptr_type = + llvm::PointerType::get(new_func_type, 0); + // Create the type cast from the old function type to the new one + llvm::Constant *new_func_cast = llvm::ConstantExpr::getCast( + llvm::Instruction::BitCast, func, new_func_ptr_type); + // create an allocation for a new function pointer + llvm::AllocaInst *new_func_ptr = + new llvm::AllocaInst(new_func_ptr_type, "new_func_ptr", call_inst); + // store the new_func_cast to the newly allocated space + (void)new llvm::StoreInst(new_func_cast, new_func_ptr, + "new_func_ptr_load_cast", call_inst); + // load the new function address ready for a jump + llvm::LoadInst *new_func_addr_load = + new llvm::LoadInst(new_func_ptr, "load_func_pointer", call_inst); + // and create a callinstruction from it + llvm::CallInst *new_call_inst = llvm::CallInst::Create( + new_func_addr_load, new_call_args, "new_func_call", call_inst); + new_call_inst->setCallingConv(call_inst->getCallingConv()); + new_call_inst->setTailCall(call_inst->isTailCall()); + llvm::LoadInst *lldb_save_result_address = + new llvm::LoadInst(return_value_alloc, "save_return_val", call_inst); + + // Now remove the old broken call + call_inst->replaceAllUsesWith(lldb_save_result_address); + call_inst->eraseFromParent(); + changed = true; + } + return changed; } -bool -fixupRSAllocationStructByValCalls(llvm::Module &module) -{ - // On x86_64, calls to functions in the RS runtime that take an `rs_allocation` type argument - // are actually handled as by-ref params by bcc, but appear to be passed by value by lldb (the callsite all use - // `struct byval`). - // On x86_64 Linux, struct arguments are transferred in registers if the struct size is no bigger than - // 128bits [ref](http://www.agner.org/optimize/calling_conventions.pdf) section 7.1 "Passing and returning objects" - // otherwise passed on the stack. - // an object of type `rs_allocation` is actually 256bits, so should be passed on the stack. However, code generated - // by bcc actually treats formal params of type `rs_allocation` as `rs_allocation *` so we need to convert the - // calling convention to pass by reference, and remove any hint of byval from formal parameters. - bool changed = false; - std::set<llvm::CallInst *> rs_callsites; - if (!findRSCallSites(module, rs_callsites, isRSAllocationTyCallSite)) - return false; - - std::set<llvm::Function *> rs_functions; - - // for all call instructions - for (auto call_inst : rs_callsites) - { - // add the called function to a set so that we can strip its byval attributes in another pass - rs_functions.insert(call_inst->getCalledFunction()); - - // get the function attributes - llvm::AttributeSet call_attribs = call_inst->getAttributes(); - - // iterate over the argument attributes - for (size_t i = 1; i <= call_attribs.getNumSlots(); ++i) - { - // if this argument is passed by val - if (call_attribs.hasAttribute(i, llvm::Attribute::ByVal)) - { - // strip away the byval attribute - call_inst->removeAttribute(i, llvm::Attribute::get(module.getContext(), llvm::Attribute::ByVal)); - changed = true; - } - } - } +bool fixupRSAllocationStructByValCalls(llvm::Module &module) { + // On x86_64, calls to functions in the RS runtime that take an + // `rs_allocation` type argument + // are actually handled as by-ref params by bcc, but appear to be passed by + // value by lldb (the callsite all use + // `struct byval`). + // On x86_64 Linux, struct arguments are transferred in registers if the + // struct size is no bigger than + // 128bits [ref](http://www.agner.org/optimize/calling_conventions.pdf) + // section 7.1 "Passing and returning objects" + // otherwise passed on the stack. + // an object of type `rs_allocation` is actually 256bits, so should be passed + // on the stack. However, code generated + // by bcc actually treats formal params of type `rs_allocation` as + // `rs_allocation *` so we need to convert the + // calling convention to pass by reference, and remove any hint of byval from + // formal parameters. + bool changed = false; + std::set<llvm::CallInst *> rs_callsites; + if (!findRSCallSites(module, rs_callsites, isRSAllocationTyCallSite)) + return false; - llvm::AttributeSet attr_byval = llvm::AttributeSet::get(module.getContext(), 1u, llvm::Attribute::ByVal); - - // for all called function decls - for (auto func : rs_functions) - { - // inspect all of the arguments in the call - llvm::SymbolTableList<llvm::Argument> &argList = func->getArgumentList(); - for (auto &arg : argList) - { - if (arg.hasByValAttr()) - { - arg.removeAttr(attr_byval); - changed = true; - } - } + std::set<llvm::Function *> rs_functions; + + // for all call instructions + for (auto call_inst : rs_callsites) { + // add the called function to a set so that we can strip its byval + // attributes in another pass + rs_functions.insert(call_inst->getCalledFunction()); + + // get the function attributes + llvm::AttributeSet call_attribs = call_inst->getAttributes(); + + // iterate over the argument attributes + for (size_t i = 1; i <= call_attribs.getNumSlots(); ++i) { + // if this argument is passed by val + if (call_attribs.hasAttribute(i, llvm::Attribute::ByVal)) { + // strip away the byval attribute + call_inst->removeAttribute( + i, + llvm::Attribute::get(module.getContext(), llvm::Attribute::ByVal)); + changed = true; + } + } + } + + llvm::AttributeSet attr_byval = + llvm::AttributeSet::get(module.getContext(), 1u, llvm::Attribute::ByVal); + + // for all called function decls + for (auto func : rs_functions) { + // inspect all of the arguments in the call + llvm::SymbolTableList<llvm::Argument> &argList = func->getArgumentList(); + for (auto &arg : argList) { + if (arg.hasByValAttr()) { + arg.removeAttr(attr_byval); + changed = true; + } } - return changed; + } + return changed; } } // end anonymous namespace -namespace lldb_private -{ -namespace lldb_renderscript -{ +namespace lldb_private { +namespace lldb_renderscript { -bool -fixupX86FunctionCalls(llvm::Module &module) -{ - return fixupX86StructRetCalls(module); +bool fixupX86FunctionCalls(llvm::Module &module) { + return fixupX86StructRetCalls(module); } -bool -fixupX86_64FunctionCalls(llvm::Module &module) -{ - bool changed = false; - changed |= fixupX86StructRetCalls(module); - changed |= fixupRSAllocationStructByValCalls(module); - return changed; +bool fixupX86_64FunctionCalls(llvm::Module &module) { + bool changed = false; + changed |= fixupX86StructRetCalls(module); + changed |= fixupRSAllocationStructByValCalls(module); + return changed; } } // end namespace lldb_renderscript diff --git a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h index d6cf965ace8..9fd10260668 100644 --- a/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h +++ b/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptx86ABIFixups.h @@ -12,16 +12,12 @@ #include "llvm/IR/Module.h" -namespace lldb_private -{ -namespace lldb_renderscript -{ +namespace lldb_private { +namespace lldb_renderscript { -bool -fixupX86FunctionCalls(llvm::Module &module); +bool fixupX86FunctionCalls(llvm::Module &module); -bool -fixupX86_64FunctionCalls(llvm::Module &module); +bool fixupX86_64FunctionCalls(llvm::Module &module); } } #endif |