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
1758 lines
68 KiB
C++
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();
|
|
}
|