[Lldb-commits] [lldb] r210272 - Added gdb-remote test for software breakpoints.
Todd Fiala
todd.fiala at gmail.com
Thu Jun 5 09:34:13 PDT 2014
Author: tfiala
Date: Thu Jun 5 11:34:13 2014
New Revision: 210272
URL: http://llvm.org/viewvc/llvm-project?rev=210272&view=rev
Log:
Added gdb-remote test for software breakpoints.
Tests $Z0 and $z0. Extends test exe get-code-address-hex:
to take a function name.
Enabled for debugserver, disabled for llgs. Implementing
in llgs branch next.
Modified:
lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
lldb/trunk/test/tools/lldb-gdbserver/main.cpp
Modified: lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py?rev=210272&r1=210271&r2=210272&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/TestLldbGdbServer.py Thu Jun 5 11:34:13 2014
@@ -49,7 +49,7 @@ class LldbGdbServerTestCase(TestBase):
self.set_inferior_startup_launch()
# Uncomment this code to force only a single test to run (by name).
- # if not re.search(r"qMemoryRegionInfo", self._testMethodName):
+ # if not re.search(r"breakpoint", self._testMethodName):
# self.skipTest("focusing on one test")
def reset_test_sequence(self):
@@ -1351,7 +1351,7 @@ class LldbGdbServerTestCase(TestBase):
def qMemoryRegionInfo_reports_code_address_as_executable(self):
# Start up the inferior.
procs = self.prep_debug_monitor_and_inferior(
- inferior_args=["get-code-address-hex:", "sleep:5"])
+ inferior_args=["get-code-address-hex:hello", "sleep:5"])
# Run the process
self.test_sequence.add_log_lines(
@@ -1534,6 +1534,101 @@ class LldbGdbServerTestCase(TestBase):
self.set_inferior_startup_launch()
self.qMemoryRegionInfo_reports_heap_address_as_readable_writeable()
+ def software_breakpoint_set_and_remove_work(self):
+ # Start up the inferior.
+ procs = self.prep_debug_monitor_and_inferior(
+ inferior_args=["get-code-address-hex:hello", "sleep:1", "call-function:hello"])
+
+ # Run the process
+ self.test_sequence.add_log_lines(
+ [
+ # Start running after initial stop.
+ "read packet: $c#00",
+ # Match output line that prints the memory address of the function call entry point.
+ # Note we require launch-only testing so we can get inferior otuput.
+ { "type":"output_match", "regex":r"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"function_address"} },
+ # Now stop the inferior.
+ "read packet: {}".format(chr(03)),
+ # And wait for the stop notification.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }],
+ True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Grab the address.
+ self.assertIsNotNone(context.get("function_address"))
+ function_address = int(context.get("function_address"), 16)
+
+ # Set the breakpoint.
+ # Note this might need to be switched per platform (ARM, mips, etc.).
+ BREAKPOINT_KIND = 1
+
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Set the breakpoint.
+ "read packet: $Z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
+ # Verify the stub could set it.
+ "send packet: $OK#00",
+ # Continue the inferior.
+ "read packet: $c#00",
+ # Expect a breakpoint stop report.
+ {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },
+ ], True)
+
+ # Run the packet stream.
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+ # Verify the stop signal reported was the breakpoint signal number.
+ stop_signo = context.get("stop_signo")
+ self.assertIsNotNone(stop_signo)
+ self.assertEquals(int(stop_signo,16), signal.SIGTRAP)
+
+ # Ensure we did not receive any output. If the breakpoint was not set, we would
+ # see output (from a launched process with captured stdio) printing a hello, world message.
+ # That would indicate the breakpoint didn't take.
+ self.assertEquals(len(context["O_content"]), 0)
+
+ # Verify that a breakpoint unset and continue gets us the expected output.
+ self.reset_test_sequence()
+ self.test_sequence.add_log_lines(
+ [
+ # Remove the breakpoint.
+ "read packet: $z0,{0:x},{1}#00".format(function_address, BREAKPOINT_KIND),
+ # Verify the stub could unset it.
+ "send packet: $OK#00",
+ # Continue running.
+ "read packet: $c#00",
+ # We should now receive the output from the call.
+ { "type":"output_match", "regex":r"^hello, world\r\n$" },
+ # And wait for program completion.
+ {"direction":"send", "regex":r"^\$W00(.*)#00" },
+ ], True)
+
+ context = self.expect_gdbremote_sequence()
+ self.assertIsNotNone(context)
+
+
+ @debugserver_test
+ @dsym_test
+ def test_software_breakpoint_set_and_remove_work_debugserver_dsym(self):
+ self.init_debugserver_test()
+ self.buildDsym()
+ self.set_inferior_startup_launch()
+ self.software_breakpoint_set_and_remove_work()
+
+ @llgs_test
+ @dwarf_test
+ @unittest2.expectedFailure()
+ def test_software_breakpoint_set_and_remove_work_llgs_dwarf(self):
+ self.init_llgs_test()
+ self.buildDwarf()
+ self.set_inferior_startup_launch()
+ self.software_breakpoint_set_and_remove_work()
+
if __name__ == '__main__':
unittest2.main()
Modified: lldb/trunk/test/tools/lldb-gdbserver/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-gdbserver/main.cpp?rev=210272&r1=210271&r2=210272&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-gdbserver/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-gdbserver/main.cpp Thu Jun 5 11:34:13 2014
@@ -20,14 +20,16 @@ int pthread_threadid_np(pthread_t,__uint
#include <sys/syscall.h>
#endif
-static const char *const RETVAL_PREFIX = "retval:";
-static const char *const SLEEP_PREFIX = "sleep:";
-static const char *const STDERR_PREFIX = "stderr:";
-static const char *const SET_MESSAGE_PREFIX = "set-message:";
+static const char *const RETVAL_PREFIX = "retval:";
+static const char *const SLEEP_PREFIX = "sleep:";
+static const char *const STDERR_PREFIX = "stderr:";
+static const char *const SET_MESSAGE_PREFIX = "set-message:";
static const char *const GET_MESSAGE_ADDRESS_COMMAND = "get-message-address-hex:";
-static const char *const GET_STACK_ADDRESS_COMMAND = "get-stack-address-hex:";
-static const char *const GET_HEAP_ADDRESS_COMMAND = "get-heap-address-hex:";
-static const char *const GET_CODE_ADDRESS_COMMAND = "get-code-address-hex:";
+static const char *const GET_STACK_ADDRESS_COMMAND = "get-stack-address-hex:";
+static const char *const GET_HEAP_ADDRESS_COMMAND = "get-heap-address-hex:";
+
+static const char *const GET_CODE_ADDRESS_PREFIX = "get-code-address-hex:";
+static const char *const CALL_FUNCTION_PREFIX = "call-function:";
static const char *const THREAD_PREFIX = "thread:";
static const char *const THREAD_COMMAND_NEW = "new";
@@ -64,12 +66,12 @@ print_thread_id ()
static void
signal_handler (int signo)
{
- const char *signal_name = NULL;
+ const char *signal_name = nullptr;
switch (signo)
{
case SIGUSR1: signal_name = "SIGUSR1"; break;
case SIGSEGV: signal_name = "SIGSEGV"; break;
- default: signal_name = NULL;
+ default: signal_name = nullptr;
}
// Print notice that we received the signal on a given thread.
@@ -111,6 +113,14 @@ signal_handler (int signo)
}
}
+static void
+hello ()
+{
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("hello, world\n");
+ pthread_mutex_unlock (&g_print_mutex);
+}
+
static void*
thread_func (void *arg)
{
@@ -144,7 +154,7 @@ thread_func (void *arg)
// Test creating a SEGV.
pthread_mutex_lock (&g_jump_buffer_mutex);
g_is_segfaulting = true;
- int *bad_p = NULL;
+ int *bad_p = nullptr;
if (setjmp(g_jump_buffer) == 0)
{
// Force a seg fault signal on this thread.
@@ -174,7 +184,7 @@ thread_func (void *arg)
sleep_seconds_remaining = sleep (sleep_seconds_remaining);
}
- return NULL;
+ return nullptr;
}
int main (int argc, char **argv)
@@ -263,12 +273,30 @@ int main (int argc, char **argv)
printf ("stack address: %p\n", &return_value);
pthread_mutex_unlock (&g_print_mutex);
}
- else if (std::strstr (argv[i], GET_CODE_ADDRESS_COMMAND))
+ else if (std::strstr (argv[i], GET_CODE_ADDRESS_PREFIX))
{
+ // Defaut to providing the address of main.
+ void (*func_p)() = nullptr;
+
+ if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "hello"))
+ func_p = hello;
+
pthread_mutex_lock (&g_print_mutex);
- printf ("code address: %p\n", main);
+ printf ("code address: %p\n", func_p);
pthread_mutex_unlock (&g_print_mutex);
}
+ else if (std::strstr (argv[i], CALL_FUNCTION_PREFIX))
+ {
+ // Defaut to providing the address of main.
+ if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "hello") == 0)
+ hello();
+ else
+ {
+ pthread_mutex_lock (&g_print_mutex);
+ printf ("unknown function: %s\n", argv[i] + strlen (CALL_FUNCTION_PREFIX));
+ pthread_mutex_unlock (&g_print_mutex);
+ }
+ }
else if (std::strstr (argv[i], THREAD_PREFIX))
{
// Check if we're creating a new thread.
@@ -276,7 +304,7 @@ int main (int argc, char **argv)
{
// Create a new thread.
pthread_t new_thread;
- const int err = ::pthread_create (&new_thread, NULL, thread_func, NULL);
+ const int err = ::pthread_create (&new_thread, nullptr, thread_func, nullptr);
if (err)
{
fprintf (stderr, "pthread_create() failed with error code %d\n", err);
@@ -316,7 +344,7 @@ int main (int argc, char **argv)
// If we launched any threads, join them
for (std::vector<pthread_t>::iterator it = threads.begin (); it != threads.end (); ++it)
{
- void *thread_retval = NULL;
+ void *thread_retval = nullptr;
const int err = ::pthread_join (*it, &thread_retval);
if (err != 0)
fprintf (stderr, "pthread_join() failed with error code %d\n", err);
More information about the lldb-commits
mailing list