summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
diff options
context:
space:
mode:
authorDavid Spickett <david.spickett@linaro.org>2021-02-19 15:57:59 +0000
committerDavid Spickett <david.spickett@linaro.org>2021-06-24 17:02:55 +0100
commitda2e614f56b196b37175e2babfac8ed7b43ab624 (patch)
tree104b8c39110298f74d39f3d164c099511f833c38 /lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
parentf6ba845da3f89ca1f9591d42ae48f6fb29079096 (diff)
[lldb][AArch64] Add memory tag reading to lldb-server
This adds memory tag reading using the new "qMemTags" packet and ptrace on AArch64 Linux. This new packet is following the one used by GDB. (https://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html) On AArch64 Linux we use ptrace's PEEKMTETAGS to read tags and we assume that lldb has already checked that the memory region actually has tagging enabled. We do not assume that lldb has expanded the requested range to granules and expand it again to be sure. (although lldb will be sending aligned ranges because it happens to need them client side anyway) Also we don't assume untagged addresses. So for AArch64 we'll remove the top byte before using them. (the top byte includes MTE and other non address data) To do the ptrace read NativeProcessLinux will ask the native register context for a memory tag manager based on the type in the packet. This also gives you the ptrace numbers you need. (it's called a register context but it also has non register data, so it saves adding another per platform sub class) The only supported platform for this is AArch64 Linux and the only supported tag type is MTE allocation tags. Anything else will error. Ptrace can return a partial result but for lldb-server we will be treating that as an error. To succeed we need to get all the tags we expect. (Note that the protocol leaves room for logical tags to be read via qMemTags but this is not going to be implemented for lldb at this time.) Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D95601
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp55
1 files changed, 55 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
index 2d53972b69b7..b816d945181c 100644
--- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -1431,6 +1431,61 @@ llvm::Error NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) {
return llvm::Error::success();
}
+Status NativeProcessLinux::ReadMemoryTags(int32_t type, lldb::addr_t addr,
+ size_t len,
+ std::vector<uint8_t> &tags) {
+ llvm::Expected<NativeRegisterContextLinux::MemoryTaggingDetails> details =
+ GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type);
+ if (!details)
+ return Status(details.takeError());
+
+ // Ignore 0 length read
+ if (!len)
+ return Status();
+
+ // lldb will align the range it requests but it is not required to by
+ // the protocol so we'll do it again just in case.
+ // Remove non address bits too. Ptrace calls may work regardless but that
+ // is not a guarantee.
+ MemoryTagManager::TagRange range(details->manager->RemoveNonAddressBits(addr),
+ len);
+ range = details->manager->ExpandToGranule(range);
+
+ // Allocate enough space for all tags to be read
+ size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize();
+ tags.resize(num_tags * details->manager->GetTagSizeInBytes());
+
+ struct iovec tags_iovec;
+ uint8_t *dest = tags.data();
+ lldb::addr_t read_addr = range.GetRangeBase();
+
+ // This call can return partial data so loop until we error or
+ // get all tags back.
+ while (num_tags) {
+ tags_iovec.iov_base = dest;
+ tags_iovec.iov_len = num_tags;
+
+ Status error = NativeProcessLinux::PtraceWrapper(
+ details->ptrace_read_req, GetID(), reinterpret_cast<void *>(read_addr),
+ static_cast<void *>(&tags_iovec), 0, nullptr);
+
+ if (error.Fail()) {
+ // Discard partial reads
+ tags.resize(0);
+ return error;
+ }
+
+ size_t tags_read = tags_iovec.iov_len;
+ assert(tags_read && (tags_read <= num_tags));
+
+ dest += tags_read * details->manager->GetTagSizeInBytes();
+ read_addr += details->manager->GetGranuleSize() * tags_read;
+ num_tags -= tags_read;
+ }
+
+ return Status();
+}
+
size_t NativeProcessLinux::UpdateThreads() {
// The NativeProcessLinux monitoring threads are always up to date with
// respect to thread state and they keep the thread list populated properly.