[Lldb-commits] [lldb] 3254168 - [lldb][AArch64/Linux] Show memory tagged memory regions

David Spickett via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 20 03:22:08 PST 2020


Author: David Spickett
Date: 2020-11-20T11:21:59Z
New Revision: 32541685b2a980290c320adb289b56395a88d4c3

URL: https://github.com/llvm/llvm-project/commit/32541685b2a980290c320adb289b56395a88d4c3
DIFF: https://github.com/llvm/llvm-project/commit/32541685b2a980290c320adb289b56395a88d4c3.diff

LOG: [lldb][AArch64/Linux] Show memory tagged memory regions

This extends the "memory region" command to
show tagged regions on AArch64 Linux when the MTE
extension is enabled.

(lldb) memory region the_page
[0x0000fffff7ff8000-0x0000fffff7ff9000) rw-
memory tagging: enabled

This is done by adding an optional "flags" field to
the qMemoryRegion packet. The only supported flag is
"mt" but this can be extended.

This "mt" flag is read from /proc/{pid}/smaps on Linux,
other platforms will leave out the "flags" field.

Where this "mt" flag is received "memory region" will
show that it is enabled. If it is not or the target
doesn't support memory tagging, the line is not shown.
(since majority of the time tagging will not be enabled)

Testing is added for the existing /proc/{pid}/maps
parsing and the new smaps parsing.
Minidump parsing has been updated where needed,
though it only uses maps not smaps.

Target specific tests can be run with QEMU and I have
added MTE flags to the existing helper scripts.

Reviewed By: labath

Differential Revision: https://reviews.llvm.org/D87442

Added: 
    lldb/test/API/linux/aarch64/mte_memory_region/Makefile
    lldb/test/API/linux/aarch64/mte_memory_region/TestAArch64LinuxMTEMemoryRegion.py
    lldb/test/API/linux/aarch64/mte_memory_region/main.c
    lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp

Modified: 
    lldb/docs/lldb-gdb-remote.txt
    lldb/docs/use/qemu-testing.rst
    lldb/include/lldb/Target/MemoryRegionInfo.h
    lldb/packages/Python/lldbsuite/test/lldbtest.py
    lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
    lldb/scripts/lldb-test-qemu/run-qemu.sh
    lldb/source/Commands/CommandObjectMemory.cpp
    lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
    lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
    lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
    lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
    lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
    lldb/source/Target/MemoryRegionInfo.cpp
    lldb/unittests/Process/Utility/CMakeLists.txt
    lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
    lldb/unittests/Process/minidump/MinidumpParserTest.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt
index 91f6a4d12c2e..7d333c8c8e6e 100644
--- a/lldb/docs/lldb-gdb-remote.txt
+++ b/lldb/docs/lldb-gdb-remote.txt
@@ -1123,6 +1123,11 @@ tuples to return are:
                  // the file while for anonymous regions it have to be the name
                  // associated to the region if that is available.
 
+    flags:<flags-string>; // where <flags-string> is a space separated string
+                          // of flag names. Currently the only supported flag
+                          // is "mt" for AArch64 memory tagging. lldb will
+                          // ignore any other flags in this field.
+
     error:<ascii-byte-error-string>; // where <ascii-byte-error-string> is
                                      // a hex encoded string value that
                                      // contains an error string

diff  --git a/lldb/docs/use/qemu-testing.rst b/lldb/docs/use/qemu-testing.rst
index a82dfb23a16a..a523137c8710 100644
--- a/lldb/docs/use/qemu-testing.rst
+++ b/lldb/docs/use/qemu-testing.rst
@@ -93,6 +93,9 @@ run-qemu.sh has following dependencies:
 
 * --sve option will enable AArch64 SVE mode.
 
+* --mte option will enable AArch64 MTE (memory tagging) mode.
+  (can be used on its own or in addition to --sve)
+
 
 **Example:** Run QEMU Arm or AArch64 system emulation using run-qemu.sh
 ::

diff  --git a/lldb/include/lldb/Target/MemoryRegionInfo.h b/lldb/include/lldb/Target/MemoryRegionInfo.h
index a22da8d72b83..19c6c17ef901 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfo.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -24,16 +24,17 @@ class MemoryRegionInfo {
   MemoryRegionInfo() = default;
   MemoryRegionInfo(RangeType range, OptionalBool read, OptionalBool write,
                    OptionalBool execute, OptionalBool mapped, ConstString name,
-                   OptionalBool flash, lldb::offset_t blocksize)
+                   OptionalBool flash, lldb::offset_t blocksize,
+                   OptionalBool memory_tagged)
       : m_range(range), m_read(read), m_write(write), m_execute(execute),
-        m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize) {
-  }
+        m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize),
+        m_memory_tagged(memory_tagged) {}
 
   RangeType &GetRange() { return m_range; }
 
   void Clear() {
     m_range.Clear();
-    m_read = m_write = m_execute = eDontKnow;
+    m_read = m_write = m_execute = m_memory_tagged = eDontKnow;
   }
 
   const RangeType &GetRange() const { return m_range; }
