[Lldb-commits] [lldb] r127457 - in /lldb/trunk: include/lldb/Symbol/SymbolContext.h include/lldb/Target/Target.h include/lldb/lldb-enumerations.h include/lldb/lldb-forward-rtti.h include/lldb/lldb-forward.h source/Commands/CommandObjectTarget.cpp source/Symbol/SymbolContext.cpp source/Target/Process.cpp source/Target/Target.cpp

Jim Ingham jingham at apple.com
Thu Mar 10 19:53:59 PST 2011


Author: jingham
Date: Thu Mar 10 21:53:59 2011
New Revision: 127457

URL: http://llvm.org/viewvc/llvm-project?rev=127457&view=rev
Log:
Add a first pass at a "stop hook" mechanism.  This allows you to add commands that get run every time the debugger stops, whether due to a breakpoint, the end of a step, interrupt, etc.  You can also specify in which context you want the stop hook to run, for instance only on a particular thread, or only in a particular shared library, function, file, line range within a file.

Still need to add "in methods of a class" to the specifiers, and the ability to write the stop hooks in the Scripting language as well as in the Command Language.

Modified:
    lldb/trunk/include/lldb/Symbol/SymbolContext.h
    lldb/trunk/include/lldb/Target/Target.h
    lldb/trunk/include/lldb/lldb-enumerations.h
    lldb/trunk/include/lldb/lldb-forward-rtti.h
    lldb/trunk/include/lldb/lldb-forward.h
    lldb/trunk/source/Commands/CommandObjectTarget.cpp
    lldb/trunk/source/Symbol/SymbolContext.cpp
    lldb/trunk/source/Target/Process.cpp
    lldb/trunk/source/Target/Target.cpp

Modified: lldb/trunk/include/lldb/Symbol/SymbolContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/SymbolContext.h?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Symbol/SymbolContext.h (original)
+++ lldb/trunk/include/lldb/Symbol/SymbolContext.h Thu Mar 10 21:53:59 2011
@@ -255,6 +255,63 @@
     Symbol *        symbol;     ///< The Symbol for a given query
 };
 
+
+class SymbolContextSpecifier
+{
+public:
+    typedef enum SpecificationType
+    {
+        eNothingSpecified          = 0,
+        eModuleSpecified           = 1 << 0,
+        eFileSpecified             = 1 << 1,
+        eLineStartSpecified        = 1 << 2,
+        eLineEndSpecified          = 1 << 3,
+        eFunctionSpecified         = 1 << 4,
+        eClassOrNamespaceSpecified = 1 << 5,
+        eAddressRangeSpecified     = 1 << 6
+    } SpecificationType;
+    
+    // This one produces a specifier that matches everything...
+    SymbolContextSpecifier (lldb::TargetSP target_sp) :
+        m_start_line(0),
+        m_end_line(0)
+    {
+        m_target_sp = target_sp;
+        m_type = eNothingSpecified;
+    }   
+    
+    bool
+    AddSpecification (const char *spec_string, SpecificationType type);
+    
+    bool
+    AddLineSpecification (uint32_t line_no, SpecificationType type);
+    
+    void
+    Clear();
+    
+    bool
+    SymbolContextMatches(SymbolContext &sc);
+    
+    bool
+    AddressMatches(lldb::addr_t addr);
+    
+    void
+    GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+private:
+    lldb::TargetSP                 m_target_sp;
+    std::string                    m_module_spec;
+    lldb::ModuleSP                 m_module_sp;
+    std::auto_ptr<FileSpec>        m_file_spec_ap;
+    size_t                         m_start_line;
+    size_t                         m_end_line;
+    std::string                    m_function_spec;
+    std::string                    m_class_name;
+    std::auto_ptr<AddressRange>    m_address_range_ap;
+    uint32_t                       m_type; // Or'ed bits from SpecificationType
+
+};
+
 //----------------------------------------------------------------------
 /// @class SymbolContextList SymbolContext.h "lldb/Symbol/SymbolContext.h"
 /// @brief Defines a list of symbol context objects.

Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Thu Mar 10 21:53:59 2011
@@ -506,7 +506,141 @@
         return m_persistent_variables;
     }
 
-
+    //------------------------------------------------------------------
+    // Target Stop Hooks
+    //------------------------------------------------------------------
+    class StopHook : public UserID
+    {
+    public:
+        ~StopHook ();
+        
+        StopHook (const StopHook &rhs);
+                
+        StringList *
+        GetCommandPointer ()
+        {
+            return &m_commands;
+        }
+        
+        const StringList &
+        GetCommands()
+        {
+            return m_commands;
+        }
+        
+        lldb::TargetSP &
+        GetTarget()
+        {
+            return m_target_sp;
+        }
+        
+        void
+        SetCommands (StringList &in_commands)
+        {
+            m_commands = in_commands;
+        }
+        
+        // Set the specifier.  The stop hook will own the specifier, and is responsible for deleting it when we're done.
+        void
+        SetSpecifier (SymbolContextSpecifier *specifier)
+        {
+            m_specifier_sp.reset (specifier);
+        }
+        
+        SymbolContextSpecifier *
+        GetSpecifier ()
+        {
+            return m_specifier_sp.get();
+        }
+        
+        // Set the Thread Specifier.  The stop hook will own the thread specifier, and is responsible for deleting it when we're done.
+        void
+        SetThreadSpecifier (ThreadSpec *specifier);
+        
+        ThreadSpec *
+        GetThreadSpecifier()
+        {
+            return m_thread_spec_ap.get();
+        }
+        
+        bool
+        IsActive()
+        {
+            return m_active;
+        }
+        
+        void
+        SetIsActive (bool is_active)
+        {
+            m_active = is_active;
+        }
+        
+        void
+        GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+        
+    private:
+        lldb::TargetSP m_target_sp;
+        StringList   m_commands;
+        lldb::SymbolContextSpecifierSP m_specifier_sp;
+        std::auto_ptr<ThreadSpec> m_thread_spec_ap;
+        bool m_active;
+        
+        // Use AddStopHook to make a new empty stop hook.  The GetCommandPointer and fill it with commands,
+        // and SetSpecifier to set the specifier shared pointer (can be null, that will match anything.)
+        StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid);
+        friend class Target;
+    };
+    typedef lldb::SharedPtr<StopHook>::Type StopHookSP;
+    
+    // Add an empty stop hook to the Target's stop hook list, and returns a shared pointer to it in new_hook.  
+    // Returns the id of the new hook.        
+    lldb::user_id_t
+    AddStopHook (StopHookSP &new_hook);
+    
+    void
+    RunStopHooks ();
+    
+    size_t
+    GetStopHookSize();
+    
+//    StopHookSP &
+//    GetStopHookByIndex (size_t index);
+//    
+    bool
+    RemoveStopHookByID (lldb::user_id_t uid);
+    
+    void
+    RemoveAllStopHooks ();
+    
+    StopHookSP
+    GetStopHookByID (lldb::user_id_t uid);
+    
+    bool
+    SetStopHookActiveStateByID (lldb::user_id_t uid, bool active_state);
+    
+    void
+    SetAllStopHooksActiveState (bool active_state);
+    
+    size_t GetNumStopHooks () const
+    {
+        return m_stop_hooks.size();
+    }
+    
+    StopHookSP
+    GetStopHookAtIndex (size_t index)
+    {
+        if (index >= GetNumStopHooks())
+            return StopHookSP();
+        StopHookCollection::iterator pos = m_stop_hooks.begin();
+        
+        while (index > 0)
+        {
+            pos++;
+            index--;
+        }
+        return (*pos).second;
+    }
+    
     //------------------------------------------------------------------
     // Target::SettingsController
     //------------------------------------------------------------------
