]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/lldb-mi/MICmdCmdSymbol.cpp
Vendor import of lldb trunk r256945:
[FreeBSD/FreeBSD.git] / tools / lldb-mi / MICmdCmdSymbol.cpp
1 //===-- MICmdCmdSymbol.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:    CMICmdCmdSymbolListLines     implementation.
11
12 // Third Party Headers:
13 #include "lldb/API/SBCommandInterpreter.h"
14
15 // In-house headers:
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"
23
24 //++ ------------------------------------------------------------------------------------
25 // Details: CMICmdCmdSymbolListLines constructor.
26 // Type:    Method.
27 // Args:    None.
28 // Return:  None.
29 // Throws:  None.
30 //--
31 CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines()
32     : m_constStrArgNameFile("file")
33 {
34     // Command factory matches this name with that received from the stdin stream
35     m_strMiCmd = "symbol-list-lines";
36
37     // Required by the CMICmdFactory when registering *this command
38     m_pSelfCreatorFn = &CMICmdCmdSymbolListLines::CreateSelf;
39 }
40
41 //++ ------------------------------------------------------------------------------------
42 // Details: CMICmdCmdSymbolListLines destructor.
43 // Type:    Overrideable.
44 // Args:    None.
45 // Return:  None.
46 // Throws:  None.
47 //--
48 CMICmdCmdSymbolListLines::~CMICmdCmdSymbolListLines()
49 {
50 }
51
52 //++ ------------------------------------------------------------------------------------
53 // Details: The invoker requires this function. The parses the command line options
54 //          arguments to extract values for each of those arguments.
55 // Type:    Overridden.
56 // Args:    None.
57 // Return:  MIstatus::success - Functional succeeded.
58 //          MIstatus::failure - Functional failed.
59 // Throws:  None.
60 //--
61 bool
62 CMICmdCmdSymbolListLines::ParseArgs()
63 {
64     m_setCmdArgs.Add(new CMICmdArgValFile(m_constStrArgNameFile, true, true));
65     return ParseValidateCmdOptions();
66 }
67
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
73 // Type:    Overridden.
74 // Args:    None.
75 // Return:  MIstatus::success - Functional succeeded.
76 //          MIstatus::failure - Functional failed.
77 // Throws:  None.
78 //--
79 bool
80 CMICmdCmdSymbolListLines::Execute()
81 {
82     CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
83
84     const CMIUtilString &strFilePath(pArgFile->GetValue());
85     const CMIUtilString strCmd(CMIUtilString::Format("source info --file \"%s\"", strFilePath.AddSlashes().c_str()));
86
87     CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
88     const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
89     MIunused(rtn);
90
91     return MIstatus::success;
92 }
93
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.
102 // Throws:  None.
103 //--
104 static bool
105 ParseLLDBLineAddressHeader(const char *input, CMIUtilString &file)
106 {
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
111
112     MIUtilParse::CRegexParser::Match match(4);
113
114     const bool ok = g_lineentry_header_regex.Execute(input, match);
115     if (ok)
116         file = match.GetMatchAtIndex(1);
117     return ok;
118 }
119
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.
131 // Throws:  None.
132 //--
133 static bool
134 ParseLLDBLineAddressEntry(const char *input, CMIUtilString &addr,
135                           CMIUtilString &file, CMIUtilString &line)
136 {
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.
142
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)
149
150     MIUtilParse::CRegexParser::Match match(6);
151
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);
156     if (ok)
157     {
158         addr = match.GetMatchAtIndex(1);
159         file = match.GetMatchAtIndex(3);
160         line = match.GetMatchAtIndex(4);
161     }
162     return ok;
163 }
164
165 //++ ------------------------------------------------------------------------------------
166 // Details: The invoker requires this function. The command prepares a MI Record Result
167 //          for the work carried out in the Execute().
168 // Type:    Overridden.
169 // Args:    None.
170 // Return:  MIstatus::success - Functional succeeded.
171 //          MIstatus::failure - Functional failed.
172 // Throws:  None.
173 //--
174 bool
175 CMICmdCmdSymbolListLines::Acknowledge()
176 {
177     if (m_lldbResult.GetErrorSize() > 0)
178     {
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;
185     }
186     else
187     {
188         CMIUtilString::VecString_t vecLines;
189         const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
190         const MIuint nLines(strLldbMsg.SplitLines(vecLines));
191
192         // Parse the file from the header.
193         const CMIUtilString &rWantFile(vecLines[0]);
194         CMIUtilString strWantFile;
195         if (!ParseLLDBLineAddressHeader(rWantFile.c_str(), strWantFile))
196         {
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;
203
204             return MIstatus::success;
205         }
206
207         // Parse the line address entries.
208         CMICmnMIValueList miValueList(true);
209         for (MIuint i = 1; i < nLines; ++i)
210         {
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;
217
218             if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine))
219                 continue;
220
221             const CMICmnMIValueConst miValueConst(strAddr);
222             const CMICmnMIValueResult miValueResult("pc", miValueConst);
223             CMICmnMIValueTuple miValueTuple(miValueResult);
224
225             const CMICmnMIValueConst miValueConst2(strLine);
226             const CMICmnMIValueResult miValueResult2("line", miValueConst2);
227             miValueTuple.Add(miValueResult2);
228
229             miValueList.Add(miValueTuple);
230         }
231
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;
236     }
237
238     return MIstatus::success;
239 }
240
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.
245 // Args:    None.
246 // Return:  CMICmdBase * - Pointer to a new command.
247 // Throws:  None.
248 //--
249 CMICmdBase *
250 CMICmdCmdSymbolListLines::CreateSelf()
251 {
252     return new CMICmdCmdSymbolListLines();
253 }