[Lldb-commits] [lldb] r236694 - Fix LLDB-MI -data-read-memory-bytes command to comply with GDB/MI spec

Bruce Mitchener bruce.mitchener at gmail.com
Wed May 6 22:32:14 PDT 2015


Author: brucem
Date: Thu May  7 00:32:13 2015
New Revision: 236694

URL: http://llvm.org/viewvc/llvm-project?rev=236694&view=rev
Log:
Fix LLDB-MI -data-read-memory-bytes command to comply with GDB/MI spec

Summary:
- The address argument can now be an expression (e.g. &array), it's no longer restricted to being just a number literal.
- The -o (offset) option is now properly handled, not just silently ignored.
- The --thread option is now properly handled.
- A new --frame option has been added for consistency with GDB.
- Added a new test to verify old and new functionality.

Patch by Vadim Macagon. Thanks!

Test Plan: ./dotest.py -A x86_64 -C clang --executable $BUILDDIR/bin/lldb tools/lldb-mi/data

Reviewers: domipheus, abidh, ki.stfu

Reviewed By: abidh, ki.stfu

Subscribers: brucem, lldb-commits

Differential Revision: http://reviews.llvm.org/D9470

Modified:
    lldb/trunk/test/tools/lldb-mi/data/TestMiData.py
    lldb/trunk/test/tools/lldb-mi/data/main.cpp
    lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp
    lldb/trunk/tools/lldb-mi/MICmdCmdData.h
    lldb/trunk/tools/lldb-mi/MICmnResources.cpp
    lldb/trunk/tools/lldb-mi/MICmnResources.h
    lldb/trunk/tools/lldb-mi/MIExtensions.txt

