llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: David Spickett (DavidSpickett)

<details>
<summary>Changes</summary>

In this change I'm extending the "memory region" command to show users the 
overlay permissions that a protection key refers to, and the result of
applying that overlay to the page table permissions.

For example, protection key 0 refers to Perm0 in the por register.
```
(lldb) register read por 
             Perm0 = Read, Write, Execute
```
This is the default key, so many regions use it. 
```
(lldb) memory region --all
&lt;...&gt;
[0x000ffffff7db0000-0x000ffffff7f40000) r-x 
/usr/lib/aarch64-linux-gnu/libc.so.6 PT_LOAD[0]
protection key: 0 (rwx, effective: r-x)
```
Protection keys can only change what was already enabled in the 
page table. So we start with read and execute. Then a read/write/execute overlay
is applied. We cannot add write, so the result is read and execute.

Here's an example of its use with a real crash (output edited):
```
(lldb) c
* thread #<!-- -->1, name = 'test.o', stop reason = signal SIGSEGV: failed 
protection key checks (fault address=0xffffff7d60000)
-&gt; 106    read_only_page[0] = '?';
(lldb) memory region 0xffffff7d60000
[0x000ffffff7d60000-0x000ffffff7d70000) rw- 
protection key: 6 (r--, effective: r--)
(lldb) register read por 
             Perm6 = Read
```
The calculation of permissions is implemented by a new ABI method.
It's in ABI for 2 reasons:
* These overlays are usually in a register (X86 and AArch64 are)
  and that register name is architecture specific.
* The way the overlay values apply may differ between architecture.
  AArch64 treats a set bit as adding a permission, but some may 
  treat it as removing.

Technically this is dependent on operating system and architecture.
However, so are the methods for removing non-address bits, and those
are in ABI too.

To test this I have changed the allocations in the test program
to use read+execute permissions by default. With read+write+execute
I could not observe that the overlay only changes enabled permissions.

---

Patch is 43.51 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/184115.diff


18 Files Affected:

- (modified) lldb/docs/resources/lldbgdbremote.md (+2) 
- (modified) lldb/include/lldb/API/SBMemoryRegionInfo.h (+13) 
- (modified) lldb/include/lldb/Target/ABI.h (+25) 
- (modified) lldb/include/lldb/Target/MemoryRegionInfo.h (+11-3) 
- (modified) lldb/source/API/SBMemoryRegionInfo.cpp (+12) 
- (modified) lldb/source/Commands/CommandObjectMemory.cpp (+23) 
- (modified) lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp (+46) 
- (modified) lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h (+5) 
- (modified) lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp (+4) 
- (modified) 
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (+4) 
- (modified) 
lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp 
(+3) 
- (modified) lldb/source/Target/MemoryRegionInfo.cpp (+8-8) 
- (modified) 
lldb/test/API/linux/aarch64/permission_overlay/TestAArch64LinuxPOE.py (+67) 
- (modified) lldb/test/API/linux/aarch64/permission_overlay/main.c (+9-3) 
- (modified) lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp (+92-34) 
- (modified) lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp 
(+1-1) 
- (modified) 
lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp (+20) 
- (modified) lldb/unittests/Process/minidump/MinidumpParserTest.cpp (+59-55) 


``````````diff
diff --git a/lldb/docs/resources/lldbgdbremote.md 
b/lldb/docs/resources/lldbgdbremote.md
index 9aa7ad2259a6a..148b3a03aff86 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -1443,6 +1443,8 @@ tuples to return are:
   listed (`dirty-pages:;`) indicates no dirty pages in
   this memory region.  The *absence* of this key means
   that this stub cannot determine dirty pages.
+* `protection-key:<key>`- where `<key>` is an unsigned integer memory 
protection
+  key.
 
 If the address requested is not in a mapped region (e.g. we've jumped through
 a NULL pointer and are at 0x0) currently lldb expects to get back the size
