| import lldb |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.gdbclientutils import * |
| from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase |
| |
| # This test ensures that LLDB correctly handles packets sent by MSPDebug. |
| # https://github.com/dlbeer/mspdebug |
| |
| |
| class MyResponder(MockGDBServerResponder): |
| def qSupported(self, client_supported): |
| return "PacketSize=4000" |
| |
| def setBreakpoint(self, packet): |
| return "OK" |
| |
| def stopPackets(): |
| # Registers 3 to 15 are empty |
| regs3to15 = "".join("%02x:%s;" % (i, "00000000") for i in range(3, 16)) |
| yield "T0500:00050000;01:00000000;02:00000000;" + regs3to15 |
| yield "T0500:10050000;01:baff0000;02:05000000;" + regs3to15 |
| yield "T0500:16050000;01:baff0000;02:05000000;" + regs3to15 |
| |
| stopPacket = stopPackets() |
| |
| def haltReason(self): |
| return next(self.stopPacket) |
| |
| def cont(self): |
| return self.haltReason() |
| |
| # Memory dump |
| def readMemory(self, addr, length): |
| # Program memory |
| if addr == 0x0400: |
| return ( |
| ("ff" * 256) |
| + "3140c0ff0c43b0121c05b01281010000b240d2043c051c423c0530413180020081430000b01210053150020030411c4330413c402a0030410c433041" |
| + ("ff" * 196) |
| ) |
| # Stack contents |
| if addr == 0xFE00: |
| return ("ff" * 442) + "280500000a05" + ("ff" * 62) + "0005" |
| |
| |
| class TestMSP430MSPDebug(GDBRemoteTestBase): |
| @skipIfLLVMTargetMissing("MSP430") |
| def test(self): |
| """ |
| Test LLDB's MSP430 functionality. |
| """ |
| target = self.createTarget("msp430.yaml") |
| self.server.responder = MyResponder() |
| |
| if self.TraceOn(): |
| self.runCmd("log enable gdb-remote packets") |
| self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets")) |
| |
| process = self.connect(target) |
| lldbutil.expect_state_changes( |
| self, self.dbg.GetListener(), process, [lldb.eStateStopped] |
| ) |
| num_threads = len(process.threads) |
| self.assertEqual(num_threads, 1, "Only one thread") |
| thread = process.GetThreadAtIndex(0) |
| |
| # Test if a breakpoint can be set |
| bp = target.BreakpointCreateByName("func") |
| self.assertTrue(bp.IsValid()) |
| bp.SetEnabled(True) |
| self.assertTrue(bp.IsEnabled()) |
| |
| # Test if the breakpoint address is resolved correctly |
| self.assertEqual(bp.GetNumLocations(), 1, "Only one location") |
| bp_loc = bp.GetLocationAtIndex(0) |
| self.assertTrue( |
| bp_loc.GetAddress().GetLoadAddress(target) == 0x510, "Address of main" |
| ) |
| |
| # Test if the process stops at the breakpoint |
| process.Continue() |
| self.assertStopReason( |
| thread.GetStopReason(), lldb.eStopReasonBreakpoint, "Hit a breakpoint" |
| ) |
| |
| # Check if disassembler works and the current function is "func" |
| func = thread.GetFrameAtIndex(0).GetFunction() |
| insts = func.GetInstructions(target) |
| inst = insts.GetInstructionAtIndex(0) |
| self.assertEqual(inst.GetMnemonic(target), "mov") |
| self.assertEqual(inst.GetOperands(target), "#1234, &1340") |
| |
| # Test if thread can step a single instruction |
| thread.StepInstruction(False) |
| self.assertTrue( |
| thread.GetFrameAtIndex(0).GetPCAddress().GetLoadAddress(target) == 0x516, |
| "Address of the next instruction", |
| ) |
| |
| # Test if registers are being set correctly |
| registerSet = thread.GetFrameAtIndex(0).GetRegisters().GetValueAtIndex(0) |
| reg_val_dict = { |
| "pc": 0x0516, |
| "sp": 0xFFBA, |
| "r2": 0x0005, |
| "r3": 0x0000, |
| "fp": 0x0000, |
| "r5": 0x0000, |
| "r6": 0x0000, |
| "r7": 0x0000, |
| "r8": 0x0000, |
| "r9": 0x0000, |
| "r10": 0x0000, |
| "r11": 0x0000, |
| "r12": 0x0000, |
| "r13": 0x0000, |
| "r14": 0x0000, |
| "r15": 0x0000, |
| } |
| for reg in registerSet: |
| self.assertEqual(reg.GetValueAsUnsigned(), reg_val_dict[reg.GetName()]) |
| |
| # Check if backtracing works: |
| self.assertTrue(len(thread.frames) >= 3) |
| crt0_addr = thread.GetFrameAtIndex(2).GetPCAddress().GetLoadAddress(target) |
| self.assertEqual(crt0_addr, 0x50A) |