diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 8fa7020d84908..4ee91be52346e 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -885,6 +885,58 @@ class CommandObjectMemoryRead : public CommandObjectParsed { #define LLDB_OPTIONS_memory_find #include "CommandOptions.inc" +static llvm::Error CopyExpressionResult(ValueObject &result, + DataBufferHeap &buffer, + ExecutionContextScope *scope) { + uint64_t value = result.GetValueAsUnsigned(0); + auto size_or_err = result.GetCompilerType().GetByteSize(scope); + if (!size_or_err) + return size_or_err.takeError(); + + switch (*size_or_err) { + case 1: { + uint8_t byte = (uint8_t)value; + buffer.CopyData(&byte, 1); + } break; + case 2: { + uint16_t word = (uint16_t)value; + buffer.CopyData(&word, 2); + } break; + case 4: { + uint32_t lword = (uint32_t)value; + buffer.CopyData(&lword, 4); + } break; + case 8: { + buffer.CopyData(&value, 8); + } break; + default: + return llvm::createStringError( + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are " + "supported. For other pattern sizes the --string (-s) option may be " + "used."); + } + + return llvm::Error::success(); +} + +static llvm::Expected +EvaluateExpression(llvm::StringRef expression, StackFrame &frame, + Process &process) { + ValueObjectSP result_sp; + auto status = + process.GetTarget().EvaluateExpression(expression, &frame, result_sp); + if (status != eExpressionCompleted || !result_sp) + return llvm::createStringError( + "expression evaluation failed. pass a string instead"); + + result_sp = result_sp->GetQualifiedRepresentationIfAvailable( + result_sp->GetDynamicValueType(), /*synthValue=*/true); + if (!result_sp) + return llvm::createStringError("failed to get dynamic result type"); + + return result_sp; +} + // Find the specified data in memory class CommandObjectMemoryFind : public CommandObjectParsed { public: @@ -1026,49 +1078,19 @@ class CommandObjectMemoryFind : public CommandObjectParsed { } buffer.CopyData(str); } else if (m_memory_options.m_expr.OptionWasSet()) { - StackFrame *frame = m_exe_ctx.GetFramePtr(); - ValueObjectSP result_sp; - if ((eExpressionCompleted == - process->GetTarget().EvaluateExpression( - m_memory_options.m_expr.GetValueAs().value_or( - ""), - frame, result_sp)) && - result_sp) { - uint64_t value = result_sp->GetValueAsUnsigned(0); - std::optional size = llvm::expectedToOptional( - result_sp->GetCompilerType().GetByteSize(nullptr)); - if (!size) - return; - switch (*size) { - case 1: { - uint8_t byte = (uint8_t)value; - buffer.CopyData(&byte, 1); - } break; - case 2: { - uint16_t word = (uint16_t)value; - buffer.CopyData(&word, 2); - } break; - case 4: { - uint32_t lword = (uint32_t)value; - buffer.CopyData(&lword, 4); - } break; - case 8: { - buffer.CopyData(&value, 8); - } break; - case 3: - case 5: - case 6: - case 7: - result.AppendError("unknown type. pass a string instead"); - return; - default: - result.AppendError( - "result size larger than 8 bytes. pass a string instead"); - return; - } - } else { - result.AppendError( - "expression evaluation failed. pass a string instead"); + auto result_or_err = EvaluateExpression( + m_memory_options.m_expr.GetValueAs().value_or(""), + m_exe_ctx.GetFrameRef(), *process); + if (!result_or_err) { + result.AppendError(llvm::toString(result_or_err.takeError())); + return; + } + + ValueObjectSP result_sp = *result_or_err; + + if (auto err = CopyExpressionResult(*result_sp, buffer, + m_exe_ctx.GetFramePtr())) { + result.AppendError(llvm::toString(std::move(err))); return; } } else { diff --git a/lldb/test/API/functionalities/memory/find/TestMemoryFind.py b/lldb/test/API/functionalities/memory/find/TestMemoryFind.py index 09611cc808777..72426e75e013e 100644 --- a/lldb/test/API/functionalities/memory/find/TestMemoryFind.py +++ b/lldb/test/API/functionalities/memory/find/TestMemoryFind.py @@ -79,3 +79,44 @@ def test_memory_find(self): 'memory find -s "nothere" `stringdata` `stringdata+10`', substrs=["data not found within the range."], ) + + # Expression results with unsupported result types. + self.expect( + 'memory find -e "ThreeBytes{}" `&bytedata[0]` `&bytedata[2]`', + substrs=[ + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported" + ], + error=True, + ) + + self.expect( + 'memory find -e "FiveBytes{}" `&bytedata[0]` `&bytedata[2]`', + substrs=[ + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported" + ], + error=True, + ) + + self.expect( + 'memory find -e "SixBytes{}" `&bytedata[0]` `&bytedata[2]`', + substrs=[ + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported" + ], + error=True, + ) + + self.expect( + 'memory find -e "SevenBytes{}" `&bytedata[0]` `&bytedata[2]`', + substrs=[ + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported" + ], + error=True, + ) + + self.expect( + 'memory find -e "NineBytes{}" `&bytedata[0]` `&bytedata[2]`', + substrs=[ + "Only expressions resulting in 1, 2, 4, or 8-byte-sized values are supported" + ], + error=True, + ) diff --git a/lldb/test/API/functionalities/memory/find/main.cpp b/lldb/test/API/functionalities/memory/find/main.cpp index e3dcfc762ee0f..15c8df1a9fcf1 100644 --- a/lldb/test/API/functionalities/memory/find/main.cpp +++ b/lldb/test/API/functionalities/memory/find/main.cpp @@ -1,9 +1,24 @@ #include #include +template struct [[gnu::packed]] Payload { + uint8_t data[T]; +}; + +using ThreeBytes = Payload<3>; +using FiveBytes = Payload<5>; +using SixBytes = Payload<5>; +using SevenBytes = Payload<7>; +using NineBytes = Payload<9>; + int main (int argc, char const *argv[]) { const char* stringdata = "hello world; I like to write text in const char pointers"; uint8_t bytedata[] = {0xAA,0xBB,0xCC,0xDD,0xEE,0xFF,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99}; + ThreeBytes b1; + FiveBytes b2; + SixBytes b3; + SevenBytes b4; + NineBytes b5; return 0; // break here } diff --git a/lldb/test/API/lang/swift/command_memory_find/Makefile b/lldb/test/API/lang/swift/command_memory_find/Makefile new file mode 100644 index 0000000000000..2a69023633b34 --- /dev/null +++ b/lldb/test/API/lang/swift/command_memory_find/Makefile @@ -0,0 +1,3 @@ +SWIFT_SOURCES := main.swift + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/command_memory_find/TestSwiftCommandMemoryFind.py b/lldb/test/API/lang/swift/command_memory_find/TestSwiftCommandMemoryFind.py new file mode 100644 index 0000000000000..0259e1a05d477 --- /dev/null +++ b/lldb/test/API/lang/swift/command_memory_find/TestSwiftCommandMemoryFind.py @@ -0,0 +1,31 @@ +""" +Test that running Swift expressions in the +`memory find` command works. +""" +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestSwiftCommandMemoryFind(TestBase): + def memory_find(self, name: str, expr: str, target): + var = target.FindGlobalVariables(name, 1) + self.assertEqual(len(var), 1) + addr = var[0].AddressOf() + self.assertTrue(addr) + addr = addr.GetValueAsUnsigned() + self.expect(f'memory find -e "{expr}" {hex(addr)} {hex(addr + 8)}', + substrs=["data found at location"]) + + @swiftTest + def test(self): + self.build() + target, _, _, _ = lldbutil.run_to_source_breakpoint( + self, 'Break', lldb.SBFileSpec('main.swift')) + + self.memory_find('elem1', 'elem1', target) + self.memory_find('elem1', '130 + 7', target) + + self.memory_find('elem2', 'elem2', target) + self.memory_find('elem2', '-42', target) diff --git a/lldb/test/API/lang/swift/command_memory_find/main.swift b/lldb/test/API/lang/swift/command_memory_find/main.swift new file mode 100644 index 0000000000000..3de3d3615d45c --- /dev/null +++ b/lldb/test/API/lang/swift/command_memory_find/main.swift @@ -0,0 +1,3 @@ +let elem1: Int32 = 137 +let elem2: Int64 = -42 +print ("Break")