Added gdb-remote test for s packet, single stepping.

llvm-svn: 210481
This commit is contained in:
Todd Fiala 2014-06-09 17:46:37 +00:00
parent 2b5a047956
commit 697bff9cb7
2 changed files with 220 additions and 22 deletions

View File

@ -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"breakpoint", self._testMethodName):
# if not re.search(r"(single_step|break)", self._testMethodName):
# self.skipTest("focusing on one test")
def reset_test_sequence(self):
@ -372,6 +372,30 @@ class LldbGdbServerTestCase(TestBase):
return threads
def add_set_breakpoint_packets(self, address, do_continue=True, breakpoint_kind=1):
self.test_sequence.add_log_lines(
[# Set the breakpoint.
"read packet: $Z0,{0:x},{1}#00".format(address, breakpoint_kind),
# Verify the stub could set it.
"send packet: $OK#00",
], True)
if (do_continue):
self.test_sequence.add_log_lines(
[# 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)
def add_remove_breakpoint_packets(self, address, breakpoint_kind=1):
self.test_sequence.add_log_lines(
[# Remove the breakpoint.
"read packet: $z0,{0:x},{1}#00".format(address, breakpoint_kind),
# Verify the stub could unset it.
"send packet: $OK#00",
], True)
def run_process_then_stop(self, run_seconds=1):
# Tell the stub to continue.
self.test_sequence.add_log_lines(
@ -1010,8 +1034,8 @@ class LldbGdbServerTestCase(TestBase):
self.add_threadinfo_collection_packets()
self.test_sequence.add_log_lines(
["read packet: $qC#00",
{ "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }],
True)
{ "direction":"send", "regex":r"^\$QC([0-9a-fA-F]+)#", "capture":{1:"thread_id"} }
], True)
# Run the packet stream.
context = self.expect_gdbremote_sequence()
@ -1310,7 +1334,7 @@ class LldbGdbServerTestCase(TestBase):
# Start up the inferior.
procs = self.prep_debug_monitor_and_inferior(
inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-message-address-hex:", "sleep:5"])
inferior_args=["set-message:%s" % MEMORY_CONTENTS, "get-data-address-hex:g_message", "sleep:5"])
# Run the process
self.test_sequence.add_log_lines(
@ -1319,7 +1343,7 @@ class LldbGdbServerTestCase(TestBase):
"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"} },
{ "type":"output_match", "regex":r"^data 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.
@ -1616,26 +1640,15 @@ class LldbGdbServerTestCase(TestBase):
self.assertIsNotNone(pc_lldb_reg_index)
self.assertIsNotNone(pc_reg_info)
# Grab the address.
# Grab the function 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)
self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
# Run the packet stream.
context = self.expect_gdbremote_sequence()
@ -1709,6 +1722,166 @@ class LldbGdbServerTestCase(TestBase):
self.set_inferior_startup_launch()
self.software_breakpoint_set_and_remove_work()
def g_c1_c2_contents_are(self, args):
g_c1_address = args["g_c1_address"]
g_c2_address = args["g_c2_address"]
expected_g_c1 = args["expected_g_c1"]
expected_g_c2 = args["expected_g_c2"]
# Read g_c1 and g_c2 contents.
self.reset_test_sequence()
self.test_sequence.add_log_lines(
["read packet: $m{0:x},{1:x}#00".format(g_c1_address, 1),
{"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c1_contents"} },
"read packet: $m{0:x},{1:x}#00".format(g_c2_address, 1),
{"direction":"send", "regex":r"^\$(.+)#[0-9a-fA-F]{2}$", "capture":{1:"g_c2_contents"} }],
True)
# Run the packet stream.
context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)
# Check if what we read from inferior memory is what we are expecting.
self.assertIsNotNone(context.get("g_c1_contents"))
self.assertIsNotNone(context.get("g_c2_contents"))
return (context.get("g_c1_contents").decode("hex") == expected_g_c1) and (context.get("g_c2_contents").decode("hex") == expected_g_c2)
def count_single_steps_until_true(self, thread_id, predicate, args, max_step_count=100):
single_step_count = 0
while single_step_count < max_step_count:
# Single step.
self.reset_test_sequence()
self.test_sequence.add_log_lines(
[# Set the continue thread.
"read packet: $Hc{0:x}#00".format(thread_id),
"send packet: $OK#00",
# Single step.
"read packet: $s#00",
# "read packet: $vCont;s:{0:x}#00".format(thread_id),
# 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)
context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)
self.assertIsNotNone(context.get("stop_signo"))
self.assertEquals(int(context.get("stop_signo"), 16), signal.SIGTRAP)
single_step_count += 1
# See if the predicate is true. If so, we're done.
if predicate(args):
return (True, single_step_count)
# The predicate didn't return true within the runaway step count.
return (False, single_step_count)
def single_step_only_steps_one_instruction(self):
# Start up the inferior.
procs = self.prep_debug_monitor_and_inferior(
inferior_args=["get-code-address-hex:swap_chars", "get-data-address-hex:g_c1", "get-data-address-hex:g_c2", "sleep:1", "call-function:swap_chars", "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 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\ndata address: 0x([0-9a-fA-F]+)\r\ndata address: 0x([0-9a-fA-F]+)\r\n$",
"capture":{ 1:"function_address", 2:"g_c1_address", 3:"g_c2_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 main thread id.
self.assertIsNotNone(context.get("stop_thread_id"))
main_thread_id = int(context.get("stop_thread_id"), 16)
# Grab the function address.
self.assertIsNotNone(context.get("function_address"))
function_address = int(context.get("function_address"), 16)
# Grab the data addresses.
self.assertIsNotNone(context.get("g_c1_address"))
g_c1_address = int(context.get("g_c1_address"), 16)
self.assertIsNotNone(context.get("g_c2_address"))
g_c2_address = int(context.get("g_c2_address"), 16)
# Set a breakpoint at the given address.
# Note this might need to be switched per platform (ARM, mips, etc.).
BREAKPOINT_KIND = 1
self.reset_test_sequence()
self.add_set_breakpoint_packets(function_address, do_continue=True, breakpoint_kind=BREAKPOINT_KIND)
context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)
# Remove the breakpoint.
self.reset_test_sequence()
self.add_remove_breakpoint_packets(function_address, breakpoint_kind=BREAKPOINT_KIND)
context = self.expect_gdbremote_sequence()
self.assertIsNotNone(context)
# Verify g_c1 and g_c2 match expected initial state.
args = {}
args["g_c1_address"] = g_c1_address
args["g_c2_address"] = g_c2_address
args["expected_g_c1"] = "0"
args["expected_g_c2"] = "1"
self.assertTrue(self.g_c1_c2_contents_are(args))
# Verify we take only a small number of steps to hit the first state. Might need to work through function entry prologue code.
args["expected_g_c1"] = "1"
args["expected_g_c2"] = "1"
(state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=25)
self.assertTrue(state_reached)
# Verify we hit the next state.
args["expected_g_c1"] = "1"
args["expected_g_c2"] = "0"
(state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
self.assertTrue(state_reached)
self.assertEquals(step_count, 1)
# Verify we hit the next state.
args["expected_g_c1"] = "0"
args["expected_g_c2"] = "0"
(state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
self.assertTrue(state_reached)
self.assertEquals(step_count, 1)
# Verify we hit the next state.
args["expected_g_c1"] = "0"
args["expected_g_c2"] = "1"
(state_reached, step_count) = self.count_single_steps_until_true(main_thread_id, self.g_c1_c2_contents_are, args, max_step_count=5)
self.assertTrue(state_reached)
self.assertEquals(step_count, 1)
@debugserver_test
@dsym_test
def test_single_step_only_steps_one_instruction_debugserver_dsym(self):
self.init_debugserver_test()
self.buildDsym()
self.set_inferior_startup_launch()
self.single_step_only_steps_one_instruction()
@llgs_test
@dwarf_test
@unittest2.expectedFailure()
def test_single_step_only_steps_one_instruction_llgs_dwarf(self):
self.init_llgs_test()
self.buildDwarf()
self.set_inferior_startup_launch()
self.single_step_only_steps_one_instruction()
if __name__ == '__main__':
unittest2.main()

View File

@ -24,7 +24,7 @@ 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_DATA_ADDRESS_PREFIX = "get-data-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:";
@ -46,6 +46,9 @@ static bool g_is_segfaulting = false;
static char g_message[256];
static volatile char g_c1 = '0';
static volatile char g_c2 = '1';
static void
print_thread_id ()
{
@ -113,6 +116,16 @@ signal_handler (int signo)
}
}
static void
swap_chars ()
{
g_c1 = '1';
g_c2 = '0';
g_c1 = '0';
g_c2 = '1';
}
static void
hello ()
{
@ -251,10 +264,19 @@ int main (int argc, char **argv)
g_message[sizeof (g_message) - 1] = '\0';
}
else if (std::strstr (argv[i], GET_MESSAGE_ADDRESS_COMMAND))
else if (std::strstr (argv[i], GET_DATA_ADDRESS_PREFIX))
{
volatile void *data_p = nullptr;
if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_message"))
data_p = &g_message[0];
else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c1"))
data_p = &g_c1;
else if (std::strstr (argv[i] + strlen (GET_DATA_ADDRESS_PREFIX), "g_c2"))
data_p = &g_c2;
pthread_mutex_lock (&g_print_mutex);
printf ("message address: %p\n", &g_message[0]);
printf ("data address: %p\n", data_p);
pthread_mutex_unlock (&g_print_mutex);
}
else if (std::strstr (argv[i], GET_HEAP_ADDRESS_COMMAND))
@ -275,11 +297,12 @@ int main (int argc, char **argv)
}
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;
else if (std::strstr (argv[i] + strlen (GET_CODE_ADDRESS_PREFIX), "swap_chars"))
func_p = swap_chars;
pthread_mutex_lock (&g_print_mutex);
printf ("code address: %p\n", func_p);
@ -290,6 +313,8 @@ int main (int argc, char **argv)
// Defaut to providing the address of main.
if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "hello") == 0)
hello();
else if (std::strcmp (argv[i] + strlen (CALL_FUNCTION_PREFIX), "swap_chars") == 0)
swap_chars();
else
{
pthread_mutex_lock (&g_print_mutex);