Modified: lldb/trunk/test/tools/lldb-mi/data/TestMiData.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-mi/data/TestMiData.py?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-mi/data/TestMiData.py (original)
+++ lldb/trunk/test/tools/lldb-mi/data/TestMiData.py Thu May  7 00:32:13 2015
@@ -41,9 +41,9 @@ class MiDataTestCase(lldbmi_testcase.MiT
     @lldbmi_test
     @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
     @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
-    @unittest2.skip("-data-evaluate-expression doesn't work") #FIXME: the global case worked before refactoring
-    def test_lldbmi_data_read_memory_bytes(self):
-        """Test that 'lldb-mi --interpreter' works for -data-read-memory-bytes."""
+    @unittest2.skip("-data-evaluate-expression doesn't work on globals") #FIXME: the global case worked before refactoring
+    def test_lldbmi_data_read_memory_bytes_global(self):
+        """Test that -data-read-memory-bytes can access global buffers."""
 
         self.spawnLldbMi(args = None)
 
@@ -80,6 +80,114 @@ class MiDataTestCase(lldbmi_testcase.MiT
 
     @lldbmi_test
     @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
+    @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
+    def test_lldbmi_data_read_memory_bytes_local(self):
+        """Test that -data-read-memory-bytes can access local buffers."""
+
+        self.spawnLldbMi(args = None)
+        self.expect(self.child_prompt, exactly = True)
+
+        # Load executable
+        self.runCmd('-file-exec-and-symbols %s' % self.myexe)
+        self.expect(r'\^done')
+
+        # Run to BP_local_array_test_inner
+        line = line_number('main.cpp', '// BP_local_array_test_inner')
+        self.runCmd('-break-insert main.cpp:%d' % line)
+        self.expect(r'\^done,bkpt=\{number="1"')
+        self.runCmd('-exec-run')
+        self.expect(r'\^running')
+        self.expect(r'\*stopped,reason="breakpoint-hit"')
+
+        # Get address of local char[]
+        self.runCmd('-data-evaluate-expression &array')
+        self.expect(r'\^done,value="0x[0-9a-f]+"')
+        addr = int(self.child.after.split('"')[1], 16)
+        size = 4
+
+        # Test that an unquoted hex literal address works
+        self.runCmd('-data-read-memory-bytes %#x %d' % (addr, size))
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # Test that a double-quoted hex literal address works
+        self.runCmd('-data-read-memory-bytes "%#x" %d' % (addr, size))
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # Test that unquoted expressions work
+        self.runCmd('-data-read-memory-bytes &array %d' % size)
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # This doesn't work, and perhaps that makes sense, but it does work on GDB
+        self.runCmd('-data-read-memory-bytes array 4')
+        self.expect(r'\^error')
+        #self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        self.runCmd('-data-read-memory-bytes &array[2] 2')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="0304"\}\]' % (addr + 2, addr + size))
+
+        self.runCmd('-data-read-memory-bytes first_element_ptr %d' % size)
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # Test that double-quoted expressions work
+        self.runCmd('-data-read-memory-bytes "&array" %d' % size)
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        self.runCmd('-data-read-memory-bytes "&array[0] + 1" 3')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+        self.runCmd('-data-read-memory-bytes "first_element_ptr + 1" 3')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+        # Test the -o (offset) option
+        self.runCmd('-data-read-memory-bytes -o 1 &array 3')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="020304"\}\]' % (addr + 1, addr + size))
+
+        # Test the --thread option
+        self.runCmd('-data-read-memory-bytes --thread 1 &array 4')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # Test the --thread option with an invalid value
+        self.runCmd('-data-read-memory-bytes --thread 999 &array 4')
+        self.expect(r'\^error')
+
+        # Test the --frame option (current frame)
+        self.runCmd('-data-read-memory-bytes --frame 0 &array 4')
+        self.expect(r'\^done,memory=\[\{begin="0x0*%x",offset="0x0+",end="0x0*%x",contents="01020304"\}\]' % (addr, addr + size))
+
+        # Test the --frame option (outer frame)
+        self.runCmd('-data-read-memory-bytes --frame 1 &array 4')
+        self.expect(r'\^done,memory=\[\{begin="0x[0-9a-f]+",offset="0x0+",end="0x[0-9a-f]+",contents="05060708"\}\]')
+
+        # Test the --frame option with an invalid value
+        self.runCmd('-data-read-memory-bytes --frame 999 &array 4')
+        self.expect(r'\^error')
+
+        # Test all the options at once
+        self.runCmd('-data-read-memory-bytes --thread 1 --frame 1 -o 2 &array 2')
+        self.expect(r'\^done,memory=\[\{begin="0x[0-9a-f]+",offset="0x0+",end="0x[0-9a-f]+",contents="0708"\}\]')
+
+        # Test that an expression that references undeclared variables doesn't work
+        self.runCmd('-data-read-memory-bytes "&undeclared_array1 + undeclared_array2[1]" 2')
+        self.expect(r'\^error')
+
+        # Test that the address argument is required
+        self.runCmd('-data-read-memory-bytes')
+        self.expect(r'\^error')
+
+        # Test that the count argument is required
+        self.runCmd('-data-read-memory-bytes &array')
+        self.expect(r'\^error')
+
+        # Test that the address argument is required when other options are present
+        self.runCmd('-data-read-memory-bytes --thread 1')
+        self.expect(r'\^error')
+
+        # Test that the count argument is required when other options are present
+        self.runCmd('-data-read-memory-bytes --thread 1 &array')
+        self.expect(r'\^error')
+
+    @lldbmi_test
+    @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows")
     @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
     def test_lldbmi_data_list_register_names(self):
         """Test that 'lldb-mi --interpreter' works for -data-list-register-names."""

Modified: lldb/trunk/test/tools/lldb-mi/data/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/tools/lldb-mi/data/main.cpp?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/test/tools/lldb-mi/data/main.cpp (original)
+++ lldb/trunk/test/tools/lldb-mi/data/main.cpp Thu May  7 00:32:13 2015
@@ -10,8 +10,27 @@
 const char g_CharArray[] = "\x10\x11\x12\x13";
 static const char s_CharArray[] = "\x20\x21\x22\x23";
 
