[Lldb-commits] [lldb] r190572 - Added a 'jump' command, similar to GDBs.

Richard Mitton richard at codersnotes.com
Wed Sep 11 19:20:34 PDT 2013


Author: rmitton
Date: Wed Sep 11 21:20:34 2013
New Revision: 190572

URL: http://llvm.org/viewvc/llvm-project?rev=190572&view=rev
Log:
Added a 'jump' command, similar to GDBs.

This allows the PC to be directly changed to a different line.
It's similar to the example python script in examples/python/jump.py, except implemented as a builtin.

Also this version will track the current function correctly even if the target line resolves to multiple addresses. (e.g. debugging a templated function)

Added:
    lldb/trunk/test/functionalities/thread/jump/
    lldb/trunk/test/functionalities/thread/jump/Makefile
    lldb/trunk/test/functionalities/thread/jump/TestThreadJump.py
    lldb/trunk/test/functionalities/thread/jump/main.cpp
    lldb/trunk/test/functionalities/thread/jump/other.cpp
Modified:
    lldb/trunk/include/lldb/API/SBThread.h
    lldb/trunk/include/lldb/Core/Error.h
    lldb/trunk/include/lldb/Core/Module.h
    lldb/trunk/include/lldb/Core/ModuleList.h
    lldb/trunk/include/lldb/Target/RegisterContext.h
    lldb/trunk/include/lldb/Target/Thread.h
    lldb/trunk/scripts/Python/interface/SBThread.i
    lldb/trunk/source/API/SBThread.cpp
    lldb/trunk/source/Commands/CommandObjectThread.cpp
    lldb/trunk/source/Core/Error.cpp
    lldb/trunk/source/Core/Module.cpp
    lldb/trunk/source/Core/ModuleList.cpp
    lldb/trunk/source/Interpreter/CommandInterpreter.cpp
    lldb/trunk/source/Target/RegisterContext.cpp
    lldb/trunk/source/Target/Thread.cpp

Modified: lldb/trunk/include/lldb/API/SBThread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBThread.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBThread.h (original)
+++ lldb/trunk/include/lldb/API/SBThread.h Wed Sep 11 21:20:34 2013
@@ -117,6 +117,9 @@ public:
                    lldb::SBFileSpec &file_spec, 
                    uint32_t line);
 
+    SBError
+    JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
+
     void
     RunToAddress (lldb::addr_t addr);
     

Modified: lldb/trunk/include/lldb/Core/Error.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Error.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Error.h (original)
+++ lldb/trunk/include/lldb/Core/Error.h Wed Sep 11 21:20:34 2013
@@ -68,7 +68,7 @@ public:
     Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
 
     explicit
-    Error (const char* err_str);
+    Error (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
     
     Error (const Error &rhs);
     //------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/Core/Module.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Module.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Module.h (original)
+++ lldb/trunk/include/lldb/Core/Module.h Wed Sep 11 21:20:34 2013
@@ -347,6 +347,32 @@ public:
                    SymbolContextList& sc_list);
 
     //------------------------------------------------------------------
+    /// Find addresses by file/line
+    ///
+    /// @param[in] target_sp
+    ///     The target the addresses are desired for.
+    ///
+    /// @param[in] file
+    ///     Source file to locate.
+    ///
+    /// @param[in] line
+    ///     Source line to locate.
+    ///
+    /// @param[in] function
+    ///	    Optional filter function. Addresses within this function will be
+    ///     added to the 'local' list. All others will be added to the 'extern' list.
+    ///
+    /// @param[out] output_local
+    ///     All matching addresses within 'function'
+    ///
+    /// @param[out] output_extern
+    ///     All matching addresses not within 'function'
+    void FindAddressesForLine (const lldb::TargetSP target_sp,
+                               const FileSpec &file, uint32_t line,
+                               Function *function,
+                               std::vector<Address> &output_local, std::vector<Address> &output_extern);
+
+    //------------------------------------------------------------------
     /// Find global and static variables by name.
     ///
     /// @param[in] name