@@ -48,6 +49,8 @@ class MemoryRegionInfo {
 
   ConstString GetName() const { return m_name; }
 
+  OptionalBool GetMemoryTagged() const { return m_memory_tagged; }
+
   void SetReadable(OptionalBool val) { m_read = val; }
 
   void SetWritable(OptionalBool val) { m_write = val; }
@@ -66,6 +69,8 @@ class MemoryRegionInfo {
 
   void SetBlocksize(lldb::offset_t blocksize) { m_blocksize = blocksize; }
 
+  void SetMemoryTagged(OptionalBool val) { m_memory_tagged = val; }
+
   // Get permissions as a uint32_t that is a mask of one or more bits from the
   // lldb::Permissions
   uint32_t GetLLDBPermissions() const {
@@ -91,7 +96,8 @@ class MemoryRegionInfo {
     return m_range == rhs.m_range && m_read == rhs.m_read &&
            m_write == rhs.m_write && m_execute == rhs.m_execute &&
            m_mapped == rhs.m_mapped && m_name == rhs.m_name &&
-           m_flash == rhs.m_flash && m_blocksize == rhs.m_blocksize;
+           m_flash == rhs.m_flash && m_blocksize == rhs.m_blocksize &&
+           m_memory_tagged == rhs.m_memory_tagged;
   }
 
   bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); }
@@ -105,6 +111,7 @@ class MemoryRegionInfo {
   ConstString m_name;
   OptionalBool m_flash = eDontKnow;
   lldb::offset_t m_blocksize = 0;
+  OptionalBool m_memory_tagged = eDontKnow;
 };
   
 inline bool operator<(const MemoryRegionInfo &lhs,

diff  --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index a02c445a937a..7ba3a154db4a 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -1318,6 +1318,30 @@ def isAArch64SVE(self):
 
         return " sve " in cpuinfo
 
+    def hasLinuxVmFlags(self):
+        """ Check that the target machine has "VmFlags" lines in
+        its /proc/{pid}/smaps files."""
+
+        triple = self.dbg.GetSelectedPlatform().GetTriple()
+        if not re.match(".*-.*-linux", triple):
+            return False
+
+        self.runCmd('platform process list')
+        pid = None
+        for line in self.res.GetOutput().splitlines():
+            if 'lldb-server' in line:
+                pid = line.split(' ')[0]
+                break
+
+        if pid is None:
+            return False
+
+        smaps_path = self.getBuildArtifact('smaps')
+        self.runCmd('platform get-file "/proc/{}/smaps" {}'.format(pid, smaps_path))
+
+        with open(smaps_path, 'r') as f:
+            return "VmFlags" in f.read()
+
     def getArchitecture(self):
         """Returns the architecture in effect the test suite is running with."""
         module = builder_module()

diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
index a0e3cb362944..ce700d9403f4 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -727,13 +727,13 @@ def parse_memory_region_packet(self, context):
 
         # Validate keys are known.
         for (key, val) in list(mem_region_dict.items()):
-            self.assertTrue(
-                key in [
-                    "start",
-                    "size",
-                    "permissions",
-                    "name",
-                    "error"])
+            self.assertIn(key,
+                ["start",
+                 "size",
+                 "permissions",
+                 "flags",
+                 "name",
+                 "error"])
             self.assertIsNotNone(val)
 
         mem_region_dict["name"] = seven.unhexlify(mem_region_dict.get("name", ""))

diff  --git a/lldb/scripts/lldb-test-qemu/run-qemu.sh b/lldb/scripts/lldb-test-qemu/run-qemu.sh
index cb28b7aaf642..339b8d955e61 100644
--- a/lldb/scripts/lldb-test-qemu/run-qemu.sh
+++ b/lldb/scripts/lldb-test-qemu/run-qemu.sh
@@ -5,7 +5,8 @@ print_usage() {
   echo -e "Starts QEMU system mode emulation for the architecture.\n"
   echo -e "  --help\t\t\tDisplay this information."
   echo -e "  --arch {arm|arm64}\t\tSelects architecture QEMU system emulation."
-  echo -e "  --sve {path}\t\t\tEnables AArch64 SVE mode.\n"
+  echo -e "  --sve\t\t\t\tEnables AArch64 SVE mode."
+  echo -e "  --mte\t\t\t\tEnables AArch64 MTE mode.\n"
   echo -e "  --rootfs {path}\t\tPath of root file system image."
   echo -e "  --qemu {path}\t\t\tPath of pre-installed qemu-system-* executable."
   echo -e "  --kernel {path}\t\tPath of Linux kernel prebuilt image.\n"
@@ -48,6 +49,7 @@ while [[ $# -gt 0 ]]; do
     --kernel)   KERNEL_IMG=$2; shift;;
     --qemu)     QEMU_BIN=$2; shift;;
     --sve)      SVE=1;;
+    --mte)      MTE=1;;
     --help)     print_usage 0 ;;
     *)          invalid_arg "$1" ;;
   esac
@@ -99,6 +101,9 @@ if [[ "$ARCH" == "arm" ]]; then
   if [[ $SVE ]]; then
     echo "warning: --sve is supported by AArch64 targets only"
   fi
+  if [[ $MTE ]]; then
+    echo "warning: --mte is supported by AArch64 targets only"
+  fi
 elif [[ "$ARCH" == "arm64" ]]; then
   QEMU_MACHINE=virt
   QEMU_SVE_MAX_VQ=4
@@ -107,6 +112,9 @@ elif [[ "$ARCH" == "arm64" ]]; then
   if [[ $SVE ]]; then
     QEMU_CPU="max,sve-max-vq=$QEMU_SVE_MAX_VQ"
   fi
