[Lldb-commits] [lldb] r143419 - in /lldb/trunk: include/lldb/Expression/ include/lldb/Target/ source/Expression/ source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/ source/Plugins/Process/Utility/ source/Target/ test/lang/objc/objc-checker/

Jim Ingham jingham at apple.com
Mon Oct 31 19:46:54 PDT 2011


Author: jingham
Date: Mon Oct 31 21:46:54 2011
New Revision: 143419

URL: http://llvm.org/viewvc/llvm-project?rev=143419&view=rev
Log:
Enhanced the ObjC DynamicCheckerFunction to test for "object responds to selector" as well as
"object borked"...  Also made the error when the checker fails reflect this fact rather than
report a crash at 0x0.

Also a little cleanup:
- StopInfoMachException had a redundant copy of the description string.
- ThreadPlanCallFunction had a redundant copy of the thread, and had a 
copy of the process that it didn't really need.

Added:
    lldb/trunk/test/lang/objc/objc-checker/
    lldb/trunk/test/lang/objc/objc-checker/Makefile
    lldb/trunk/test/lang/objc/objc-checker/TestObjCCheckers.py
    lldb/trunk/test/lang/objc/objc-checker/main.m
Modified:
    lldb/trunk/include/lldb/Expression/IRDynamicChecks.h
    lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
    lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h
    lldb/trunk/source/Expression/IRDynamicChecks.cpp
    lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
    lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.h
    lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
    lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp

Modified: lldb/trunk/include/lldb/Expression/IRDynamicChecks.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/IRDynamicChecks.h?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/IRDynamicChecks.h (original)
+++ lldb/trunk/include/lldb/Expression/IRDynamicChecks.h Mon Oct 31 21:46:54 2011
@@ -10,6 +10,7 @@
 #ifndef liblldb_IRDynamicChecks_h_
 #define liblldb_IRDynamicChecks_h_
 
+#include "lldb-types.h"
 #include "llvm/Pass.h"
 
 namespace llvm {
@@ -74,6 +75,8 @@
     bool Install (Stream &error_stream,
                   ExecutionContext &exe_ctx);
     
+    bool DoCheckersExplainStop (lldb::addr_t addr, Stream &message);
+    
     std::auto_ptr<ClangUtilityFunction> m_valid_pointer_check;
     std::auto_ptr<ClangUtilityFunction> m_objc_object_check;
 };

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallFunction.h Mon Oct 31 21:46:54 2011
@@ -127,6 +127,12 @@
     {
         return m_real_stop_info_sp;
     }
+    
+    lldb::addr_t
+    GetStopAddress ()
+    {
+        return m_stop_address;
+    }
 
 protected:
     void ReportRegisterState (const char *message);
@@ -148,8 +154,8 @@
     Address                                         m_function_addr;
     Address                                         m_start_addr;
     lldb::addr_t                                    m_function_sp;
-    Process                                        &m_process;
-    Thread                                         &m_thread;
+//    Process                                        &m_process;
+//    Thread                                         &m_thread;
     Thread::RegisterCheckpoint                      m_register_backup;
     lldb::ThreadPlanSP                              m_subplan_sp;
     LanguageRuntime                                *m_cxx_language_runtime;
@@ -161,6 +167,7 @@
                                                                          // This gets set in DoTakedown.
     lldb::ValueSP                                   m_return_value_sp;  // If this contains a valid pointer, use the ABI to extract values when complete
     bool                                            m_takedown_done;    // We want to ensure we only do the takedown once.  This ensures that.
+    lldb::addr_t                                    m_stop_address;     // This is the address we stopped at.  Also set in DoTakedown;
 
     DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
 };

Modified: lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h (original)
+++ lldb/trunk/include/lldb/Target/ThreadPlanCallUserExpression.h Mon Oct 31 21:46:54 2011
@@ -48,6 +48,9 @@
             m_user_expression_sp.reset();
     }
 
+    virtual lldb::StopInfoSP
+    GetRealStopInfo();
+    
 protected:
 private:
     ClangUserExpression::ClangUserExpressionSP m_user_expression_sp;    // This is currently just used to ensure the

Modified: lldb/trunk/source/Expression/IRDynamicChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRDynamicChecks.cpp?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/source/Expression/IRDynamicChecks.cpp (original)
+++ lldb/trunk/source/Expression/IRDynamicChecks.cpp Mon Oct 31 21:46:54 2011
@@ -74,6 +74,25 @@
     return true;
 }
 
