[Lldb-commits] [lldb] r194544 - <rdar://problem/14322677>
Enrico Granata
egranata at apple.com
Tue Nov 12 18:18:45 PST 2013
Author: enrico
Date: Tue Nov 12 20:18:44 2013
New Revision: 194544
URL: http://llvm.org/viewvc/llvm-project?rev=194544&view=rev
Log:
<rdar://problem/14322677>
Implement a "memory find" command for LLDB
This is still fairly rough around the edges but works well enough for simple scenarios where a chunk of text or a number are to be found within a certain range of memory, as in
mem find `buffer` `buffer+0x1000` -s "me" -c 5 -r
Modified:
lldb/trunk/source/Commands/CommandObjectMemory.cpp
Modified: lldb/trunk/source/Commands/CommandObjectMemory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectMemory.cpp?rev=194544&r1=194543&r2=194544&view=diff
==============================================================================
--- lldb/trunk/source/Commands/CommandObjectMemory.cpp (original)
+++ lldb/trunk/source/Commands/CommandObjectMemory.cpp Tue Nov 12 20:18:44 2013
@@ -914,6 +914,309 @@ protected:
ClangASTType m_prev_clang_ast_type;
};
+OptionDefinition
+g_memory_find_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "expr", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
+ { LLDB_OPT_SET_1, false, "string", 's', OptionParser::eRequiredArgument, NULL, 0, eArgTypeName, "Use text to find a byte pattern."},
+ { LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCount, "How many times to perform the search."},
+ { LLDB_OPT_SET_1, false, "do-read", 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Should we do a memory read at each match."},
+};
+
+
+//----------------------------------------------------------------------
+// Find the specified data in memory
+//----------------------------------------------------------------------
+class CommandObjectMemoryFind : public CommandObjectParsed
+{
+public:
+
+ class OptionGroupFindMemory : public OptionGroup
+ {
+ public:
+ OptionGroupFindMemory () :
+ OptionGroup(),
+ m_count(1),
+ m_do_read(false)
+ {
+ }
+
+ virtual
+ ~OptionGroupFindMemory ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_memory_find_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_memory_find_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'e':
+ m_expr.SetValueFromCString(option_arg);
+ break;
+
+ case 's':
+ m_string.SetValueFromCString(option_arg);
+ break;
+
+ case 'c':
+ if (m_count.SetValueFromCString(option_arg).Fail())
+ error.SetErrorString("unrecognized value for count");
+ break;
+
+
+ case 'r':
+ m_do_read.SetValueFromCString("true");
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_expr.Clear();
+ m_string.Clear();
+ m_count.Clear();
+ m_do_read.Clear();
+ }
+
+ OptionValueString m_expr;
+ OptionValueString m_string;
+ OptionValueUInt64 m_count;
+ OptionValueBoolean m_do_read;
+ };
+
+ CommandObjectMemoryFind (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory find",
+ "Find a value in the memory of the process being debugged.",
+ NULL,
+ eFlagRequiresProcess | eFlagProcessMustBeLaunched),
+ m_option_group (interpreter),
+ m_memory_options ()
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData addr_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ addr_arg.arg_type = eArgTypeAddress;
+ addr_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (addr_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectMemoryFind ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 2)
+ {
+ result.AppendError("Two addressed needed for memory find");
+ return false;
+ }
+
+ Error error;
+ lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error);
+ if (low_addr == LLDB_INVALID_ADDRESS || error.Fail())
+ {
+ result.AppendError("invalid low address");
+ return false;
+ }
+ lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error);
+ if (high_addr == LLDB_INVALID_ADDRESS || error.Fail())
+ {
+ result.AppendError("invalid low address");
+ return false;
+ }
+
+ if (high_addr <= low_addr)
+ {
+ result.AppendError("starting address must be smaller than ending address");
+ return false;
+ }
+
+ lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
+
+ DataBufferHeap buffer;
+
+ if (m_memory_options.m_string.OptionWasSet())
+ buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue()));
+ else if (m_memory_options.m_expr.OptionWasSet())
+ {
+ StackFrame* frame = m_exe_ctx.GetFramePtr();
+ ValueObjectSP result_sp;
+ if (process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp) && result_sp.get())
+ {
+ uint64_t value = result_sp->GetValueAsUnsigned(0);
+ switch (result_sp->GetClangType().GetByteSize())
+ {
+ 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 false;
+ default:
+ result.AppendError("do not know how to deal with larger than 8 byte result types. pass a string instead");
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("expression evaluation failed. pass a string instead?");
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("please pass either a block of text, or an expression to evaluate.");
+ return false;
+ }
+
+ size_t count = m_memory_options.m_count.GetCurrentValue();
+ found_location = low_addr;
+ bool ever_found = false;
+ while (count)
+ {
+ found_location = Search(found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
+ if (found_location == LLDB_INVALID_ADDRESS)
+ {
+ if (!ever_found)
+ {
+ result.AppendMessage("Your data was not found within the range.\n");
+ result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendMessage("No more matches found within the range.\n");
+ break;
+ }
+ result.AppendMessageWithFormat("Your data was found at location: 0x%" PRIx64 "\n", found_location);
+ if (m_memory_options.m_do_read.GetCurrentValue())
+ {
+ StreamString cmd_buffer;
+ cmd_buffer.Printf("memory read 0x%" PRIx64, found_location);
+ m_interpreter.HandleCommand(cmd_buffer.GetData(), eLazyBoolNo, result);
+ }
+ --count;
+ found_location++;
+ ever_found = true;
+ }
+
+ result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ lldb::addr_t
+ Search (lldb::addr_t low,
+ lldb::addr_t high,
+ uint8_t* buffer,
+ size_t buffer_size)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ DataBufferHeap heap(buffer_size, 0);
+ lldb::addr_t fictional_ptr = low;
+ for (auto ptr = low;
+ low < high;
+ fictional_ptr++)
+ {
+ Error error;
+ if (ptr == low || buffer_size == 1)
+ process->ReadMemory(ptr, heap.GetBytes(), buffer_size, error);
+ else
+ {
+ memmove(heap.GetBytes(), heap.GetBytes()+1, buffer_size-1);
+ process->ReadMemory(ptr, heap.GetBytes()+buffer_size-1, 1, error);
+ }
+ if (error.Fail())
+ return LLDB_INVALID_ADDRESS;
+ if (memcmp(heap.GetBytes(), buffer, buffer_size) == 0)
+ return fictional_ptr;
+ if (ptr == low)
+ ptr += buffer_size;
+ else
+ ptr += 1;
+ }
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFindMemory m_memory_options;
+};
+
OptionDefinition
g_memory_write_option_table[] =
@@ -922,7 +1225,6 @@ g_memory_write_option_table[] =
{ LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
};
-
//----------------------------------------------------------------------
// Write memory to the inferior process
//----------------------------------------------------------------------
@@ -948,13 +1250,13 @@ public:
{
return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
}
-
+
virtual const OptionDefinition*
GetDefinitions ()
{
return g_memory_write_option_table;
}
-
+
virtual Error
SetOptionValue (CommandInterpreter &interpreter,
uint32_t option_idx,
@@ -962,7 +1264,7 @@ public:
{
Error error;
const int short_option = g_memory_write_option_table[option_idx].short_option;
-
+
switch (short_option)
{
case 'i':
@@ -973,7 +1275,7 @@ public:
error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
}
break;
-
+
case 'o':
{
bool success;
@@ -1374,6 +1676,7 @@ CommandObjectMemory::CommandObjectMemory
"A set of commands for operating on memory.",
"memory <subcommand> [<subcommand-options>]")
{
+ LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
}
More information about the lldb-commits
mailing list