+  if [[ $MTE ]]; then
+    QEMU_MACHINE="$QEMU_MACHINE,mte=on"
+  fi
 fi
 
 run_qemu

diff  --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index 20a1fbb0f1b2..7d5c642d0131 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -1709,12 +1709,18 @@ class CommandObjectMemoryRegion : public CommandObjectParsed {
           section_name = section_sp->GetName();
         }
       }
+
       result.AppendMessageWithFormatv(
-          "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}\n",
+          "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",
           range_info.GetRange().GetRangeBase(),
           range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),
           range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",
           name, section_name ? " " : "", section_name);
+      MemoryRegionInfo::OptionalBool memory_tagged =
+          range_info.GetMemoryTagged();
+      if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)
+        result.AppendMessage("memory tagging: enabled");
+
       m_prev_end_addr = range_info.GetRange().GetRangeEnd();
       result.SetStatus(eReturnStatusSuccessFinishResult);
       return true;

diff  --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 9883e1cfc532..e07d763c2de7 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1297,26 +1297,36 @@ Status NativeProcessLinux::PopulateMemoryRegionCache() {
     return Status();
   }
 
-  auto BufferOrError = getProcFile(GetID(), "maps");
-  if (!BufferOrError) {
+  Status Result;
+  LinuxMapCallback callback = [&](llvm::Expected<MemoryRegionInfo> Info) {
+    if (Info) {
+      FileSpec file_spec(Info->GetName().GetCString());
+      FileSystem::Instance().Resolve(file_spec);
+      m_mem_region_cache.emplace_back(*Info, file_spec);
+      return true;
+    }
+
+    Result = Info.takeError();
     m_supports_mem_region = LazyBool::eLazyBoolNo;
-    return BufferOrError.getError();
+    LLDB_LOG(log, "failed to parse proc maps: {0}", Result);
+    return false;
+  };
+
+  // Linux kernel since 2.6.14 has /proc/{pid}/smaps
+  // if CONFIG_PROC_PAGE_MONITOR is enabled
+  auto BufferOrError = getProcFile(GetID(), "smaps");
+  if (BufferOrError)
+    ParseLinuxSMapRegions(BufferOrError.get()->getBuffer(), callback);
+  else {
+    BufferOrError = getProcFile(GetID(), "maps");
+    if (!BufferOrError) {
+      m_supports_mem_region = LazyBool::eLazyBoolNo;
+      return BufferOrError.getError();
+    }
+
+    ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), callback);
   }
-  Status Result;
-  ParseLinuxMapRegions(BufferOrError.get()->getBuffer(),
-                       [&](const MemoryRegionInfo &Info, const Status &ST) {
-                         if (ST.Success()) {
-                           FileSpec file_spec(Info.GetName().GetCString());
-                           FileSystem::Instance().Resolve(file_spec);
-                           m_mem_region_cache.emplace_back(Info, file_spec);
-                           return true;
-                         } else {
-                           m_supports_mem_region = LazyBool::eLazyBoolNo;
-                           LLDB_LOG(log, "failed to parse proc maps: {0}", ST);
-                           Result = ST;
-                           return false;
-                         }
-                       });
+
   if (Result.Fail())
     return Result;
 

diff  --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
index 0c7d9ddc5ac6..947b970edf6c 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -7,80 +7,93 @@
 //===----------------------------------------------------------------------===//
 
 #include "LinuxProcMaps.h"
-#include "llvm/ADT/StringRef.h"
 #include "lldb/Target/MemoryRegionInfo.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/StringRef.h"
 
 using namespace lldb_private;
 
-static Status
+enum class MapsKind { Maps, SMaps };
+
+static llvm::Expected<MemoryRegionInfo> ProcMapError(const char *msg,
+                                                     MapsKind kind) {
+  return llvm::createStringError(llvm::inconvertibleErrorCode(), msg,
+                                 kind == MapsKind::Maps ? "maps" : "smaps");
+}
+
+static llvm::Expected<MemoryRegionInfo>
 ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
-                                      MemoryRegionInfo &memory_region_info) {
-  memory_region_info.Clear();
-  
+                                      MapsKind maps_kind) {
+  MemoryRegionInfo region;
   StringExtractor line_extractor(maps_line);
-  
+
   // Format: {address_start_hex}-{address_end_hex} perms offset  dev   inode
   // pathname perms: rwxp   (letter is present if set, '-' if not, final
   // character is p=private, s=shared).
-  
+
   // Parse out the starting address
   lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0);
-  
+
   // Parse out hyphen separating start and end address from range.
   if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-'))
-    return Status(
-        "malformed /proc/{pid}/maps entry, missing dash between address range");
-  
+    return ProcMapError(
+        "malformed /proc/{pid}/%s entry, missing dash between address range",
+        maps_kind);
+
   // Parse out the ending address
   lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address);
-  
+
   // Parse out the space after the address.
   if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' '))
-    return Status(
-        "malformed /proc/{pid}/maps entry, missing space after range");
-  
+    return ProcMapError(
+        "malformed /proc/{pid}/%s entry, missing space after range", maps_kind);
+
   // Save the range.
-  memory_region_info.GetRange().SetRangeBase(start_address);
-  memory_region_info.GetRange().SetRangeEnd(end_address);
-  
-  // Any memory region in /proc/{pid}/maps is by definition mapped into the
-  // process.
-  memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
-  
+  region.GetRange().SetRangeBase(start_address);
+  region.GetRange().SetRangeEnd(end_address);
+
+  // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped
+  // into the process.
+  region.SetMapped(MemoryRegionInfo::OptionalBool::eYes);
+
   // Parse out each permission entry.
   if (line_extractor.GetBytesLeft() < 4)
