From 0811e7140260af0da2bbbadf9c8c51011ee78949 Mon Sep 17 00:00:00 2001 From: Todd Fiala Date: Wed, 4 Jun 2014 15:44:33 +0000 Subject: [PATCH] Add gdb-remote test for $qMemoryRegionInfo code querying. Added test stub for collecting a code, heap and stack address. Added test to verify that the code address returns a readable, executable memory region and that the memory region range was indeed the one that the code belonged to. llvm-svn: 210187 --- .../tools/lldb-gdbserver/TestLldbGdbServer.py | 88 ++++++++++++++++++- lldb/test/tools/lldb-gdbserver/main.cpp | 26 ++++++ 2 files changed, 113 insertions(+), 1 deletion(-) diff --git a/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py b/lldb/test/tools/lldb-gdbserver/TestLldbGdbServer.py index 267944373496..76f8e4f6fcec 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"m_packet_reads_memory", self._testMethodName): + # if not re.search(r"qMemoryRegionInfo", self._testMethodName): # self.skipTest("focusing on one test") def reset_test_sequence(self): @@ -255,6 +255,14 @@ class LldbGdbServerTestCase(TestBase): self.assertTrue("encoding" in reg_info) self.assertTrue("format" in reg_info) + def assert_address_within_range(self, test_address, range_start, range_size): + range_end = range_start + range_size + + if test_address < range_start: + self.fail("address 0x{0:x} comes before range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size)) + elif test_address >= range_end: + self.fail("address 0x{0:x} comes after range 0x{1:x} - 0x{2:x} (size 0x{3:x})".format(test_address, range_start, range_end, range_size)) + def add_threadinfo_collection_packets(self): self.test_sequence.add_log_lines( [ { "type":"multi_response", "first_query":"qfThreadInfo", "next_query":"qsThreadInfo", @@ -1313,6 +1321,84 @@ class LldbGdbServerTestCase(TestBase): self.set_inferior_startup_launch() self.qMemoryRegionInfo_is_supported() + 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"]) + + # 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"^code address: 0x([0-9a-fA-F]+)\r\n$", "capture":{ 1:"code_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 code address. + self.assertIsNotNone(context.get("code_address")) + code_address = int(context.get("code_address"), 16) + + # Grab memory region info from the inferior. + self.reset_test_sequence() + self.test_sequence.add_log_lines( + ["read packet: $qMemoryRegionInfo:{0:x}#00".format(code_address), + {"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"memory_region_response"} }], + True) + + # Run the packet stream. + context = self.expect_gdbremote_sequence() + self.assertIsNotNone(context) + + # Parse the memory region response + self.assertIsNotNone(context.get("memory_region_response")) + mem_region_dict = {match.group(1):match.group(2) for match in re.finditer(r"([^:]+):([^;]+);", context.get("memory_region_response"))} + # print "mem_region_dict: {}".format(mem_region_dict) + + for (key, val) in mem_region_dict.items(): + self.assertTrue(key in ["start", "size", "permissions", "error"]) + self.assertIsNotNone(val) + + # Ensure code address is readable and executable. + self.assertTrue("permissions" in mem_region_dict) + self.assertTrue("r" in mem_region_dict["permissions"]) + self.assertTrue("x" in mem_region_dict["permissions"]) + + # Ensure it has a start address and a size. + self.assertTrue("start" in mem_region_dict) + self.assertTrue("size" in mem_region_dict) + + # Ensure the start address and size encompass the address we queried. + self.assert_address_within_range(code_address, int(mem_region_dict["start"], 16), int(mem_region_dict["size"], 16)) + + + @debugserver_test + @dsym_test + def test_qMemoryRegionInfo_reports_code_address_as_executable_debugserver_dsym(self): + self.init_debugserver_test() + self.buildDsym() + self.set_inferior_startup_launch() + self.qMemoryRegionInfo_reports_code_address_as_executable() + + @llgs_test + @dwarf_test + @unittest2.expectedFailure() + def test_qMemoryRegionInfo_reports_code_address_as_executable_llgs_dwarf(self): + self.init_llgs_test() + self.buildDwarf() + self.set_inferior_startup_launch() + self.qMemoryRegionInfo_reports_code_address_as_executable() + + if __name__ == '__main__': unittest2.main() diff --git a/lldb/test/tools/lldb-gdbserver/main.cpp b/lldb/test/tools/lldb-gdbserver/main.cpp index 874a69d4ee81..4a2784af3cd2 100644 --- a/lldb/test/tools/lldb-gdbserver/main.cpp +++ b/lldb/test/tools/lldb-gdbserver/main.cpp @@ -24,6 +24,9 @@ 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 THREAD_PREFIX = "thread:"; static const char *const THREAD_COMMAND_NEW = "new"; @@ -176,6 +179,7 @@ thread_func (void *arg) int main (int argc, char **argv) { std::vector threads; + std::unique_ptr heap_array_up; int return_value = 0; // Set the signal handler. @@ -241,6 +245,28 @@ int main (int argc, char **argv) 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], GET_HEAP_ADDRESS_COMMAND)) + { + // Create a byte array if not already present. + if (!heap_array_up) + heap_array_up.reset (new uint8_t[32]); + + pthread_mutex_lock (&g_print_mutex); + printf ("heap address: %p\n", heap_array_up.get ()); + pthread_mutex_unlock (&g_print_mutex); + } + else if (std::strstr (argv[i], GET_STACK_ADDRESS_COMMAND)) + { + pthread_mutex_lock (&g_print_mutex); + printf ("stack address: %p\n", &return_value); + pthread_mutex_unlock (&g_print_mutex); + } + else if (std::strstr (argv[i], GET_CODE_ADDRESS_COMMAND)) + { + pthread_mutex_lock (&g_print_mutex); + printf ("code address: %p\n", main); + pthread_mutex_unlock (&g_print_mutex); } else if (std::strstr (argv[i], THREAD_PREFIX)) {