@@ -555,7 +689,7 @@
 
 protected:
     friend class lldb::SBTarget;
-
+    
     //------------------------------------------------------------------
     // Member variables.
     //------------------------------------------------------------------
@@ -576,6 +710,11 @@
     std::auto_ptr<ClangASTContext> m_scratch_ast_context_ap;
     ClangPersistentVariables m_persistent_variables;      ///< These are the persistent variables associated with this process for the expression parser.
 
+
+    typedef std::map<lldb::user_id_t, StopHookSP> StopHookCollection;
+    StopHookCollection      m_stop_hooks;
+    lldb::user_id_t         m_stop_hook_next_id;
+    
     //------------------------------------------------------------------
     // Methods.
     //------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/lldb-enumerations.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-enumerations.h (original)
+++ lldb/trunk/include/lldb/lldb-enumerations.h Thu Mar 10 21:53:59 2011
@@ -494,6 +494,7 @@
     eArgTypeBreakpointID,
     eArgTypeBreakpointIDRange,
     eArgTypeByteSize,
+    eArgTypeClassName,
     eArgTypeCommandName,
     eArgTypeCount,
     eArgTypeEndAddress,

Modified: lldb/trunk/include/lldb/lldb-forward-rtti.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward-rtti.h?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward-rtti.h (original)
+++ lldb/trunk/include/lldb/lldb-forward-rtti.h Thu Mar 10 21:53:59 2011
@@ -61,6 +61,7 @@
     typedef SharedPtr<lldb_private::StoppointLocation>::Type StoppointLocationSP;
     typedef SharedPtr<lldb_private::Stream>::Type StreamSP;
     typedef SharedPtr<lldb_private::SymbolFile>::Type SymbolFileSP;
+    typedef SharedPtr<lldb_private::SymbolContextSpecifier>::Type SymbolContextSpecifierSP;
     typedef SharedPtr<lldb_private::Target>::Type TargetSP;
     typedef SharedPtr<lldb_private::Thread>::Type ThreadSP;
     typedef SharedPtr<lldb_private::ThreadPlan>::Type ThreadPlanSP;

Modified: lldb/trunk/include/lldb/lldb-forward.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/include/lldb/lldb-forward.h (original)
+++ lldb/trunk/include/lldb/lldb-forward.h Thu Mar 10 21:53:59 2011
@@ -130,6 +130,7 @@
 class   SymbolContext;
 class   SymbolContextList;
 class   SymbolContextScope;
+class   SymbolContextSpecifier;
 class   SymbolFile;
 class   SymbolVendor;
 class   Symtab;

Modified: lldb/trunk/source/Commands/CommandObjectTarget.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectTarget.cpp?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectTarget.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectTarget.cpp Thu Mar 10 21:53:59 2011
@@ -17,13 +17,14 @@
 // Project includes
 #include "lldb/Interpreter/Args.h"
 #include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
 #include "lldb/Core/Timer.h"
-#include "lldb/Core/Debugger.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
 #include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -447,7 +448,7 @@
 //};
 
 
-#pragma mark CommandObjectMultiwordTarget
+#pragma mark CommandObjectMultiwordImageSearchPaths
 
 //-------------------------------------------------------------------------
 // CommandObjectMultiwordImageSearchPaths
@@ -475,6 +476,620 @@
     }
 };
 
