This revision was automatically updated to reflect the committed changes.
Closed by commit rGe07a421dd587: [lldb] Show register fields using bitfield 
struct types (authored by DavidSpickett).

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145580/new/

https://reviews.llvm.org/D145580

Files:
  lldb/include/lldb/Core/DumpRegisterValue.h
  lldb/include/lldb/Core/PluginManager.h
  lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
  lldb/include/lldb/Target/RegisterFlags.h
  lldb/include/lldb/Target/RegisterTypeBuilder.h
  lldb/include/lldb/Target/Target.h
  lldb/include/lldb/lldb-forward.h
  lldb/include/lldb/lldb-private-interfaces.h
  lldb/source/Commands/CommandObjectRegister.cpp
  lldb/source/Core/DumpRegisterValue.cpp
  lldb/source/Core/PluginManager.cpp
  lldb/source/DataFormatters/DumpValueObjectOptions.cpp
  lldb/source/DataFormatters/ValueObjectPrinter.cpp
  lldb/source/Plugins/CMakeLists.txt
  lldb/source/Plugins/RegisterTypeBuilder/CMakeLists.txt
  lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
  lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
  lldb/source/Target/Target.cpp
  lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
  lldb/unittests/Target/RegisterFlagsTest.cpp
  llvm/docs/ReleaseNotes.rst

Index: llvm/docs/ReleaseNotes.rst
===================================================================
--- llvm/docs/ReleaseNotes.rst
+++ llvm/docs/ReleaseNotes.rst
@@ -251,6 +251,12 @@
 * LLDB is now able to show the subtype of signals found in a core file. For example
   memory tagging specific segfaults such as ``SIGSEGV: sync tag check fault``.
 
+* LLDB can now display register fields if they are described in target XML sent
+  by a debug server such as ``gdbserver`` (``lldb-server`` does not currently produce
+  this information). Fields are only printed when reading named registers, for
+  example ``register read cpsr``. They are not shown when reading a register set,
+  ``register read -s 0``.
+
 Changes to Sanitizers
 ---------------------
 * For Darwin users that override weak symbols, note that the dynamic linker will
Index: lldb/unittests/Target/RegisterFlagsTest.cpp
===================================================================
--- lldb/unittests/Target/RegisterFlagsTest.cpp
+++ lldb/unittests/Target/RegisterFlagsTest.cpp
@@ -121,3 +121,19 @@
                 make_field(20, 21), make_field(12, 19), make_field(8, 11),
                 make_field(0, 7)});
 }
+
+TEST(RegisterFieldsTest, ReverseFieldOrder) {
+  // Unchanged
+  RegisterFlags rf("", 4, {make_field(0, 31)});
+  ASSERT_EQ(0x12345678ULL, rf.ReverseFieldOrder(0x12345678));
+
+  // Swap the two halves around.
+  RegisterFlags rf2("", 4, {make_field(16, 31), make_field(0, 15)});
+  ASSERT_EQ(0x56781234ULL, rf2.ReverseFieldOrder(0x12345678));
+
+  // Many small fields.
+  RegisterFlags rf3("", 4,
+                    {make_field(31, 31), make_field(30, 30), make_field(29, 29),
+                     make_field(28, 28)});
+  ASSERT_EQ(0x00000005ULL, rf3.ReverseFieldOrder(0xA0000000));
+}
Index: lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/gdb_remote_client/TestXMLRegisterFlags.py
@@ -0,0 +1,497 @@
+""" 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_requried_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_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_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="4">
+                    <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="4">
+                    <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 cpsr 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="4">
+                    <field name="incorrect" start="0" end="0"/>
+                  </flags>
+                  <reg name="cpsr" regnum="33" bitsize="32" type="my_flags"/>
+                </feature>
+            """),
+        })
+
+        self.expect("register read x0", substrs=["(correct = 1)"])
+        self.expect("register read cpsr", substrs=["(correct = 1)"])
Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -46,6 +46,7 @@
 #include "lldb/Target/Language.h"
 #include "lldb/Target/LanguageRuntime.h"
 #include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterTypeBuilder.h"
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/StackFrame.h"
 #include "lldb/Target/StackFrameRecognizer.h"