-    return Status("malformed /proc/{pid}/maps entry, missing some portion of "
-                  "permissions");
-  
+    return ProcMapError(
+        "malformed /proc/{pid}/%s entry, missing some portion of "
+        "permissions",
+        maps_kind);
+
   // Handle read permission.
   const char read_perm_char = line_extractor.GetChar();
   if (read_perm_char == 'r')
-    memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
+    region.SetReadable(MemoryRegionInfo::OptionalBool::eYes);
   else if (read_perm_char == '-')
-    memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
+    region.SetReadable(MemoryRegionInfo::OptionalBool::eNo);
   else
-    return Status("unexpected /proc/{pid}/maps read permission char");
-  
+    return ProcMapError("unexpected /proc/{pid}/%s read permission char",
+                        maps_kind);
+
   // Handle write permission.
   const char write_perm_char = line_extractor.GetChar();
   if (write_perm_char == 'w')
-    memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
+    region.SetWritable(MemoryRegionInfo::OptionalBool::eYes);
   else if (write_perm_char == '-')
-    memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
+    region.SetWritable(MemoryRegionInfo::OptionalBool::eNo);
   else
-    return Status("unexpected /proc/{pid}/maps write permission char");
-  
+    return ProcMapError("unexpected /proc/{pid}/%s write permission char",
+                        maps_kind);
+
   // Handle execute permission.
   const char exec_perm_char = line_extractor.GetChar();
   if (exec_perm_char == 'x')
-    memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
+    region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes);
   else if (exec_perm_char == '-')
-    memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
+    region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo);
   else
-    return Status("unexpected /proc/{pid}/maps exec permission char");
-  
+    return ProcMapError("unexpected /proc/{pid}/%s exec permission char",
+                        maps_kind);
+
   line_extractor.GetChar();              // Read the private bit
   line_extractor.SkipSpaces();           // Skip the separator
   line_extractor.GetHexMaxU64(false, 0); // Read the offset
@@ -89,13 +102,13 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
   line_extractor.GetHexMaxU64(false, 0); // Read the major device number
   line_extractor.SkipSpaces();           // Skip the separator
   line_extractor.GetU64(0, 10);          // Read the inode number
-  
+
   line_extractor.SkipSpaces();
   const char *name = line_extractor.Peek();
   if (name)
-    memory_region_info.SetName(name);
-  
-  return Status();
+    region.SetName(name);
+
+  return region;
 }
 
 void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
@@ -104,9 +117,80 @@ void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map,
   llvm::StringRef line;
   while (!lines.empty()) {
     std::tie(line, lines) = lines.split('\n');
-    MemoryRegionInfo region;
-    Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
-    if (!callback(region, error))
+    if (!callback(ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::Maps)))
       break;
   }
 }
+
+void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+                                         LinuxMapCallback const &callback) {
+  // Entries in /smaps look like:
+  // 00400000-0048a000 r-xp 00000000 fd:03 960637
+  // Size:                552 kB
+  // Rss:                 460 kB
+  // <...>
+  // VmFlags: rd ex mr mw me dw
+  // 00500000-0058a000 rwxp 00000000 fd:03 960637
+  // <...>
+  //
+  // Where the first line is identical to the /maps format
+  // and VmFlags is only printed for kernels >= 3.8.
+
+  llvm::StringRef lines(linux_smap);
+  llvm::StringRef line;
+  llvm::Optional<MemoryRegionInfo> region;
+
+  while (lines.size()) {
+    std::tie(line, lines) = lines.split('\n');
+
+    // A property line looks like:
+    // <word>: <value>
+    // (no spaces on the left hand side)
+    // A header will have a ':' but the LHS will contain spaces
+    llvm::StringRef name;
+    llvm::StringRef value;
+    std::tie(name, value) = line.split(':');
+
+    // If this line is a property line
+    if (!name.contains(' ')) {
+      if (region) {
+        if (name == "VmFlags") {
+          if (value.contains("mt"))
+            region->SetMemoryTagged(MemoryRegionInfo::eYes);
+          else
+            region->SetMemoryTagged(MemoryRegionInfo::eNo);
+        }
+        // Ignore anything else
+      } else {
+        // Orphaned settings line
+        callback(ProcMapError(
+            "Found a property line without a corresponding mapping "
+            "in /proc/{pid}/%s",
+            MapsKind::SMaps));
+        return;
+      }
+    } else {
+      // Must be a new region header
+      if (region) {
+        // Save current region
+        callback(*region);
+        region.reset();
+      }
+
+      // Try to start a new region
+      llvm::Expected<MemoryRegionInfo> new_region =
+          ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::SMaps);
+      if (new_region) {
+        region = *new_region;
+      } else {
+        // Stop at first invalid region header
+        callback(new_region.takeError());
+        return;
+      }
+    }
+  }
+
+  // Catch last region
+  if (region)
+    callback(*region);
+}

diff  --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
index 363f248fd416..02f78d55c290 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
@@ -11,16 +11,16 @@
 
 #include "lldb/lldb-forward.h"
 #include "llvm/ADT/StringRef.h"