+void
+local_array_test_inner()
+{
+    char array[] = { 0x01, 0x02, 0x03, 0x04 };
+    char *first_element_ptr = &array[0];
+    // BP_local_array_test_inner
+    return;
+}
+
+void
+local_array_test()
+{
+    char array[] = { 0x05, 0x06, 0x07, 0x08 };
+    // BP_local_array_test
+    local_array_test_inner();
+    return;
+}
+
 int
 main(int argc, char const *argv[])
 { // FUNC_main
+    local_array_test();
     return 0;
 }

Modified: lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp (original)
+++ lldb/trunk/tools/lldb-mi/MICmdCmdData.cpp Thu May  7 00:32:13 2015
@@ -517,13 +517,13 @@ CMICmdCmdDataDisassemble::CreateSelf(voi
 //--
 CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes(void)
     : m_constStrArgThread("thread")
+    , m_constStrArgFrame("frame")
     , m_constStrArgByteOffset("o")
-    , m_constStrArgAddrStart("address")
+    , m_constStrArgAddrExpr("address")
     , m_constStrArgNumBytes("count")
     , m_pBufferMemory(nullptr)
     , m_nAddrStart(0)
     , m_nAddrNumBytesToRead(0)
-    , m_nAddrOffset(0)
 {
     // Command factory matches this name with that received from the stdin stream
     m_strMiCmd = "data-read-memory-bytes";
@@ -561,11 +561,13 @@ bool
 CMICmdCmdDataReadMemoryBytes::ParseArgs(void)
 {
     bool bOk =
-        m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1)));
+        m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1)));
+    bOk = bOk &&
+        m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, true, CMICmdArgValListBase::eArgValType_Number, 1)));
     bOk =
         bOk &&
         m_setCmdArgs.Add(*(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1)));
-    bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgAddrStart, true, true, CMICmdArgValNumber::eArgValNumberFormat_Auto)));
+    bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValString(m_constStrArgAddrExpr, true, true, true, true)));
     bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true)));
     return (bOk && ParseValidateCmdOptions());
 }
@@ -575,21 +577,108 @@ CMICmdCmdDataReadMemoryBytes::ParseArgs(
 //          The command is likely to communicate with the LLDB SBDebugger in here.
 // Type:    Overridden.
 // Args:    None.
-// Return:  MIstatus::success - Functional succeeded.
-//          MIstatus::failure - Functional failed.
+// Return:  MIstatus::success - Function succeeded.
+//          MIstatus::failure - Function failed.
 // Throws:  None.
 //--
 bool
 CMICmdCmdDataReadMemoryBytes::Execute(void)
 {
-    CMICMDBASE_GETOPTION(pArgAddrStart, Number, m_constStrArgAddrStart);
-    CMICMDBASE_GETOPTION(pArgAddrOffset, Number, m_constStrArgByteOffset);
+    CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
+    CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame);
+    CMICMDBASE_GETOPTION(pArgAddrOffset, OptionShort, m_constStrArgByteOffset);
+    CMICMDBASE_GETOPTION(pArgAddrExpr, String, m_constStrArgAddrExpr);
     CMICMDBASE_GETOPTION(pArgNumBytes, Number, m_constStrArgNumBytes);
 
-    const MIuint64 nAddrStart = pArgAddrStart->GetValue();
+    // get the --thread option value
+    MIuint64 nThreadId = UINT64_MAX;
+    if (pArgThread->GetFound() && !pArgThread->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nThreadId))
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
+                 m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str()));
+        return MIstatus::failure;
+    }
+
+    // get the --frame option value
+    MIuint64 nFrame = UINT64_MAX;
+    if (pArgFrame->GetFound() && !pArgFrame->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nFrame))
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
+                 m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str()));
+        return MIstatus::failure;
+    }
+
+    // get the -o option value
+    MIuint64 nAddrOffset = 0;
+    if (pArgAddrOffset->GetFound() && !pArgAddrOffset->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nAddrOffset))
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
+                 m_cmdData.strMiCmd.c_str(), m_constStrArgByteOffset.c_str()));
+        return MIstatus::failure;
+    }
+
+    // FIXME: shouldn't have to ensure mandatory arguments are present, that should've been handled
+    // in ParseArgs(), unfortunately that seems kinda sorta broken right now if options are provided
+    // but mandatory arguments are missing, so here we go...
+    if (!pArgAddrExpr->GetFound())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MANDATORY), m_constStrArgAddrExpr.c_str()));
+        return MIstatus::failure;
+    }
+
+    if (!pArgNumBytes->GetFound())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MANDATORY), m_constStrArgNumBytes.c_str()));
+        return MIstatus::failure;
+    }
+
+    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
+    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
+    if (!sbProcess.IsValid())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
+        return MIstatus::failure;
+    }
+
+    lldb::SBThread thread = (nThreadId != UINT64_MAX) ?
+                            sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread();
+    if (!thread.IsValid())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str()));
+        return MIstatus::failure;
+    }
+
+    lldb::SBFrame frame = (nFrame != UINT64_MAX) ?
+                          thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame();
+    if (!frame.IsValid())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str()));
+        return MIstatus::failure;
+    }
+
+    const CMIUtilString &rAddrExpr = pArgAddrExpr->GetValue();
+    lldb::SBValue addrExprValue = frame.EvaluateExpression(rAddrExpr.c_str());
+    lldb::SBError error = addrExprValue.GetError();
+    if (error.Fail())
+    {
+        SetError(error.GetCString());
+        return MIstatus::failure;
+    }
+    else if (!addrExprValue.IsValid())
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
+        return MIstatus::failure;
+    }
+
+    MIuint64 nAddrStart = 0;
+    if (!CMICmnLLDBProxySBValue::GetValueAsUnsigned(addrExprValue, nAddrStart))
+    {
+        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
+        return MIstatus::failure;
+    }
+
+    nAddrStart += nAddrOffset;
     const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue();
