1 //===-- MICmdCmdSymbol.cpp --------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Overview: CMICmdCmdSymbolListLines implementation.
12 // Third Party Headers:
13 #include "lldb/API/SBCommandInterpreter.h"
16 #include "MICmdArgValFile.h"
17 #include "MICmdCmdSymbol.h"
18 #include "MICmnLLDBDebugSessionInfo.h"
19 #include "MICmnMIResultRecord.h"
20 #include "MICmnMIValueList.h"
21 #include "MICmnMIValueTuple.h"
22 #include "MIUtilParse.h"
24 //++ ------------------------------------------------------------------------------------
25 // Details: CMICmdCmdSymbolListLines constructor.
31 CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines()
32 : m_constStrArgNameFile("file")
34 // Command factory matches this name with that received from the stdin stream
35 m_strMiCmd = "symbol-list-lines";
37 // Required by the CMICmdFactory when registering *this command
38 m_pSelfCreatorFn = &CMICmdCmdSymbolListLines::CreateSelf;
41 //++ ------------------------------------------------------------------------------------
42 // Details: CMICmdCmdSymbolListLines destructor.
43 // Type: Overrideable.
48 CMICmdCmdSymbolListLines::~CMICmdCmdSymbolListLines()
52 //++ ------------------------------------------------------------------------------------
53 // Details: The invoker requires this function. The parses the command line options
54 // arguments to extract values for each of those arguments.
57 // Return: MIstatus::success - Functional succeeded.
58 // MIstatus::failure - Functional failed.
62 CMICmdCmdSymbolListLines::ParseArgs()
64 m_setCmdArgs.Add(new CMICmdArgValFile(m_constStrArgNameFile, true, true));
65 return ParseValidateCmdOptions();
68 //++ ------------------------------------------------------------------------------------
69 // Details: The invoker requires this function. The command does work in this function.
70 // The command is likely to communicate with the LLDB SBDebugger in here.
71 // Synopsis: -symbol-list-lines file
72 // Ref: http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Symbol-Query.html#GDB_002fMI-Symbol-Query
75 // Return: MIstatus::success - Functional succeeded.
76 // MIstatus::failure - Functional failed.
80 CMICmdCmdSymbolListLines::Execute()
82 CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
84 const CMIUtilString &strFilePath(pArgFile->GetValue());
85 const CMIUtilString strCmd(CMIUtilString::Format("source info --file \"%s\"", strFilePath.AddSlashes().c_str()));
87 CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
88 const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
91 return MIstatus::success;
94 //++ ------------------------------------------------------------------------------------
95 // Details: Helper function for parsing the header returned from lldb for the command:
96 // target modules dump line-table <file>
97 // where the header is of the format:
98 // Line table for /path/to/file in `/path/to/module
99 // Args: input - (R) Input string to parse.
100 // file - (W) String representing the file.
101 // Return: bool - True = input was parsed successfully, false = input could not be parsed.
105 ParseLLDBLineAddressHeader(const char *input, CMIUtilString &file)
107 // Match LineEntry using regex.
108 static MIUtilParse::CRegexParser g_lineentry_header_regex(
109 "^ *Lines found for file (.+) in compilation unit (.+) in `(.+)$");
110 // ^1=file ^2=cu ^3=module
112 MIUtilParse::CRegexParser::Match match(4);
114 const bool ok = g_lineentry_header_regex.Execute(input, match);
116 file = match.GetMatchAtIndex(1);
120 //++ ------------------------------------------------------------------------------------
121 // Details: Helper function for parsing a line entry returned from lldb for the command:
122 // target modules dump line-table <file>
123 // where the line entry is of the format:
124 // 0x0000000100000e70: /path/to/file:3002[:4]
125 // addr file line column(opt)
126 // Args: input - (R) Input string to parse.
127 // addr - (W) String representing the pc address.
128 // file - (W) String representing the file.
129 // line - (W) String representing the line.
130 // Return: bool - True = input was parsed successfully, false = input could not be parsed.
134 ParseLLDBLineAddressEntry(const char *input, CMIUtilString &addr,
135 CMIUtilString &file, CMIUtilString &line)
137 // Note: Ambiguities arise because the column is optional, and
138 // because : can appear in filenames or as a byte in a multibyte
139 // UTF8 character. We keep those cases to a minimum by using regex
140 // to work on the string from both the left and right, so that what
141 // is remains is assumed to be the filename.
143 // Match LineEntry using regex.
144 static MIUtilParse::CRegexParser g_lineentry_nocol_regex(
145 "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$");
146 static MIUtilParse::CRegexParser g_lineentry_col_regex(
147 "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$");
148 // ^1=start ^2=end ^3=f ^4=line ^5=:col(opt)
150 MIUtilParse::CRegexParser::Match match(6);
152 // First try matching the LineEntry with the column,
153 // then try without the column.
154 const bool ok = g_lineentry_col_regex.Execute(input, match) ||
155 g_lineentry_nocol_regex.Execute(input, match);
158 addr = match.GetMatchAtIndex(1);
159 file = match.GetMatchAtIndex(3);
160 line = match.GetMatchAtIndex(4);
165 //++ ------------------------------------------------------------------------------------
166 // Details: The invoker requires this function. The command prepares a MI Record Result
167 // for the work carried out in the Execute().
170 // Return: MIstatus::success - Functional succeeded.
171 // MIstatus::failure - Functional failed.
175 CMICmdCmdSymbolListLines::Acknowledge()
177 if (m_lldbResult.GetErrorSize() > 0)
179 const char *pLldbErr = m_lldbResult.GetError();
180 const CMIUtilString strMsg(CMIUtilString(pLldbErr).StripCRAll());
181 const CMICmnMIValueConst miValueConst(strMsg);
182 const CMICmnMIValueResult miValueResult("message", miValueConst);
183 const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
184 m_miResultRecord = miRecordResult;
188 CMIUtilString::VecString_t vecLines;
189 const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
190 const MIuint nLines(strLldbMsg.SplitLines(vecLines));
192 // Parse the file from the header.
193 const CMIUtilString &rWantFile(vecLines[0]);
194 CMIUtilString strWantFile;
195 if (!ParseLLDBLineAddressHeader(rWantFile.c_str(), strWantFile))
197 // Unexpected error - parsing failed.
198 // MI print "%s^error,msg=\"Command '-symbol-list-lines'. Error: Line address header is absent or has an unknown format.\""
199 const CMICmnMIValueConst miValueConst(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(), "Line address header is absent or has an unknown format."));
200 const CMICmnMIValueResult miValueResult("msg", miValueConst);
201 const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, miValueResult);
202 m_miResultRecord = miRecordResult;
204 return MIstatus::success;
207 // Parse the line address entries.
208 CMICmnMIValueList miValueList(true);
209 for (MIuint i = 1; i < nLines; ++i)
211 // String looks like:
212 // 0x0000000100000e70: /path/to/file:3[:4]
213 const CMIUtilString &rLine(vecLines[i]);
214 CMIUtilString strAddr;
215 CMIUtilString strFile;
216 CMIUtilString strLine;
218 if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine))
221 const CMICmnMIValueConst miValueConst(strAddr);
222 const CMICmnMIValueResult miValueResult("pc", miValueConst);
223 CMICmnMIValueTuple miValueTuple(miValueResult);
225 const CMICmnMIValueConst miValueConst2(strLine);
226 const CMICmnMIValueResult miValueResult2("line", miValueConst2);
227 miValueTuple.Add(miValueResult2);
229 miValueList.Add(miValueTuple);
232 // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]"
233 const CMICmnMIValueResult miValueResult("lines", miValueList);
234 const CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
235 m_miResultRecord = miRecordResult;
238 return MIstatus::success;
241 //++ ------------------------------------------------------------------------------------
242 // Details: Required by the CMICmdFactory when registering *this command. The factory
243 // calls this function to create an instance of *this command.
244 // Type: Static method.
246 // Return: CMICmdBase * - Pointer to a new command.
250 CMICmdCmdSymbolListLines::CreateSelf()
252 return new CMICmdCmdSymbolListLines();