| """ Check that registers written to memory for expression evaluation are |
| written using the target's endian not the host's. |
| """ |
| |
| from enum import Enum |
| from textwrap import dedent |
| import lldb |
| from lldbsuite.test.lldbtest import * |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.gdbclientutils import * |
| from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase |
| |
| |
| class Endian(Enum): |
| BIG = 0 |
| LITTLE = 1 |
| |
| |
| class Responder(MockGDBServerResponder): |
| def __init__(self, doc, endian): |
| super().__init__() |
| self.target_xml = doc |
| self.endian = endian |
| |
| def qXferRead(self, obj, annex, offset, length): |
| if annex == "target.xml": |
| return self.target_xml, False |
| return (None,) |
| |
| def readRegister(self, regnum): |
| return "E01" |
| |
| def readRegisters(self): |
| # 64 bit pc value. |
| data = ["00", "00", "00", "00", "00", "00", "12", "34"] |
| if self.endian == Endian.LITTLE: |
| data.reverse() |
| return "".join(data) |
| |
| |
| class TestXMLRegisterFlags(GDBRemoteTestBase): |
| def do_endian_test(self, endian): |
| architecture, pc_reg_name, yaml_file, data, machine = { |
| Endian.BIG: ("s390x", "pswa", "s390x.yaml", "ELFDATA2MSB", "EM_S390"), |
| Endian.LITTLE: ( |
| "aarch64", |
| "pc", |
| "aarch64.yaml", |
| "ELFDATA2LSB", |
| "EM_AARCH64", |
| ), |
| }[endian] |
| |
| self.server.responder = Responder( |
| dedent( |
| f"""\ |
| <?xml version="1.0"?> |
| <target version="1.0"> |
| <architecture>{architecture}</architecture> |
| <feature> |
| <reg name="{pc_reg_name}" bitsize="64"/> |
| </feature> |
| </target>""" |
| ), |
| endian, |
| ) |
| |
| # We need to have a program file, so that we have a full type system, |
| # so that we can do the casts later. |
| obj_path = self.getBuildArtifact("main.o") |
| yaml_path = self.getBuildArtifact(yaml_file) |
| with open(yaml_path, "w") as f: |
| f.write( |
| dedent( |
| f"""\ |
| --- !ELF |
| FileHeader: |
| Class: ELFCLASS64 |
| Data: {data} |
| Type: ET_REL |
| Machine: {machine} |
| ... |
| """ |
| ) |
| ) |
| self.yaml2obj(yaml_path, obj_path) |
| target = self.dbg.CreateTarget(obj_path) |
| |
| process = self.connect(target) |
| lldbutil.expect_state_changes( |
| self, self.dbg.GetListener(), process, [lldb.eStateStopped] |
| ) |
| |
| # If expressions convert register values into target endian, the |
| # result of register read, expr and casts should be the same. |
| pc_value = "0x0000000000001234" |
| self.expect( |
| "register read pc", |
| substrs=[pc_value], |
| ) |
| self.expect("expr --format hex -- $pc", substrs=[pc_value]) |
| |
| pc = ( |
| process.thread[0] |
| .frame[0] |
| .GetRegisters() |
| .GetValueAtIndex(0) |
| .GetChildMemberWithName("pc") |
| ) |
| ull = target.FindTypes("unsigned long long").GetTypeAtIndex(0) |
| pc_ull = pc.Cast(ull) |
| |
| self.assertEqual(pc.GetValue(), pc_ull.GetValue()) |
| self.assertEqual(pc.GetValueAsAddress(), pc_ull.GetValueAsAddress()) |
| self.assertEqual(pc.GetValueAsSigned(), pc_ull.GetValueAsSigned()) |
| self.assertEqual(pc.GetValueAsUnsigned(), pc_ull.GetValueAsUnsigned()) |
| |
| @skipIfXmlSupportMissing |
| @skipIfRemote |
| @skipIfLLVMTargetMissing("AArch64") |
| def test_little_endian_target(self): |
| self.do_endian_test(Endian.LITTLE) |
| |
| @skipIfXmlSupportMissing |
| @skipIfRemote |
| @skipIfLLVMTargetMissing("SystemZ") |
| def test_big_endian_target(self): |
| self.do_endian_test(Endian.BIG) |