Skip to content

Commit 8473b63

Browse files
Merge pull request #10827 from swiftlang/lldb/memory-find-swift-to-6.2
🍒[lldb][Commands] Fix memory find for Swift expressions
2 parents 15a1479 + 2a53b82 commit 8473b63

File tree

6 files changed

+158
-43
lines changed

6 files changed

+158
-43
lines changed

lldb/source/Commands/CommandObjectMemory.cpp

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,58 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
885885
#define LLDB_OPTIONS_memory_find
886886
#include "CommandOptions.inc"
887887

888+
static llvm::Error CopyExpressionResult(ValueObject &result,
889+
DataBufferHeap &buffer,
890+
ExecutionContextScope *scope) {
891+
uint64_t value = result.GetValueAsUnsigned(0);
892+
auto size_or_err = result.GetCompilerType().GetByteSize(scope);
893+
if (!size_or_err)
894+
return size_or_err.takeError();
895+
896+
switch (*size_or_err) {
897+
case 1: {
898+
uint8_t byte = (uint8_t)value;
899+
buffer.CopyData(&byte, 1);
900+
} break;
901+
case 2: {
902+
uint16_t word = (uint16_t)value;
903+
buffer.CopyData(&word, 2);
904+
} break;
905+
case 4: {
906+
uint32_t lword = (uint32_t)value;
907+
buffer.CopyData(&lword, 4);
908+
} break;
909+
case 8: {
910+
buffer.CopyData(&value, 8);
911+
} break;
912+
default:
913+
return llvm::createStringError(
914+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are "
915+
"supported. For other pattern sizes the --string (-s) option may be "
916+
"used.");
917+
}
918+
919+
return llvm::Error::success();
920+
}
921+
922+
static llvm::Expected<ValueObjectSP>
923+
EvaluateExpression(llvm::StringRef expression, StackFrame &frame,
924+
Process &process) {
925+
ValueObjectSP result_sp;
926+
auto status =
927+
process.GetTarget().EvaluateExpression(expression, &frame, result_sp);
928+
if (status != eExpressionCompleted || !result_sp)
929+
return llvm::createStringError(
930+
"expression evaluation failed. pass a string instead");
931+
932+
result_sp = result_sp->GetQualifiedRepresentationIfAvailable(
933+
result_sp->GetDynamicValueType(), /*synthValue=*/true);
934+
if (!result_sp)
935+
return llvm::createStringError("failed to get dynamic result type");
936+
937+
return result_sp;
938+
}
939+
888940
// Find the specified data in memory
889941
class CommandObjectMemoryFind : public CommandObjectParsed {
890942
public:
@@ -1026,49 +1078,19 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
10261078
}
10271079
buffer.CopyData(str);
10281080
} else if (m_memory_options.m_expr.OptionWasSet()) {
1029-
StackFrame *frame = m_exe_ctx.GetFramePtr();
1030-
ValueObjectSP result_sp;
1031-
if ((eExpressionCompleted ==
1032-
process->GetTarget().EvaluateExpression(
1033-
m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(
1034-
""),
1035-
frame, result_sp)) &&
1036-
result_sp) {
1037-
uint64_t value = result_sp->GetValueAsUnsigned(0);
1038-
std::optional<uint64_t> size = llvm::expectedToOptional(
1039-
result_sp->GetCompilerType().GetByteSize(nullptr));
1040-
if (!size)
1041-
return;
1042-
switch (*size) {
1043-
case 1: {
1044-
uint8_t byte = (uint8_t)value;
1045-
buffer.CopyData(&byte, 1);
1046-
} break;
1047-
case 2: {
1048-
uint16_t word = (uint16_t)value;
1049-
buffer.CopyData(&word, 2);
1050-
} break;
1051-
case 4: {
1052-
uint32_t lword = (uint32_t)value;
1053-
buffer.CopyData(&lword, 4);
1054-
} break;
1055-
case 8: {
1056-
buffer.CopyData(&value, 8);
1057-
} break;
1058-
case 3:
1059-
case 5:
1060-
case 6:
1061-
case 7:
1062-
result.AppendError("unknown type. pass a string instead");
1063-
return;
1064-
default:
1065-
result.AppendError(
1066-
"result size larger than 8 bytes. pass a string instead");
1067-
return;
1068-
}
1069-
} else {
1070-
result.AppendError(
1071-
"expression evaluation failed. pass a string instead");
1081+
auto result_or_err = EvaluateExpression(
1082+
m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(""),
1083+
m_exe_ctx.GetFrameRef(), *process);
1084+
if (!result_or_err) {
1085+
result.AppendError(llvm::toString(result_or_err.takeError()));
1086+
return;
1087+
}
1088+
1089+
ValueObjectSP result_sp = *result_or_err;
1090+
1091+
if (auto err = CopyExpressionResult(*result_sp, buffer,
1092+
m_exe_ctx.GetFramePtr())) {
1093+
result.AppendError(llvm::toString(std::move(err)));
10721094
return;
10731095
}
10741096
} else {

lldb/test/API/functionalities/memory/find/TestMemoryFind.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,44 @@ def test_memory_find(self):
7979
'memory find -s "nothere" `stringdata` `stringdata+10`',
8080
substrs=["data not found within the range."],
8181
)
82+
83+
# Expression results with unsupported result types.
84+
self.expect(
85+
'memory find -e "ThreeBytes{}" `&bytedata[0]` `&bytedata[2]`',
86+
substrs=[
87+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported"
88+
],
89+
error=True,
90+
)
91+
92+
self.expect(
93+
'memory find -e "FiveBytes{}" `&bytedata[0]` `&bytedata[2]`',
94+
substrs=[
95+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported"
96+
],
97+
error=True,
98+
)
99+
100+
self.expect(
101+
'memory find -e "SixBytes{}" `&bytedata[0]` `&bytedata[2]`',
102+
substrs=[
103+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported"
104+
],
105+
error=True,
106+
)
107+
108+
self.expect(
109+
'memory find -e "SevenBytes{}" `&bytedata[0]` `&bytedata[2]`',
110+
substrs=[
111+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported"
112+
],
113+
error=True,
114+
)
115+
116+
self.expect(
117+
'memory find -e "NineBytes{}" `&bytedata[0]` `&bytedata[2]`',
118+
substrs=[
119+
"Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported"
120+
],
121+
error=True,
122+
)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
#include <stdio.h>
22
#include <stdint.h>
33

4+
template <size_t T> struct [[gnu::packed]] Payload {
5+
uint8_t data[T];
6+
};
7+
8+
using ThreeBytes = Payload<3>;
9+
using FiveBytes = Payload<5>;
10+
using SixBytes = Payload<5>;
11+
using SevenBytes = Payload<7>;
12+
using NineBytes = Payload<9>;
13+
414
int main (int argc, char const *argv[])
515
{
616
const char* stringdata = "hello world; I like to write text in const char pointers";
717
uint8_t bytedata[] = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99};
18+
ThreeBytes b1;
19+
FiveBytes b2;
20+
SixBytes b3;
21+
SevenBytes b4;
22+
NineBytes b5;
823
return 0; // break here
924
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
SWIFT_SOURCES := main.swift
2+
3+
include Makefile.rules
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Test that running Swift expressions in the
3+
`memory find` command works.
4+
"""
5+
import lldb
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test.decorators import *
8+
import lldbsuite.test.lldbutil as lldbutil
9+
10+
11+
class TestSwiftCommandMemoryFind(TestBase):
12+
def memory_find(self, name: str, expr: str, target):
13+
var = target.FindGlobalVariables(name, 1)
14+
self.assertEqual(len(var), 1)
15+
addr = var[0].AddressOf()
16+
self.assertTrue(addr)
17+
addr = addr.GetValueAsUnsigned()
18+
self.expect(f'memory find -e "{expr}" {hex(addr)} {hex(addr + 8)}',
19+
substrs=["data found at location"])
20+
21+
@swiftTest
22+
def test(self):
23+
self.build()
24+
target, _, _, _ = lldbutil.run_to_source_breakpoint(
25+
self, 'Break', lldb.SBFileSpec('main.swift'))
26+
27+
self.memory_find('elem1', 'elem1', target)
28+
self.memory_find('elem1', '130 + 7', target)
29+
30+
self.memory_find('elem2', 'elem2', target)
31+
self.memory_find('elem2', '-42', target)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
let elem1: Int32 = 137
2+
let elem2: Int64 = -42
3+
print ("Break")

0 commit comments

Comments
 (0)