-#include <functional>
-
+#include "llvm/Support/Error.h"
 
 namespace lldb_private {
 
-typedef std::function<bool(const lldb_private::MemoryRegionInfo &,
-                           const lldb_private::Status &)> LinuxMapCallback;
+typedef std::function<bool(llvm::Expected<MemoryRegionInfo>)> LinuxMapCallback;
 
 void ParseLinuxMapRegions(llvm::StringRef linux_map,
                           LinuxMapCallback const &callback);
+void ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+                           LinuxMapCallback const &callback);
 
 } // namespace lldb_private
 

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index b1552a3a43ad..d375a312ae2c 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1529,6 +1529,22 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
           std::string name;
           name_extractor.GetHexByteString(name);
           region_info.SetName(name.c_str());
+        } else if (name.equals("flags")) {
+          region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+
+          llvm::StringRef flags = value;
+          llvm::StringRef flag;
+          while (flags.size()) {
+            flags = flags.ltrim();
+            std::tie(flag, flags) = flags.split(' ');
+            // To account for trailing whitespace
+            if (flag.size()) {
+              if (flag == "mt") {
+                region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
+                break;
+              }
+            }
+          }
         } else if (name.equals("error")) {
           StringExtractorGDBRemote error_extractor(value);
           std::string error_string;

diff  --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 2e57d7e3ecae..2cf88c0d9f70 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2605,6 +2605,17 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
       response.PutChar(';');
     }
 
+    // Flags
+    MemoryRegionInfo::OptionalBool memory_tagged =
+        region_info.GetMemoryTagged();
+    if (memory_tagged != MemoryRegionInfo::eDontKnow) {
+      response.PutCString("flags:");
+      if (memory_tagged == MemoryRegionInfo::eYes) {
+        response.PutCString("mt");
+      }
+      response.PutChar(';');
+    }
+
     // Name
     ConstString name = region_info.GetName();
     if (name) {

diff  --git a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
index 9108d4d18aa5..e16f86cca1c2 100644
--- a/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
+++ b/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -263,13 +263,18 @@ CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser,
   auto data = parser.GetStream(StreamType::LinuxMaps);
   if (data.empty())
     return false;
-  ParseLinuxMapRegions(llvm::toStringRef(data),
-                       [&](const lldb_private::MemoryRegionInfo &region,
-                           const lldb_private::Status &status) -> bool {
-                         if (status.Success())
-                           regions.push_back(region);
-                         return true;
-                       });
+
+  Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS);
+  ParseLinuxMapRegions(
+      llvm::toStringRef(data),
+      [&regions, &log](llvm::Expected<MemoryRegionInfo> region) -> bool {
+        if (region)
+          regions.push_back(*region);
+        else
+          LLDB_LOG_ERROR(log, region.takeError(),
+                         "Reading memory region from minidump failed: {0}");
+        return true;
+      });
   return !regions.empty();
 }
 

diff  --git a/lldb/source/Target/MemoryRegionInfo.cpp b/lldb/source/Target/MemoryRegionInfo.cpp
index c7fb349ee1cc..0d5ebbdbe238 100644
--- a/lldb/source/Target/MemoryRegionInfo.cpp
+++ b/lldb/source/Target/MemoryRegionInfo.cpp
@@ -13,12 +13,12 @@ using namespace lldb_private;
 llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS,
                                             const MemoryRegionInfo &Info) {
   return OS << llvm::formatv("MemoryRegionInfo([{0}, {1}), {2:r}{3:w}{4:x}, "
-                             "{5}, `{6}`, {7}, {8})",
+                             "{5}, `{6}`, {7}, {8}, {9})",
                              Info.GetRange().GetRangeBase(),
                              Info.GetRange().GetRangeEnd(), Info.GetReadable(),
                              Info.GetWritable(), Info.GetExecutable(),
                              Info.GetMapped(), Info.GetName(), Info.GetFlash(),
-                             Info.GetBlocksize());
+                             Info.GetBlocksize(), Info.GetMemoryTagged());
 }
 
 void llvm::format_provider<MemoryRegionInfo::OptionalBool>::format(

diff  --git a/lldb/test/API/linux/aarch64/mte_memory_region/Makefile b/lldb/test/API/linux/aarch64/mte_memory_region/Makefile
new file mode 100644
index 000000000000..10495940055b
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/mte_memory_region/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules

diff  --git a/lldb/test/API/linux/aarch64/mte_memory_region/TestAArch64LinuxMTEMemoryRegion.py b/lldb/test/API/linux/aarch64/mte_memory_region/TestAArch64LinuxMTEMemoryRegion.py
new file mode 100644
index 000000000000..ff8e01cb28c8
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/mte_memory_region/TestAArch64LinuxMTEMemoryRegion.py
@@ -0,0 +1,55 @@
+"""
+Test that "memory region" command can show memory tagged regions
+on AArch64 Linux.
+"""
+
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class AArch64LinuxMTEMemoryRegionTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    NO_DEBUG_INFO_TESTCASE = True
+
+    @skipIf(archs=no_match(["aarch64"]))
+    @skipUnlessPlatform(["linux"])
+    def test_mte_regions(self):
+        if not self.hasLinuxVmFlags():
+            self.skipTest('/proc/{pid}/smaps VmFlags must be present')
+
+        self.build()
+        self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(self, "main.c",
+            line_number('main.c', '// Set break point at this line.'),
+            num_expected_locations=1)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        if self.process().GetState() == lldb.eStateExited:
+            # 47 = non MTE toolchain
+            # 48 = non MTE target
+            exit_status = self.process().GetExitStatus()
+            if exit_status == 47:
+                self.skipTest("MTE must be available in toolchain")
+            elif exit_status == 48:
+                self.skipTest("target must have MTE enabled")
+
+            # Otherwise we have MTE but another problem occured
+            self.fail("Test program failed to run.")
+
+        self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
+            substrs=['stopped',
+                     'stop reason = breakpoint'])
+
+        substrs = ["memory tagging: enabled"]
+        # The new page will be tagged
+        self.expect("memory region the_page", substrs=substrs)
+        # Code page will not be
+        self.expect("memory region main", substrs=substrs, matching=False)