+bool
+DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &message)
+{
+    // FIXME: We have to get the checkers to know why they scotched the call in more detail,
+    // so we can print a better message here.
+    if (m_valid_pointer_check.get() != NULL && m_valid_pointer_check->ContainsAddress(addr))
+    {
+        message.Printf ("Attempted to dereference an invalid pointer.");
+        return true;
+    }
+    else if (m_objc_object_check.get() != NULL && m_objc_object_check->ContainsAddress(addr))
+    {
+        message.Printf ("Attempted to dereference an invalid ObjC Object or send it an unrecognized selector");
+        return true;
+    }
+    return false;
+}
+
+
 static std::string 
 PrintValue(llvm::Value *V, bool truncate = false)
 {

Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original)
+++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Mon Oct 31 21:46:54 2011
@@ -99,7 +99,7 @@
     m_isa_to_name_cache(),
     m_isa_to_parent_cache()
 {
-    m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(ConstString("gdb_object_getClass")) != NULL);
+    m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(ConstString("gdb_object_getClass"), eSymbolTypeCode) != NULL);
 }
 
 bool
@@ -492,38 +492,56 @@
 ClangUtilityFunction *
 AppleObjCRuntimeV2::CreateObjectChecker(const char *name)
 {
-    char check_function_code[1024];
+    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\" 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"
-                          "}                                                        \n",
+                          "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\" 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"
-                          "}                                                        \n", 
+                          "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);
     }
     

Modified: lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.h?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.h (original)
+++ lldb/trunk/source/Plugins/Process/Utility/StopInfoMachException.h Mon Oct 31 21:46:54 2011
@@ -67,7 +67,6 @@
     uint32_t m_exc_data_count;
     uint64_t m_exc_code;
     uint64_t m_exc_subcode;
-    std::string m_description;
 };
 
 

Modified: lldb/trunk/source/Target/ThreadPlanCallFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallFunction.cpp?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallFunction.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallFunction.cpp Mon Oct 31 21:46:54 2011
@@ -47,9 +47,8 @@
     m_stop_other_threads (stop_other_threads),
     m_function_addr (function),
     m_function_sp (NULL),
-    m_process (thread.GetProcess()),
-    m_thread (thread),
-    m_takedown_done (false)
+    m_takedown_done (false),
+    m_stop_address (LLDB_INVALID_ADDRESS)
 {
     SetOkayToDiscard (discard_on_error);
 
@@ -163,8 +162,6 @@
     m_stop_other_threads (stop_other_threads),
     m_function_addr (function),
     m_function_sp(NULL),
-    m_process (thread.GetProcess()),
-    m_thread (thread),
     m_takedown_done (false)
 {
     SetOkayToDiscard (discard_on_error);
@@ -294,6 +291,7 @@
         if (log)
             log->Printf ("DoTakedown called for thread 0x%4.4llx, m_valid: %d complete: %d.\n", m_thread.GetID(), m_valid, IsPlanComplete());
         m_takedown_done = true;
+        m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
         m_real_stop_info_sp = GetPrivateStopReason();
         m_thread.RestoreThreadStateFromCheckpoint(m_stored_thread_state);
         SetPlanComplete();
@@ -324,7 +322,7 @@
     }
     else
     {
-        s->Printf("Thread plan to call 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()));
+        s->Printf("Thread plan to call 0x%llx", m_function_addr.GetLoadAddress(&m_thread.GetProcess().GetTarget()));
     }
 }
 
@@ -474,8 +472,8 @@
 void
 ThreadPlanCallFunction::SetBreakpoints ()
 {
-    m_cxx_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus);
-    m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC);
+    m_cxx_language_runtime = m_thread.GetProcess().GetLanguageRuntime(eLanguageTypeC_plus_plus);
+    m_objc_language_runtime = m_thread.GetProcess().GetLanguageRuntime(eLanguageTypeObjC);
     
     if (m_cxx_language_runtime)
         m_cxx_language_runtime->SetExceptionBreakpoints();

Modified: lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp?rev=143419&r1=143418&r2=143419&view=diff
==============================================================================
--- lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp (original)
+++ lldb/trunk/source/Target/ThreadPlanCallUserExpression.cpp Mon Oct 31 21:46:54 2011
@@ -55,6 +55,20 @@
 
 void
 ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level)
