Moved the FindAddressesForLine function up into ModuleList, so other code can
make use of it.
I'm not sure I agree that there's a better name than just 'force' for the
command line. Right now the only reason the jump would refuse is because it
won't jump to different functions, but perhaps in future there might be other
reasons. Also other command-line options use 'force', and it makes sense to try
and keep things consistent across commands.
http://llvm-reviews.chandlerc.com/D1452
CHANGE SINCE LAST DIFF
http://llvm-reviews.chandlerc.com/D1452?vs=3883&id=3996#toc
Files:
include/lldb/API/SBThread.h
include/lldb/Core/Error.h
include/lldb/Core/Module.h
include/lldb/Core/ModuleList.h
include/lldb/Target/RegisterContext.h
include/lldb/Target/Thread.h
scripts/Python/interface/SBThread.i
source/API/SBThread.cpp
source/Commands/CommandObjectThread.cpp
source/Core/Error.cpp
source/Core/Module.cpp
source/Core/ModuleList.cpp
source/Interpreter/CommandInterpreter.cpp
source/Target/RegisterContext.cpp
source/Target/Thread.cpp
test/functionalities/thread/jump/Makefile
test/functionalities/thread/jump/TestThreadJump.py
test/functionalities/thread/jump/main.cpp
test/functionalities/thread/jump/other.cpp
Index: include/lldb/API/SBThread.h
===================================================================
--- include/lldb/API/SBThread.h
+++ include/lldb/API/SBThread.h
@@ -117,6 +117,9 @@
lldb::SBFileSpec &file_spec,
uint32_t line);
+ SBError
+ JumpToLine (lldb::SBFileSpec &file_spec, uint32_t line);
+
void
RunToAddress (lldb::addr_t addr);
Index: include/lldb/Core/Error.h
===================================================================
--- include/lldb/Core/Error.h
+++ include/lldb/Core/Error.h
@@ -68,7 +68,7 @@
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);
//------------------------------------------------------------------
Index: include/lldb/Core/Module.h
===================================================================
--- include/lldb/Core/Module.h
+++ include/lldb/Core/Module.h
@@ -346,6 +346,32 @@
bool append,
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.
///
Index: include/lldb/Core/ModuleList.h
===================================================================
--- include/lldb/Core/ModuleList.h
+++ include/lldb/Core/ModuleList.h
@@ -439,7 +439,35 @@
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);
Index: include/lldb/Target/RegisterContext.h
===================================================================
--- include/lldb/Target/RegisterContext.h
+++ include/lldb/Target/RegisterContext.h
@@ -129,6 +129,8 @@
bool
SetPC (uint64_t pc);
+ bool SetPC (Address addr);
+
uint64_t
GetSP (uint64_t fail_value = LLDB_INVALID_ADDRESS);
Index: include/lldb/Target/Thread.h
===================================================================
--- include/lldb/Target/Thread.h
+++ include/lldb/Target/Thread.h
@@ -377,7 +377,10 @@
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)
{
Index: scripts/Python/interface/SBThread.i
===================================================================
--- scripts/Python/interface/SBThread.i
+++ scripts/Python/interface/SBThread.i
@@ -136,10 +136,13 @@
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);
Index: source/API/SBThread.cpp
===================================================================
--- source/API/SBThread.cpp
+++ source/API/SBThread.cpp
@@ -910,6 +910,31 @@
}
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;
Index: source/Commands/CommandObjectThread.cpp
===================================================================
--- source/Commands/CommandObjectThread.cpp
+++ source/Commands/CommandObjectThread.cpp
@@ -1463,6 +1463,208 @@
};
//-------------------------------------------------------------------------
+// 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', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specifies the source file to jump to."},
+
+ { LLDB_OPT_SET_1, true, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Specifies the line number to jump to."},
+
+ { LLDB_OPT_SET_2, true, "by", 'b', required_argument, NULL, 0, eArgTypeOffset,
+ "Jumps by a relative line offset from the current line."},
+
+ { LLDB_OPT_SET_3, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression,
+ "Jumps to a specific address."},
+
+ { LLDB_OPT_SET_1|
+ LLDB_OPT_SET_2|
+ LLDB_OPT_SET_3, false, "force",'r', no_argument, 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 @@
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 (
Index: source/Core/Error.cpp
===================================================================
--- source/Core/Error.cpp
+++ source/Core/Error.cpp
@@ -52,12 +52,16 @@
{
}
-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);
}
//----------------------------------------------------------------------
Index: source/Core/Module.cpp
===================================================================
--- source/Core/Module.cpp
+++ source/Core/Module.cpp
@@ -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 @@
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 @@
lookup_name = name;
match_name_after_lookup = false;
}
-}
\ No newline at end of file
+}
Index: source/Core/ModuleList.cpp
===================================================================
--- source/Core/ModuleList.cpp
+++ source/Core/ModuleList.cpp
@@ -663,7 +663,19 @@
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
Index: source/Interpreter/CommandInterpreter.cpp
===================================================================
--- source/Interpreter/CommandInterpreter.cpp
+++ source/Interpreter/CommandInterpreter.cpp
@@ -230,6 +230,13 @@
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)
{
@@ -620,6 +627,26 @@
}
}
+ 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
Index: source/Target/RegisterContext.cpp
===================================================================
--- source/Target/RegisterContext.cpp
+++ source/Target/RegisterContext.cpp
@@ -113,6 +113,19 @@
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)
{
Index: source/Target/Thread.cpp
===================================================================
--- source/Target/Thread.cpp
+++ source/Target/Thread.cpp
@@ -1745,6 +1745,79 @@
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)
{
Index: test/functionalities/thread/jump/Makefile
===================================================================
--- /dev/null
+++ test/functionalities/thread/jump/Makefile
@@ -0,0 +1,4 @@
+LEVEL = ../../../make
+
+CXX_SOURCES := main.cpp other.cpp
+include $(LEVEL)/Makefile.rules
Index: test/functionalities/thread/jump/TestThreadJump.py
===================================================================
--- /dev/null
+++ test/functionalities/thread/jump/TestThreadJump.py
@@ -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()
Index: test/functionalities/thread/jump/main.cpp
===================================================================
--- /dev/null
+++ test/functionalities/thread/jump/main.cpp
@@ -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;
+}
Index: test/functionalities/thread/jump/other.cpp
===================================================================
--- /dev/null
+++ test/functionalities/thread/jump/other.cpp
@@ -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
+}
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits