mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 00:16:39 +00:00
1059 lines
38 KiB
Python
1059 lines
38 KiB
Python
""" Check that register fields found in target XML are properly processed.
|
|
|
|
These tests make XML out of string substitution. This can lead to some strange
|
|
failures. Check that the final XML is valid and each child is indented more than
|
|
the parent tag.
|
|
"""
|
|
|
|
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 MultiDocResponder(MockGDBServerResponder):
|
|
# docs is a dictionary of filename -> file content.
|
|
def __init__(self, docs):
|
|
super().__init__()
|
|
self.docs = docs
|
|
|
|
def qXferRead(self, obj, annex, offset, length):
|
|
try:
|
|
return self.docs[annex], False
|
|
except KeyError:
|
|
return (None,)
|
|
|
|
def readRegister(self, regnum):
|
|
return "E01"
|
|
|
|
def readRegisters(self):
|
|
return "".join(
|
|
[
|
|
# Data for all registers requested by the tests below.
|
|
# 0x7 and 0xE are used because their lsb and msb are opposites, which
|
|
# is needed for a byte order test.
|
|
"77777777EEEEEEEE", # 64 bit x0/r0
|
|
"7777EEEE", # 32 bit cpsr/fpc
|
|
"0000000000000000", # 64 bit pc/pswa
|
|
]
|
|
)
|
|
|
|
|
|
class TestXMLRegisterFlags(GDBRemoteTestBase):
|
|
def setup_multidoc_test(self, docs):
|
|
self.server.responder = MultiDocResponder(docs)
|
|
target = self.dbg.CreateTarget("")
|
|
|
|
if self.TraceOn():
|
|
self.runCmd("log enable gdb-remote packets process")
|
|
self.addTearDownHook(
|
|
lambda: self.runCmd("log disable gdb-remote packets process")
|
|
)
|
|
|
|
process = self.connect(target)
|
|
lldbutil.expect_state_changes(
|
|
self, self.dbg.GetListener(), process, [lldb.eStateStopped]
|
|
)
|
|
|
|
def setup_register_test(self, registers):
|
|
self.setup_multidoc_test(
|
|
# This *must* begin with the opening tag, leading whitespace is not allowed.
|
|
{
|
|
"target.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<target version="1.0">
|
|
<architecture>aarch64</architecture>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
{}
|
|
</feature>
|
|
</target>"""
|
|
).format(registers)
|
|
}
|
|
)
|
|
|
|
def setup_flags_test(self, flags):
|
|
# pc is required here though we don't look at it in the tests.
|
|
# x0 is only used by some tests but always including it keeps the data ordering
|
|
# the same throughout.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
{}
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>""".format(
|
|
flags
|
|
)
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_no_flags(self):
|
|
self.setup_flags_test("")
|
|
self.expect("register read cpsr", substrs=["= 0xeeee7777"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_single_field_pad_msb(self):
|
|
self.setup_flags_test("""<field name="SP" start="0" end="0"/>""")
|
|
# Pads from 31 to 1.
|
|
self.expect("register read cpsr", substrs=["(SP = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_single_field_pad_lsb(self):
|
|
self.setup_flags_test("""<field name="SP" start="31" end="31"/>""")
|
|
self.expect("register read cpsr", substrs=["(SP = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_multiple_fields_sorted(self):
|
|
self.setup_flags_test(
|
|
"""<field name="SP" start="0" end="0"/>
|
|
<field name="EL" start="1" end="2"/>"""
|
|
)
|
|
|
|
# Fields should be sorted with MSB on the left.
|
|
self.expect("register read cpsr", substrs=["(EL = 3, SP = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_ignore_invalid_start_end(self):
|
|
self.setup_flags_test(
|
|
# Is valid so is used.
|
|
'<field name="EL" start="2" end="3"/>'
|
|
# Start/end cannot be negative, ignored.
|
|
'<field name="SP" start="-1" end="2"/>'
|
|
'<field name="SP2" start="1" end="-5"/>'
|
|
# Start is not <= end, ignored.
|
|
'<field name="ABC" start="12" end="10"/>'
|
|
# Start cannot be >= (size of register in bits)
|
|
'<field name="?" start="32" end="29"/>'
|
|
# End cannot be >= (size of register in bits)
|
|
'<field name="DEF" start="30" end="35"/>'
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(EL = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_field_overlap(self):
|
|
self.setup_flags_test(
|
|
'<field name="?" start="10" end="12"/>'
|
|
# A overlaps B
|
|
'<field name="A" start="0" end="3"/>'
|
|
'<field name="B" start="0" end="0"/>'
|
|
)
|
|
|
|
# Ignore the whole flags set, it is unlikely to be valid.
|
|
self.expect("register read cpsr", substrs=["("], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_field_required_attributes(self):
|
|
# Fields must have a name, start and end. Any without are ignored.
|
|
self.setup_flags_test(
|
|
# Missing name
|
|
'<field start="0" end="0"/>'
|
|
# Missing start
|
|
'<field name="A" end="0"/>'
|
|
# Missing end
|
|
'<field name="B" start="0"/>'
|
|
# Valid
|
|
'<field name="C" start="0" end="0"/>'
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(C = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_little_endian_target_order(self):
|
|
# We are using little endian AArch64 here.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="lsb" start="0" end="0"/>
|
|
<field name="msb" start="31" end="31"/>
|
|
</flags>
|
|
<flags id="x0_flags" size="8">
|
|
<field name="lsb" start="0" end="0"/>
|
|
<field name="msb" start="63" end="63"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
# If lldb used the wrong byte ordering for the value for printing fields,
|
|
# these field values would flip. Since the top and bottom bits of 0x7 and 0xE
|
|
# are different.
|
|
self.expect(
|
|
"register read cpsr x0",
|
|
substrs=[
|
|
" cpsr = 0xeeee7777\n"
|
|
" = (msb = 1, lsb = 1)\n"
|
|
" x0 = 0xeeeeeeee77777777\n"
|
|
" = (msb = 1, lsb = 1)"
|
|
],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
# Unlike AArch64, we do need the backend present for this test to work.
|
|
@skipIfLLVMTargetMissing("SystemZ")
|
|
def test_big_endian_target_order(self):
|
|
# s390x/SystemZ is big endian.
|
|
self.setup_multidoc_test(
|
|
{
|
|
"target.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<target version="1.0">
|
|
<architecture>s390x</architecture>
|
|
<feature name="org.gnu.gdb.s390x.core">
|
|
<flags id="r0_flags" size="8">
|
|
<field name="lsb" start="0" end="0"/>
|
|
<field name="msb" start="63" end="63"/>
|
|
</flags>
|
|
<flags id="fpc_flags" size="4">
|
|
<field name="lsb" start="0" end="0"/>
|
|
<field name="msb" start="31" end="31"/>
|
|
</flags>
|
|
<reg name="r0" bitsize="64" type="r0_flags"/>
|
|
<reg name="fpc" bitsize="32" type="fpc_flags"/>
|
|
<reg name="pswa" bitsize="64"/>
|
|
</feature>
|
|
</target>"""
|
|
)
|
|
}
|
|
)
|
|
|
|
# If we did not swap correctly, these fields would show as 1s when run on
|
|
# a little endian host.
|
|
self.expect(
|
|
"register read r0 fpc",
|
|
substrs=[
|
|
" r0 = 0x77777777eeeeeeee\n"
|
|
" = (msb = 0, lsb = 0)\n"
|
|
" fpc = 0x7777eeee\n"
|
|
" = (msb = 0, lsb = 0)\n"
|
|
],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_many_flag_sets(self):
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="correct" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags_alt" size="4">
|
|
<field name="incorrect" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="x0_flags" size="8">
|
|
<field name="foo" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register read cpsr x0",
|
|
substrs=[
|
|
" cpsr = 0xeeee7777\n"
|
|
" = (correct = 1)\n"
|
|
" x0 = 0xeeeeeeee77777777\n"
|
|
" = (foo = 1)"
|
|
],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_repeated_flag_set(self):
|
|
# The second definition of "cpsr_flags" should be ignored.
|
|
# This is because we assign the types to registers as we go. If we allowed
|
|
# the later flag set, it would destroy the first definition, making the
|
|
# pointer to the flags invalid.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="correct" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="incorrect" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(correct = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_missing_flags(self):
|
|
self.setup_register_test(
|
|
"""\
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
# Register prints with default formatting only if we can't find the
|
|
# flags type.
|
|
self.expect("register read cpsr", substrs=["cpsr = 0xeeee7777"])
|
|
self.expect("register read cpsr", substrs=["("], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_invalid_size(self):
|
|
# We're not using the size for anything yet so just check that we handle
|
|
# it not being a positive integer.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="???">
|
|
<field name="A" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags" size="-1">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="C" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
# Only the final set has a valid size, use that.
|
|
self.expect("register read cpsr", substrs=["(C = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_unknown_attribute(self):
|
|
# Unknown attributes on flags or field are ignored.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4" stuff="abcd">
|
|
<field name="A" start="0" abcd="???" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(A = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_required_attributes(self):
|
|
# flags must have an id and size so the flags with "C" is the only valid one
|
|
# here.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags size="4">
|
|
<field name="A" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="C" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(C = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_register_size_mismatch(self):
|
|
# If the size of the flag set found does not match the size of the
|
|
# register, we discard the flags.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="8">
|
|
<field name="C" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(C = 1)"], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_set_even_if_format_set(self):
|
|
# lldb also sends "format". If that is set, we should still read the
|
|
# flags type.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"
|
|
format="example"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(B = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_set_even_if_encoding_set(self):
|
|
# lldb also sends "encoding". If that is set, we should still read the
|
|
# flags type.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"
|
|
encoding="example"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(B = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_set_even_if_encoding_and_format_set(self):
|
|
# As above but both encoding and format are set.
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"
|
|
encoding="example" format="example"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(B = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_multiple_lines(self):
|
|
# Since we use C types they follow lldb's usual decisions as to whether
|
|
# to print them on one line or many. Long field names will usually mean
|
|
# many lines.
|
|
self.setup_flags_test(
|
|
'<field name="this_is_a_long_field_0" start="0" end="0"/>'
|
|
'<field name="this_is_a_long_field_1" start="1" end="1"/>'
|
|
'<field name="this_is_a_long_field_2" start="2" end="2"/>'
|
|
'<field name="this_is_a_long_field_3" start="3" end="3"/>'
|
|
)
|
|
|
|
self.expect(
|
|
"register read cpsr",
|
|
substrs=[
|
|
" cpsr = 0xeeee7777\n"
|
|
" = {\n"
|
|
" this_is_a_long_field_3 = 0\n"
|
|
" this_is_a_long_field_2 = 1\n"
|
|
" this_is_a_long_field_1 = 1\n"
|
|
" this_is_a_long_field_0 = 1\n"
|
|
" }"
|
|
],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_child_limit(self):
|
|
# Flags print like C types so they should follow the child limit setting.
|
|
self.runCmd("settings set target.max-children-count 3")
|
|
self.setup_flags_test(
|
|
'<field name="field_0" start="0" end="0"/>'
|
|
'<field name="field_1" start="1" end="1"/>'
|
|
'<field name="field_2" start="2" end="2"/>'
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["= (field_2 = 1, field_1 = 1, ...)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_format_disables_flags(self):
|
|
# If asked for a specific format, don't print flags after it.
|
|
self.setup_flags_test('<field name="field_0" start="0" end="0"/>')
|
|
|
|
self.expect("register read cpsr --format X", substrs=["cpsr = 0xEEEE7777"])
|
|
self.expect(
|
|
"register read cpsr --format X", substrs=["field_0"], matching=False
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_xml_includes(self):
|
|
# Certain targets e.g. s390x QEMU split their defintions over multiple
|
|
# files that are included into target.xml.
|
|
self.setup_multidoc_test(
|
|
{
|
|
# The formatting is very specific here. lldb doesn't like leading
|
|
# spaces, and nested tags must be indented more than their parent.
|
|
"target.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<target version="1.0">
|
|
<architecture>aarch64</architecture>
|
|
<xi:include href="core.xml"/>
|
|
</target>"""
|
|
),
|
|
"core.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>
|
|
</feature>
|
|
"""
|
|
),
|
|
}
|
|
)
|
|
|
|
self.expect("register read cpsr", substrs=["(B = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_xml_includes_multiple(self):
|
|
self.setup_multidoc_test(
|
|
{
|
|
"target.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<target version="1.0">
|
|
<architecture>aarch64</architecture>
|
|
<xi:include href="core.xml"/>
|
|
<xi:include href="core-2.xml"/>
|
|
</target>"""
|
|
),
|
|
"core.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
<flags id="x0_flags" size="8">
|
|
<field name="B" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
</feature>"""
|
|
),
|
|
"core-2.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="C" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>
|
|
</feature>
|
|
"""
|
|
),
|
|
}
|
|
)
|
|
|
|
self.expect("register read x0 cpsr", substrs=["(B = 1)", "(C = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_xml_includes_flags_redefined(self):
|
|
self.setup_multidoc_test(
|
|
{
|
|
"target.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<target version="1.0">
|
|
<architecture>aarch64</architecture>
|
|
<xi:include href="core.xml"/>
|
|
<xi:include href="core-2.xml"/>
|
|
</target>"""
|
|
),
|
|
# Treating xi:include as a textual include, my_flags is first defined
|
|
# in core.xml. The second definition in core-2.xml
|
|
# is ignored.
|
|
"core.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
<flags id="my_flags" size="8">
|
|
<field name="correct" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="my_flags"/>
|
|
</feature>"""
|
|
),
|
|
# The my_flags here is ignored, so x1 will use the my_flags from above.
|
|
"core-2.xml": dedent(
|
|
"""\
|
|
<?xml version="1.0"?>
|
|
<feature name="org.gnu.gdb.aarch64.core">
|
|
<flags id="my_flags" size="8">
|
|
<field name="incorrect" start="0" end="0"/>
|
|
</flags>
|
|
<reg name="x1" regnum="33" bitsize="64" type="my_flags"/>
|
|
</feature>
|
|
"""
|
|
),
|
|
}
|
|
)
|
|
|
|
self.expect("register read x0", substrs=["(correct = 1)"])
|
|
self.expect("register read x1", substrs=["(correct = 1)"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_in_register_info(self):
|
|
# See RegisterFlags for comprehensive formatting tests.
|
|
self.setup_flags_test(
|
|
'<field name="D" start="0" end="7"/>'
|
|
'<field name="C" start="8" end="15"/>'
|
|
'<field name="B" start="16" end="23"/>'
|
|
'<field name="A" start="24" end="31"/>'
|
|
)
|
|
|
|
# The table should split according to terminal width.
|
|
self.runCmd("settings set term-width 17")
|
|
|
|
self.expect(
|
|
"register info cpsr",
|
|
substrs=[
|
|
" Name: cpsr\n"
|
|
" Size: 4 bytes (32 bits)\n"
|
|
" In sets: general (index 0)\n"
|
|
"\n"
|
|
"| 31-24 | 23-16 |\n"
|
|
"|-------|-------|\n"
|
|
"| A | B |\n"
|
|
"\n"
|
|
"| 15-8 | 7-0 |\n"
|
|
"|------|-----|\n"
|
|
"| C | D |"
|
|
],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_flags_name_xml_reserved_characters(self):
|
|
"""Check that lldb converts reserved character replacements like &
|
|
when found in field names."""
|
|
self.setup_flags_test(
|
|
'<field name="E&" start="0" end="0"/>'
|
|
'<field name="D"" start="1" end="1"/>'
|
|
'<field name="C'" start="2" end="2"/>'
|
|
'<field name="B>" start="3" end="3"/>'
|
|
'<field name="A<" start="4" end="4"/>'
|
|
)
|
|
|
|
self.expect(
|
|
"register info cpsr",
|
|
substrs=["| A< | B> | C' | D\" | E& |"],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_no_enum(self):
|
|
"""Check that lldb does not try to print an enum when there isn't one."""
|
|
|
|
self.setup_flags_test('<field name="E" start="0" end="0">' "</field>")
|
|
|
|
self.expect("register info cpsr", patterns=["E:.*$"], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_type_not_found(self):
|
|
"""Check that lldb uses the default format if we don't find the enum type."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register read cpsr", patterns=[r"\(E = 1\)$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_duplicated_evalue(self):
|
|
"""Check that lldb only uses the last instance of a evalue for each
|
|
value."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="abc" value="1"/>
|
|
<evalue name="def" value="1"/>
|
|
<evalue name="geh" value="2"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="1" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 1 = def, 2 = geh$"])
|
|
self.expect("register read cpsr", patterns=[r"\(E = def \| geh\)$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_duplicated(self):
|
|
"""Check that lldb only uses the last instance of enums with the same
|
|
id."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="abc" value="1"/>
|
|
</enum>
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="def" value="1"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 1 = def$"])
|
|
self.expect("register read cpsr", patterns=[r"\(E = def\)$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_use_first_valid(self):
|
|
"""Check that lldb uses the first enum that parses correctly and ignores
|
|
the rest."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4"/>
|
|
<enum size="4">
|
|
<evalue name="invalid" value="1"/>
|
|
</enum>
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="valid" value="1"/>
|
|
</enum>
|
|
<enum id="another_enum" size="4">
|
|
<evalue name="invalid" value="1"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 1 = valid$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_empty_name(self):
|
|
"""Check that lldb ignores evalues with an empty name."""
|
|
|
|
# The only potential use case for empty names is to shadow an evalue
|
|
# declared later so that it's name is hidden should the debugger only
|
|
# pick one of them. This behaviour would be debugger specific so the protocol
|
|
# would probably not care or leave it up to us, and I think it's not a
|
|
# useful thing to allow.
|
|
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="" value="1"/>
|
|
<evalue name="valid" value="2"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="1" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 2 = valid$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_invalid_value(self):
|
|
"""Check that lldb ignores evalues with an invalid value."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="negative_dec" value="-1"/>
|
|
<evalue name="negative_hex" value="-0x1"/>
|
|
<evalue name="negative_bin" value="-0b1"/>
|
|
<evalue name="negative_float" value="-0.5"/>
|
|
<evalue name="nan" value="aardvark"/>
|
|
<evalue name="dec" value="1"/>
|
|
<evalue name="hex" value="0x2"/>
|
|
<evalue name="octal" value="03"/>
|
|
<evalue name="float" value="0.5"/>
|
|
<evalue name="bin" value="0b100"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="2" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register info cpsr", patterns=["E: 1 = dec, 2 = hex, 3 = octal, 4 = bin$"]
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_out_of_range(self):
|
|
"""Check that lldb will not use an enum type if one of its evalues
|
|
exceeds the size of the field it is applied to."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="A" value="0"/>
|
|
<evalue name="B" value="2"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
# The whole eunm is rejected even if just 1 value is out of range.
|
|
self.expect("register info cpsr", patterns=["E: 0 = "], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_ignore_unknown_attributes(self):
|
|
"""Check that lldb ignores unknown attributes on an enum or evalue."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4" foo=\"bar\">
|
|
<evalue name="valid" value="1" colour=\"red"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 1 = valid$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_required_attributes(self):
|
|
"""Check that lldb rejects any evalue missing a name and/or value."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="foo"/>
|
|
<evalue value="1"/>
|
|
<evalue />
|
|
<evalue name="valid" value="1"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="0" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect("register info cpsr", patterns=["E: 1 = valid$"])
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_name_xml_reserved_characters(self):
|
|
"""Check that lldb converts reserved character replacements like &
|
|
when found in evalue names."""
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="A&" value="0"/>
|
|
<evalue name="B"" value="1"/>
|
|
<evalue name="C'" value="2"/>
|
|
<evalue name="D>" value="3"/>
|
|
<evalue name="E<" value="4"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="E" start="0" end="2" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register info cpsr",
|
|
patterns=["E: 0 = A&, 1 = B\", 2 = C', 3 = D>, 4 = E<$"],
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_enum_value_range(self):
|
|
"""Check that lldb ignores enums whose values would not fit into
|
|
their field."""
|
|
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="4">
|
|
<evalue name="A" value="0"/>
|
|
<evalue name="B" value="1"/>
|
|
<evalue name="C" value="2"/>
|
|
<evalue name="D" value="3"/>
|
|
<evalue name="E" value="4"/>
|
|
</enum>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="foo" start="0" end="1" type="some_enum"/>
|
|
<field name="bar" start="2" end="10" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
# some_enum can apply to foo
|
|
self.expect(
|
|
"register info cpsr", patterns=["bar: 0 = A, 1 = B, 2 = C, 3 = D, 4 = E$"]
|
|
)
|
|
# but not to bar
|
|
self.expect("register info cpsr", patterns=["foo: "], matching=False)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_evalue_value_limits(self):
|
|
"""Check that lldb can handle an evalue for a field up to 64 bits
|
|
in size and anything greater is ignored."""
|
|
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="8">
|
|
<evalue name="min" value="0"/>
|
|
<evalue name="max" value="0xffffffffffffffff"/>
|
|
<evalue name="invalid" value="0xfffffffffffffffff"/>
|
|
</enum>
|
|
<flags id="x0_flags" size="8">
|
|
<field name="foo" start="0" end="63" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register info x0", patterns=["foo: 0 = min, 18446744073709551615 = max$"]
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_field_size_limit(self):
|
|
"""Check that lldb ignores any field > 64 bits. We can't handle those
|
|
correctly."""
|
|
|
|
self.setup_register_test(
|
|
"""\
|
|
<flags id="x0_flags" size="8">
|
|
<field name="invalid" start="0" end="64"/>
|
|
<field name="valid" start="0" end="63"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register info x0", substrs=["| 63-0 |\n" "|-------|\n" "| valid |"]
|
|
)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_many_fields_same_enum(self):
|
|
"""Check that an enum can be reused by many fields, and fields of many
|
|
registers."""
|
|
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="some_enum" size="8">
|
|
<evalue name="valid" value="1"/>
|
|
</enum>
|
|
<flags id="x0_flags" size="8">
|
|
<field name="f1" start="0" end="0" type="some_enum"/>
|
|
<field name="f2" start="1" end="1" type="some_enum"/>
|
|
</flags>
|
|
<flags id="cpsr_flags" size="4">
|
|
<field name="f1" start="0" end="0" type="some_enum"/>
|
|
<field name="f2" start="1" end="1" type="some_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32" type="cpsr_flags"/>"""
|
|
)
|
|
|
|
expected_info = [
|
|
dedent(
|
|
"""\
|
|
f2: 1 = valid
|
|
|
|
f1: 1 = valid$"""
|
|
)
|
|
]
|
|
self.expect("register info x0", patterns=expected_info)
|
|
|
|
self.expect("register info cpsr", patterns=expected_info)
|
|
|
|
expected_read = [r"\(f2 = valid, f1 = valid\)$"]
|
|
self.expect("register read x0", patterns=expected_read)
|
|
self.expect("register read cpsr", patterns=expected_read)
|
|
|
|
@skipIfXmlSupportMissing
|
|
@skipIfRemote
|
|
def test_fields_same_name_different_enum(self):
|
|
"""Check that lldb does something sensible when there are two fields with
|
|
the same name, but their enum types differ."""
|
|
|
|
# It's unlikely anyone would do this intentionally but it is allowed by
|
|
# the protocol spec so we have to cope with it.
|
|
self.setup_register_test(
|
|
"""\
|
|
<enum id="foo_enum" size="8">
|
|
<evalue name="foo_0" value="1"/>
|
|
</enum>
|
|
<enum id="foo_alt_enum" size="8">
|
|
<evalue name="foo_1" value="1"/>
|
|
</enum>
|
|
<flags id="x0_flags" size="8">
|
|
<field name="foo" start="0" end="0" type="foo_enum"/>
|
|
<field name="foo" start="1" end="1" type="foo_alt_enum"/>
|
|
</flags>
|
|
<reg name="pc" bitsize="64"/>
|
|
<reg name="x0" regnum="0" bitsize="64" type="x0_flags"/>
|
|
<reg name="cpsr" regnum="33" bitsize="32"/>"""
|
|
)
|
|
|
|
self.expect(
|
|
"register info x0",
|
|
patterns=[
|
|
dedent(
|
|
"""\
|
|
foo: 1 = foo_1
|
|
|
|
foo: 1 = foo_0$"""
|
|
)
|
|
],
|
|
)
|
|
|
|
self.expect("register read x0", patterns=[r"\(foo = foo_1, foo = foo_0\)$"])
|