+#pragma mark CommandObjectTargetStopHookAdd
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookAdd : public CommandObject
+{
+public:
+
+    class CommandOptions : public Options
+    {
+    public:
+        CommandOptions () :
+            Options(),
+            m_line_start(0),
+            m_line_end (UINT_MAX),
+            m_func_name_type_mask (eFunctionNameTypeAuto),
+            m_sym_ctx_specified (false),
+            m_thread_specified (false)
+        {
+        }
+        
+        ~CommandOptions () {}
+        
+        const lldb::OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        virtual Error
+        SetOptionValue (int option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            bool success;
+
+            switch (short_option)
+            {
+                case 'c':
+                    m_class_name = option_arg;
+                    m_sym_ctx_specified = true;
+                break;
+                
+                case 'e':
+                    m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success);
+                    if (!success)
+                    {
+                        error.SetErrorStringWithFormat ("Invalid end line number: \"%s\".", option_arg);
+                        break;
+                    }
+                    m_sym_ctx_specified = true;
+                break;
+                
+                case 'l':
+                    m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
+                    if (!success)
+                    {
+                        error.SetErrorStringWithFormat ("Invalid start line number: \"%s\".", option_arg);
+                        break;
+                    }
+                    m_sym_ctx_specified = true;
+                break;
+                
+                case 'n':
+                    m_function_name = option_arg;
+                    m_func_name_type_mask |= eFunctionNameTypeAuto;
+                    m_sym_ctx_specified = true;
+                break;
+                
+                case 'f':
+                    m_file_name = option_arg;
+                    m_sym_ctx_specified = true;
+                break;
+                case 's':
+                    m_module_name = option_arg;
+                    m_sym_ctx_specified = true;
+                break;
+                case 't' :
+                {
+                    m_thread_id = Args::StringToUInt64(optarg, LLDB_INVALID_THREAD_ID, 0);
+                    if (m_thread_id == LLDB_INVALID_THREAD_ID)
+                       error.SetErrorStringWithFormat ("Invalid thread id string '%s'.\n", optarg);
+                    m_thread_specified = true;
+                }
+                break;
+                case 'T':
+                    m_thread_name = option_arg;
+                    m_thread_specified = true;
+                break;
+                case 'q':
+                    m_queue_name = option_arg;
+                    m_thread_specified = true;
+                    break;
+                case 'x':
+                {
+                    m_thread_index = Args::StringToUInt32(optarg, UINT32_MAX, 0);
+                    if (m_thread_id == UINT32_MAX)
+                       error.SetErrorStringWithFormat ("Invalid thread index string '%s'.\n", optarg);
+                    m_thread_specified = true;
+                }
+                break;
+                default:
+                    error.SetErrorStringWithFormat ("Unrecognized option %c.");
+                break;
+            }
+            return error;
+        }
+
+        void
+        ResetOptionValues ()
+        {
+            m_class_name.clear();
+            m_function_name.clear();
+            m_line_start = 0;
+            m_line_end = UINT_MAX;
+            m_file_name.clear();
+            m_module_name.clear();
+            m_func_name_type_mask = eFunctionNameTypeAuto;
+            m_thread_id = LLDB_INVALID_THREAD_ID;
+            m_thread_index = UINT32_MAX;
+            m_thread_name.clear();
+            m_queue_name.clear();
+
+            m_sym_ctx_specified = false;
+            m_thread_specified = false;
+        }
+
+        
+        static lldb::OptionDefinition g_option_table[];
+        
+        std::string m_class_name;
+        std::string m_function_name;
+        uint32_t    m_line_start;
+        uint32_t    m_line_end;
+        std::string m_file_name;
+        std::string m_module_name;
+        uint32_t m_func_name_type_mask;  // A pick from lldb::FunctionNameType.
+        lldb::tid_t m_thread_id;
+        uint32_t m_thread_index;
+        std::string m_thread_name;
+        std::string m_queue_name;
+        bool        m_sym_ctx_specified;
+        bool        m_thread_specified;
+    
+    };
+
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    CommandObjectTargetStopHookAdd (CommandInterpreter &interpreter) :
+        CommandObject (interpreter,
+                       "target stop-hook add ",
+                       "Add a hook to be executed when the target stops.",
+                       "target stop-hook add")
+    {
+    }
+
+    ~CommandObjectTargetStopHookAdd ()
+    {
+    }
+
+    static size_t 
+    ReadCommandsCallbackFunction (void *baton, 
+                                  InputReader &reader, 
+                                  lldb::InputReaderAction notification,
+                                  const char *bytes, 
+                                  size_t bytes_len)
+    {
+        File &out_file = reader.GetDebugger().GetOutputFile();
+        Target::StopHook *new_stop_hook = ((Target::StopHook *) baton);
+
+        switch (notification)
+        {
+        case eInputReaderActivate:
+            out_file.Printf ("%s\n", "Enter your stop hook command(s).  Type 'DONE' to end.");
+            if (reader.GetPrompt())
+                out_file.Printf ("%s", reader.GetPrompt());
+            out_file.Flush();
+            break;
+
+        case eInputReaderDeactivate:
+            break;
+
+        case eInputReaderReactivate:
+            if (reader.GetPrompt())
+            {
+                out_file.Printf ("%s", reader.GetPrompt());
+                out_file.Flush();
+            }
+            break;
+
+        case eInputReaderGotToken:
+            if (bytes && bytes_len && baton)
+            {
+                StringList *commands = new_stop_hook->GetCommandPointer();
+                if (commands)
+                {
+                    commands->AppendString (bytes, bytes_len); 
+                }
+            }
+            if (!reader.IsDone() && reader.GetPrompt())
+            {
+                out_file.Printf ("%s", reader.GetPrompt());
+                out_file.Flush();
+            }
+            break;
+            
+        case eInputReaderInterrupt:
+            {
+                // Finish, and cancel the stop hook.
+                new_stop_hook->GetTarget()->RemoveStopHookByID(new_stop_hook->GetID());
+                out_file.Printf ("Stop hook cancelled.\n");
+
+                reader.SetIsDone (true);
+            }
+            break;
+            
+        case eInputReaderEndOfFile:
+            reader.SetIsDone (true);
+            break;
+            
+        case eInputReaderDone:
+            out_file.Printf ("Stop hook #%d added.\n", new_stop_hook->GetID());
+            break;
+        }
+
+        return bytes_len;
+    }
+
+    bool
+    Execute (Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        if (target)
+        {
+            Target::StopHookSP new_hook_sp;
+            target->AddStopHook (new_hook_sp);
+
+            //  First step, make the specifier.
+            std::auto_ptr<SymbolContextSpecifier> specifier_ap;
+            if (m_options.m_sym_ctx_specified)
+            {
+                specifier_ap.reset(new SymbolContextSpecifier(m_interpreter.GetDebugger().GetSelectedTarget()));
+                
+                if (!m_options.m_module_name.empty())
+                {
+                    specifier_ap->AddSpecification (m_options.m_module_name.c_str(), SymbolContextSpecifier::eModuleSpecified);
+                }
+                
+                if (!m_options.m_class_name.empty())
+                {
+                    specifier_ap->AddSpecification (m_options.m_class_name.c_str(), SymbolContextSpecifier::eClassOrNamespaceSpecified);
+                }
+                
+                if (!m_options.m_file_name.empty())
+                {
+                    specifier_ap->AddSpecification (m_options.m_file_name.c_str(), SymbolContextSpecifier::eFileSpecified);
+                }
+                
+                if (m_options.m_line_start != 0)
+                {
+                    specifier_ap->AddLineSpecification (m_options.m_line_start, SymbolContextSpecifier::eLineStartSpecified);
+                }
+                
+                if (m_options.m_line_end != UINT_MAX)
+                {
+                    specifier_ap->AddLineSpecification (m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified);
+                }
+                
+                if (!m_options.m_function_name.empty())
+                {
+                    specifier_ap->AddSpecification (m_options.m_function_name.c_str(), SymbolContextSpecifier::eFunctionSpecified);
+                }
+            }
+            
+            if (specifier_ap.get())
+                new_hook_sp->SetSpecifier (specifier_ap.release());
+
+            // Next see if any of the thread options have been entered:
+            
+            if (m_options.m_thread_specified)
+            {
+                ThreadSpec *thread_spec = new ThreadSpec();
+                
+                if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
+                {
+                    thread_spec->SetTID (m_options.m_thread_id);
+                }
+                
+                if (m_options.m_thread_index != UINT32_MAX)
+                    thread_spec->SetIndex (m_options.m_thread_index);
+                
+                if (!m_options.m_thread_name.empty())
+                    thread_spec->SetName (m_options.m_thread_name.c_str());
+                
+                if (!m_options.m_queue_name.empty())
+                    thread_spec->SetQueueName (m_options.m_queue_name.c_str());
+                    
+                new_hook_sp->SetThreadSpecifier (thread_spec);
+            
+            }
+            // Next gather up the command list, we'll push an input reader and suck the data from that directly into
+            // the new stop hook's command string.
+            
+            InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+            if (!reader_sp)
+            {
+                result.AppendError("out of memory");
+                result.SetStatus (eReturnStatusFailed);
+                target->RemoveStopHookByID (new_hook_sp->GetID());
+                return false;
+            }
+            
+            Error err (reader_sp->Initialize (CommandObjectTargetStopHookAdd::ReadCommandsCallbackFunction,
+                                              new_hook_sp.get(), // baton
+                                              eInputReaderGranularityLine,  // token size, to pass to callback function
+                                              "DONE",                       // end token
+                                              "> ",                         // prompt
+                                              true));                       // echo input
+            if (!err.Success())
+            {
+                result.AppendError (err.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+                target->RemoveStopHookByID (new_hook_sp->GetID());
+                return false;
+            }
+            m_interpreter.GetDebugger().PushInputReader (reader_sp);
+
+            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+        }
+        else
+        {
+            result.AppendError ("invalid target");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        
+        return result.Succeeded();
+    }
+private:
+    CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectTargetStopHookAdd::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_ALL, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+        "Set the module within which the stop-hook is to be run."},
+    { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, NULL, eArgTypeThreadIndex,
+        "The stop hook is run only for the thread whose index matches this argument."},
+    { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, NULL, eArgTypeThreadID,
+        "The stop hook is run only for the thread whose TID matches this argument."},
+    { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, NULL, eArgTypeThreadName,
+        "The stop hook is run only for the thread whose thread name matches this argument."},
+    { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, NULL, eArgTypeQueueName,
+        "The stop hook is run only for threads in the queue whose name is given by this argument."},
+    { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+        "Specify the source file within which the stop-hook is to be run." },
+    { LLDB_OPT_SET_1, false, "start-line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+        "Set the start of the line range for which the stop-hook is to be run."},
+    { LLDB_OPT_SET_1, false, "end-line", 'e', required_argument, NULL, 0, eArgTypeLineNum,
+        "Set the end of the line range for which the stop-hook is to be run."},
+    { LLDB_OPT_SET_2, false, "classname", 'c', required_argument, NULL, NULL, eArgTypeClassName,
+        "Specify the class within which the stop-hook is to be run." },
+    { LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+        "Set the function name within which the stop hook will be run." },
+    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetStopHookDelete
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookDelete : public CommandObject
+{
+public:
+
+    CommandObjectTargetStopHookDelete (CommandInterpreter &interpreter) :
+        CommandObject (interpreter,
+                       "target stop-hook delete [<id>]",
+                       "Delete a stop-hook.",
+                       "target stop-hook delete")
+    {
+    }
+
+    ~CommandObjectTargetStopHookDelete ()
+    {
+    }
+
+    bool
+    Execute (Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        if (target)
+        {
+            // FIXME: see if we can use the breakpoint id style parser?
+            size_t num_args = command.GetArgumentCount();
+            if (num_args == 0)
+            {
+                if (!m_interpreter.Confirm ("Delete all stop hooks?", true))
+                {
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+                else
+                {
+                    target->RemoveAllStopHooks();
+                }
+            }
+            else
+            {
+                bool success;
+                for (size_t i = 0; i < num_args; i++)
+                {
+                    lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+                    if (!success)
+                    {
+                        result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".", command.GetArgumentAtIndex(i));
+                        result.SetStatus(eReturnStatusFailed);
+                        return false;
+                    }
+                    success = target->RemoveStopHookByID (user_id);
+                    if (!success)
+                    {
+                        result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".", command.GetArgumentAtIndex(i));
+                        result.SetStatus(eReturnStatusFailed);
+                        return false;
+                    }
+                }
+            }
+            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+        }
+        else
+        {
+            result.AppendError ("invalid target");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        
+        return result.Succeeded();
+    }
+};
+#pragma mark CommandObjectTargetStopHookEnableDisable
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookEnableDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookEnableDisable : public CommandObject
+{
+public:
+
+    CommandObjectTargetStopHookEnableDisable (CommandInterpreter &interpreter, bool enable, const char *name, const char *help, const char *syntax) :
+        CommandObject (interpreter,
+                       name,
+                       help,
+                       syntax),
+        m_enable (enable)
+    {
+    }
+
+    ~CommandObjectTargetStopHookEnableDisable ()
+    {
+    }
+
+    bool
+    Execute (Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        if (target)
+        {
+            // FIXME: see if we can use the breakpoint id style parser?
+            size_t num_args = command.GetArgumentCount();
+            bool success;
+            
+            if (num_args == 0)
+            {
+                target->SetAllStopHooksActiveState (m_enable);
+            }
+            else
+            {
+                for (size_t i = 0; i < num_args; i++)
+                {
+                    lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+                    if (!success)
+                    {
+                        result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".", command.GetArgumentAtIndex(i));
+                        result.SetStatus(eReturnStatusFailed);
+                        return false;
+                    }
+                    success = target->SetStopHookActiveStateByID (user_id, m_enable);
+                    if (!success)
+                    {
+                        result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".", command.GetArgumentAtIndex(i));
+                        result.SetStatus(eReturnStatusFailed);
+                        return false;
+                    }
+                }
+            }
+            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+        }
+        else
+        {
+            result.AppendError ("invalid target");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+private:
+    bool m_enable;
+};
+
+#pragma mark CommandObjectTargetStopHookList
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookList
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookList : public CommandObject
+{
+public:
+
+    CommandObjectTargetStopHookList (CommandInterpreter &interpreter) :
+        CommandObject (interpreter,
+                       "target stop-hook list [<type>]",
+                       "List all stop-hooks.",
+                       "target stop-hook list")
+    {
+    }
+
+    ~CommandObjectTargetStopHookList ()
+    {
+    }
+
+    bool
+    Execute (Args& command,
+             CommandReturnObject &result)
+    {
+        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+        if (target)
+        {
+            bool notify = true;
+            target->GetImageSearchPathList().Clear(notify);
+            result.SetStatus (eReturnStatusSuccessFinishNoResult);
+        }
+        else
+        {
+            result.AppendError ("invalid target");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        
+        size_t num_hooks = target->GetNumStopHooks ();
+        if (num_hooks == 0)
+        {
+            result.GetOutputStream().PutCString ("No stop hooks.\n");
+        }
+        else
+        {
+            for (size_t i = 0; i < num_hooks; i++)
+            {
+                Target::StopHookSP this_hook = target->GetStopHookAtIndex (i);
+                if (i > 0)
+                    result.GetOutputStream().PutCString ("\n");
+                this_hook->GetDescription (&(result.GetOutputStream()), eDescriptionLevelFull);
+            }
+        }
+        return result.Succeeded();
+    }
+};
+
+#pragma mark CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword
+{
+public:
+
+    CommandObjectMultiwordTargetStopHooks (CommandInterpreter &interpreter) :
+        CommandObjectMultiword (interpreter, 
+                                "target stop-hook",
+                                "A set of commands for operating on debugger target stop-hooks.",
+                                "target stop-hook <subcommand> [<subcommand-options>]")
+    {
+        LoadSubCommand ("add",      CommandObjectSP (new CommandObjectTargetStopHookAdd (interpreter)));
+        LoadSubCommand ("delete",   CommandObjectSP (new CommandObjectTargetStopHookDelete (interpreter)));
+        LoadSubCommand ("disable",  CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter, 
+                                                                                                   false, 
+                                                                                                   "target stop-hook disable [<id>]",
+                                                                                                   "Disable a stop-hook.",
+                                                                                                   "target stop-hook disable")));
+        LoadSubCommand ("enable",   CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter, 
+                                                                                                   true, 
+                                                                                                   "target stop-hook enable [<id>]",
+                                                                                                   "Enable a stop-hook.",
+                                                                                                   "target stop-hook enable")));
+        LoadSubCommand ("list",     CommandObjectSP (new CommandObjectTargetStopHookList (interpreter)));
+    }
+
+    ~CommandObjectMultiwordTargetStopHooks()
+    {
+    }
+};
+
+
 
 #pragma mark CommandObjectMultiwordTarget
 
