]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/lldb-mi/MICmdCmdSymbol.cpp
Vendor import of lldb trunk r290819:
[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 #include "llvm/ADT/SmallVector.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Regex.h"
17
18 // In-house headers:
19 #include "MICmdArgValFile.h"
20 #include "MICmdCmdSymbol.h"
21 #include "MICmnLLDBDebugSessionInfo.h"
22 #include "MICmnMIResultRecord.h"
23 #include "MICmnMIValueList.h"
24 #include "MICmnMIValueTuple.h"
25
26 //++
27 //------------------------------------------------------------------------------------
28 // Details: CMICmdCmdSymbolListLines constructor.
29 // Type:    Method.
30 // Args:    None.
31 // Return:  None.
32 // Throws:  None.
33 //--
34 CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines()
35     : m_constStrArgNameFile("file") {
36   // Command factory matches this name with that received from the stdin stream
37   m_strMiCmd = "symbol-list-lines";
38
39   // Required by the CMICmdFactory when registering *this command
40   m_pSelfCreatorFn = &CMICmdCmdSymbolListLines::CreateSelf;
41 }
42
43 //++
44 //------------------------------------------------------------------------------------
45 // Details: CMICmdCmdSymbolListLines destructor.
46 // Type:    Overrideable.
47 // Args:    None.
48 // Return:  None.
49 // Throws:  None.
50 //--
51 CMICmdCmdSymbolListLines::~CMICmdCmdSymbolListLines() {}
52
53 //++
54 //------------------------------------------------------------------------------------
55 // Details: The invoker requires this function. The parses the command line
56 // options
57 //          arguments to extract values for each of those arguments.
58 // Type:    Overridden.
59 // Args:    None.
60 // Return:  MIstatus::success - Functional succeeded.
61 //          MIstatus::failure - Functional failed.
62 // Throws:  None.
63 //--
64 bool CMICmdCmdSymbolListLines::ParseArgs() {
65   m_setCmdArgs.Add(new CMICmdArgValFile(m_constStrArgNameFile, true, true));
66   return ParseValidateCmdOptions();
67 }
68
69 //++
70 //------------------------------------------------------------------------------------
71 // Details: The invoker requires this function. The command does work in this
72 // function.
73 //          The command is likely to communicate with the LLDB SBDebugger in
74 //          here.
75 //          Synopsis: -symbol-list-lines file
76 //          Ref:
77 //          http://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Symbol-Query.html#GDB_002fMI-Symbol-Query
78 // Type:    Overridden.
79 // Args:    None.
80 // Return:  MIstatus::success - Functional succeeded.
81 //          MIstatus::failure - Functional failed.
82 // Throws:  None.
83 //--
84 bool CMICmdCmdSymbolListLines::Execute() {
85   CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
86
87   const CMIUtilString &strFilePath(pArgFile->GetValue());
88   const CMIUtilString strCmd(CMIUtilString::Format(
89       "source info --file \"%s\"", strFilePath.AddSlashes().c_str()));
90
91   CMICmnLLDBDebugSessionInfo &rSessionInfo(
92       CMICmnLLDBDebugSessionInfo::Instance());
93   const lldb::ReturnStatus rtn =
94       rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(
95           strCmd.c_str(), m_lldbResult);
96   MIunused(rtn);
97
98   return MIstatus::success;
99 }
100
101 //++
102 //------------------------------------------------------------------------------------
103 // Details: Helper function for parsing the header returned from lldb for the
104 // command:
105 //              target modules dump line-table <file>
106 //          where the header is of the format:
107 //              Line table for /path/to/file in `/path/to/module
108 // Args:    input - (R) Input string to parse.
109 //          file  - (W) String representing the file.
110 // Return:  bool - True = input was parsed successfully, false = input could not
111 // be parsed.
112 // Throws:  None.
113 //--
114 static bool ParseLLDBLineAddressHeader(const char *input, CMIUtilString &file) {
115   // Match LineEntry using regex.
116   static llvm::Regex g_lineentry_header_regex(llvm::StringRef(
117       "^ *Lines found for file (.+) in compilation unit (.+) in `(.+)$"));
118   //                                       ^1=file                  ^2=cu
119   //                                       ^3=module
120
121   llvm::SmallVector<llvm::StringRef, 4> match;
122
123   const bool ok = g_lineentry_header_regex.match(input, &match);
124   if (ok)
125     file = match[1];
126   return ok;
127 }
128
129 //++
130 //------------------------------------------------------------------------------------
131 // Details: Helper function for parsing a line entry returned from lldb for the
132 // command:
133 //              target modules dump line-table <file>
134 //          where the line entry is of the format:
135 //              0x0000000100000e70: /path/to/file:3002[:4]
136 //              addr                file          line column(opt)
137 // Args:    input - (R) Input string to parse.
138 //          addr  - (W) String representing the pc address.
139 //          file  - (W) String representing the file.
140 //          line  - (W) String representing the line.
141 // Return:  bool - True = input was parsed successfully, false = input could not
142 // be parsed.
143 // Throws:  None.
144 //--
145 static bool ParseLLDBLineAddressEntry(const char *input, CMIUtilString &addr,
146                                       CMIUtilString &file,
147                                       CMIUtilString &line) {
148   // Note: Ambiguities arise because the column is optional, and
149   // because : can appear in filenames or as a byte in a multibyte
150   // UTF8 character.  We keep those cases to a minimum by using regex
151   // to work on the string from both the left and right, so that what
152   // is remains is assumed to be the filename.
153
154   // Match LineEntry using regex.
155   static llvm::Regex g_lineentry_nocol_regex(llvm::StringRef(
156       "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$"));
157   static llvm::Regex g_lineentry_col_regex(llvm::StringRef(
158       "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$"));
159   //                     ^1=start         ^2=end               ^3=f ^4=line
160   //                     ^5=:col(opt)
161
162   llvm::SmallVector<llvm::StringRef, 6> match;
163
164   // First try matching the LineEntry with the column,
165   // then try without the column.
166   const bool ok = g_lineentry_col_regex.match(input, &match) ||
167                   g_lineentry_nocol_regex.match(input, &match);
168   if (ok) {
169     addr = match[1];
170     file = match[3];
171     line = match[4];
172   }
173   return ok;
174 }
175
176 //++
177 //------------------------------------------------------------------------------------
178 // Details: The invoker requires this function. The command prepares a MI Record
179 // Result
180 //          for the work carried out in the Execute().
181 // Type:    Overridden.
182 // Args:    None.
183 // Return:  MIstatus::success - Functional succeeded.
184 //          MIstatus::failure - Functional failed.
185 // Throws:  None.
186 //--
187 bool CMICmdCmdSymbolListLines::Acknowledge() {
188   if (m_lldbResult.GetErrorSize() > 0) {
189     const char *pLldbErr = m_lldbResult.GetError();
190     const CMIUtilString strMsg(CMIUtilString(pLldbErr).StripCRAll());
191     const CMICmnMIValueConst miValueConst(strMsg);
192     const CMICmnMIValueResult miValueResult("message", miValueConst);
193     const CMICmnMIResultRecord miRecordResult(
194         m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
195         miValueResult);
196     m_miResultRecord = miRecordResult;
197   } else {
198     CMIUtilString::VecString_t vecLines;
199     const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
200     const MIuint nLines(strLldbMsg.SplitLines(vecLines));
201
202     // Parse the file from the header.
203     const CMIUtilString &rWantFile(vecLines[0]);
204     CMIUtilString strWantFile;
205     if (!ParseLLDBLineAddressHeader(rWantFile.c_str(), strWantFile)) {
206       // Unexpected error - parsing failed.
207       // MI print "%s^error,msg=\"Command '-symbol-list-lines'. Error: Line
208       // address header is absent or has an unknown format.\""
209       const CMICmnMIValueConst miValueConst(CMIUtilString::Format(
210           MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(),
211           "Line address header is absent or has an unknown format."));
212       const CMICmnMIValueResult miValueResult("msg", miValueConst);
213       const CMICmnMIResultRecord miRecordResult(
214           m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
215           miValueResult);
216       m_miResultRecord = miRecordResult;
217
218       return MIstatus::success;
219     }
220
221     // Parse the line address entries.
222     CMICmnMIValueList miValueList(true);
223     for (MIuint i = 1; i < nLines; ++i) {
224       // String looks like:
225       // 0x0000000100000e70: /path/to/file:3[:4]
226       const CMIUtilString &rLine(vecLines[i]);
227       CMIUtilString strAddr;
228       CMIUtilString strFile;
229       CMIUtilString strLine;
230
231       if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine))
232         continue;
233
234       const CMICmnMIValueConst miValueConst(strAddr);
235       const CMICmnMIValueResult miValueResult("pc", miValueConst);
236       CMICmnMIValueTuple miValueTuple(miValueResult);
237
238       const CMICmnMIValueConst miValueConst2(strLine);
239       const CMICmnMIValueResult miValueResult2("line", miValueConst2);
240       miValueTuple.Add(miValueResult2);
241
242       miValueList.Add(miValueTuple);
243     }
244
245     // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]"
246     const CMICmnMIValueResult miValueResult("lines", miValueList);
247     const CMICmnMIResultRecord miRecordResult(
248         m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
249         miValueResult);
250     m_miResultRecord = miRecordResult;
251   }
252
253   return MIstatus::success;
254 }
255
256 //++
257 //------------------------------------------------------------------------------------
258 // Details: Required by the CMICmdFactory when registering *this command. The
259 // factory
260 //          calls this function to create an instance of *this command.
261 // Type:    Static method.
262 // Args:    None.
263 // Return:  CMICmdBase * - Pointer to a new command.
264 // Throws:  None.
265 //--
266 CMICmdBase *CMICmdCmdSymbolListLines::CreateSelf() {
267   return new CMICmdCmdSymbolListLines();
268 }