diff options
author | Enrico Granata <granata.enrico@gmail.com> | 2011-08-03 02:18:51 +0000 |
---|---|---|
committer | Enrico Granata <granata.enrico@gmail.com> | 2011-08-03 02:18:51 +0000 |
commit | 9910bc855d55b4958182321cfc81140346aa2e9f (patch) | |
tree | b1580154477ba572aee2e9b1ed49954c408c9ffb | |
parent | 59546b8f79bd020362c4478628111c0beb0b1dc0 (diff) | |
download | bcm5719-llvm-9910bc855d55b4958182321cfc81140346aa2e9f.tar.gz bcm5719-llvm-9910bc855d55b4958182321cfc81140346aa2e9f.zip |
Fixed an issue where the KVO swizzled type would be returned as the dynamic type instead of the actual user-level type
- see the test case in lang/objc/objc-dynamic-value for an example
Objective-C dynamic type lookup now works for every Objective-C type
- previously, true dynamic lookup was only performed for type id
llvm-svn: 136763
6 files changed, 72 insertions, 14 deletions
diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 14bd709fa98..23300464001 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -360,12 +360,13 @@ private: if (log) log->Printf("appended bitfield info, final result is %s", name.GetCString()); } + const char* typeName = name.GetCString(); if (log) log->Printf("trying to get %s for VO name %s of type %s", m_name.c_str(), vobj.GetName().AsCString(), - name.AsCString()); - if (Get(name.GetCString(), entry)) + typeName); + if (Get(typeName, entry)) { if (log) log->Printf("direct match found, returning"); @@ -385,7 +386,8 @@ private: } } if (use_dynamic != lldb::eNoDynamicValues && - typePtr == vobj.GetClangAST()->ObjCBuiltinIdTy.getTypePtr()) + (/*strstr(typeName, "id") == typeName ||*/ + ClangASTType::GetMinimumLanguage(vobj.GetClangAST(), vobj.GetClangType()) == lldb::eLanguageTypeObjC)) { if (log) log->Printf("this is an ObjC 'id', let's do dynamic search"); diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index b742d0b0da1..c9310753d96 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -93,7 +93,7 @@ ValueObject::ValueObject (ValueObject &parent) : m_is_bitfield_for_scalar(false), m_is_expression_path_child(false), m_is_child_at_offset(false), - m_is_expression_result(false), + m_is_expression_result(parent.m_is_expression_result), m_dump_printable_counter(0) { m_manager->ManageObject(this); @@ -240,7 +240,7 @@ ValueObject::UpdateFormatsIfNeeded(lldb::DynamicValueType use_dynamic) m_synthetic_value = NULL; - Debugger::Formatting::ValueFormats::Get(*this, use_dynamic, m_last_value_format); + Debugger::Formatting::ValueFormats::Get(*this, lldb::eNoDynamicValues, m_last_value_format); Debugger::Formatting::GetSummaryFormat(*this, use_dynamic, m_last_summary_format); Debugger::Formatting::GetSyntheticFilter(*this, use_dynamic, m_last_synthetic_filter); @@ -2599,23 +2599,26 @@ ValueObject::DumpValueObject // Always show the type for the top level items. if (show_types || (curr_depth == 0 && !flat_output)) { - s.Printf("(%s", valobj->GetTypeName().AsCString("<invalid type>")); - if (use_dynamic != lldb::eNoDynamicValues && - strcmp(valobj->GetTypeName().AsCString("NULL"), "id") == 0) + const char* typeName = valobj->GetTypeName().AsCString("<invalid type>"); + s.Printf("(%s", typeName); + // only show dynamic types if the user really wants to see types + if (show_types && use_dynamic != lldb::eNoDynamicValues && + (/*strstr(typeName, "id") == typeName ||*/ + ClangASTType::GetMinimumLanguage(valobj->GetClangAST(), valobj->GetClangType()) == lldb::eLanguageTypeObjC)) { Process* process = valobj->GetUpdatePoint().GetProcessSP().get(); if (process == NULL) - s.Printf(") "); + s.Printf(", dynamic type: unknown) "); else { ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime(); if (runtime == NULL) - s.Printf(") "); + s.Printf(", dynamic type: unknown) "); else { ObjCLanguageRuntime::ObjCISA isa = runtime->GetISA(*valobj); if (!runtime->IsValidISA(isa)) - s.Printf(") "); + s.Printf(", dynamic type: unknown) "); else s.Printf(", dynamic type: %s) ", runtime->GetActualTypeName(isa).GetCString()); diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index f48bebd7d7e..3dd360d9876 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -160,7 +160,7 @@ ValueObjectDynamicValue::UpdateValue () { LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC); if (objc_runtime) - found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); + found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); } } diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 753d1e29055..10422386ff4 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -26,6 +26,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" +#include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Expression/ClangFunction.h" #include "lldb/Expression/ClangUtilityFunction.h" #include "lldb/Symbol/ClangASTContext.h" @@ -566,9 +567,35 @@ AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const c lldb_private::ObjCLanguageRuntime::ObjCISA AppleObjCRuntimeV2::GetISA(ValueObject& valobj) { + + if (valobj.GetIsExpressionResult() && + valobj.GetValue().GetValueType() == Value::eValueTypeHostAddress) + { + // when using the expression parser, an additional layer of "frozen data" + // can be created, which is basically a byte-exact copy of the data returned + // by the expression, but in host memory. because Python code might need to read + // into the object memory in non-obvious ways, we need to hand it the target version + // of the expression output + lldb::addr_t tgt_address = valobj.GetValueAsUnsigned(); + ValueObjectSP target_object = ValueObjectConstResult::Create (valobj.GetExecutionContextScope(), + valobj.GetClangAST(), + valobj.GetClangType(), + valobj.GetName(), + tgt_address, + eAddressTypeLoad, + valobj.GetUpdatePoint().GetProcessSP()->GetAddressByteSize()); + return GetISA(*target_object); + } + if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != lldb::eLanguageTypeObjC) return 0; + // 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.GetValue().GetContextType() == Value::eContextTypeInvalid) + return 0; + uint32_t offset = 0; uint64_t isa_pointer = valobj.GetDataExtractor().GetPointer(&offset); @@ -583,6 +610,8 @@ AppleObjCRuntimeV2::GetISA(ValueObject& valobj) return isa; } +// 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(lldb_private::ObjCLanguageRuntime::ObjCISA isa) { @@ -625,7 +654,20 @@ AppleObjCRuntimeV2::GetActualTypeName(lldb_private::ObjCLanguageRuntime::ObjCISA //printf("name_pointer: %llx\n", name_pointer); char* cstr = new char[512]; if (m_process->ReadCStringFromMemory(name_pointer, cstr, 512) > 0) - return ConstString(cstr); + { + if (::strstr(cstr, "NSKVONotify") == cstr) + { + // the ObjC runtime implements KVO by replacing the isa with a special + // NSKVONotifying_className that overrides the relevant methods + // the side effect on us is that getting the typename for a KVO-ed object + // will return the swizzled class instead of the actual one + // this swizzled class is a descendant of the real class, so just + // return the parent type and all should be fine + return GetActualTypeName(GetParentClass(isa)); + } + else + return ConstString(cstr); + } else return ConstString("unknown"); } diff --git a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py index 31a64a439e8..70994d41a2a 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjC.py @@ -226,9 +226,12 @@ class DataFormatterTestCase(TestBase): substrs = ['Process Name: a.out Process Id:']) self.expect('frame variable dyn_test', matching=False, substrs = ['Process Name: a.out Process Id:']) - self.expect('frame variable dyn_test -d run-target', + self.expect('frame variable dyn_test -d run-target -T', substrs = ['(id, dynamic type:', 'Process Name: a.out Process Id:']) + self.expect('frame variable dyn_test -d run-target', + substrs = ['(id)', + 'Process Name: a.out Process Id:']) # check that we can format stuff out of the expression parser diff --git a/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py b/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py index 1a5547bccce..bffe060274a 100644 --- a/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py +++ b/lldb/test/lang/objc/objc-dynamic-value/TestObjCDynamicValue.py @@ -93,6 +93,14 @@ class ObjCDynamicValueTestCase(TestBase): self.expect('frame var -d run-target myObserver->_source', 'frame var finds its way into a child member', patterns = ['\(SourceDerived \*\)']) + + # check that our ObjC GetISA() does a good job at hiding KVO swizzled classes + + self.expect('frame var -d run-target myObserver->_source -T', 'the KVO-ed class is hidden', + substrs = ['dynamic type: SourceDerived']) + + self.expect('frame var -d run-target myObserver->_source -T', 'the KVO-ed class is hidden', matching = False, + substrs = ['dynamic type: NSKVONotify']) # This test is not entirely related to the main thrust of this test case, but since we're here, # try stepping into setProperty, and make sure we get into the version in Source: |