@@ -2358,6 +2359,14 @@
                                                             create_on_demand);
 }
 
+CompilerType Target::GetRegisterType(const std::string &name,
+                                     const lldb_private::RegisterFlags &flags,
+                                     uint32_t byte_size) {
+  RegisterTypeBuilderSP provider = PluginManager::GetRegisterTypeBuilder(*this);
+  assert(provider);
+  return provider->GetRegisterType(name, flags, byte_size);
+}
+
 std::vector<lldb::TypeSystemSP>
 Target::GetScratchTypeSystems(bool create_on_demand) {
   if (!m_valid)
Index: lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.h
@@ -0,0 +1,40 @@
+//===-- RegisterTypeBuilderClang.h ------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_PLUGINS_REGISTERTYPEBUILDER_REGISTERTYPEBUILDERCLANG_H
+#define LLDB_PLUGINS_REGISTERTYPEBUILDER_REGISTERTYPEBUILDERCLANG_H
+
+#include "lldb/Target/RegisterTypeBuilder.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+class RegisterTypeBuilderClang : public RegisterTypeBuilder {
+public:
+  RegisterTypeBuilderClang(Target &target);
+
+  static void Initialize();
+  static void Terminate();
+  static llvm::StringRef GetPluginNameStatic() {
+    return "register-types-clang";
+  }
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+  static llvm::StringRef GetPluginDescriptionStatic() {
+    return "Create register types using TypeSystemClang";
+  }
+  static lldb::RegisterTypeBuilderSP CreateInstance(Target &target);
+
+  CompilerType GetRegisterType(const std::string &name,
+                               const lldb_private::RegisterFlags &flags,
+                               uint32_t byte_size) override;
+
+private:
+  Target &m_target;
+};
+} // namespace lldb_private
+
+#endif // LLDB_PLUGINS_REGISTERTYPEBUILDER_REGISTERTYPEBUILDERCLANG_H
Index: lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/RegisterTypeBuilder/RegisterTypeBuilderClang.cpp
@@ -0,0 +1,82 @@
+//===-- RegisterTypeBuilderClang.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+
+#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "RegisterTypeBuilderClang.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(RegisterTypeBuilderClang)
+
+void RegisterTypeBuilderClang::Initialize() {
+  static llvm::once_flag g_once_flag;
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                  GetPluginDescriptionStatic(), CreateInstance);
+  });
+}
+
+void RegisterTypeBuilderClang::Terminate() {}
+
+lldb::RegisterTypeBuilderSP
+RegisterTypeBuilderClang::CreateInstance(Target &target) {
+  return std::make_shared<RegisterTypeBuilderClang>(target);
+}
+
+RegisterTypeBuilderClang::RegisterTypeBuilderClang(Target &target)
+    : m_target(target) {}
+
+CompilerType RegisterTypeBuilderClang::GetRegisterType(
+    const std::string &name, const lldb_private::RegisterFlags &flags,
+    uint32_t byte_size) {
+  lldb::TypeSystemClangSP type_system =
+      ScratchTypeSystemClang::GetForTarget(m_target);
+  assert(type_system);
+
+  std::string register_type_name = "__lldb_register_fields_";
+  register_type_name += name;
+  // See if we have made this type before and can reuse it.
+  CompilerType fields_type =
+      type_system->GetTypeForIdentifier<clang::CXXRecordDecl>(
+          ConstString(register_type_name.c_str()));
+
+  if (!fields_type) {
+    // In most ABI, a change of field type means a change in storage unit.
+    // We want it all in one unit, so we use a field type the same as the
+    // register's size.
+    CompilerType field_uint_type =
+        type_system->GetBuiltinTypeForEncodingAndBitSize(lldb::eEncodingUint,
+                                                         byte_size * 8);
+
+    fields_type = type_system->CreateRecordType(
+        nullptr, OptionalClangModuleID(), lldb::eAccessPublic,
+        register_type_name, clang::TTK_Struct, lldb::eLanguageTypeC);
+    type_system->StartTagDeclarationDefinition(fields_type);
+
+    // We assume that RegisterFlags has padded and sorted the fields
+    // already.
+    for (const RegisterFlags::Field &field : flags.GetFields()) {
+      type_system->AddFieldToRecordType(fields_type, field.GetName(),
+                                        field_uint_type, lldb::eAccessPublic,
+                                        field.GetSizeInBits());
+    }
+
+    type_system->CompleteTagDeclarationDefinition(fields_type);
+    // So that the size of the type matches the size of the register.
+    type_system->SetIsPacked(fields_type);
+
+    // This should be true if RegisterFlags padded correctly.
+    assert(*fields_type.GetByteSize(nullptr) == flags.GetSize());
+  }
+
+  return fields_type;
+}
Index: lldb/source/Plugins/RegisterTypeBuilder/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/source/Plugins/RegisterTypeBuilder/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginRegisterTypeBuilderClang PLUGIN
+  RegisterTypeBuilderClang.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbTarget
+
+  LINK_COMPONENTS
+    Support
+  )
Index: lldb/source/Plugins/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/CMakeLists.txt
+++ lldb/source/Plugins/CMakeLists.txt
@@ -15,6 +15,7 @@
 add_subdirectory(Platform)
 add_subdirectory(Process)
 add_subdirectory(REPL)
