@skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
@skipIfDarwin # pexpect is known to be unreliable on Darwin
@skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
- def test_lldbmi_data_info_line(self):
- """Test that 'lldb-mi --interpreter' works for -data-info-line."""
-
- self.spawnLldbMi(args=None)
-
- # Load executable
- self.runCmd("-file-exec-and-symbols %s" % self.myexe)
- self.expect("\^done")
-
- # Run to main
- self.runCmd("-break-insert -f main")
- self.expect("\^done,bkpt={number=\"1\"")
- self.runCmd("-exec-run")
- self.expect("\^running")
- self.expect("\*stopped,reason=\"breakpoint-hit\"")
-
- # Get the address of main and its line
- self.runCmd("-data-evaluate-expression main")
- self.expect(
- "\^done,value=\"0x[0-9a-f]+ \(a.out`main at main.cpp:[0-9]+\)\"")
- addr = int(self.child.after.split("\"")[1].split(" ")[0], 16)
- line = line_number('main.cpp', '// FUNC_main')
-
- # Test that -data-info-line works for address
- self.runCmd("-data-info-line *%#x" % addr)
- self.expect(
- "\^done,start=\"0x0*%x\",end=\"0x[0-9a-f]+\",file=\".+?main.cpp\",line=\"%d\"" %
- (addr, line))
-
- # Test that -data-info-line works for file:line
- self.runCmd("-data-info-line main.cpp:%d" % line)
- self.expect(
- "\^done,start=\"0x0*%x\",end=\"0x[0-9a-f]+\",file=\".+?main.cpp\",line=\"%d\"" %
- (addr, line))
-
- # Test that -data-info-line fails when invalid address is specified
- self.runCmd("-data-info-line *0x0")
- self.expect(
- "\^error,msg=\"Command 'data-info-line'\. Error: The LineEntry is absent or has an unknown format\.\"")
-
- # Test that -data-info-line fails when file is unknown
- self.runCmd("-data-info-line unknown_file:1")
- self.expect(
- "\^error,msg=\"Command 'data-info-line'\. Error: The LineEntry is absent or has an unknown format\.\"")
-
- # Test that -data-info-line fails when line has invalid format
- self.runCmd("-data-info-line main.cpp:bad_line")
- self.expect(
- "\^error,msg=\"error: invalid line number string 'bad_line'")
- self.runCmd("-data-info-line main.cpp:0")
- self.expect("\^error,msg=\"error: zero is an invalid line number")
-
- @skipIfRemote # We do not currently support remote debugging via the MI.
- @skipIfWindows # llvm.org/pr24452: Get lldb-mi tests working on Windows
- @skipIfDarwin # pexpect is known to be unreliable on Darwin
- @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races
def test_lldbmi_data_evaluate_expression(self):
"""Test that 'lldb-mi --interpreter' works for -data-evaluate-expression."""
// CMICmdCmdDataInfoLine implementation.
// Third Party Headers:
-#include "lldb/API/SBCommandInterpreter.h"
#include "lldb/API/SBInstruction.h"
#include "lldb/API/SBInstructionList.h"
#include "lldb/API/SBStream.h"
#include "lldb/API/SBThread.h"
-#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/Regex.h"
#include <inttypes.h> // For PRIx64
+#include <string>
// In-house headers:
#include "MICmdArgValConsume.h"
#include "MICmnMIResultRecord.h"
#include "MICmnMIValueConst.h"
+namespace {
+CMIUtilString IntToHexAddrStr(uint32_t number) {
+ return CMIUtilString("0x" + llvm::Twine::utohexstr(number).str());
+}
+} // namespace
+
//++
//------------------------------------------------------------------------------------
// Details: CMICmdCmdDataEvaluateExpression constructor.
// Throws: None.
//--
CMICmdCmdDataInfoLine::CMICmdCmdDataInfoLine()
- : m_constStrArgLocation("location") {
+ : m_constStrArgLocation("location"),
+ m_resultRecord(m_cmdData.strMiCmdToken,
+ CMICmnMIResultRecord::eResultClass_Done) {
// Command factory matches this name with that received from the stdin stream
m_strMiCmd = "data-info-line";
// Return: None.
// Throws: None.
//--
-CMICmdCmdDataInfoLine::~CMICmdCmdDataInfoLine() {}
+CMICmdCmdDataInfoLine::~CMICmdCmdDataInfoLine() = default;
//++
//------------------------------------------------------------------------------------
bool CMICmdCmdDataInfoLine::Execute() {
CMICMDBASE_GETOPTION(pArgLocation, String, m_constStrArgLocation);
+ lldb::SBLineEntry line;
+ bool found_line = false;
const CMIUtilString &strLocation(pArgLocation->GetValue());
- CMIUtilString strCmdOptionsLocation;
+ lldb::SBTarget target = CMICmnLLDBDebugSessionInfo::Instance().GetTarget();
+
if (strLocation.at(0) == '*') {
// Parse argument:
// *0x12345
- // ^^^^^^^ -- address
- const CMIUtilString strAddress(strLocation.substr(1));
- strCmdOptionsLocation =
- CMIUtilString::Format("--address %s", strAddress.c_str());
+ // ^^^^^^^^^ -- address
+ lldb::addr_t address = 0x0;
+ if (llvm::StringRef(strLocation.substr(1)).getAsInteger(0, address)) {
+ SetError(CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_SOME_ERROR),
+ m_cmdData.strMiCmd.c_str(),
+ "Failed to parse address."));
+ return MIstatus::failure;
+ }
+ line = target.ResolveFileAddress(address).GetLineEntry();
+ // Check that found line is valid.
+ if (line.GetLine())
+ found_line = true;
} else {
const size_t nLineStartPos = strLocation.rfind(':');
if ((nLineStartPos == std::string::npos) || (nLineStartPos == 0) ||
(nLineStartPos == strLocation.length() - 1)) {
- SetError(
- CMIUtilString::Format(MIRSRC(IDS_CMD_ERR_INVALID_LOCATION_FORMAT),
- m_cmdData.strMiCmd.c_str(), strLocation.c_str())
- .c_str());
+ SetError(CMIUtilString::Format(
+ MIRSRC(IDS_CMD_ERR_INVALID_LOCATION_FORMAT),
+ m_cmdData.strMiCmd.c_str(), strLocation.c_str()));
return MIstatus::failure;
}
// Parse argument:
// hello.cpp:5
// ^^^^^^^^^ -- file
// ^ -- line
- const CMIUtilString strFile(strLocation.substr(0, nLineStartPos));
- const CMIUtilString strLine(strLocation.substr(nLineStartPos + 1));
- strCmdOptionsLocation =
- CMIUtilString::Format("--file \"%s\" --line %s",
- strFile.AddSlashes().c_str(), strLine.c_str());
+ const CMIUtilString &strFile(strLocation.substr(0, nLineStartPos));
+ uint32_t numLine = 0;
+ llvm::StringRef(strLocation.substr(nLineStartPos + 1))
+ .getAsInteger(0, numLine);
+ lldb::SBSymbolContextList sc_cu_list =
+ target.FindCompileUnits(lldb::SBFileSpec(strFile.c_str(), false));
+ for (uint32_t i = 0, e = sc_cu_list.GetSize(); i < e; ++i) {
+ const lldb::SBCompileUnit &cu =
+ sc_cu_list.GetContextAtIndex(i).GetCompileUnit();
+ // Break if we have already found requested line.
+ if (found_line)
+ break;
+ for (uint32_t j = 0, e = cu.GetNumLineEntries(); j < e; ++j) {
+ const lldb::SBLineEntry &curLine = cu.GetLineEntryAtIndex(j);
+ if (curLine.GetLine() == numLine) {
+ line = curLine;
+ found_line = true;
+ break;
+ }
+ }
+ }
}
- const CMIUtilString strCmd(CMIUtilString::Format(
- "target modules lookup -v %s", strCmdOptionsLocation.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 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 llvm::Regex g_lineentry_nocol_regex(llvm::StringRef(
- "^ *LineEntry: \\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$"));
- static llvm::Regex g_lineentry_col_regex(
- llvm::StringRef("^ *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::SmallVector<llvm::StringRef, 6> match;
-
- // 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) {
- start = match[1];
- end = match[2];
- file = match[3];
- line = match[4];
+ if (!found_line) {
+ SetError(CMIUtilString::Format(
+ MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(),
+ "The LineEntry is absent or has an unknown format."));
+ return MIstatus::failure;
}
- return ok;
+ // Start address.
+ m_resultRecord.Add(CMICmnMIValueResult(
+ "start", CMICmnMIValueConst(IntToHexAddrStr(
+ line.GetStartAddress().GetFileAddress()))));
+ // End address.
+ m_resultRecord.Add(CMICmnMIValueResult(
+ "end", CMICmnMIValueConst(IntToHexAddrStr(
+ line.GetEndAddress().GetFileAddress()))));
+ // File.
+ std::unique_ptr<char[]> upPath(new char[PATH_MAX]);
+ line.GetFileSpec().GetPath(upPath.get(), PATH_MAX);
+ m_resultRecord.Add(CMICmnMIValueResult(
+ "file", CMICmnMIValueConst(CMIUtilString(upPath.get()))));
+ // Line.
+ m_resultRecord.Add(CMICmnMIValueResult(
+ "line", CMICmnMIValueConst(std::to_string(line.GetLine()))));
+ return MIstatus::success;
}
//++
// Throws: None.
//--
bool CMICmdCmdDataInfoLine::Acknowledge() {
- if (m_lldbResult.GetErrorSize() > 0) {
- const CMICmnMIValueConst miValueConst(m_lldbResult.GetError());
- const CMICmnMIValueResult miValueResult("msg", miValueConst);
- const CMICmnMIResultRecord miRecordResult(
- m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
- miValueResult);
- m_miResultRecord = miRecordResult;
- return MIstatus::success;
- } else if (m_lldbResult.GetOutputSize() > 0) {
- CMIUtilString::VecString_t vecLines;
- const CMIUtilString strLldbMsg(m_lldbResult.GetOutput());
- const MIuint nLines(strLldbMsg.SplitLines(vecLines));
-
- for (MIuint i = 0; i < nLines; ++i) {
- // String looks like:
- // LineEntry: \[0x0000000100000f37-0x0000000100000f45\):
- // /path/to/file:3[:1]
- const CMIUtilString &rLine(vecLines[i]);
- CMIUtilString strStart;
- CMIUtilString strEnd;
- CMIUtilString strFile;
- CMIUtilString strLine;
-
- if (!ParseLLDBLineEntry(rLine.c_str(), strStart, strEnd, strFile,
- strLine))
- continue;
-
- const CMICmnMIValueConst miValueConst(strStart);
- const CMICmnMIValueResult miValueResult("start", miValueConst);
- CMICmnMIResultRecord miRecordResult(
- m_cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Done,
- miValueResult);
- const CMICmnMIValueConst miValueConst2(strEnd);
- const CMICmnMIValueResult miValueResult2("end", miValueConst2);
- miRecordResult.Add(miValueResult2);
- const CMICmnMIValueConst miValueConst3(strFile);
- const CMICmnMIValueResult miValueResult3("file", miValueConst3);
- miRecordResult.Add(miValueResult3);
- const CMICmnMIValueConst miValueConst4(strLine);
- const CMICmnMIValueResult miValueResult4("line", miValueConst4);
- miRecordResult.Add(miValueResult4);
-
- // MI print "%s^done,start=\"%d\",end=\"%d\"",file=\"%s\",line=\"%d\"
- m_miResultRecord = miRecordResult;
-
- return MIstatus::success;
- }
- }
-
- // MI print "%s^error,msg=\"Command '-data-info-line'. Error: The LineEntry is
- // absent or has an unknown format.\""
- const CMICmnMIValueConst miValueConst(CMIUtilString::Format(
- MIRSRC(IDS_CMD_ERR_SOME_ERROR), m_cmdData.strMiCmd.c_str(),
- "The LineEntry 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;
-
+ m_miResultRecord = m_resultRecord;
return MIstatus::success;
}