1092 lines · python
1"""2Test case for testing the gdbremote protocol.3 4Tests run against debugserver and lldb-server (llgs).5lldb-server tests run where the lldb-server exe is6available.7 8This class will be broken into smaller test case classes by9gdb remote packet functional areas. For now it contains10the initial set of tests implemented.11"""12 13import binascii14import itertools15import struct16 17import gdbremote_testcase18import lldbgdbserverutils19from lldbsuite.support import seven20from lldbsuite.test.decorators import *21from lldbsuite.test.lldbtest import *22from lldbsuite.test.lldbdwarf import *23from lldbsuite.test import lldbutil, lldbplatformutil24 25# On Linux systems with Yama ptrace_scope = 1 there is a race condition when the26# debugee enables tracing. See https://github.com/llvm/llvm-project/issues/161510.27@skipIfLinux28class LldbGdbServerTestCase(29 gdbremote_testcase.GdbRemoteTestCaseBase, DwarfOpcodeParser30):31 def test_thread_suffix_supported(self):32 server = self.connect_to_debug_monitor()33 self.assertIsNotNone(server)34 35 self.do_handshake()36 self.test_sequence.add_log_lines(37 [38 "lldb-server < 26> read packet: $QThreadSuffixSupported#e4",39 "lldb-server < 6> send packet: $OK#9a",40 ],41 True,42 )43 44 self.expect_gdbremote_sequence()45 46 def test_list_threads_in_stop_reply_supported(self):47 server = self.connect_to_debug_monitor()48 self.assertIsNotNone(server)49 50 self.do_handshake()51 self.test_sequence.add_log_lines(52 [53 "lldb-server < 27> read packet: $QListThreadsInStopReply#21",54 "lldb-server < 6> send packet: $OK#9a",55 ],56 True,57 )58 self.expect_gdbremote_sequence()59 60 def test_c_packet_works(self):61 self.build()62 procs = self.prep_debug_monitor_and_inferior()63 self.test_sequence.add_log_lines(64 ["read packet: $c#63", "send packet: $W00#00"], True65 )66 67 self.expect_gdbremote_sequence()68 69 @skipIfWindows # No pty support to test any inferior output70 def test_inferior_print_exit(self):71 self.build()72 procs = self.prep_debug_monitor_and_inferior(inferior_args=["hello, world"])73 self.test_sequence.add_log_lines(74 [75 "read packet: $vCont;c#a8",76 {77 "type": "output_match",78 "regex": self.maybe_strict_output_regex(r"hello, world\r\n"),79 },80 "send packet: $W00#00",81 ],82 True,83 )84 85 context = self.expect_gdbremote_sequence()86 self.assertIsNotNone(context)87 88 # Sometimes fails:89 # regex '^\$QC([0-9a-fA-F]+)#' failed to match against content '$E45#ae'90 # See https://github.com/llvm/llvm-project/issues/138085.91 @skipIfWindows92 def test_first_launch_stop_reply_thread_matches_first_qC(self):93 self.build()94 procs = self.prep_debug_monitor_and_inferior()95 self.test_sequence.add_log_lines(96 [97 "read packet: $qC#00",98 {99 "direction": "send",100 "regex": r"^\$QC([0-9a-fA-F]+)#",101 "capture": {1: "thread_id_QC"},102 },103 "read packet: $?#00",104 {105 "direction": "send",106 "regex": r"^\$T[0-9a-fA-F]{2}thread:([0-9a-fA-F]+)",107 "capture": {1: "thread_id_?"},108 },109 ],110 True,111 )112 context = self.expect_gdbremote_sequence()113 self.assertEqual(context.get("thread_id_QC"), context.get("thread_id_?"))114 115 # This test is flaky on Windows. Sometimes returns 'Exception 0x80000003'.116 @skipIf(oslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/138085")117 def test_attach_commandline_continue_app_exits(self):118 self.build()119 self.set_inferior_startup_attach()120 procs = self.prep_debug_monitor_and_inferior()121 self.test_sequence.add_log_lines(122 ["read packet: $vCont;c#a8", "send packet: $W00#00"], True123 )124 self.expect_gdbremote_sequence()125 126 # Wait a moment for completed and now-detached inferior process to127 # clear.128 time.sleep(1)129 130 if not lldb.remote_platform:131 # Process should be dead now. Reap results.132 poll_result = procs["inferior"].poll()133 self.assertIsNotNone(poll_result)134 135 # Where possible, verify at the system level that the process is not136 # running.137 self.assertFalse(138 lldbgdbserverutils.process_is_running(procs["inferior"].pid, False)139 )140 141 def qThreadInfo_contains_thread(self):142 procs = self.prep_debug_monitor_and_inferior()143 self.add_threadinfo_collection_packets()144 145 # Run the packet stream.146 context = self.expect_gdbremote_sequence()147 self.assertIsNotNone(context)148 149 # Gather threadinfo entries.150 threads = self.parse_threadinfo_packets(context)151 self.assertIsNotNone(threads)152 153 # We should have exactly one thread.154 self.assertEqual(len(threads), 1)155 156 def test_qThreadInfo_contains_thread_launch(self):157 self.build()158 self.set_inferior_startup_launch()159 self.qThreadInfo_contains_thread()160 161 @expectedFailureAll(oslist=["windows"]) # expect one more thread stopped162 def test_qThreadInfo_contains_thread_attach(self):163 self.build()164 self.set_inferior_startup_attach()165 self.qThreadInfo_contains_thread()166 167 def qThreadInfo_matches_qC(self):168 procs = self.prep_debug_monitor_and_inferior()169 170 self.add_threadinfo_collection_packets()171 self.test_sequence.add_log_lines(172 [173 "read packet: $qC#00",174 {175 "direction": "send",176 "regex": r"^\$QC([0-9a-fA-F]+)#",177 "capture": {1: "thread_id"},178 },179 ],180 True,181 )182 183 # Run the packet stream.184 context = self.expect_gdbremote_sequence()185 self.assertIsNotNone(context)186 187 # Gather threadinfo entries.188 threads = self.parse_threadinfo_packets(context)189 self.assertIsNotNone(threads)190 191 # We should have exactly one thread from threadinfo.192 self.assertEqual(len(threads), 1)193 194 # We should have a valid thread_id from $QC.195 QC_thread_id_hex = context.get("thread_id")196 self.assertIsNotNone(QC_thread_id_hex)197 QC_thread_id = int(QC_thread_id_hex, 16)198 199 # Those two should be the same.200 self.assertEqual(threads[0], QC_thread_id)201 202 def test_qThreadInfo_matches_qC_launch(self):203 self.build()204 self.set_inferior_startup_launch()205 self.qThreadInfo_matches_qC()206 207 # This test is flaky on AArch64 Linux. Sometimes it causes an unhandled Error:208 # Operation not permitted in lldb_private::process_linux::NativeProcessLinux::Attach(int).209 @skipIf(210 oslist=["linux"],211 archs=["aarch64"],212 bugnumber="github.com/llvm/llvm-project/issues/138085",213 )214 @expectedFailureAll(oslist=["windows"]) # expect one more thread stopped215 def test_qThreadInfo_matches_qC_attach(self):216 self.build()217 self.set_inferior_startup_attach()218 self.qThreadInfo_matches_qC()219 220 def test_p_returns_correct_data_size_for_each_qRegisterInfo_launch(self):221 self.build()222 self.set_inferior_startup_launch()223 procs = self.prep_debug_monitor_and_inferior()224 self.add_register_info_collection_packets()225 226 # Run the packet stream.227 context = self.expect_gdbremote_sequence()228 self.assertIsNotNone(context)229 230 # Gather register info entries.231 reg_infos = self.parse_register_info_packets(context)232 self.assertIsNotNone(reg_infos)233 self.assertGreater(len(reg_infos), 0)234 235 byte_order = self.get_target_byte_order()236 237 # Read value for each register.238 reg_index = 0239 for reg_info in reg_infos:240 # Skip registers that don't have a register set. For x86, these are241 # the DRx registers, which have no LLDB-kind register number and thus242 # cannot be read via normal243 # NativeRegisterContext::ReadRegister(reg_info,...) calls.244 if not "set" in reg_info:245 continue246 247 # Clear existing packet expectations.248 self.reset_test_sequence()249 250 # Run the register query251 self.test_sequence.add_log_lines(252 [253 "read packet: $p{0:x}#00".format(reg_index),254 {255 "direction": "send",256 "regex": r"^\$([0-9a-fA-F]+)#",257 "capture": {1: "p_response"},258 },259 ],260 True,261 )262 context = self.expect_gdbremote_sequence()263 self.assertIsNotNone(context)264 265 # Verify the response length.266 p_response = context.get("p_response")267 self.assertIsNotNone(p_response)268 269 # Skip erraneous (unsupported) registers.270 # TODO: remove this once we make unsupported registers disappear.271 if p_response.startswith("E") and len(p_response) == 3:272 continue273 274 if "dynamic_size_dwarf_expr_bytes" in reg_info:275 self.updateRegInfoBitsize(reg_info, byte_order)276 self.assertEqual(277 len(p_response), 2 * int(reg_info["bitsize"]) / 8, reg_info278 )279 280 # Increment loop281 reg_index += 1282 283 def Hg_switches_to_3_threads(self, pass_pid=False):284 _, threads = self.launch_with_threads(3)285 286 pid_str = ""287 if pass_pid:288 pid_str = "p{0:x}.".format(procs["inferior"].pid)289 290 # verify we can $H to each thead, and $qC matches the thread we set.291 for thread in threads:292 # Change to each thread, verify current thread id.293 self.reset_test_sequence()294 self.test_sequence.add_log_lines(295 [296 "read packet: $Hg{0}{1:x}#00".format(297 pid_str, thread298 ), # Set current thread.299 "send packet: $OK#00",300 "read packet: $qC#00",301 {302 "direction": "send",303 "regex": r"^\$QC([0-9a-fA-F]+)#",304 "capture": {1: "thread_id"},305 },306 ],307 True,308 )309 310 context = self.expect_gdbremote_sequence()311 self.assertIsNotNone(context)312 313 # Verify the thread id.314 self.assertIsNotNone(context.get("thread_id"))315 self.assertEqual(int(context.get("thread_id"), 16), thread)316 317 # This test is flaky on Windows. Sometimes returns '$E37#af'.318 @skipIf(oslist=["windows"], bugnumber="github.com/llvm/llvm-project/issues/138085")319 @skipIf(compiler="clang", compiler_version=["<", "11.0"])320 def test_Hg_switches_to_3_threads_launch(self):321 self.build()322 self.set_inferior_startup_launch()323 self.Hg_switches_to_3_threads()324 325 def Hg_fails_on_pid(self, pass_pid):326 _, threads = self.launch_with_threads(2)327 328 if pass_pid == -1:329 pid_str = "p-1."330 else:331 pid_str = "p{0:x}.".format(pass_pid)332 thread = threads[1]333 334 self.test_sequence.add_log_lines(335 [336 "read packet: $Hg{0}{1:x}#00".format(337 pid_str, thread338 ), # Set current thread.339 "send packet: $Eff#00",340 ],341 True,342 )343 344 self.expect_gdbremote_sequence()345 346 @add_test_categories(["llgs"])347 def test_Hg_fails_on_another_pid(self):348 self.build()349 self.set_inferior_startup_launch()350 self.Hg_fails_on_pid(1)351 352 @add_test_categories(["llgs"])353 def test_Hg_fails_on_zero_pid(self):354 self.build()355 self.set_inferior_startup_launch()356 self.Hg_fails_on_pid(0)357 358 @add_test_categories(["llgs"])359 @skipIfWindows # Sometimes returns '$E37'.360 def test_Hg_fails_on_minus_one_pid(self):361 self.build()362 self.set_inferior_startup_launch()363 self.Hg_fails_on_pid(-1)364 365 def Hc_then_Csignal_signals_correct_thread(self, segfault_signo):366 # NOTE only run this one in inferior-launched mode: we can't grab inferior stdout when running attached,367 # and the test requires getting stdout from the exe.368 369 NUM_THREADS = 3370 371 # Startup the inferior with three threads (main + NUM_THREADS-1 worker threads).372 # inferior_args=["thread:print-ids"]373 inferior_args = ["thread:segfault"]374 for i in range(NUM_THREADS - 1):375 # if i > 0:376 # Give time between thread creation/segfaulting for the handler to work.377 # inferior_args.append("sleep:1")378 inferior_args.append("thread:new")379 inferior_args.append("sleep:10")380 381 # Launch/attach. (In our case, this should only ever be launched since382 # we need inferior stdout/stderr).383 procs = self.prep_debug_monitor_and_inferior(inferior_args=inferior_args)384 self.test_sequence.add_log_lines(["read packet: $c#63"], True)385 context = self.expect_gdbremote_sequence()386 387 signaled_tids = {}388 print_thread_ids = {}389 390 # Switch to each thread, deliver a signal, and verify signal delivery391 for i in range(NUM_THREADS - 1):392 # Run until SIGSEGV comes in.393 self.reset_test_sequence()394 self.test_sequence.add_log_lines(395 [396 {397 "direction": "send",398 "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",399 "capture": {1: "signo", 2: "thread_id"},400 }401 ],402 True,403 )404 405 context = self.expect_gdbremote_sequence()406 self.assertIsNotNone(context)407 signo = context.get("signo")408 self.assertEqual(int(signo, 16), segfault_signo)409 410 # Ensure we haven't seen this tid yet.411 thread_id = int(context.get("thread_id"), 16)412 self.assertNotIn(thread_id, signaled_tids)413 signaled_tids[thread_id] = 1414 415 # Send SIGUSR1 to the thread that signaled the SIGSEGV.416 self.reset_test_sequence()417 self.test_sequence.add_log_lines(418 [419 # Set the continue thread.420 # Set current thread.421 "read packet: $Hc{0:x}#00".format(thread_id),422 "send packet: $OK#00",423 # Continue sending the signal number to the continue thread.424 # The commented out packet is a way to do this same operation without using425 # a $Hc (but this test is testing $Hc, so we'll stick with the former).426 "read packet: $C{0:x}#00".format(427 lldbutil.get_signal_number("SIGUSR1")428 ),429 # "read packet: $vCont;C{0:x}:{1:x};c#00".format(lldbutil.get_signal_number('SIGUSR1'), thread_id),430 # FIXME: Linux does not report the thread stop on the delivered signal (SIGUSR1 here). MacOSX debugserver does.431 # But MacOSX debugserver isn't guaranteeing the thread the signal handler runs on, so currently its an XFAIL.432 # Need to rectify behavior here. The linux behavior is more intuitive to me since we're essentially swapping out433 # an about-to-be-delivered signal (for which we already sent a stop packet) to a different signal.434 # {"direction":"send", "regex":r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);", "capture":{1:"stop_signo", 2:"stop_thread_id"} },435 # "read packet: $c#63",436 {437 "type": "output_match",438 "regex": r"^received SIGUSR1 on thread id: ([0-9a-fA-F]+)\r\nthread ([0-9a-fA-F]+): past SIGSEGV\r\n",439 "capture": {1: "print_thread_id", 2: "post_handle_thread_id"},440 },441 ],442 True,443 )444 445 # Run the sequence.446 context = self.expect_gdbremote_sequence()447 self.assertIsNotNone(context)448 449 # Ensure the stop signal is the signal we delivered.450 # stop_signo = context.get("stop_signo")451 # self.assertIsNotNone(stop_signo)452 # self.assertEqual(int(stop_signo,16), lldbutil.get_signal_number('SIGUSR1'))453 454 # Ensure the stop thread is the thread to which we delivered the signal.455 # stop_thread_id = context.get("stop_thread_id")456 # self.assertIsNotNone(stop_thread_id)457 # self.assertEqual(int(stop_thread_id,16), thread_id)458 459 # Ensure we haven't seen this thread id yet. The inferior's460 # self-obtained thread ids are not guaranteed to match the stub461 # tids (at least on MacOSX).462 print_thread_id = context.get("print_thread_id")463 self.assertIsNotNone(print_thread_id)464 print_thread_id = int(print_thread_id, 16)465 self.assertNotIn(print_thread_id, print_thread_ids)466 467 # Now remember this print (i.e. inferior-reflected) thread id and468 # ensure we don't hit it again.469 print_thread_ids[print_thread_id] = 1470 471 # Ensure post signal-handle thread id matches the thread that472 # initially raised the SIGSEGV.473 post_handle_thread_id = context.get("post_handle_thread_id")474 self.assertIsNotNone(post_handle_thread_id)475 post_handle_thread_id = int(post_handle_thread_id, 16)476 self.assertEqual(post_handle_thread_id, print_thread_id)477 478 @expectedFailureDarwin479 @skipIfWindows # no SIGSEGV support480 @expectedFailureNetBSD481 def test_Hc_then_Csignal_signals_correct_thread_launch(self):482 self.build()483 self.set_inferior_startup_launch()484 485 if self.platformIsDarwin():486 # Darwin debugserver translates some signals like SIGSEGV into some gdb487 # expectations about fixed signal numbers.488 self.Hc_then_Csignal_signals_correct_thread(self.TARGET_EXC_BAD_ACCESS)489 else:490 self.Hc_then_Csignal_signals_correct_thread(491 lldbutil.get_signal_number("SIGSEGV")492 )493 494 @skipIfWindows # No pty support to test any inferior output495 def test_m_packet_reads_memory(self):496 self.build()497 self.set_inferior_startup_launch()498 # This is the memory we will write into the inferior and then ensure we499 # can read back with $m.500 MEMORY_CONTENTS = "Test contents 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"501 502 # Start up the inferior.503 procs = self.prep_debug_monitor_and_inferior(504 inferior_args=[505 "set-message:%s" % MEMORY_CONTENTS,506 "get-data-address-hex:g_message",507 "sleep:5",508 ]509 )510 511 # Run the process512 self.test_sequence.add_log_lines(513 [514 # Start running after initial stop.515 "read packet: $c#63",516 # Match output line that prints the memory address of the message buffer within the inferior.517 # Note we require launch-only testing so we can get inferior otuput.518 {519 "type": "output_match",520 "regex": self.maybe_strict_output_regex(521 r"data address: 0x([0-9a-fA-F]+)\r\n"522 ),523 "capture": {1: "message_address"},524 },525 # Now stop the inferior.526 "read packet: {}".format(chr(3)),527 # And wait for the stop notification.528 {529 "direction": "send",530 "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",531 "capture": {1: "stop_signo", 2: "stop_thread_id"},532 },533 ],534 True,535 )536 537 # Run the packet stream.538 context = self.expect_gdbremote_sequence()539 self.assertIsNotNone(context)540 541 # Grab the message address.542 self.assertIsNotNone(context.get("message_address"))543 message_address = int(context.get("message_address"), 16)544 545 # Grab contents from the inferior.546 self.reset_test_sequence()547 self.test_sequence.add_log_lines(548 [549 "read packet: $m{0:x},{1:x}#00".format(550 message_address, len(MEMORY_CONTENTS)551 ),552 {553 "direction": "send",554 "regex": r"^\$(.+)#[0-9a-fA-F]{2}$",555 "capture": {1: "read_contents"},556 },557 ],558 True,559 )560 561 # Run the packet stream.562 context = self.expect_gdbremote_sequence()563 self.assertIsNotNone(context)564 565 # Ensure what we read from inferior memory is what we wrote.566 self.assertIsNotNone(context.get("read_contents"))567 read_contents = seven.unhexlify(context.get("read_contents"))568 self.assertEqual(read_contents, MEMORY_CONTENTS)569 570 def breakpoint_set_and_remove_work(self, want_hardware):571 # Start up the inferior.572 procs = self.prep_debug_monitor_and_inferior(573 inferior_args=[574 "get-code-address-hex:hello",575 "sleep:1",576 "call-function:hello",577 ]578 )579 580 # Run the process581 self.add_register_info_collection_packets()582 self.add_process_info_collection_packets()583 self.test_sequence.add_log_lines(584 [ # Start running after initial stop.585 "read packet: $c#63",586 # Match output line that prints the memory address of the function call entry point.587 # Note we require launch-only testing so we can get inferior otuput.588 {589 "type": "output_match",590 "regex": self.maybe_strict_output_regex(591 r"code address: 0x([0-9a-fA-F]+)\r\n"592 ),593 "capture": {1: "function_address"},594 },595 # Now stop the inferior.596 "read packet: {}".format(chr(3)),597 # And wait for the stop notification.598 {599 "direction": "send",600 "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",601 "capture": {1: "stop_signo", 2: "stop_thread_id"},602 },603 ],604 True,605 )606 607 # Run the packet stream.608 context = self.expect_gdbremote_sequence()609 self.assertIsNotNone(context)610 611 # Gather process info - we need endian of target to handle register612 # value conversions.613 process_info = self.parse_process_info_response(context)614 endian = process_info.get("endian")615 self.assertIsNotNone(endian)616 617 # Gather register info entries.618 reg_infos = self.parse_register_info_packets(context)619 (pc_lldb_reg_index, pc_reg_info) = self.find_pc_reg_info(reg_infos)620 self.assertIsNotNone(pc_lldb_reg_index)621 self.assertIsNotNone(pc_reg_info)622 623 # Grab the function address.624 self.assertIsNotNone(context.get("function_address"))625 function_address = int(context.get("function_address"), 16)626 627 # Get current target architecture628 target_arch = self.getArchitecture()629 630 # Set the breakpoint.631 if target_arch in ["arm", "arm64", "aarch64"]:632 # TODO: Handle case when setting breakpoint in thumb code633 BREAKPOINT_KIND = 4634 else:635 BREAKPOINT_KIND = 1636 637 # Set default packet type to Z0 (software breakpoint)638 z_packet_type = 0639 640 # If hardware breakpoint is requested set packet type to Z1641 if want_hardware:642 z_packet_type = 1643 644 self.reset_test_sequence()645 self.add_set_breakpoint_packets(646 function_address,647 z_packet_type,648 do_continue=True,649 breakpoint_kind=BREAKPOINT_KIND,650 )651 652 # Run the packet stream.653 context = self.expect_gdbremote_sequence()654 self.assertIsNotNone(context)655 656 # Verify the stop signal reported was the breakpoint signal number.657 stop_signo = context.get("stop_signo")658 self.assertIsNotNone(stop_signo)659 self.assertEqual(int(stop_signo, 16), lldbutil.get_signal_number("SIGTRAP"))660 661 # Ensure we did not receive any output. If the breakpoint was not set, we would662 # see output (from a launched process with captured stdio) printing a hello, world message.663 # That would indicate the breakpoint didn't take.664 self.assertEqual(len(context["O_content"]), 0)665 666 # Verify that the PC for the main thread is where we expect it - right at the breakpoint address.667 # This acts as a another validation on the register reading code.668 self.reset_test_sequence()669 self.test_sequence.add_log_lines(670 [671 # Print the PC. This should match the breakpoint address.672 "read packet: $p{0:x}#00".format(pc_lldb_reg_index),673 # Capture $p results.674 {675 "direction": "send",676 "regex": r"^\$([0-9a-fA-F]+)#",677 "capture": {1: "p_response"},678 },679 ],680 True,681 )682 683 context = self.expect_gdbremote_sequence()684 self.assertIsNotNone(context)685 686 # Verify the PC is where we expect. Note response is in endianness of687 # the inferior.688 p_response = context.get("p_response")689 self.assertIsNotNone(p_response)690 691 # Convert from target endian to int.692 returned_pc = lldbgdbserverutils.unpack_register_hex_unsigned(693 endian, p_response694 )695 self.assertEqual(returned_pc, function_address)696 697 # Verify that a breakpoint remove and continue gets us the expected698 # output.699 self.reset_test_sequence()700 701 # Add breakpoint remove packets702 self.add_remove_breakpoint_packets(703 function_address, z_packet_type, breakpoint_kind=BREAKPOINT_KIND704 )705 706 self.test_sequence.add_log_lines(707 [708 # Continue running.709 "read packet: $c#63",710 # We should now receive the output from the call.711 {"type": "output_match", "regex": r"^hello, world\r\n$"},712 # And wait for program completion.713 {"direction": "send", "regex": r"^\$W00(.*)#[0-9a-fA-F]{2}$"},714 ],715 True,716 )717 718 context = self.expect_gdbremote_sequence()719 self.assertIsNotNone(context)720 721 @skipIfWindows # No pty support to test any inferior output722 def test_software_breakpoint_set_and_remove_work(self):723 if self.getArchitecture() == "arm":724 # TODO: Handle case when setting breakpoint in thumb code725 self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})726 else:727 self.build()728 self.set_inferior_startup_launch()729 self.breakpoint_set_and_remove_work(want_hardware=False)730 731 @skipUnlessPlatform(oslist=["linux"])732 @skipIf(archs=no_match(["arm$", "aarch64"]))733 def test_hardware_breakpoint_set_and_remove_work(self):734 if self.getArchitecture() == "arm":735 # TODO: Handle case when setting breakpoint in thumb code736 self.build(dictionary={"CFLAGS_EXTRAS": "-marm"})737 else:738 self.build()739 self.set_inferior_startup_launch()740 self.breakpoint_set_and_remove_work(want_hardware=True)741 742 @skipIfWindows # No pty support to test any inferior output743 def test_written_M_content_reads_back_correctly(self):744 self.build()745 self.set_inferior_startup_launch()746 747 TEST_MESSAGE = "Hello, memory"748 749 # Start up the stub and start/prep the inferior.750 procs = self.prep_debug_monitor_and_inferior(751 inferior_args=[752 "set-message:xxxxxxxxxxxxxX",753 "get-data-address-hex:g_message",754 "sleep:1",755 "print-message:",756 ]757 )758 self.test_sequence.add_log_lines(759 [760 # Start running after initial stop.761 "read packet: $c#63",762 # Match output line that prints the memory address of the message buffer within the inferior.763 # Note we require launch-only testing so we can get inferior otuput.764 {765 "type": "output_match",766 "regex": self.maybe_strict_output_regex(767 r"data address: 0x([0-9a-fA-F]+)\r\n"768 ),769 "capture": {1: "message_address"},770 },771 # Now stop the inferior.772 "read packet: {}".format(chr(3)),773 # And wait for the stop notification.774 {775 "direction": "send",776 "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",777 "capture": {1: "stop_signo", 2: "stop_thread_id"},778 },779 ],780 True,781 )782 context = self.expect_gdbremote_sequence()783 self.assertIsNotNone(context)784 785 # Grab the message address.786 self.assertIsNotNone(context.get("message_address"))787 message_address = int(context.get("message_address"), 16)788 789 # Hex-encode the test message, adding null termination.790 hex_encoded_message = seven.hexlify(TEST_MESSAGE)791 792 # Write the message to the inferior. Verify that we can read it with the hex-encoded (m)793 # and binary (x) memory read packets.794 self.reset_test_sequence()795 self.test_sequence.add_log_lines(796 [797 "read packet: $M{0:x},{1:x}:{2}#00".format(798 message_address, len(TEST_MESSAGE), hex_encoded_message799 ),800 "send packet: $OK#00",801 "read packet: $m{0:x},{1:x}#00".format(802 message_address, len(TEST_MESSAGE)803 ),804 "send packet: ${0}#00".format(hex_encoded_message),805 "read packet: $x{0:x},{1:x}#00".format(806 message_address, len(TEST_MESSAGE)807 ),808 "send packet: ${0}#00".format(TEST_MESSAGE),809 "read packet: $m{0:x},4#00".format(message_address),810 "send packet: ${0}#00".format(hex_encoded_message[0:8]),811 "read packet: $x{0:x},4#00".format(message_address),812 "send packet: ${0}#00".format(TEST_MESSAGE[0:4]),813 "read packet: $c#63",814 {815 "type": "output_match",816 "regex": r"^message: (.+)\r\n$",817 "capture": {1: "printed_message"},818 },819 "send packet: $W00#00",820 ],821 True,822 )823 context = self.expect_gdbremote_sequence()824 self.assertIsNotNone(context)825 826 # Ensure what we read from inferior memory is what we wrote.827 printed_message = context.get("printed_message")828 self.assertIsNotNone(printed_message)829 self.assertEqual(printed_message, TEST_MESSAGE + "X")830 831 # Note: as of this moment, a hefty number of the GPR writes are failing with E32 (everything except rax-rdx, rdi, rsi, rbp).832 # Come back to this. I have the test rigged to verify that at least some833 # of the bit-flip writes work.834 def test_P_writes_all_gpr_registers(self):835 self.build()836 self.set_inferior_startup_launch()837 838 # Start inferior debug session, grab all register info.839 procs = self.prep_debug_monitor_and_inferior(inferior_args=["sleep:2"])840 self.add_register_info_collection_packets()841 self.add_process_info_collection_packets()842 843 context = self.expect_gdbremote_sequence()844 self.assertIsNotNone(context)845 846 # Process register infos.847 reg_infos = self.parse_register_info_packets(context)848 self.assertIsNotNone(reg_infos)849 self.add_lldb_register_index(reg_infos)850 851 # Process endian.852 process_info = self.parse_process_info_response(context)853 endian = process_info.get("endian")854 self.assertIsNotNone(endian)855 856 # Pull out the register infos that we think we can bit flip857 # successfully,.858 gpr_reg_infos = [859 reg_info860 for reg_info in reg_infos861 if self.is_bit_flippable_register(reg_info)862 ]863 self.assertGreater(len(gpr_reg_infos), 0)864 865 # Write flipped bit pattern of existing value to each register.866 (successful_writes, failed_writes) = self.flip_all_bits_in_each_register_value(867 gpr_reg_infos, endian868 )869 self.trace(870 "successful writes: {}, failed writes: {}".format(871 successful_writes, failed_writes872 )873 )874 self.assertGreater(successful_writes, 0)875 876 # Note: as of this moment, a hefty number of the GPR writes are failing877 # with E32 (everything except rax-rdx, rdi, rsi, rbp).878 @skipIfWindows879 def test_P_and_p_thread_suffix_work(self):880 self.build()881 self.set_inferior_startup_launch()882 883 # Startup the inferior with three threads.884 _, threads = self.launch_with_threads(3)885 886 self.reset_test_sequence()887 self.add_thread_suffix_request_packets()888 self.add_register_info_collection_packets()889 self.add_process_info_collection_packets()890 891 context = self.expect_gdbremote_sequence()892 self.assertIsNotNone(context)893 894 process_info = self.parse_process_info_response(context)895 self.assertIsNotNone(process_info)896 endian = process_info.get("endian")897 self.assertIsNotNone(endian)898 899 reg_infos = self.parse_register_info_packets(context)900 self.assertIsNotNone(reg_infos)901 self.add_lldb_register_index(reg_infos)902 903 reg_index = self.select_modifiable_register(reg_infos)904 self.assertIsNotNone(reg_index)905 reg_byte_size = int(reg_infos[reg_index]["bitsize"]) // 8906 self.assertGreater(reg_byte_size, 0)907 908 expected_reg_values = []909 register_increment = 1910 next_value = None911 912 # Set the same register in each of 3 threads to a different value.913 # Verify each one has the unique value.914 for thread in threads:915 # If we don't have a next value yet, start it with the initial read916 # value + 1917 if not next_value:918 # Read pre-existing register value.919 self.reset_test_sequence()920 self.test_sequence.add_log_lines(921 [922 "read packet: $p{0:x};thread:{1:x}#00".format(923 reg_index, thread924 ),925 {926 "direction": "send",927 "regex": r"^\$([0-9a-fA-F]+)#",928 "capture": {1: "p_response"},929 },930 ],931 True,932 )933 context = self.expect_gdbremote_sequence()934 self.assertIsNotNone(context)935 936 # Set the next value to use for writing as the increment plus937 # current value.938 p_response = context.get("p_response")939 self.assertIsNotNone(p_response)940 next_value = lldbgdbserverutils.unpack_register_hex_unsigned(941 endian, p_response942 )943 944 # Set new value using P and thread suffix.945 self.reset_test_sequence()946 self.test_sequence.add_log_lines(947 [948 "read packet: $P{0:x}={1};thread:{2:x}#00".format(949 reg_index,950 lldbgdbserverutils.pack_register_hex(951 endian, next_value, byte_size=reg_byte_size952 ),953 thread,954 ),955 "send packet: $OK#00",956 ],957 True,958 )959 context = self.expect_gdbremote_sequence()960 self.assertIsNotNone(context)961 962 # Save the value we set.963 expected_reg_values.append(next_value)964 965 # Increment value for next thread to use (we want them all966 # different so we can verify they wrote to each thread correctly967 # next.)968 next_value += register_increment969 970 # Revisit each thread and verify they have the expected value set for971 # the register we wrote.972 thread_index = 0973 for thread in threads:974 # Read pre-existing register value.975 self.reset_test_sequence()976 self.test_sequence.add_log_lines(977 [978 "read packet: $p{0:x};thread:{1:x}#00".format(reg_index, thread),979 {980 "direction": "send",981 "regex": r"^\$([0-9a-fA-F]+)#",982 "capture": {1: "p_response"},983 },984 ],985 True,986 )987 context = self.expect_gdbremote_sequence()988 self.assertIsNotNone(context)989 990 # Get the register value.991 p_response = context.get("p_response")992 self.assertIsNotNone(p_response)993 read_value = lldbgdbserverutils.unpack_register_hex_unsigned(994 endian, p_response995 )996 997 # Make sure we read back what we wrote.998 self.assertEqual(read_value, expected_reg_values[thread_index])999 thread_index += 11000 1001 @skipUnlessPlatform(oslist=["freebsd", "linux"])1002 @add_test_categories(["llgs"])1003 def test_qXfer_siginfo_read(self):1004 self.build()1005 self.set_inferior_startup_launch()1006 procs = self.prep_debug_monitor_and_inferior(1007 inferior_args=["thread:segfault", "thread:new", "sleep:10"]1008 )1009 self.test_sequence.add_log_lines(["read packet: $c#63"], True)1010 self.expect_gdbremote_sequence()1011 1012 # Run until SIGSEGV comes in.1013 self.reset_test_sequence()1014 self.test_sequence.add_log_lines(1015 [1016 {1017 "direction": "send",1018 "regex": r"^\$T([0-9a-fA-F]{2})thread:([0-9a-fA-F]+);",1019 "capture": {1: "signo", 2: "thread_id"},1020 }1021 ],1022 True,1023 )1024 1025 # Figure out which thread crashed.1026 context = self.expect_gdbremote_sequence()1027 self.assertIsNotNone(context)1028 self.assertEqual(1029 int(context["signo"], 16), lldbutil.get_signal_number("SIGSEGV")1030 )1031 crashing_thread = int(context["thread_id"], 16)1032 1033 # Grab siginfo for the crashing thread.1034 self.reset_test_sequence()1035 self.add_process_info_collection_packets()1036 self.test_sequence.add_log_lines(1037 [1038 "read packet: $Hg{:x}#00".format(crashing_thread),1039 "send packet: $OK#00",1040 "read packet: $qXfer:siginfo:read::0,80:#00",1041 {1042 "direction": "send",1043 "regex": re.compile(1044 r"^\$([^E])(.*)#[0-9a-fA-F]{2}$", re.MULTILINE | re.DOTALL1045 ),1046 "capture": {1: "response_type", 2: "content_raw"},1047 },1048 ],1049 True,1050 )1051 context = self.expect_gdbremote_sequence()1052 self.assertIsNotNone(context)1053 1054 # Ensure we end up with all data in one packet.1055 self.assertEqual(context.get("response_type"), "l")1056 1057 # Decode binary data.1058 content_raw = context.get("content_raw")1059 self.assertIsNotNone(content_raw)1060 content = self.decode_gdbremote_binary(content_raw).encode("latin1")1061 1062 # Decode siginfo_t.1063 process_info = self.parse_process_info_response(context)1064 pad = ""1065 if process_info["ptrsize"] == "8":1066 pad = "i"1067 signo_idx = 01068 errno_idx = 11069 code_idx = 21070 addr_idx = -11071 SEGV_MAPERR = 11072 if process_info["ostype"] == "linux":1073 # si_signo, si_errno, si_code, [pad], _sifields._sigfault.si_addr1074 format_str = "iii{}P".format(pad)1075 elif process_info["ostype"].startswith("freebsd"):1076 # si_signo, si_errno, si_code, si_pid, si_uid, si_status, si_addr1077 format_str = "iiiiiiP"1078 elif process_info["ostype"].startswith("netbsd"):1079 # _signo, _code, _errno, [pad], _reason._fault._addr1080 format_str = "iii{}P".format(pad)1081 errno_idx = 21082 code_idx = 11083 else:1084 assert False, "unknown ostype"1085 1086 decoder = struct.Struct(format_str)1087 decoded = decoder.unpack(content[: decoder.size])1088 self.assertEqual(decoded[signo_idx], lldbutil.get_signal_number("SIGSEGV"))1089 self.assertEqual(decoded[errno_idx], 0) # si_errno1090 self.assertEqual(decoded[code_idx], SEGV_MAPERR) # si_code1091 self.assertEqual(decoded[addr_idx], 0) # si_addr1092