Modified: lldb/trunk/include/lldb/Core/ModuleList.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ModuleList.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ModuleList.h (original)
+++ lldb/trunk/include/lldb/Core/ModuleList.h Wed Sep 11 21:20:34 2013
@@ -439,7 +439,35 @@ public:
     
     bool
     FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const;
-    
+
+
+    //------------------------------------------------------------------
+    /// Find addresses by file/line
+    ///
+    /// @param[in] target_sp
+    ///     The target the addresses are desired for.
+    ///
+    /// @param[in] file
+    ///     Source file to locate.
+    ///
+    /// @param[in] line
+    ///     Source line to locate.
+    ///
+    /// @param[in] function
+    ///     Optional filter function. Addresses within this function will be
+    ///     added to the 'local' list. All others will be added to the 'extern' list.
+    ///
+    /// @param[out] output_local
+    ///     All matching addresses within 'function'
+    ///
+    /// @param[out] output_extern
+    ///     All matching addresses not within 'function'
+    void FindAddressesForLine (const lldb::TargetSP target_sp,
+                               const FileSpec &file, uint32_t line,
+                               Function *function,
+                               std::vector<Address> &output_local, std::vector<Address> &output_extern);
+
+
     bool
     Remove (const lldb::ModuleSP &module_sp);
 

Modified: lldb/trunk/include/lldb/Target/RegisterContext.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/RegisterContext.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/RegisterContext.h (original)
+++ lldb/trunk/include/lldb/Target/RegisterContext.h Wed Sep 11 21:20:34 2013
@@ -129,6 +129,8 @@ public:
     bool
     SetPC (uint64_t pc);
 
+    bool SetPC (Address addr);
+
     uint64_t
     GetSP (uint64_t fail_value = LLDB_INVALID_ADDRESS);
 

Modified: lldb/trunk/include/lldb/Target/Thread.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Thread.h (original)
+++ lldb/trunk/include/lldb/Target/Thread.h Wed Sep 11 21:20:34 2013
@@ -377,7 +377,10 @@ public:
     
     Error
     ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp, bool broadcast = false);
