llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp
Hafiz Abid Qadeer d122fd8d06 Better handle the arguments common to all MI commands.
Summary:
I observed that eclipse was passing --thread-group for many other commands
then we are currently handling. Looking at the MI documentation, the
following link states that each MI command accept the --thread and
--frame option. Looking at the GDB implementation, it seems that apart
from these 2, --thread-group is also handled the same way.

https://sourceware.org/gdb/onlinedocs/gdb/Context-management.html#Context-management

So instead of handling those arguments in every comamnds, I have moved
them into the base class and removed them from elsewhere. Now any command
can use these arguments. The patch seems big but most of the changes are
mechanical.

Reviewers: ki.stfu

Subscribers: lldb-commits

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

llvm-svn: 251636
2015-10-29 16:30:47 +00:00

1758 lines
68 KiB
C++

//===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Overview: CMICmdCmdDataEvaluateExpression implementation.
// CMICmdCmdDataDisassemble implementation.
// CMICmdCmdDataReadMemoryBytes implementation.
// CMICmdCmdDataReadMemory implementation.
// CMICmdCmdDataListRegisterNames implementation.
// CMICmdCmdDataListRegisterValues implementation.
// CMICmdCmdDataListRegisterChanged implementation.
// CMICmdCmdDataWriteMemoryBytes implementation.
// CMICmdCmdDataWriteMemory implementation.
// CMICmdCmdDataInfoLine implementation.
// Third Party Headers:
#include <inttypes.h> // For PRIx64
#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBThread.h"
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBStream.h"
// In-house headers:
#include "MICmdCmdData.h"
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
#include "MICmnLLDBDebugger.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MICmnLLDBProxySBValue.h"
#include "MICmdArgValNumber.h"
#include "MICmdArgValString.h"
#include "MICmdArgValThreadGrp.h"
#include "MICmdArgValOptionLong.h"
#include "MICmdArgValOptionShort.h"
#include "MICmdArgValListOfN.h"
#include "MICmdArgValConsume.h"
#include "MICmnLLDBDebugSessionInfoVarObj.h"
#include "MICmnLLDBUtilSBValue.h"
#include "MIUtilParse.h"
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataEvaluateExpression constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataEvaluateExpression::CMICmdCmdDataEvaluateExpression()
: m_bExpressionValid(true)
, m_bEvaluatedExpression(true)
, m_strValue("??")
, m_bFoundInvalidChar(false)
, m_cExpressionInvalidChar(0x00)
, m_constStrArgExpr("expr")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-evaluate-expression";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataEvaluateExpression::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataEvaluateExpression destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataEvaluateExpression::~CMICmdCmdDataEvaluateExpression()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataEvaluateExpression::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgExpr, true, true, true, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataEvaluateExpression::Execute()
{
CMICMDBASE_GETOPTION(pArgExpr, String, m_constStrArgExpr);
const CMIUtilString &rExpression(pArgExpr->GetValue());
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
lldb::SBThread thread = sbProcess.GetSelectedThread();
m_bExpressionValid = (thread.GetNumFrames() > 0);
if (!m_bExpressionValid)
return MIstatus::success;
lldb::SBFrame frame = thread.GetSelectedFrame();
lldb::SBValue value = frame.EvaluateExpression(rExpression.c_str());
if (!value.IsValid() || value.GetError().Fail())
value = frame.FindVariable(rExpression.c_str());
const CMICmnLLDBUtilSBValue utilValue(value, true);
if (!utilValue.IsValid() || utilValue.IsValueUnknown())
{
m_bEvaluatedExpression = false;
return MIstatus::success;
}
if (!utilValue.HasName())
{
if (HaveInvalidCharacterInExpression(rExpression, m_cExpressionInvalidChar))
{
m_bFoundInvalidChar = true;
return MIstatus::success;
}
m_strValue = rExpression;
return MIstatus::success;
}
if (rExpression.IsQuoted())
{
m_strValue = rExpression.Trim('\"');
return MIstatus::success;
}
m_strValue = utilValue.GetValue(true).Escape().AddSlashes();
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataEvaluateExpression::Acknowledge()
{
if (m_bExpressionValid)
{
if (m_bEvaluatedExpression)
{
if (m_bFoundInvalidChar)
{
const CMICmnMIValueConst miValueConst(
CMIUtilString::Format("Invalid character '%c' in expression", m_cExpressionInvalidChar));
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
const CMICmnMIValueConst miValueConst(m_strValue);
const CMICmnMIValueResult miValueResult("value", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
const CMICmnMIValueConst miValueConst("Could not evaluate expression");
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
const CMICmnMIValueConst miValueConst("Invalid expression");
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataEvaluateExpression::CreateSelf()
{
return new CMICmdCmdDataEvaluateExpression();
}
//++ ------------------------------------------------------------------------------------
// Details: Examine the expression string to see if it contains invalid characters.
// Type: Method.
// Args: vrExpr - (R) Expression string given to *this command.
// vrwInvalidChar - (W) True = Invalid character found, false = nothing found.
// Return: bool - True = Invalid character found, false = nothing found.
// Throws: None.
//--
bool
CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, char &vrwInvalidChar)
{
static const std::string strInvalidCharacters(";#\\");
const size_t nInvalidCharacterOffset = vrExpr.find_first_of(strInvalidCharacters);
const bool bFoundInvalidCharInExpression = (nInvalidCharacterOffset != CMIUtilString::npos);
vrwInvalidChar = bFoundInvalidCharInExpression ? vrExpr[nInvalidCharacterOffset] : 0x00;
return bFoundInvalidCharInExpression;
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataDisassemble constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataDisassemble::CMICmdCmdDataDisassemble()
: m_constStrArgAddrStart("s")
, m_constStrArgAddrEnd("e")
, m_constStrArgConsume("--")
, m_constStrArgMode("mode")
, m_miValueList(true)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-disassemble";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataDisassemble::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataDisassemble destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataDisassemble::~CMICmdCmdDataDisassemble()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataDisassemble::ParseArgs()
{
m_setCmdArgs.Add(
new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1));
m_setCmdArgs.Add(
new CMICmdArgValOptionShort(m_constStrArgAddrEnd, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1));
m_setCmdArgs.Add(new CMICmdArgValConsume(m_constStrArgConsume, true));
m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgMode, true, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataDisassemble::Execute()
{
CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
CMICMDBASE_GETOPTION(pArgAddrStart, OptionShort, m_constStrArgAddrStart);
CMICMDBASE_GETOPTION(pArgAddrEnd, OptionShort, m_constStrArgAddrEnd);
CMICMDBASE_GETOPTION(pArgMode, Number, m_constStrArgMode);
// Retrieve the --thread option's thread ID (only 1)
MIuint64 nThreadId = UINT64_MAX;
if (pArgThread->GetFound() && !pArgThread->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nThreadId))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str()));
return MIstatus::failure;
}
CMIUtilString strAddrStart;
if (!pArgAddrStart->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strAddrStart))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(),
m_constStrArgAddrStart.c_str()));
return MIstatus::failure;
}
MIint64 nAddrStart = 0;
if (!strAddrStart.ExtractNumber(nAddrStart))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(),
m_constStrArgAddrStart.c_str()));
return MIstatus::failure;
}
CMIUtilString strAddrEnd;
if (!pArgAddrEnd->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strAddrEnd))
{
SetError(
CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str()));
return MIstatus::failure;
}
MIint64 nAddrEnd = 0;
if (!strAddrEnd.ExtractNumber(nAddrEnd))
{
SetError(
CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str()));
return MIstatus::failure;
}
const MIuint nDisasmMode = pArgMode->GetValue();
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBTarget sbTarget = rSessionInfo.GetTarget();
lldb::addr_t lldbStartAddr = static_cast<lldb::addr_t>(nAddrStart);
lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart);
const MIuint nInstructions = instructions.GetSize();
// Calculate the offset of first instruction so that we can generate offset starting at 0
lldb::addr_t start_offset = 0;
if(nInstructions > 0)
start_offset = instructions.GetInstructionAtIndex(0).GetAddress().GetOffset();
for (size_t i = 0; i < nInstructions; i++)
{
const char *pUnknown = "??";
lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i);
const char *pStrMnemonic = instrt.GetMnemonic(sbTarget);
pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown;
const char *pStrComment = instrt.GetComment(sbTarget);
CMIUtilString strComment;
if (pStrComment != nullptr && *pStrComment != '\0')
strComment = CMIUtilString::Format("; %s", pStrComment);
lldb::SBAddress address = instrt.GetAddress();
lldb::addr_t addr = address.GetLoadAddress(sbTarget);
const char *pFnName = address.GetFunction().GetName();
pFnName = (pFnName != nullptr) ? pFnName : pUnknown;
lldb::addr_t addrOffSet = address.GetOffset() - start_offset;
const char *pStrOperands = instrt.GetOperands(sbTarget);
pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown;
const size_t instrtSize = instrt.GetByteSize();
// MI "{address=\"0x%016" PRIx64 "\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, addr));
const CMICmnMIValueResult miValueResult("address", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
const CMICmnMIValueConst miValueConst2(pFnName);
const CMICmnMIValueResult miValueResult2("func-name", miValueConst2);
miValueTuple.Add(miValueResult2);
const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("%lld", addrOffSet));
const CMICmnMIValueResult miValueResult3("offset", miValueConst3);
miValueTuple.Add(miValueResult3);
const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", instrtSize));
const CMICmnMIValueResult miValueResult4("size", miValueConst4);
miValueTuple.Add(miValueResult4);
const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s%s", pStrMnemonic, pStrOperands, strComment.Escape(true).c_str()));
const CMICmnMIValueResult miValueResult5("inst", miValueConst5);
miValueTuple.Add(miValueResult5);
if (nDisasmMode == 1)
{
lldb::SBLineEntry lineEntry = address.GetLineEntry();
const MIuint nLine = lineEntry.GetLine();
const char *pFileName = lineEntry.GetFileSpec().GetFilename();
pFileName = (pFileName != nullptr) ? pFileName : pUnknown;
// MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}"
const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%u", nLine));
const CMICmnMIValueResult miValueResult("line", miValueConst);
CMICmnMIValueTuple miValueTuple2(miValueResult);
const CMICmnMIValueConst miValueConst2(pFileName);
const CMICmnMIValueResult miValueResult2("file", miValueConst2);
miValueTuple2.Add(miValueResult2);
const CMICmnMIValueList miValueList(miValueTuple);
const CMICmnMIValueResult miValueResult3("line_asm_insn", miValueList);
miValueTuple2.Add(miValueResult3);
const CMICmnMIValueResult miValueResult4("src_and_asm_line", miValueTuple2);
m_miValueList.Add(miValueResult4);
}
else
{
m_miValueList.Add(miValueTuple);
}
}
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataDisassemble::Acknowledge()
{
const CMICmnMIValueResult miValueResult("asm_insns", m_miValueList);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataDisassemble::CreateSelf()
{
return new CMICmdCmdDataDisassemble();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataReadMemoryBytes constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes()
: m_constStrArgByteOffset("o")
, m_constStrArgAddrExpr("address")
, m_constStrArgNumBytes("count")
, m_pBufferMemory(nullptr)
, m_nAddrStart(0)
, m_nAddrNumBytesToRead(0)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-read-memory-bytes";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataReadMemoryBytes::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataReadMemoryBytes destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataReadMemoryBytes::~CMICmdCmdDataReadMemoryBytes()
{
if (m_pBufferMemory != nullptr)
{
delete[] m_pBufferMemory;
m_pBufferMemory = nullptr;
}
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemoryBytes::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1));
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgAddrExpr, true, true, true, true));
m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// The command is likely to communicate with the LLDB SBDebugger in here.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Function succeeded.
// MIstatus::failure - Function failed.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemoryBytes::Execute()
{
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);
// 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;
}
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();
m_pBufferMemory = new unsigned char[nAddrNumBytes];
if (m_pBufferMemory == nullptr)
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), nAddrNumBytes));
return MIstatus::failure;
}
const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast<lldb::addr_t>(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error);
if (nReadBytes != nAddrNumBytes)
{
SetError(
CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart));
return MIstatus::failure;
}
if (error.Fail())
{
lldb::SBStream err;
const bool bOk = error.GetDescription(err);
MIunused(bOk);
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart,
err.GetData()));
return MIstatus::failure;
}
m_nAddrStart = nAddrStart;
m_nAddrNumBytesToRead = nAddrNumBytes;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemoryBytes::Acknowledge()
{
// MI: memory=[{begin=\"0x%016" PRIx64 "\",offset=\"0x%016" PRIx64" \",end=\"0x%016" PRIx64 "\",contents=\" \" }]"
const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart));
const CMICmnMIValueResult miValueResult("begin", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
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));
const CMICmnMIValueResult miValueResult3("end", miValueConst3);
miValueTuple.Add(miValueResult3);
// MI: contents=\" \"
CMIUtilString strContent;
strContent.reserve((m_nAddrNumBytesToRead << 1) + 1);
for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++)
{
strContent += CMIUtilString::Format("%02hhx", m_pBufferMemory[i]);
}
const CMICmnMIValueConst miValueConst4(strContent);
const CMICmnMIValueResult miValueResult4("contents", miValueConst4);
miValueTuple.Add(miValueResult4);
const CMICmnMIValueList miValueList(miValueTuple);
const CMICmnMIValueResult miValueResult5("memory", miValueList);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataReadMemoryBytes::CreateSelf()
{
return new CMICmdCmdDataReadMemoryBytes();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataReadMemory constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataReadMemory::CMICmdCmdDataReadMemory()
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-read-memory";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataReadMemory::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataReadMemory destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataReadMemory::~CMICmdCmdDataReadMemory()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemory::Execute()
{
// Do nothing - command deprecated use "data-read-memory-bytes" command
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataReadMemory::Acknowledge()
{
// Command CMICmdCmdSupportListFeatures sends "data-read-memory-bytes" which causes this command not to be called
const CMICmnMIValueConst miValueConst(MIRSRC(IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED));
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataReadMemory::CreateSelf()
{
return new CMICmdCmdDataReadMemory();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataListRegisterNames constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterNames::CMICmdCmdDataListRegisterNames()
: m_constStrArgRegNo("regno")
, m_miValueList(true)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-list-register-names";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataListRegisterNames::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataReadMemoryBytes destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterNames::~CMICmdCmdDataListRegisterNames()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterNames::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValListOfN(m_constStrArgRegNo, false, false, CMICmdArgValListBase::eArgValType_Number));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterNames::Execute()
{
CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo);
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;
}
const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions());
if (!rVecRegNo.empty())
{
// List of required registers
CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
while (it != rVecRegNo.end())
{
const CMICmdArgValNumber *pRegNo = static_cast<CMICmdArgValNumber *>(*it);
const MIuint nRegIndex = pRegNo->GetValue();
lldb::SBValue regValue = GetRegister(nRegIndex);
if (regValue.IsValid())
{
const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName());
m_miValueList.Add(miValueConst);
}
// Next
++it;
}
}
else
{
// List of all registers
lldb::SBThread thread = sbProcess.GetSelectedThread();
lldb::SBFrame frame = thread.GetSelectedFrame();
lldb::SBValueList registers = frame.GetRegisters();
const MIuint nRegisters = registers.GetSize();
for (MIuint i = 0; i < nRegisters; i++)
{
lldb::SBValue value = registers.GetValueAtIndex(i);
const MIuint nRegChildren = value.GetNumChildren();
for (MIuint j = 0; j < nRegChildren; j++)
{
lldb::SBValue regValue = value.GetChildAtIndex(j);
if (regValue.IsValid())
{
const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName());
m_miValueList.Add(miValueConst);
}
}
}
}
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterNames::Acknowledge()
{
const CMICmnMIValueResult miValueResult("register-names", m_miValueList);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataListRegisterNames::CreateSelf()
{
return new CMICmdCmdDataListRegisterNames();
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Method.
// Args: None.
// Return: lldb::SBValue - LLDB SBValue object.
// Throws: None.
//--
lldb::SBValue
CMICmdCmdDataListRegisterNames::GetRegister(const MIuint vRegisterIndex) const
{
lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread();
lldb::SBFrame frame = thread.GetSelectedFrame();
lldb::SBValueList registers = frame.GetRegisters();
const MIuint nRegisters = registers.GetSize();
MIuint nRegisterIndex(vRegisterIndex);
for (MIuint i = 0; i < nRegisters; i++)
{
lldb::SBValue value = registers.GetValueAtIndex(i);
const MIuint nRegChildren = value.GetNumChildren();
if (nRegisterIndex >= nRegChildren)
{
nRegisterIndex -= nRegChildren;
continue;
}
lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex);
if (value2.IsValid())
{
return value2;
}
}
return lldb::SBValue();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataListRegisterValues constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterValues::CMICmdCmdDataListRegisterValues()
: m_constStrArgSkip("skip-unavailable")
, m_constStrArgFormat("fmt")
, m_constStrArgRegNo("regno")
, m_miValueList(true)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-list-register-values";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataListRegisterValues::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataListRegisterValues destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterValues::~CMICmdCmdDataListRegisterValues()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterValues::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1));
m_setCmdArgs.Add(new CMICmdArgValOptionLong(m_constStrArgSkip, false, false));
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgFormat, true, true));
m_setCmdArgs.Add(new CMICmdArgValListOfN(m_constStrArgRegNo, false, true, CMICmdArgValListBase::eArgValType_Number));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterValues::Execute()
{
CMICMDBASE_GETOPTION(pArgFormat, String, m_constStrArgFormat);
CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo);
const CMIUtilString &rStrFormat(pArgFormat->GetValue());
if (rStrFormat.length() != 1)
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str()));
return MIstatus::failure;
}
const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat = CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(rStrFormat[0]);
if (eFormat == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid)
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.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;
}
const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions());
if (!rVecRegNo.empty())
{
// List of required registers
CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
while (it != rVecRegNo.end())
{
const CMICmdArgValNumber *pRegNo = static_cast<CMICmdArgValNumber *>(*it);
const MIuint nRegIndex = pRegNo->GetValue();
lldb::SBValue regValue = GetRegister(nRegIndex);
if (regValue.IsValid())
{
AddToOutput(nRegIndex, regValue, eFormat);
}
// Next
++it;
}
}
else
{
// No register numbers are provided. Output all registers.
lldb::SBThread thread = sbProcess.GetSelectedThread();
lldb::SBFrame frame = thread.GetSelectedFrame();
lldb::SBValueList registers = frame.GetRegisters();
const MIuint nRegisters = registers.GetSize();
MIuint nRegIndex = 0;
for (MIuint i = 0; i < nRegisters; i++)
{
lldb::SBValue value = registers.GetValueAtIndex(i);
const MIuint nRegChildren = value.GetNumChildren();
for (MIuint j = 0; j < nRegChildren; j++)
{
lldb::SBValue regValue = value.GetChildAtIndex(j);
if (regValue.IsValid())
{
AddToOutput(nRegIndex, regValue, eFormat);
}
// Next
++nRegIndex;
}
}
}
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterValues::Acknowledge()
{
const CMICmnMIValueResult miValueResult("register-values", m_miValueList);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataListRegisterValues::CreateSelf()
{
return new CMICmdCmdDataListRegisterValues();
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Method.
// Args: None.
// Return: lldb::SBValue - LLDB SBValue object.
// Throws: None.
//--
lldb::SBValue
CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const
{
lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread();
lldb::SBFrame frame = thread.GetSelectedFrame();
lldb::SBValueList registers = frame.GetRegisters();
const MIuint nRegisters = registers.GetSize();
MIuint nRegisterIndex(vRegisterIndex);
for (MIuint i = 0; i < nRegisters; i++)
{
lldb::SBValue value = registers.GetValueAtIndex(i);
const MIuint nRegChildren = value.GetNumChildren();
if (nRegisterIndex >= nRegChildren)
{
nRegisterIndex -= nRegChildren;
continue;
}
lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex);
if (value2.IsValid())
{
return value2;
}
}
return lldb::SBValue();
}
//++ ------------------------------------------------------------------------------------
// Details: Adds the register value to the output list.
// Type: Method.
// Args: Value of the register, its index and output format.
// Return: None
// Throws: None.
//--
void
CMICmdCmdDataListRegisterValues::AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue,
CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat)
{
const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%u", vnIndex));
const CMICmnMIValueResult miValueResult("number", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
const CMIUtilString strRegValue(CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(vrValue, veVarFormat));
const CMICmnMIValueConst miValueConst2(strRegValue);
const CMICmnMIValueResult miValueResult2("value", miValueConst2);
miValueTuple.Add(miValueResult2);
m_miValueList.Add(miValueTuple);
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataListRegisterChanged constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterChanged::CMICmdCmdDataListRegisterChanged()
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-list-changed-registers";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataListRegisterChanged::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataListRegisterChanged destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataListRegisterChanged::~CMICmdCmdDataListRegisterChanged()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterChanged::Execute()
{
// Do nothing
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataListRegisterChanged::Acknowledge()
{
const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED));
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataListRegisterChanged::CreateSelf()
{
return new CMICmdCmdDataListRegisterChanged();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataWriteMemoryBytes constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataWriteMemoryBytes::CMICmdCmdDataWriteMemoryBytes()
: m_constStrArgAddr("address")
, m_constStrArgContents("contents")
, m_constStrArgCount("count")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-write-memory-bytes";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataWriteMemoryBytes::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataWriteMemoryBytes destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataWriteMemoryBytes::~CMICmdCmdDataWriteMemoryBytes()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemoryBytes::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgAddr, true, true, false, true));
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgContents, true, true, true, true));
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgCount, false, true, false, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemoryBytes::Execute()
{
// Do nothing - not reproduceable (yet) in Eclipse
// CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
// CMICMDBASE_GETOPTION( pArgAddr, String, m_constStrArgAddr );
// CMICMDBASE_GETOPTION( pArgNumber, String, m_constStrArgNumber );
// CMICMDBASE_GETOPTION( pArgContents, String, m_constStrArgContents );
//
// Numbers extracts as string types as they could be hex numbers
// '&' is not recognised and so has to be removed
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemoryBytes::Acknowledge()
{
const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED));
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataWriteMemoryBytes::CreateSelf()
{
return new CMICmdCmdDataWriteMemoryBytes();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataWriteMemory constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataWriteMemory::CMICmdCmdDataWriteMemory()
: m_constStrArgOffset("o")
, m_constStrArgAddr("address")
, m_constStrArgD("d")
, m_constStrArgNumber("a number")
, m_constStrArgContents("contents")
, m_nAddr(0)
, m_nCount(0)
, m_pBufferMemory(nullptr)
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-write-memory";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataWriteMemory::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataWriteMemory destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataWriteMemory::~CMICmdCmdDataWriteMemory()
{
if (m_pBufferMemory != nullptr)
{
delete[] m_pBufferMemory;
m_pBufferMemory = nullptr;
}
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemory::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValOptionShort(m_constStrArgOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1));
m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgAddr, true, true));
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgD, true, true));
m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgNumber, true, true));
m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgContents, true, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemory::Execute()
{
CMICMDBASE_GETOPTION(pArgOffset, OptionShort, m_constStrArgOffset);
CMICMDBASE_GETOPTION(pArgAddr, Number, m_constStrArgAddr);
CMICMDBASE_GETOPTION(pArgNumber, Number, m_constStrArgNumber);
CMICMDBASE_GETOPTION(pArgContents, Number, m_constStrArgContents);
MIuint nAddrOffset = 0;
if (pArgOffset->GetFound() && !pArgOffset->GetExpectedOption<CMICmdArgValNumber, MIuint>(nAddrOffset))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddr.c_str()));
return MIstatus::failure;
}
m_nAddr = pArgAddr->GetValue();
m_nCount = pArgNumber->GetValue();
const MIuint64 nValue = pArgContents->GetValue();
m_pBufferMemory = new unsigned char[m_nCount];
if (m_pBufferMemory == nullptr)
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), m_nCount));
return MIstatus::failure;
}
*m_pBufferMemory = static_cast<char>(nValue);
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
lldb::SBError error;
lldb::addr_t addr = static_cast<lldb::addr_t>(m_nAddr + nAddrOffset);
const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error);
if (nBytesWritten != static_cast<size_t>(m_nCount))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr));
return MIstatus::failure;
}
if (error.Fail())
{
lldb::SBStream err;
const bool bOk = error.GetDescription(err);
MIunused(bOk);
SetError(
CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES), m_cmdData.strMiCmd.c_str(), m_nCount, addr, err.GetData()));
return MIstatus::failure;
}
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataWriteMemory::Acknowledge()
{
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataWriteMemory::CreateSelf()
{
return new CMICmdCmdDataWriteMemory();
}
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataInfoLine constructor.
// Type: Method.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataInfoLine::CMICmdCmdDataInfoLine()
: m_constStrArgLocation("location")
{
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-info-line";
// Required by the CMICmdFactory when registering *this command
m_pSelfCreatorFn = &CMICmdCmdDataInfoLine::CreateSelf;
}
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataInfoLine destructor.
// Type: Overrideable.
// Args: None.
// Return: None.
// Throws: None.
//--
CMICmdCmdDataInfoLine::~CMICmdCmdDataInfoLine()
{
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The parses the command line options
// arguments to extract values for each of those arguments.
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataInfoLine::ParseArgs()
{
m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgLocation, true, true));
return ParseValidateCmdOptions();
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command does work in this function.
// 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.
// Throws: None.
//--
bool
CMICmdCmdDataInfoLine::Execute()
{
CMICMDBASE_GETOPTION(pArgLocation, String, m_constStrArgLocation);
const CMIUtilString &strLocation(pArgLocation->GetValue());
CMIUtilString strCmdOptionsLocation;
if (strLocation.at(0) == '*')
{
// Parse argument:
// *0x12345
// ^^^^^^^ -- address
const CMIUtilString strAddress(strLocation.substr(1));
strCmdOptionsLocation = CMIUtilString::Format("--address %s", strAddress.c_str());
}
else
{
const size_t nLineStartPos = strLocation.rfind(':');
if ((nLineStartPos == std::string::npos) || (nLineStartPos == 0) || (nLineStartPos == strLocation.length() - 1))
{
SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_LOCATION_FORMAT), m_cmdData.strMiCmd.c_str(), strLocation.c_str())
.c_str());
return MIstatus::failure;
}
// Parse argument:
// hello.cpp:5
// ^^^^^^^^^ -- file
// ^ -- line
const CMIUtilString strFile(strLocation.substr(0, nLineStartPos));
const CMIUtilString strLine(strLocation.substr(nLineStartPos + 1));
strCmdOptionsLocation = CMIUtilString::Format("--file \"%s\" --line %s", strFile.AddSlashes().c_str(), strLine.c_str());
}
const CMIUtilString strCmd(CMIUtilString::Format("target modules lookup -v %s", strCmdOptionsLocation.c_str()));
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
MIunused(rtn);
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Helper function for parsing a line entry returned from lldb for the command:
// target modules lookup -v <location>
// where the line entry is of the format:
// LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/file:3[:1]
// start end file line column(opt)
// Args: input - (R) Input string to parse.
// start - (W) String representing the start address.
// end - (W) String representing the end address.
// file - (W) String representing the file.
// line - (W) String representing the line.
// Return: bool - True = input was parsed successfully, false = input could not be parsed.
// Throws: None.
//--
static bool
ParseLLDBLineEntry(const char *input, CMIUtilString &start, CMIUtilString &end,
CMIUtilString &file, CMIUtilString &line)
{
// Note: Ambiguities arise because the column is optional, and
// because : can appear in filenames or as a byte in a multibyte
// UTF8 character. We keep those cases to a minimum by using regex
// to work on the string from both the left and right, so that what
// is remains is assumed to be the filename.
// Match LineEntry using regex.
static MIUtilParse::CRegexParser g_lineentry_nocol_regex(
"^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$");
static MIUtilParse::CRegexParser g_lineentry_col_regex(
"^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$");
// ^1=start ^2=end ^3=f ^4=line ^5=:col(opt)
MIUtilParse::CRegexParser::Match match(6);
// First try matching the LineEntry with the column,
// then try without the column.
const bool ok = g_lineentry_col_regex.Execute(input, match) ||
g_lineentry_nocol_regex.Execute(input, match);
if (ok)
{
start = match.GetMatchAtIndex(1);
end = match.GetMatchAtIndex(2);
file = match.GetMatchAtIndex(3);
line = match.GetMatchAtIndex(4);
}
return ok;
}
//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
// Args: None.
// Return: MIstatus::success - Functional succeeded.
// MIstatus::failure - Functional failed.
// Throws: None.
//--
bool
CMICmdCmdDataInfoLine::Acknowledge()
{
if (m_lldbResult.GetErrorSize() > 0)
{
const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
else if (m_lldbResult.GetOutputSize() > 0)
{
CMIUtilString::VecString_t vecLines;
const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
const MIuint nLines(strLldbMsg.SplitLines(vecLines));
for (MIuint i = 0; i < nLines; ++i)
{
// String looks like:
// LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
const CMIUtilString &rLine(vecLines[i]);
CMIUtilString strStart;
CMIUtilString strEnd;
CMIUtilString strFile;
CMIUtilString strLine;
if (!ParseLLDBLineEntry(rLine.c_str(), strStart, strEnd, strFile, strLine))
continue;
const CMICmnMIValueConst miValueConst(strStart);
const CMICmnMIValueResult miValueResult("start", miValueConst);
CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken,
CMICmnMIResultRecord::eResultClass_Done,
miValueResult);
const CMICmnMIValueConst miValueConst2(strEnd);
const CMICmnMIValueResult miValueResult2("end", miValueConst2);
miRecordResult.Add(miValueResult2);
const CMICmnMIValueConst miValueConst3(strFile);
const CMICmnMIValueResult miValueResult3("file", miValueConst3);
miRecordResult.Add(miValueResult3);
const CMICmnMIValueConst miValueConst4(strLine);
const CMICmnMIValueResult miValueResult4("line", miValueConst4);
miRecordResult.Add(miValueResult4);
// MI print "%s^done,start=\"%d\",end=\"%d\"",file=\"%s\",line=\"%d\"
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
}
// MI print "%s^error,msg=\"Command '-data-info-line'. Error: The LineEntry is absent or has an unknown format.\""
const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(), "The LineEntry is absent or has an unknown format."));
const CMICmnMIValueResult miValueResult("msg", miValueConst);
const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
m_miResultRecord = miRecordResult;
return MIstatus::success;
}
//++ ------------------------------------------------------------------------------------
// Details: Required by the CMICmdFactory when registering *this command. The factory
// calls this function to create an instance of *this command.
// Type: Static method.
// Args: None.
// Return: CMICmdBase * - Pointer to a new command.
// Throws: None.
//--
CMICmdBase *
CMICmdCmdDataInfoLine::CreateSelf()
{
return new CMICmdCmdDataInfoLine();
}