forked from OSchip/llvm-project
1822 lines
69 KiB
C++
1822 lines
69 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 "lldb/API/SBCommandInterpreter.h"
|
|
#include "lldb/API/SBInstruction.h"
|
|
#include "lldb/API/SBInstructionList.h"
|
|
#include "lldb/API/SBStream.h"
|
|
#include "lldb/API/SBThread.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Regex.h"
|
|
#include <inttypes.h> // For PRIx64
|
|
|
|
// In-house headers:
|
|
#include "MICmdArgValConsume.h"
|
|
#include "MICmdArgValListOfN.h"
|
|
#include "MICmdArgValNumber.h"
|
|
#include "MICmdArgValOptionLong.h"
|
|
#include "MICmdArgValOptionShort.h"
|
|
#include "MICmdArgValString.h"
|
|
#include "MICmdArgValThreadGrp.h"
|
|
#include "MICmdCmdData.h"
|
|
#include "MICmnLLDBDebugSessionInfo.h"
|
|
#include "MICmnLLDBDebugSessionInfoVarObj.h"
|
|
#include "MICmnLLDBDebugger.h"
|
|
#include "MICmnLLDBProxySBValue.h"
|
|
#include "MICmnLLDBUtilSBValue.h"
|
|
#include "MICmnMIResultRecord.h"
|
|
#include "MICmnMIValueConst.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());
|
|
m_Error = value.GetError();
|
|
if (!value.IsValid() || m_Error.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;
|
|
}
|
|
CMIUtilString mi_error_msg = "Could not evaluate expression";
|
|
if (const char *err_msg = m_Error.GetCString())
|
|
mi_error_msg = err_msg;
|
|
const CMICmnMIValueConst miValueConst(mi_error_msg.Escape(true));
|
|
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_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 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 llvm::Regex g_lineentry_nocol_regex(llvm::StringRef(
|
|
"^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$"));
|
|
static llvm::Regex g_lineentry_col_regex(
|
|
llvm::StringRef("^ *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)
|
|
|
|
llvm::SmallVector<llvm::StringRef, 6> match;
|
|
|
|
// First try matching the LineEntry with the column,
|
|
// then try without the column.
|
|
const bool ok = g_lineentry_col_regex.match(input, &match) ||
|
|
g_lineentry_nocol_regex.match(input, &match);
|
|
if (ok) {
|
|
start = match[1];
|
|
end = match[2];
|
|
file = match[3];
|
|
line = match[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();
|
|
}
|