-    if (pArgAddrOffset->GetFound())
-        m_nAddrOffset = pArgAddrOffset->GetValue();
 
     m_pBufferMemory = new MIuchar[nAddrNumBytes];
     if (m_pBufferMemory == nullptr)
@@ -598,9 +687,6 @@ CMICmdCmdDataReadMemoryBytes::Execute(vo
         return MIstatus::failure;
     }
 
-    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
-    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
-    lldb::SBError error;
     const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast<lldb::addr_t>(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error);
     if (nReadBytes != nAddrNumBytes)
     {
@@ -640,7 +726,8 @@ CMICmdCmdDataReadMemoryBytes::Acknowledg
     const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart));
     const CMICmnMIValueResult miValueResult("begin", miValueConst);
     CMICmnMIValueTuple miValueTuple(miValueResult);
-    const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%016" PRIx64, m_nAddrOffset));
+    const MIuint64 nAddrOffset = 0;
+    const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%016" PRIx64, nAddrOffset));
     const CMICmnMIValueResult miValueResult2("offset", miValueConst2);
     miValueTuple.Add(miValueResult2);
     const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart + m_nAddrNumBytesToRead));

Modified: lldb/trunk/tools/lldb-mi/MICmdCmdData.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-mi/MICmdCmdData.h?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-mi/MICmdCmdData.h (original)
+++ lldb/trunk/tools/lldb-mi/MICmdCmdData.h Thu May  7 00:32:13 2015
@@ -150,14 +150,14 @@ class CMICmdCmdDataReadMemoryBytes : pub
 
     // Attributes:
   private:
-    const CMIUtilString m_constStrArgThread; // Not specified in MI spec but Eclipse gives this option. Not handled by command.
+    const CMIUtilString m_constStrArgThread; // Not in the MI spec but implemented by GDB.
+    const CMIUtilString m_constStrArgFrame; // Not in the MI spec but implemented by GDB.
     const CMIUtilString m_constStrArgByteOffset;
-    const CMIUtilString m_constStrArgAddrStart;
+    const CMIUtilString m_constStrArgAddrExpr;
     const CMIUtilString m_constStrArgNumBytes;
     MIuchar *m_pBufferMemory;
     MIuint64 m_nAddrStart;
     MIuint64 m_nAddrNumBytesToRead;
-    MIuint64 m_nAddrOffset;
 };
 
 //++ ============================================================================