@@ -489,6 +1104,7 @@
                             "target <subcommand> [<subcommand-options>]")
 {
     LoadSubCommand ("image-search-paths", CommandObjectSP (new CommandObjectMultiwordImageSearchPaths (interpreter)));
+    LoadSubCommand ("stop-hook", CommandObjectSP (new CommandObjectMultiwordTargetStopHooks (interpreter)));
 }
 
 CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget ()

Modified: lldb/trunk/source/Symbol/SymbolContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/SymbolContext.cpp?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/source/Symbol/SymbolContext.cpp (original)
+++ lldb/trunk/source/Symbol/SymbolContext.cpp Thu Mar 10 21:53:59 2011
@@ -433,25 +433,298 @@
     return return_value;
 }
 
-//SymbolContext
-//SymbolContext::CreateSymbolContextFromDescription (lldb::TargetSP &target_sp,
-//                                    const char *module,
-//                                    const char *comp_unit,
-//                                    const char *function,
-//                                    const char *block_spec
-//                                    const char *line_number,
-//                                    const char *symbol)
-//{
-//    SymbolContext sc;
-//    sc.target = target_sp;
-//    
-//    if (module != NULL && module[0] != '0')
-//    {
-//    
-//    }
-//    
-//    return sc;
-//}
+//----------------------------------------------------------------------
+//
+//  SymbolContextSpecifier
+//
+//----------------------------------------------------------------------
+
+bool
+SymbolContextSpecifier::AddLineSpecification (uint32_t line_no, SpecificationType type)
+{
+    bool return_value = true;
+    switch (type)
+    {
+    case eNothingSpecified:
+        Clear();
+        break;
+    case eLineStartSpecified:
+        m_start_line = line_no;
+        m_type |= eLineStartSpecified;
+        break;
+    case eLineEndSpecified:
+        m_end_line = line_no;
+        m_type |= eLineEndSpecified;
+        break;
+    default:
+        return_value = false;
+        break;
+    }
+    return return_value;
+}
+
+bool
+SymbolContextSpecifier::AddSpecification (const char *spec_string, SpecificationType type)
+{
+    bool return_value = true;
+    switch (type)
+    {
+    case eNothingSpecified:
+        Clear();
+        break;
+    case eModuleSpecified:
+        {
+        // See if we can find the Module, if so stick it in the SymbolContext.
+            FileSpec module_spec(spec_string, true);
+            lldb::ModuleSP module_sp = m_target_sp->GetImages().FindFirstModuleForFileSpec (module_spec);
+            m_type |= eModuleSpecified;
+            if (module_sp)
+                m_module_sp = module_sp;
+            else
+                m_module_spec.assign (spec_string);
+        }
+        break;
+    case eFileSpecified:
+        // CompUnits can't necessarily be resolved here, since an inlined function might show up in 
+        // a number of CompUnits.  Instead we just convert to a FileSpec and store it away.
+        m_file_spec_ap.reset (new FileSpec (spec_string, true));
+        m_type |= eFileSpecified;
+        break;
+    case eLineStartSpecified:
+        m_start_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
+        if (return_value)
+            m_type |= eLineStartSpecified;
+        break;
+    case eLineEndSpecified:
+        m_end_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
+        if (return_value)
+            m_type |= eLineEndSpecified;
+        break;
+    case eFunctionSpecified:
+        m_function_spec.assign(spec_string);
+        m_type |= eFunctionSpecified;
+        break;
+    case eClassOrNamespaceSpecified:
+        Clear();
+        m_class_name.assign (spec_string);
+        m_type = eClassOrNamespaceSpecified;
+        break;
+    case eAddressRangeSpecified:
+        // Not specified yet...
+        break;
+    }
+    
+    return return_value;
+}
+
+void
+SymbolContextSpecifier::Clear()
+{
+    m_module_spec.clear();
+    m_file_spec_ap.reset();
+    m_function_spec.clear();
+    m_class_name.clear();
+    m_start_line = 0;
+    m_end_line = 0;
+    m_address_range_ap.reset();
+    
+    m_type = eNothingSpecified;
+}
+
+bool
+SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
+{
+    if (m_type == eNothingSpecified)
+        return true;
+        
+    if (m_target_sp.get() != sc.target_sp.get())
+        return false;
+        
+    if (m_type & eModuleSpecified)
+    {
+        if (sc.module_sp)
+        {
+            if (m_module_sp.get() != NULL)
+            { 
+                if (m_module_sp.get() != sc.module_sp.get())
+                    return false;
+            }
+            else
+            {
+                FileSpec module_file_spec (m_module_spec.c_str(), false);
+                if (!FileSpec::Equal (module_file_spec, sc.module_sp->GetFileSpec(), false))
+                    return false;
+            }
+        }
+    }
+    if (m_type & eFileSpecified)
+    {
+        if (m_file_spec_ap.get())
+        {
+            // If we don't have a block or a comp_unit, then we aren't going to match a source file.
+            if (sc.block == NULL && sc.comp_unit == NULL)
+                return false;
+                
+            // Check if the block is present, and if so is it inlined:
+            bool was_inlined = false;
+            if (sc.block != NULL)
+            {
+                const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
+                if (inline_info != NULL)
+                {
+                    was_inlined = true;
+                    if (!FileSpec::Equal (inline_info->GetDeclaration().GetFile(), *(m_file_spec_ap.get()), false))
+                        return false;
+                }
+            }
+            
+            // Next check the comp unit, but only if the SymbolContext was not inlined.
+            if (!was_inlined && sc.comp_unit != NULL)
+            {
+                if (!FileSpec::Equal (*(sc.comp_unit), *(m_file_spec_ap.get()), false))
+                    return false;
+            }
+        }
+    }
+    if (m_type & eLineStartSpecified 
+        || m_type & eLineEndSpecified)
+    {
+        if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line)
+            return false;
+    }
+    
+    if (m_type & eFunctionSpecified)
+    {
+        // First check the current block, and if it is inlined, get the inlined function name:
+        bool was_inlined = false;
+        ConstString func_name(m_function_spec.c_str());
+        
+        if (sc.block != NULL)
+        {
+            const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
+            if (inline_info != NULL)
+            {
+                was_inlined = true;
+                const Mangled &name = inline_info->GetMangled();
+                if (!name.NameMatches (func_name))
+                    return false;
+            }
+        }
+        //  If it wasn't inlined, check the name in the function or symbol:
+        if (!was_inlined)
+        {
+            if (sc.function != NULL)
+            {
+                if (!sc.function->GetMangled().NameMatches(func_name))
+                    return false;
+            }
+            else if (sc.symbol != NULL)
+            {
+                if (!sc.symbol->GetMangled().NameMatches(func_name))
+                    return false;
+            }
+        }
+        
+            
+    }
+    
+    return true;
+}
+
+bool
+SymbolContextSpecifier::AddressMatches(lldb::addr_t addr)
+{
+    if (m_type & eAddressRangeSpecified)
+    {
+    
+    }
+    else
+    {
+        Address match_address (addr, NULL);
+        SymbolContext sc;
+        m_target_sp->GetImages().ResolveSymbolContextForAddress(match_address, eSymbolContextEverything, sc);
+        return SymbolContextMatches(sc);
+    }
+    return true;
+}
+
+void
+SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+    char path_str[PATH_MAX + 1];
+
+    if (m_type == eNothingSpecified)
+    {
+        s->Printf ("Nothing specified.\n");
+    }
+    
+    if (m_type == eModuleSpecified)
+    {
+        s->Indent();
+        if (m_module_sp)
+        {
+            m_module_sp->GetFileSpec().GetPath (path_str, PATH_MAX);
+            s->Printf ("Module: %s\n", path_str);
+        }
+        else
+            s->Printf ("Module: %s\n", m_module_spec.c_str());
+    }
+    
+    if (m_type == eFileSpecified  && m_file_spec_ap.get() != NULL)
+    {
+        m_file_spec_ap->GetPath (path_str, PATH_MAX);
+        s->Indent();
+        s->Printf ("File: %s", path_str);
+        if (m_type == eLineStartSpecified)
+        {
+            s->Printf (" from line %d", m_start_line);
+            if (m_type == eLineEndSpecified)
+                s->Printf ("to line %d", m_end_line);
+            else
+                s->Printf ("to end", m_end_line);
+        }
+        else if (m_type == eLineEndSpecified)
+        {
+            s->Printf (" from start to line %d", m_end_line);
+        }
+        s->Printf (".\n");
+    }
+    
+    if (m_type == eLineStartSpecified)
+    {
+        s->Indent();
+        s->Printf ("From line %d", m_start_line);
+        if (m_type == eLineEndSpecified)
+            s->Printf ("to line %d", m_end_line);
+        else
+            s->Printf ("to end", m_end_line);
+        s->Printf (".\n");
+    }
+    else if (m_type == eLineEndSpecified)
+    {
+        s->Printf ("From start to line %d.\n", m_end_line);
+    }
+    
+    if (m_type == eFunctionSpecified)
+    {
+        s->Indent();
+        s->Printf ("Function: %s.\n", m_function_spec.c_str());
+    }
+    
+    if (m_type == eClassOrNamespaceSpecified)
+    {
+        s->Indent();
+        s->Printf ("Class name: %s.\n", m_class_name.c_str());
+    }
+    
+    if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != NULL)
+    {
+        s->Indent();
+        s->PutCString ("Address range: ");
+        m_address_range_ap->Dump (s, m_target_sp.get(), Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+        s->PutCString ("\n");
+    }
+}
 
 //----------------------------------------------------------------------
 //

Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Thu Mar 10 21:53:59 2011
@@ -2256,11 +2256,12 @@
                          StateAsCString (GetState ()),
                          IsHijackedForEvent(eBroadcastBitStateChanged) ? "hijacked" : "public");
         }
