diff options
| -rw-r--r-- | lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py | 67 | ||||
| -rw-r--r-- | lldb/test/tools/lldb-gdbserver/main.cpp | 22 |
2 files changed, 86 insertions, 3 deletions
diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py index 8aae233dbbf..122bf87533f 100644 --- a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py +++ b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py @@ -49,9 +49,8 @@ class LldbGdbServerTestCase(TestBase): self.set_inferior_startup_launch() # Uncomment this code to force only a single test to run (by name). - # if self._testMethodName != "test_Hc_then_Csignal_signals_correct_thread_launch_debugserver_dsym": - # # print "skipping test {}".format(self._testMethodName) - # self.skipTest("focusing on one test") + # if not re.search(r"m_packet_reads_memory", self._testMethodName): + # self.skipTest("focusing on one test") def reset_test_sequence(self): self.test_sequence = GdbRemoteTestSequence(self.logger) @@ -1223,6 +1222,68 @@ class LldbGdbServerTestCase(TestBase): self.set_inferior_startup_launch() self.Hc_then_Csignal_signals_correct_thread() + def m_packet_reads_memory(self): + # This is the memory we will write into the inferior and then ensure we can read back with $m. + MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz" + + # Start up the inferior. + procs = self.prep_debug_monitor_and_inferior( + inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-message-address-hex:", "sleep:5"]) + + # 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 message buffer within the inferior. + # Note we require launch-only testing so we can get inferior otuput. + { "type":"output_match", "regex":r"^message address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"message_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 message address. + self.assertIsNotNone(context.get("message_address")) + message_address = int(context.get("message_address"), 16) + + # Grab contents from the inferior. + self.reset_test_sequence() + self.test_sequence.add_log_lines( + ["read packet: $m{0:x},{1:x}#00".format(message_address, len(MEMORY_CONTENTS)), + {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"read_contents"} }], + True) + + # Run the packet stream. + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Ensure what we read from inferior memory is what we wrote. + self.assertIsNotNone(context.get("read_contents")) + read_contents = context.get("read_contents").decode("hex") + self.assertEquals(read_contents, MEMORY_CONTENTS) + + @debugserver_test + @dsym_test + def test_m_packet_reads_memory_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.m_packet_reads_memory() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_m_packet_reads_memory_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.m_packet_reads_memory() if __name__ == '__main__': unittest2.main() diff --git a/lldb/test/tools/lldb-gdbserver/main.cpp b/lldb/test/tools/lldb-gdbserver/main.cpp index e7ae168c2b3..874a69d4ee8 100644 --- a/lldb/test/tools/lldb-gdbserver/main.cpp +++ b/lldb/test/tools/lldb-gdbserver/main.cpp @@ -7,6 +7,8 @@ #include <signal.h> #include <stdint.h> #include <stdio.h> +#include <string.h> +#include <time.h> #include <unistd.h> #include <vector> @@ -20,6 +22,8 @@ int pthread_threadid_np(pthread_t,__uint64_t*); 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 THREAD_PREFIX = "thread:"; static const char *const THREAD_COMMAND_NEW = "new"; @@ -34,6 +38,8 @@ static pthread_mutex_t g_jump_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; static jmp_buf g_jump_buffer; static bool g_is_segfaulting = false; +static char g_message[256]; + static void print_thread_id () { @@ -220,6 +226,22 @@ int main (int argc, char **argv) // std::cout << "sleep result (call " << i << "): " << sleep_seconds_remaining << std::endl; } } + else if (std::strstr (argv[i], SET_MESSAGE_PREFIX)) + { + // Copy the contents after "set-message:" to the g_message buffer. + // Used for reading inferior memory and verifying contents match expectations. + strncpy (g_message, argv[i] + strlen (SET_MESSAGE_PREFIX), sizeof (g_message)); + + // Ensure we're null terminated. + g_message[sizeof (g_message) - 1] = '\0'; + + } + else if (std::strstr (argv[i], GET_MESSAGE_ADDRESS_COMMAND)) + { + pthread_mutex_lock (&g_print_mutex); + printf ("message address: %p\n", &g_message[0]); + pthread_mutex_unlock (&g_print_mutex); + } else if (std::strstr (argv[i], THREAD_PREFIX)) { // Check if we're creating a new thread. |

