diff --git a/lldb/examples/summaries/cocoa/NSDate.py b/lldb/examples/summaries/cocoa/NSDate.py index ae1ff6b432b2..4dd63b4a5c32 100644 --- a/lldb/examples/summaries/cocoa/NSDate.py +++ b/lldb/examples/summaries/cocoa/NSDate.py @@ -5,7 +5,8 @@ part of The LLVM Compiler Infrastructure This file is distributed under the University of Illinois Open Source License. See LICENSE.TXT for details. """ -# summary provider for NSDate +# example summary provider for NSDate +# the real summary is now C++ code built into LLDB import lldb import ctypes import lldb.runtime.objc.objc_runtime diff --git a/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h b/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h index 61757891189a..1b3360e91611 100644 --- a/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h +++ b/lldb/include/lldb/DataFormatters/CXXFormatterFunctions.h @@ -115,6 +115,12 @@ namespace lldb_private { bool CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream); + bool + NSDateSummaryProvider (ValueObject& valobj, Stream& stream); + + bool + CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream); + bool NSBundleSummaryProvider (ValueObject& valobj, Stream& stream); diff --git a/lldb/scripts/Python/finish-swig-Python-LLDB.sh b/lldb/scripts/Python/finish-swig-Python-LLDB.sh index d0f3c251a222..e87d44a9f502 100755 --- a/lldb/scripts/Python/finish-swig-Python-LLDB.sh +++ b/lldb/scripts/Python/finish-swig-Python-LLDB.sh @@ -223,38 +223,11 @@ package_files="${SRC_ROOT}/examples/synthetic/gnu_libstdcpp.py ${SRC_ROOT}/examples/synthetic/libcxx.py" create_python_package "/formatters/cpp" "${package_files}" -# lldb/formatters/objc -package_files="${SRC_ROOT}/examples/summaries/cocoa/Selector.py -${SRC_ROOT}/examples/summaries/objc.py -${SRC_ROOT}/examples/summaries/cocoa/Class.py -${SRC_ROOT}/examples/summaries/cocoa/CFArray.py -${SRC_ROOT}/examples/summaries/cocoa/CFBag.py -${SRC_ROOT}/examples/summaries/cocoa/CFBinaryHeap.py -${SRC_ROOT}/examples/summaries/cocoa/CFBitVector.py -${SRC_ROOT}/examples/summaries/cocoa/CFDictionary.py -${SRC_ROOT}/examples/summaries/cocoa/CFString.py -${SRC_ROOT}/examples/summaries/cocoa/NSBundle.py -${SRC_ROOT}/examples/summaries/cocoa/NSData.py -${SRC_ROOT}/examples/summaries/cocoa/NSDate.py -${SRC_ROOT}/examples/summaries/cocoa/NSException.py -${SRC_ROOT}/examples/summaries/cocoa/NSIndexSet.py -${SRC_ROOT}/examples/summaries/cocoa/NSMachPort.py -${SRC_ROOT}/examples/summaries/cocoa/NSNotification.py -${SRC_ROOT}/examples/summaries/cocoa/NSNumber.py -${SRC_ROOT}/examples/summaries/cocoa/NSSet.py -${SRC_ROOT}/examples/summaries/cocoa/NSURL.py" -create_python_package "/formatters/objc" "${package_files}" - - # make an empty __init__.py in lldb/runtime # this is required for Python to recognize lldb.runtime as a valid package # (and hence, lldb.runtime.objc as a valid contained package) create_python_package "/runtime" "" -# lldb/runtime/objc -package_files="${SRC_ROOT}/examples/summaries/cocoa/objc_runtime.py" -create_python_package "/runtime/objc" "${package_files}" - # lldb/formatters # having these files copied here ensures that lldb/formatters is a valid package itself package_files="${SRC_ROOT}/examples/summaries/cocoa/cache.py diff --git a/lldb/source/DataFormatters/CXXFormatterFunctions.cpp b/lldb/source/DataFormatters/CXXFormatterFunctions.cpp index c0c9dcbb4a62..2df6524c365e 100644 --- a/lldb/source/DataFormatters/CXXFormatterFunctions.cpp +++ b/lldb/source/DataFormatters/CXXFormatterFunctions.cpp @@ -9,6 +9,8 @@ #include "lldb/lldb-python.h" +#include + #include "lldb/DataFormatters/CXXFormatterFunctions.h" #include "llvm/Support/ConvertUTF.h" @@ -1618,6 +1620,131 @@ lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& s return true; } +// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001 +// this call gives the POSIX equivalent of the Cocoa epoch +time_t +GetOSXEpoch () +{ + static time_t epoch = 0; + if (!epoch) + { + tzset(); + tm tm_epoch; + tm_epoch.tm_sec = 0; + tm_epoch.tm_hour = 0; + tm_epoch.tm_min = 0; + tm_epoch.tm_mon = 0; + tm_epoch.tm_mday = 1; + tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why. + tm_epoch.tm_isdst = -1; + tm_epoch.tm_gmtoff = 0; + tm_epoch.tm_zone = NULL; + epoch = timegm(&tm_epoch); + } + return epoch; +} + +bool +lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream) +{ + ProcessSP process_sp = valobj.GetProcessSP(); + if (!process_sp) + return false; + + ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); + + if (!runtime) + return false; + + ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); + + if (!descriptor.get() || !descriptor->IsValid()) + return false; + + uint32_t ptr_size = process_sp->GetAddressByteSize(); + + lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); + + if (!valobj_addr) + return false; + + uint64_t date_value_bits = 0; + double date_value = 0.0; + + const char* class_name = descriptor->GetClassName().GetCString(); + + if (!class_name || !*class_name) + return false; + + if (strcmp(class_name,"NSDate") == 0 || + strcmp(class_name,"__NSDate") == 0 || + strcmp(class_name,"__NSTaggedDate") == 0) + { + if (descriptor->IsTagged()) + { + uint64_t info_bits = (valobj_addr & 0xF0ULL) >> 4; + uint64_t value_bits = (valobj_addr & ~0x0000000000000000FFULL) >> 8; + date_value_bits = ((value_bits << 8) | (info_bits << 4)); + date_value = *((double*)&date_value_bits); + } + else + { + Error error; + date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error); + date_value = *((double*)&date_value_bits); + if (error.Fail()) + return false; + } + } + else if (!strcmp(class_name,"NSCalendarDate")) + { + Error error; + date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); + date_value = *((double*)&date_value_bits); + if (error.Fail()) + return false; + } + else + { + if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false) + return false; + date_value = *((double*)&date_value_bits); + } + if (date_value == -63114076800) + { + stream.Printf("0001-12-30 00:00:00 +0000"); + return true; + } + // this snippet of code assumes that time_t == seconds since Jan-1-1970 + // this is generally true and POSIXly happy, but might break if a library + // vendor decides to get creative + time_t epoch = GetOSXEpoch(); + epoch = epoch + (time_t)date_value; + tm *tm_date = localtime(&epoch); + if (!tm_date) + return false; + std::string buffer(1024,0); + if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) + return false; + stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); + return true; +} + +bool +lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream) +{ + time_t epoch = GetOSXEpoch(); + epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0); + tm *tm_date = localtime(&epoch); + if (!tm_date) + return false; + std::string buffer(1024,0); + if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) + return false; + stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); + return true; +} + size_t lldb_private::formatters::ExtractIndexFromString (const char* item_name) { diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index f10d16e714b9..e4937ceebcf5 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -974,10 +974,10 @@ FormatManager::LoadObjCFormatters() AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", ConstString("NSURL"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", ConstString("CFURLRef"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSDate.NSDate_SummaryProvider", ConstString("NSDate"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSDate.NSDate_SummaryProvider", ConstString("__NSDate"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSDate.NSDate_SummaryProvider", ConstString("__NSTaggedDate"), appkit_flags); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSDate.NSDate_SummaryProvider", ConstString("NSCalendarDate"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("NSDate"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("__NSDate"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("__NSTaggedDate"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("NSCalendarDate"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("NSTimeZone"), appkit_flags); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("CFTimeZoneRef"), appkit_flags); @@ -986,7 +986,7 @@ FormatManager::LoadObjCFormatters() // CFAbsoluteTime is actually a double rather than a pointer to an object // we do not care about the numeric value, since it is probably meaningless to users appkit_flags.SetDontShowValue(true); - AddScriptSummary(appkit_category_sp, "lldb.formatters.objc.NSDate.CFAbsoluteTime_SummaryProvider", ConstString("CFAbsoluteTime"), appkit_flags); + AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFAbsoluteTimeSummaryProvider, "CFAbsoluteTime summary provider", ConstString("CFAbsoluteTime"), appkit_flags); appkit_flags.SetDontShowValue(false); AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", ConstString("NSIndexSet"), appkit_flags); diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 0b0aec1ae682..5a97107ac101 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -489,7 +489,7 @@ ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interprete // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set // and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task run_string.Clear(); - run_string.Printf ("run_one_line (%s, 'import lldb.runtime.objc, lldb.formatters, lldb.formatters.objc, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str()); + run_string.Printf ("run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str()); PyRun_SimpleString (run_string.GetData()); int new_count = Debugger::TestDebuggerRefCount(); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index ae1eca83d608..f116bc79ec1c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1433,16 +1433,16 @@ public: m_class_bits = (value & 0xE) >> 1; lldb::TargetSP target_sp = isa_pointer.GetTargetSP(); - LazyBool is_lion = IsLion(target_sp); + uint32_t foundation_version = GetFoundationVersion(target_sp); // TODO: check for OSX version - for now assume Mtn Lion - if (is_lion == eLazyBoolCalculate) + if (foundation_version == UINT32_MAX) { // if we can't determine the matching table (e.g. we have no Foundation), // assume this is not a valid tagged pointer m_valid = false; } - else if (is_lion == eLazyBoolNo) + else if (foundation_version >= 900) { switch (m_class_bits) { @@ -1571,13 +1571,14 @@ public: {} protected: - // TODO make this into a smarter OS version detector - LazyBool - IsLion (lldb::TargetSP &target_sp) + // we use the version of Foundation to make assumptions about the ObjC runtime on a target + uint32_t + GetFoundationVersion (lldb::TargetSP &target_sp) { if (!target_sp) return eLazyBoolCalculate; const ModuleList& modules = target_sp->GetImages(); + uint32_t major = UINT32_MAX; for (uint32_t idx = 0; idx < modules.GetSize(); idx++) { lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); @@ -1585,15 +1586,11 @@ protected: continue; if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0) { - uint32_t major = UINT32_MAX; module_sp->GetVersion(&major,1); - if (major == UINT32_MAX) - return eLazyBoolCalculate; - - return (major > 900 ? eLazyBoolNo : eLazyBoolYes); + break; } } - return eLazyBoolCalculate; + return major; } private: