diff options
| author | Todd Fiala <todd.fiala@gmail.com> | 2014-06-05 16:34:13 +0000 |
|---|---|---|
| committer | Todd Fiala <todd.fiala@gmail.com> | 2014-06-05 16:34:13 +0000 |
| commit | f032399bc479833a6f948a1ced6413e906f221be (patch) | |
| tree | 6ffd61a9e1aec7c271b4163ca9f202e9feb32b37 | |
| parent | 82f9e8a62ed327d8ac2787444fd7b3c6ab0c17fc (diff) | |
| download | bcm5719-llvm-f032399bc479833a6f948a1ced6413e906f221be.tar.gz bcm5719-llvm-f032399bc479833a6f948a1ced6413e906f221be.zip | |
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.
llvm-svn: 210272
| -rw-r--r-- | lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py | 99 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-gdbserver/main.cpp | 58 |
2 files changed, 140 insertions, 17 deletions
diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py index ef524dcdf50..5f0c8801e8c 100644 --- a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py +++ b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py @@ -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() diff --git a/lldb/test/tools/lldb-gdbserver/main.cpp b/lldb/test/tools/lldb-gdbserver/main.cpp index 933d778fe45..1c3b8f09e06 100644 --- a/lldb/test/tools/lldb-gdbserver/main.cpp +++ b/lldb/test/tools/lldb-gdbserver/main.cpp @@ -20,14 +20,16 @@ int pthread_threadid_np(pthread_t,__uint64_t*); #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); |

