| """Test unions from GDB remote target description XML.""" | |
| from textwrap import dedent | |
| import lldb | |
| from lldbsuite.test.decorators import * | |
| from lldbsuite.test.gdbclientutils import * | |
| from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase | |
| from lldbsuite.test.lldbtest import * | |
| class TestXMLRegisterUnion(GDBRemoteTestBase): | |
| def setup_multidoc_test(self, docs, register_data): | |
| self.server.responder = MockGDBServerXMLResponder(docs, register_data) | |
| target = self.dbg.CreateTarget("") | |
| process = self.connect(target) | |
| lldbutil.expect_state_changes( | |
| self, self.dbg.GetListener(), process, [lldb.eStateStopped] | |
| ) | |
| return process | |
| def setup_register_test(self, definitions, register_data): | |
| return self.setup_multidoc_test( | |
| { | |
| "target.xml": dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <target version="1.0"> | |
| <architecture>aarch64</architecture> | |
| <feature name="test.register.unions"> | |
| {} | |
| </feature> | |
| </target>""" | |
| ).format(definitions) | |
| }, | |
| register_data, | |
| ) | |
| def assert_union_info(self, name, byte_size, members): | |
| self.expect( | |
| "register info {}".format(name), | |
| substrs=["Size: {} bytes".format(byte_size), "Union members:"] + members, | |
| ) | |
| def assert_no_union_info(self, name): | |
| self.expect("register info {}".format(name), substrs=["Name: {}".format(name)]) | |
| self.expect( | |
| "register info {}".format(name), | |
| matching=False, | |
| substrs=["Union members:"], | |
| ) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| def test_direct_and_nested_union_metadata(self): | |
| self.setup_register_test( | |
| """\ | |
| <vector id="v2f" type="ieee_single" count="2"/> | |
| <union id="views"> | |
| <field name="f32" type="ieee_single"/> | |
| <field name="f64" type="ieee_double"/> | |
| <field name="lanes" type="v2f"/> | |
| </union> | |
| <union id="nested"> | |
| <field name="view" type="views"/> | |
| <field name="raw" type="uint64"/> | |
| </union> | |
| <reg name="direct" regnum="0" bitsize="64" type="views"/> | |
| <reg name="nested" regnum="1" bitsize="64" type="nested"/> | |
| <reg name="larger" regnum="2" bitsize="128" type="views"/> | |
| <reg name="pc" bitsize="64"/>""", | |
| "00" * 40, | |
| ) | |
| self.assert_union_info( | |
| "direct", | |
| 8, | |
| [ | |
| "f32 (ieee_single, 4 bytes)", | |
| "f64 (ieee_double, 8 bytes)", | |
| "lanes (v2f, 8 bytes)", | |
| ], | |
| ) | |
| self.assert_union_info( | |
| "nested", 8, ["view (views, 8 bytes)", "raw (uint64, 8 bytes)"] | |
| ) | |
| self.assert_union_info( | |
| "larger", | |
| 16, | |
| [ | |
| "f32 (ieee_single, 4 bytes)", | |
| "f64 (ieee_double, 8 bytes)", | |
| "lanes (v2f, 8 bytes)", | |
| ], | |
| ) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| def test_vector_of_union_metadata(self): | |
| self.setup_register_test( | |
| """\ | |
| <union id="scalar32_views"> | |
| <field name="f32" type="ieee_single"/> | |
| <field name="u32" type="uint32"/> | |
| </union> | |
| <vector id="v4views" type="scalar32_views" count="4"/> | |
| <union id="pointer_view"> | |
| <field name="pointer" type="data_ptr"/> | |
| </union> | |
| <vector id="v2p" type="pointer_view" count="2"/> | |
| <reg name="u0" regnum="0" bitsize="32" type="scalar32_views"/> | |
| <reg name="v0" regnum="1" bitsize="128" type="v4views"/> | |
| <reg name="p0" regnum="2" bitsize="128" type="v2p"/> | |
| <reg name="pc" bitsize="64"/>""", | |
| "00" * 44, | |
| ) | |
| self.assert_union_info( | |
| "u0", 4, ["f32 (ieee_single, 4 bytes)", "u32 (uint32, 4 bytes)"] | |
| ) | |
| self.expect( | |
| "register info v0", | |
| substrs=["Size: 16 bytes", "Vector elements: 4"], | |
| ) | |
| self.expect( | |
| "register info p0", | |
| substrs=["Size: 16 bytes", "Vector elements: 2"], | |
| ) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| def test_invalid_unions_are_ignored(self): | |
| self.setup_register_test( | |
| """\ | |
| <enum id="enumeration" size="4"> | |
| <evalue name="zero" value="0"/> | |
| </enum> | |
| <flags id="flags" size="4"> | |
| <field name="bit" start="0" end="0"/> | |
| </flags> | |
| <union> | |
| <field name="value" type="uint64"/> | |
| </union> | |
| <union id="empty"/> | |
| <union id="missing_field_name"> | |
| <field type="uint64"/> | |
| </union> | |
| <union id="missing_field_type"> | |
| <field name="value"/> | |
| </union> | |
| <union id="unknown_field_type"> | |
| <field name="value" type="not_defined"/> | |
| </union> | |
| <union id="partial_invalid_field"> | |
| <field name="valid" type="uint64"/> | |
| <field name="invalid" type="not_defined"/> | |
| </union> | |
| <union id="forward_field_type"> | |
| <field name="value" type="later"/> | |
| </union> | |
| <union id="enum_field_type"> | |
| <field name="value" type="enumeration"/> | |
| </union> | |
| <union id="flags_field_type"> | |
| <field name="value" type="flags"/> | |
| </union> | |
| <union id="later"> | |
| <field name="value" type="uint64"/> | |
| </union> | |
| <union id="wide"> | |
| <field name="value" type="uint64"/> | |
| </union> | |
| <reg name="empty" regnum="0" bitsize="64" type="empty"/> | |
| <reg name="missing_field_name" regnum="1" bitsize="64" | |
| type="missing_field_name"/> | |
| <reg name="missing_field_type" regnum="2" bitsize="64" | |
| type="missing_field_type"/> | |
| <reg name="unknown_field_type" regnum="3" bitsize="64" | |
| type="unknown_field_type"/> | |
| <reg name="forward_field_type" regnum="4" bitsize="64" | |
| type="forward_field_type"/> | |
| <reg name="enum_field_type" regnum="5" bitsize="32" | |
| type="enum_field_type"/> | |
| <reg name="flags_field_type" regnum="6" bitsize="32" | |
| type="flags_field_type"/> | |
| <reg name="later" regnum="7" bitsize="64" type="later"/> | |
| <reg name="wrong_size" regnum="8" bitsize="32" type="wide"/> | |
| <reg name="partial_invalid_field" regnum="9" bitsize="64" | |
| type="partial_invalid_field"/> | |
| <reg name="pc" bitsize="64"/>""", | |
| "00" * 76, | |
| ) | |
| for name in [ | |
| "empty", | |
| "missing_field_name", | |
| "missing_field_type", | |
| "unknown_field_type", | |
| "partial_invalid_field", | |
| "forward_field_type", | |
| "enum_field_type", | |
| "flags_field_type", | |
| "wrong_size", | |
| ]: | |
| self.assert_no_union_info(name) | |
| self.assert_union_info("later", 8, ["value (uint64, 8 bytes)"]) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| def test_duplicate_union_id_uses_first_definition(self): | |
| self.setup_register_test( | |
| """\ | |
| <union id="shared"> | |
| <field name="first" type="uint64"/> | |
| </union> | |
| <union id="shared"> | |
| <field name="second" type="ieee_double"/> | |
| </union> | |
| <reg name="u0" regnum="0" bitsize="64" type="shared"/> | |
| <reg name="pc" bitsize="64"/>""", | |
| "00" * 16, | |
| ) | |
| self.assert_union_info("u0", 8, ["first (uint64, 8 bytes)"]) | |
| self.expect("register info u0", matching=False, substrs=["second"]) | |
| @skipIfXmlSupportMissing | |
| @skipIfRemote | |
| def test_union_ids_are_scoped_to_included_feature(self): | |
| self.setup_multidoc_test( | |
| { | |
| "target.xml": dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <target version="1.0"> | |
| <architecture>aarch64</architecture> | |
| <xi:include href="first.xml"/> | |
| <xi:include href="second.xml"/> | |
| <xi:include href="third.xml"/> | |
| </target>""" | |
| ), | |
| "first.xml": dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <feature name="feature.first"> | |
| <union id="shared"> | |
| <field name="first" type="uint64"/> | |
| </union> | |
| <reg name="first" regnum="0" bitsize="64" type="shared"/> | |
| </feature>""" | |
| ), | |
| "second.xml": dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <feature name="feature.second"> | |
| <union id="shared"> | |
| <field name="second" type="uint32"/> | |
| </union> | |
| <reg name="second" regnum="1" bitsize="32" type="shared"/> | |
| </feature>""" | |
| ), | |
| "third.xml": dedent( | |
| """\ | |
| <?xml version="1.0"?> | |
| <feature name="feature.third"> | |
| <reg name="unresolved" regnum="2" bitsize="64" type="shared"/> | |
| <reg name="pc" bitsize="64"/> | |
| </feature>""" | |
| ), | |
| }, | |
| "00" * 28, | |
| ) | |
| self.assert_union_info("first", 8, ["first (uint64, 8 bytes)"]) | |
| self.assert_union_info("second", 4, ["second (uint32, 4 bytes)"]) | |
| self.assert_no_union_info("unresolved") |