+add_subdirectory(RegisterTypeBuilder)
 add_subdirectory(ScriptInterpreter)
 add_subdirectory(StructuredData)
 add_subdirectory(SymbolFile)
Index: lldb/source/DataFormatters/ValueObjectPrinter.cpp
===================================================================
--- lldb/source/DataFormatters/ValueObjectPrinter.cpp
+++ lldb/source/DataFormatters/ValueObjectPrinter.cpp
@@ -696,6 +696,9 @@
 
     for (size_t idx = 0; idx < num_children; ++idx) {
       if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) {
+        if (m_options.m_child_printing_decider &&
+            !m_options.m_child_printing_decider(child_sp->GetName()))
+          continue;
         if (!any_children_printed) {
           PrintChildrenPreamble(value_printed, summary_printed);
           any_children_printed = true;
@@ -744,14 +747,19 @@
   if (num_children) {
     m_stream->PutChar('(');
 
+    bool did_print_children = false;
     for (uint32_t idx = 0; idx < num_children; ++idx) {
       lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true));
       if (child_sp)
         child_sp = child_sp->GetQualifiedRepresentationIfAvailable(
             m_options.m_use_dynamic, m_options.m_use_synthetic);
       if (child_sp) {
-        if (idx)
+        if (m_options.m_child_printing_decider &&
+            !m_options.m_child_printing_decider(child_sp->GetName()))
+          continue;
+        if (idx && did_print_children)
           m_stream->PutCString(", ");
+        did_print_children = true;
         if (!hide_names) {
           const char *name = child_sp.get()->GetName().AsCString();
           if (name && *name) {
Index: lldb/source/DataFormatters/DumpValueObjectOptions.cpp
===================================================================
--- lldb/source/DataFormatters/DumpValueObjectOptions.cpp
+++ lldb/source/DataFormatters/DumpValueObjectOptions.cpp
@@ -16,7 +16,8 @@
 DumpValueObjectOptions::DumpValueObjectOptions()
     : m_summary_sp(), m_root_valobj_name(),
       m_max_ptr_depth(PointerDepth{PointerDepth::Mode::Default, 0}),
-      m_decl_printing_helper(), m_pointer_as_array(), m_use_synthetic(true),
+      m_decl_printing_helper(), m_child_printing_decider(),
+      m_pointer_as_array(), m_use_synthetic(true),
       m_scope_already_checked(false), m_flat_output(false), m_ignore_cap(false),
       m_show_types(false), m_show_location(false), m_use_objc(false),
       m_hide_root_type(false), m_hide_root_name(false), m_hide_name(false),
@@ -50,6 +51,12 @@
   return *this;
 }
 
+DumpValueObjectOptions &
+DumpValueObjectOptions::SetChildPrintingDecider(ChildPrintingDecider decider) {
+  m_child_printing_decider = decider;
+  return *this;
+}
+
 DumpValueObjectOptions &DumpValueObjectOptions::SetShowTypes(bool show) {
   m_show_types = show;
   return *this;
Index: lldb/source/Core/PluginManager.cpp
===================================================================
--- lldb/source/Core/PluginManager.cpp
+++ lldb/source/Core/PluginManager.cpp
@@ -875,6 +875,45 @@
   }
 }
 
+#pragma mark RegisterTypeBuilder
+
+struct RegisterTypeBuilderInstance
+    : public PluginInstance<RegisterTypeBuilderCreateInstance> {
+  RegisterTypeBuilderInstance(llvm::StringRef name, llvm::StringRef description,
+                              CallbackType create_callback)
+      : PluginInstance<RegisterTypeBuilderCreateInstance>(name, description,
+                                                          create_callback) {}
+};
+
+typedef PluginInstances<RegisterTypeBuilderInstance>
+    RegisterTypeBuilderInstances;
+
+static RegisterTypeBuilderInstances &GetRegisterTypeBuilderInstances() {
+  static RegisterTypeBuilderInstances g_instances;
+  return g_instances;
+}
+
+bool PluginManager::RegisterPlugin(
+    llvm::StringRef name, llvm::StringRef description,
+    RegisterTypeBuilderCreateInstance create_callback) {
+  return GetRegisterTypeBuilderInstances().RegisterPlugin(name, description,
+                                                          create_callback);
+}
+
+bool PluginManager::UnregisterPlugin(
+    RegisterTypeBuilderCreateInstance create_callback) {
+  return GetRegisterTypeBuilderInstances().UnregisterPlugin(create_callback);
+}
+
+lldb::RegisterTypeBuilderSP
+PluginManager::GetRegisterTypeBuilder(Target &target) {
+  const auto &instances = GetRegisterTypeBuilderInstances().GetInstances();
+  // We assume that RegisterTypeBuilderClang is the only instance of this plugin
+  // type and is always present.
+  assert(instances.size());
+  return instances[0].create_callback(target);
+}
+
 #pragma mark ScriptInterpreter
 
 struct ScriptInterpreterInstance
Index: lldb/source/Core/DumpRegisterValue.cpp
===================================================================
--- lldb/source/Core/DumpRegisterValue.cpp
+++ lldb/source/Core/DumpRegisterValue.cpp
@@ -8,19 +8,63 @@
 
 #include "lldb/Core/DumpRegisterValue.h"
 #include "lldb/Core/DumpDataExtractor.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/DumpValueObjectOptions.h"
 #include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/Endian.h"
 #include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/StreamString.h"
 #include "lldb/lldb-private-types.h"
 
 using namespace lldb;
 
+static uint32_t swap_value(uint32_t v) { return __builtin_bswap32(v); }
+static uint64_t swap_value(uint64_t v) { return __builtin_bswap64(v); }
+
+template <typename T>
+static void dump_type_value(lldb_private::CompilerType &fields_type, T value,
+                            lldb_private::ExecutionContextScope *exe_scope,
+                            const lldb_private::RegisterInfo &reg_info,
+                            lldb_private::Stream &strm) {
+  lldb::ByteOrder target_order = exe_scope->CalculateProcess()->GetByteOrder();
+
+  // For the bitfield types we generate, it is expected that the fields are
+  // in what is usually a big endian order. Most significant field first.
+  // This is also clang's internal ordering and the order we want to print
+  // them. On a big endian host this all matches up, for a little endian
+  // host we have to swap the order of the fields before display.
+  if (target_order == lldb::ByteOrder::eByteOrderLittle) {
+    value = reg_info.flags_type->ReverseFieldOrder(value);
+  }
+
+  // Then we need to match the target's endian on a byte level as well.
+  if (lldb_private::endian::InlHostByteOrder() != target_order)
+    value = swap_value(value);
+
+  lldb_private::DataExtractor data_extractor{
+      &value, sizeof(T), lldb_private::endian::InlHostByteOrder(), 8};
+
+  lldb::ValueObjectSP vobj_sp = lldb_private::ValueObjectConstResult::Create(
+      exe_scope, fields_type, lldb_private::ConstString(), data_extractor);
+  lldb_private::DumpValueObjectOptions dump_options;
+  lldb_private::DumpValueObjectOptions::ChildPrintingDecider decider =
+      [](lldb_private::ConstString varname) {
+        // Unnamed bit-fields are padding that we don't want to show.
+        return varname.GetLength();
+      };
+  dump_options.SetChildPrintingDecider(decider).SetHideRootType(true);
+
+  vobj_sp->Dump(strm, dump_options);
+}
+
 void lldb_private::DumpRegisterValue(const RegisterValue &reg_val, Stream *s,
                                      const RegisterInfo *reg_info,
                                      bool prefix_with_name,
                                      bool prefix_with_alt_name, Format format,
                                      uint32_t reg_name_right_align_at,
-                                     ExecutionContextScope *exe_scope) {
+                                     ExecutionContextScope *exe_scope,
+                                     bool print_flags, TargetSP target_sp) {
   DataExtractor data;
   if (!reg_val.GetData(data))
     return;
@@ -76,4 +120,55 @@
                     0,                    // item_bit_size
                     0,                    // item_bit_offset
                     exe_scope);
+
+  if (!print_flags || !reg_info->flags_type || !exe_scope || !target_sp ||
+      (reg_info->byte_size != 4 && reg_info->byte_size != 8))
+    return;
+
+  CompilerType fields_type = target_sp->GetRegisterType(
+      reg_info->name, *reg_info->flags_type, reg_info->byte_size);
+
+  // Use a new stream so we can remove a trailing newline later.
+  StreamString fields_stream;
+
+  if (reg_info->byte_size == 4) {
+    dump_type_value(fields_type, reg_val.GetAsUInt32(), exe_scope, *reg_info,
+                    fields_stream);
+  } else {
+    dump_type_value(fields_type, reg_val.GetAsUInt64(), exe_scope, *reg_info,
+                    fields_stream);
+  }
+
+  // Registers are indented like:
+  // (lldb) register read foo
+  //     foo = 0x12345678
+  // So we need to indent to match that.
+
+  // First drop the extra newline that the value printer added. The register
+  // command will add one itself.
+  llvm::StringRef fields_str = fields_stream.GetString().drop_back();
+
+  // End the line that contains "    foo = 0x12345678".
+  s->EOL();
+
+  // Then split the value lines and indent each one.
+  bool first = true;
+  while (fields_str.size()) {
+    std::pair<llvm::StringRef, llvm::StringRef> split = fields_str.split('\n');
+    fields_str = split.second;
+    // Indent as far as the register name did.
+    s->Printf(fmt.c_str(), "");
+
+    // Lines after the first won't have " = " so compensate for that.
+    if (!first)
+      (*s) << "   ";
+    first = false;
+
+    (*s) << split.first;
+
+    // On the last line we don't want a newline because the command will add
+    // one too.
+    if (fields_str.size())
+      s->EOL();
+  }
 }
Index: lldb/source/Commands/CommandObjectRegister.cpp
===================================================================
--- lldb/source/Commands/CommandObjectRegister.cpp
+++ lldb/source/Commands/CommandObjectRegister.cpp
@@ -84,7 +84,8 @@
   Options *GetOptions() override { return &m_option_group; }
 
   bool DumpRegister(const ExecutionContext &exe_ctx, Stream &strm,
-                    RegisterContext *reg_ctx, const RegisterInfo *reg_info) {
+                    RegisterContext *reg_ctx, const RegisterInfo *reg_info,
+                    bool print_flags) {
     if (reg_info) {
       RegisterValue reg_value;
 
@@ -95,7 +96,8 @@
         bool prefix_with_name = !prefix_with_altname;
         DumpRegisterValue(reg_value, &strm, reg_info, prefix_with_name,
                           prefix_with_altname, m_format_options.GetFormat(), 8,
-                          exe_ctx.GetBestExecutionContextScope());
+                          exe_ctx.GetBestExecutionContextScope(), print_flags,
+                          exe_ctx.GetTargetSP());
         if ((reg_info->encoding == eEncodingUint) ||
             (reg_info->encoding == eEncodingSint)) {
           Process *process = exe_ctx.GetProcessPtr();
@@ -142,7 +144,8 @@
         if (primitive_only && reg_info && reg_info->value_regs)
           continue;
 
-        if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info))
+        if (DumpRegister(exe_ctx, strm, reg_ctx, reg_info,
+                         /*print_flags=*/false))
           ++available_count;
         else
           ++unavailable_count;
@@ -218,7 +221,8 @@
           reg_info = reg_ctx->GetRegisterInfoByName(arg_str);
 
           if (reg_info) {
-            if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info))
+            if (!DumpRegister(m_exe_ctx, strm, reg_ctx, reg_info,
+                              /*print_flags=*/true))
               strm.Printf("%-12s = error: unavailable\n", reg_info->name);
           } else {
             result.AppendErrorWithFormat("Invalid register name '%s'.\n",
Index: lldb/include/lldb/lldb-private-interfaces.h
===================================================================
--- lldb/include/lldb/lldb-private-interfaces.h
+++ lldb/include/lldb/lldb-private-interfaces.h
@@ -82,6 +82,8 @@
 typedef lldb::ProcessSP (*ProcessCreateInstance)(
     lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
     const FileSpec *crash_file_path, bool can_connect);
+typedef lldb::RegisterTypeBuilderSP (*RegisterTypeBuilderCreateInstance)(
+    Target &target);
 typedef lldb::ScriptInterpreterSP (*ScriptInterpreterCreateInstance)(
     Debugger &debugger);
 typedef SymbolFile *(*SymbolFileCreateInstance)(lldb::ObjectFileSP objfile_sp);
Index: lldb/include/lldb/lldb-forward.h
===================================================================
--- lldb/include/lldb/lldb-forward.h
+++ lldb/include/lldb/lldb-forward.h
@@ -175,6 +175,7 @@
 class RecognizedStackFrame;
 class RegisterCheckpoint;
 class RegisterContext;
+class RegisterTypeBuilder;
 class RegisterValue;
 class RegularExpression;
 class RichManglingContext;
@@ -371,6 +372,8 @@
 typedef std::weak_ptr<lldb_private::Process> ProcessWP;
 typedef std::shared_ptr<lldb_private::RegisterCheckpoint> RegisterCheckpointSP;
 typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP;
+typedef std::shared_ptr<lldb_private::RegisterTypeBuilder>
+    RegisterTypeBuilderSP;
 typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP;
 typedef std::shared_ptr<lldb_private::Queue> QueueSP;
 typedef std::weak_ptr<lldb_private::Queue> QueueWP;
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -1243,6 +1243,10 @@
   ///     if none can be found.
   llvm::Expected<lldb_private::Address> GetEntryPointAddress();
 
+  CompilerType GetRegisterType(const std::string &name,
+                               const lldb_private::RegisterFlags &flags,
+                               uint32_t byte_size);
+
   // Target Stop Hooks
   class StopHook : public UserID {
   public:
Index: lldb/include/lldb/Target/RegisterTypeBuilder.h
===================================================================
--- /dev/null
+++ lldb/include/lldb/Target/RegisterTypeBuilder.h
@@ -0,0 +1,35 @@
+//===-- RegisterTypeBuilder.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TARGET_REGISTER_TYPE_BUILDER_H
+#define LLDB_TARGET_REGISTER_TYPE_BUILDER_H
+
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class RegisterTypeBuilder : public PluginInterface {
+public:
+  ~RegisterTypeBuilder() override = default;
+
+  virtual CompilerType GetRegisterType(const std::string &name,
+                                       const lldb_private::RegisterFlags &flags,
+                                       uint32_t byte_size) = 0;
+
+protected:
+  RegisterTypeBuilder() = default;
+
+private:
+  RegisterTypeBuilder(const RegisterTypeBuilder &) = delete;
+  const RegisterTypeBuilder &operator=(const RegisterTypeBuilder &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_REGISTER_TYPE_BUILDER_H
Index: lldb/include/lldb/Target/RegisterFlags.h
===================================================================
--- lldb/include/lldb/Target/RegisterFlags.h
+++ lldb/include/lldb/Target/RegisterFlags.h
@@ -71,6 +71,23 @@
   RegisterFlags(std::string id, unsigned size,
                 const std::vector<Field> &fields);
 
+  // Reverse the order of the fields, keeping their values the same.
+  // For example a field from bit 31 to 30 with value 0b10 will become bits
+  // 1 to 0, with the same 0b10 value.
+  // Use this when you are going to show the register using a bitfield struct
+  // type. If that struct expects MSB first and you are on little endian where
+  // LSB would be first, this corrects that (and vice versa for big endian).
+  template <typename T> T ReverseFieldOrder(T value) const {
+    T ret = 0;
+    unsigned shift = 0;
+    for (auto field : GetFields()) {
+      ret |= field.GetValue(value) << shift;
+      shift += field.GetSizeInBits();
+    }
+
+    return ret;
+  }
+
   const std::vector<Field> &GetFields() const { return m_fields; }
   const std::string &GetID() const { return m_id; }
   unsigned GetSize() const { return m_size; }
Index: lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
===================================================================
--- lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
+++ lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h
@@ -53,6 +53,8 @@
                              const DumpValueObjectOptions &, Stream &)>
       DeclPrintingHelper;
 
+  typedef std::function<bool(ConstString)> ChildPrintingDecider;
+
   static const DumpValueObjectOptions DefaultOptions() {
     static DumpValueObjectOptions g_default_options;
 
@@ -70,6 +72,8 @@
 
   DumpValueObjectOptions &SetDeclPrintingHelper(DeclPrintingHelper helper);
 
+  DumpValueObjectOptions &SetChildPrintingDecider(ChildPrintingDecider decider);
+
   DumpValueObjectOptions &SetShowTypes(bool show = false);
 
   DumpValueObjectOptions &SetShowLocation(bool show = false);
@@ -136,6 +140,7 @@
   lldb::LanguageType m_varformat_language = lldb::eLanguageTypeUnknown;
   PointerDepth m_max_ptr_depth;
   DeclPrintingHelper m_decl_printing_helper;
+  ChildPrintingDecider m_child_printing_decider;
   PointerAsArraySettings m_pointer_as_array;
   bool m_use_synthetic : 1;
   bool m_scope_already_checked : 1;
Index: lldb/include/lldb/Core/PluginManager.h
===================================================================
--- lldb/include/lldb/Core/PluginManager.h
+++ lldb/include/lldb/Core/PluginManager.h
@@ -253,6 +253,15 @@
   static void AutoCompleteProcessName(llvm::StringRef partial_name,
                                       CompletionRequest &request);
 
+  // Register Type Provider
+  static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
+                             RegisterTypeBuilderCreateInstance create_callback);
+
+  static bool
+  UnregisterPlugin(RegisterTypeBuilderCreateInstance create_callback);
+
+  static lldb::RegisterTypeBuilderSP GetRegisterTypeBuilder(Target &target);
+
   // ScriptInterpreter
   static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description,
                              lldb::ScriptLanguage script_lang,
Index: lldb/include/lldb/Core/DumpRegisterValue.h
===================================================================
--- lldb/include/lldb/Core/DumpRegisterValue.h
+++ lldb/include/lldb/Core/DumpRegisterValue.h
@@ -10,6 +10,7 @@
 #define LLDB_CORE_DUMPREGISTERVALUE_H
 
 #include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
 #include <cstdint>
 
 namespace lldb_private {
@@ -21,11 +22,15 @@
 
 // The default value of 0 for reg_name_right_align_at means no alignment at
 // all.
+// Set print_flags to true to print register fields if they are available.
+// If you do so, target_sp must be non-null for it to work.
 void DumpRegisterValue(const RegisterValue &reg_val, Stream *s,
                        const RegisterInfo *reg_info, bool prefix_with_name,
                        bool prefix_with_alt_name, lldb::Format format,
                        uint32_t reg_name_right_align_at = 0,
-                       ExecutionContextScope *exe_scope = nullptr);
+                       ExecutionContextScope *exe_scope = nullptr,
+                       bool print_flags = false,
+                       lldb::TargetSP target_sp = nullptr);
 
 } // namespace lldb_private
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to