Index: lit/tools/lldb-mi/symbol/inputs/list-lines-helper.h =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/inputs/list-lines-helper.h @@ -0,0 +1 @@ +void HelpFunction(void); Index: lit/tools/lldb-mi/symbol/inputs/list-lines-helper.c =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/inputs/list-lines-helper.c @@ -0,0 +1,3 @@ +void HelpFunction(void) { + int x = 12345; +} Index: lit/tools/lldb-mi/symbol/inputs/main.c =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/inputs/main.c @@ -0,0 +1,6 @@ +#include "symbol-list-lines.h" + +int main(void) { + int x = GetZero(); + return 0; +} Index: lit/tools/lldb-mi/symbol/inputs/symbol-list-lines.h =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/inputs/symbol-list-lines.h @@ -0,0 +1 @@ +int GetZero(); Index: lit/tools/lldb-mi/symbol/inputs/symbol-list-lines.c =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/inputs/symbol-list-lines.c @@ -0,0 +1,6 @@ +#include "list-lines-helper.h" + +int GetZero() { + HelpFunction(); + return 0; +} Index: lit/tools/lldb-mi/symbol/lit.local.cfg =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/lit.local.cfg @@ -0,0 +1 @@ +config.suffixes = ['.test'] Index: lit/tools/lldb-mi/symbol/symbol-list-lines.test =================================================================== --- /dev/null +++ lit/tools/lldb-mi/symbol/symbol-list-lines.test @@ -0,0 +1,17 @@ +# RUN: %cc -o %t %p/inputs/main.c %p/inputs/symbol-list-lines.c %p/inputs/list-lines-helper.c -g +# RUN: %lldbmi %t < %s | FileCheck %s + +# Test lldb-mi -symbol-list-lines command. + +# Check that we have a valid target created via '%lldbmi %t'. +# CHECK: ^done + +-symbol-list-lines invalid_file.c +# Check a case of invalid file name. +# CHECK: ^error,msg="File Handler. Invalid file name path" + +-symbol-list-lines symbol-list-lines.c +# CHECK: ^done,lines=[{pc="0x{{[0-9A-Fa-f]+}}",line="3"},{pc="0x{{[0-9A-Fa-f]+}}",line="4"},{pc="0x{{[0-9A-Fa-f]+}}",line="5"}] + +-symbol-list-lines list-lines-helper.c +# CHECK: ^done,lines=[{pc="0x{{[0-9A-Fa-f]+}}",line="1"},{pc="0x{{[0-9A-Fa-f]+}}",line="2"},{pc="0x{{[0-9A-Fa-f]+}}",line="3"}] Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -LEVEL = ../../../make - -CXX_SOURCES := main.cpp symbol_list_lines_inline_test.cpp symbol_list_lines_inline_test2.cpp - -include $(LEVEL)/Makefile.rules Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/main.cpp +++ /dev/null @@ -1,18 +0,0 @@ -//===-- main.cpp ------------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -extern int j; -extern int gfunc(int i); -extern int gfunc2(int i); -int -main() -{ // FUNC_main - int i = gfunc(j) + gfunc2(j); - return i == 0; -} Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h +++ /dev/null @@ -1,24 +0,0 @@ -namespace ns -{ -inline int -ifunc(int i) -{ // FUNC_ifunc - return i; -} -struct S -{ - int a; - int b; - S() - : a(3) - , b(4) - { - } - int - mfunc() - { // FUNC_mfunc - return a + b; - } -}; -extern S s; -} Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// Skip lines so we can make sure we're not seeing any lines from -// symbol_list_lines_inline_test.h included in -symbol-list-lines -// symbol_list_lines_inline_test.cpp, by checking that all the lines -// are between 30 and 39. -// 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 -// line 20 -// line 21 -// line 22 -// line 23 -// line 24 -// line 25 -// line 26 -// line 27 -// line 28 -// line 29 -#include "symbol_list_lines_inline_test.h" -int -gfunc(int i) -{ // FUNC_gfunc - return ns::ifunc(i); -} -namespace ns -{ -S s; // STRUCT_s -} Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp =================================================================== --- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test2.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Skip lines so we can make sure we're not seeing any lines from -// symbol_list_lines_inline_test.h included in -symbol-list-lines -// symbol_list_lines_inline_test2.cpp, by checking that all the lines -// are between 30 and 39. -// 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 -// line 20 -// line 21 -// line 22 -// line 23 -// line 24 -// line 25 -// line 26 -// line 27 -// line 28 -// line 29 -#include "symbol_list_lines_inline_test.h" -int j = 2; -int -gfunc2(int i) -{ // FUNC_gfunc2 - i += ns::s.mfunc(); - i += ns::ifunc(i); - return i == 0; // END_gfunc2 -} Index: tools/lldb-mi/MICmdCmdSymbol.h =================================================================== --- tools/lldb-mi/MICmdCmdSymbol.h +++ tools/lldb-mi/MICmdCmdSymbol.h @@ -24,10 +24,10 @@ #pragma once // Third party headers: -#include "lldb/API/SBCommandReturnObject.h" // In-house headers: #include "MICmdBase.h" +#include "MICmnMIValueList.h" //++ //============================================================================ @@ -55,6 +55,6 @@ // Attributes: private: - lldb::SBCommandReturnObject m_lldbResult; + CMICmnMIValueList m_resultList; const CMIUtilString m_constStrArgNameFile; }; Index: tools/lldb-mi/MICmdCmdSymbol.cpp =================================================================== --- tools/lldb-mi/MICmdCmdSymbol.cpp +++ tools/lldb-mi/MICmdCmdSymbol.cpp @@ -10,18 +10,28 @@ // Overview: CMICmdCmdSymbolListLines implementation. // Third Party Headers: -#include "lldb/API/SBCommandInterpreter.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Regex.h" +#include "llvm/ADT/Twine.h" // In-house headers: #include "MICmdArgValFile.h" #include "MICmdCmdSymbol.h" #include "MICmnLLDBDebugSessionInfo.h" #include "MICmnMIResultRecord.h" -#include "MICmnMIValueList.h" #include "MICmnMIValueTuple.h" +#include "MICmnMIValueResult.h" + +namespace { +const CMICmnMIValueTuple +CreateMITuplePCLine(const uint32_t addr, const uint32_t line_number) { + const CMICmnMIValueConst miValueConstAddr("0x" + llvm::Twine::utohexstr(addr).str()); + const CMICmnMIValueConst miValueConstLine(llvm::Twine(line_number).str()); + const CMICmnMIValueResult miValueResultAddr("pc", miValueConstAddr); + const CMICmnMIValueResult miValueResultLine("line", miValueConstLine); + CMICmnMIValueTuple miValueTuple(miValueResultAddr); + miValueTuple.Add(miValueResultLine); + return miValueTuple; +} +} // namespace //++ //------------------------------------------------------------------------------------ @@ -32,7 +42,7 @@ // Throws: None. //-- CMICmdCmdSymbolListLines::CMICmdCmdSymbolListLines() - : m_constStrArgNameFile("file") { + : m_resultList(false), m_constStrArgNameFile("file") { // Command factory matches this name with that received from the stdin stream m_strMiCmd = "symbol-list-lines"; @@ -84,93 +94,51 @@ bool CMICmdCmdSymbolListLines::Execute() { CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile); - const CMIUtilString &strFilePath(pArgFile->GetValue()); - const CMIUtilString strCmd(CMIUtilString::Format( - "source info --file \"%s\"", strFilePath.AddSlashes().c_str())); - - CMICmnLLDBDebugSessionInfo &rSessionInfo( - CMICmnLLDBDebugSessionInfo::Instance()); - const lldb::ReturnStatus rtn = - rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand( - strCmd.c_str(), m_lldbResult); - MIunused(rtn); - - return MIstatus::success; -} - -//++ -//------------------------------------------------------------------------------------ -// Details: Helper function for parsing the header returned from lldb for the -// command: -// target modules dump line-table -// 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 llvm::Regex g_lineentry_header_regex(llvm::StringRef( - "^ *Lines found for file (.+) in compilation unit (.+) in `(.+)$")); - // ^1=file ^2=cu - // ^3=module - - llvm::SmallVector match; - - const bool ok = g_lineentry_header_regex.match(input, &match); - if (ok) - file = match[1]; - return ok; -} - -//++ -//------------------------------------------------------------------------------------ -// Details: Helper function for parsing a line entry returned from lldb for the -// command: -// target modules dump line-table -// 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 llvm::Regex g_lineentry_nocol_regex(llvm::StringRef( - "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$")); - static llvm::Regex g_lineentry_col_regex(llvm::StringRef( - "^ *\\[(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::SmallVector match; + const auto &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + if (rSessionInfo.GetTarget() == rSessionInfo.GetDebugger().GetDummyTarget()) { + SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_TARGET_CURRENT), + m_cmdData.strMiCmd.c_str())); + return MIstatus::failure; + } - // First try matching the LineEntry with the column, - // then try without the column. - const bool ok = g_lineentry_col_regex.match(input, &match) || - g_lineentry_nocol_regex.match(input, &match); - if (ok) { - addr = match[1]; - file = match[3]; - line = match[4]; + const lldb::SBFileSpec source_file_spec(pArgFile->GetValue().c_str(), true); + const char *source_file_name = source_file_spec.GetFilename(); + const char *source_file_directory = source_file_spec.GetDirectory(); + const bool has_path = source_file_directory; + + lldb::SBSymbolContextList sc_cu_list = + CMICmnLLDBDebugSessionInfo::Instance().GetTarget().FindCompileUnits( + source_file_spec); + + bool found_something = false; + for (uint32_t i = 0, e = sc_cu_list.GetSize(); i < e; ++i) { + const lldb::SBCompileUnit cu = + sc_cu_list.GetContextAtIndex(i).GetCompileUnit(); + for (uint32_t j = 0, e = cu.GetNumLineEntries(); j < e; ++j) { + const lldb::SBLineEntry line = cu.GetLineEntryAtIndex(j); + const lldb::SBFileSpec line_spec = line.GetFileSpec(); + if (line_spec.GetFilename() == source_file_name) { + if (has_path && (line_spec.GetDirectory() != source_file_directory)) + continue; + // We don't need a line with start address equals to end one, + // so just skip it. + const lldb::SBAddress line_start_address = line.GetStartAddress(); + const lldb::SBAddress line_end_address = line.GetEndAddress(); + if (line_start_address == line_end_address) + continue; + // We have a matching line. + found_something = true; + m_resultList.Add(CreateMITuplePCLine( + line_start_address.GetFileAddress(), + line.GetLine())); + } + } + } + if (!found_something) { + SetError(MIRSRC(IDS_UTIL_FILE_ERR_INVALID_PATHNAME)); + return MIstatus::failure; } - return ok; + return MIstatus::success; } //++ @@ -185,71 +153,11 @@ // Throws: None. //-- bool CMICmdCmdSymbolListLines::Acknowledge() { - if (m_lldbResult.GetErrorSize() > 0) { - const char *pLldbErr = m_lldbResult.GetError(); - const CMIUtilString strMsg(CMIUtilString(pLldbErr).StripCRAll()); - const CMICmnMIValueConst miValueConst(strMsg); - const CMICmnMIValueResult miValueResult("message", miValueConst); - const CMICmnMIResultRecord miRecordResult( - m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, - miValueResult); - m_miResultRecord = miRecordResult; - } else { - CMIUtilString::VecString_t vecLines; - 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. - // MI print "%s^error,msg=\"Command '-symbol-list-lines'. Error: Line - // address header is absent or has an unknown format.\"" - 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.")); - const CMICmnMIValueResult miValueResult("msg", miValueConst); - const CMICmnMIResultRecord miRecordResult( - m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error, - miValueResult); - m_miResultRecord = miRecordResult; - - return MIstatus::success; - } - - // Parse the line address entries. - CMICmnMIValueList miValueList(true); - for (MIuint i = 1; i < nLines; ++i) { - // String looks like: - // 0x0000000100000e70: /path/to/file:3[:4] - const CMIUtilString &rLine(vecLines[i]); - CMIUtilString strAddr; - CMIUtilString strFile; - CMIUtilString strLine; - - if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine)) - continue; - - const CMICmnMIValueConst miValueConst(strAddr); - const CMICmnMIValueResult miValueResult("pc", miValueConst); - CMICmnMIValueTuple miValueTuple(miValueResult); - - const CMICmnMIValueConst miValueConst2(strLine); - const CMICmnMIValueResult miValueResult2("line", miValueConst2); - miValueTuple.Add(miValueResult2); - - miValueList.Add(miValueTuple); - } - - // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]" - const CMICmnMIValueResult miValueResult("lines", miValueList); - const CMICmnMIResultRecord miRecordResult( - m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, - miValueResult); - m_miResultRecord = miRecordResult; - } - + // MI print "%s^done,lines=[{pc=\"%d\",line=\"%d\"}...]" + const CMICmnMIValueResult miValueResult("lines", m_resultList); + m_miResultRecord = CMICmnMIResultRecord( + m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done, + miValueResult); return MIstatus::success; }