Example #1
0
    def breakpoint_set_and_remove_work(self, want_hardware):
        # 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.add_register_info_collection_packets()
        self.add_process_info_collection_packets()
        self.test_sequence.add_log_lines(
            [  # Start running after initial stop.
                "read packet: $c#63",
                # 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":
                    self.maybe_strict_output_regex(
                        r"code address: 0x([0-9a-fA-F]+)\r\n"),
                    "capture": {
                        1: "function_address"
                    }
                },
                # Now stop the inferior.
                "read packet: {}".format(chr(3)),
                # 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)

        # Gather process info - we need endian of target to handle register
        # value conversions.
        process_info = self.parse_process_info_response(context)
        endian = process_info.get("endian")
        self.assertIsNotNone(endian)

        # Gather register info entries.
        reg_infos = self.parse_register_info_packets(context)
        (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)
        self.assertIsNotNone(pc_lldb_reg_index)
        self.assertIsNotNone(pc_reg_info)

        # Grab the function address.
        self.assertIsNotNone(context.get("function_address"))
        function_address = int(context.get("function_address"), 16)

        # Get current target architecture
        target_arch = self.getArchitecture()

        # Set the breakpoint.
        if (target_arch == "arm") or (target_arch == "aarch64"):
            # TODO: Handle case when setting breakpoint in thumb code
            BREAKPOINT_KIND = 4
        else:
            BREAKPOINT_KIND = 1

        # Set default packet type to Z0 (software breakpoint)
        z_packet_type = 0

        # If hardware breakpoint is requested set packet type to Z1
        if want_hardware == True:
            z_packet_type = 1

        self.reset_test_sequence()
        self.add_set_breakpoint_packets(function_address,
                                        z_packet_type,
                                        do_continue=True,
                                        breakpoint_kind=BREAKPOINT_KIND)

        # 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.assertEqual(int(stop_signo, 16),
                         lldbutil.get_signal_number('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.assertEqual(len(context["O_content"]), 0)

        # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.
        # This acts as a another validation on the register reading code.
        self.reset_test_sequence()
        self.test_sequence.add_log_lines(
            [
                # Print the PC.  This should match the breakpoint address.
                "read packet: $p{0:x}#00".format(pc_lldb_reg_index),
                # Capture $p results.
                {
                    "direction": "send",
                    "regex": r"^\$([0-9a-fA-F]+)#",
                    "capture": {
                        1: "p_response"
                    }
                },
            ],
            True)

        context = self.expect_gdbremote_sequence()
        self.assertIsNotNone(context)

        # Verify the PC is where we expect.  Note response is in endianness of
        # the inferior.
        p_response = context.get("p_response")
        self.assertIsNotNone(p_response)

        # Convert from target endian to int.
        returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(
            endian, p_response)
        self.assertEqual(returned_pc, function_address)

        # Verify that a breakpoint remove and continue gets us the expected
        # output.
        self.reset_test_sequence()

        # Add breakpoint remove packets
        self.add_remove_breakpoint_packets(function_address,
                                           z_packet_type,
                                           breakpoint_kind=BREAKPOINT_KIND)

        self.test_sequence.add_log_lines(
            [
                # Continue running.
                "read packet: $c#63",
                # 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(.*)#[0-9a-fA-F]{2}$"
                },
            ],
            True)

        context = self.expect_gdbremote_sequence()
        self.assertIsNotNone(context)
Example #2
0
    def test_P_and_p_thread_suffix_work(self):
        self.build()
        self.set_inferior_startup_launch()

        # Startup the inferior with three threads.
        procs = self.prep_debug_monitor_and_inferior(
            inferior_args=["thread:new", "thread:new"])
        self.add_thread_suffix_request_packets()
        self.add_register_info_collection_packets()
        self.add_process_info_collection_packets()

        context = self.expect_gdbremote_sequence()
        self.assertIsNotNone(context)

        process_info = self.parse_process_info_response(context)
        self.assertIsNotNone(process_info)
        endian = process_info.get("endian")
        self.assertIsNotNone(endian)

        reg_infos = self.parse_register_info_packets(context)
        self.assertIsNotNone(reg_infos)
        self.add_lldb_register_index(reg_infos)

        reg_index = self.select_modifiable_register(reg_infos)
        self.assertIsNotNone(reg_index)
        reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8
        self.assertTrue(reg_byte_size > 0)

        # Run the process a bit so threads can start up, and collect register
        # info.
        context = self.run_process_then_stop(run_seconds=1)
        self.assertIsNotNone(context)

        # Wait for 3 threads to be present.
        threads = self.wait_for_thread_count(3)
        self.assertEqual(len(threads), 3)

        expected_reg_values = []
        register_increment = 1
        next_value = None

        # Set the same register in each of 3 threads to a different value.
        # Verify each one has the unique value.
        for thread in threads:
            # If we don't have a next value yet, start it with the initial read
            # value + 1
            if not next_value:
                # Read pre-existing register value.
                self.reset_test_sequence()
                self.test_sequence.add_log_lines([
                    "read packet: $p{0:x};thread:{1:x}#00".format(
                        reg_index, thread),
                    {
                        "direction": "send",
                        "regex": r"^\$([0-9a-fA-F]+)#",
                        "capture": {
                            1: "p_response"
                        }
                    },
                ], True)
                context = self.expect_gdbremote_sequence()
                self.assertIsNotNone(context)

                # Set the next value to use for writing as the increment plus
                # current value.
                p_response = context.get("p_response")
                self.assertIsNotNone(p_response)
                next_value = lldbgdbserverutils.unpack_register_hex_unsigned(
                    endian, p_response)

            # Set new value using P and thread suffix.
            self.reset_test_sequence()
            self.test_sequence.add_log_lines([
                "read packet: $P{0:x}={1};thread:{2:x}#00".format(
                    reg_index,
                    lldbgdbserverutils.pack_register_hex(
                        endian, next_value, byte_size=reg_byte_size), thread),
                "send packet: $OK#00",
            ], True)
            context = self.expect_gdbremote_sequence()
            self.assertIsNotNone(context)

            # Save the value we set.
            expected_reg_values.append(next_value)

            # Increment value for next thread to use (we want them all
            # different so we can verify they wrote to each thread correctly
            # next.)
            next_value += register_increment

        # Revisit each thread and verify they have the expected value set for
        # the register we wrote.
        thread_index = 0
        for thread in threads:
            # Read pre-existing register value.
            self.reset_test_sequence()
            self.test_sequence.add_log_lines([
                "read packet: $p{0:x};thread:{1:x}#00".format(
                    reg_index, thread),
                {
                    "direction": "send",
                    "regex": r"^\$([0-9a-fA-F]+)#",
                    "capture": {
                        1: "p_response"
                    }
                },
            ], True)
            context = self.expect_gdbremote_sequence()
            self.assertIsNotNone(context)

            # Get the register value.
            p_response = context.get("p_response")
            self.assertIsNotNone(p_response)
            read_value = lldbgdbserverutils.unpack_register_hex_unsigned(
                endian, p_response)

            # Make sure we read back what we wrote.
            self.assertEqual(read_value, expected_reg_values[thread_index])
            thread_index += 1