+        Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
         if (StateIsRunningState (new_state))
             PushProcessInputReader ();
         else 
             PopProcessInputReader ();
-        Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
+
         BroadcastEvent (event_sp);
     }
     else
@@ -2431,6 +2432,15 @@
 
         if (m_process_sp->GetPrivateState() == eStateRunning)
             SetRestarted(true);
+        else
+        {
+            // Finally, if we didn't restart, run the Stop Hooks here:
+            // They might also restart the target, so watch for that.
+            m_process_sp->GetTarget().RunStopHooks();
+            if (m_process_sp->GetPrivateState() == eStateRunning)
+                SetRestarted(true);
+        }
+        
     }
 }
 

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=127457&r1=127456&r2=127457&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Thu Mar 10 21:53:59 2011
@@ -24,10 +24,14 @@
 #include "lldb/Core/Timer.h"
 #include "lldb/Core/ValueObject.h"
 #include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
 #include "lldb/lldb-private-log.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -48,7 +52,8 @@
     m_search_filter_sp(),
     m_image_search_paths (ImageSearchPathsChanged, this),
     m_scratch_ast_context_ap (NULL),
-    m_persistent_variables ()
+    m_persistent_variables (),
+    m_stop_hook_next_id(0)
 {
     SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
     SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
@@ -979,6 +984,257 @@
     return execution_results;
 }
 