diff  --git a/lldb/test/API/linux/aarch64/mte_memory_region/main.c b/lldb/test/API/linux/aarch64/mte_memory_region/main.c
new file mode 100644
index 000000000000..17c135dc3344
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/mte_memory_region/main.c
@@ -0,0 +1,44 @@
+#include <asm/hwcap.h>
+#include <asm/mman.h>
+#include <sys/auxv.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#define INCOMPATIBLE_TOOLCHAIN 47
+#define INCOMPATIBLE_TARGET 48
+
+// This is in a seperate non static function
+// so that we can always breakpoint the return 0 here.
+// Even if main never reaches it because HWCAP2_MTE
+// is not defined.
+// If it were in main then you would effectively have:
+// return TEST_INCOMPATIBLE;
+// return 0;
+// So the two returns would have the same breakpoint location
+// and we couldn't tell them apart.
+int setup_mte_page(void) {
+#ifdef HWCAP2_MTE
+  if (!(getauxval(AT_HWCAP2) & HWCAP2_MTE))
+    return INCOMPATIBLE_TARGET;
+
+  int got = prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0);
+  if (got)
+    return 1;
+
+  void *the_page = mmap(0, sysconf(_SC_PAGESIZE), PROT_MTE,
+                        MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (the_page == MAP_FAILED)
+    return 1;
+#endif
+
+  return 0; // Set break point at this line.
+}
+
+int main(int argc, char const *argv[]) {
+#ifdef HWCAP2_MTE
+  return setup_mte_page();
+#else
+  return INCOMPATIBLE_TOOLCHAIN;
+#endif
+}

diff  --git a/lldb/unittests/Process/Utility/CMakeLists.txt b/lldb/unittests/Process/Utility/CMakeLists.txt
index 0041a94a79a3..9d827582b3cf 100644
--- a/lldb/unittests/Process/Utility/CMakeLists.txt
+++ b/lldb/unittests/Process/Utility/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_unittest(ProcessUtilityTests
   RegisterContextFreeBSDTest.cpp
+  LinuxProcMapsTest.cpp
 
   LINK_LIBS
     lldbPluginProcessUtility)

