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)
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