Index: test/tools/lldb-mi/stack/TestMiStack.py =================================================================== --- test/tools/lldb-mi/stack/TestMiStack.py +++ test/tools/lldb-mi/stack/TestMiStack.py @@ -204,6 +204,133 @@ @lldbmi_test @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races + def test_lldbmi_stack_list_variables(self): + """Test that 'lldb-mi --interpreter' can shows local variables and arguments.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Run to main + self.runCmd("-break-insert -f main") + self.expect("\^done,bkpt={number=\"1\"") + self.runCmd("-exec-run") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test int local variables: + # Run to BP_local_int_test + line = line_number('main.cpp', '// BP_local_int_test_with_args') + self.runCmd("-break-insert --file main.cpp:%d" % line) + self.expect("\^done,bkpt={number=\"2\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -stack-list-variables: use 0 or --no-values + self.runCmd("-stack-list-variables 0") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\"},{arg=\"1\",name=\"d\"},{name=\"a\"},{name=\"b\"}\]") + self.runCmd("-stack-list-variables --no-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\"},{arg=\"1\",name=\"d\"},{name=\"a\"},{name=\"b\"}\]") + + # Test -stack-list-variables: use 1 or --all-values + self.runCmd("-stack-list-variables 1") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + self.runCmd("-stack-list-variables --all-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + + # Test -stack-list-variables: use 2 or --simple-values + self.runCmd("-stack-list-variables 2") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + self.runCmd("-stack-list-variables --simple-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"c\",value=\"30\"},{arg=\"1\",name=\"d\",value=\"40\"},{name=\"a\",value=\"10\"},{name=\"b\",value=\"20\"}\]") + + # Test struct local variable: + # Run to BP_local_struct_test + line = line_number('main.cpp', '// BP_local_struct_test_with_args') + self.runCmd("-break-insert --file main.cpp:%d" % line) + self.expect("\^done,bkpt={number=\"3\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -stack-list-variables: use 0 or --no-values + self.runCmd("-stack-list-variables 0") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]") + self.runCmd("-stack-list-variables --no-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]") + + # Test -stack-list-variables: use 1 or --all-values + self.runCmd("-stack-list-variables 1") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",value=\"{var_a = 20, var_b = 98 'b', inner_ = {var_d = 40}}\"},{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]") + self.runCmd("-stack-list-variables --all-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\",value=\"{var_a = 20, var_b = 98 'b', inner_ = {var_d = 40}}\"},{name=\"var_c\",value=\"{var_a = 10, var_b = 97 'a', inner_ = {var_d = 30}}\"}\]") + + # Test -stack-list-variables: use 2 or --simple-values + self.runCmd("-stack-list-variables 2") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]") + self.runCmd("-stack-list-variables --simple-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"var_e\"},{name=\"var_c\"}\]") + + # Test array local variable: + # Run to BP_local_array_test + line = line_number('main.cpp', '// BP_local_array_test_with_args') + self.runCmd("-break-insert --file main.cpp:%d" % line) + self.expect("\^done,bkpt={number=\"4\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -stack-list-variables: use 0 or --no-values + self.runCmd("-stack-list-variables 0") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\"},{name=\"array\"}\]") + self.runCmd("-stack-list-variables --no-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\"},{name=\"array\"}\]") + + # Test -stack-list-variables: use 1 or --all-values + self.runCmd("-stack-list-variables 1") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]") + self.runCmd("-stack-list-variables --all-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\",value=\"{\[0\] = 100, \[1\] = 200, \[2\] = 300}\"}\]") + + # Test -stack-list-variables: use 2 or --simple-values + self.runCmd("-stack-list-variables 2") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\"}\]") + self.runCmd("-stack-list-variables --simple-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"other_array\",value=\".*?\"},{name=\"array\"}\]") + + # Test pointers as local variable: + # Run to BP_local_pointer_test + line = line_number('main.cpp', '// BP_local_pointer_test_with_args') + self.runCmd("-break-insert --file main.cpp:%d" % line) + self.expect("\^done,bkpt={number=\"5\"") + self.runCmd("-exec-continue") + self.expect("\^running") + self.expect("\*stopped,reason=\"breakpoint-hit\"") + + # Test -stack-list-variables: use 0 or --no-values + self.runCmd("-stack-list-variables 0") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\"},{arg=\"1\",name=\"arg_ptr\"},{name=\"test_str\"},{name=\"var_e\"},{name=\"ptr\"}\]") + self.runCmd("-stack-list-variables --no-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\"},{arg=\"1\",name=\"arg_ptr\"},{name=\"test_str\"},{name=\"var_e\"},{name=\"ptr\"}\]") + + # Test -stack-list-variables: use 1 or --all-values + self.runCmd("-stack-list-variables 1") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]") + self.runCmd("-stack-list-variables --all-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]") + + # Test -stack-list-variables: use 2 or --simple-values + self.runCmd("-stack-list-variables 2") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]") + self.runCmd("-stack-list-variables --simple-values") + self.expect("\^done,variables=\[{arg=\"1\",name=\"arg_str\",value=\".*?String.*?\"},{arg=\"1\",name=\"arg_ptr\",value=\".*?\"},{name=\"test_str\",value=\".*?Rakaposhi.*?\"},{name=\"var_e\",value=\"24\"},{name=\"ptr\",value=\".*?\"}\]") + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races def test_lldbmi_stack_info_depth(self): """Test that 'lldb-mi --interpreter' can shows depth of the stack.""" Index: test/tools/lldb-mi/stack/main.cpp =================================================================== --- test/tools/lldb-mi/stack/main.cpp +++ test/tools/lldb-mi/stack/main.cpp @@ -27,6 +27,13 @@ } int +local_int_test_with_args(int c, int d) +{ + int a = 10, b = 20; + return 0; // BP_local_int_test_with_args +} + +int local_struct_test(void) { struct my_type var_c; @@ -36,6 +43,15 @@ return 0; // BP_local_struct_test } +int local_struct_test_with_args(struct my_type var_e) +{ + struct my_type var_c; + var_c.var_a = 10; + var_c.var_b = 'a'; + var_c.inner_.var_d = 30; + return 0; // BP_local_struct_test_with_args +} + int local_array_test(void) { @@ -47,6 +63,16 @@ } int +local_array_test_with_args(int* other_array) +{ + int array[3]; + array[0] = 100; + array[1] = 200; + array[2] = 300; + return 0; // BP_local_array_test_with_args +} + +int local_pointer_test(void) { const char *test_str = "Rakaposhi"; @@ -56,11 +82,46 @@ } int +local_pointer_test_with_args(const char *arg_str, int *arg_ptr) +{ + const char *test_str = "Rakaposhi"; + int var_e = 24; + int *ptr = &var_e; + return 0; // BP_local_pointer_test_with_args +} + +int do_tests_with_args() +{ + local_int_test_with_args(30, 40); + + struct my_type var_e; + var_e.var_a = 20; + var_e.var_b = 'b'; + var_e.inner_.var_d = 40; + local_struct_test_with_args(var_e); + + int array[3]; + array[0] = 400; + array[1] = 500; + array[2] = 600; + local_array_test_with_args(array); + + const char *test_str = "String"; + int var_z = 25; + int *ptr = &var_z; + local_pointer_test_with_args(test_str, ptr); + + return 0; +} + +int main(int argc, char const *argv[]) { local_int_test(); local_struct_test(); local_array_test(); local_pointer_test(); + + do_tests_with_args(); return 0; } Index: tools/lldb-mi/MICmdCmdStack.h =================================================================== --- tools/lldb-mi/MICmdCmdStack.h +++ tools/lldb-mi/MICmdCmdStack.h @@ -214,6 +214,42 @@ //++ ============================================================================ // Details: MI command class. MI commands derived from the command base class. +// *this class implements MI command "stack-list-variables". +//-- +class CMICmdCmdStackListVariables : public CMICmdBase +{ + // Statics: +public: + // Required by the CMICmdFactory when registering *this command + static CMICmdBase *CreateSelf(void); + + // Methods: +public: + /* ctor */ CMICmdCmdStackListVariables(void); + + // Overridden: +public: + // From CMICmdInvoker::ICmd + virtual bool Execute(void); + virtual bool Acknowledge(void); + virtual bool ParseArgs(void); + // From CMICmnBase + /* dtor */ virtual ~CMICmdCmdStackListVariables(void); + + // Attributes +private: + bool m_bThreadInvalid; // True = yes invalid thread, false = thread object valid + CMICmnMIValueList m_miValueList; + const CMIUtilString m_constStrArgThread; + const CMIUtilString m_constStrArgFrame; + const CMIUtilString m_constStrArgPrintValues; + const CMIUtilString m_constStrArgNoValues; + const CMIUtilString m_constStrArgAllValues; + const CMIUtilString m_constStrArgSimpleValues; +}; + +//++ ============================================================================ +// Details: MI command class. MI commands derived from the command base class. // *this class implements MI command "stack-select-frame". //-- class CMICmdCmdStackSelectFrame : public CMICmdBase Index: tools/lldb-mi/MICmdCmdStack.cpp =================================================================== --- tools/lldb-mi/MICmdCmdStack.cpp +++ tools/lldb-mi/MICmdCmdStack.cpp @@ -850,6 +850,200 @@ //--------------------------------------------------------------------------------------- //++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdStackListVariables constructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdStackListVariables::CMICmdCmdStackListVariables(void) + : m_bThreadInvalid(false) + , m_miValueList(true) + , m_constStrArgThread("thread") + , m_constStrArgFrame("frame") + , m_constStrArgPrintValues("print-values") + , m_constStrArgNoValues("no-values") + , m_constStrArgAllValues("all-values") + , m_constStrArgSimpleValues("simple-values") +{ + // Command factory matches this name with that received from the stdin stream + m_strMiCmd = "stack-list-variables"; + + // Required by the CMICmdFactory when registering *this command + m_pSelfCreatorFn = &CMICmdCmdStackListVariables::CreateSelf; +} + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmdCmdStackListVariables destructor. +// Type: Overrideable. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmdCmdStackListVariables::~CMICmdCmdStackListVariables(void) +{ +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The parses the command line options +// arguments to extract values for each of those arguments. +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool +CMICmdCmdStackListVariables::ParseArgs(void) +{ + bool bOk = + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgThread, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && + m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgFrame, false, true, CMICmdArgValListBase::eArgValType_Number, 1))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValNumber(m_constStrArgPrintValues, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgNoValues, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgAllValues, false, true))); + bOk = bOk && m_setCmdArgs.Add(*(new CMICmdArgValOptionLong(m_constStrArgSimpleValues, false, true))); + return (bOk && ParseValidateCmdOptions()); +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The command does work in this function. +// The command is likely to communicate with the LLDB SBDebugger in here. +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool +CMICmdCmdStackListVariables::Execute(void) +{ + CMICMDBASE_GETOPTION(pArgThread, OptionLong, m_constStrArgThread); + CMICMDBASE_GETOPTION(pArgFrame, OptionLong, m_constStrArgFrame); + CMICMDBASE_GETOPTION(pArgPrintValues, Number, m_constStrArgPrintValues); + CMICMDBASE_GETOPTION(pArgNoValues, OptionLong, m_constStrArgNoValues); + CMICMDBASE_GETOPTION(pArgAllValues, OptionLong, m_constStrArgAllValues); + CMICMDBASE_GETOPTION(pArgSimpleValues, OptionLong, m_constStrArgSimpleValues); + + // Retrieve the --thread option's thread ID (only 1) + MIuint64 nThreadId = UINT64_MAX; + if (pArgThread->GetFound()) + { + if (!pArgThread->GetExpectedOption(nThreadId)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgThread.c_str())); + return MIstatus::failure; + } + } + + MIuint64 nFrame = UINT64_MAX; + if (pArgFrame->GetFound()) + { + if (!pArgFrame->GetExpectedOption(nFrame)) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_OPTION_NOT_FOUND), m_cmdData.strMiCmd.c_str(), m_constStrArgFrame.c_str())); + return MIstatus::failure; + } + } + + CMICmnLLDBDebugSessionInfo::VariableInfoFormat_e eVarInfoFormat; + if (pArgPrintValues->GetFound()) + { + const MIuint nPrintValues = pArgPrintValues->GetValue(); + if (nPrintValues >= CMICmnLLDBDebugSessionInfo::kNumVariableInfoFormats) + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + eVarInfoFormat = static_cast(nPrintValues); + } + else if (pArgNoValues->GetFound()) + eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_NoValues; + else if (pArgAllValues->GetFound()) + eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_AllValues; + else if (pArgSimpleValues->GetFound()) + eVarInfoFormat = CMICmnLLDBDebugSessionInfo::eVariableInfoFormat_SimpleValues; + else + { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_PRINT_VALUES), m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } + + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); + lldb::SBThread thread = (nThreadId != UINT64_MAX) ? sbProcess.GetThreadByIndexID(nThreadId) : sbProcess.GetSelectedThread(); + m_bThreadInvalid = !thread.IsValid(); + if (m_bThreadInvalid) + return MIstatus::success; + + const lldb::StopReason eStopReason = thread.GetStopReason(); + if ((eStopReason == lldb::eStopReasonNone) || (eStopReason == lldb::eStopReasonInvalid)) + { + m_bThreadInvalid = true; + return MIstatus::success; + } + + lldb::SBFrame frame = (nFrame != UINT64_MAX) ? thread.GetFrameAtIndex(nFrame) : thread.GetSelectedFrame(); + + CMICmnMIValueList miValueList(true); + const MIuint maskVarTypes = CMICmnLLDBDebugSessionInfo::eVariableType_Arguments | CMICmnLLDBDebugSessionInfo::eVariableType_Locals; + if (!rSessionInfo.MIResponseFormVariableInfo(frame, maskVarTypes, eVarInfoFormat, miValueList, 10, true)) + return MIstatus::failure; + m_miValueList = miValueList; + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: The invoker requires this function. The command prepares a MI Record Result +// for the work carried out in the Execute(). +// Type: Overridden. +// Args: None. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool +CMICmdCmdStackListVariables::Acknowledge(void) +{ + if (m_bThreadInvalid) + { + // MI print "%s^done,variables=[]" + const CMICmnMIValueList miValueList(true); + const CMICmnMIValueResult miValueResult("variables", miValueList); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + return MIstatus::success; + } + + // MI print "%s^done,variables=[%s]" + const CMICmnMIValueResult miValueResult("variables", m_miValueList); + const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult); + m_miResultRecord = miRecordResult; + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Required by the CMICmdFactory when registering *this command. The factory +// calls this function to create an instance of *this command. +// Type: Static method. +// Args: None. +// Return: CMICmdBase * - Pointer to a new command. +// Throws: None. +//-- +CMICmdBase * +CMICmdCmdStackListVariables::CreateSelf(void) +{ + return new CMICmdCmdStackListVariables(); +} + +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------- + +//++ ------------------------------------------------------------------------------------ // Details: CMICmdCmdStackSelectFrame constructor. // Type: Method. // Args: None. Index: tools/lldb-mi/MICmdCommands.cpp =================================================================== --- tools/lldb-mi/MICmdCommands.cpp +++ tools/lldb-mi/MICmdCommands.cpp @@ -115,6 +115,7 @@ bOk &= Register(); bOk &= Register(); bOk &= Register(); + bOk &= Register(); bOk &= Register(); bOk &= Register(); bOk &= Register(); Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.h =================================================================== --- tools/lldb-mi/MICmnLLDBDebugSessionInfo.h +++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.h @@ -159,7 +159,7 @@ const ThreadInfoFormat_e veThreadInfoFormat, CMICmnMIValueTuple &vwrMIValueTuple); bool MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, - const MIuint vnMaxDepth = 10); + const MIuint vnMaxDepth = 10, const bool vbMarkArgs = false); bool MIResponseFormBrkPtFrameInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); bool MIResponseFormBrkPtInfo(const SBrkPtInfo &vrBrkPtInfo, CMICmnMIValueTuple &vwrMiValueTuple); bool GetBrkPtInfo(const lldb::SBBreakpoint &vBrkPt, SBrkPtInfo &vrwBrkPtInfo) const; @@ -204,6 +204,8 @@ CMIUtilString &vwPath, MIuint &vwnLine); bool GetThreadFrames(const SMICmdData &vCmdData, const MIuint vThreadIdx, const FrameInfoFormat_e veFrameInfoFormat, CMIUtilString &vwrThreadFrames); + bool MIResponseForVariableInfoInternal(const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, + const lldb::SBValueList &vwrSBValueList, const MIuint vnMaxDepth, const bool vbIsArgs, const bool vbMarkArgs); // Overridden: private: Index: tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp =================================================================== --- tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp +++ tools/lldb-mi/MICmnLLDBDebugSessionInfo.cpp @@ -431,7 +431,8 @@ bool CMICmnLLDBDebugSessionInfo::MIResponseFormVariableInfo(const lldb::SBFrame &vrFrame, const MIuint vMaskVarTypes, const VariableInfoFormat_e veVarInfoFormat, CMICmnMIValueList &vwrMiValueList, - const MIuint vnMaxDepth /* = 10 */) + const MIuint vnMaxDepth, /* = 10 */ + const bool vbMarkArgs /* = false*/) { bool bOk = MIstatus::success; lldb::SBFrame &rFrame = const_cast(vrFrame); @@ -440,14 +441,40 @@ const bool bLocals = (vMaskVarTypes & eVariableType_Locals); const bool bStatics = (vMaskVarTypes & eVariableType_Statics); const bool bInScopeOnly = (vMaskVarTypes & eVariableType_InScope); - lldb::SBValueList listArg = rFrame.GetVariables(bArg, bLocals, bStatics, bInScopeOnly); - const MIuint nArgs = listArg.GetSize(); + + // Handle arguments first + lldb::SBValueList listArg = rFrame.GetVariables(bArg, false, false, false); + bOk = bOk && MIResponseForVariableInfoInternal(veVarInfoFormat, vwrMiValueList, listArg, vnMaxDepth, true, vbMarkArgs); + + // Handle remaining variables + lldb::SBValueList listVars = rFrame.GetVariables(false, bLocals, bStatics, bInScopeOnly); + bOk = bOk && MIResponseForVariableInfoInternal(veVarInfoFormat, vwrMiValueList, listVars, vnMaxDepth, false, vbMarkArgs); + + return bOk; +} + +bool +CMICmnLLDBDebugSessionInfo::MIResponseForVariableInfoInternal(const VariableInfoFormat_e veVarInfoFormat, + CMICmnMIValueList &vwrMiValueList, + const lldb::SBValueList &vwrSBValueList, + const MIuint vnMaxDepth, + const bool vbIsArgs, + const bool vbMarkArgs) +{ + bool bOk = MIstatus::success; + const MIuint nArgs = vwrSBValueList.GetSize(); for (MIuint i = 0; bOk && (i < nArgs); i++) { CMICmnMIValueTuple miValueTuple; - lldb::SBValue value = listArg.GetValueAtIndex(i); + lldb::SBValue value = vwrSBValueList.GetValueAtIndex(i); const CMICmnMIValueConst miValueConst(value.GetName()); const CMICmnMIValueResult miValueResultName("name", miValueConst); + if (vbMarkArgs && vbIsArgs) + { + const CMICmnMIValueConst miValueConstArg("1"); + const CMICmnMIValueResult miValueResultArg("arg", miValueConstArg); + miValueTuple.Add(miValueResultArg); + } if (veVarInfoFormat != eVariableInfoFormat_NoValues) { const MIuint nChildren = value.GetNumChildren(); @@ -468,8 +495,18 @@ } } } - // If we are printing name only then no need to put it in the tuple. - vwrMiValueList.Add(miValueResultName); + + if (vbMarkArgs) + { + // If we are printing names only with vbMarkArgs, we still need to add the name to the value tuple + miValueTuple.Add(miValueResultName); // name + vwrMiValueList.Add(miValueTuple); + } + else + { + // If we are printing name only then no need to put it in the tuple. + vwrMiValueList.Add(miValueResultName); + } } return bOk; }