[lldb-server] Add type info for qMemoryinfo reponse#209235
[lldb-server] Add type info for qMemoryinfo reponse#209235felipepiovezan wants to merge 3 commits into
Conversation
Use the name of the memory region to report the known cases of where an address points to stack/heap: "[stack]" or "[heap"]. According to [1], the "[stack]" name is only available for the main thread. So we can only set "isStack" to Yes in some cases, and to "No" when the name is "[heap]". If there is no name, or the name is something else, we keep the "don't know" answer. > [stack:tid] (from Linux 3.4 to Linux 4.4) > A thread's stack (where the tid is a thread ID). It > corresponds to the /proc/pid/task/tid/ path. This > field was removed in Linux 4.5, since providing this > information for a process with large numbers of > threads is expensive. https://man7.org/linux/man-pages/man5/proc_pid_maps.5.html
|
@llvm/pr-subscribers-lldb Author: Felipe de Azevedo Piovezan (felipepiovezan) ChangesUse the name of the memory region to report the known cases of where an address points to stack/heap: "[stack]" or "[heap"]. According to [1], the "[stack]" name is only available for the main thread. So we can only set "isStack" to Yes in some cases, and to "No" when the name is "[heap]". If there is no name, or the name is something else, we keep the "don't know" answer. > [stack:tid] (from Linux 3.4 to Linux 4.4) https://man7.org/linux/man-pages/man5/proc_pid_maps.5.html Full diff: https://github.com/llvm/llvm-project/pull/209235.diff 4 Files Affected:
diff --git a/lldb/include/lldb/Target/MemoryRegionInfo.h b/lldb/include/lldb/Target/MemoryRegionInfo.h
index 16faf6ed9d64b..e8a16a3ab9757 100644
--- a/lldb/include/lldb/Target/MemoryRegionInfo.h
+++ b/lldb/include/lldb/Target/MemoryRegionInfo.h
@@ -142,7 +142,10 @@ class MemoryRegionInfo {
LazyBool IsStackMemory() const { return m_is_stack_memory; }
- void SetIsStackMemory(LazyBool val) { m_is_stack_memory = val; }
+ MemoryRegionInfo &SetIsStackMemory(LazyBool val) {
+ m_is_stack_memory = val;
+ return *this;
+ }
void SetPageSize(int pagesize) { m_pagesize = pagesize; }
diff --git a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
index d952b7dbdb816..bdb340332851a 100644
--- a/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
+++ b/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp
@@ -114,8 +114,15 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line,
line_extractor.SkipSpaces();
const char *name = line_extractor.Peek();
- if (name)
+ if (name) {
region.SetName(name);
+ // /proc/maps labels only the main thread's stack; thread stacks are
+ // anonymous and the default MemoryRegionInfo::eDontKnow is kept.
+ if (llvm::StringRef(name) == "[stack]")
+ region.SetIsStackMemory(eLazyBoolYes);
+ else if (llvm::StringRef(name) == "[heap]")
+ region.SetIsStackMemory(eLazyBoolNo);
+ }
return region;
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
index 769705588fbdf..451855ef80e75 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp
@@ -2971,6 +2971,13 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo(
if (std::optional<unsigned> protection_key = region_info.GetProtectionKey())
response.Printf("protection-key:%" PRIu32 ";", *protection_key);
+
+ // Type: stack/heap classification, when known.
+ LazyBool is_stack = region_info.IsStackMemory();
+ if (is_stack == eLazyBoolYes)
+ response.PutCString("type:stack;");
+ else if (is_stack == eLazyBoolNo)
+ response.PutCString("type:heap;");
}
return SendPacketNoLock(response.GetString());
diff --git a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
index fcfd76cc67960..84aa206b4e50a 100644
--- a/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
+++ b/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp
@@ -99,7 +99,18 @@ INSTANTIATE_TEST_SUITE_P(
MemoryRegionInfo(make_range(0x55a4512f7000, 0x55a451b68000),
eLazyBoolYes, eLazyBoolYes, eLazyBoolNo,
eLazyBoolNo, eLazyBoolYes,
- ConstString("[heap]")),
+ ConstString("[heap]"))
+ .SetIsStackMemory(eLazyBoolNo),
+ },
+ ""),
+ std::make_tuple(
+ "7ffcad8f7000-7ffcad918000 rw-p 00000000 00:00 0 [stack]",
+ MemoryRegionInfos{
+ MemoryRegionInfo(make_range(0x7ffcad8f7000, 0x7ffcad918000),
+ eLazyBoolYes, eLazyBoolYes, eLazyBoolNo,
+ eLazyBoolNo, eLazyBoolYes,
+ ConstString("[stack]"))
+ .SetIsStackMemory(eLazyBoolYes),
},
""),
// Multiple entries
|
|
As a bit of motivation, I'm trying to implement Linux support for some swift stuff, where CFAs are usually on the heap, and stumbled on this lack of memory information. |
| if (is_stack == eLazyBoolYes) | ||
| response.PutCString("type:stack;"); | ||
| else if (is_stack == eLazyBoolNo) | ||
| response.PutCString("type:heap;"); |
There was a problem hiding this comment.
I don't know linux VM but I don't think "if not stack, is heap" is a good assumption. We could be looking at shared memory or binary data or other VM types that are not heap allocations.
There was a problem hiding this comment.
But that's not the assumption we're making here, right? What we're doing is:
If stack => stack.
else If heap => not stack.
else => unknown.
There was a problem hiding this comment.
Ah, sorry I didn't see where IsStackMemory was initialized,
for (llvm::StringRef entry : llvm::split(value, ',')) {
if (entry == "stack")
region_info.SetIsStackMemory(eLazyBoolYes);
else if (entry == "heap")
region_info.SetIsStackMemory(eLazyBoolNo);
}
Ah, I see, using a LazyBool here isn't the clearest.
"Yes" == definitely-stack, "No" == definitely-heap, "Calculate" == could be anything incl maybe stack. Yeah this change is fine.
There was a problem hiding this comment.
It used to be a different kind of value, whose options were "yes/no/don't know", but I believe @DavidSpickett unified them with LazyBool.
There was a problem hiding this comment.
You can do "don't know" with lazybool, it's an alias to calculate:
enum LazyBool {
eLazyBoolCalculate = -1,
eLazyBoolDontKnow = eLazyBoolCalculate,
eLazyBoolNo = 0,
eLazyBoolYes = 1
};
There was a problem hiding this comment.
And yes we unified them because calculate/don't know was the only state that was different between the 2 types.
There was a problem hiding this comment.
You should put a comment as the implicit else:
// Else we do not know, so don't add any type.
There was a problem hiding this comment.
Or you could refactor it like:
if (is_stack != eLazyBoolDontKnow)
response.Printf("type: %s", is_stack ? "stack" : "heap");
There was a problem hiding this comment.
You can do "don't know" with lazybool, it's an alias to calculate:
TIL!
|
What you quoted is confusing me because you've quoted a field removed in 4.4, and maybe you have a reason to support that even though it's a 10 year old kernel, but the code is actually parsing this one: Which doesn't have the TID number in it. Please make it clear which one you're looking for. This information is in |
| if (llvm::StringRef(name) == "[stack]") | ||
| region.SetIsStackMemory(eLazyBoolYes); | ||
| else if (llvm::StringRef(name) == "[heap]") | ||
| region.SetIsStackMemory(eLazyBoolNo); |
There was a problem hiding this comment.
It's a few cycles, but I'd put an explicit else here. That's a stronger signal than a comment.
Yup, good catch. I really meant just |
felipepiovezan
left a comment
There was a problem hiding this comment.
Addressed review comments
| if (is_stack == eLazyBoolYes) | ||
| response.PutCString("type:stack;"); | ||
| else if (is_stack == eLazyBoolNo) | ||
| response.PutCString("type:heap;"); |
There was a problem hiding this comment.
You can do "don't know" with lazybool, it's an alias to calculate:
TIL!
|
(Updated the PR description, which will be used as the final commit message) |
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
🪟 Windows x64 Test Results
✅ The build succeeded and all tests passed. |
In newer kernels you mean. |
Oops, yes. Fixed |
Use the name of the memory region to report the known cases where an address points to stack/heap: "[stack]" or "[heap"].
According to 1, the "[stack]" name is the main thread's stack region:
For other threads, we can't know their stack region because this field got removed in newer kernels:
So we can only set "isStack" to Yes in some cases, and to "No" when the name is "[heap]". If there is no name, or the name is something else, we keep the "don't know" answer.