diff  --git a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
new file mode 100644
index 000000000000..203875533d93
--- /dev/null
+++ b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
@@ -0,0 +1,262 @@
+//===-- LinuxProcMapsTest.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 "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "Plugins/Process/Utility/LinuxProcMaps.h"
+#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/Status.h"
+#include <tuple>
+
+using namespace lldb_private;
+
+typedef std::tuple<const char *, MemoryRegionInfos, const char *>
+    LinuxProcMapsTestParams;
+
+// Wrapper for convenience because Range is usually begin, size
+static MemoryRegionInfo::RangeType make_range(lldb::addr_t begin,
+                                              lldb::addr_t end) {
+  MemoryRegionInfo::RangeType range(begin, 0);
+  range.SetRangeEnd(end);
+  return range;
+}
+
+class LinuxProcMapsTestFixture
+    : public ::testing::TestWithParam<LinuxProcMapsTestParams> {
+protected:
+  Status error;
+  std::string err_str;
+  MemoryRegionInfos regions;
+  LinuxMapCallback callback;
+
+  void SetUp() override {
+    callback = [this](llvm::Expected<MemoryRegionInfo> Info) {
+      if (Info) {
+        err_str.clear();
+        regions.push_back(*Info);
+        return true;
+      }
+
+      err_str = toString(Info.takeError());
+      return false;
+    };
+  }
+
+  void check_regions(LinuxProcMapsTestParams params) {
+    EXPECT_THAT(std::get<1>(params), testing::ContainerEq(regions));
+    ASSERT_EQ(std::get<2>(params), err_str);
+  }
+};
+
+TEST_P(LinuxProcMapsTestFixture, ParseMapRegions) {
+  auto params = GetParam();
+  ParseLinuxMapRegions(std::get<0>(params), callback);
+  check_regions(params);
+}
+
+// Note: ConstString("") != ConstString(nullptr)
+// When a region has no name, it will have the latter in the MemoryRegionInfo
+INSTANTIATE_TEST_CASE_P(
+    ProcMapTests, LinuxProcMapsTestFixture,
+    ::testing::Values(
+        // Nothing in nothing out
+        std::make_tuple("", MemoryRegionInfos{}, ""),
+        // Various formatting error conditions
+        std::make_tuple("55a4512f7000/55a451b68000 rw-p 00000000 00:00 0",
+                        MemoryRegionInfos{},
+                        "malformed /proc/{pid}/maps entry, missing dash "
+                        "between address range"),
+        std::make_tuple("0-0 rw", MemoryRegionInfos{},
+                        "malformed /proc/{pid}/maps entry, missing some "
+                        "portion of permissions"),
+        std::make_tuple("0-0 z--p 00000000 00:00 0", MemoryRegionInfos{},
+                        "unexpected /proc/{pid}/maps read permission char"),
+        std::make_tuple("0-0 rz-p 00000000 00:00 0", MemoryRegionInfos{},
+                        "unexpected /proc/{pid}/maps write permission char"),
+        std::make_tuple("0-0 rwzp 00000000 00:00 0", MemoryRegionInfos{},
+                        "unexpected /proc/{pid}/maps exec permission char"),
+        // Stops at first parsing error
+        std::make_tuple(
+            "0-1 rw-p 00000000 00:00 0 [abc]\n"
+            "0-0 rwzp 00000000 00:00 0\n"
+            "2-3 r-xp 00000000 00:00 0 [def]\n",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0, 1), MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                                 MemoryRegionInfo::eYes, ConstString("[abc]"),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+            },
+            "unexpected /proc/{pid}/maps exec permission char"),
+        // Single entry
+        std::make_tuple(
+            "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0    [heap]",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x55a4512f7000, 0x55a451b68000),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString("[heap]"),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+            },
+            ""),
+        // Multiple entries
+        std::make_tuple(
+            "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n"
+            "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
+            "[vsyscall]",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x7fc090021000, 0x7fc094000000),
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eNo,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString(nullptr),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+                MemoryRegionInfo(
+                    make_range(0xffffffffff600000, 0xffffffffff601000),
+                    MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                    MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                    ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0,
+                    MemoryRegionInfo::eDontKnow),
+            },
+            "")), );
+
+class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {};
+
+INSTANTIATE_TEST_CASE_P(
+    ProcSMapTests, LinuxProcSMapsTestFixture,
+    ::testing::Values(
+        // Nothing in nothing out
+        std::make_tuple("", MemoryRegionInfos{}, ""),
+        // Uses the same parsing for first line, so same errors but referring to
+        // smaps
+        std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{},
+                        "malformed /proc/{pid}/smaps entry, missing dash "
+                        "between address range"),
+        // Stop parsing at first error
+        std::make_tuple(
+            "1111-2222 rw-p 00000000 00:00 0 [foo]\n"
+            "0/0 rw-p 00000000 00:00 0",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x1111, 0x2222),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString("[foo]"),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+            },
+            "malformed /proc/{pid}/smaps entry, missing dash between address "
+            "range"),
+        // Property line without a region is an error
+        std::make_tuple("Referenced:         2188 kB\n"
+                        "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
+                        "3333-4444 rw-p 00000000 00:00 0    [bar]\n",
+                        MemoryRegionInfos{},
+                        "Found a property line without a corresponding mapping "
+                        "in /proc/{pid}/smaps"),
+        // Single region parses, has no flags
+        std::make_tuple(
+            "1111-2222 rw-p 00000000 00:00 0    [foo]",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x1111, 0x2222),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString("[foo]"),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+            },
+            ""),
+        // Single region with flags, other lines ignored
+        std::make_tuple(
+            "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
+            "Referenced:         2188 kB\n"
+            "AnonHugePages:         0 kB\n"
+            "VmFlags: mt",
+            MemoryRegionInfos{
+                MemoryRegionInfo(
+                    make_range(0x1111, 0x2222), MemoryRegionInfo::eYes,
+                    MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                    MemoryRegionInfo::eYes, ConstString("[foo]"),
+                    MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes),
+            },
+            ""),
+        // Whitespace ignored
+        std::make_tuple(
+            "0-0 rw-p 00000000 00:00 0\n"
+            "VmFlags:      mt      ",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                                 MemoryRegionInfo::eYes, ConstString(nullptr),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eYes),
+            },
+            ""),
+        // VmFlags line means it has flag info, but nothing is set
+        std::make_tuple(
+            "0-0 rw-p 00000000 00:00 0\n"
+            "VmFlags:         ",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                                 MemoryRegionInfo::eYes, ConstString(nullptr),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eNo),
+            },
+            ""),
+        // Handle some pages not having a flags line
+        std::make_tuple(
+            "1111-2222 rw-p 00000000 00:00 0    [foo]\n"
+            "Referenced:         2188 kB\n"
+            "AnonHugePages:         0 kB\n"
+            "3333-4444 r-xp 00000000 00:00 0    [bar]\n"
+            "VmFlags: mt",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x1111, 0x2222),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString("[foo]"),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+                MemoryRegionInfo(
+                    make_range(0x3333, 0x4444), MemoryRegionInfo::eYes,
+                    MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                    MemoryRegionInfo::eYes, ConstString("[bar]"),
+                    MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes),
+            },
+            ""),
+        // Handle no pages having a flags line (older kernels)
+        std::make_tuple(
+            "1111-2222 rw-p 00000000 00:00 0\n"
+            "Referenced:         2188 kB\n"
+            "AnonHugePages:         0 kB\n"
+            "3333-4444 r-xp 00000000 00:00 0\n"
+            "KernelPageSize:        4 kB\n"
+            "MMUPageSize:           4 kB\n",
+            MemoryRegionInfos{
+                MemoryRegionInfo(make_range(0x1111, 0x2222),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+                                 ConstString(nullptr),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+                MemoryRegionInfo(make_range(0x3333, 0x4444),
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+                                 MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+                                 ConstString(nullptr),
+                                 MemoryRegionInfo::eDontKnow, 0,
+                                 MemoryRegionInfo::eDontKnow),
+            },
+            "")), );
+
+TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
+  auto params = GetParam();
+  ParseLinuxSMapRegions(std::get<0>(params), callback);
+  check_regions(params);
+}

