Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 58 additions & 43 deletions lldb/source/Commands/CommandObjectMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,52 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
#define LLDB_OPTIONS_memory_find
#include "CommandOptions.inc"

static llvm::Error CopyExpressionResult(ValueObject &result,
DataBufferHeap &buffer) {
uint64_t value = result.GetValueAsUnsigned(0);
auto size_or_err = result.GetCompilerType().GetByteSize(nullptr);
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<ValueObjectSP>
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be two separate error messages?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what the value would be tbh. Both indicate that something went wrong during expression evaluation. But if you disagree happy to split it into two

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would be nice to bubble up the error from the expression, but that is presumably attached to result_sp and this condition just catches execution failures, not compiler diagnostics, which should be much rarer. I think this is fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea that seems reasonable. Happy to address that in a separate patch (just to keep things simple for this particular fix)

return llvm::createStringError(
"expression evaluation failed. pass a string instead");

return result_sp;
}

// Find the specified data in memory
class CommandObjectMemoryFind : public CommandObjectParsed {
public:
Expand Down Expand Up @@ -1026,49 +1072,18 @@ 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<llvm::StringRef>().value_or(
""),
frame, result_sp)) &&
result_sp) {
uint64_t value = result_sp->GetValueAsUnsigned(0);
std::optional<uint64_t> 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<llvm::StringRef>().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)) {
result.AppendError(llvm::toString(std::move(err)));
return;
}
} else {
Expand Down
41 changes: 41 additions & 0 deletions lldb/test/API/functionalities/memory/find/TestMemoryFind.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
15 changes: 15 additions & 0 deletions lldb/test/API/functionalities/memory/find/main.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
#include <stdio.h>
#include <stdint.h>

template <size_t T> 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
}
Loading