diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 329768dd7915..771a9ab84a20 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -1377,29 +1377,26 @@ public: return; } - DataExtractor register_data; - - if (!reg_value.GetData(register_data)) { - err = Status::FromErrorStringWithFormat( - "couldn't get the data for register %s", m_register_info.name); - return; - } - - if (register_data.GetByteSize() != m_register_info.byte_size) { + if (reg_value.GetByteSize() != m_register_info.byte_size) { err = Status::FromErrorStringWithFormat( "data for register %s had size %llu but we expected %llu", - m_register_info.name, (unsigned long long)register_data.GetByteSize(), + m_register_info.name, (unsigned long long)reg_value.GetByteSize(), (unsigned long long)m_register_info.byte_size); return; } - m_register_contents = std::make_shared( - register_data.GetDataStart(), register_data.GetByteSize()); + lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0); + reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(), + buf.GetByteSize(), map.GetByteOrder(), err); + if (!err.Success()) + return; + + m_register_contents = std::make_shared(buf); Status write_error; - map.WriteMemory(load_addr, register_data.GetDataStart(), - register_data.GetByteSize(), write_error); + map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(), + write_error); if (!write_error.Success()) { err = Status::FromErrorStringWithFormat( diff --git a/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py new file mode 100644 index 000000000000..66e38df3a969 --- /dev/null +++ b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py @@ -0,0 +1,86 @@ +""" 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 = { + Endian.BIG: ("s390x", "pswa"), + Endian.LITTLE: ("aarch64", "pc"), + }[endian] + + self.server.responder = Responder( + dedent( + f"""\ + + + {architecture} + + + + """ + ), + endian, + ) + target = self.dbg.CreateTarget("") + 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 and expr should be the same. + pc_value = "0x0000000000001234" + self.expect( + "register read pc", + substrs=[pc_value], + ) + self.expect("expr --format hex -- $pc", substrs=[pc_value]) + + @skipIfXmlSupportMissing + @skipIfRemote + def test_little_endian_target(self): + self.do_endian_test(Endian.LITTLE) + + @skipIfXmlSupportMissing + @skipIfRemote + # Unlike AArch64, we do need the backend present for this test to work. + @skipIfLLVMTargetMissing("SystemZ") + def test_big_endian_target(self): + self.do_endian_test(Endian.BIG)