summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/API/SBSourceManager.h5
-rw-r--r--lldb/include/lldb/Core/Debugger.h6
-rw-r--r--lldb/include/lldb/Core/Disassembler.h8
-rw-r--r--lldb/include/lldb/Core/SourceManager.h22
-rw-r--r--lldb/include/lldb/lldb-enumerations.h7
-rw-r--r--lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py4
-rw-r--r--lldb/packages/Python/lldbsuite/test/lldbtest.py4
-rw-r--r--lldb/packages/Python/lldbsuite/test/settings/TestSettings.py1
-rw-r--r--lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py70
-rw-r--r--lldb/scripts/interface/SBSourceManager.i7
-rw-r--r--lldb/source/API/SBSourceManager.cpp25
-rw-r--r--lldb/source/Commands/CommandObjectSource.cpp21
-rw-r--r--lldb/source/Core/Debugger.cpp51
-rw-r--r--lldb/source/Core/Disassembler.cpp6
-rw-r--r--lldb/source/Core/SourceManager.cpp152
-rw-r--r--lldb/source/Target/StackFrame.cpp3
16 files changed, 341 insertions, 51 deletions
diff --git a/lldb/include/lldb/API/SBSourceManager.h b/lldb/include/lldb/API/SBSourceManager.h
index 989764cb1bf..6f1c49504d5 100644
--- a/lldb/include/lldb/API/SBSourceManager.h
+++ b/lldb/include/lldb/API/SBSourceManager.h
@@ -30,6 +30,11 @@ public:
const lldb::SBFileSpec &file, uint32_t line, uint32_t context_before,
uint32_t context_after, const char *current_line_cstr, lldb::SBStream &s);
+ size_t DisplaySourceLinesWithLineNumbersAndColumn(
+ const lldb::SBFileSpec &file, uint32_t line, uint32_t column,
+ uint32_t context_before, uint32_t context_after,
+ const char *current_line_cstr, lldb::SBStream &s);
+
protected:
friend class SBCommandInterpreter;
friend class SBDebugger;
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index ec269957943..573c10b0a0f 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -238,6 +238,12 @@ public:
bool SetUseColor(bool use_color);
+ lldb::StopShowColumn GetStopShowColumn() const;
+
+ const FormatEntity::Entry *GetStopShowColumnAnsiPrefix() const;
+
+ const FormatEntity::Entry *GetStopShowColumnAnsiSuffix() const;
+
uint32_t GetStopSourceLineCount(bool before) const;
StopDisassemblyType GetStopDisassemblyDisplay() const;
diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index 81e17f9fb0e..73dbc4285f2 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -428,15 +428,16 @@ protected:
struct SourceLine {
FileSpec file;
uint32_t line;
+ uint32_t column;
- SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER) {}
+ SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER), column(0) {}
bool operator==(const SourceLine &rhs) const {
- return file == rhs.file && line == rhs.line;
+ return file == rhs.file && line == rhs.line && rhs.column == column;
}
bool operator!=(const SourceLine &rhs) const {
- return file != rhs.file || line != rhs.line;
+ return file != rhs.file || line != rhs.line || column != rhs.column;
}
bool IsValid() const { return line != LLDB_INVALID_LINE_NUMBER; }
@@ -486,6 +487,7 @@ protected:
SourceLine sl;
sl.file = line.file;
sl.line = line.line;
+ sl.column = line.column;
return ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, sl);
};
diff --git a/lldb/include/lldb/Core/SourceManager.h b/lldb/include/lldb/Core/SourceManager.h
index 923b555c63c..c279491ddc4 100644
--- a/lldb/include/lldb/Core/SourceManager.h
+++ b/lldb/include/lldb/Core/SourceManager.h
@@ -32,12 +32,14 @@ public:
public:
File(const FileSpec &file_spec, Target *target);
+ File(const FileSpec &file_spec, lldb::DebuggerSP debugger_sp);
~File();
void UpdateIfNeeded();
- size_t DisplaySourceLines(uint32_t line, uint32_t context_before,
- uint32_t context_after, Stream *s);
+ size_t DisplaySourceLines(uint32_t line, uint32_t column,
+ uint32_t context_before, uint32_t context_after,
+ Stream *s);
void FindLinesMatchingRegex(RegularExpression &regex, uint32_t start_line,
uint32_t end_line,
std::vector<uint32_t> &match_lines);
@@ -76,6 +78,10 @@ public:
lldb::DataBufferSP m_data_sp;
typedef std::vector<uint32_t> LineOffsets;
LineOffsets m_offsets;
+ lldb::DebuggerWP m_debugger_wp;
+
+ private:
+ void CommonInitializer(const FileSpec &file_spec, Target *target);
};
#endif // SWIG
@@ -114,14 +120,16 @@ public:
FileSP GetLastFile() { return m_last_file_sp; }
- size_t DisplaySourceLinesWithLineNumbers(
- const FileSpec &file, uint32_t line, uint32_t context_before,
- uint32_t context_after, const char *current_line_cstr, Stream *s,
- const SymbolContextList *bp_locs = nullptr);
+ size_t
+ DisplaySourceLinesWithLineNumbers(const FileSpec &file, uint32_t line,
+ uint32_t column, uint32_t context_before,
+ uint32_t context_after,
+ const char *current_line_cstr, Stream *s,
+ const SymbolContextList *bp_locs = nullptr);
// This variant uses the last file we visited.
size_t DisplaySourceLinesWithLineNumbersUsingLastFile(
- uint32_t start_line, uint32_t count, uint32_t curr_line,
+ uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
const char *current_line_cstr, Stream *s,
const SymbolContextList *bp_locs = nullptr);
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 2e51165a3b8..3292ba7e6d0 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -462,6 +462,13 @@ enum DynamicValueType {
eDynamicDontRunTarget = 2
};
+enum StopShowColumn {
+ eStopShowColumnAnsiOrCaret = 0,
+ eStopShowColumnAnsi = 1,
+ eStopShowColumnCaret = 2,
+ eStopShowColumnNone = 3
+};
+
enum AccessType {
eAccessNone,
eAccessPublic,
diff --git a/lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py b/lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
index 8b3ce441ced..027968a727f 100644
--- a/lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
+++ b/lldb/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
@@ -158,6 +158,10 @@ class LoadUnloadTestCase(TestBase):
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+ # Shut off ANSI color usage so we don't get ANSI escape sequences
+ # mixed in with stop locations.
+ self.dbg.SetUseColor(False)
+
if self.platformIsDarwin():
dylibName = 'libloadunload_d.dylib'
dsymName = 'libloadunload_d.dylib.dSYM'
diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py
index ae355a80c52..104cb619885 100644
--- a/lldb/packages/Python/lldbsuite/test/lldbtest.py
+++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py
@@ -228,6 +228,10 @@ def line_number(filename, string_to_match):
"Unable to find '%s' within file %s" %
(string_to_match, filename))
+def get_line(filename, line_number):
+ """Return the text of the line at the 1-based line number."""
+ with io.open(filename, mode='r', encoding="utf-8") as f:
+ return f.readlines()[line_number - 1]
def pointer_size():
"""Return the pointer size of the host system."""
diff --git a/lldb/packages/Python/lldbsuite/test/settings/TestSettings.py b/lldb/packages/Python/lldbsuite/test/settings/TestSettings.py
index 577cac17753..a8bd57341ed 100644
--- a/lldb/packages/Python/lldbsuite/test/settings/TestSettings.py
+++ b/lldb/packages/Python/lldbsuite/test/settings/TestSettings.py
@@ -527,6 +527,7 @@ class SettingsCommandTestCase(TestBase):
"stop-disassembly-display",
"stop-line-count-after",
"stop-line-count-before",
+ "stop-show-column",
"term-width",
"thread-format",
"use-external-editor",
diff --git a/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py b/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
index 904f0e7b7b2..31fe5437d1d 100644
--- a/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
+++ b/lldb/packages/Python/lldbsuite/test/source-manager/TestSourceManager.py
@@ -10,7 +10,7 @@ o test_modify_source_file_while_debugging:
"""
from __future__ import print_function
-
+import re
import lldb
from lldbsuite.test.decorators import *
@@ -18,19 +18,37 @@ from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
+def ansi_underline_surround_regex(inner_regex_text):
+ # return re.compile(r"\[4m%s\[0m" % inner_regex_text)
+ return "4.+\033\\[4m%s\033\\[0m" % inner_regex_text
+
+
class SourceManagerTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
+ SOURCE_FILE = 'main.c'
+
+ NO_DEBUG_INFO_TESTCASE = True
+
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break inside main().
- self.line = line_number('main.c', '// Set break point at this line.')
-
- @add_test_categories(['pyapi'])
- def test_display_source_python(self):
- """Test display of source using the SBSourceManager API."""
+ self.line = line_number(self.SOURCE_FILE, '// Set break point at this line.')
+
+ def get_expected_stop_column_number(self):
+ """Return the 1-based column number of the first non-whitespace
+ character in the breakpoint source line."""
+ stop_line = get_line(self.SOURCE_FILE, self.line)
+ # The number of spaces that must be skipped to get to the first non-
+ # whitespace character --- where we expect the debugger breakpoint
+ # column to be --- is equal to the number of characters that get
+ # stripped off the front when we lstrip it, plus one to specify
+ # the character column after the initial whitespace.
+ return len(stop_line) - len(stop_line.lstrip()) + 1
+
+ def do_display_source_python_api(self, use_color, column_marker_regex):
self.build()
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
@@ -39,24 +57,32 @@ class SourceManagerTestCase(TestBase):
self.assertTrue(target, VALID_TARGET)
# Launch the process, and do not stop at the entry point.
+ args = None
+ envp = None
process = target.LaunchSimple(
- None, None, self.get_process_working_directory())
+ args, envp, self.get_process_working_directory())
+ self.assertIsNotNone(process)
#
# Exercise Python APIs to display source lines.
#
+ # Setup whether we should use ansi escape sequences, including color
+ # and styles such as underline.
+ self.dbg.SetUseColor(use_color)
+
# Create the filespec for 'main.c'.
filespec = lldb.SBFileSpec('main.c', False)
source_mgr = self.dbg.GetSourceManager()
# Use a string stream as the destination.
stream = lldb.SBStream()
- source_mgr.DisplaySourceLinesWithLineNumbers(filespec,
- self.line,
- 2, # context before
- 2, # context after
- "=>", # prefix for current line
- stream)
+ column = self.get_expected_stop_column_number()
+ context_before = 2
+ context_after = 2
+ current_line_prefix = "=>"
+ source_mgr.DisplaySourceLinesWithLineNumbersAndColumn(
+ filespec, self.line, column, context_before, context_after,
+ current_line_prefix, stream)
# 2
# 3 int main(int argc, char const *argv[]) {
@@ -65,12 +91,28 @@ class SourceManagerTestCase(TestBase):
# 6 }
self.expect(stream.GetData(), "Source code displayed correctly",
exe=False,
- patterns=['=> %d.*Hello world' % self.line])
+ patterns=['=> %d.*Hello world' % self.line,
+ column_marker_regex])
# Boundary condition testings for SBStream(). LLDB should not crash!
stream.Print(None)
stream.RedirectToFile(None, True)
+ @add_test_categories(['pyapi'])
+ def test_display_source_python_dumb_terminal(self):
+ """Test display of source using the SBSourceManager API, using a
+ dumb terminal and thus no color support (the default)."""
+ use_color = False
+ self.do_display_source_python_api(use_color, r"\s+\^")
+
+ @add_test_categories(['pyapi'])
+ def test_display_source_python_ansi_terminal(self):
+ """Test display of source using the SBSourceManager API, using a
+ dumb terminal and thus no color support (the default)."""
+ use_color = True
+ underline_regex = ansi_underline_surround_regex(r".")
+ self.do_display_source_python_api(use_color, underline_regex)
+
def test_move_and_then_display_source(self):
"""Test that target.source-map settings work by moving main.c to hidden/main.c."""
self.build()
diff --git a/lldb/scripts/interface/SBSourceManager.i b/lldb/scripts/interface/SBSourceManager.i
index 09cd449149d..10fa7a68550 100644
--- a/lldb/scripts/interface/SBSourceManager.i
+++ b/lldb/scripts/interface/SBSourceManager.i
@@ -49,6 +49,13 @@ public:
uint32_t context_after,
const char* current_line_cstr,
lldb::SBStream &s);
+ size_t
+ DisplaySourceLinesWithLineNumbersAndColumn (const lldb::SBFileSpec &file,
+ uint32_t line, uint32_t column,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ lldb::SBStream &s);
};
} // namespace lldb
diff --git a/lldb/source/API/SBSourceManager.cpp b/lldb/source/API/SBSourceManager.cpp
index 69220760c9f..ecf532c3116 100644
--- a/lldb/source/API/SBSourceManager.cpp
+++ b/lldb/source/API/SBSourceManager.cpp
@@ -37,7 +37,7 @@ public:
}
size_t DisplaySourceLinesWithLineNumbers(const lldb_private::FileSpec &file,
- uint32_t line,
+ uint32_t line, uint32_t column,
uint32_t context_before,
uint32_t context_after,
const char *current_line_cstr,
@@ -48,14 +48,15 @@ public:
lldb::TargetSP target_sp(m_target_wp.lock());
if (target_sp) {
return target_sp->GetSourceManager().DisplaySourceLinesWithLineNumbers(
- file, line, context_before, context_after, current_line_cstr, s);
+ file, line, column, context_before, context_after, current_line_cstr,
+ s);
} else {
lldb::DebuggerSP debugger_sp(m_debugger_wp.lock());
if (debugger_sp) {
return debugger_sp->GetSourceManager()
- .DisplaySourceLinesWithLineNumbers(file, line, context_before,
- context_after, current_line_cstr,
- s);
+ .DisplaySourceLinesWithLineNumbers(file, line, column,
+ context_before, context_after,
+ current_line_cstr, s);
}
}
return 0;
@@ -96,10 +97,20 @@ SBSourceManager::~SBSourceManager() {}
size_t SBSourceManager::DisplaySourceLinesWithLineNumbers(
const SBFileSpec &file, uint32_t line, uint32_t context_before,
uint32_t context_after, const char *current_line_cstr, SBStream &s) {
+ const uint32_t column = 0;
+ return DisplaySourceLinesWithLineNumbersAndColumn(
+ file.ref(), line, column, context_before, context_after,
+ current_line_cstr, s);
+}
+
+size_t SBSourceManager::DisplaySourceLinesWithLineNumbersAndColumn(
+ const SBFileSpec &file, uint32_t line, uint32_t column,
+ uint32_t context_before, uint32_t context_after,
+ const char *current_line_cstr, SBStream &s) {
if (m_opaque_ap.get() == NULL)
return 0;
return m_opaque_ap->DisplaySourceLinesWithLineNumbers(
- file.ref(), line, context_before, context_after, current_line_cstr,
- s.get());
+ file.ref(), line, column, context_before, context_after,
+ current_line_cstr, s.get());
}
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 6085168c8da..237b3402e45 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -896,8 +896,10 @@ protected:
result.AppendMessageWithFormat("File: %s\n",
start_file.GetPath().c_str());
+ // We don't care about the column here.
+ const uint32_t column = 0;
return target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
- start_file, line_no, 0, m_options.num_lines, "",
+ start_file, line_no, 0, m_options.num_lines, column, "",
&result.GetOutputStream(), GetBreakpointLocations());
} else {
result.AppendErrorWithFormat(
@@ -1150,8 +1152,13 @@ protected:
size_t lines_to_back_up =
m_options.num_lines >= 10 ? 5 : m_options.num_lines / 2;
+ const uint32_t column =
+ (m_interpreter.GetDebugger().GetStopShowColumn() !=
+ eStopShowColumnNone)
+ ? sc.line_entry.column
+ : 0;
target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
- sc.comp_unit, sc.line_entry.line, lines_to_back_up,
+ sc.comp_unit, sc.line_entry.line, lines_to_back_up, column,
m_options.num_lines - lines_to_back_up, "->",
&result.GetOutputStream(), GetBreakpointLocations());
result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -1187,12 +1194,14 @@ protected:
} else
m_breakpoint_locations.Clear();
+ const uint32_t column = 0;
if (target->GetSourceManager()
.DisplaySourceLinesWithLineNumbersUsingLastFile(
m_options.start_line, // Line to display
m_options.num_lines, // Lines after line to
UINT32_MAX, // Don't mark "line"
- "", // Don't mark "line"
+ column,
+ "", // Don't mark "line"
&result.GetOutputStream(), GetBreakpointLocations())) {
result.SetStatus(eReturnStatusSuccessFinishResult);
}
@@ -1269,10 +1278,10 @@ protected:
if (m_options.num_lines == 0)
m_options.num_lines = 10;
-
+ const uint32_t column = 0;
target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
- sc.comp_unit, m_options.start_line, 0, m_options.num_lines, "",
- &result.GetOutputStream(), GetBreakpointLocations());
+ sc.comp_unit, m_options.start_line, 0, m_options.num_lines,
+ column, "", &result.GetOutputStream(), GetBreakpointLocations());
result.SetStatus(eReturnStatusSuccessFinishResult);
} else {
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 835f8034cdf..7a727479e16 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -140,6 +140,24 @@ OptionEnumValueElement g_language_enumerators[] = {
// {${function.initial-function}{${module.file.basename}`}{${function.name-without-args}}:\n}{${function.changed}\n{${module.file.basename}`}{${function.name-without-args}}:\n}{${current-pc-arrow}
// }{${addr-file-or-load}}:
+#define DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX "${ansi.underline}"
+#define DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX "${ansi.normal}"
+
+static OptionEnumValueElement s_stop_show_column_values[] = {
+ {eStopShowColumnAnsiOrCaret, "ansi-or-caret",
+ "Highlight the stop column with ANSI terminal codes when color/ANSI mode "
+ "is enabled; otherwise, fall back to using a text-only caret (^) as if "
+ "\"caret-only\" mode was selected."},
+ {eStopShowColumnAnsi, "ansi", "Highlight the stop column with ANSI "
+ "terminal codes when running LLDB with "
+ "color/ANSI enabled."},
+ {eStopShowColumnCaret, "caret",
+ "Highlight the stop column with a caret character (^) underneath the stop "
+ "column. This method introduces a new line in source listings that "
+ "display thread stop locations."},
+ {eStopShowColumnNone, "none", "Do not highlight the stop column."},
+ {0, nullptr, nullptr}};
+
static PropertyDefinition g_properties[] = {
{"auto-confirm", OptionValue::eTypeBoolean, true, false, nullptr, nullptr,
"If true all confirmation prompts will receive their default reply."},
@@ -173,6 +191,20 @@ static PropertyDefinition g_properties[] = {
{"stop-line-count-before", OptionValue::eTypeSInt64, true, 3, nullptr,
nullptr, "The number of sources lines to display that come before the "
"current source line when displaying a stopped context."},
+ {"stop-show-column", OptionValue::eTypeEnum, false,
+ eStopShowColumnAnsiOrCaret, nullptr, s_stop_show_column_values,
+ "If true, LLDB will use the column information from the debug info to "
+ "mark the current position when displaying a stopped context."},
+ {"stop-show-column-ansi-prefix", OptionValue::eTypeFormatEntity, true, 0,
+ DEFAULT_STOP_SHOW_COLUMN_ANSI_PREFIX, nullptr,
+ "When displaying the column marker in a color-enabled (i.e. ANSI) "
+ "terminal, use the ANSI terminal code specified in this format at the "
+ "immediately before the column to be marked."},
+ {"stop-show-column-ansi-suffix", OptionValue::eTypeFormatEntity, true, 0,
+ DEFAULT_STOP_SHOW_COLUMN_ANSI_SUFFIX, nullptr,
+ "When displaying the column marker in a color-enabled (i.e. ANSI) "
+ "terminal, use the ANSI terminal code specified in this format "
+ "immediately after the column to be marked."},
{"term-width", OptionValue::eTypeSInt64, true, 80, nullptr, nullptr,
"The maximum number of columns to use for displaying text."},
{"thread-format", OptionValue::eTypeFormatEntity, true, 0,
@@ -210,6 +242,9 @@ enum {
ePropertyStopDisassemblyDisplay,
ePropertyStopLineCountAfter,
ePropertyStopLineCountBefore,
+ ePropertyStopShowColumn,
+ ePropertyStopShowColumnAnsiPrefix,
+ ePropertyStopShowColumnAnsiSuffix,
ePropertyTerminalWidth,
ePropertyThreadFormat,
ePropertyUseExternalEditor,
@@ -371,6 +406,22 @@ bool Debugger::SetUseColor(bool b) {
return ret;
}
+StopShowColumn Debugger::GetStopShowColumn() const {
+ const uint32_t idx = ePropertyStopShowColumn;
+ return (lldb::StopShowColumn)m_collection_sp->GetPropertyAtIndexAsEnumeration(
+ nullptr, idx, g_properties[idx].default_uint_value);
+}
+
+const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiPrefix() const {
+ const uint32_t idx = ePropertyStopShowColumnAnsiPrefix;
+ return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+}
+
+const FormatEntity::Entry *Debugger::GetStopShowColumnAnsiSuffix() const {
+ const uint32_t idx = ePropertyStopShowColumnAnsiSuffix;
+ return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx);
+}
+
uint32_t Debugger::GetStopSourceLineCount(bool before) const {
const uint32_t idx =
before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index a2bbf71d501..5a320d1cd37 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -289,6 +289,9 @@ Disassembler::GetFunctionDeclLineEntry(const SymbolContext &sc) {
func_decl_file == prologue_end_line.original_file) {
decl_line.file = func_decl_file;
decl_line.line = func_decl_line;
+ // TODO do we care about column on these entries? If so, we need to
+ // plumb that through GetStartLineSourceInfo.
+ decl_line.column = 0;
}
}
return decl_line;
@@ -448,6 +451,7 @@ bool Disassembler::PrintInstructions(Disassembler *disasm_ptr,
SourceLine this_line;
this_line.file = sc.line_entry.file;
this_line.line = sc.line_entry.line;
+ this_line.column = sc.line_entry.column;
if (ElideMixedSourceAndDisassemblyLine(exe_ctx, sc, this_line) ==
false)
AddLineToSourceLineTables(this_line, source_lines_seen);
@@ -613,7 +617,7 @@ bool Disassembler::PrintInstructions(Disassembler *disasm_ptr,
line_highlight = "**";
}
source_manager.DisplaySourceLinesWithLineNumbers(
- ln.file, ln.line, 0, 0, line_highlight, &strm);
+ ln.file, ln.line, ln.column, 0, 0, line_highlight, &strm);
}
if (source_lines_to_display.print_source_context_end_eol)
strm.EOL();
diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp
index 6ecd8da33d8..ff0ee7d8246 100644
--- a/lldb/source/Core/SourceManager.cpp
+++ b/lldb/source/Core/SourceManager.cpp
@@ -22,6 +22,7 @@
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/AnsiTerminal.h"
using namespace lldb;
using namespace lldb_private;
@@ -71,7 +72,10 @@ SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
// If file_sp is no good or it points to a non-existent file, reset it.
if (!file_sp || !file_sp->GetFileSpec().Exists()) {
- file_sp.reset(new File(file_spec, target_sp.get()));
+ if (target_sp)
+ file_sp.reset(new File(file_spec, target_sp.get()));
+ else
+ file_sp.reset(new File(file_spec, debugger_sp));
if (debugger_sp)
debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
@@ -79,8 +83,44 @@ SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
return file_sp;
}
+static bool should_show_stop_column_with_ansi(DebuggerSP debugger_sp) {
+ // We don't use ANSI stop column formatting if we can't lookup values from
+ // the debugger.
+ if (!debugger_sp)
+ return false;
+
+ // We don't use ANSI stop column formatting if the debugger doesn't think
+ // it should be using color.
+ if (!debugger_sp->GetUseColor())
+ return false;
+
+ // We only use ANSI stop column formatting if we're either supposed to show
+ // ANSI where available (which we know we have when we get to this point), or
+ // if we're only supposed to use ANSI.
+ const auto value = debugger_sp->GetStopShowColumn();
+ return ((value == eStopShowColumnAnsiOrCaret) ||
+ (value == eStopShowColumnAnsi));
+}
+
+static bool should_show_stop_column_with_caret(DebuggerSP debugger_sp) {
+ // We don't use text-based stop column formatting if we can't lookup values
+ // from the debugger.
+ if (!debugger_sp)
+ return false;
+
+ // If we're asked to show the first available of ANSI or caret, then
+ // we do show the caret when ANSI is not available.
+ const auto value = debugger_sp->GetStopShowColumn();
+ if ((value == eStopShowColumnAnsiOrCaret) && !debugger_sp->GetUseColor())
+ return true;
+
+ // The only other time we use caret is if we're explicitly asked to show
+ // caret.
+ return value == eStopShowColumnCaret;
+}
+
size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
- uint32_t start_line, uint32_t count, uint32_t curr_line,
+ uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
const char *current_line_cstr, Stream *s,
const SymbolContextList *bp_locs) {
if (count == 0)
@@ -123,7 +163,20 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
return_value +=
s->Printf("%s%2.2s %-4u\t", prefix,
line == curr_line ? current_line_cstr : "", line);
- size_t this_line_size = m_last_file_sp->DisplaySourceLines(line, 0, 0, s);
+ size_t this_line_size = m_last_file_sp->DisplaySourceLines(
+ line, line == curr_line ? column : 0, 0, 0, s);
+ if (column != 0 && line == curr_line &&
+ should_show_stop_column_with_caret(m_debugger_wp.lock())) {
+ // Display caret cursor.
+ std::string src_line;
+ m_last_file_sp->GetLine(line, src_line);
+ return_value += s->Printf(" \t");
+ // Insert a space for every non-tab character in the source line.
+ for (int i = 0; i < column - 1 && i < src_line.length(); ++i)
+ return_value += s->PutChar(src_line[i] == '\t' ? '\t' : ' ');
+ // Now add the caret.
+ return_value += s->Printf("^\n");
+ }
if (this_line_size == 0) {
m_last_line = UINT32_MAX;
break;
@@ -135,8 +188,9 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
}
size_t SourceManager::DisplaySourceLinesWithLineNumbers(
- const FileSpec &file_spec, uint32_t line, uint32_t context_before,
- uint32_t context_after, const char *current_line_cstr, Stream *s,
+ const FileSpec &file_spec, uint32_t line, uint32_t column,
+ uint32_t context_before, uint32_t context_after,
+ const char *current_line_cstr, Stream *s,
const SymbolContextList *bp_locs) {
FileSP file_sp(GetFile(file_spec));
@@ -153,7 +207,7 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbers(
m_last_file_sp = file_sp;
}
return DisplaySourceLinesWithLineNumbersUsingLastFile(
- start_line, count, line, current_line_cstr, s, bp_locs);
+ start_line, count, line, column, current_line_cstr, s, bp_locs);
}
size_t SourceManager::DisplayMoreWithLineNumbers(
@@ -193,8 +247,9 @@ size_t SourceManager::DisplayMoreWithLineNumbers(
} else
m_last_line = 1;
+ const uint32_t column = 0;
return DisplaySourceLinesWithLineNumbersUsingLastFile(
- m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs);
+ m_last_line, m_last_count, UINT32_MAX, column, "", s, bp_locs);
}
return 0;
}
@@ -272,10 +327,27 @@ void SourceManager::FindLinesMatchingRegex(FileSpec &file_spec,
match_lines);
}
+SourceManager::File::File(const FileSpec &file_spec,
+ lldb::DebuggerSP debugger_sp)
+ : m_file_spec_orig(file_spec), m_file_spec(file_spec),
+ m_mod_time(file_spec.GetModificationTime()), m_source_map_mod_id(0),
+ m_data_sp(), m_offsets(), m_debugger_wp(debugger_sp) {
+ CommonInitializer(file_spec, nullptr);
+}
+
SourceManager::File::File(const FileSpec &file_spec, Target *target)
: m_file_spec_orig(file_spec), m_file_spec(file_spec),
m_mod_time(file_spec.GetModificationTime()), m_source_map_mod_id(0),
- m_data_sp(), m_offsets() {
+ m_data_sp(), m_offsets(),
+ m_debugger_wp(target ? target->GetDebugger().shared_from_this()
+ : DebuggerSP()) {
+ CommonInitializer(file_spec, target);
+}
+
+SourceManager::File::~File() {}
+
+void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
+ Target *target) {
if (!m_mod_time.IsValid()) {
if (target) {
m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
@@ -337,8 +409,6 @@ SourceManager::File::File(const FileSpec &file_spec, Target *target)
m_data_sp = m_file_spec.ReadFileContents();
}
-SourceManager::File::~File() {}
-
uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
if (line == 0)
return UINT32_MAX;
@@ -418,10 +488,14 @@ void SourceManager::File::UpdateIfNeeded() {
}
}
-size_t SourceManager::File::DisplaySourceLines(uint32_t line,
+size_t SourceManager::File::DisplaySourceLines(uint32_t line, uint32_t column,
uint32_t context_before,
uint32_t context_after,
Stream *s) {
+ // Nothing to write if there's no stream.
+ if (!s)
+ return 0;
+
// Sanity check m_data_sp before proceeding.
if (!m_data_sp)
return 0;
@@ -440,7 +514,61 @@ size_t SourceManager::File::DisplaySourceLines(uint32_t line,
if (start_line_offset < end_line_offset) {
size_t count = end_line_offset - start_line_offset;
const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
- bytes_written = s->Write(cstr, count);
+
+ bool displayed_line = false;
+
+ if (column && (column < count)) {
+ auto debugger_sp = m_debugger_wp.lock();
+ if (should_show_stop_column_with_ansi(debugger_sp) && debugger_sp) {
+ // Check if we have any ANSI codes with which to mark this column.
+ // If not, no need to do this work.
+ auto ansi_prefix_entry = debugger_sp->GetStopShowColumnAnsiPrefix();
+ auto ansi_suffix_entry = debugger_sp->GetStopShowColumnAnsiSuffix();
+
+ // We only bother breaking up the line to format the marked column if
+ // there is any marking specified on both sides of the marked column.
+ // In ANSI-terminal-sequence land, there must be a post if there is a
+ // pre format, and vice versa.
+ if (ansi_prefix_entry && ansi_suffix_entry) {
+ // Mark the current column with the desired escape sequence for
+ // formatting the column (e.g. underline, inverse, etc.)
+
+ // First print the part before the column to mark.
+ bytes_written = s->Write(cstr, column - 1);
+
+ // Write the pre escape sequence.
+ const SymbolContext *sc = nullptr;
+ const ExecutionContext *exe_ctx = nullptr;
+ const Address addr = LLDB_INVALID_ADDRESS;
+ ValueObject *valobj = nullptr;
+ const bool function_changed = false;
+ const bool initial_function = false;
+
+ FormatEntity::Format(*ansi_prefix_entry, *s, sc, exe_ctx, &addr,
+ valobj, function_changed, initial_function);
+
+ // Write the marked column.
+ bytes_written += s->Write(cstr + column - 1, 1);
+
+ // Write the post escape sequence.
+ FormatEntity::Format(*ansi_suffix_entry, *s, sc, exe_ctx, &addr,
+ valobj, function_changed, initial_function);
+
+ // And finish up with the rest of the line.
+ bytes_written += s->Write(cstr + column, count - column);
+
+ // Keep track of the fact that we just wrote the line.
+ displayed_line = true;
+ }
+ }
+ }
+
+ // If we didn't end up displaying the line with ANSI codes for whatever
+ // reason, display it now sans codes.
+ if (!displayed_line)
+ bytes_written = s->Write(cstr, count);
+
+ // Ensure we get an end of line character one way or another.
if (!is_newline_char(cstr[count - 1]))
bytes_written += s->EOL();
}
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 3f791d783a1..a0e9c5001f1 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1855,7 +1855,8 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
size_t num_lines =
target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
m_sc.line_entry.file, m_sc.line_entry.line,
- source_lines_before, source_lines_after, "->", &strm);
+ m_sc.line_entry.column, source_lines_before,
+ source_lines_after, "->", &strm);
if (num_lines != 0)
have_source = true;
// TODO: Give here a one time warning if source file is missing.