def signal_two_signals(self): threads = self.start_threads(1) # try sending two different signals to two threads self.test_sequence.add_log_lines([ "read packet: $vCont;C{0:x}:{1:x};C{2:x}:{3:x}#00".format( lldbutil.get_signal_number('SIGUSR1'), threads[0], lldbutil.get_signal_number('SIGUSR2'), threads[1]), {"direction": "send", "regex": r"^\$E1e#db$"}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context)
def test_signal_process_without_tid(self): self.build() self.set_inferior_startup_launch() threads = self.start_threads(1) self.send_and_check_signal( "C{0:x}".format(lldbutil.get_signal_number('SIGUSR1')), threads)
def test_signal_minus_one(self): self.build() self.set_inferior_startup_launch() threads = self.start_threads(1) self.send_and_check_signal( "C{0:x}:-1".format(lldbutil.get_signal_number('SIGUSR1')), threads)
def test_inferior_seg_fault_received(self): self.build() if self.platformIsDarwin(): self.inferior_seg_fault_received( self.GDB_REMOTE_STOP_CODE_BAD_ACCESS) else: self.inferior_seg_fault_received( lldbutil.get_signal_number('SIGSEGV'))
def test_signal_one_thread(self): self.build() self.set_inferior_startup_launch() threads = self.start_threads(1) # try sending a signal to one of the two threads self.send_and_check_signal( "C{0:x}:{1:x};c".format(lldbutil.get_signal_number('SIGUSR1')), threads[:1])
def test_signal_all_threads(self): self.build() self.set_inferior_startup_launch() threads = self.start_threads(1) # try sending a signal to two threads (= the process) self.send_and_check_signal( "C{0:x}:{1:x};C{0:x}:{2:x}".format( lldbutil.get_signal_number('SIGUSR1'), *threads), threads)
def test_default_signals_behavior(self): self.build() self.set_inferior_startup_launch() procs = self.prep_debug_monitor_and_inferior() expected_signals = ["SIGSEGV", "SIGUSR1", "SIGUSR2", "SIGALRM", "SIGFPE", "SIGBUS", "SIGINT", "SIGHUP"] for signal_name in expected_signals: signo = lldbutil.get_signal_number(signal_name) self.expect_signal(signo) self.expect_exit_code(0)
def test_Hc_then_Csignal_signals_correct_thread_launch(self): self.build() self.set_inferior_startup_launch() if self.platformIsDarwin(): # Darwin debugserver translates some signals like SIGSEGV into some gdb # expectations about fixed signal numbers. self.Hc_then_Csignal_signals_correct_thread(self.TARGET_EXC_BAD_ACCESS) else: self.Hc_then_Csignal_signals_correct_thread( lldbutil.get_signal_number('SIGSEGV'))
def signal_one_thread(self): threads = self.start_threads(1) # try sending a signal to one of the two threads self.test_sequence.add_log_lines([ "read packet: $vCont;C{0:x}:{1:x};c#00".format( lldbutil.get_signal_number('SIGUSR1'), threads[0]), {"direction": "send", "regex": r"^\$W00#b7$"}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context)
def test_default_signals_behavior(self): self.init_llgs_test() self.build() self.set_inferior_startup_launch() procs = self.prep_debug_monitor_and_inferior() expected_signals = ["SIGSEGV", "SIGUSR1", "SIGUSR2", "SIGALRM", "SIGFPE", "SIGBUS", "SIGINT", "SIGHUP"] for signal_name in expected_signals: signo = lldbutil.get_signal_number(signal_name) self.expect_signal(signo) self.expect_exit_code(0)
def test_q_pass_signals(self): self.build() self.set_inferior_startup_launch() procs = self.prep_debug_monitor_and_inferior() expected_signals = ["SIGSEGV", "SIGALRM", "SIGFPE", "SIGBUS", "SIGINT", "SIGHUP"] signals_to_ignore = ["SIGUSR1", "SIGUSR2"] self.ignore_signals(signals_to_ignore) for signal_name in expected_signals: signo = lldbutil.get_signal_number(signal_name) self.expect_signal(signo) self.expect_exit_code(len(signals_to_ignore))
def signal_two_of_three_threads(self): threads = self.start_threads(2) # try sending a signal to 2 out of 3 threads self.test_sequence.add_log_lines([ "read packet: $vCont;C{0:x}:{1:x};C{0:x}:{2:x};c#00".format( lldbutil.get_signal_number('SIGUSR1'), threads[1], threads[2]), {"direction": "send", "regex": r"^\$E1e#db$"}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context)
def test_signal_all_threads(self): self.build() self.set_inferior_startup_launch() threads = self.start_threads(1) # try sending a signal to two threads (= the process) self.test_sequence.add_log_lines([ "read packet: $vCont;C{0:x}:{1:x};C{0:x}:{2:x}#00".format( lldbutil.get_signal_number('SIGUSR1'), threads[0], threads[1]), {"direction": "send", "regex": r"^\$W00#b7$"}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context)
def test_change_signals_at_runtime(self): self.init_llgs_test() self.build() self.set_inferior_startup_launch() procs = self.prep_debug_monitor_and_inferior() expected_signals = ["SIGSEGV", "SIGUSR1", "SIGUSR2", "SIGALRM", "SIGHUP"] signals_to_ignore = ["SIGFPE", "SIGBUS", "SIGINT"] for signal_name in expected_signals: signo = lldbutil.get_signal_number(signal_name) self.expect_signal(signo) if signal_name == "SIGALRM": self.ignore_signals(signals_to_ignore) self.expect_exit_code(len(signals_to_ignore))
def inferior_abort_received(self): procs = self.prep_debug_monitor_and_inferior(inferior_args=["abort"]) self.assertIsNotNone(procs) self.test_sequence.add_log_lines([ "read packet: $vCont;c#a8", {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture":{ 1:"hex_exit_code"} }, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) hex_exit_code = context.get("hex_exit_code") self.assertIsNotNone(hex_exit_code) self.assertEqual(int(hex_exit_code, 16), lldbutil.get_signal_number('SIGABRT'))
def run_and_check_name(self, expected_name): self.test_sequence.add_log_lines(["read packet: $vCont;c#a8", {"direction": "send", "regex": r"^\$T([0-9a-fA-F]{2})([^#]+)#[0-9a-fA-F]{2}$", "capture": { 1: "signal", 2: "key_vals_text"}}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) sigint = lldbutil.get_signal_number("SIGINT") self.assertEqual(sigint, int(context.get("signal"), 16)) kv_dict = self.parse_key_val_dict(context.get("key_vals_text")) self.assertEqual(expected_name, kv_dict.get("name"))
def inferior_abort_received(self): procs = self.prep_debug_monitor_and_inferior(inferior_args=["abort"]) self.assertIsNotNone(procs) self.test_sequence.add_log_lines(["read packet: $vCont;c#a8", {"direction": "send", "regex": r"^\$T([0-9a-fA-F]{2}).*#[0-9a-fA-F]{2}$", "capture": {1: "hex_exit_code"}}, ], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) hex_exit_code = context.get("hex_exit_code") self.assertIsNotNone(hex_exit_code) self.assertEqual(int(hex_exit_code, 16), lldbutil.get_signal_number('SIGABRT'))
def signal_name_to_hex(signame): return format(lldbutil.get_signal_number(signame), 'x')
def test_inferior_seg_fault_received_llgs(self): self.build() self.inferior_seg_fault_received(lldbutil.get_signal_number('SIGSEGV'))
def test_with_run_command(self): """Test that lldb command 'process signal SIGUSR1' sends a signal to the inferior process.""" self.build() exe = self.getBuildArtifact("a.out") # Create a target by the debugger. target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Now create a breakpoint on main.c by name 'c'. breakpoint = target.BreakpointCreateByLocation('main.c', self.line) self.assertTrue(breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT) # Get the breakpoint location from breakpoint after we verified that, # indeed, it has one location. location = breakpoint.GetLocationAtIndex(0) self.assertTrue(location and location.IsEnabled(), VALID_BREAKPOINT_LOCATION) # Now launch the process, no arguments & do not stop at entry point. launch_info = target.GetLaunchInfo() launch_info.SetWorkingDirectory(self.get_process_working_directory()) process_listener = lldb.SBListener("signal_test_listener") launch_info.SetListener(process_listener) error = lldb.SBError() process = target.Launch(launch_info, error) self.assertTrue(process, PROCESS_IS_VALID) self.runCmd("process handle -n False -p True -s True SIGUSR1") thread = lldbutil.get_stopped_thread( process, lldb.eStopReasonBreakpoint) self.assertTrue(thread.IsValid(), "We hit the first breakpoint.") # After resuming the process, send it a SIGUSR1 signal. self.setAsync(True) self.assertTrue( process_listener.IsValid(), "Got a good process listener") # Disable our breakpoint, we don't want to hit it anymore... breakpoint.SetEnabled(False) # Now continue: process.Continue() # If running remote test, there should be a connected event if lldb.remote_platform: self.match_state(process_listener, lldb.eStateConnected) self.match_state(process_listener, lldb.eStateRunning) # Now signal the process, and make sure it stops: process.Signal(lldbutil.get_signal_number('SIGUSR1')) self.match_state(process_listener, lldb.eStateStopped) # Now make sure the thread was stopped with a SIGUSR1: threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonSignal) self.assertEquals(len(threads), 1, "One thread stopped for a signal.") thread = threads[0] self.assertTrue( thread.GetStopReasonDataCount() >= 1, "There was data in the event.") self.assertTrue( thread.GetStopReasonDataAtIndex(0) == lldbutil.get_signal_number('SIGUSR1'), "The stop signal was SIGUSR1")
def test_inferior_seg_fault_received_llgs(self): self.init_llgs_test() self.build() self.inferior_seg_fault_received(lldbutil.get_signal_number('SIGSEGV'))
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_with_run_command(self): """Test that lldb command 'process signal SIGUSR1' sends a signal to the inferior process.""" self.build() exe = os.path.join(os.getcwd(), "a.out") # Create a target by the debugger. target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Now create a breakpoint on main.c by name 'c'. breakpoint = target.BreakpointCreateByLocation('main.c', self.line) self.assertTrue(breakpoint and breakpoint.GetNumLocations() == 1, VALID_BREAKPOINT) # Get the breakpoint location from breakpoint after we verified that, # indeed, it has one location. location = breakpoint.GetLocationAtIndex(0) self.assertTrue(location and location.IsEnabled(), VALID_BREAKPOINT_LOCATION) # Now launch the process, no arguments & do not stop at entry point. launch_info = lldb.SBLaunchInfo([exe]) launch_info.SetWorkingDirectory(self.get_process_working_directory()) process_listener = lldb.SBListener("signal_test_listener") launch_info.SetListener(process_listener) error = lldb.SBError() process = target.Launch(launch_info, error) self.assertTrue(process, PROCESS_IS_VALID) self.runCmd("process handle -n False -p True -s True SIGUSR1") thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint) self.assertTrue(thread.IsValid(), "We hit the first breakpoint.") # After resuming the process, send it a SIGUSR1 signal. self.setAsync(True) self.assertTrue(process_listener.IsValid(), "Got a good process listener") # Disable our breakpoint, we don't want to hit it anymore... breakpoint.SetEnabled(False) # Now continue: process.Continue() # If running remote test, there should be a connected event if lldb.remote_platform: self.match_state(process_listener, lldb.eStateConnected) self.match_state(process_listener, lldb.eStateRunning) # Now signal the process, and make sure it stops: process.Signal(lldbutil.get_signal_number('SIGUSR1')) self.match_state(process_listener, lldb.eStateStopped) # Now make sure the thread was stopped with a SIGUSR1: threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonSignal) self.assertTrue(len(threads) == 1, "One thread stopped for a signal.") thread = threads[0] self.assertTrue(thread.GetStopReasonDataCount() >= 1, "There was data in the event.") self.assertTrue(thread.GetStopReasonDataAtIndex(0) == lldbutil.get_signal_number('SIGUSR1'), "The stop signal was SIGUSR1")
def Hc_then_Csignal_signals_correct_thread(self, segfault_signo): # NOTE only run this one in inferior-launched mode: we can't grab inferior stdout when running attached, # and the test requires getting stdout from the exe. NUM_THREADS = 3 # Startup the inferior with three threads (main + NUM_THREADS-1 worker threads). # inferior_args=["thread:print-ids"] inferior_args = ["thread:segfault"] for i in range(NUM_THREADS - 1): # if i > 0: # Give time between thread creation/segfaulting for the handler to work. # inferior_args.append("sleep:1") inferior_args.append("thread:new") inferior_args.append("sleep:10") # Launch/attach. (In our case, this should only ever be launched since # we need inferior stdout/stderr). procs = self.prep_debug_monitor_and_inferior( inferior_args=inferior_args) self.test_sequence.add_log_lines(["read packet: $c#63"], True) context = self.expect_gdbremote_sequence() # Let the inferior process have a few moments to start up the thread when launched. # context = self.run_process_then_stop(run_seconds=1) # Wait at most x seconds for all threads to be present. # threads = self.wait_for_thread_count(NUM_THREADS) # self.assertEquals(len(threads), NUM_THREADS) signaled_tids = {} print_thread_ids = {} # Switch to each thread, deliver a signal, and verify signal delivery for i in range(NUM_THREADS - 1): # Run until SIGSEGV comes in. self.reset_test_sequence() self.test_sequence.add_log_lines([{ "direction": "send", "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture": { 1: "signo", 2: "thread_id" } }], True) context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) signo = context.get("signo") self.assertEqual(int(signo, 16), segfault_signo) # Ensure we haven't seen this tid yet. thread_id = int(context.get("thread_id"), 16) self.assertFalse(thread_id in signaled_tids) signaled_tids[thread_id] = 1 # Send SIGUSR1 to the thread that signaled the SIGSEGV. self.reset_test_sequence() self.test_sequence.add_log_lines( [ # Set the continue thread. # Set current thread. "read packet: $Hc{0:x}#00".format(thread_id), "send packet: $OK#00", # Continue sending the signal number to the continue thread. # The commented out packet is a way to do this same operation without using # a $Hc (but this test is testing $Hc, so we'll stick with the former). "read packet: $C{0:x}#00".format( lldbutil.get_signal_number('SIGUSR1')), # "read packet: $vCont;C{0:x}:{1:x};c#00".format(lldbutil.get_signal_number('SIGUSR1'), thread_id), # FIXME: Linux does not report the thread stop on the delivered signal (SIGUSR1 here). MacOSX debugserver does. # But MacOSX debugserver isn't guaranteeing the thread the signal handler runs on, so currently its an XFAIL. # Need to rectify behavior here. The linux behavior is more intuitive to me since we're essentially swapping out # an about-to-be-delivered signal (for which we already sent a stop packet) to a different signal. # {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} }, # "read packet: $c#63", { "type": "output_match", "regex": r"^received SIGUSR1 on thread id: ([0-9a-fA-F]+)\r\nthread ([0-9a-fA-F]+): past SIGSEGV\r\n", "capture": { 1: "print_thread_id", 2: "post_handle_thread_id" } }, ], True) # Run the sequence. context = self.expect_gdbremote_sequence() self.assertIsNotNone(context) # Ensure the stop signal is the signal we delivered. # stop_signo = context.get("stop_signo") # self.assertIsNotNone(stop_signo) # self.assertEquals(int(stop_signo,16), lldbutil.get_signal_number('SIGUSR1')) # Ensure the stop thread is the thread to which we delivered the signal. # stop_thread_id = context.get("stop_thread_id") # self.assertIsNotNone(stop_thread_id) # self.assertEquals(int(stop_thread_id,16), thread_id) # Ensure we haven't seen this thread id yet. The inferior's # self-obtained thread ids are not guaranteed to match the stub # tids (at least on MacOSX). print_thread_id = context.get("print_thread_id") self.assertIsNotNone(print_thread_id) print_thread_id = int(print_thread_id, 16) self.assertFalse(print_thread_id in print_thread_ids) # Now remember this print (i.e. inferior-reflected) thread id and # ensure we don't hit it again. print_thread_ids[print_thread_id] = 1 # Ensure post signal-handle thread id matches the thread that # initially raised the SIGSEGV. post_handle_thread_id = context.get("post_handle_thread_id") self.assertIsNotNone(post_handle_thread_id) post_handle_thread_id = int(post_handle_thread_id, 16) self.assertEqual(post_handle_thread_id, print_thread_id)