-{
+{        
     ThreadPlanCallFunction::GetDescription (s, level);
 }
+
+StopInfoSP
+ThreadPlanCallUserExpression::GetRealStopInfo()
+{
+    StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo();
+    lldb::addr_t addr = GetStopAddress();
+    DynamicCheckerFunctions *checkers = m_thread.GetProcess().GetDynamicCheckers();
+    StreamString s;
+    
+    if (checkers && checkers->DoCheckersExplainStop(addr, s))
+        stop_info_sp->SetDescription(s.GetData());
+
+    return stop_info_sp;
+}

Added: lldb/trunk/test/lang/objc/objc-checker/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/objc-checker/Makefile?rev=143419&view=auto
==============================================================================
--- lldb/trunk/test/lang/objc/objc-checker/Makefile (added)
+++ lldb/trunk/test/lang/objc/objc-checker/Makefile Mon Oct 31 21:46:54 2011
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+OBJC_SOURCES := main.m
+LDFLAGS = $(CFLAGS) -lobjc -framework Foundation
+
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/lang/objc/objc-checker/TestObjCCheckers.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/objc-checker/TestObjCCheckers.py?rev=143419&view=auto
==============================================================================
--- lldb/trunk/test/lang/objc/objc-checker/TestObjCCheckers.py (added)
+++ lldb/trunk/test/lang/objc/objc-checker/TestObjCCheckers.py Mon Oct 31 21:46:54 2011
@@ -0,0 +1,85 @@
+"""
+Use lldb Python API to make sure the dynamic checkers are doing their jobs.
+"""
+
+import os, time
+import re
+import unittest2
+import lldb, lldbutil
+from lldbtest import *
+
+class ObjCDynamicValueTestCase(TestBase):
+
+    mydir = os.path.join("lang", "objc", "objc-checker")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @python_api_test
+    def test_get_dynamic_objc_vals_with_dsym(self):
+        """Test that checkers catch unrecognized selectors"""
+        self.buildDsym()
+        self.do_test_checkers()
+
+    @python_api_test
+    def test_get_objc_dynamic_vals_with_dwarf(self):
+        """Test that checkers catch unrecognized selectors"""
+        self.buildDwarf()
+        self.do_test_checkers()
+
+    def setUp(self):
+        # Call super's setUp().                                                                                                           
+        TestBase.setUp(self)
+
+        # Find the line number to break for main.c.                                                                                       
+
+        self.source_name = 'main.m'
+
+    def do_test_checkers (self):
+        """Make sure the dynamic checkers catch messages to unrecognized selectors"""
+        exe = os.path.join(os.getcwd(), "a.out")
+
+        # Create a target from the debugger.
+
+        target = self.dbg.CreateTarget (exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Set up our breakpoints:
+
+        
+        main_bkpt = target.BreakpointCreateBySourceRegex ("Set a breakpoint here.", lldb.SBFileSpec (self.source_name))
+        self.assertTrue(main_bkpt and
+                        main_bkpt.GetNumLocations() == 1,
+                        VALID_BREAKPOINT)
+
+        # Now launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple (None, None, os.getcwd())
+
+        self.assertTrue(process.GetState() == lldb.eStateStopped,
+                        PROCESS_STOPPED)
+
+        threads = lldbutil.get_threads_stopped_at_breakpoint (process, main_bkpt)
+        self.assertTrue (len(threads) == 1)
+        thread = threads[0]
+
+        #
+        #  The class Simple doesn't have a count method.  Make sure that we don't 
+        #  actually try to send count but catch it as an unrecognized selector.
+
+        frame = thread.GetFrameAtIndex(0)
+        expr_value = frame.EvaluateExpression("(int) [my_simple count]", False)
+        expr_error = expr_value.GetError()
+
+        self.assertTrue (expr_error.Fail())
+        
+        # Make sure the call produced no NSLog stdout.
+        stdout = process.GetSTDOUT(100)
+        self.assertTrue (len(stdout) == 0)
+        
+        # Make sure the error is helpful:
+        err_string = expr_error.GetCString()
+        self.assertTrue ("selector" in err_string)
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/lang/objc/objc-checker/main.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/lang/objc/objc-checker/main.m?rev=143419&view=auto
==============================================================================
--- lldb/trunk/test/lang/objc/objc-checker/main.m (added)
+++ lldb/trunk/test/lang/objc/objc-checker/main.m Mon Oct 31 21:46:54 2011
@@ -0,0 +1,30 @@
+#import <Foundation/Foundation.h>
+
+ at interface Simple : NSObject
+{
+  int _value;
+}
+- (int) value;
+- (void) setValue: (int) newValue;
+ at end
+
+ at implementation Simple
+- (int) value
+{
+  return _value;
+}
+
+- (void) setValue: (int) newValue
+{
+  _value = newValue;
+}
+ at end
+
+int main ()
+{
+  Simple *my_simple = [[Simple alloc] init];
+  my_simple.value = 20;
+  // Set a breakpoint here.
+  NSLog (@"Object has value: %d.", my_simple.value); 
+  return 0;
+}





More information about the lldb-commits mailing list