Modified: lldb/trunk/tools/lldb-mi/MICmnResources.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-mi/MICmnResources.cpp?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-mi/MICmnResources.cpp (original)
+++ lldb/trunk/tools/lldb-mi/MICmnResources.cpp Thu May  7 00:32:13 2015
@@ -249,7 +249,8 @@ const CMICmnResources::SRsrcTextData CMI
     {IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS, "'print' expects option-name and \"on\" or \"off\""},
     {IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION, "'print' error. The option '%s' not found"},
     {IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS, "'print' expects option-name and \"on\" or \"off\""},
-    {IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION, "'print' error. The option '%s' not found"}};
+    {IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION, "'print' error. The option '%s' not found"},
+    {IDS_CMD_ERR_EXPR_INVALID, "Failed to evaluate expression: %s"}};
 
 //++ ------------------------------------------------------------------------------------
 // Details: CMICmnResources constructor.

Modified: lldb/trunk/tools/lldb-mi/MICmnResources.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-mi/MICmnResources.h?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-mi/MICmnResources.h (original)
+++ lldb/trunk/tools/lldb-mi/MICmnResources.h Thu May  7 00:32:13 2015
@@ -267,7 +267,8 @@ enum
     IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS,
     IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION,
     IDS_CMD_ERR_GDBSHOW_OPT_PRINT_BAD_ARGS,
-    IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION
+    IDS_CMD_ERR_GDBSHOW_OPT_PRINT_UNKNOWN_OPTION,
+    IDS_CMD_ERR_EXPR_INVALID
 };
 
 //++ ============================================================================

Modified: lldb/trunk/tools/lldb-mi/MIExtensions.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/lldb-mi/MIExtensions.txt?rev=236694&r1=236693&r2=236694&view=diff
==============================================================================
--- lldb/trunk/tools/lldb-mi/MIExtensions.txt (original)
+++ lldb/trunk/tools/lldb-mi/MIExtensions.txt Thu May  7 00:32:13 2015
@@ -32,6 +32,55 @@ Example:
     -data-info-line hello.cpp:15
     ^done,start="0x0000000100000f80",end="0x0000000100000f94",file="/Users/IliaK/p/hello.cpp",line="15"
 
+# -data-read-memory-bytes
+
+Synopsis
+
+	-data-read-memory-bytes [--thread <thread-id>] [--frame <frame-index>] [-o <byte-offset>] <address> <count>
+
+Where:
+
+	`address`
+		An expression specifying the start of the memory range to read.
+	`count`
+		Number of bytes to read.
+	`byte-offset`
+		Relative offset in bytes from `address` where reading should start.
+	`thread-id`
+		Integer identifier of the thread within which the expression should be evaluated,
+		if this option is omitted the currently selected thread will be used.
+		This option is not in the MI specification but is implemented by GDB.
+	`frame-index`
+		Index of the frame within which the expression should be evaluated,
+		if this option is omitted the currently selected frame will be used.
+		This option is not in the MI specification but is implemented by GDB.
+
+Reads a block of memory from the specified range.
+
+Note that currently this command works in an all-or-nothing fashion where it either reads the entire
+block of memory successfully and returns it as a single block, or it returns an error. This doesn't
+quite match up with the MI specification that says that subsets of the specified range may be
+returned as individual blocks if only some of the memory within the specified range is accessible.
+
+The result record for this command may contain one or more tuples representing the blocks of memory
+that were read, where each tuple has the following fields:
+
+	`begin`
+		The start of the address range for this block (in hex notation).
+	`end`
+		The end of the address range for this block (in hex notation).
+	`offset`
+		Offset of this block from `address` (that was passed in as an argument).
+	`contents`
+		The actual data in this block (in hex notation).
+
+Example:
+
+	(gdb)
+	-data-read-memory-bytes &array 4
+	^done,memory=[{begin="0x00007fffffffeccc",offset="0x0000000000000000",end="0x00007fffffffecd0",contents="01020304"}]
+	(gdb)
+
 # =library-loaded notification
 
 The =library-loaded notification has 3 extra fields:





More information about the lldb-commits mailing list