+lldb::user_id_t
+Target::AddStopHook (Target::StopHookSP &new_hook_sp)
+{
+    lldb::user_id_t new_uid = ++m_stop_hook_next_id;
+    new_hook_sp.reset (new StopHook(GetSP(), new_uid));
+    m_stop_hooks[new_uid] = new_hook_sp;
+    return new_uid;
+}
+
+bool
+Target::RemoveStopHookByID (lldb::user_id_t user_id)
+{
+    size_t num_removed;
+    num_removed = m_stop_hooks.erase (user_id);
+    if (num_removed == 0)
+        return false;
+    else
+        return true;
+}
+
+void
+Target::RemoveAllStopHooks ()
+{
+    m_stop_hooks.clear();
+}
+
+Target::StopHookSP
+Target::GetStopHookByID (lldb::user_id_t user_id)
+{
+    StopHookSP found_hook;
+    
+    StopHookCollection::iterator specified_hook_iter;
+    specified_hook_iter = m_stop_hooks.find (user_id);
+    if (specified_hook_iter != m_stop_hooks.end())
+        found_hook = (*specified_hook_iter).second;
+    return found_hook;
+}
+
+bool
+Target::SetStopHookActiveStateByID (lldb::user_id_t user_id, bool active_state)
+{
+    StopHookCollection::iterator specified_hook_iter;
+    specified_hook_iter = m_stop_hooks.find (user_id);
+    if (specified_hook_iter == m_stop_hooks.end())
+        return false;
+        
+    (*specified_hook_iter).second->SetIsActive (active_state);
+    return true;
+}
+
+void
+Target::SetAllStopHooksActiveState (bool active_state)
+{
+    StopHookCollection::iterator pos, end = m_stop_hooks.end();
+    for (pos = m_stop_hooks.begin(); pos != end; pos++)
+    {
+        (*pos).second->SetIsActive (active_state);
+    }
+}
+
+void
+Target::RunStopHooks ()
+{
+    if (!m_process_sp)
+        return;
+        
+    if (m_stop_hooks.empty())
+        return;
+        
+    StopHookCollection::iterator pos, end = m_stop_hooks.end();
+        
+    // If there aren't any active stop hooks, don't bother either:
+    bool any_active_hooks = false;
+    for (pos = m_stop_hooks.begin(); pos != end; pos++)
+    {
+        if ((*pos).second->IsActive())
+        {
+            any_active_hooks = true;
+            break;
+        }
+    }
+    if (!any_active_hooks)
+        return;
+    
+    CommandReturnObject result;
+    
+    std::vector<ExecutionContext> exc_ctx_with_reasons;
+    std::vector<SymbolContext> sym_ctx_with_reasons;
+    
+    ThreadList &cur_threadlist = m_process_sp->GetThreadList();
+    size_t num_threads = cur_threadlist.GetSize();
+    for (size_t i = 0; i < num_threads; i++)
+    {
+        lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex (i);
+        if (cur_thread_sp->ThreadStoppedForAReason())
+        {
+            lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0);
+            exc_ctx_with_reasons.push_back(ExecutionContext(m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get()));
+            sym_ctx_with_reasons.push_back(cur_frame_sp->GetSymbolContext(eSymbolContextEverything));
+        }
+    }
+    
+    // If no threads stopped for a reason, don't run the stop-hooks.
+    size_t num_exe_ctx = exc_ctx_with_reasons.size();
+    if (num_exe_ctx == 0)
+        return;
+    
+    result.SetImmediateOutputFile (m_debugger.GetOutputFile().GetStream());
+    result.SetImmediateErrorFile (m_debugger.GetErrorFile().GetStream());
+    
+    bool keep_going = true;
+    bool hooks_ran = false;
+    for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++)
+    {
+        // result.Clear();
+        StopHookSP cur_hook_sp = (*pos).second;
+        if (!cur_hook_sp->IsActive())
+            continue;
+        
+        bool any_thread_matched = false;
+        for (size_t i = 0; keep_going && i < num_exe_ctx; i++)
+        {
+            if ((cur_hook_sp->GetSpecifier () == NULL 
+                  || cur_hook_sp->GetSpecifier()->SymbolContextMatches(sym_ctx_with_reasons[i]))
+                && (cur_hook_sp->GetThreadSpecifier() == NULL
+                    || cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx_with_reasons[i].thread)))
+            {
+                if (!hooks_ran)
+                {
+                    result.AppendMessage("\n** Stop Hooks **\n");
+                    hooks_ran = true;
+                }
+                if (!any_thread_matched)
+                {
+                    result.AppendMessageWithFormat("\n- Hook %d\n", cur_hook_sp->GetID());
+                    any_thread_matched = true;
+                }
+                
+                result.AppendMessageWithFormat("-- Thread %d\n", exc_ctx_with_reasons[i].thread->GetIndexID());
+                
+                bool stop_on_continue = true; 
+                bool stop_on_error = true; 
+                bool echo_commands = false;
+                bool print_results = true; 
+                GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(), 
+                                                                          &exc_ctx_with_reasons[i], 
+                                                                          stop_on_continue, 
+                                                                          stop_on_error, 
+                                                                          echo_commands,
+                                                                          print_results, 
+                                                                          result);
+
+                // If the command started the target going again, we should bag out of
+                // running the stop hooks.
+                if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult)
+                        || (result.GetStatus() == eReturnStatusSuccessContinuingResult))
+                {
+                    result.AppendMessageWithFormat ("Aborting stop hooks, hook %d set the program running.", cur_hook_sp->GetID());
+                    keep_going = false;
+                }
+            }
+        }
+    }
+    if (hooks_ran)
+        result.AppendMessage ("\n** End Stop Hooks **\n");
+}
+
+//--------------------------------------------------------------
+// class Target::StopHook
+//--------------------------------------------------------------
+
+
+Target::StopHook::StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid) :
+        UserID (uid),
+        m_target_sp (target_sp),
+        m_active (true),
+        m_commands (),
+        m_specifier_sp (),
+        m_thread_spec_ap(NULL)
+{
+}
+
+Target::StopHook::StopHook (const StopHook &rhs) :
+        UserID (rhs.GetID()),
+        m_target_sp (rhs.m_target_sp),
+        m_commands (rhs.m_commands),
+        m_specifier_sp (rhs.m_specifier_sp),
+        m_active (rhs.m_active),
+        m_thread_spec_ap (NULL)
+{
+    if (rhs.m_thread_spec_ap.get() != NULL)
+        m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+}
+        
+
+Target::StopHook::~StopHook ()
+{
+}
+
+void
+Target::StopHook::SetThreadSpecifier (ThreadSpec *specifier)
+{
+    m_thread_spec_ap.reset (specifier);
+}
+        
+
+void
+Target::StopHook::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+    int indent_level = s->GetIndentLevel();
+
+    s->SetIndentLevel(indent_level + 2);
+
+    s->Printf ("Hook: %d\n", GetID());
+    if (m_active)
+        s->Indent ("State: enabled\n");
+    else
+        s->Indent ("State: disabled\n");    
+    
+    if (m_specifier_sp)
+    {
+        s->Indent();
+        s->PutCString ("Specifier:\n");
+        s->SetIndentLevel (indent_level + 4);
+        m_specifier_sp->GetDescription (s, level);
+        s->SetIndentLevel (indent_level + 2);
+    }
+
+    if (m_thread_spec_ap.get() != NULL)
+    {
+        StreamString tmp;
+        s->Indent("Thread:\n");
+        m_thread_spec_ap->GetDescription (&tmp, level);
+        s->SetIndentLevel (indent_level + 4);
+        s->Indent (tmp.GetData());
+        s->PutCString ("\n");
+        s->SetIndentLevel (indent_level + 2);
+    }
+
+    s->Indent ("Commands: \n");
+    s->SetIndentLevel (indent_level + 4);
+    uint32_t num_commands = m_commands.GetSize();
+    for (uint32_t i = 0; i < num_commands; i++)
+    {
+        s->Indent(m_commands.GetStringAtIndex(i));
+        s->PutCString ("\n");
+    }
+    s->SetIndentLevel (indent_level);
+}
+
+
 //--------------------------------------------------------------
 // class Target::SettingsController
 //--------------------------------------------------------------





More information about the lldb-commits mailing list