1//===-- MICmdCmdGdbSet.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:    CMICmdCmdGdbSet implementation.
11
12// In-house headers:
13#include "MICmdCmdGdbSet.h"
14#include "MICmnMIResultRecord.h"
15#include "MICmnMIValueConst.h"
16#include "MICmdArgValString.h"
17#include "MICmdArgValListOfN.h"
18#include "MICmdArgValOptionLong.h"
19#include "MICmnLLDBDebugSessionInfo.h"
20
21// Instantiations:
22const CMICmdCmdGdbSet::MapGdbOptionNameToFnGdbOptionPtr_t CMICmdCmdGdbSet::ms_mapGdbOptionNameToFnGdbOptionPtr = {
23    {"target-async", &CMICmdCmdGdbSet::OptionFnTargetAsync},
24    {"print", &CMICmdCmdGdbSet::OptionFnPrint},
25    // { "auto-solib-add", &CMICmdCmdGdbSet::OptionFnAutoSolibAdd },    // Example code if need to implement GDB set other options
26    {"output-radix", &CMICmdCmdGdbSet::OptionFnOutputRadix},
27    {"solib-search-path", &CMICmdCmdGdbSet::OptionFnSolibSearchPath},
28    {"fallback", &CMICmdCmdGdbSet::OptionFnFallback}};
29
30//++ ------------------------------------------------------------------------------------
31// Details: CMICmdCmdGdbSet constructor.
32// Type:    Method.
33// Args:    None.
34// Return:  None.
35// Throws:  None.
36//--
37CMICmdCmdGdbSet::CMICmdCmdGdbSet()
38    : m_constStrArgNamedGdbOption("option")
39    , m_bGdbOptionRecognised(true)
40    , m_bGdbOptionFnSuccessful(false)
41    , m_bGbbOptionFnHasError(false)
42    , m_strGdbOptionFnError(MIRSRC(IDS_WORD_ERR_MSG_NOT_IMPLEMENTED_BRKTS))
43{
44    // Command factory matches this name with that received from the stdin stream
45    m_strMiCmd = "gdb-set";
46
47    // Required by the CMICmdFactory when registering *this command
48    m_pSelfCreatorFn = &CMICmdCmdGdbSet::CreateSelf;
49}
50
51//++ ------------------------------------------------------------------------------------
52// Details: CMICmdCmdGdbSet destructor.
53// Type:    Overrideable.
54// Args:    None.
55// Return:  None.
56// Throws:  None.
57//--
58CMICmdCmdGdbSet::~CMICmdCmdGdbSet()
59{
60}
61
62//++ ------------------------------------------------------------------------------------
63// Details: The invoker requires this function. The parses the command line options
64//          arguments to extract values for each of those arguments.
65// Type:    Overridden.
66// Args:    None.
67// Return:  MIstatus::success - Functional succeeded.
68//          MIstatus::failure - Functional failed.
69// Throws:  None.
70//--
71bool
72CMICmdCmdGdbSet::ParseArgs()
73{
74    m_setCmdArgs.Add(
75        new CMICmdArgValListOfN(m_constStrArgNamedGdbOption, true, true, CMICmdArgValListBase::eArgValType_StringAnything));
76    return ParseValidateCmdOptions();
77}
78
79//++ ------------------------------------------------------------------------------------
80// Details: The invoker requires this function. The command is executed in this function.
81//          The command is likely to communicate with the LLDB SBDebugger in here.
82// Type:    Overridden.
83// Args:    None.
84// Return:  MIstatus::success - Functional succeeded.
85//          MIstatus::failure - Functional failed.
86// Throws:  None.
87//--
88bool
89CMICmdCmdGdbSet::Execute()
90{
91    CMICMDBASE_GETOPTION(pArgGdbOption, ListOfN, m_constStrArgNamedGdbOption);
92    const CMICmdArgValListBase::VecArgObjPtr_t &rVecWords(pArgGdbOption->GetExpectedOptions());
93
94    // Get the gdb-set option to carry out. This option will be used as an action
95    // which should be done. Further arguments will be used as parameters for it.
96    CMICmdArgValListBase::VecArgObjPtr_t::const_iterator it = rVecWords.begin();
97    const CMICmdArgValString *pOption = static_cast<const CMICmdArgValString *>(*it);
98    const CMIUtilString strOption(pOption->GetValue());
99    ++it;
100
101    // Retrieve the parameter(s) for the option
102    CMIUtilString::VecString_t vecWords;
103    while (it != rVecWords.end())
104    {
105        const CMICmdArgValString *pWord = static_cast<const CMICmdArgValString *>(*it);
106        vecWords.push_back(pWord->GetValue());
107
108        // Next
109        ++it;
110    }
111
112    FnGdbOptionPtr pPrintRequestFn = nullptr;
113    if (!GetOptionFn(strOption, pPrintRequestFn))
114    {
115        // For unimplemented option handlers, fallback on a generic handler
116        // ToDo: Remove this when ALL options have been implemented
117        if (!GetOptionFn("fallback", pPrintRequestFn))
118        {
119            m_bGdbOptionRecognised = false;
120            m_strGdbOptionName = "fallback"; // This would be the strOption name
121            return MIstatus::success;
122        }
123    }
124
125    m_bGdbOptionFnSuccessful = (this->*(pPrintRequestFn))(vecWords);
126    if (!m_bGdbOptionFnSuccessful && !m_bGbbOptionFnHasError)
127        return MIstatus::failure;
128
129    return MIstatus::success;
130}
131
132//++ ------------------------------------------------------------------------------------
133// Details: The invoker requires this function. The command prepares a MI Record Result
134//          for the work carried out in the Execute() method.
135// Type:    Overridden.
136// Args:    None.
137// Return:  MIstatus::success - Functional succeeded.
138//          MIstatus::failure - Functional failed.
139// Throws:  None.
140//--
141bool
142CMICmdCmdGdbSet::Acknowledge()
143{
144    // Print error if option isn't recognized:
145    // ^error,msg="The request '%s' was not recognized, not implemented"
146    if (!m_bGdbOptionRecognised)
147    {
148        const CMICmnMIValueConst miValueConst(
149            CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_NOT_FOUND), m_strGdbOptionName.c_str()));
150        const CMICmnMIValueResult miValueResult("msg", miValueConst);
151        const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
152        m_miResultRecord = miRecordResult;
153        return MIstatus::success;
154    }
155
156    // ^done,value="%s"
157    if (m_bGdbOptionFnSuccessful)
158    {
159        const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done);
160        m_miResultRecord = miRecordResult;
161        return MIstatus::success;
162    }
163
164    // Print error if request failed:
165    // ^error,msg="The request '%s' failed.
166    const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INFO_PRINTFN_FAILED), m_strGdbOptionFnError.c_str()));
167    const CMICmnMIValueResult miValueResult("msg", miValueConst);
168    const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
169    m_miResultRecord = miRecordResult;
170
171    return MIstatus::success;
172}
173
174//++ ------------------------------------------------------------------------------------
175// Details: Required by the CMICmdFactory when registering *this command. The factory
176//          calls this function to create an instance of *this command.
177// Type:    Static method.
178// Args:    None.
179// Return:  CMICmdBase * - Pointer to a new command.
180// Throws:  None.
181//--
182CMICmdBase *
183CMICmdCmdGdbSet::CreateSelf()
184{
185    return new CMICmdCmdGdbSet();
186}
187
188//++ ------------------------------------------------------------------------------------
189// Details: Retrieve the print function's pointer for the matching print request.
190// Type:    Method.
191// Args:    vrPrintFnName   - (R) The info requested.
192//          vrwpFn          - (W) The print function's pointer of the function to carry out
193// Return:  bool    - True = Print request is implemented, false = not found.
194// Throws:  None.
195//--
196bool
197CMICmdCmdGdbSet::GetOptionFn(const CMIUtilString &vrPrintFnName, FnGdbOptionPtr &vrwpFn) const
198{
199    vrwpFn = nullptr;
200
201    const MapGdbOptionNameToFnGdbOptionPtr_t::const_iterator it = ms_mapGdbOptionNameToFnGdbOptionPtr.find(vrPrintFnName);
202    if (it != ms_mapGdbOptionNameToFnGdbOptionPtr.end())
203    {
204        vrwpFn = (*it).second;
205        return true;
206    }
207
208    return false;
209}
210
211//++ ------------------------------------------------------------------------------------
212// Details: Carry out work to complete the GDB set option 'target-async' to prepare
213//          and send back information asked for.
214// Type:    Method.
215// Args:    vrWords - (R) List of additional parameters used by this option.
216// Return:  MIstatus::success - Function succeeded.
217//          MIstatus::failure - Function failed.
218// Throws:  None.
219//--
220bool
221CMICmdCmdGdbSet::OptionFnTargetAsync(const CMIUtilString::VecString_t &vrWords)
222{
223    bool bAsyncMode = false;
224    bool bOk = true;
225
226    if (vrWords.size() > 1)
227        // Too many arguments.
228        bOk = false;
229    else if (vrWords.size() == 0)
230        // If no arguments, default is "on".
231        bAsyncMode = true;
232    else if (CMIUtilString::Compare(vrWords[0], "on"))
233        bAsyncMode = true;
234    else if (CMIUtilString::Compare(vrWords[0], "off"))
235        bAsyncMode = false;
236    else
237        // Unrecognized argument.
238        bOk = false;
239
240    if (!bOk)
241    {
242        // Report error.
243        m_bGbbOptionFnHasError = true;
244        m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_TARGETASYNC);
245        return MIstatus::failure;
246    }
247
248    // Turn async mode on/off.
249    CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
250    rSessionInfo.GetDebugger().SetAsync(bAsyncMode);
251
252    return MIstatus::success;
253}
254
255//++ ------------------------------------------------------------------------------------
256// Details: Carry out work to complete the GDB set option 'print-char-array-as-string' to
257//          prepare and send back information asked for.
258// Type:    Method.
259// Args:    vrWords - (R) List of additional parameters used by this option.
260// Return:  MIstatus::success - Function succeeded.
261//          MIstatus::failure - Function failed.
262// Throws:  None.
263//--
264bool
265CMICmdCmdGdbSet::OptionFnPrint(const CMIUtilString::VecString_t &vrWords)
266{
267    const bool bAllArgs(vrWords.size() == 2);
268    const bool bArgOn(bAllArgs && (CMIUtilString::Compare(vrWords[1], "on") || CMIUtilString::Compare(vrWords[1], "1")));
269    const bool bArgOff(bAllArgs && (CMIUtilString::Compare(vrWords[1], "off") || CMIUtilString::Compare(vrWords[1], "0")));
270    if (!bAllArgs || (!bArgOn && !bArgOff))
271    {
272        m_bGbbOptionFnHasError = true;
273        m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_PRINT_BAD_ARGS);
274        return MIstatus::failure;
275    }
276
277    const CMIUtilString strOption(vrWords[0]);
278    CMIUtilString strOptionKey;
279    if (CMIUtilString::Compare(strOption, "char-array-as-string"))
280        strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintCharArrayAsString;
281    else if (CMIUtilString::Compare(strOption, "expand-aggregates"))
282        strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintExpandAggregates;
283    else if (CMIUtilString::Compare(strOption, "aggregate-field-names"))
284        strOptionKey = m_rLLDBDebugSessionInfo.m_constStrPrintAggregateFieldNames;
285    else
286    {
287        m_bGbbOptionFnHasError = true;
288        m_strGdbOptionFnError = CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_GDBSET_OPT_PRINT_UNKNOWN_OPTION), strOption.c_str());
289        return MIstatus::failure;
290    }
291
292    const bool bOptionValue(bArgOn);
293    if (!m_rLLDBDebugSessionInfo.SharedDataAdd<bool>(strOptionKey, bOptionValue))
294    {
295        m_bGbbOptionFnHasError = false;
296        SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD), m_cmdData.strMiCmd.c_str(), strOptionKey.c_str()));
297        return MIstatus::failure;
298    }
299
300    return MIstatus::success;
301}
302
303//++ ------------------------------------------------------------------------------------
304// Details: Carry out work to complete the GDB set option 'solib-search-path' to prepare
305//          and send back information asked for.
306// Type:    Method.
307// Args:    vrWords - (R) List of additional parameters used by this option.
308// Return:  MIstatus::success - Functional succeeded.
309//          MIstatus::failure - Functional failed.
310// Throws:  None.
311//--
312bool
313CMICmdCmdGdbSet::OptionFnSolibSearchPath(const CMIUtilString::VecString_t &vrWords)
314{
315    // Check we have at least one argument
316    if (vrWords.size() < 1)
317    {
318        m_bGbbOptionFnHasError = true;
319        m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH);
320        return MIstatus::failure;
321    }
322    const CMIUtilString &rStrValSolibPath(vrWords[0]);
323
324    // Add 'solib-search-path' to the shared data list
325    const CMIUtilString &rStrKeySolibPath(m_rLLDBDebugSessionInfo.m_constStrSharedDataSolibPath);
326    if (!m_rLLDBDebugSessionInfo.SharedDataAdd<CMIUtilString>(rStrKeySolibPath, rStrValSolibPath))
327    {
328        m_bGbbOptionFnHasError = false;
329        SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD), m_cmdData.strMiCmd.c_str(), rStrKeySolibPath.c_str()));
330        return MIstatus::failure;
331    }
332
333    return MIstatus::success;
334}
335
336//++ ------------------------------------------------------------------------------------
337// Details: Carry out work to complete the GDB set option 'output-radix' to prepare
338//          and send back information asked for.
339// Type:    Method.
340// Args:    vrWords - (R) List of additional parameters used by this option.
341// Return:  MIstatus::success - Functional succeeded.
342//          MIstatus::failure - Functional failed.
343// Throws:  None.
344//--
345bool
346CMICmdCmdGdbSet::OptionFnOutputRadix(const CMIUtilString::VecString_t &vrWords)
347{
348    // Check we have at least one argument
349    if (vrWords.size() < 1)
350    {
351        m_bGbbOptionFnHasError = true;
352        m_strGdbOptionFnError = MIRSRC(IDS_CMD_ERR_GDBSET_OPT_SOLIBSEARCHPATH);
353        return MIstatus::failure;
354    }
355    const CMIUtilString &rStrValOutputRadix(vrWords[0]);
356
357    CMICmnLLDBDebugSessionInfoVarObj::varFormat_e  format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid;
358    MIint64 radix;
359    if (rStrValOutputRadix.ExtractNumber(radix))
360    {
361        switch (radix)
362        {
363        case 8:
364            format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Octal;
365            break;
366        case 10:
367            format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Natural;
368            break;
369        case 16:
370            format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Hex;
371            break;
372        default:
373            format = CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid;
374            break;
375        }
376    }
377    if (format == CMICmnLLDBDebugSessionInfoVarObj::eVarFormat_Invalid)
378    {
379        m_bGbbOptionFnHasError = false;
380        SetError(CMIUtilString::Format(MIRSRC(IDS_DBGSESSION_ERR_SHARED_DATA_ADD), m_cmdData.strMiCmd.c_str(), "Output Radix"));
381        return MIstatus::failure;
382    }
383    CMICmnLLDBDebugSessionInfoVarObj::VarObjSetFormat(format);
384
385    return MIstatus::success;
386}
387
388//++ ------------------------------------------------------------------------------------
389// Details: Carry out work to complete the GDB set option to prepare and send back the
390//          requested information.
391// Type:    Method.
392// Args:    None.
393// Return:  MIstatus::success - Functional succeeded.
394//          MIstatus::failure - Functional failed.
395// Throws:  None.
396//--
397bool
398CMICmdCmdGdbSet::OptionFnFallback(const CMIUtilString::VecString_t &vrWords)
399{
400    MIunused(vrWords);
401
402    // Do nothing - intentional. This is a fallback function to do nothing.
403    // This allows the search for gdb-set options to always succeed when the option is not
404    // found (implemented).
405
406    return MIstatus::success;
407}
408