-    
+
+    Error
+    JumpToLine (const FileSpec &file, uint32_t line, bool can_leave_function, std::string *warnings = NULL);
+
     virtual lldb::StackFrameSP
     GetFrameWithStackID (const StackID &stack_id)
     {

Modified: lldb/trunk/scripts/Python/interface/SBThread.i
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/Python/interface/SBThread.i?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/scripts/Python/interface/SBThread.i (original)
+++ lldb/trunk/scripts/Python/interface/SBThread.i Wed Sep 11 21:20:34 2013
@@ -136,10 +136,13 @@ public:
     StepInstruction(bool step_over);
 
     SBError
-    StepOverUntil (lldb::SBFrame &frame, 
-                   lldb::SBFileSpec &file_spec, 
+    StepOverUntil (lldb::SBFrame &frame,
+                   lldb::SBFileSpec &file_spec,
                    uint32_t line);
 
+    SBError
+    JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
+
     void
     RunToAddress (lldb::addr_t addr);
 

Modified: lldb/trunk/source/API/SBThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/API/SBThread.cpp (original)
+++ lldb/trunk/source/API/SBThread.cpp Wed Sep 11 21:20:34 2013
@@ -910,6 +910,31 @@ SBThread::StepOverUntil (lldb::SBFrame &
 }
 
 SBError
+SBThread::JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+    SBError sb_error;
+
+    Mutex::Locker api_locker;
+    ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+    if (log)
+        log->Printf ("SBThread(%p)::JumpToLine (file+line = %s:%u)", exe_ctx.GetThreadPtr(), file_spec->GetPath().c_str(), line);
+
+    if (!exe_ctx.HasThreadScope())
+    {
+        sb_error.SetErrorString("this SBThread object is invalid");
+        return sb_error;
+    }
+
+    Thread *thread = exe_ctx.GetThreadPtr();
+
+    Error err = thread->JumpToLine (file_spec.get(), line, true);
+    sb_error.SetError (err);
+    return sb_error;
+}
+
+SBError
 SBThread::ReturnFromFrame (SBFrame &frame, SBValue &return_value)
 {
     SBError sb_error;

Modified: lldb/trunk/source/Commands/CommandObjectThread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectThread.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectThread.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectThread.cpp Wed Sep 11 21:20:34 2013
@@ -1463,6 +1463,208 @@ CommandObjectThreadReturn::CommandOption
 };
 
 //-------------------------------------------------------------------------
+// CommandObjectThreadJump
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadJump : public CommandObjectParsed
+{
+public:
+    class CommandOptions : public Options
+    {
+    public:
+
+        CommandOptions (CommandInterpreter &interpreter) :
+            Options (interpreter)
+        {
+            OptionParsingStarting ();
+        }
+
+        void
+        OptionParsingStarting ()
+        {
+            m_filenames.Clear();
+            m_line_num = 0;
+            m_line_offset = 0;
+            m_load_addr = LLDB_INVALID_ADDRESS;
+            m_force = false;
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (uint32_t option_idx, const char *option_arg)
+        {
+            bool success;
+            const int short_option = m_getopt_table[option_idx].val;
+            Error error;
+
+            switch (short_option)
+            {
+                case 'f':
+                    m_filenames.AppendIfUnique (FileSpec(option_arg, false));
+                    if (m_filenames.GetSize() > 1)
+                        return Error("only one source file expected.");
+                    break;
+                case 'l':
+                    m_line_num = Args::StringToUInt32 (option_arg, 0, 0, &success);
+                    if (!success || m_line_num == 0)
+                        return Error("invalid line number: '%s'.", option_arg);
+                    break;
+                case 'b':
+                    m_line_offset = Args::StringToSInt32 (option_arg, 0, 0, &success);
+                    if (!success)
+                        return Error("invalid line offset: '%s'.", option_arg);
+                    break;
+                case 'a':
+                    {
+                        ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+                        m_load_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+                    }
+                    break;
+                case 'r':
+                    m_force = true;
+                    break;
+
+                 default:
+                    return Error("invalid short option character '%c'", short_option);
+
+            }
+            return error;
+        }
+
+        const OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        FileSpecList m_filenames;
+        uint32_t m_line_num;
+        int32_t m_line_offset;
+        lldb::addr_t m_load_addr;
+        bool m_force;
+
+        static OptionDefinition g_option_table[];
+    };
+
+    virtual
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    CommandObjectThreadJump (CommandInterpreter &interpreter) :
+        CommandObjectParsed (interpreter,
+                          "thread jump",
+                          "Sets the program counter to a new address.",
+                          "thread jump",
+                          eFlagRequiresFrame         |
+                          eFlagTryTargetAPILock      |
+                          eFlagProcessMustBeLaunched |
+                          eFlagProcessMustBePaused   ),
+        m_options (interpreter)
+    {
+    }
+
+    ~CommandObjectThreadJump()
+    {
+    }
+
+protected:
+
+    bool DoExecute (Args& args, CommandReturnObject &result)
+    {
+        RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
+        StackFrame *frame = m_exe_ctx.GetFramePtr();
+        Thread *thread = m_exe_ctx.GetThreadPtr();
+        Target *target = m_exe_ctx.GetTargetPtr();
+        const SymbolContext &sym_ctx = frame->GetSymbolContext (eSymbolContextLineEntry);
+
+        if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
+        {
+            // Use this address directly.
+            Address dest = Address(m_options.m_load_addr);
+
+            lldb::addr_t callAddr = dest.GetCallableLoadAddress (target);
+            if (callAddr == LLDB_INVALID_ADDRESS)
+            {
+                result.AppendErrorWithFormat ("Invalid destination address.");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            if (!reg_ctx->SetPC (callAddr))
+            {
+                result.AppendErrorWithFormat ("Error changing PC value for thread %d.", thread->GetIndexID());
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+        }
+        else
+        {
+            // Pick either the absolute line, or work out a relative one.
+            int32_t line = (int32_t)m_options.m_line_num;
+            if (line == 0)
+                line = sym_ctx.line_entry.line + m_options.m_line_offset;
+
+            // Try the current file, but override if asked.
+            FileSpec file = sym_ctx.line_entry.file;
+            if (m_options.m_filenames.GetSize() == 1)
+                file = m_options.m_filenames.GetFileSpecAtIndex(0);
+
+            if (!file)
+            {
+                result.AppendErrorWithFormat ("No source file available for the current location.");
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            std::string warnings;
+            Error err = thread->JumpToLine (file, line, m_options.m_force, &warnings);
+
+            if (err.Fail())
+            {
+                result.SetError (err);
+                return false;
+            }
+
+            if (!warnings.empty())
+                result.AppendWarning (warnings.c_str());
+        }
+
+        result.SetStatus (eReturnStatusSuccessFinishResult);
+        return true;
+    }
+
+    CommandOptions m_options;
+};
+OptionDefinition
+CommandObjectThreadJump::CommandOptions::g_option_table[] =
+{
+    { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+        "Specifies the source file to jump to."},
+
+    { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeLineNum,
+        "Specifies the line number to jump to."},
+
+    { LLDB_OPT_SET_2, true, "by", 'b', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset,
+        "Jumps by a relative line offset from the current line."},
+
+    { LLDB_OPT_SET_3, true, "address", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeAddressOrExpression,
+        "Jumps to a specific address."},
+
+    { LLDB_OPT_SET_1|
+      LLDB_OPT_SET_2|
+      LLDB_OPT_SET_3, false, "force",'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone,"Allows the PC to leave the current function."},
+
+    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
 // CommandObjectMultiwordThread
 //-------------------------------------------------------------------------
 
@@ -1476,6 +1678,7 @@ CommandObjectMultiwordThread::CommandObj
     LoadSubCommand ("continue",   CommandObjectSP (new CommandObjectThreadContinue (interpreter)));
     LoadSubCommand ("list",       CommandObjectSP (new CommandObjectThreadList (interpreter)));
     LoadSubCommand ("return",     CommandObjectSP (new CommandObjectThreadReturn (interpreter)));
+    LoadSubCommand ("jump",       CommandObjectSP (new CommandObjectThreadJump (interpreter)));
     LoadSubCommand ("select",     CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
     LoadSubCommand ("until",      CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
     LoadSubCommand ("step-in",    CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (

Modified: lldb/trunk/source/Core/Error.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Error.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Core/Error.cpp (original)
+++ lldb/trunk/source/Core/Error.cpp Wed Sep 11 21:20:34 2013
@@ -52,12 +52,16 @@ Error::Error (const Error &rhs) :
 {
 }
 
-Error::Error (const char* err_str):
+Error::Error (const char* format, ...):
     m_code (0),
     m_type (eErrorTypeInvalid),
     m_string ()
 {
-    SetErrorString(err_str);
+    va_list args;
+    va_start (args, format);
+    SetErrorToGenericError ();
+    SetErrorStringWithVarArg (format, args);
+    va_end (args);
 }
 
 //----------------------------------------------------------------------

Modified: lldb/trunk/source/Core/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Module.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Core/Module.cpp (original)
+++ lldb/trunk/source/Core/Module.cpp Wed Sep 11 21:20:34 2013
@@ -9,6 +9,7 @@
 
 #include "lldb/lldb-python.h"
 
+#include "lldb/Core/AddressResolverFileLine.h"
 #include "lldb/Core/Error.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/DataBuffer.h"
@@ -752,6 +753,27 @@ Module::FindFunctions (const RegularExpr
     return sc_list.GetSize() - start_size;
 }
 
+void
+Module::FindAddressesForLine (const lldb::TargetSP target_sp,
+                              const FileSpec &file, uint32_t line,
+                              Function *function,
+                              std::vector<Address> &output_local, std::vector<Address> &output_extern)
+{
+    SearchFilterByModule filter(target_sp, m_file);
+    AddressResolverFileLine resolver(file, line, true);
+    resolver.ResolveAddress (filter);
+
+    for (size_t n=0;n<resolver.GetNumberOfAddresses();n++)
+    {
+        Address addr = resolver.GetAddressRangeAtIndex(n).GetBaseAddress();
+        Function *f = addr.CalculateSymbolContextFunction();
+        if (f && f == function)
+            output_local.push_back (addr);
+        else
+            output_extern.push_back (addr);
+    }
+}
+
 size_t
 Module::FindTypes_Impl (const SymbolContext& sc,
                         const ConstString &name,
@@ -1606,4 +1628,4 @@ Module::PrepareForFunctionNameLookup (co
         lookup_name = name;
         match_name_after_lookup = false;
     }
-}
\ No newline at end of file
+}

Modified: lldb/trunk/source/Core/ModuleList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ModuleList.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Core/ModuleList.cpp (original)
+++ lldb/trunk/source/Core/ModuleList.cpp Wed Sep 11 21:20:34 2013
@@ -663,7 +663,19 @@ ModuleList::FindSourceFile (const FileSp
     return false;
 }
 
-
+void
+ModuleList::FindAddressesForLine (const lldb::TargetSP target_sp,
+                                  const FileSpec &file, uint32_t line,
+                                  Function *function,
+                                  std::vector<Address> &output_local, std::vector<Address> &output_extern)
+{
+    Mutex::Locker locker(m_modules_mutex);
+    collection::const_iterator pos, end = m_modules.end();
+    for (pos = m_modules.begin(); pos != end; ++pos)
+    {
+        (*pos)->FindAddressesForLine(target_sp, file, line, function, output_local, output_extern);
+    }
+}
 
 ModuleSP
 ModuleList::FindFirstModule (const ModuleSpec &module_spec) const

Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Wed Sep 11 21:20:34 2013
@@ -228,6 +228,13 @@ CommandInterpreter::Initialize ()
         AddAlias ("t", cmd_obj_sp);
     }
 
+    cmd_obj_sp = GetCommandSPExact ("_regexp-jump",false);
+    if (cmd_obj_sp)
+    {
+        AddAlias ("j", cmd_obj_sp);
+        AddAlias ("jump", cmd_obj_sp);
+    }
+
     cmd_obj_sp = GetCommandSPExact ("_regexp-list", false);
     if (cmd_obj_sp)
     {
@@ -618,6 +625,26 @@ CommandInterpreter::LoadCommandDictionar
         }
     }
 
+    std::unique_ptr<CommandObjectRegexCommand>
+    jump_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+                                                    "_regexp-jump",
+                                                    "Sets the program counter to a new address.",
+                                                    "_regexp-jump [<line>]\n"
+                                                    "_regexp-jump [<+-lineoffset>]\n"
+                                                    "_regexp-jump [<file>:<line>]\n"
+                                                    "_regexp-jump [*<addr>]\n", 2));
+    if (jump_regex_cmd_ap.get())
+    {
+        if (jump_regex_cmd_ap->AddRegexCommand("^\\*(.*)$", "thread jump --addr %1") &&
+            jump_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "thread jump --line %1") &&
+            jump_regex_cmd_ap->AddRegexCommand("^([^:]+):([0-9]+)$", "thread jump --file %1 --line %2") &&
+            jump_regex_cmd_ap->AddRegexCommand("^([+\\-][0-9]+)$", "thread jump --by %1"))
+        {
+            CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_ap.release());
+            m_command_dict[jump_regex_cmd_sp->GetCommandName ()] = jump_regex_cmd_sp;
+        }
+    }
+
 }
 
 int

Modified: lldb/trunk/source/Target/RegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/RegisterContext.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Target/RegisterContext.cpp (original)
+++ lldb/trunk/source/Target/RegisterContext.cpp Wed Sep 11 21:20:34 2013
@@ -113,6 +113,19 @@ RegisterContext::SetPC(uint64_t pc)
     return success;
 }
 
+bool
+RegisterContext::SetPC(Address addr)
+{
+    TargetSP target_sp = m_thread.CalculateTarget();
+    Target *target = target_sp.get();
+
+    lldb::addr_t callAddr = addr.GetCallableLoadAddress (target);
+    if (callAddr == LLDB_INVALID_ADDRESS)
+        return false;
+
+    return SetPC (callAddr);
+}
+
 uint64_t
 RegisterContext::GetSP(uint64_t fail_value)
 {

Modified: lldb/trunk/source/Target/Thread.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=190572&r1=190571&r2=190572&view=diff
==============================================================================
--- lldb/trunk/source/Target/Thread.cpp (original)
+++ lldb/trunk/source/Target/Thread.cpp Wed Sep 11 21:20:34 2013
@@ -1745,6 +1745,79 @@ Thread::ReturnFromFrame (lldb::StackFram
     return return_error;
 }
 
+static void DumpAddressList (Stream &s, const std::vector<Address> &list, ExecutionContextScope *exe_scope)
+{
+    for (size_t n=0;n<list.size();n++)
+    {
+        s << "\t";
+        list[n].Dump (&s, exe_scope, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset);
+        s << "\n";
+    }
+}
+
+Error
+Thread::JumpToLine (const FileSpec &file, uint32_t line, bool can_leave_function, std::string *warnings)
+{
+    ExecutionContext exe_ctx (GetStackFrameAtIndex(0));
+    Target *target = exe_ctx.GetTargetPtr();
+    TargetSP target_sp = exe_ctx.GetTargetSP();
+    RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+    StackFrame *frame = exe_ctx.GetFramePtr();
+    const SymbolContext &sc = frame->GetSymbolContext(eSymbolContextFunction);
+
+    // Find candidate locations.
+    std::vector<Address> candidates, within_function, outside_function;
+    target->GetImages().FindAddressesForLine (target_sp, file, line, sc.function, within_function, outside_function);
+
+    // If possible, we try and stay within the current function.
+    // Within a function, we accept multiple locations (optimized code may do this,
+    // there's no solution here so we do the best we can).
+    // However if we're trying to leave the function, we don't know how to pick the
+    // right location, so if there's more than one then we bail.
+    if (!within_function.empty())
+        candidates = within_function;
+    else if (outside_function.size() == 1 && can_leave_function)
+        candidates = outside_function;
+
+    // Check if we got anything.
+    if (candidates.empty())
+    {
+        if (outside_function.empty())
+        {
+            return Error("Cannot locate an address for %s:%i.",
+                         file.GetFilename().AsCString(), line);
+        }
+        else if (outside_function.size() == 1)
+        {
+            return Error("%s:%i is outside the current function.",
+                         file.GetFilename().AsCString(), line);
+        }
+        else
+        {
+            StreamString sstr;
+            DumpAddressList(sstr, outside_function, target);
+            return Error("%s:%i has multiple candidate locations:\n%s",
+                         file.GetFilename().AsCString(), line, sstr.GetString().c_str());
+        }
+    }
+
+    // Accept the first location, warn about any others.
+    Address dest = candidates[0];
+    if (warnings && candidates.size() > 1)
+    {
+        StreamString sstr;
+        sstr.Printf("%s:%i appears multiple times in this function, selecting the first location:\n",
+                     file.GetFilename().AsCString(), line);
+        DumpAddressList(sstr, candidates, target);
+        *warnings = sstr.GetString();
+    }
+
+    if (!reg_ctx->SetPC (dest))
+        return Error("Cannot change PC to target address.");
+
+    return Error();
+}
+
 void
 Thread::DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx)
 {

Added: lldb/trunk/test/functionalities/thread/jump/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/jump/Makefile?rev=190572&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/jump/Makefile (added)
+++ lldb/trunk/test/functionalities/thread/jump/Makefile Wed Sep 11 21:20:34 2013
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp other.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/test/functionalities/thread/jump/TestThreadJump.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/jump/TestThreadJump.py?rev=190572&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/jump/TestThreadJump.py (added)
+++ lldb/trunk/test/functionalities/thread/jump/TestThreadJump.py Wed Sep 11 21:20:34 2013
@@ -0,0 +1,75 @@
+"""
+Test jumping to different places.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class ThreadJumpTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "thread", "jump")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym(self):
+        """Test thread jump handling."""
+        self.buildDsym(dictionary=self.getBuildFlags())
+        self.thread_jump_test()
+
+    @dwarf_test
+    def test_with_dwarf(self):
+        """Test thread jump handling."""
+        self.buildDwarf(dictionary=self.getBuildFlags())
+        self.thread_jump_test()
+
+    def do_min_test(self, start, jump, var, value):
+        self.runCmd("j %i" % start)                     # jump to the start marker
+        self.runCmd("thread step-in")                   # step into the min fn
+        self.runCmd("j %i" % jump)                      # jump to the branch we're interested in
+        self.runCmd("thread step-out")                  # return out
+        self.runCmd("thread step-over")                 # assign to the global
+        self.expect("expr %s" % var, substrs = [value]) # check it
+
+    def thread_jump_test(self):
+        """Test thread exit handling."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        # Find the line numbers for our breakpoints.
+        self.mark1 = line_number('main.cpp', '// 1st marker')
+        self.mark2 = line_number('main.cpp', '// 2nd marker')
+        self.mark3 = line_number('main.cpp', '// 3rd marker')
+        self.mark4 = line_number('main.cpp', '// 4th marker')
+        self.mark5 = line_number('other.cpp', '// other marker')
+
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.mark3, num_expected_locations=1)
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # The stop reason of the thread should be breakpoint 1.
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT + " 1",
+            substrs = ['stopped',
+                       '* thread #1',
+                       'stop reason = breakpoint 1'])
+
+        self.do_min_test(self.mark3, self.mark1, "i", "4"); # Try the int path, force it to return 'a'
+        self.do_min_test(self.mark3, self.mark2, "i", "5"); # Try the int path, force it to return 'b'
+        self.do_min_test(self.mark4, self.mark1, "j", "7"); # Try the double path, force it to return 'a'
+        self.do_min_test(self.mark4, self.mark2, "j", "8"); # Try the double path, force it to return 'b'
+
+        # Try jumping to another function in a different file.
+        self.runCmd("thread jump --file other.cpp --line %i --force" % self.mark5)
+        self.expect("process status",
+            substrs = ["at other.cpp:%i" % self.mark5])
+
+        # Try jumping to another function (without forcing)
+        self.expect("j main.cpp:%i" % self.mark1, COMMAND_FAILED_AS_EXPECTED, error = True,
+            substrs = ["error"])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/thread/jump/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/jump/main.cpp?rev=190572&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/jump/main.cpp (added)
+++ lldb/trunk/test/functionalities/thread/jump/main.cpp Wed Sep 11 21:20:34 2013
@@ -0,0 +1,34 @@
+//===-- main.cpp ------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This test verifies the correct handling of program counter jumps.
+
+int otherfn();
+
+template<typename T>
+T min(T a, T b)
+{
+    if (a < b)
+    {
+        return a; // 1st marker
+    } else {
+        return b; // 2nd marker
+    }
+}
+
+int main ()
+{
+    int i;
+    double j;
+
+    i = min(4, 5); // 3rd marker
+    j = min(7.0, 8.0); // 4th marker
+
+    return 0;
+}

Added: lldb/trunk/test/functionalities/thread/jump/other.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/thread/jump/other.cpp?rev=190572&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/thread/jump/other.cpp (added)
+++ lldb/trunk/test/functionalities/thread/jump/other.cpp Wed Sep 11 21:20:34 2013
@@ -0,0 +1,13 @@
+//===-- other.cpp -----------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int otherfn()
+{
+    return 4; // other marker
+}





More information about the lldb-commits mailing list