diff options
Diffstat (limited to 'contrib/llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp')
| -rw-r--r-- | contrib/llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp | 1673 |
1 files changed, 1673 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp b/contrib/llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp new file mode 100644 index 000000000000..e0a165765199 --- /dev/null +++ b/contrib/llvm-project/lldb/tools/lldb-mi/MICmdCmdData.cpp @@ -0,0 +1,1673 @@ +//===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// 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/SBInstruction.h" +#include "lldb/API/SBInstructionList.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBThread.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include <inttypes.h> +#include <string> + +// 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" +#include "Platform.h" + +namespace { +CMIUtilString IntToHexAddrStr(uint32_t number) { + return CMIUtilString("0x" + llvm::Twine::utohexstr(number).str()); +} +} // namespace + +//++ +// 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; + // Get a full path to the file. + char pathBuffer[PATH_MAX]; + lineEntry.GetFileSpec().GetPath(pathBuffer, PATH_MAX); + + // MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ], + // fullname=\"%s\"}" + const CMICmnMIValueConst miValueConst( + CMIUtilString::Format("%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 CMICmnMIValueConst miValueConst5(pathBuffer); + const CMICmnMIValueResult miValueResult5("fullname", miValueConst5); + miValueTuple2.Add(miValueResult5); + 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"), + m_resultRecord(m_cmdData.strMiCmdToken, + CMICmnMIResultRecord::eResultClass_Done) { + // 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() = default; + +//++ +// 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); + + lldb::SBLineEntry line; + bool found_line = false; + const CMIUtilString &strLocation(pArgLocation->GetValue()); + lldb::SBTarget target = CMICmnLLDBDebugSessionInfo::Instance().GetTarget(); + + if (strLocation.at(0) == '*') { + // Parse argument: + // *0x12345 + // ^^^^^^^^^ -- address + lldb::addr_t address = 0x0; + if (llvm::StringRef(strLocation.substr(1)).getAsInteger(0, address)) { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR), + m_cmdData.strMiCmd.c_str(), + "Failed to parse address.")); + return MIstatus::failure; + } + line = target.ResolveFileAddress(address).GetLineEntry(); + // Check that found line is valid. + if (line.GetLine()) + found_line = true; + } 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())); + return MIstatus::failure; + } + // Parse argument: + // hello.cpp:5 + // ^^^^^^^^^ -- file + // ^ -- line + const CMIUtilString &strFile(strLocation.substr(0, nLineStartPos)); + uint32_t numLine = 0; + llvm::StringRef(strLocation.substr(nLineStartPos + 1)) + .getAsInteger(0, numLine); + lldb::SBSymbolContextList sc_cu_list = + target.FindCompileUnits(lldb::SBFileSpec(strFile.c_str(), false)); + for (uint32_t i = 0, e = sc_cu_list.GetSize(); i < e; ++i) { + const lldb::SBCompileUnit &cu = + sc_cu_list.GetContextAtIndex(i).GetCompileUnit(); + // Break if we have already found requested line. + if (found_line) + break; + for (uint32_t j = 0, e = cu.GetNumLineEntries(); j < e; ++j) { + const lldb::SBLineEntry &curLine = cu.GetLineEntryAtIndex(j); + if (curLine.GetLine() == numLine) { + line = curLine; + found_line = true; + break; + } + } + } + } + if (!found_line) { + SetError(CMIUtilString::Format( + MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(), + "The LineEntry is absent or has an unknown format.")); + return MIstatus::failure; + } + // Start address. + m_resultRecord.Add(CMICmnMIValueResult( + "start", CMICmnMIValueConst(IntToHexAddrStr( + line.GetStartAddress().GetFileAddress())))); + // End address. + m_resultRecord.Add(CMICmnMIValueResult( + "end", CMICmnMIValueConst(IntToHexAddrStr( + line.GetEndAddress().GetFileAddress())))); + // File. + std::unique_ptr<char[]> upPath(new char[PATH_MAX]); + line.GetFileSpec().GetPath(upPath.get(), PATH_MAX); + m_resultRecord.Add(CMICmnMIValueResult( + "file", CMICmnMIValueConst(CMIUtilString(upPath.get())))); + // Line. + m_resultRecord.Add(CMICmnMIValueResult( + "line", CMICmnMIValueConst(std::to_string(line.GetLine())))); + 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 CMICmdCmdDataInfoLine::Acknowledge() { + m_miResultRecord = m_resultRecord; + 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(); +} |
