1//===-- MICmdCmdData.cpp ----------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// Overview:    CMICmdCmdDataEvaluateExpression     implementation.
11//              CMICmdCmdDataDisassemble            implementation.
12//              CMICmdCmdDataReadMemoryBytes        implementation.
13//              CMICmdCmdDataReadMemory             implementation.
14//              CMICmdCmdDataListRegisterNames      implementation.
15//              CMICmdCmdDataListRegisterValues     implementation.
16//              CMICmdCmdDataListRegisterChanged    implementation.
17//              CMICmdCmdDataWriteMemoryBytes       implementation.
18//              CMICmdCmdDataWriteMemory            implementation.
19//              CMICmdCmdDataInfoLine               implementation.
20
21// Third Party Headers:
22#include <inttypes.h> // For PRIx64
23#include "lldb/API/SBCommandInterpreter.h"
24#include "lldb/API/SBThread.h"
25#include "lldb/API/SBInstruction.h"
26#include "lldb/API/SBInstructionList.h"
27#include "lldb/API/SBStream.h"
28
29// In-house headers:
30#include "MICmdCmdData.h"
31#include "MICmnMIResultRecord.h"
32#include "MICmnMIValueConst.h"
33#include "MICmnLLDBDebugger.h"
34#include "MICmnLLDBDebugSessionInfo.h"
35#include "MICmnLLDBProxySBValue.h"
36#include "MICmdArgValNumber.h"
37#include "MICmdArgValString.h"
38#include "MICmdArgValThreadGrp.h"
39#include "MICmdArgValOptionLong.h"
40#include "MICmdArgValOptionShort.h"
41#include "MICmdArgValListOfN.h"
42#include "MICmdArgValConsume.h"
43#include "MICmnLLDBDebugSessionInfoVarObj.h"
44#include "MICmnLLDBUtilSBValue.h"
45#include "MIUtilParse.h"
46
47//++ ------------------------------------------------------------------------------------
48// Details: CMICmdCmdDataEvaluateExpression constructor.
49// Type:    Method.
50// Args:    None.
51// Return:  None.
52// Throws:  None.
53//--
54CMICmdCmdDataEvaluateExpression::CMICmdCmdDataEvaluateExpression()
55    : m_bExpressionValid(true)
56    , m_bEvaluatedExpression(true)
57    , m_strValue("??")
58    , m_bFoundInvalidChar(false)
59    , m_cExpressionInvalidChar(0x00)
60    , m_constStrArgExpr("expr")
61{
62    // Command factory matches this name with that received from the stdin stream
63    m_strMiCmd = "data-evaluate-expression";
64
65    // Required by the CMICmdFactory when registering *this command
66    m_pSelfCreatorFn = &CMICmdCmdDataEvaluateExpression::CreateSelf;
67}
68
69//++ ------------------------------------------------------------------------------------
70// Details: CMICmdCmdDataEvaluateExpression destructor.
71// Type:    Overrideable.
72// Args:    None.
73// Return:  None.
74// Throws:  None.
75//--
76CMICmdCmdDataEvaluateExpression::~CMICmdCmdDataEvaluateExpression()
77{
78}
79
80//++ ------------------------------------------------------------------------------------
81// Details: The invoker requires this function. The parses the command line options
82//          arguments to extract values for each of those arguments.
83// Type:    Overridden.
84// Args:    None.
85// Return:  MIstatus::success - Functional succeeded.
86//          MIstatus::failure - Functional failed.
87// Throws:  None.
88//--
89bool
90CMICmdCmdDataEvaluateExpression::ParseArgs()
91{
92    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgExpr, true, true, true, true));
93    return ParseValidateCmdOptions();
94}
95
96//++ ------------------------------------------------------------------------------------
97// Details: The invoker requires this function. The command does work in this function.
98//          The command is likely to communicate with the LLDB SBDebugger in here.
99// Type:    Overridden.
100// Args:    None.
101// Return:  MIstatus::success - Functional succeeded.
102//          MIstatus::failure - Functional failed.
103// Throws:  None.
104//--
105bool
106CMICmdCmdDataEvaluateExpression::Execute()
107{
108    CMICMDBASE_GETOPTION(pArgExpr, String, m_constStrArgExpr);
109
110    const CMIUtilString &rExpression(pArgExpr->GetValue());
111    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
112    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
113    lldb::SBThread thread = sbProcess.GetSelectedThread();
114    m_bExpressionValid = (thread.GetNumFrames() > 0);
115    if (!m_bExpressionValid)
116        return MIstatus::success;
117
118    lldb::SBFrame frame = thread.GetSelectedFrame();
119    lldb::SBValue value = frame.EvaluateExpression(rExpression.c_str());
120    if (!value.IsValid() || value.GetError().Fail())
121        value = frame.FindVariable(rExpression.c_str());
122    const CMICmnLLDBUtilSBValue utilValue(value, true);
123    if (!utilValue.IsValid() || utilValue.IsValueUnknown())
124    {
125        m_bEvaluatedExpression = false;
126        return MIstatus::success;
127    }
128    if (!utilValue.HasName())
129    {
130        if (HaveInvalidCharacterInExpression(rExpression, m_cExpressionInvalidChar))
131        {
132            m_bFoundInvalidChar = true;
133            return MIstatus::success;
134        }
135
136        m_strValue = rExpression;
137        return MIstatus::success;
138    }
139    if (rExpression.IsQuoted())
140    {
141        m_strValue = rExpression.Trim('\"');
142        return MIstatus::success;
143    }
144    m_strValue = utilValue.GetValue(true).Escape().AddSlashes();
145    return MIstatus::success;
146}
147
148//++ ------------------------------------------------------------------------------------
149// Details: The invoker requires this function. The command prepares a MI Record Result
150//          for the work carried out in the Execute().
151// Type:    Overridden.
152// Args:    None.
153// Return:  MIstatus::success - Functional succeeded.
154//          MIstatus::failure - Functional failed.
155// Throws:  None.
156//--
157bool
158CMICmdCmdDataEvaluateExpression::Acknowledge()
159{
160    if (m_bExpressionValid)
161    {
162        if (m_bEvaluatedExpression)
163        {
164            if (m_bFoundInvalidChar)
165            {
166                const CMICmnMIValueConst miValueConst(
167                    CMIUtilString::Format("Invalid character '%c' in expression", m_cExpressionInvalidChar));
168                const CMICmnMIValueResult miValueResult("msg", miValueConst);
169                const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
170                m_miResultRecord = miRecordResult;
171                return MIstatus::success;
172            }
173
174            const CMICmnMIValueConst miValueConst(m_strValue);
175            const CMICmnMIValueResult miValueResult("value", miValueConst);
176            const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
177            m_miResultRecord = miRecordResult;
178            return MIstatus::success;
179        }
180
181        const CMICmnMIValueConst miValueConst("Could not evaluate expression");
182        const CMICmnMIValueResult miValueResult("msg", miValueConst);
183        const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
184        m_miResultRecord = miRecordResult;
185        return MIstatus::success;
186    }
187
188    const CMICmnMIValueConst miValueConst("Invalid expression");
189    const CMICmnMIValueResult miValueResult("msg", miValueConst);
190    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
191    m_miResultRecord = miRecordResult;
192
193    return MIstatus::success;
194}
195
196//++ ------------------------------------------------------------------------------------
197// Details: Required by the CMICmdFactory when registering *this command. The factory
198//          calls this function to create an instance of *this command.
199// Type:    Static method.
200// Args:    None.
201// Return:  CMICmdBase * - Pointer to a new command.
202// Throws:  None.
203//--
204CMICmdBase *
205CMICmdCmdDataEvaluateExpression::CreateSelf()
206{
207    return new CMICmdCmdDataEvaluateExpression();
208}
209
210//++ ------------------------------------------------------------------------------------
211// Details: Examine the expression string to see if it contains invalid characters.
212// Type:    Method.
213// Args:    vrExpr          - (R) Expression string given to *this command.
214//          vrwInvalidChar  - (W) True = Invalid character found, false = nothing found.
215// Return:  bool - True = Invalid character found, false = nothing found.
216// Throws:  None.
217//--
218bool
219CMICmdCmdDataEvaluateExpression::HaveInvalidCharacterInExpression(const CMIUtilString &vrExpr, char &vrwInvalidChar)
220{
221    static const std::string strInvalidCharacters(";#\\");
222    const size_t nInvalidCharacterOffset = vrExpr.find_first_of(strInvalidCharacters);
223    const bool bFoundInvalidCharInExpression = (nInvalidCharacterOffset != CMIUtilString::npos);
224    vrwInvalidChar = bFoundInvalidCharInExpression ? vrExpr[nInvalidCharacterOffset] : 0x00;
225    return bFoundInvalidCharInExpression;
226}
227
228//---------------------------------------------------------------------------------------
229//---------------------------------------------------------------------------------------
230//---------------------------------------------------------------------------------------
231
232//++ ------------------------------------------------------------------------------------
233// Details: CMICmdCmdDataDisassemble constructor.
234// Type:    Method.
235// Args:    None.
236// Return:  None.
237// Throws:  None.
238//--
239CMICmdCmdDataDisassemble::CMICmdCmdDataDisassemble()
240    : m_constStrArgAddrStart("s")
241    , m_constStrArgAddrEnd("e")
242    , m_constStrArgMode("mode")
243    , m_miValueList(true)
244{
245    // Command factory matches this name with that received from the stdin stream
246    m_strMiCmd = "data-disassemble";
247
248    // Required by the CMICmdFactory when registering *this command
249    m_pSelfCreatorFn = &CMICmdCmdDataDisassemble::CreateSelf;
250}
251
252//++ ------------------------------------------------------------------------------------
253// Details: CMICmdCmdDataDisassemble destructor.
254// Type:    Overrideable.
255// Args:    None.
256// Return:  None.
257// Throws:  None.
258//--
259CMICmdCmdDataDisassemble::~CMICmdCmdDataDisassemble()
260{
261}
262
263//++ ------------------------------------------------------------------------------------
264// Details: The invoker requires this function. The parses the command line options
265//          arguments to extract values for each of those arguments.
266// Type:    Overridden.
267// Args:    None.
268// Return:  MIstatus::success - Functional succeeded.
269//          MIstatus::failure - Functional failed.
270// Throws:  None.
271//--
272bool
273CMICmdCmdDataDisassemble::ParseArgs()
274{
275    m_setCmdArgs.Add(
276        new CMICmdArgValOptionShort(m_constStrArgAddrStart, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1));
277    m_setCmdArgs.Add(
278        new CMICmdArgValOptionShort(m_constStrArgAddrEnd, true, true, CMICmdArgValListBase::eArgValType_StringQuotedNumber, 1));
279    m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgMode, true, true));
280    return ParseValidateCmdOptions();
281}
282
283//++ ------------------------------------------------------------------------------------
284// Details: The invoker requires this function. The command does work in this function.
285//          The command is likely to communicate with the LLDB SBDebugger in here.
286// Type:    Overridden.
287// Args:    None.
288// Return:  MIstatus::success - Functional succeeded.
289//          MIstatus::failure - Functional failed.
290// Throws:  None.
291//--
292bool
293CMICmdCmdDataDisassemble::Execute()
294{
295    CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
296    CMICMDBASE_GETOPTION(pArgAddrStart, OptionShort, m_constStrArgAddrStart);
297    CMICMDBASE_GETOPTION(pArgAddrEnd, OptionShort, m_constStrArgAddrEnd);
298    CMICMDBASE_GETOPTION(pArgMode, Number, m_constStrArgMode);
299
300    // Retrieve the --thread option's thread ID (only 1)
301    MIuint64 nThreadId = UINT64_MAX;
302    if (pArgThread->GetFound() && !pArgThread->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nThreadId))
303    {
304        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str()));
305        return MIstatus::failure;
306    }
307    CMIUtilString strAddrStart;
308    if (!pArgAddrStart->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strAddrStart))
309    {
310        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(),
311                                       m_constStrArgAddrStart.c_str()));
312        return MIstatus::failure;
313    }
314    MIint64 nAddrStart = 0;
315    if (!strAddrStart.ExtractNumber(nAddrStart))
316    {
317        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_START_INVALID), m_cmdData.strMiCmd.c_str(),
318                                       m_constStrArgAddrStart.c_str()));
319        return MIstatus::failure;
320    }
321
322    CMIUtilString strAddrEnd;
323    if (!pArgAddrEnd->GetExpectedOption<CMICmdArgValString, CMIUtilString>(strAddrEnd))
324    {
325        SetError(
326            CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str()));
327        return MIstatus::failure;
328    }
329    MIint64 nAddrEnd = 0;
330    if (!strAddrEnd.ExtractNumber(nAddrEnd))
331    {
332        SetError(
333            CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_DISASM_ADDR_END_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddrEnd.c_str()));
334        return MIstatus::failure;
335    }
336    const MIuint nDisasmMode = pArgMode->GetValue();
337
338    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
339    lldb::SBTarget sbTarget = rSessionInfo.GetTarget();
340    lldb::addr_t lldbStartAddr = static_cast<lldb::addr_t>(nAddrStart);
341    lldb::SBInstructionList instructions = sbTarget.ReadInstructions(lldb::SBAddress(lldbStartAddr, sbTarget), nAddrEnd - nAddrStart);
342    const MIuint nInstructions = instructions.GetSize();
343    // Calculate the offset of first instruction so that we can generate offset starting at 0
344    lldb::addr_t start_offset = 0;
345    if(nInstructions > 0)
346        start_offset = instructions.GetInstructionAtIndex(0).GetAddress().GetOffset();
347
348    for (size_t i = 0; i < nInstructions; i++)
349    {
350        const char *pUnknown = "??";
351        lldb::SBInstruction instrt = instructions.GetInstructionAtIndex(i);
352        const char *pStrMnemonic = instrt.GetMnemonic(sbTarget);
353        pStrMnemonic = (pStrMnemonic != nullptr) ? pStrMnemonic : pUnknown;
354        const char *pStrComment = instrt.GetComment(sbTarget);
355        CMIUtilString strComment;
356        if (pStrComment != nullptr && *pStrComment != '\0')
357            strComment = CMIUtilString::Format("; %s", pStrComment);
358        lldb::SBAddress address = instrt.GetAddress();
359        lldb::addr_t addr = address.GetLoadAddress(sbTarget);
360        const char *pFnName = address.GetFunction().GetName();
361        pFnName = (pFnName != nullptr) ? pFnName : pUnknown;
362        lldb::addr_t addrOffSet = address.GetOffset() - start_offset;
363        const char *pStrOperands = instrt.GetOperands(sbTarget);
364        pStrOperands = (pStrOperands != nullptr) ? pStrOperands : pUnknown;
365        const size_t instrtSize = instrt.GetByteSize();
366
367        // MI "{address=\"0x%016" PRIx64 "\",func-name=\"%s\",offset=\"%lld\",inst=\"%s %s\"}"
368        const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, addr));
369        const CMICmnMIValueResult miValueResult("address", miValueConst);
370        CMICmnMIValueTuple miValueTuple(miValueResult);
371        const CMICmnMIValueConst miValueConst2(pFnName);
372        const CMICmnMIValueResult miValueResult2("func-name", miValueConst2);
373        miValueTuple.Add(miValueResult2);
374        const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("%lld", addrOffSet));
375        const CMICmnMIValueResult miValueResult3("offset", miValueConst3);
376        miValueTuple.Add(miValueResult3);
377        const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", instrtSize));
378        const CMICmnMIValueResult miValueResult4("size", miValueConst4);
379        miValueTuple.Add(miValueResult4);
380        const CMICmnMIValueConst miValueConst5(CMIUtilString::Format("%s %s%s", pStrMnemonic, pStrOperands, strComment.Escape(true).c_str()));
381        const CMICmnMIValueResult miValueResult5("inst", miValueConst5);
382        miValueTuple.Add(miValueResult5);
383
384        if (nDisasmMode == 1)
385        {
386            lldb::SBLineEntry lineEntry = address.GetLineEntry();
387            const MIuint nLine = lineEntry.GetLine();
388            const char *pFileName = lineEntry.GetFileSpec().GetFilename();
389            pFileName = (pFileName != nullptr) ? pFileName : pUnknown;
390
391            // MI "src_and_asm_line={line=\"%u\",file=\"%s\",line_asm_insn=[ ]}"
392            const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%u", nLine));
393            const CMICmnMIValueResult miValueResult("line", miValueConst);
394            CMICmnMIValueTuple miValueTuple2(miValueResult);
395            const CMICmnMIValueConst miValueConst2(pFileName);
396            const CMICmnMIValueResult miValueResult2("file", miValueConst2);
397            miValueTuple2.Add(miValueResult2);
398            const CMICmnMIValueList miValueList(miValueTuple);
399            const CMICmnMIValueResult miValueResult3("line_asm_insn", miValueList);
400            miValueTuple2.Add(miValueResult3);
401            const CMICmnMIValueResult miValueResult4("src_and_asm_line", miValueTuple2);
402            m_miValueList.Add(miValueResult4);
403        }
404        else
405        {
406            m_miValueList.Add(miValueTuple);
407        }
408    }
409
410    return MIstatus::success;
411}
412
413//++ ------------------------------------------------------------------------------------
414// Details: The invoker requires this function. The command prepares a MI Record Result
415//          for the work carried out in the Execute().
416// Type:    Overridden.
417// Args:    None.
418// Return:  MIstatus::success - Functional succeeded.
419//          MIstatus::failure - Functional failed.
420// Throws:  None.
421//--
422bool
423CMICmdCmdDataDisassemble::Acknowledge()
424{
425    const CMICmnMIValueResult miValueResult("asm_insns", m_miValueList);
426    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
427    m_miResultRecord = miRecordResult;
428
429    return MIstatus::success;
430}
431
432//++ ------------------------------------------------------------------------------------
433// Details: Required by the CMICmdFactory when registering *this command. The factory
434//          calls this function to create an instance of *this command.
435// Type:    Static method.
436// Args:    None.
437// Return:  CMICmdBase * - Pointer to a new command.
438// Throws:  None.
439//--
440CMICmdBase *
441CMICmdCmdDataDisassemble::CreateSelf()
442{
443    return new CMICmdCmdDataDisassemble();
444}
445
446//---------------------------------------------------------------------------------------
447//---------------------------------------------------------------------------------------
448//---------------------------------------------------------------------------------------
449
450//++ ------------------------------------------------------------------------------------
451// Details: CMICmdCmdDataReadMemoryBytes constructor.
452// Type:    Method.
453// Args:    None.
454// Return:  None.
455// Throws:  None.
456//--
457CMICmdCmdDataReadMemoryBytes::CMICmdCmdDataReadMemoryBytes()
458    : m_constStrArgByteOffset("o")
459    , m_constStrArgAddrExpr("address")
460    , m_constStrArgNumBytes("count")
461    , m_pBufferMemory(nullptr)
462    , m_nAddrStart(0)
463    , m_nAddrNumBytesToRead(0)
464{
465    // Command factory matches this name with that received from the stdin stream
466    m_strMiCmd = "data-read-memory-bytes";
467
468    // Required by the CMICmdFactory when registering *this command
469    m_pSelfCreatorFn = &CMICmdCmdDataReadMemoryBytes::CreateSelf;
470}
471
472//++ ------------------------------------------------------------------------------------
473// Details: CMICmdCmdDataReadMemoryBytes destructor.
474// Type:    Overrideable.
475// Args:    None.
476// Return:  None.
477// Throws:  None.
478//--
479CMICmdCmdDataReadMemoryBytes::~CMICmdCmdDataReadMemoryBytes()
480{
481    if (m_pBufferMemory != nullptr)
482    {
483        delete[] m_pBufferMemory;
484        m_pBufferMemory = nullptr;
485    }
486}
487
488//++ ------------------------------------------------------------------------------------
489// Details: The invoker requires this function. The parses the command line options
490//          arguments to extract values for each of those arguments.
491// Type:    Overridden.
492// Args:    None.
493// Return:  MIstatus::success - Functional succeeded.
494//          MIstatus::failure - Functional failed.
495// Throws:  None.
496//--
497bool
498CMICmdCmdDataReadMemoryBytes::ParseArgs()
499{
500    m_setCmdArgs.Add(new CMICmdArgValOptionShort(m_constStrArgByteOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1));
501    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgAddrExpr, true, true, true, true));
502    m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgNumBytes, true, true));
503    return ParseValidateCmdOptions();
504}
505
506//++ ------------------------------------------------------------------------------------
507// Details: The invoker requires this function. The command does work in this function.
508//          The command is likely to communicate with the LLDB SBDebugger in here.
509// Type:    Overridden.
510// Args:    None.
511// Return:  MIstatus::success - Function succeeded.
512//          MIstatus::failure - Function failed.
513// Throws:  None.
514//--
515bool
516CMICmdCmdDataReadMemoryBytes::Execute()
517{
518    CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread);
519    CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame);
520    CMICMDBASE_GETOPTION(pArgAddrOffset, OptionShort, m_constStrArgByteOffset);
521    CMICMDBASE_GETOPTION(pArgAddrExpr, String, m_constStrArgAddrExpr);
522    CMICMDBASE_GETOPTION(pArgNumBytes, Number, m_constStrArgNumBytes);
523
524    // get the --thread option value
525    MIuint64 nThreadId = UINT64_MAX;
526    if (pArgThread->GetFound() && !pArgThread->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nThreadId))
527    {
528        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
529                 m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str()));
530        return MIstatus::failure;
531    }
532
533    // get the --frame option value
534    MIuint64 nFrame = UINT64_MAX;
535    if (pArgFrame->GetFound() && !pArgFrame->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nFrame))
536    {
537        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
538                 m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str()));
539        return MIstatus::failure;
540    }
541
542    // get the -o option value
543    MIuint64 nAddrOffset = 0;
544    if (pArgAddrOffset->GetFound() && !pArgAddrOffset->GetExpectedOption<CMICmdArgValNumber, MIuint64>(nAddrOffset))
545    {
546        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND),
547                 m_cmdData.strMiCmd.c_str(), m_constStrArgByteOffset.c_str()));
548        return MIstatus::failure;
549    }
550
551    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
552    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
553    if (!sbProcess.IsValid())
554    {
555        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
556        return MIstatus::failure;
557    }
558
559    lldb::SBThread thread = (nThreadId != UINT64_MAX) ?
560                            sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread();
561    if (!thread.IsValid())
562    {
563        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_THREAD_INVALID), m_cmdData.strMiCmd.c_str()));
564        return MIstatus::failure;
565    }
566
567    lldb::SBFrame frame = (nFrame != UINT64_MAX) ?
568                          thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame();
569    if (!frame.IsValid())
570    {
571        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_FRAME_INVALID), m_cmdData.strMiCmd.c_str()));
572        return MIstatus::failure;
573    }
574
575    const CMIUtilString &rAddrExpr = pArgAddrExpr->GetValue();
576    lldb::SBValue addrExprValue = frame.EvaluateExpression(rAddrExpr.c_str());
577    lldb::SBError error = addrExprValue.GetError();
578    if (error.Fail())
579    {
580        SetError(error.GetCString());
581        return MIstatus::failure;
582    }
583    else if (!addrExprValue.IsValid())
584    {
585        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
586        return MIstatus::failure;
587    }
588
589    MIuint64 nAddrStart = 0;
590    if (!CMICmnLLDBProxySBValue::GetValueAsUnsigned(addrExprValue, nAddrStart))
591    {
592        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_EXPR_INVALID), rAddrExpr.c_str()));
593        return MIstatus::failure;
594    }
595
596    nAddrStart += nAddrOffset;
597    const MIuint64 nAddrNumBytes = pArgNumBytes->GetValue();
598
599    m_pBufferMemory = new unsigned char[nAddrNumBytes];
600    if (m_pBufferMemory == nullptr)
601    {
602        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), nAddrNumBytes));
603        return MIstatus::failure;
604    }
605
606    const MIuint64 nReadBytes = sbProcess.ReadMemory(static_cast<lldb::addr_t>(nAddrStart), (void *)m_pBufferMemory, nAddrNumBytes, error);
607    if (nReadBytes != nAddrNumBytes)
608    {
609        SetError(
610            CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_READ_WHOLE_BLK), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart));
611        return MIstatus::failure;
612    }
613    if (error.Fail())
614    {
615        lldb::SBStream err;
616        const bool bOk = error.GetDescription(err);
617        MIunused(bOk);
618        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_READ_MEM_BYTES), m_cmdData.strMiCmd.c_str(), nAddrNumBytes, nAddrStart,
619                                       err.GetData()));
620        return MIstatus::failure;
621    }
622
623    m_nAddrStart = nAddrStart;
624    m_nAddrNumBytesToRead = nAddrNumBytes;
625
626    return MIstatus::success;
627}
628
629//++ ------------------------------------------------------------------------------------
630// Details: The invoker requires this function. The command prepares a MI Record Result
631//          for the work carried out in the Execute().
632// Type:    Overridden.
633// Args:    None.
634// Return:  MIstatus::success - Functional succeeded.
635//          MIstatus::failure - Functional failed.
636// Throws:  None.
637//--
638bool
639CMICmdCmdDataReadMemoryBytes::Acknowledge()
640{
641    // MI: memory=[{begin=\"0x%016" PRIx64 "\",offset=\"0x%016" PRIx64" \",end=\"0x%016" PRIx64 "\",contents=\" \" }]"
642    const CMICmnMIValueConst miValueConst(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart));
643    const CMICmnMIValueResult miValueResult("begin", miValueConst);
644    CMICmnMIValueTuple miValueTuple(miValueResult);
645    const MIuint64 nAddrOffset = 0;
646    const CMICmnMIValueConst miValueConst2(CMIUtilString::Format("0x%016" PRIx64, nAddrOffset));
647    const CMICmnMIValueResult miValueResult2("offset", miValueConst2);
648    miValueTuple.Add(miValueResult2);
649    const CMICmnMIValueConst miValueConst3(CMIUtilString::Format("0x%016" PRIx64, m_nAddrStart + m_nAddrNumBytesToRead));
650    const CMICmnMIValueResult miValueResult3("end", miValueConst3);
651    miValueTuple.Add(miValueResult3);
652
653    // MI: contents=\" \"
654    CMIUtilString strContent;
655    strContent.reserve((m_nAddrNumBytesToRead << 1) + 1);
656    for (MIuint64 i = 0; i < m_nAddrNumBytesToRead; i++)
657    {
658        strContent += CMIUtilString::Format("%02hhx", m_pBufferMemory[i]);
659    }
660    const CMICmnMIValueConst miValueConst4(strContent);
661    const CMICmnMIValueResult miValueResult4("contents", miValueConst4);
662    miValueTuple.Add(miValueResult4);
663    const CMICmnMIValueList miValueList(miValueTuple);
664    const CMICmnMIValueResult miValueResult5("memory", miValueList);
665
666    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult5);
667    m_miResultRecord = miRecordResult;
668
669    return MIstatus::success;
670}
671
672//++ ------------------------------------------------------------------------------------
673// Details: Required by the CMICmdFactory when registering *this command. The factory
674//          calls this function to create an instance of *this command.
675// Type:    Static method.
676// Args:    None.
677// Return:  CMICmdBase * - Pointer to a new command.
678// Throws:  None.
679//--
680CMICmdBase *
681CMICmdCmdDataReadMemoryBytes::CreateSelf()
682{
683    return new CMICmdCmdDataReadMemoryBytes();
684}
685
686//---------------------------------------------------------------------------------------
687//---------------------------------------------------------------------------------------
688//---------------------------------------------------------------------------------------
689
690//++ ------------------------------------------------------------------------------------
691// Details: CMICmdCmdDataReadMemory constructor.
692// Type:    Method.
693// Args:    None.
694// Return:  None.
695// Throws:  None.
696//--
697CMICmdCmdDataReadMemory::CMICmdCmdDataReadMemory()
698{
699    // Command factory matches this name with that received from the stdin stream
700    m_strMiCmd = "data-read-memory";
701
702    // Required by the CMICmdFactory when registering *this command
703    m_pSelfCreatorFn = &CMICmdCmdDataReadMemory::CreateSelf;
704}
705
706//++ ------------------------------------------------------------------------------------
707// Details: CMICmdCmdDataReadMemory destructor.
708// Type:    Overrideable.
709// Args:    None.
710// Return:  None.
711// Throws:  None.
712//--
713CMICmdCmdDataReadMemory::~CMICmdCmdDataReadMemory()
714{
715}
716
717//++ ------------------------------------------------------------------------------------
718// Details: The invoker requires this function. The command does work in this function.
719//          The command is likely to communicate with the LLDB SBDebugger in here.
720// Type:    Overridden.
721// Args:    None.
722// Return:  MIstatus::success - Functional succeeded.
723//          MIstatus::failure - Functional failed.
724// Throws:  None.
725//--
726bool
727CMICmdCmdDataReadMemory::Execute()
728{
729    // Do nothing - command deprecated use "data-read-memory-bytes" command
730    return MIstatus::success;
731}
732
733//++ ------------------------------------------------------------------------------------
734// Details: The invoker requires this function. The command prepares a MI Record Result
735//          for the work carried out in the Execute().
736// Type:    Overridden.
737// Args:    None.
738// Return:  MIstatus::success - Functional succeeded.
739//          MIstatus::failure - Functional failed.
740// Throws:  None.
741//--
742bool
743CMICmdCmdDataReadMemory::Acknowledge()
744{
745    // Command CMICmdCmdSupportListFeatures sends "data-read-memory-bytes" which causes this command not to be called
746    const CMICmnMIValueConst miValueConst(MIRSRC(IDS_CMD_ERR_NOT_IMPLEMENTED_DEPRECATED));
747    const CMICmnMIValueResult miValueResult("msg", miValueConst);
748    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
749    m_miResultRecord = miRecordResult;
750
751    return MIstatus::success;
752}
753
754//++ ------------------------------------------------------------------------------------
755// Details: Required by the CMICmdFactory when registering *this command. The factory
756//          calls this function to create an instance of *this command.
757// Type:    Static method.
758// Args:    None.
759// Return:  CMICmdBase * - Pointer to a new command.
760// Throws:  None.
761//--
762CMICmdBase *
763CMICmdCmdDataReadMemory::CreateSelf()
764{
765    return new CMICmdCmdDataReadMemory();
766}
767
768//---------------------------------------------------------------------------------------
769//---------------------------------------------------------------------------------------
770//---------------------------------------------------------------------------------------
771
772//++ ------------------------------------------------------------------------------------
773// Details: CMICmdCmdDataListRegisterNames constructor.
774// Type:    Method.
775// Args:    None.
776// Return:  None.
777// Throws:  None.
778//--
779CMICmdCmdDataListRegisterNames::CMICmdCmdDataListRegisterNames()
780    : m_constStrArgRegNo("regno")
781    , m_miValueList(true)
782{
783    // Command factory matches this name with that received from the stdin stream
784    m_strMiCmd = "data-list-register-names";
785
786    // Required by the CMICmdFactory when registering *this command
787    m_pSelfCreatorFn = &CMICmdCmdDataListRegisterNames::CreateSelf;
788}
789
790//++ ------------------------------------------------------------------------------------
791// Details: CMICmdCmdDataReadMemoryBytes destructor.
792// Type:    Overrideable.
793// Args:    None.
794// Return:  None.
795// Throws:  None.
796//--
797CMICmdCmdDataListRegisterNames::~CMICmdCmdDataListRegisterNames()
798{
799}
800
801//++ ------------------------------------------------------------------------------------
802// Details: The invoker requires this function. The parses the command line options
803//          arguments to extract values for each of those arguments.
804// Type:    Overridden.
805// Args:    None.
806// Return:  MIstatus::success - Functional succeeded.
807//          MIstatus::failure - Functional failed.
808// Throws:  None.
809//--
810bool
811CMICmdCmdDataListRegisterNames::ParseArgs()
812{
813    m_setCmdArgs.Add(new CMICmdArgValListOfN(m_constStrArgRegNo, false, false, CMICmdArgValListBase::eArgValType_Number));
814    return ParseValidateCmdOptions();
815}
816
817//++ ------------------------------------------------------------------------------------
818// Details: The invoker requires this function. The command does work in this function.
819//          The command is likely to communicate with the LLDB SBDebugger in here.
820// Type:    Overridden.
821// Args:    None.
822// Return:  MIstatus::success - Functional succeeded.
823//          MIstatus::failure - Functional failed.
824// Throws:  None.
825//--
826bool
827CMICmdCmdDataListRegisterNames::Execute()
828{
829    CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo);
830
831    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
832    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
833    if (!sbProcess.IsValid())
834    {
835        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
836        return MIstatus::failure;
837    }
838
839    const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions());
840    if (!rVecRegNo.empty())
841    {
842        // List of required registers
843        CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
844        while (it != rVecRegNo.end())
845        {
846            const CMICmdArgValNumber *pRegNo = static_cast<CMICmdArgValNumber *>(*it);
847            const MIuint nRegIndex = pRegNo->GetValue();
848            lldb::SBValue regValue = GetRegister(nRegIndex);
849            if (regValue.IsValid())
850            {
851                const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName());
852                m_miValueList.Add(miValueConst);
853            }
854
855            // Next
856            ++it;
857        }
858    }
859    else
860    {
861        // List of all registers
862        lldb::SBThread thread = sbProcess.GetSelectedThread();
863        lldb::SBFrame frame = thread.GetSelectedFrame();
864        lldb::SBValueList registers = frame.GetRegisters();
865        const MIuint nRegisters = registers.GetSize();
866        for (MIuint i = 0; i < nRegisters; i++)
867        {
868            lldb::SBValue value = registers.GetValueAtIndex(i);
869            const MIuint nRegChildren = value.GetNumChildren();
870            for (MIuint j = 0; j < nRegChildren; j++)
871            {
872                lldb::SBValue regValue = value.GetChildAtIndex(j);
873                if (regValue.IsValid())
874                {
875                    const CMICmnMIValueConst miValueConst(CMICmnLLDBUtilSBValue(regValue).GetName());
876                    m_miValueList.Add(miValueConst);
877                }
878            }
879        }
880    }
881
882    return MIstatus::success;
883}
884
885//++ ------------------------------------------------------------------------------------
886// Details: The invoker requires this function. The command prepares a MI Record Result
887//          for the work carried out in the Execute().
888// Type:    Overridden.
889// Args:    None.
890// Return:  MIstatus::success - Functional succeeded.
891//          MIstatus::failure - Functional failed.
892// Throws:  None.
893//--
894bool
895CMICmdCmdDataListRegisterNames::Acknowledge()
896{
897    const CMICmnMIValueResult miValueResult("register-names", m_miValueList);
898    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
899    m_miResultRecord = miRecordResult;
900
901    return MIstatus::success;
902}
903
904//++ ------------------------------------------------------------------------------------
905// Details: Required by the CMICmdFactory when registering *this command. The factory
906//          calls this function to create an instance of *this command.
907// Type:    Static method.
908// Args:    None.
909// Return:  CMICmdBase * - Pointer to a new command.
910// Throws:  None.
911//--
912CMICmdBase *
913CMICmdCmdDataListRegisterNames::CreateSelf()
914{
915    return new CMICmdCmdDataListRegisterNames();
916}
917
918//++ ------------------------------------------------------------------------------------
919// Details: Required by the CMICmdFactory when registering *this command. The factory
920//          calls this function to create an instance of *this command.
921// Type:    Method.
922// Args:    None.
923// Return:  lldb::SBValue - LLDB SBValue object.
924// Throws:  None.
925//--
926lldb::SBValue
927CMICmdCmdDataListRegisterNames::GetRegister(const MIuint vRegisterIndex) const
928{
929    lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread();
930    lldb::SBFrame frame = thread.GetSelectedFrame();
931    lldb::SBValueList registers = frame.GetRegisters();
932    const MIuint nRegisters = registers.GetSize();
933    MIuint nRegisterIndex(vRegisterIndex);
934    for (MIuint i = 0; i < nRegisters; i++)
935    {
936        lldb::SBValue value = registers.GetValueAtIndex(i);
937        const MIuint nRegChildren = value.GetNumChildren();
938        if (nRegisterIndex >= nRegChildren)
939        {
940            nRegisterIndex -= nRegChildren;
941            continue;
942        }
943
944        lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex);
945        if (value2.IsValid())
946        {
947            return value2;
948        }
949    }
950
951    return lldb::SBValue();
952}
953
954//---------------------------------------------------------------------------------------
955//---------------------------------------------------------------------------------------
956//---------------------------------------------------------------------------------------
957
958//++ ------------------------------------------------------------------------------------
959// Details: CMICmdCmdDataListRegisterValues constructor.
960// Type:    Method.
961// Args:    None.
962// Return:  None.
963// Throws:  None.
964//--
965CMICmdCmdDataListRegisterValues::CMICmdCmdDataListRegisterValues()
966    : m_constStrArgSkip("skip-unavailable")
967    , m_constStrArgFormat("fmt")
968    , m_constStrArgRegNo("regno")
969    , m_miValueList(true)
970{
971    // Command factory matches this name with that received from the stdin stream
972    m_strMiCmd = "data-list-register-values";
973
974    // Required by the CMICmdFactory when registering *this command
975    m_pSelfCreatorFn = &CMICmdCmdDataListRegisterValues::CreateSelf;
976}
977
978//++ ------------------------------------------------------------------------------------
979// Details: CMICmdCmdDataListRegisterValues destructor.
980// Type:    Overrideable.
981// Args:    None.
982// Return:  None.
983// Throws:  None.
984//--
985CMICmdCmdDataListRegisterValues::~CMICmdCmdDataListRegisterValues()
986{
987}
988
989//++ ------------------------------------------------------------------------------------
990// Details: The invoker requires this function. The parses the command line options
991//          arguments to extract values for each of those arguments.
992// Type:    Overridden.
993// Args:    None.
994// Return:  MIstatus::success - Functional succeeded.
995//          MIstatus::failure - Functional failed.
996// Throws:  None.
997//--
998bool
999CMICmdCmdDataListRegisterValues::ParseArgs()
1000{
1001    m_setCmdArgs.Add(new CMICmdArgValOptionLong(m_constStrArgThread, false, false, CMICmdArgValListBase::eArgValType_Number, 1));
1002    m_setCmdArgs.Add(new CMICmdArgValOptionLong(m_constStrArgSkip, false, false));
1003    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgFormat, true, true));
1004    m_setCmdArgs.Add(new CMICmdArgValListOfN(m_constStrArgRegNo, false, true, CMICmdArgValListBase::eArgValType_Number));
1005    return ParseValidateCmdOptions();
1006}
1007
1008//++ ------------------------------------------------------------------------------------
1009// Details: The invoker requires this function. The command does work in this function.
1010//          The command is likely to communicate with the LLDB SBDebugger in here.
1011// Type:    Overridden.
1012// Args:    None.
1013// Return:  MIstatus::success - Functional succeeded.
1014//          MIstatus::failure - Functional failed.
1015// Throws:  None.
1016//--
1017bool
1018CMICmdCmdDataListRegisterValues::Execute()
1019{
1020    CMICMDBASE_GETOPTION(pArgFormat, String, m_constStrArgFormat);
1021    CMICMDBASE_GETOPTION(pArgRegNo, ListOfN, m_constStrArgRegNo);
1022
1023    const CMIUtilString &rStrFormat(pArgFormat->GetValue());
1024    if (rStrFormat.length() != 1)
1025    {
1026        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str()));
1027        return MIstatus::failure;
1028    }
1029    const CMICmnLLDBDebugSessionInfoVarObj::varFormat_e eFormat = CMICmnLLDBDebugSessionInfoVarObj::GetVarFormatForChar(rStrFormat[0]);
1030    if (eFormat == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid)
1031    {
1032        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_FORMAT_TYPE), m_cmdData.strMiCmd.c_str(), rStrFormat.c_str()));
1033        return MIstatus::failure;
1034    }
1035
1036    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
1037    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
1038    if (!sbProcess.IsValid())
1039    {
1040        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PROCESS), m_cmdData.strMiCmd.c_str()));
1041        return MIstatus::failure;
1042    }
1043
1044    const CMICmdArgValListBase::VecArgObjPtr_t &rVecRegNo(pArgRegNo->GetExpectedOptions());
1045    if (!rVecRegNo.empty())
1046    {
1047        // List of required registers
1048        CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecRegNo.begin();
1049        while (it != rVecRegNo.end())
1050        {
1051            const CMICmdArgValNumber *pRegNo = static_cast<CMICmdArgValNumber *>(*it);
1052            const MIuint nRegIndex = pRegNo->GetValue();
1053            lldb::SBValue regValue = GetRegister(nRegIndex);
1054            if (regValue.IsValid())
1055            {
1056                AddToOutput(nRegIndex, regValue, eFormat);
1057            }
1058
1059            // Next
1060            ++it;
1061        }
1062    }
1063    else
1064    {
1065        // No register numbers are provided. Output all registers.
1066        lldb::SBThread thread = sbProcess.GetSelectedThread();
1067        lldb::SBFrame frame = thread.GetSelectedFrame();
1068        lldb::SBValueList registers = frame.GetRegisters();
1069        const MIuint nRegisters = registers.GetSize();
1070        MIuint nRegIndex = 0;
1071        for (MIuint i = 0; i < nRegisters; i++)
1072        {
1073            lldb::SBValue value = registers.GetValueAtIndex(i);
1074            const MIuint nRegChildren = value.GetNumChildren();
1075            for (MIuint j = 0; j < nRegChildren; j++)
1076            {
1077                lldb::SBValue regValue = value.GetChildAtIndex(j);
1078                if (regValue.IsValid())
1079                {
1080                    AddToOutput(nRegIndex, regValue, eFormat);
1081                }
1082
1083                // Next
1084                ++nRegIndex;
1085            }
1086        }
1087    }
1088
1089    return MIstatus::success;
1090}
1091
1092//++ ------------------------------------------------------------------------------------
1093// Details: The invoker requires this function. The command prepares a MI Record Result
1094//          for the work carried out in the Execute().
1095// Type:    Overridden.
1096// Args:    None.
1097// Return:  MIstatus::success - Functional succeeded.
1098//          MIstatus::failure - Functional failed.
1099// Throws:  None.
1100//--
1101bool
1102CMICmdCmdDataListRegisterValues::Acknowledge()
1103{
1104    const CMICmnMIValueResult miValueResult("register-values", m_miValueList);
1105    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
1106    m_miResultRecord = miRecordResult;
1107
1108    return MIstatus::success;
1109}
1110
1111//++ ------------------------------------------------------------------------------------
1112// Details: Required by the CMICmdFactory when registering *this command. The factory
1113//          calls this function to create an instance of *this command.
1114// Type:    Static method.
1115// Args:    None.
1116// Return:  CMICmdBase * - Pointer to a new command.
1117// Throws:  None.
1118//--
1119CMICmdBase *
1120CMICmdCmdDataListRegisterValues::CreateSelf()
1121{
1122    return new CMICmdCmdDataListRegisterValues();
1123}
1124
1125//++ ------------------------------------------------------------------------------------
1126// Details: Required by the CMICmdFactory when registering *this command. The factory
1127//          calls this function to create an instance of *this command.
1128// Type:    Method.
1129// Args:    None.
1130// Return:  lldb::SBValue - LLDB SBValue object.
1131// Throws:  None.
1132//--
1133lldb::SBValue
1134CMICmdCmdDataListRegisterValues::GetRegister(const MIuint vRegisterIndex) const
1135{
1136    lldb::SBThread thread = CMICmnLLDBDebugSessionInfo::Instance().GetProcess().GetSelectedThread();
1137    lldb::SBFrame frame = thread.GetSelectedFrame();
1138    lldb::SBValueList registers = frame.GetRegisters();
1139    const MIuint nRegisters = registers.GetSize();
1140    MIuint nRegisterIndex(vRegisterIndex);
1141    for (MIuint i = 0; i < nRegisters; i++)
1142    {
1143        lldb::SBValue value = registers.GetValueAtIndex(i);
1144        const MIuint nRegChildren = value.GetNumChildren();
1145        if (nRegisterIndex >= nRegChildren)
1146        {
1147            nRegisterIndex -= nRegChildren;
1148            continue;
1149        }
1150
1151        lldb::SBValue value2 = value.GetChildAtIndex(nRegisterIndex);
1152        if (value2.IsValid())
1153        {
1154            return value2;
1155        }
1156    }
1157
1158    return lldb::SBValue();
1159}
1160
1161//++ ------------------------------------------------------------------------------------
1162// Details: Adds the register value to the output list.
1163// Type:    Method.
1164// Args:    Value of the register, its index and output format.
1165// Return:  None
1166// Throws:  None.
1167//--
1168void
1169CMICmdCmdDataListRegisterValues::AddToOutput(const MIuint vnIndex, const lldb::SBValue &vrValue,
1170	    CMICmnLLDBDebugSessionInfoVarObj::varFormat_e veVarFormat)
1171{
1172    const CMICmnMIValueConst miValueConst(CMIUtilString::Format("%u", vnIndex));
1173    const CMICmnMIValueResult miValueResult("number", miValueConst);
1174    CMICmnMIValueTuple miValueTuple(miValueResult);
1175    const CMIUtilString strRegValue(CMICmnLLDBDebugSessionInfoVarObj::GetValueStringFormatted(vrValue, veVarFormat));
1176    const CMICmnMIValueConst miValueConst2(strRegValue);
1177    const CMICmnMIValueResult miValueResult2("value", miValueConst2);
1178    miValueTuple.Add(miValueResult2);
1179    m_miValueList.Add(miValueTuple);
1180}
1181
1182//---------------------------------------------------------------------------------------
1183//---------------------------------------------------------------------------------------
1184//---------------------------------------------------------------------------------------
1185
1186//++ ------------------------------------------------------------------------------------
1187// Details: CMICmdCmdDataListRegisterChanged constructor.
1188// Type:    Method.
1189// Args:    None.
1190// Return:  None.
1191// Throws:  None.
1192//--
1193CMICmdCmdDataListRegisterChanged::CMICmdCmdDataListRegisterChanged()
1194{
1195    // Command factory matches this name with that received from the stdin stream
1196    m_strMiCmd = "data-list-changed-registers";
1197
1198    // Required by the CMICmdFactory when registering *this command
1199    m_pSelfCreatorFn = &CMICmdCmdDataListRegisterChanged::CreateSelf;
1200}
1201
1202//++ ------------------------------------------------------------------------------------
1203// Details: CMICmdCmdDataListRegisterChanged destructor.
1204// Type:    Overrideable.
1205// Args:    None.
1206// Return:  None.
1207// Throws:  None.
1208//--
1209CMICmdCmdDataListRegisterChanged::~CMICmdCmdDataListRegisterChanged()
1210{
1211}
1212
1213//++ ------------------------------------------------------------------------------------
1214// Details: The invoker requires this function. The command does work in this function.
1215//          The command is likely to communicate with the LLDB SBDebugger in here.
1216// Type:    Overridden.
1217// Args:    None.
1218// Return:  MIstatus::success - Functional succeeded.
1219//          MIstatus::failure - Functional failed.
1220// Throws:  None.
1221//--
1222bool
1223CMICmdCmdDataListRegisterChanged::Execute()
1224{
1225    // Do nothing
1226
1227    return MIstatus::success;
1228}
1229
1230//++ ------------------------------------------------------------------------------------
1231// Details: The invoker requires this function. The command prepares a MI Record Result
1232//          for the work carried out in the Execute().
1233// Type:    Overridden.
1234// Args:    None.
1235// Return:  MIstatus::success - Functional succeeded.
1236//          MIstatus::failure - Functional failed.
1237// Throws:  None.
1238//--
1239bool
1240CMICmdCmdDataListRegisterChanged::Acknowledge()
1241{
1242    const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED));
1243    const CMICmnMIValueResult miValueResult("msg", miValueConst);
1244    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
1245    m_miResultRecord = miRecordResult;
1246
1247    return MIstatus::success;
1248}
1249
1250//++ ------------------------------------------------------------------------------------
1251// Details: Required by the CMICmdFactory when registering *this command. The factory
1252//          calls this function to create an instance of *this command.
1253// Type:    Static method.
1254// Args:    None.
1255// Return:  CMICmdBase * - Pointer to a new command.
1256// Throws:  None.
1257//--
1258CMICmdBase *
1259CMICmdCmdDataListRegisterChanged::CreateSelf()
1260{
1261    return new CMICmdCmdDataListRegisterChanged();
1262}
1263
1264//---------------------------------------------------------------------------------------
1265//---------------------------------------------------------------------------------------
1266//---------------------------------------------------------------------------------------
1267
1268//++ ------------------------------------------------------------------------------------
1269// Details: CMICmdCmdDataWriteMemoryBytes constructor.
1270// Type:    Method.
1271// Args:    None.
1272// Return:  None.
1273// Throws:  None.
1274//--
1275CMICmdCmdDataWriteMemoryBytes::CMICmdCmdDataWriteMemoryBytes()
1276    : m_constStrArgAddr("address")
1277    , m_constStrArgContents("contents")
1278    , m_constStrArgCount("count")
1279{
1280    // Command factory matches this name with that received from the stdin stream
1281    m_strMiCmd = "data-write-memory-bytes";
1282
1283    // Required by the CMICmdFactory when registering *this command
1284    m_pSelfCreatorFn = &CMICmdCmdDataWriteMemoryBytes::CreateSelf;
1285}
1286
1287//++ ------------------------------------------------------------------------------------
1288// Details: CMICmdCmdDataWriteMemoryBytes destructor.
1289// Type:    Overrideable.
1290// Args:    None.
1291// Return:  None.
1292// Throws:  None.
1293//--
1294CMICmdCmdDataWriteMemoryBytes::~CMICmdCmdDataWriteMemoryBytes()
1295{
1296}
1297
1298//++ ------------------------------------------------------------------------------------
1299// Details: The invoker requires this function. The parses the command line options
1300//          arguments to extract values for each of those arguments.
1301// Type:    Overridden.
1302// Args:    None.
1303// Return:  MIstatus::success - Functional succeeded.
1304//          MIstatus::failure - Functional failed.
1305// Throws:  None.
1306//--
1307bool
1308CMICmdCmdDataWriteMemoryBytes::ParseArgs()
1309{
1310    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgAddr, true, true, false, true));
1311    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgContents, true, true, true, true));
1312    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgCount, false, true, false, true));
1313    return ParseValidateCmdOptions();
1314}
1315
1316//++ ------------------------------------------------------------------------------------
1317// Details: The invoker requires this function. The command does work in this function.
1318//          The command is likely to communicate with the LLDB SBDebugger in here.
1319// Type:    Overridden.
1320// Args:    None.
1321// Return:  MIstatus::success - Functional succeeded.
1322//          MIstatus::failure - Functional failed.
1323// Throws:  None.
1324//--
1325bool
1326CMICmdCmdDataWriteMemoryBytes::Execute()
1327{
1328    // Do nothing - not reproduceable (yet) in Eclipse
1329    // CMICMDBASE_GETOPTION( pArgOffset, OptionShort, m_constStrArgOffset );
1330    // CMICMDBASE_GETOPTION( pArgAddr, String, m_constStrArgAddr );
1331    // CMICMDBASE_GETOPTION( pArgNumber, String, m_constStrArgNumber );
1332    // CMICMDBASE_GETOPTION( pArgContents, String, m_constStrArgContents );
1333    //
1334    // Numbers extracts as string types as they could be hex numbers
1335    // '&' is not recognised and so has to be removed
1336
1337    return MIstatus::success;
1338}
1339
1340//++ ------------------------------------------------------------------------------------
1341// Details: The invoker requires this function. The command prepares a MI Record Result
1342//          for the work carried out in the Execute().
1343// Type:    Overridden.
1344// Args:    None.
1345// Return:  MIstatus::success - Functional succeeded.
1346//          MIstatus::failure - Functional failed.
1347// Throws:  None.
1348//--
1349bool
1350CMICmdCmdDataWriteMemoryBytes::Acknowledge()
1351{
1352    const CMICmnMIValueConst miValueConst(MIRSRC(IDS_WORD_NOT_IMPLEMENTED));
1353    const CMICmnMIValueResult miValueResult("msg", miValueConst);
1354    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
1355    m_miResultRecord = miRecordResult;
1356
1357    return MIstatus::success;
1358}
1359
1360//++ ------------------------------------------------------------------------------------
1361// Details: Required by the CMICmdFactory when registering *this command. The factory
1362//          calls this function to create an instance of *this command.
1363// Type:    Static method.
1364// Args:    None.
1365// Return:  CMICmdBase * - Pointer to a new command.
1366// Throws:  None.
1367//--
1368CMICmdBase *
1369CMICmdCmdDataWriteMemoryBytes::CreateSelf()
1370{
1371    return new CMICmdCmdDataWriteMemoryBytes();
1372}
1373
1374//---------------------------------------------------------------------------------------
1375//---------------------------------------------------------------------------------------
1376//---------------------------------------------------------------------------------------
1377
1378//++ ------------------------------------------------------------------------------------
1379// Details: CMICmdCmdDataWriteMemory constructor.
1380// Type:    Method.
1381// Args:    None.
1382// Return:  None.
1383// Throws:  None.
1384//--
1385CMICmdCmdDataWriteMemory::CMICmdCmdDataWriteMemory()
1386    : m_constStrArgOffset("o")
1387    , m_constStrArgAddr("address")
1388    , m_constStrArgD("d")
1389    , m_constStrArgNumber("a number")
1390    , m_constStrArgContents("contents")
1391    , m_nAddr(0)
1392    , m_nCount(0)
1393    , m_pBufferMemory(nullptr)
1394{
1395    // Command factory matches this name with that received from the stdin stream
1396    m_strMiCmd = "data-write-memory";
1397
1398    // Required by the CMICmdFactory when registering *this command
1399    m_pSelfCreatorFn = &CMICmdCmdDataWriteMemory::CreateSelf;
1400}
1401
1402//++ ------------------------------------------------------------------------------------
1403// Details: CMICmdCmdDataWriteMemory destructor.
1404// Type:    Overrideable.
1405// Args:    None.
1406// Return:  None.
1407// Throws:  None.
1408//--
1409CMICmdCmdDataWriteMemory::~CMICmdCmdDataWriteMemory()
1410{
1411    if (m_pBufferMemory != nullptr)
1412    {
1413        delete[] m_pBufferMemory;
1414        m_pBufferMemory = nullptr;
1415    }
1416}
1417
1418//++ ------------------------------------------------------------------------------------
1419// Details: The invoker requires this function. The parses the command line options
1420//          arguments to extract values for each of those arguments.
1421// Type:    Overridden.
1422// Args:    None.
1423// Return:  MIstatus::success - Functional succeeded.
1424//          MIstatus::failure - Functional failed.
1425// Throws:  None.
1426//--
1427bool
1428CMICmdCmdDataWriteMemory::ParseArgs()
1429{
1430    m_setCmdArgs.Add(new CMICmdArgValOptionShort(m_constStrArgOffset, false, true, CMICmdArgValListBase::eArgValType_Number, 1));
1431    m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgAddr, true, true));
1432    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgD, true, true));
1433    m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgNumber, true, true));
1434    m_setCmdArgs.Add(new CMICmdArgValNumber(m_constStrArgContents, true, true));
1435    return ParseValidateCmdOptions();
1436}
1437
1438//++ ------------------------------------------------------------------------------------
1439// Details: The invoker requires this function. The command does work in this function.
1440//          The command is likely to communicate with the LLDB SBDebugger in here.
1441// Type:    Overridden.
1442// Args:    None.
1443// Return:  MIstatus::success - Functional succeeded.
1444//          MIstatus::failure - Functional failed.
1445// Throws:  None.
1446//--
1447bool
1448CMICmdCmdDataWriteMemory::Execute()
1449{
1450    CMICMDBASE_GETOPTION(pArgOffset, OptionShort, m_constStrArgOffset);
1451    CMICMDBASE_GETOPTION(pArgAddr, Number, m_constStrArgAddr);
1452    CMICMDBASE_GETOPTION(pArgNumber, Number, m_constStrArgNumber);
1453    CMICMDBASE_GETOPTION(pArgContents, Number, m_constStrArgContents);
1454
1455    MIuint nAddrOffset = 0;
1456    if (pArgOffset->GetFound() && !pArgOffset->GetExpectedOption<CMICmdArgValNumber, MIuint>(nAddrOffset))
1457    {
1458        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_INVALID), m_cmdData.strMiCmd.c_str(), m_constStrArgAddr.c_str()));
1459        return MIstatus::failure;
1460    }
1461    m_nAddr = pArgAddr->GetValue();
1462    m_nCount = pArgNumber->GetValue();
1463    const MIuint64 nValue = pArgContents->GetValue();
1464
1465    m_pBufferMemory = new unsigned char[m_nCount];
1466    if (m_pBufferMemory == nullptr)
1467    {
1468        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_MEMORY_ALLOC_FAILURE), m_cmdData.strMiCmd.c_str(), m_nCount));
1469        return MIstatus::failure;
1470    }
1471    *m_pBufferMemory = static_cast<char>(nValue);
1472
1473    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
1474    lldb::SBProcess sbProcess = rSessionInfo.GetProcess();
1475    lldb::SBError error;
1476    lldb::addr_t addr = static_cast<lldb::addr_t>(m_nAddr + nAddrOffset);
1477    const size_t nBytesWritten = sbProcess.WriteMemory(addr, (const void *)m_pBufferMemory, (size_t)m_nCount, error);
1478    if (nBytesWritten != static_cast<size_t>(m_nCount))
1479    {
1480        SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_NOT_WRITE_WHOLEBLK), m_cmdData.strMiCmd.c_str(), m_nCount, addr));
1481        return MIstatus::failure;
1482    }
1483    if (error.Fail())
1484    {
1485        lldb::SBStream err;
1486        const bool bOk = error.GetDescription(err);
1487        MIunused(bOk);
1488        SetError(
1489            CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_LLDB_ERR_WRITE_MEM_BYTES), m_cmdData.strMiCmd.c_str(), m_nCount, addr, err.GetData()));
1490        return MIstatus::failure;
1491    }
1492
1493    return MIstatus::success;
1494}
1495
1496//++ ------------------------------------------------------------------------------------
1497// Details: The invoker requires this function. The command prepares a MI Record Result
1498//          for the work carried out in the Execute().
1499// Type:    Overridden.
1500// Args:    None.
1501// Return:  MIstatus::success - Functional succeeded.
1502//          MIstatus::failure - Functional failed.
1503// Throws:  None.
1504//--
1505bool
1506CMICmdCmdDataWriteMemory::Acknowledge()
1507{
1508    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
1509    m_miResultRecord = miRecordResult;
1510
1511    return MIstatus::success;
1512}
1513
1514//++ ------------------------------------------------------------------------------------
1515// Details: Required by the CMICmdFactory when registering *this command. The factory
1516//          calls this function to create an instance of *this command.
1517// Type:    Static method.
1518// Args:    None.
1519// Return:  CMICmdBase * - Pointer to a new command.
1520// Throws:  None.
1521//--
1522CMICmdBase *
1523CMICmdCmdDataWriteMemory::CreateSelf()
1524{
1525    return new CMICmdCmdDataWriteMemory();
1526}
1527
1528//---------------------------------------------------------------------------------------
1529//---------------------------------------------------------------------------------------
1530//---------------------------------------------------------------------------------------
1531
1532//++ ------------------------------------------------------------------------------------
1533// Details: CMICmdCmdDataInfoLine constructor.
1534// Type:    Method.
1535// Args:    None.
1536// Return:  None.
1537// Throws:  None.
1538//--
1539CMICmdCmdDataInfoLine::CMICmdCmdDataInfoLine()
1540    : m_constStrArgLocation("location")
1541{
1542    // Command factory matches this name with that received from the stdin stream
1543    m_strMiCmd = "data-info-line";
1544
1545    // Required by the CMICmdFactory when registering *this command
1546    m_pSelfCreatorFn = &CMICmdCmdDataInfoLine::CreateSelf;
1547}
1548
1549//++ ------------------------------------------------------------------------------------
1550// Details: CMICmdCmdDataInfoLine destructor.
1551// Type:    Overrideable.
1552// Args:    None.
1553// Return:  None.
1554// Throws:  None.
1555//--
1556CMICmdCmdDataInfoLine::~CMICmdCmdDataInfoLine()
1557{
1558}
1559
1560//++ ------------------------------------------------------------------------------------
1561// Details: The invoker requires this function. The parses the command line options
1562//          arguments to extract values for each of those arguments.
1563// Type:    Overridden.
1564// Args:    None.
1565// Return:  MIstatus::success - Functional succeeded.
1566//          MIstatus::failure - Functional failed.
1567// Throws:  None.
1568//--
1569bool
1570CMICmdCmdDataInfoLine::ParseArgs()
1571{
1572    m_setCmdArgs.Add(new CMICmdArgValString(m_constStrArgLocation, true, true));
1573    return ParseValidateCmdOptions();
1574}
1575
1576//++ ------------------------------------------------------------------------------------
1577// Details: The invoker requires this function. The command does work in this function.
1578//          The command is likely to communicate with the LLDB SBDebugger in here.
1579// Type:    Overridden.
1580// Args:    None.
1581// Return:  MIstatus::success - Functional succeeded.
1582//          MIstatus::failure - Functional failed.
1583// Throws:  None.
1584//--
1585bool
1586CMICmdCmdDataInfoLine::Execute()
1587{
1588    CMICMDBASE_GETOPTION(pArgLocation, String, m_constStrArgLocation);
1589
1590    const CMIUtilString &strLocation(pArgLocation->GetValue());
1591    CMIUtilString strCmdOptionsLocation;
1592    if (strLocation.at(0) == '*')
1593    {
1594        // Parse argument:
1595        // *0x12345
1596        //  ^^^^^^^ -- address
1597        const CMIUtilString strAddress(strLocation.substr(1));
1598        strCmdOptionsLocation = CMIUtilString::Format("--address %s", strAddress.c_str());
1599    }
1600    else
1601    {
1602        const size_t nLineStartPos = strLocation.rfind(':');
1603        if ((nLineStartPos == std::string::npos) || (nLineStartPos == 0) || (nLineStartPos == strLocation.length() - 1))
1604        {
1605            SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_LOCATION_FORMAT), m_cmdData.strMiCmd.c_str(), strLocation.c_str())
1606                         .c_str());
1607            return MIstatus::failure;
1608        }
1609        // Parse argument:
1610        // hello.cpp:5
1611        // ^^^^^^^^^ -- file
1612        //           ^ -- line
1613        const CMIUtilString strFile(strLocation.substr(0, nLineStartPos));
1614        const CMIUtilString strLine(strLocation.substr(nLineStartPos + 1));
1615        strCmdOptionsLocation = CMIUtilString::Format("--file \"%s\" --line %s", strFile.AddSlashes().c_str(), strLine.c_str());
1616    }
1617    const CMIUtilString strCmd(CMIUtilString::Format("target modules lookup -v %s", strCmdOptionsLocation.c_str()));
1618
1619    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
1620    const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
1621    MIunused(rtn);
1622
1623    return MIstatus::success;
1624}
1625
1626//++ ------------------------------------------------------------------------------------
1627// Details: Helper function for parsing a line entry returned from lldb for the command:
1628//              target modules lookup -v <location>
1629//          where the line entry is of the format:
1630//              LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/file:3[:1]
1631//                           start              end                   file       line column(opt)
1632// Args:    input - (R) Input string to parse.
1633//          start - (W) String representing the start address.
1634//          end   - (W) String representing the end address.
1635//          file  - (W) String representing the file.
1636//          line  - (W) String representing the line.
1637// Return:  bool - True = input was parsed successfully, false = input could not be parsed.
1638// Throws:  None.
1639//--
1640static bool
1641ParseLLDBLineEntry(const char *input, CMIUtilString &start, CMIUtilString &end,
1642                   CMIUtilString &file, CMIUtilString &line)
1643{
1644    // Note: Ambiguities arise because the column is optional, and
1645    // because : can appear in filenames or as a byte in a multibyte
1646    // UTF8 character.  We keep those cases to a minimum by using regex
1647    // to work on the string from both the left and right, so that what
1648    // is remains is assumed to be the filename.
1649
1650    // Match LineEntry using regex.
1651    static MIUtilParse::CRegexParser g_lineentry_nocol_regex(
1652        "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$");
1653    static MIUtilParse::CRegexParser g_lineentry_col_regex(
1654        "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$");
1655        //                ^1=start         ^2=end               ^3=f ^4=line ^5=:col(opt)
1656
1657    MIUtilParse::CRegexParser::Match match(6);
1658
1659    // First try matching the LineEntry with the column,
1660    // then try without the column.
1661    const bool ok = g_lineentry_col_regex.Execute(input, match) ||
1662                    g_lineentry_nocol_regex.Execute(input, match);
1663    if (ok)
1664    {
1665        start = match.GetMatchAtIndex(1);
1666        end   = match.GetMatchAtIndex(2);
1667        file  = match.GetMatchAtIndex(3);
1668        line  = match.GetMatchAtIndex(4);
1669    }
1670    return ok;
1671}
1672
1673//++ ------------------------------------------------------------------------------------
1674// Details: The invoker requires this function. The command prepares a MI Record Result
1675//          for the work carried out in the Execute().
1676// Type:    Overridden.
1677// Args:    None.
1678// Return:  MIstatus::success - Functional succeeded.
1679//          MIstatus::failure - Functional failed.
1680// Throws:  None.
1681//--
1682bool
1683CMICmdCmdDataInfoLine::Acknowledge()
1684{
1685    if (m_lldbResult.GetErrorSize() > 0)
1686    {
1687        const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
1688        const CMICmnMIValueResult miValueResult("msg", miValueConst);
1689        const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
1690        m_miResultRecord = miRecordResult;
1691        return MIstatus::success;
1692    }
1693    else if (m_lldbResult.GetOutputSize() > 0)
1694    {
1695        CMIUtilString::VecString_t vecLines;
1696        const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
1697        const MIuint nLines(strLldbMsg.SplitLines(vecLines));
1698
1699        for (MIuint i = 0; i < nLines; ++i)
1700        {
1701            // String looks like:
1702            // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
1703            const CMIUtilString &rLine(vecLines[i]);
1704            CMIUtilString strStart;
1705            CMIUtilString strEnd;
1706            CMIUtilString strFile;
1707            CMIUtilString strLine;
1708
1709            if (!ParseLLDBLineEntry(rLine.c_str(), strStart, strEnd, strFile, strLine))
1710                continue;
1711
1712            const CMICmnMIValueConst miValueConst(strStart);
1713            const CMICmnMIValueResult miValueResult("start", miValueConst);
1714            CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken,
1715                                                CMICmnMIResultRecord::eResultClass_Done,
1716                                                miValueResult);
1717            const CMICmnMIValueConst miValueConst2(strEnd);
1718            const CMICmnMIValueResult miValueResult2("end", miValueConst2);
1719            miRecordResult.Add(miValueResult2);
1720            const CMICmnMIValueConst miValueConst3(strFile);
1721            const CMICmnMIValueResult miValueResult3("file", miValueConst3);
1722            miRecordResult.Add(miValueResult3);
1723            const CMICmnMIValueConst miValueConst4(strLine);
1724            const CMICmnMIValueResult miValueResult4("line", miValueConst4);
1725            miRecordResult.Add(miValueResult4);
1726
1727            // MI print "%s^done,start=\"%d\",end=\"%d\"",file=\"%s\",line=\"%d\"
1728            m_miResultRecord = miRecordResult;
1729
1730            return MIstatus::success;
1731        }
1732    }
1733
1734    // MI print "%s^error,msg=\"Command '-data-info-line'. Error: The LineEntry is absent or has an unknown format.\""
1735    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."));
1736    const CMICmnMIValueResult miValueResult("msg", miValueConst);
1737    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
1738    m_miResultRecord = miRecordResult;
1739
1740    return MIstatus::success;
1741}
1742
1743//++ ------------------------------------------------------------------------------------
1744// Details: Required by the CMICmdFactory when registering *this command. The factory
1745//          calls this function to create an instance of *this command.
1746// Type:    Static method.
1747// Args:    None.
1748// Return:  CMICmdBase * - Pointer to a new command.
1749// Throws:  None.
1750//--
1751CMICmdBase *
1752CMICmdCmdDataInfoLine::CreateSelf()
1753{
1754    return new CMICmdCmdDataInfoLine();
1755}
1756