diff  --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
index adfead6aed98..2cca197f63a1 100644
--- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -343,6 +343,25 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
   EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
   EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
   EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
+  EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged());
+
+  result = std::async(std::launch::async, [&] {
+    return client.GetMemoryRegionInfo(addr, region_info);
+  });
+
+  HandlePacket(server, "qMemoryRegionInfo:a000",
+               "start:a000;size:2000;flags:;");
+  EXPECT_TRUE(result.get().Success());
+  EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged());
+
+  result = std::async(std::launch::async, [&] {
+    return client.GetMemoryRegionInfo(addr, region_info);
+  });
+
+  HandlePacket(server, "qMemoryRegionInfo:a000",
+               "start:a000;size:2000;flags: mt  zz mt  ;");
+  EXPECT_TRUE(result.get().Success());
+  EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged());
 }
 
 TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {

diff  --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
index 25d7e237bd20..69046af283eb 100644
--- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
+++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -378,15 +378,15 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
       parser->BuildMemoryRegions(),
       testing::Pair(testing::ElementsAre(
                         MemoryRegionInfo({0x0, 0x10000}, no, no, no, no,
-                                         ConstString(), unknown, 0),
+                                         ConstString(), unknown, 0, unknown),
                         MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes,
-                                         ConstString(), unknown, 0),
+                                         ConstString(), unknown, 0, unknown),
                         MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes,
-                                         ConstString(), unknown, 0),
+                                         ConstString(), unknown, 0, unknown),
                         MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes,
-                                         ConstString(), unknown, 0),
+                                         ConstString(), unknown, 0, unknown),
                         MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes,
-                                         ConstString(), unknown, 0)),
+                                         ConstString(), unknown, 0, unknown)),
                     true));
 }
 
@@ -409,12 +409,13 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
 
   EXPECT_THAT(
       parser->BuildMemoryRegions(),
-      testing::Pair(testing::ElementsAre(
-                        MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,
-                                         yes, ConstString(), unknown, 0),
-                        MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,
-                                         yes, ConstString(), unknown, 0)),
-                    false));
+      testing::Pair(
+          testing::ElementsAre(
+              MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes,
+                               ConstString(), unknown, 0, unknown),
+              MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
+                               ConstString(), unknown, 0, unknown)),
+          false));
 }
 
 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
@@ -424,12 +425,13 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
   // we don't have a MemoryInfoListStream.
   EXPECT_THAT(
       parser->BuildMemoryRegions(),
-      testing::Pair(testing::ElementsAre(
-                        MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown,
-                                         yes, ConstString(), unknown, 0),
-                        MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown,
-                                         yes, ConstString(), unknown, 0)),
-                    false));
+      testing::Pair(
+          testing::ElementsAre(
+              MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes,
+                               ConstString(), unknown, 0, unknown),
+              MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
+                               ConstString(), unknown, 0, unknown)),
+          false));
 }
 
 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
@@ -453,22 +455,42 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
   ConstString app_process("/system/bin/app_process");
   ConstString linker("/system/bin/linker");
   ConstString liblog("/system/lib/liblog.so");
-  EXPECT_THAT(
-      parser->BuildMemoryRegions(),
-      testing::Pair(testing::ElementsAre(
-                        MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes,
-                                         yes, app_process, unknown, 0),
-                        MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes,
-                                         app_process, unknown, 0),
-                        MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no,
-                                         yes, ConstString(), unknown, 0),
-                        MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes,
-                                         ConstString(), unknown, 0),
-                        MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no,
-                                         yes, linker, unknown, 0),
-                        MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes,
-                                         yes, liblog, unknown, 0)),
-                    true));
+  EXPECT_THAT(parser->BuildMemoryRegions(),
+              testing::Pair(
+                  testing::ElementsAre(
+                      MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, yes,
+                                       app_process, unknown, 0, unknown),
+                      MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes,
+                                       app_process, unknown, 0, unknown),
+                      MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes,
+                                       ConstString(), unknown, 0, unknown),
+                      MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes,
+                                       ConstString(), unknown, 0, unknown),
+                      MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes,
+                                       linker, unknown, 0, unknown),
+                      MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes,
+                                       liblog, unknown, 0, unknown)),
+                  true));
+}
+
+TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
+  ASSERT_THAT_ERROR(SetUpFromYaml(R"(
+--- !minidump
+Streams:
+  - Type:            LinuxMaps
+    Text:             |
+      400d9000-400db000 r?xp 00000000 b3:04 227
+      400fc000-400fd000 rwxp 00001000 b3:04 1096
+...
+)"),
+                    llvm::Succeeded());
+  // Test that when a /proc/maps region fails to parse
+  // we handle the error and continue with the rest.
+  EXPECT_THAT(parser->BuildMemoryRegions(),
+              testing::Pair(testing::ElementsAre(MemoryRegionInfo(
+                                {0x400fc000, 0x1000}, yes, yes, yes, yes,
+                                ConstString(nullptr), unknown, 0, unknown)),
+                            true));
 }
 
 // Windows Minidump tests


        


More information about the lldb-commits mailing list