diff --git a/lldb/include/lldb/Target/MemoryRegionInfo.h b/lldb/include/lldb/Target/MemoryRegionInfo.h index 7e1385b210b8c..dc37a7dbeda52 100644 --- a/lldb/include/lldb/Target/MemoryRegionInfo.h +++ b/lldb/include/lldb/Target/MemoryRegionInfo.h @@ -29,11 +29,11 @@ class MemoryRegionInfo { OptionalBool execute, OptionalBool shared, OptionalBool mapped, ConstString name, OptionalBool flash, lldb::offset_t blocksize, OptionalBool memory_tagged, - OptionalBool stack_memory) + OptionalBool stack_memory, OptionalBool shadow_stack) : 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_stack_memory(stack_memory), m_is_shadow_stack(shadow_stack) {} RangeType &GetRange() { return m_range; } @@ -55,6 +55,8 @@ class MemoryRegionInfo { OptionalBool GetMemoryTagged() const { return m_memory_tagged; } + OptionalBool IsShadowStack() const { return m_is_shadow_stack; } + void SetReadable(OptionalBool val) { m_read = val; } void SetWritable(OptionalBool val) { m_write = val; } @@ -77,6 +79,8 @@ class MemoryRegionInfo { void SetMemoryTagged(OptionalBool val) { m_memory_tagged = val; } + void SetIsShadowStack(OptionalBool val) { m_is_shadow_stack = val; } + // Get permissions as a uint32_t that is a mask of one or more bits from the // lldb::Permissions uint32_t GetLLDBPermissions() const { @@ -106,7 +110,8 @@ class MemoryRegionInfo { m_blocksize == rhs.m_blocksize && m_memory_tagged == rhs.m_memory_tagged && m_pagesize == rhs.m_pagesize && - m_is_stack_memory == rhs.m_is_stack_memory; + m_is_stack_memory == rhs.m_is_stack_memory && + m_is_shadow_stack == rhs.m_is_shadow_stack; } bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); } @@ -148,6 +153,7 @@ class MemoryRegionInfo { lldb::offset_t m_blocksize = 0; OptionalBool m_memory_tagged = eDontKnow; OptionalBool m_is_stack_memory = eDontKnow; + OptionalBool m_is_shadow_stack = eDontKnow; int m_pagesize = 0; std::optional> m_dirty_pages; }; diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 1338d16a9171e..4b7988deaffb9 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -1364,6 +1364,9 @@ def isAArch64SMEFA64(self): def isAArch64MTE(self): return self.isAArch64() and "mte" in self.getCPUInfo() + def isAArch64GCS(self): + return self.isAArch64() and "gcs" in self.getCPUInfo() + def isAArch64PAuth(self): if self.getArchitecture() == "arm64e": return True diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index b5612f21f1156..6ca4056c960ee 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -1664,6 +1664,9 @@ class CommandObjectMemoryRegion : public CommandObjectParsed { MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged(); if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes) result.AppendMessage("memory tagging: enabled"); + MemoryRegionInfo::OptionalBool is_shadow_stack = range_info.IsShadowStack(); + if (is_shadow_stack == MemoryRegionInfo::OptionalBool::eYes) + result.AppendMessage("shadow stack: yes"); const std::optional> &dirty_page_list = range_info.GetDirtyPageList(); diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp index fd803c8cabafe..2ed896327a2f8 100644 --- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp +++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp @@ -164,12 +164,17 @@ void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap, if (!name.contains(' ')) { if (region) { if (name == "VmFlags") { - if (value.contains("mt")) - region->SetMemoryTagged(MemoryRegionInfo::eYes); - else - region->SetMemoryTagged(MemoryRegionInfo::eNo); + region->SetMemoryTagged(MemoryRegionInfo::eNo); + region->SetIsShadowStack(MemoryRegionInfo::eNo); + + llvm::SmallVector flags; + value.split(flags, ' ', /*MaxSplit=*/-1, /*KeepEmpty=*/false); + for (llvm::StringRef flag : flags) + if (flag == "mt") + region->SetMemoryTagged(MemoryRegionInfo::eYes); + else if (flag == "ss") + region->SetIsShadowStack(MemoryRegionInfo::eYes); } - // Ignore anything else } else { // Orphaned settings line callback(ProcMapError( diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index e42526c8fd726..b3f1c6f052955 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1621,6 +1621,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( region_info.SetName(name.c_str()); } else if (name == "flags") { region_info.SetMemoryTagged(MemoryRegionInfo::eNo); + region_info.SetIsShadowStack(MemoryRegionInfo::eNo); llvm::StringRef flags = value; llvm::StringRef flag; @@ -1629,10 +1630,10 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( std::tie(flag, flags) = flags.split(' '); // To account for trailing whitespace if (flag.size()) { - if (flag == "mt") { + if (flag == "mt") region_info.SetMemoryTagged(MemoryRegionInfo::eYes); - break; - } + else if (flag == "ss") + region_info.SetIsShadowStack(MemoryRegionInfo::eYes); } } } else if (name == "type") { diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 35fa93e53bc66..8cdeaac5c7cb2 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -2796,11 +2796,18 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( // Flags MemoryRegionInfo::OptionalBool memory_tagged = region_info.GetMemoryTagged(); - if (memory_tagged != MemoryRegionInfo::eDontKnow) { + MemoryRegionInfo::OptionalBool is_shadow_stack = + region_info.IsShadowStack(); + + if (memory_tagged != MemoryRegionInfo::eDontKnow || + is_shadow_stack != MemoryRegionInfo::eDontKnow) { response.PutCString("flags:"); - if (memory_tagged == MemoryRegionInfo::eYes) { - response.PutCString("mt"); - } + // Space is the separator. + if (memory_tagged == MemoryRegionInfo::eYes) + response.PutCString("mt "); + if (is_shadow_stack == MemoryRegionInfo::eYes) + response.PutCString("ss "); + response.PutChar(';'); } diff --git a/lldb/source/Target/MemoryRegionInfo.cpp b/lldb/source/Target/MemoryRegionInfo.cpp index 0d5ebbdbe2380..979e45ad023af 100644 --- a/lldb/source/Target/MemoryRegionInfo.cpp +++ b/lldb/source/Target/MemoryRegionInfo.cpp @@ -13,12 +13,13 @@ 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})", + "{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.GetBlocksize(), Info.GetMemoryTagged(), + Info.IsStackMemory(), Info.IsShadowStack()); } void llvm::format_provider::format( diff --git a/lldb/test/API/linux/aarch64/gcs/Makefile b/lldb/test/API/linux/aarch64/gcs/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/linux/aarch64/gcs/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py new file mode 100644 index 0000000000000..b425c9e548ee5 --- /dev/null +++ b/lldb/test/API/linux/aarch64/gcs/TestAArch64LinuxGCS.py @@ -0,0 +1,63 @@ +""" +Check that lldb features work when the AArch64 Guarded Control Stack (GCS) +extension is enabled. +""" + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class AArch64LinuxGCSTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + @skipUnlessArch("aarch64") + @skipUnlessPlatform(["linux"]) + def test_gcs_region(self): + if not self.isAArch64GCS(): + self.skipTest("Target must support GCS.") + + # This test assumes that we have /proc//smaps files + # that include "VmFlags:" lines. + # AArch64 kernel config defaults to enabling smaps with + # PROC_PAGE_MONITOR and "VmFlags" was added in kernel 3.8, + # before GCS was supported at all. + + 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: + self.fail("Test program failed to run.") + + self.expect( + "thread list", + STOPPED_DUE_TO_BREAKPOINT, + substrs=["stopped", "stop reason = breakpoint"], + ) + + # By now either the program or the system C library enabled GCS and there + # should be one region marked for use by it (we cannot predict exactly + # where it will be). + self.runCmd("memory region --all") + found_ss = False + for line in self.res.GetOutput().splitlines(): + if line.strip() == "shadow stack: yes": + if found_ss: + self.fail("Found more than one shadow stack region.") + found_ss = True + + self.assertTrue(found_ss, "Failed to find a shadow stack region.") + + # Note that we must let the debugee get killed here as it cannot exit + # cleanly if GCS was manually enabled. diff --git a/lldb/test/API/linux/aarch64/gcs/main.c b/lldb/test/API/linux/aarch64/gcs/main.c new file mode 100644 index 0000000000000..9633ed2838f9e --- /dev/null +++ b/lldb/test/API/linux/aarch64/gcs/main.c @@ -0,0 +1,54 @@ +#include +#include +#include + +#ifndef HWCAP2_GCS +#define HWCAP2_GCS (1UL << 63) +#endif + +#define PR_GET_SHADOW_STACK_STATUS 74 +#define PR_SET_SHADOW_STACK_STATUS 75 +#define PR_SHADOW_STACK_ENABLE (1UL) +#define PRCTL_SYSCALL_NO 167 + +// Once we enable GCS, we cannot return from the function that made the syscall +// to enable it. This is because the control stack is empty, there is no valid +// address for us to return to. So for the initial enable we must use inline asm +// instead of the libc's prctl wrapper function. +#define my_prctl(option, arg2, arg3, arg4, arg5) \ + ({ \ + register unsigned long x0 __asm__("x0") = option; \ + register unsigned long x1 __asm__("x1") = arg2; \ + register unsigned long x2 __asm__("x2") = arg3; \ + register unsigned long x3 __asm__("x3") = arg4; \ + register unsigned long x4 __asm__("x4") = arg5; \ + register unsigned long x8 __asm__("x8") = PRCTL_SYSCALL_NO; \ + __asm__ __volatile__("svc #0\n" \ + : "=r"(x0) \ + : "r"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), \ + "r"(x8) \ + : "cc", "memory"); \ + }) + +unsigned long get_gcs_status() { + unsigned long mode = 0; + prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0); + return mode; +} + +int main() { + if (!(getauxval(AT_HWCAP2) & HWCAP2_GCS)) + return 1; + + unsigned long mode = get_gcs_status(); + if ((mode & 1) == 0) { + // If GCS wasn't already enabled by the C library, enable it. + my_prctl(PR_SET_SHADOW_STACK_STATUS, PR_SHADOW_STACK_ENABLE, 0, 0, 0); + // From this point on, we cannot return from main without faulting because + // the return address from main, and every function before that, is not on + // the guarded control stack. + } + + // By now we should have one memory region where the GCS is stored. + return 0; // Set break point at this line. +} diff --git a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp index ac1c6132630b0..d94bb4f4db982 100644 --- a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp +++ b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp @@ -87,12 +87,13 @@ INSTANTIATE_TEST_SUITE_P( "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::eNo, - MemoryRegionInfo::eYes, ConstString("[abc]"), - MemoryRegionInfo::eDontKnow, 0, - MemoryRegionInfo::eDontKnow, - MemoryRegionInfo::eDontKnow), + MemoryRegionInfo( + make_range(0, 1), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[abc]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eDontKnow), }, "unexpected /proc/{pid}/maps exec permission char"), // Single entry @@ -101,10 +102,10 @@ INSTANTIATE_TEST_SUITE_P( MemoryRegionInfos{ MemoryRegionInfo( make_range(0x55a4512f7000, 0x55a451b68000), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - ConstString("[heap]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString("[heap]"), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, ""), @@ -117,24 +118,24 @@ INSTANTIATE_TEST_SUITE_P( MemoryRegionInfos{ MemoryRegionInfo( make_range(0x7fc090021000, 0x7fc094000000), - MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), MemoryRegionInfo( make_range(0x7fc094000000, 0x7fc094a00000), - MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - MemoryRegionInfo::eYes, - ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), MemoryRegionInfo( make_range(0xffffffffff600000, 0xffffffffff601000), - MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString("[vsyscall]"), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, ""))); @@ -157,11 +158,11 @@ INSTANTIATE_TEST_SUITE_P( "0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString("[foo]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, "malformed /proc/{pid}/smaps entry, missing dash between address " @@ -178,11 +179,11 @@ INSTANTIATE_TEST_SUITE_P( "1111-2222 rw-p 00000000 00:00 0 [foo]", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString("[foo]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, ""), @@ -191,11 +192,11 @@ INSTANTIATE_TEST_SUITE_P( "1111-2222 rw-s 00000000 00:00 0 [foo]", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - MemoryRegionInfo::eYes, ConstString("[foo]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, ""), @@ -207,12 +208,12 @@ INSTANTIATE_TEST_SUITE_P( "VmFlags: mt", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString("[foo]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes, - MemoryRegionInfo::eDontKnow), + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eNo), }, ""), // Whitespace ignored @@ -220,13 +221,13 @@ INSTANTIATE_TEST_SUITE_P( "0-0 rw-p 00000000 00:00 0\n" "VmFlags: mt ", MemoryRegionInfos{ - MemoryRegionInfo(make_range(0, 0), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString(nullptr), - MemoryRegionInfo::eDontKnow, 0, - MemoryRegionInfo::eYes, - MemoryRegionInfo::eDontKnow), + MemoryRegionInfo( + make_range(0, 0), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eNo), }, ""), // VmFlags line means it has flag info, but nothing is set @@ -234,13 +235,13 @@ INSTANTIATE_TEST_SUITE_P( "0-0 rw-p 00000000 00:00 0\n" "VmFlags: ", MemoryRegionInfos{ - MemoryRegionInfo(make_range(0, 0), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString(nullptr), - MemoryRegionInfo::eDontKnow, 0, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eDontKnow), + MemoryRegionInfo( + make_range(0, 0), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eNo), }, ""), // Handle some pages not having a flags line @@ -252,18 +253,19 @@ INSTANTIATE_TEST_SUITE_P( "VmFlags: mt", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString("[foo]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), MemoryRegionInfo( - make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString("[bar]"), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes, - MemoryRegionInfo::eDontKnow), + make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[bar]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eNo), }, ""), // Handle no pages having a flags line (older kernels) @@ -276,20 +278,35 @@ INSTANTIATE_TEST_SUITE_P( "MMUPageSize: 4 kB\n", MemoryRegionInfos{ MemoryRegionInfo( - make_range(0x1111, 0x2222), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString(nullptr), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), MemoryRegionInfo( - make_range(0x3333, 0x4444), - MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, ConstString(nullptr), - MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eDontKnow, + make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow), }, + ""), + // We must look for exact flag strings, ignoring substrings of longer + // flag names. + std::make_tuple( + "0-0 rw-p 00000000 00:00 0\n" + "VmFlags: amt mtb amtb", + MemoryRegionInfos{ + MemoryRegionInfo( + make_range(0, 0), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eNo, MemoryRegionInfo::eDontKnow, + MemoryRegionInfo::eNo), + }, ""))); TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) { diff --git a/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp b/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp index 6d8b699bbadae..40d7c3601ccfd 100644 --- a/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp +++ b/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp @@ -200,14 +200,12 @@ TEST(MemoryTagManagerAArch64MTETest, ExpandToGranule) { static MemoryRegionInfo MakeRegionInfo(lldb::addr_t base, lldb::addr_t size, bool tagged) { return MemoryRegionInfo( - MemoryRegionInfo::RangeType(base, size), - MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, - MemoryRegionInfo::eNo, - MemoryRegionInfo::eYes, - ConstString(), MemoryRegionInfo::eNo, 0, + MemoryRegionInfo::RangeType(base, size), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString(), MemoryRegionInfo::eNo, 0, /*memory_tagged=*/ tagged ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo, - MemoryRegionInfo::eDontKnow); + MemoryRegionInfo::eDontKnow, MemoryRegionInfo::eDontKnow); } TEST(MemoryTagManagerAArch64MTETest, MakeTaggedRange) { diff --git a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp index ce5ab2cf50829..96f377ec7dfac 100644 --- a/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -344,6 +344,7 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) { EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef()); EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged()); EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.IsStackMemory()); + EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.IsShadowStack()); result = std::async(std::launch::async, [&] { return client.GetMemoryRegionInfo(addr, region_info); @@ -354,16 +355,18 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) { EXPECT_TRUE(result.get().Success()); EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged()); EXPECT_EQ(MemoryRegionInfo::eYes, region_info.IsStackMemory()); + EXPECT_EQ(MemoryRegionInfo::eNo, region_info.IsShadowStack()); result = std::async(std::launch::async, [&] { return client.GetMemoryRegionInfo(addr, region_info); }); HandlePacket(server, "qMemoryRegionInfo:a000", - "start:a000;size:2000;flags: mt zz mt ;type:ha,ha,stack;"); + "start:a000;size:2000;flags: mt zz mt ss ;type:ha,ha,stack;"); EXPECT_TRUE(result.get().Success()); EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged()); EXPECT_EQ(MemoryRegionInfo::eYes, region_info.IsStackMemory()); + EXPECT_EQ(MemoryRegionInfo::eYes, region_info.IsShadowStack()); result = std::async(std::launch::async, [&] { return client.GetMemoryRegionInfo(addr, region_info); diff --git a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp index a6d015e79a7ef..ee31c8e63644b 100644 --- a/lldb/unittests/Process/minidump/MinidumpParserTest.cpp +++ b/lldb/unittests/Process/minidump/MinidumpParserTest.cpp @@ -379,19 +379,23 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfo) { EXPECT_THAT( parser->BuildMemoryRegions(), - testing::Pair( - testing::ElementsAre( - MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown, no, ConstString(), - unknown, 0, unknown, unknown), - MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, unknown, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, unknown, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, unknown, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, unknown, yes, - ConstString(), unknown, 0, unknown, unknown)), - true)); + testing::Pair(testing::ElementsAre( + MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown, + no, ConstString(), unknown, 0, unknown, + unknown, unknown), + MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown), + MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown), + MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown), + MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown)), + true)); } TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { @@ -413,13 +417,14 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { EXPECT_THAT( parser->BuildMemoryRegions(), - testing::Pair( - testing::ElementsAre( - MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes, - ConstString(), unknown, 0, unknown, unknown)), - false)); + testing::Pair(testing::ElementsAre( + MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown), + MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown)), + false)); } TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { @@ -429,13 +434,14 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { // we don't have a MemoryInfoListStream. EXPECT_THAT( parser->BuildMemoryRegions(), - testing::Pair( - testing::ElementsAre( - MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes, - ConstString(), unknown, 0, unknown, unknown)), - false)); + testing::Pair(testing::ElementsAre( + MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown), + MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, + unknown, yes, ConstString(), unknown, + 0, unknown, unknown, unknown)), + false)); } TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { @@ -464,17 +470,21 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { testing::Pair( testing::ElementsAre( MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, no, yes, - app_process, unknown, 0, unknown, unknown), + app_process, unknown, 0, unknown, unknown, + unknown), MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, no, yes, - app_process, unknown, 0, unknown, unknown), + app_process, unknown, 0, unknown, unknown, + unknown), MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, no, yes, - ConstString(), unknown, 0, unknown, unknown), + ConstString(), unknown, 0, unknown, unknown, + unknown), MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, no, yes, - ConstString(), unknown, 0, unknown, unknown), - MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes, linker, - unknown, 0, unknown, unknown), - MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes, liblog, - unknown, 0, unknown, unknown)), + ConstString(), unknown, 0, unknown, unknown, + unknown), + MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes, + linker, unknown, 0, unknown, unknown, unknown), + MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes, + liblog, unknown, 0, unknown, unknown, unknown)), true)); } @@ -491,12 +501,12 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) { 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, no, yes, - ConstString(nullptr), unknown, 0, unknown, unknown)), - true)); + EXPECT_THAT(parser->BuildMemoryRegions(), + testing::Pair(testing::ElementsAre(MemoryRegionInfo( + {0x400fc000, 0x1000}, yes, yes, yes, no, yes, + ConstString(nullptr), unknown, 0, unknown, + unknown, unknown)), + true)); } // Windows Minidump tests