diff --git a/lldb/include/lldb/API/SBMemoryRegionInfo.h 
b/lldb/include/lldb/API/SBMemoryRegionInfo.h
index dc5aa0858e1e3..9174675d2a11c 100644
--- a/lldb/include/lldb/API/SBMemoryRegionInfo.h
+++ b/lldb/include/lldb/API/SBMemoryRegionInfo.h
@@ -111,6 +111,19 @@ class LLDB_API SBMemoryRegionInfo {
   ///     or 0 if this information is unavailable.
   int GetPageSize();
 
+  /// Returns whether this memory region has a memory protection key.
+  ///
+  /// \return
+  ///     True if the region memory region has a memory protection key.
+  bool HasProtectionKey();
+
+  /// Returns the memory protection key of the memory region.
+  ///
+  /// \return
+  ///     The memory protection key of the region. This value is only valid if
+  ///     HasProtectionKey() is true.
+  uint32_t GetProtectionKey();
+
   bool operator==(const lldb::SBMemoryRegionInfo &rhs) const;
 
   bool operator!=(const lldb::SBMemoryRegionInfo &rhs) const;
diff --git a/lldb/include/lldb/Target/ABI.h b/lldb/include/lldb/Target/ABI.h
index 1a1f1724222e3..4eb38d33c9eed 100644
--- a/lldb/include/lldb/Target/ABI.h
+++ b/lldb/include/lldb/Target/ABI.h
@@ -152,6 +152,31 @@ class ABI : public PluginInterface {
 
   static lldb::ABISP FindPlugin(lldb::ProcessSP process_sp, const ArchSpec 
&arch);
 
+  struct MemoryPermissions {
+    // Both of these are sets of lldb::Permissions values.
+    // Overlay are the permissions being applied to the original permissions.
+    uint32_t overlay;
+    // Effective is the result of applying the overlay to the original
+    // permissions. Calculating this is done by the plugin because some
+    // permission overlays are done as positive (add permissions) and some as
+    // negative (remove permissions).
+    uint32_t effective;
+  };
+
+  /// Get the permissions being overlayed for a given memory key, and the
+  /// resulting permissions after applying the overlay. Typically the 
protection
+  /// key is used to look up in some architecture specific set of permissions.
+  /// On AArch64, this is the POR register, used by the Permission Overlay
+  /// Extension.
+  ///
+  /// Returns std::nullopt if the current target does not have such an overlay
+  /// system, or if the protection key is not valid.
+  virtual std::optional<MemoryPermissions>
+  GetMemoryPermissions(lldb_private::RegisterContext &reg_ctx,
+                       unsigned protection_key, uint32_t original_permissions) 
{
+    return std::nullopt;
+  }
+
 protected:
   ABI(lldb::ProcessSP process_sp, std::unique_ptr<llvm::MCRegisterInfo> 
info_up)
       : m_process_wp(process_sp), m_mc_register_info_up(std::move(info_up)) {
diff --git a/lldb/include/lldb/Target/MemoryRegionInfo.h 
b/lldb/include/lldb/Target/MemoryRegionInfo.h
index dc37a7dbeda52..1513d93f1ab22 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfo.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -29,11 +29,13 @@ class MemoryRegionInfo {
                    OptionalBool execute, OptionalBool shared,
                    OptionalBool mapped, ConstString name, OptionalBool flash,
                    lldb::offset_t blocksize, OptionalBool memory_tagged,
-                   OptionalBool stack_memory, OptionalBool shadow_stack)
+                   OptionalBool stack_memory, OptionalBool shadow_stack,
+                   std::optional<unsigned> protection_key)
       : m_range(range), m_read(read), m_write(write), m_execute(execute),
         m_shared(shared), m_mapped(mapped), m_name(name), m_flash(flash),
         m_blocksize(blocksize), m_memory_tagged(memory_tagged),
-        m_is_stack_memory(stack_memory), m_is_shadow_stack(shadow_stack) {}
+        m_is_stack_memory(stack_memory), m_is_shadow_stack(shadow_stack),
+        m_protection_key(protection_key) {}
 
   RangeType &GetRange() { return m_range; }
 
@@ -57,6 +59,8 @@ class MemoryRegionInfo {
 
   OptionalBool IsShadowStack() const { return m_is_shadow_stack; }
 
+  std::optional<unsigned> GetProtectionKey() const { return m_protection_key; }
+
   void SetReadable(OptionalBool val) { m_read = val; }
 
   void SetWritable(OptionalBool val) { m_write = val; }
@@ -81,6 +85,8 @@ class MemoryRegionInfo {
 
   void SetIsShadowStack(OptionalBool val) { m_is_shadow_stack = val; }
 
+  void SetProtectionKey(std::optional<unsigned> key) { m_protection_key = key; 
}
+
   // Get permissions as a uint32_t that is a mask of one or more bits from the
   // lldb::Permissions
   uint32_t GetLLDBPermissions() const {
@@ -111,7 +117,8 @@ class MemoryRegionInfo {
            m_memory_tagged == rhs.m_memory_tagged &&
            m_pagesize == rhs.m_pagesize &&
            m_is_stack_memory == rhs.m_is_stack_memory &&
-           m_is_shadow_stack == rhs.m_is_shadow_stack;
+           m_is_shadow_stack == rhs.m_is_shadow_stack &&
+           m_protection_key == rhs.m_protection_key;
   }
 
   bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); 
}
@@ -154,6 +161,7 @@ class MemoryRegionInfo {
   OptionalBool m_memory_tagged = eDontKnow;
   OptionalBool m_is_stack_memory = eDontKnow;
   OptionalBool m_is_shadow_stack = eDontKnow;
+  std::optional<unsigned> m_protection_key = std::nullopt;
   int m_pagesize = 0;
   std::optional<std::vector<lldb::addr_t>> m_dirty_pages;
 };
diff --git a/lldb/source/API/SBMemoryRegionInfo.cpp 
b/lldb/source/API/SBMemoryRegionInfo.cpp
index cd25be5d52769..99bb6f0de4915 100644
--- a/lldb/source/API/SBMemoryRegionInfo.cpp
+++ b/lldb/source/API/SBMemoryRegionInfo.cpp
@@ -160,6 +160,18 @@ int SBMemoryRegionInfo::GetPageSize() {
   return m_opaque_up->GetPageSize();
 }
 
+bool SBMemoryRegionInfo::HasProtectionKey() {
+  LLDB_INSTRUMENT_VA(this);
+
+  return m_opaque_up->GetProtectionKey() != std::nullopt;
+}
+
+uint32_t SBMemoryRegionInfo::GetProtectionKey() {
+  LLDB_INSTRUMENT_VA(this);
+
+  return m_opaque_up->GetProtectionKey().value_or(0);
+}
+
 bool SBMemoryRegionInfo::GetDescription(SBStream &description) {
   LLDB_INSTRUMENT_VA(this, description);
 
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp 
b/lldb/source/Commands/CommandObjectMemory.cpp
index 93b6c1751b121..f1e3479fc8f69 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -1694,6 +1694,29 @@ class CommandObjectMemoryRegion : public 
CommandObjectParsed {
     MemoryRegionInfo::OptionalBool is_shadow_stack = 
range_info.IsShadowStack();
     if (is_shadow_stack == MemoryRegionInfo::OptionalBool::eYes)
       result.AppendMessage("shadow stack: yes");
+    if (std::optional<unsigned> protection_key =
+            range_info.GetProtectionKey()) {
+      result.AppendMessageWithFormat("protection key: %" PRIu32,
+                                     *protection_key);
+
+      if (const lldb::ABISP &abi = target.GetProcessSP()->GetABI()) {
+        uint32_t base_permissions = range_info.GetLLDBPermissions();
+        if (auto permissions =
+                abi->GetMemoryPermissions(*m_exe_ctx.GetRegisterContext(),
+                                          *protection_key, base_permissions)) {
+          result.AppendMessageWithFormatv(
+              " ({0}{1}{2}, effective: {3}{4}{5})",
+              permissions->overlay & lldb::ePermissionsReadable ? 'r' : '-',
+              permissions->overlay & lldb::ePermissionsWritable ? 'w' : '-',
+              permissions->overlay & lldb::ePermissionsExecutable ? 'x' : '-',
+              permissions->effective & lldb::ePermissionsReadable ? 'r' : '-',
+              permissions->effective & lldb::ePermissionsWritable ? 'w' : '-',
+              permissions->effective & lldb::ePermissionsExecutable ? 'x'
+                                                                    : '-');
+        }
+      } else
+        result.AppendMessage("");
+    }
 
     const std::optional<std::vector<addr_t>> &dirty_page_list =
         range_info.GetDirtyPageList();
diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp 
b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
index aa9c20b6bb2cf..83a777da3237e 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
+++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp
@@ -884,3 +884,49 @@ void ABISysV_arm64::Initialize() {
 void ABISysV_arm64::Terminate() {
   PluginManager::UnregisterPlugin(CreateInstance);
 }
+
+std::optional<ABISysV_arm64::MemoryPermissions>
+ABISysV_arm64::GetMemoryPermissions(lldb_private::RegisterContext &reg_ctx,
+                                    unsigned protection_key,
+                                    uint32_t original_permissions) {
+  // The presence of the POR register means we have the Permission Overlay
+  // Extension.
+  // See Arm Architecture Reference manual "POR_EL0, Permission Overlay 
Register
+  // 0 (EL0)".
+  const RegisterInfo *por_info = reg_ctx.GetRegisterInfoByName("por");
+  if (!por_info)
+    return std::nullopt;
+
+  uint64_t por_value =
+      reg_ctx.ReadRegisterAsUnsigned(por_info, LLDB_INVALID_ADDRESS);
+  if (por_value == LLDB_INVALID_ADDRESS)
+    return std::nullopt;
+
+  // POR contains 16, 4-bit permission sets (though Linux limits this to 8
+  // useable sets).
+  if (protection_key >= 16)
+    return std::nullopt;
+
+  // Bit 3 - reserved, bit 2 - write, bit 1 - execute, bit 0 - read.
+  const uint64_t por_permissions = (por_value >> (protection_key * 4)) & 0xf;
+  uint32_t overlay = 0;
+  if (por_permissions & 4)
+    overlay |= lldb::ePermissionsWritable;
+  if (por_permissions & 2)
+    overlay |= lldb::ePermissionsExecutable;
+  if (por_permissions & 1)
+    overlay |= lldb::ePermissionsReadable;
+
+  uint32_t effective = original_permissions;
+
+  // Permission overlays cannot add permissions, they can only keep, or 
disable,
+  // what was originally set.
+  if (!(overlay & lldb::ePermissionsWritable))
+    effective &= ~lldb::ePermissionsWritable;
+  if (!(overlay & lldb::ePermissionsExecutable))
+    effective &= ~lldb::ePermissionsExecutable;
+  if (!(overlay & lldb::ePermissionsReadable))
+    effective &= ~lldb::ePermissionsReadable;
+
+  return MemoryPermissions{overlay, effective};
+}
diff --git a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h 
b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
index 213fbf7417b2c..53c79ee2d6eb1 100644
--- a/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
+++ b/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h
@@ -81,6 +81,11 @@ class ABISysV_arm64 : public ABIAArch64 {
   lldb::addr_t FixCodeAddress(lldb::addr_t pc) override;
   lldb::addr_t FixDataAddress(lldb::addr_t pc) override;
 
+  virtual std::optional<MemoryPermissions>
+  GetMemoryPermissions(lldb_private::RegisterContext &reg_ctx,
+                       unsigned protection_key,
+                       uint32_t original_permissions) override;
+
 protected:
   lldb::ValueObjectSP
   GetReturnValueObjectImpl(lldb_private::Thread &thread,
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp 
b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
index 2ed896327a2f8..eea0bf245877d 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -174,6 +174,10 @@ void lldb_private::ParseLinuxSMapRegions(llvm::StringRef 
linux_smap,
               region->SetMemoryTagged(MemoryRegionInfo::eYes);
             else if (flag == "ss")
               region->SetIsShadowStack(MemoryRegionInfo::eYes);
+        } else if (name == "ProtectionKey") {
+          unsigned key = 0;
+          if (!value.ltrim().getAsInteger(10, key))
+            region->SetProtectionKey(key);
         }
       } else {
         // Orphaned settings line
diff --git 
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp 
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 738e4013b6154..c639090ebe9af 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1677,6 +1677,10 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
               dirty_page_list.push_back(page);
           }
           region_info.SetDirtyPageList(dirty_page_list);
+        } else if (name == "protection-key") {
+          unsigned protection_key = 0;
+          if (!value.getAsInteger(10, protection_key))
+            region_info.SetProtectionKey(protection_key);
         }
       }
 
diff --git 
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp 
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 2f62415446b7a..72b6d7adbbf96 100644
--- 
a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ 
b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2907,6 +2907,9 @@ 
GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
       response.PutStringAsRawHex8(name.GetStringRef());
       response.PutChar(';');
     }
+
+    if (std::optional<unsigned> protection_key = 
region_info.GetProtectionKey())
+      response.Printf("protection-key:%" PRIu32 ";", *protection_key);
   }
 
   return SendPacketNoLock(response.GetString());
diff --git a/lldb/source/Target/MemoryRegionInfo.cpp 
b/lldb/source/Target/MemoryRegionInfo.cpp
index 979e45ad023af..7bdb3dc4f3168 100644
--- a/lldb/source/Target/MemoryRegionInfo.cpp
+++ b/lldb/source/Target/MemoryRegionInfo.cpp
@@ -12,14 +12,14 @@ 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}, {9}, {10}, {11})",
-                             Info.GetRange().GetRangeBase(),
-                             Info.GetRange().GetRangeEnd(), Info.GetReadable(),
-                             Info.GetWritable(), Info.GetExecutable(),
-                             Info.GetMapped(), Info.GetName(), Info.GetFlash(),
-                             Info.GetBlocksize(), Info.GetMemoryTagged(),
-                             Info.IsStackMemory(), Info.IsShadowStack());
+  return OS << llvm::formatv(
+             "MemoryRegionInfo([{0}, {1}), {2:r}{3:w}{4:x}, "
+             "{5}, `{6}`, {7}, {8}, {9}, {10}, {11}, {12})",
+             Info.GetRange().GetRangeBase(), Info.GetRange().GetRangeEnd(),
+             Info.GetReadable(), Info.GetWritable(), Info.GetExecutable(),
+             Info.GetMapped(), Info.GetName(), Info.GetFlash(),
+             Info.GetBlocksize(), Info.GetMemoryTagged(), Info.IsStackMemory(),
+             Info.IsShadowStack(), Info.GetProtectionKey());
 }
 
 void llvm::format_provider<MemoryRegionInfo::OptionalBool>::format(
diff --git 
a/lldb/test/API/linux/aarch64/permission_overlay/TestAArch64LinuxPOE.py 
b/lldb/test/API/linux/aarch64/permission_overlay/TestAArch64LinuxPOE.py
index 056267a2dc900..9b20b39095789 100644
--- a/lldb/test/API/linux/aarch64/permission_overlay/TestAArch64LinuxPOE.py
+++ b/lldb/test/API/linux/aarch64/permission_overlay/TestAArch64LinuxPOE.py
@@ -79,6 +79,63 @@ def test_poe_live(self):
         self.expect("expression expr_function()", substrs=["$0 = 1"])
         self.expect("register read por", substrs=[self.EXPECTED_POR])
 
+        # Unmapped region has no key (not even default).
+        self.expect("memory region 0", substrs=["protection key:"], 
matching=False)
+
+        # The region has base permissions r-x, and overlay is r--. The result
+        # is that execution is disabled.
+        self.expect(
+            "memory region read_only_page",
+            substrs=["rw-", "protection key: 6 (r--, effective: r--)"],
+        )
+        # A region not assigned to a protection key has the default key 0. This
+        # key is rwx, but overlays cannot add permissions not already in the
+        # page table. So the execute permission is not enabled.
+        self.expect(
+            "memory region key_zero_page",
+            substrs=["rw-", "protection key: 0 (rwx, effective: rw-)"],
+        )
+
+        # Overlay permissions are on their own line.
+        self.expect(
+            "memory region --all",
+            patterns=["\nprotection key: [0-9]+ \([rwx-]{3}, effective: 
[rwx-]{3}\)\n"],
+        )
+
+        # Protection keys are also in SBMemoryRegionInfo.
+        process = self.dbg.GetSelectedTarget().GetProcess()
+        info = lldb.SBMemoryRegionInfo()
+
+        frame = (
+            self.dbg.GetSelectedTarget()
+            .GetProcess()
+            .GetSelectedThread()
+            .GetSelectedFrame()
+        )
+
+        err = lldb.SBError()
+        read_only_addr = frame.GetValueForVariablePath(
+            "read_only_page"
+        ).GetValueAsUnsigned(err)
+        self.assertTrue(err.Success())
+        key_zero_addr = frame.GetValueForVariablePath(
+            "key_zero_page"
+        ).GetValueAsUnsigned(err)
+        self.assertTrue(err.Success())
+
+        region_api_info = [
+            # An unmapped region will have no key at all.
+            # The getter returns 0 as a default, but should not be trusted.
+            (0, False, 0),
+            (read_only_addr, True, 6),
+            (key_zero_addr, True, 0),
+        ]
+        for addr, valid, key in region_api_info:
+            err = process.GetMemoryRegionInfo(addr, info)
+            self.assertTrue(err.Success())
+            self.assertEqual(info.HasProtectionKey(), valid)
+            self.assertEqual(info.GetProtectionKey(), key)
+
         # Not passing this to the application allows us to fix the permissions
         # using lldb, then continue to a normal exit.
         self.runCmd("process handle SIGSEGV --pass false")
@@ -127,3 +184,13 @@ def test_poe_core(self):
                 "register read por",
                 substrs=[f"     {self.EXPECTED_POR}\n" + 
self.EXPECTED_POR_FIELDS],
             )
