Skip to content

Commit 6f2f79e

Browse files
committed
[lldb][Commands] Fix memory find for Swift expressions
1 parent 7a2d13e commit 6f2f79e

File tree

6 files changed

+151
-43
lines changed

6 files changed

+151
-43
lines changed

lldb/source/Commands/CommandObjectMemory.cpp

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,61 @@ 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+
case 3:
913+
case 5:
914+
case 6:
915+
case 7:
916+
return llvm::createStringError("unknown type. pass a string instead");
917+
default:
918+
return llvm::createStringError(
919+
"result size larger than 8 bytes. pass a string instead");
920+
}
921+
922+
return llvm::Error::success();
923+
}
924+
925+
static llvm::Expected<ValueObjectSP>
926+
EvaluateExpression(llvm::StringRef expression, StackFrame &frame,
927+
Process &process) {
928+
ValueObjectSP result_sp;
929+
auto status =
930+
process.GetTarget().EvaluateExpression(expression, &frame, result_sp);
931+
if (status != eExpressionCompleted || !result_sp)
932+
return llvm::createStringError(
933+
"expression evaluation failed. pass a string instead");
934+
935+
result_sp = result_sp->GetQualifiedRepresentationIfAvailable(
936+
result_sp->GetDynamicValueType(), /*synthValue=*/true);
937+
if (!result_sp)
938+
return llvm::createStringError("failed to unwrap expression result type");
939+
940+
return result_sp;
941+
}
942+
888943
// Find the specified data in memory
889944
class CommandObjectMemoryFind : public CommandObjectParsed {
890945
public:
@@ -1026,49 +1081,19 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
10261081
}
10271082
buffer.CopyData(str);
10281083
} 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");
1084+
auto result_or_err = EvaluateExpression(
1085+
m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(""),
1086+
m_exe_ctx.GetFrameRef(), *process);
1087+
if (!result_or_err) {
1088+
result.AppendError(llvm::toString(result_or_err.takeError()));
1089+
return;
1090+
}
1091+
1092+
ValueObjectSP result_sp = *result_or_err;
1093+
1094+
if (auto err = CopyExpressionResult(*result_sp, buffer,
1095+
m_exe_ctx.GetFramePtr())) {
1096+
result.AppendError(llvm::toString(std::move(err)));
10721097
return;
10731098
}
10741099
} else {

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,34 @@ 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=["unknown type."],
87+
error=True,
88+
)
89+
90+
self.expect(
91+
'memory find -e "FiveBytes{}" `&bytedata[0]` `&bytedata[2]`',
92+
substrs=["unknown type."],
93+
error=True,
94+
)
95+
96+
self.expect(
97+
'memory find -e "SixBytes{}" `&bytedata[0]` `&bytedata[2]`',
98+
substrs=["unknown type."],
99+
error=True,
100+
)
101+
102+
self.expect(
103+
'memory find -e "SevenBytes{}" `&bytedata[0]` `&bytedata[2]`',
104+
substrs=["unknown type."],
105+
error=True,
106+
)
107+
108+
self.expect(
109+
'memory find -e "NineBytes{}" `&bytedata[0]` `&bytedata[2]`',
110+
substrs=["result size larger than 8 bytes."],
111+
error=True,
112+
)
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)