DavidSpickett updated this revision to Diff 291835.
DavidSpickett added a comment.
- clang-format Minidump file
- Remove HasFlags from API, return True/False from GetFlags instead
- Rename MapKind to MapsKind and make it an enum class
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D87442/new/
https://reviews.llvm.org/D87442
Files:
lldb/bindings/interface/SBMemoryRegionInfo.i
lldb/docs/lldb-gdb-remote.txt
lldb/include/lldb/API/SBMemoryRegionInfo.h
lldb/include/lldb/Target/MemoryRegionInfo.h
lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
lldb/source/API/SBMemoryRegionInfo.cpp
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/Target/MemoryRegionInfo.cpp
lldb/unittests/Process/CMakeLists.txt
lldb/unittests/Process/Utility/CMakeLists.txt
lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
lldb/unittests/Process/minidump/MinidumpParserTest.cpp
Index: lldb/unittests/Process/minidump/MinidumpParserTest.cpp
===================================================================
--- lldb/unittests/Process/minidump/MinidumpParserTest.cpp
+++ lldb/unittests/Process/minidump/MinidumpParserTest.cpp
@@ -374,20 +374,20 @@
)"),
llvm::Succeeded());
- EXPECT_THAT(
- parser->BuildMemoryRegions(),
- testing::Pair(testing::ElementsAre(
- MemoryRegionInfo({0x0, 0x10000}, no, no, no, no,
- ConstString(), unknown, 0),
- MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes,
- ConstString(), unknown, 0),
- MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes,
- ConstString(), unknown, 0),
- MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes,
- ConstString(), unknown, 0),
- MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes,
- ConstString(), unknown, 0)),
- true));
+ EXPECT_THAT(parser->BuildMemoryRegions(),
+ testing::Pair(
+ testing::ElementsAre(
+ MemoryRegionInfo({0x0, 0x10000}, no, no, no, no,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes,
+ ConstString(), unknown, 0, llvm::None)),
+ true));
}
TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
@@ -409,12 +409,13 @@
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, llvm::None),
+ MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
+ ConstString(), unknown, 0, llvm::None)),
+ false));
}
TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
@@ -424,12 +425,13 @@
// 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, llvm::None),
+ MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes,
+ ConstString(), unknown, 0, llvm::None)),
+ false));
}
TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
@@ -453,22 +455,22 @@
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, llvm::None),
+ MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes,
+ app_process, unknown, 0, llvm::None),
+ MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes,
+ ConstString(), unknown, 0, llvm::None),
+ MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes,
+ linker, unknown, 0, llvm::None),
+ MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes,
+ liblog, unknown, 0, llvm::None)),
+ true));
}
// Windows Minidump tests
Index: lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
===================================================================
--- lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
+++ lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
@@ -343,6 +343,28 @@
EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable());
EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable());
EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef());
+ EXPECT_FALSE(region_info.HasFlags());
+ EXPECT_EQ("?", region_info.GetFlags());
+
+ 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_TRUE(region_info.HasFlags());
+ EXPECT_EQ("", region_info.GetFlags());
+
+ result = std::async(std::launch::async, [&] {
+ return client.GetMemoryRegionInfo(addr, region_info);
+ });
+
+ HandlePacket(server, "qMemoryRegionInfo:a000",
+ "start:a000;size:2000;flags: me mr mw ;");
+ EXPECT_TRUE(result.get().Success());
+ EXPECT_TRUE(region_info.HasFlags());
+ EXPECT_EQ("me mr mw", region_info.GetFlags());
}
TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
Index: lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
@@ -0,0 +1,256 @@
+//===-- 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 "gtest/gtest.h"
+
+#include "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 = [&](const MemoryRegionInfo &Info, const Status &ST) {
+ if (ST.Success()) {
+ err_str.clear();
+ regions.push_back(Info);
+ return true;
+ }
+ err_str = ST.AsCString();
+ return false;
+ };
+ }
+
+ void check_regions(LinuxProcMapsTestParams params) {
+ ASSERT_EQ(std::get<1>(params).size(), regions.size());
+ ASSERT_EQ(std::get<1>(params), 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, llvm::None),
+ },
+ "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, llvm::None),
+ },
+ ""),
+ // 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, llvm::None),
+ MemoryRegionInfo(make_range(0xffffffffff600000,
+ 0xffffffffff601000),
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+ ConstString("[vsyscall]"),
+ MemoryRegionInfo::eDontKnow, 0, llvm::None),
+ },
+ "")), );
+
+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, llvm::None),
+ },
+ "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, llvm::None),
+ },
+ ""),
+ // 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: rd wr ab cd",
+ MemoryRegionInfos{
+ MemoryRegionInfo(
+ make_range(0x1111, 0x2222),
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+ MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+ ConstString("[foo]"),
+ MemoryRegionInfo::eDontKnow, 0,
+ llvm::Optional<llvm::StringRef>("rd wr ab cd")),
+ },
+ ""),
+ // Whitespace in flags line ignored, any number of chars per flag
+ std::make_tuple("0-0 rw-p 00000000 00:00 0\n"
+ "VmFlags: rd abc x yz ",
+ MemoryRegionInfos{
+ MemoryRegionInfo(
+ make_range(0, 0), MemoryRegionInfo::eYes,
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+ MemoryRegionInfo::eYes, ConstString(nullptr),
+ MemoryRegionInfo::eDontKnow, 0,
+ llvm::Optional<llvm::StringRef>("rd abc x yz")),
+ },
+ ""),
+ // VmFlags line means it has flag info, but nothing is set
+ // Also leading whitespace is ignored for property lines
+ 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,
+ llvm::Optional<llvm::StringRef>("")),
+ },
+ ""),
+ // 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: rd wr ab cd",
+ MemoryRegionInfos{
+ MemoryRegionInfo(make_range(0x1111, 0x2222),
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+ MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+ ConstString("[foo]"),
+ MemoryRegionInfo::eDontKnow, 0, llvm::None),
+ MemoryRegionInfo(
+ make_range(0x3333, 0x4444), MemoryRegionInfo::eYes,
+ MemoryRegionInfo::eNo, MemoryRegionInfo::eYes,
+ MemoryRegionInfo::eYes, ConstString("[bar]"),
+ MemoryRegionInfo::eDontKnow, 0,
+ llvm::Optional<llvm::StringRef>("rd wr ab cd")),
+ },
+ ""),
+ // 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, llvm::None),
+ MemoryRegionInfo(make_range(0x3333, 0x4444),
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eNo,
+ MemoryRegionInfo::eYes, MemoryRegionInfo::eYes,
+ ConstString(nullptr),
+ MemoryRegionInfo::eDontKnow, 0, llvm::None),
+ },
+ "")), );
+
+TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) {
+ auto params = GetParam();
+ ParseLinuxSMapRegions(std::get<0>(params), callback);
+ check_regions(params);
+}
Index: lldb/unittests/Process/Utility/CMakeLists.txt
===================================================================
--- /dev/null
+++ lldb/unittests/Process/Utility/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_unittest(LinuxProcMapsTests
+ LinuxProcMapsTest.cpp
+
+ LINK_LIBS
+ lldbPluginProcessLinux
+ )
+
+target_include_directories(LinuxProcMapsTests PRIVATE
+ ${LLDB_SOURCE_DIR}/source/Plugins/Process/Utility)
Index: lldb/unittests/Process/CMakeLists.txt
===================================================================
--- lldb/unittests/Process/CMakeLists.txt
+++ lldb/unittests/Process/CMakeLists.txt
@@ -4,6 +4,7 @@
add_subdirectory(POSIX)
endif()
add_subdirectory(minidump)
+add_subdirectory(Utility)
add_lldb_unittest(ProcessEventDataTests
ProcessEventDataTest.cpp
Index: lldb/source/Target/MemoryRegionInfo.cpp
===================================================================
--- lldb/source/Target/MemoryRegionInfo.cpp
+++ lldb/source/Target/MemoryRegionInfo.cpp
@@ -7,18 +7,41 @@
//===----------------------------------------------------------------------===//
#include "lldb/Target/MemoryRegionInfo.h"
+#include <cctype>
using namespace lldb_private;
+void MemoryRegionInfo::SetFlags(llvm::StringRef flags) {
+ // Assuming a line of the format:
+ // <flag><spaces><flag><spaces>...
+ // E.g. "rd wr ex"
+ m_flags = std::set<std::string>();
+ llvm::StringRef flag;
+ while (flags.size()) {
+ flags = flags.drop_while(iswspace);
+ std::tie(flag, flags) = flags.split(' ');
+ // Account for trailing whitespace
+ if (flag.size()) {
+ m_flags->insert(flag.str());
+ }
+ }
+}
+
+std::string MemoryRegionInfo::GetFlags() const {
+ if (HasFlags())
+ return llvm::join(m_flags.getValue(), " ");
+ return "?";
+}
+
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.GetFlags());
}
void llvm::format_provider<MemoryRegionInfo::OptionalBool>::format(
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2491,6 +2491,14 @@
response.PutChar(';');
}
+ // Flags
+ if (region_info.HasFlags()) {
+ std::string flags_str = region_info.GetFlags();
+ response.PutCString("flags:");
+ response.PutCString(flags_str.c_str());
+ response.PutChar(';');
+ }
+
// Name
ConstString name = region_info.GetName();
if (name) {
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -1529,6 +1529,8 @@
std::string name;
name_extractor.GetHexByteString(name);
region_info.SetName(name.c_str());
+ } else if (name.equals("flags")) {
+ region_info.SetFlags(value);
} else if (name.equals("error")) {
StringExtractorGDBRemote error_extractor(value);
std::string error_string;
Index: lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
===================================================================
--- lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
+++ lldb/source/Plugins/Process/Utility/LinuxProcMaps.h
@@ -21,6 +21,8 @@
void ParseLinuxMapRegions(llvm::StringRef linux_map,
LinuxMapCallback const &callback);
+void ParseLinuxSMapRegions(llvm::StringRef linux_smap,
+ LinuxMapCallback const &callback);
} // namespace lldb_private
Index: lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
===================================================================
--- lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -7,16 +7,25 @@
//===----------------------------------------------------------------------===//
#include "LinuxProcMaps.h"
-#include "llvm/ADT/StringRef.h"
#include "lldb/Target/MemoryRegionInfo.h"
+#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StringExtractor.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
+enum class MapsKind { eMaps, eSMaps };
+
+static Status ProcMapError(const char *msg, MapsKind kind) {
+ return Status(msg, kind == MapsKind::eMaps ? "maps" : "smaps");
+}
+
static Status
ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
- MemoryRegionInfo &memory_region_info) {
+ MemoryRegionInfo &memory_region_info,
+ MapsKind maps_kind) {
memory_region_info.Clear();
StringExtractor line_extractor(maps_line);
@@ -30,30 +39,33 @@
// 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.
+
+ // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped
+ // into the process.
memory_region_info.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')
@@ -61,8 +73,9 @@
else if (read_perm_char == '-')
memory_region_info.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')
@@ -70,8 +83,9 @@
else if (write_perm_char == '-')
memory_region_info.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')
@@ -79,8 +93,9 @@
else if (exec_perm_char == '-')
memory_region_info.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
@@ -105,8 +120,87 @@
while (!lines.empty()) {
std::tie(line, lines) = lines.split('\n');
MemoryRegionInfo region;
- Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region);
+ Status error =
+ ParseMemoryRegionInfoFromProcMapsLine(line, region, MapsKind::eMaps);
if (!callback(region, error))
break;
}
}
+
+static bool IsRegionPropertyLine(llvm::StringRef line, llvm::StringRef &name,
+ llvm::StringRef &value) {
+ llvm::SmallVector<llvm::StringRef, 3> matches;
+ // Note: llvm::regex doesn't do character classes
+ RegularExpression expr("^[ ]*([A-za-z0-9_]+)[ ]*:(.*)");
+ if (expr.Execute(line, &matches)) {
+ name = matches[1];
+ value = matches[2];
+ return true;
+ }
+ return false;
+}
+
+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;
+ Status error;
+
+ while (!lines.empty()) {
+ std::tie(line, lines) = lines.split('\n');
+
+ llvm::StringRef name;
+ llvm::StringRef value;
+ if (IsRegionPropertyLine(line, name, value)) {
+ if (region) {
+ if (name == "VmFlags")
+ region->SetFlags(value);
+ // Ignore anything else
+ } else {
+ // Orphaned settings line
+ error = Status("Found a property line without a corresponding mapping "
+ "in /proc/{pid}/smaps");
+ region = MemoryRegionInfo();
+ callback(*region, error);
+ return;
+ }
+ } else {
+ // Must be a new region header
+ if (region) {
+ // Save current region (error will always be Success here)
+ callback(*region, error);
+ region.reset();
+ }
+
+ // Try to start a new region
+ MemoryRegionInfo new_region;
+ error = ParseMemoryRegionInfoFromProcMapsLine(line, new_region,
+ MapsKind::eSMaps);
+ if (error.Fail()) {
+ // Stop at first invalid region header
+ callback(*region, error);
+ return;
+ } else {
+ region = new_region;
+ }
+ }
+ }
+
+ // Catch last region (error will always be Success here)
+ if (region) {
+ callback(*region, error);
+ }
+}
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1297,28 +1297,44 @@
return Status();
}
- auto BufferOrError = getProcFile(GetID(), "maps");
- if (!BufferOrError) {
- m_supports_mem_region = LazyBool::eLazyBoolNo;
- return BufferOrError.getError();
- }
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;
+ Result.SetErrorToGenericError();
+ LinuxMapCallback callback = [&](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);
+ Result = ST;
+ return true;
+ } else {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ LLDB_LOG(log, "failed to parse proc maps: {0}", ST);
+ Result = ST;
+ 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);
+ if (Result.Fail()) {
+ return Result;
+ }
+ } else {
+ BufferOrError = getProcFile(GetID(), "maps");
+ if (!BufferOrError) {
+ m_supports_mem_region = LazyBool::eLazyBoolNo;
+ return BufferOrError.getError();
+ }
+
+ ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), callback);
+ if (Result.Fail()) {
+ return Result;
+ }
+ }
if (m_mem_region_cache.empty()) {
// No entries after attempting to read them. This shouldn't happen if
Index: lldb/source/Commands/CommandObjectMemory.cpp
===================================================================
--- lldb/source/Commands/CommandObjectMemory.cpp
+++ lldb/source/Commands/CommandObjectMemory.cpp
@@ -1726,11 +1726,16 @@
}
}
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);
+ if (range_info.HasFlags()) {
+ result.AppendMessageWithFormatv("flags: {0}",
+ range_info.GetFlags().c_str());
+ }
+
m_prev_end_addr = range_info.GetRange().GetRangeEnd();
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
Index: lldb/source/API/SBMemoryRegionInfo.cpp
===================================================================
--- lldb/source/API/SBMemoryRegionInfo.cpp
+++ lldb/source/API/SBMemoryRegionInfo.cpp
@@ -116,6 +116,19 @@
return m_opaque_up->GetName().AsCString();
}
+bool SBMemoryRegionInfo::GetFlags(SBStream &flags) {
+ LLDB_RECORD_METHOD(bool, SBMemoryRegionInfo, GetFlags, (lldb::SBStream &),
+ flags);
+
+ if (!m_opaque_up->HasFlags())
+ return false;
+
+ Stream &strm = flags.ref();
+ strm.Printf("%s", m_opaque_up->GetFlags().c_str());
+
+ return true;
+}
+
bool SBMemoryRegionInfo::GetDescription(SBStream &description) {
LLDB_RECORD_METHOD(bool, SBMemoryRegionInfo, GetDescription,
(lldb::SBStream &), description);
@@ -128,6 +141,8 @@
strm.Printf(m_opaque_up->GetReadable() ? "R" : "-");
strm.Printf(m_opaque_up->GetWritable() ? "W" : "-");
strm.Printf(m_opaque_up->GetExecutable() ? "X" : "-");
+ if (m_opaque_up->HasFlags())
+ strm.Printf(" flags: %s", m_opaque_up->GetFlags().c_str());
strm.Printf("]");
return true;
@@ -158,6 +173,7 @@
LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfo, IsExecutable, ());
LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfo, IsMapped, ());
LLDB_REGISTER_METHOD(const char *, SBMemoryRegionInfo, GetName, ());
+ LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfo, GetFlags, (lldb::SBStream &));
LLDB_REGISTER_METHOD(bool, SBMemoryRegionInfo, GetDescription,
(lldb::SBStream &));
}
Index: lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
===================================================================
--- lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
+++ lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py
@@ -800,8 +800,9 @@
"start",
"size",
"permissions",
+ "flags",
"name",
- "error"])
+ "error"], "Unexpected key \"%s\"" % key)
self.assertIsNotNone(val)
mem_region_dict["name"] = seven.unhexlify(mem_region_dict.get("name", ""))
Index: lldb/include/lldb/Target/MemoryRegionInfo.h
===================================================================
--- lldb/include/lldb/Target/MemoryRegionInfo.h
+++ lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -12,7 +12,9 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/RangeMap.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FormatProviders.h"
+#include <set>
namespace lldb_private {
class MemoryRegionInfo {
@@ -24,9 +26,13 @@
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,
+ llvm::Optional<llvm::StringRef> flags)
: m_range(range), m_read(read), m_write(write), m_execute(execute),
m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize) {
+ if (flags) {
+ SetFlags(*flags);
+ }
}
RangeType &GetRange() { return m_range; }
@@ -48,6 +54,11 @@
ConstString GetName() const { return m_name; }
+ bool HasFlags() const { return m_flags.hasValue(); }
+
+ // Get space joined string of flags
+ std::string GetFlags() const;
+
void SetReadable(OptionalBool val) { m_read = val; }
void SetWritable(OptionalBool val) { m_write = val; }
@@ -66,6 +77,9 @@
void SetBlocksize(lldb::offset_t blocksize) { m_blocksize = blocksize; }
+ // Init from space seperated list of flags
+ void SetFlags(llvm::StringRef flags);
+
// 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 +105,8 @@
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_flags == rhs.m_flags;
}
bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); }
@@ -105,6 +120,7 @@
ConstString m_name;
OptionalBool m_flash = eDontKnow;
lldb::offset_t m_blocksize = 0;
+ llvm::Optional<std::set<std::string>> m_flags;
};
inline bool operator<(const MemoryRegionInfo &lhs,
Index: lldb/include/lldb/API/SBMemoryRegionInfo.h
===================================================================
--- lldb/include/lldb/API/SBMemoryRegionInfo.h
+++ lldb/include/lldb/API/SBMemoryRegionInfo.h
@@ -73,6 +73,16 @@
/// region. If no name can be determined the returns nullptr.
const char *GetName();
+ /// If the region has flag information, get its flags as a space
+ /// seperated string.
+ ///
+ /// \param[out] flags
+ /// Stream to write the flags string to.
+ ///
+ /// \return
+ /// True if flags were written to \p flags, False otherwise.
+ bool GetFlags(lldb::SBStream &flags);
+
bool operator==(const lldb::SBMemoryRegionInfo &rhs) const;
bool operator!=(const lldb::SBMemoryRegionInfo &rhs) const;
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -1086,6 +1086,10 @@
// 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 seperated string
+ // of flag names. These names are platform specific
+ // e.g. on Linux it might be "rd ex mr".
+
error:<ascii-byte-error-string>; // where <ascii-byte-error-string> is
// a hex encoded string value that
// contains an error string
Index: lldb/bindings/interface/SBMemoryRegionInfo.i
===================================================================
--- lldb/bindings/interface/SBMemoryRegionInfo.i
+++ lldb/bindings/interface/SBMemoryRegionInfo.i
@@ -47,6 +47,9 @@
GetName ();
bool
+ GetFlags (lldb::SBStream &flags);
+
+ bool
operator == (const lldb::SBMemoryRegionInfo &rhs) const;
bool
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits