Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
104 changes: 61 additions & 43 deletions lldb/source/Commands/CommandObjectMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,55 @@ 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;
case 3:
case 5:
case 6:
case 7:
return llvm::createStringError("unknown type. pass a string instead");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return llvm::createStringError("unknown type. pass a string instead");
return llvm::createStringError("unknown type. Pass a string instead");

Mildly confused about the "pass a string" advice. Is this user-visible and if yes, what's an example where this would be shown?

Copy link
Collaborator

Choose a reason for hiding this comment

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

(I also understand this isn't your error message)

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 this is user visible. It would show exactly this error message:

unknown type. Pass a string instead

What it's trying to say is to use the memory find -s option instead. Could definitely be clearer

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah I see. How about?

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.

default:
return llvm::createStringError(
"result size larger than 8 bytes. pass a string instead");
}

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 +1075,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
31 changes: 31 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,34 @@ 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=["unknown type."],
error=True,
)

self.expect(
'memory find -e "FiveBytes{}" `&bytedata[0]` `&bytedata[2]`',
substrs=["unknown type."],
error=True,
)

self.expect(
'memory find -e "SixBytes{}" `&bytedata[0]` `&bytedata[2]`',
substrs=["unknown type."],
error=True,
)

self.expect(
'memory find -e "SevenBytes{}" `&bytedata[0]` `&bytedata[2]`',
substrs=["unknown type."],
error=True,
)

self.expect(
'memory find -e "NineBytes{}" `&bytedata[0]` `&bytedata[2]`',
substrs=["result size larger than 8 bytes."],
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