+
+        # Protection keys are listed in /proc/<pid>/smaps, which is not 
included
+        # in core files.
+        self.expect("memory region --all", substrs=["protection key:"], 
matching=False)
+
+        # No region should have a key at all, not even a default.
+        process = self.dbg.GetSelectedTarget().GetProcess()
+        for region in 
self.dbg.GetSelectedTarget().GetProcess().GetMemoryRegions():
+            self.assertEqual(region.HasProtectionKey(), False)
+            self.assertEqual(region.GetProtectionKey(), 0)
diff --git a/lldb/test/API/linux/aarch64/permission_overlay/main.c 
b/lldb/test/API/linux/aarch64/permission_overlay/main.c
index 6f47ba9d774da..5eb4782b9a6ca 100644
--- a/lldb/test/API/linux/aarch64/permission_overlay/main.c
+++ b/lldb/test/API/linux/aarch64/permission_overlay/main.c
@@ -76,11 +76,17 @@ int main(void) {
   // Which leaves 7 keys available for programs to allocate.
 
   const size_t page_size = (size_t)sysconf(_SC_PAGESIZE);
-  // pkeys can only subtract from the set of permissions in the page table,
-  // so we set the page table to allow everything.
-  const int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
+  // pkeys can only subtract from the set of permissions in the page table.
+  // So we leave out execute here to check later that an overlay does not
+  // enable execution.
+  const int prot = PROT_READ | PROT_WRITE;
   const int flags = MAP_PRIVATE | MAP_ANONYMOUS;
 
+  // This page will have the default key 0.
+  char *key_zero_page = mmap(NULL, page_size, prot, flags, -1, 0);
+  if (key_zero_page == MAP_FAILED)
+    exit(2);
+
   // Later we will use this to cause a protection key fault.
   char *read_only_page = NULL;
 
diff --git a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp 
b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
index d94bb4f4db982..f3f40cbc2f19d 100644
--- a/l...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/184115
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to