dawn updated this revision to Diff 34406.
Repository:
rL LLVM
http://reviews.llvm.org/D12115
Files:
test/tools/lldb-mi/symbol/Makefile
test/tools/lldb-mi/symbol/TestMiSymbol.py
test/tools/lldb-mi/symbol/main.cpp
test/tools/lldb-mi/symbol/x.cpp
test/tools/lldb-mi/symbol/x.h
tools/lldb-mi/MICmdCmdData.cpp
tools/lldb-mi/MICmdCmdSymbol.cpp
tools/lldb-mi/MIUtilString.cpp
tools/lldb-mi/MIUtilString.h
Index: tools/lldb-mi/MIUtilString.h
===================================================================
--- tools/lldb-mi/MIUtilString.h
+++ tools/lldb-mi/MIUtilString.h
@@ -43,6 +43,7 @@
/* ctor */ CMIUtilString();
/* ctor */ CMIUtilString(const char *vpData);
/* ctor */ CMIUtilString(const char *const *vpData);
+ /* ctor */ CMIUtilString(const char *vpData, size_t nLen);
//
bool ExtractNumber(MIint64 &vwrNumber) const;
CMIUtilString FindAndReplace(const CMIUtilString &vFind, const CMIUtilString &vReplaceWith) const;
Index: tools/lldb-mi/MIUtilString.cpp
===================================================================
--- tools/lldb-mi/MIUtilString.cpp
+++ tools/lldb-mi/MIUtilString.cpp
@@ -55,6 +55,20 @@
}
//++ ------------------------------------------------------------------------------------
+// Details: CMIUtilString constructor.
+// Type: Method.
+// Args: vpData - Pointer to UTF8 text data.
+// nLen - Length of string.
+// Return: None.
+// Throws: None.
+//--
+CMIUtilString::CMIUtilString(const char *vpData, size_t nLen)
+ : std::string(vpData, nLen)
+{
+}
+
+
+//++ ------------------------------------------------------------------------------------
// Details: CMIUtilString assignment operator.
// Type: Method.
// Args: vpRhs - Pointer to UTF8 text data.
Index: tools/lldb-mi/MICmdCmdSymbol.cpp
===================================================================
--- tools/lldb-mi/MICmdCmdSymbol.cpp
+++ tools/lldb-mi/MICmdCmdSymbol.cpp
@@ -11,6 +11,9 @@
// Third Party Headers:
#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "llvm/ADT/StringRef.h"
// In-house headers:
#include "MICmdArgValFile.h"
@@ -20,6 +23,8 @@
#include "MICmnMIValueList.h"
#include "MICmnMIValueTuple.h"
+using namespace lldb_private;
+
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdSymbolListLines constructor.
// Type: Method.
@@ -81,6 +86,10 @@
CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
const CMIUtilString &strFilePath(pArgFile->GetValue());
+ // FIXME: this won't work for header files! To try and use existing
+ // commands to get this to work for header files would be too slow.
+ // Instead, this code should be rewritten to use APIs and/or support
+ // should be added to lldb which would work for header files.
const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-table \"%s\"", strFilePath.AddSlashes().c_str()));
CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
@@ -91,6 +100,100 @@
}
//++ ------------------------------------------------------------------------------------
+// Details: Helper function for parsing the header returned from lldb for the command:
+// target modules dump line-table <file>
+// where the header is of the format:
+// Line table for /path/to/file in `/path/to/module
+// Args: input - (R) Input string to parse.
+// file - (W) String representing the file.
+// Return: bool - True = input was parsed successfully, false = input could not be parsed.
+// Throws: None.
+//--
+static bool
+ParseLLDBLineAddressHeader (const char *input, CMIUtilString &file)
+{
+ // Match LineEntry using regex.
+ static RegularExpression g_lineentry_header_regex(
+ "^ *Line table for (.+) in `(.+)$");
+ // ^1=file
+
+ llvm::StringRef fileRef;
+ RegularExpression::Match match(3);
+
+ if (g_lineentry_header_regex.Execute (input, &match))
+ {
+ match.GetMatchAtIndex(input, 1, fileRef);
+ }
+ else
+ {
+ // No match.
+ return false;
+ }
+ file = CMIUtilString(fileRef.data(), fileRef.size());
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
+// Details: Helper function for parsing a line entry returned from lldb for the command:
+// target modules dump line-table <file>
+// where the line entry is of the format:
+// 0x0000000100000e70: /path/to/file:3002[:4]
+// addr file line column(opt)
+// Args: input - (R) Input string to parse.
+// addr - (W) String representing the pc address.
+// file - (W) String representing the file.
+// line - (W) String representing the line.
+// Return: bool - True = input was parsed successfully, false = input could not be parsed.
+// Throws: None.
+//--
+static bool
+ParseLLDBLineAddressEntry (const char *input, CMIUtilString &addr,
+ CMIUtilString &file, CMIUtilString &line)
+{
+ // Note: Ambiguities arise because the column is optional, and
+ // because : can appear in filenames or as a byte in a multibyte
+ // UTF8 character. We keep those cases to a minimum by using regex
+ // to work on the string from both the left and right, so that what
+ // is remains is assumed to be the filename.
+
+ // Match LineEntry using regex.
+ static RegularExpression g_lineentry_nocol_regex(
+ "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+)$");
+ static RegularExpression g_lineentry_col_regex(
+ "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+):[0-9]+$");
+ // ^1=addr ^2=f ^3=line ^4=:col(opt)
+
+ llvm::StringRef addrRef;
+ llvm::StringRef fileRef;
+ llvm::StringRef lineRef;
+ RegularExpression::Match match(4);
+
+ // First try matching the LineEntry with the column.
+ if (g_lineentry_col_regex.Execute (input, &match))
+ {
+ match.GetMatchAtIndex(input, 1, addrRef);
+ match.GetMatchAtIndex(input, 2, fileRef);
+ match.GetMatchAtIndex(input, 3, lineRef);
+ }
+ // Then try without the column.
+ else if (g_lineentry_nocol_regex.Execute (input, &match))
+ {
+ match.GetMatchAtIndex(input, 1, addrRef);
+ match.GetMatchAtIndex(input, 2, fileRef);
+ match.GetMatchAtIndex(input, 3, lineRef);
+ }
+ else
+ {
+ // No match.
+ return false;
+ }
+ addr = CMIUtilString(addrRef.data(), addrRef.size());
+ file = CMIUtilString(fileRef.data(), fileRef.size());
+ line = CMIUtilString(lineRef.data(), lineRef.size());
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
@@ -117,6 +220,17 @@
const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
const MIuint nLines(strLldbMsg.SplitLines(vecLines));
+ // Parse the file from the header.
+ const CMIUtilString &rWantFile(vecLines[0]);
+ CMIUtilString strWantFile;
+ if (!ParseLLDBLineAddressHeader (rWantFile.c_str(), strWantFile))
+ {
+ // Unexpected error - parsing failed.
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_CMD_RUN_BUT_NO_ACTION)));
+ return MIstatus::failure;
+ }
+
+ // Parse the line address entries.
CMICmnMIValueList miValueList(true);
for (MIuint i = 1; i < nLines; ++i)
{
@@ -123,23 +237,21 @@
// String looks like:
// 0x0000000100000e70: /path/to/file:3[:4]
const CMIUtilString &rLine(vecLines[i]);
+ CMIUtilString strAddr;
+ CMIUtilString strFile;
+ CMIUtilString strLine;
- // 0x0000000100000e70: /path/to/file:3[:4]
- // ^^^^^^^^^^^^^^^^^^ -- pc
- const size_t nAddrEndPos = rLine.find(':');
- const CMIUtilString strAddr(rLine.substr(0, nAddrEndPos).c_str());
+ if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine))
+ continue;
+
+ // Skip entries which don't match the desired source.
+ if (strWantFile != strFile)
+ continue;
+
const CMICmnMIValueConst miValueConst(strAddr);
const CMICmnMIValueResult miValueResult("pc", miValueConst);
CMICmnMIValueTuple miValueTuple(miValueResult);
- // 0x0000000100000e70: /path/to/file:3[:4]
- // ^ -- line
- const size_t nLineOrColumnStartPos = rLine.rfind(':');
- const CMIUtilString strLineOrColumn(rLine.substr(nLineOrColumnStartPos + 1).c_str());
- const size_t nPathOrLineStartPos = rLine.rfind(':', nLineOrColumnStartPos - 1);
- const size_t nPathOrLineLen = nLineOrColumnStartPos - nPathOrLineStartPos - 1;
- const CMIUtilString strPathOrLine(rLine.substr(nPathOrLineStartPos + 1, nPathOrLineLen).c_str());
- const CMIUtilString strLine(strPathOrLine.IsNumber() ? strPathOrLine : strLineOrColumn);
const CMICmnMIValueConst miValueConst2(strLine);
const CMICmnMIValueResult miValueResult2("line", miValueConst2);
miValueTuple.Add(miValueResult2);
Index: tools/lldb-mi/MICmdCmdData.cpp
===================================================================
--- tools/lldb-mi/MICmdCmdData.cpp
+++ tools/lldb-mi/MICmdCmdData.cpp
@@ -25,6 +25,8 @@
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBStream.h"
+#include "lldb/Core/RegularExpression.h"
+#include "llvm/ADT/StringRef.h"
// In-house headers:
#include "MICmdCmdData.h"
@@ -43,6 +45,8 @@
#include "MICmnLLDBDebugSessionInfoVarObj.h"
#include "MICmnLLDBUtilSBValue.h"
+using namespace lldb_private;
+
//++ ------------------------------------------------------------------------------------
// Details: CMICmdCmdDataEvaluateExpression constructor.
// Type: Method.
@@ -1686,6 +1690,71 @@
}
//++ ------------------------------------------------------------------------------------
+// Details: Helper function for parsing a line entry returned from lldb for the command:
+// target modules lookup -v <location>
+// where the line entry is of the format:
+// LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/file:3[:1]
+// start end file line column(opt)
+// Args: input - (R) Input string to parse.
+// start - (W) String representing the start address.
+// end - (W) String representing the end address.
+// file - (W) String representing the file.
+// line - (W) String representing the line.
+// Return: bool - True = input was parsed successfully, false = input could not be parsed.
+// Throws: None.
+//--
+static bool
+ParseLLDBLineEntry (const char *input, CMIUtilString &start, CMIUtilString &end,
+ CMIUtilString &file, CMIUtilString &line)
+{
+ // Note: Ambiguities arise because the column is optional, and
+ // because : can appear in filenames or as a byte in a multibyte
+ // UTF8 character. We keep those cases to a minimum by using regex
+ // to work on the string from both the left and right, so that what
+ // is remains is assumed to be the filename.
+
+ // Match LineEntry using regex.
+ static RegularExpression g_lineentry_nocol_regex(
+ "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$");
+ static RegularExpression g_lineentry_col_regex(
+ "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$");
+ // ^1=start ^2=end ^3=f ^4=line ^5=:col(opt)
+
+ llvm::StringRef startRef;
+ llvm::StringRef endRef;
+ llvm::StringRef fileRef;
+ llvm::StringRef lineRef;
+ RegularExpression::Match match(5);
+
+ // First try matching the LineEntry with the column.
+ if (g_lineentry_col_regex.Execute (input, &match))
+ {
+ match.GetMatchAtIndex(input, 1, startRef);
+ match.GetMatchAtIndex(input, 2, endRef);
+ match.GetMatchAtIndex(input, 3, fileRef);
+ match.GetMatchAtIndex(input, 4, lineRef);
+ }
+ // Then try without the column.
+ else if (g_lineentry_nocol_regex.Execute (input, &match))
+ {
+ match.GetMatchAtIndex(input, 1, startRef);
+ match.GetMatchAtIndex(input, 2, endRef);
+ match.GetMatchAtIndex(input, 3, fileRef);
+ match.GetMatchAtIndex(input, 4, lineRef);
+ }
+ else
+ {
+ // No match.
+ return false;
+ }
+ start = CMIUtilString(startRef.data(), startRef.size());
+ end = CMIUtilString(endRef.data(), endRef.size());
+ file = CMIUtilString(fileRef.data(), fileRef.size());
+ line = CMIUtilString(lineRef.data(), lineRef.size());
+ return true;
+}
+
+//++ ------------------------------------------------------------------------------------
// Details: The invoker requires this function. The command prepares a MI Record Result
// for the work carried out in the Execute().
// Type: Overridden.
@@ -1716,58 +1785,25 @@
// String looks like:
// LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
const CMIUtilString &rLine(vecLines[i]);
+ CMIUtilString strStart;
+ CMIUtilString strEnd;
+ CMIUtilString strFile;
+ CMIUtilString strLine;
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
- // ^^^^^^^^^ -- property
- const size_t nPropertyStartPos = rLine.find_first_not_of(' ');
- const size_t nPropertyEndPos = rLine.find(':');
- const size_t nPropertyLen = nPropertyEndPos - nPropertyStartPos;
- const CMIUtilString strProperty(rLine.substr(nPropertyStartPos, nPropertyLen).c_str());
-
- // Skip all except LineEntry
- if (!CMIUtilString::Compare(strProperty, "LineEntry"))
+ if (!ParseLLDBLineEntry(rLine.c_str(), strStart, strEnd, strFile, strLine))
continue;
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
- // ^^^^^^^^^^^^^^^^^^ -- start address
- const size_t nStartAddressStartPos = rLine.find('[');
- const size_t nStartAddressEndPos = rLine.find('-');
- const size_t nStartAddressLen = nStartAddressEndPos - nStartAddressStartPos - 1;
- const CMIUtilString strStartAddress(rLine.substr(nStartAddressStartPos + 1, nStartAddressLen).c_str());
- const CMICmnMIValueConst miValueConst(strStartAddress);
+ const CMICmnMIValueConst miValueConst(strStart);
const CMICmnMIValueResult miValueResult("start", miValueConst);
- CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, miValueResult);
-
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
- // ^^^^^^^^^^^^^^^^^^ -- end address
- const size_t nEndAddressEndPos = rLine.find(')');
- const size_t nEndAddressLen = nEndAddressEndPos - nStartAddressEndPos - 1;
- const CMIUtilString strEndAddress(rLine.substr(nStartAddressEndPos + 1, nEndAddressLen).c_str());
- const CMICmnMIValueConst miValueConst2(strEndAddress);
+ CMICmnMIResultRecord miRecordResult(m_cmdData.strMiCmdToken,
+ CMICmnMIResultRecord::eResultClass_Done,
+ miValueResult);
+ const CMICmnMIValueConst miValueConst2(strEnd);
const CMICmnMIValueResult miValueResult2("end", miValueConst2);
miRecordResult.Add(miValueResult2);
-
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
- // ^^^^^^^^^^^^^ -- file
- // ^ -- line
- // ^ -- column (optional)
- const size_t nFileStartPos = rLine.find_first_not_of(' ', nEndAddressEndPos + 2);
- const size_t nFileOrLineEndPos = rLine.rfind(':');
- const size_t nFileOrLineStartPos = rLine.rfind(':', nFileOrLineEndPos - 1);
- const size_t nFileEndPos = nFileStartPos < nFileOrLineStartPos ? nFileOrLineStartPos : nFileOrLineEndPos;
- const size_t nFileLen = nFileEndPos - nFileStartPos;
- const CMIUtilString strFile(rLine.substr(nFileStartPos, nFileLen).c_str());
const CMICmnMIValueConst miValueConst3(strFile);
const CMICmnMIValueResult miValueResult3("file", miValueConst3);
miRecordResult.Add(miValueResult3);
-
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\): /path/to/file:3[:1]
- // ^ -- line
- const size_t nLineStartPos = nFileEndPos + 1;
- const size_t nLineEndPos = rLine.find(':', nLineStartPos);
- const size_t nLineLen = nLineEndPos != std::string::npos ? nLineEndPos - nLineStartPos
- : std::string::npos;
- const CMIUtilString strLine(rLine.substr(nLineStartPos, nLineLen).c_str());
const CMICmnMIValueConst miValueConst4(strLine);
const CMICmnMIValueResult miValueResult4("line", miValueConst4);
miRecordResult.Add(miValueResult4);
Index: test/tools/lldb-mi/symbol/x.h
===================================================================
--- test/tools/lldb-mi/symbol/x.h
+++ test/tools/lldb-mi/symbol/x.h
@@ -0,0 +1,14 @@
+namespace ns {
+ inline int ifunc(int i) {
+ return i;
+ }
+ struct S {
+ int a;
+ int b;
+ S() : a(3), b(4) {}
+ int mfunc() {
+ return a + b;
+ }
+ };
+ extern S s;
+}
Index: test/tools/lldb-mi/symbol/x.cpp
===================================================================
--- test/tools/lldb-mi/symbol/x.cpp
+++ test/tools/lldb-mi/symbol/x.cpp
@@ -0,0 +1,27 @@
+// Skip lines so we can make sure we're not seeing any lines from x.h
+// included in -symbol-list-lines x.cpp, by checking that all the lines
+// are between 20 and 29.
+// line 4
+// line 5
+// line 6
+// line 7
+// line 8
+// line 9
+// line 10
+// line 11
+// line 12
+// line 13
+// line 14
+// line 15
+// line 16
+// line 17
+// line 18
+// line 19
+#include "x.h"
+int j = 2;
+int gfunc(int i) { // FUNC_gfunc
+ return ++i;
+}
+namespace ns {
+ S s; // STRUCT_s
+}
Index: test/tools/lldb-mi/symbol/main.cpp
===================================================================
--- test/tools/lldb-mi/symbol/main.cpp
+++ test/tools/lldb-mi/symbol/main.cpp
@@ -7,8 +7,23 @@
//
//===----------------------------------------------------------------------===//
-int
-main(int argc, char const *argv[])
-{ // FUNC_main
- return 0;
+// Skip lines so we can make sure we're not seeing any lines from x.h
+// included in -symbol-list-lines main.cpp, by checking that all the lines
+// are between 20 and 29.
+// line 13
+// line 14
+// line 15
+// line 16
+// line 17
+// line 18
+// line 19
+#include "x.h"
+extern int j;
+extern int gfunc(int i);
+int i;
+int main() { // FUNC_main
+ i = gfunc(j);
+ i += ns::s.mfunc();
+ i += ns::ifunc(i);
+ return i == 0; // END_main
}
Index: test/tools/lldb-mi/symbol/TestMiSymbol.py
===================================================================
--- test/tools/lldb-mi/symbol/TestMiSymbol.py
+++ test/tools/lldb-mi/symbol/TestMiSymbol.py
@@ -39,6 +39,19 @@
self.runCmd("-symbol-list-lines main.cpp")
self.expect("\^done,lines=\[\{pc=\"0x0*%x\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d+\"\})+\]" % (addr, line))
+ # Test that -symbol-list-lines doesn't include lines from other sources
+ # by checking the first and last line, and making sure the other lines
+ # are between 20 and 29.
+ sline = line_number('main.cpp', '// FUNC_main')
+ eline = line_number('main.cpp', '// END_main')
+ self.runCmd("-symbol-list-lines main.cpp")
+ self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"2\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline))
+ ##FIXME: This doesn't work for x.cpp due to clang bug llvm.org/pr24716
+ ##sline = line_number('x.cpp', '// FUNC_gfunc')
+ ##eline = line_number('x.cpp', '// STRUCT_s')
+ ##self.runCmd("-symbol-list-lines x.cpp")
+ ##self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"2\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline))
+
# Test that -symbol-list-lines fails when file doesn't exist
self.runCmd("-symbol-list-lines unknown_file")
self.expect("\^error,message=\"warning: No source filenames matched 'unknown_file'\. error: no source filenames matched any command arguments \"")
Index: test/tools/lldb-mi/symbol/Makefile
===================================================================
--- test/tools/lldb-mi/symbol/Makefile
+++ test/tools/lldb-mi/symbol/Makefile
@@ -1,5 +1,5 @@
LEVEL = ../../../make
-CXX_SOURCES := main.cpp
+CXX_SOURCES := main.cpp x.cpp
include $(LEVEL)/Makefile.rules
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits