aprantl updated this revision to Diff 163231.
aprantl marked 4 inline comments as done.
aprantl added a comment.

Address review feedback.


https://reviews.llvm.org/D51461

Files:
  include/lldb/API/SBTarget.h
  include/lldb/Breakpoint/BreakpointResolver.h
  include/lldb/Breakpoint/BreakpointResolverFileLine.h
  include/lldb/Target/Target.h
  
packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/Makefile
  
packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
  
packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/main.c
  
packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
  
packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
  packages/Python/lldbsuite/test/lldbutil.py
  scripts/interface/SBTarget.i
  source/API/SBTarget.cpp
  source/Breakpoint/BreakpointResolver.cpp
  source/Breakpoint/BreakpointResolverFileLine.cpp
  source/Commands/CommandObjectBreakpoint.cpp
  source/Core/IOHandler.cpp
  source/Symbol/LineEntry.cpp
  source/Target/Target.cpp

Index: source/Target/Target.cpp
===================================================================
--- source/Target/Target.cpp
+++ source/Target/Target.cpp
@@ -322,7 +322,7 @@
 
 BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules,
                                       const FileSpec &file, uint32_t line_no,
-                                      lldb::addr_t offset,
+                                      uint32_t column, lldb::addr_t offset,
                                       LazyBool check_inlines,
                                       LazyBool skip_prologue, bool internal,
                                       bool hardware,
@@ -366,8 +366,8 @@
     move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo;
 
   BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine(
-      nullptr, remapped_file, line_no, offset, check_inlines, skip_prologue,
-      !static_cast<bool>(move_to_nearest_code)));
+      nullptr, remapped_file, line_no, column, offset, check_inlines,
+      skip_prologue, !static_cast<bool>(move_to_nearest_code)));
   return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true);
 }
 
Index: source/Symbol/LineEntry.cpp
===================================================================
--- source/Symbol/LineEntry.cpp
+++ source/Symbol/LineEntry.cpp
@@ -50,23 +50,23 @@
 }
 
 bool LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const {
-  bool result = false;
   if (file) {
     if (show_fullpaths)
       file.Dump(s);
     else
       file.GetFilename().Dump(s);
 
     if (line)
       s->PutChar(':');
-    result = true;
   }
-  if (line)
+  if (line) {
     s->Printf("%u", line);
-  else
-    result = false;
-
-  return result;
+    if (column) {
+      s->PutChar(':');
+      s->Printf("%u", column);
+    }
+  }
+  return file || line;
 }
 
 bool LineEntry::Dump(Stream *s, Target *target, bool show_file,
Index: source/Core/IOHandler.cpp
===================================================================
--- source/Core/IOHandler.cpp
+++ source/Core/IOHandler.cpp
@@ -4340,6 +4340,7 @@
               m_file_sp->GetFileSpec(), // Source file
               m_selected_line +
                   1, // Source line number (m_selected_line is zero based)
+              0,     // Unspecified column.
               0,     // No offset
               eLazyBoolCalculate,  // Check inlines using global setting
               eLazyBoolCalculate,  // Skip prologue using global setting,
@@ -4379,6 +4380,7 @@
               m_file_sp->GetFileSpec(), // Source file
               m_selected_line +
                   1, // Source line number (m_selected_line is zero based)
+              0,     // No column specified.
               0,     // No offset
               eLazyBoolCalculate,  // Check inlines using global setting
               eLazyBoolCalculate,  // Skip prologue using global setting,
Index: source/Commands/CommandObjectBreakpoint.cpp
===================================================================
--- source/Commands/CommandObjectBreakpoint.cpp
+++ source/Commands/CommandObjectBreakpoint.cpp
@@ -696,7 +696,8 @@
 
       bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 
                                        file,
-                                       m_options.m_line_num, 
+                                       m_options.m_line_num,
+                                       m_options.m_column,
                                        m_options.m_offset_addr,
                                        check_inlines, 
                                        m_options.m_skip_prologue,
Index: source/Breakpoint/BreakpointResolverFileLine.cpp
===================================================================
--- source/Breakpoint/BreakpointResolverFileLine.cpp
+++ source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -28,19 +28,21 @@
 //----------------------------------------------------------------------
 BreakpointResolverFileLine::BreakpointResolverFileLine(
     Breakpoint *bkpt, const FileSpec &file_spec, uint32_t line_no,
-    lldb::addr_t offset, bool check_inlines, bool skip_prologue,
-    bool exact_match)
+    uint32_t column, lldb::addr_t offset, bool check_inlines,
+    bool skip_prologue, bool exact_match)
     : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset),
-      m_file_spec(file_spec), m_line_number(line_no), m_inlines(check_inlines),
-      m_skip_prologue(skip_prologue), m_exact_match(exact_match) {}
+      m_file_spec(file_spec), m_line_number(line_no), m_column(column),
+      m_inlines(check_inlines), m_skip_prologue(skip_prologue),
+      m_exact_match(exact_match) {}
 
 BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
 
 BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
     Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
     Status &error) {
   llvm::StringRef filename;
   uint32_t line_no;
+  uint32_t column;
   bool check_inlines;
   bool skip_prologue;
   bool exact_match;
@@ -62,6 +64,13 @@
     return nullptr;
   }
 
+  success =
+      options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Column), column);
+  if (!success) {
+    // Backwards compatibility.
+    column = 0;
+  }
+
   success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
                                                  check_inlines);
   if (!success) {
@@ -85,8 +94,8 @@
 
   FileSpec file_spec(filename, false);
 
-  return new BreakpointResolverFileLine(bkpt, file_spec, line_no, offset,
-                                        check_inlines, skip_prologue,
+  return new BreakpointResolverFileLine(bkpt, file_spec, line_no, column,
+                                        offset, check_inlines, skip_prologue,
                                         exact_match);
 }
 
@@ -99,6 +108,8 @@
                                  m_file_spec.GetPath());
   options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
                                   m_line_number);
+  options_dict_sp->AddIntegerItem(GetKey(OptionNames::Column),
+                                  m_column);
   options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines);
   options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
                                   m_skip_prologue);
@@ -240,7 +251,8 @@
   s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"),
            m_line_number);
 
-  SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString());
+  SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(),
+                     m_line_number, m_column);
 
   return Searcher::eCallbackReturnContinue;
 }
@@ -250,16 +262,19 @@
 }
 
 void BreakpointResolverFileLine::GetDescription(Stream *s) {
-  s->Printf("file = '%s', line = %u, exact_match = %d",
-            m_file_spec.GetPath().c_str(), m_line_number, m_exact_match);
+  s->Printf("file = '%s', line = %u, ", m_file_spec.GetPath().c_str(),
+            m_line_number);
+  if (m_column)
+    s->Printf("column = %u, ", m_column);
+  s->Printf("exact_match = %d", m_exact_match);
 }
 
 void BreakpointResolverFileLine::Dump(Stream *s) const {}
 
 lldb::BreakpointResolverSP
 BreakpointResolverFileLine::CopyForBreakpoint(Breakpoint &breakpoint) {
   lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(
-      &breakpoint, m_file_spec, m_line_number, m_offset, m_inlines,
+      &breakpoint, m_file_spec, m_line_number, m_column, m_offset, m_inlines,
       m_skip_prologue, m_exact_match));
 
   return ret_sp;
Index: source/Breakpoint/BreakpointResolver.cpp
===================================================================
--- source/Breakpoint/BreakpointResolver.cpp
+++ source/Breakpoint/BreakpointResolver.cpp
@@ -44,9 +44,9 @@
 
 const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
     BreakpointResolver::OptionNames::LastOptionName)] = {
-    "AddressOffset", "Exact",        "FileName",   "Inlines", "Language",
-    "LineNumber",    "ModuleName",   "NameMask",   "Offset",  "Regex",
-    "SectionName",   "SkipPrologue", "SymbolNames"};
+    "AddressOffset", "Exact",       "FileName",     "Inlines",    "Language",
+    "LineNumber",    "Column",      "ModuleName",   "NameMask",   "Offset",
+    "Regex",         "SectionName", "SkipPrologue", "SymbolNames"};
 
 const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
   if (type > LastKnownResolverType)
@@ -176,18 +176,37 @@
   filter.Search(*this);
 }
 
+namespace {
+struct SourceLoc {
+  uint32_t line = UINT32_MAX;
+  uint32_t column;
+  SourceLoc(uint32_t l, uint32_t c) : line(l), column(c ? c : UINT32_MAX) {}
+  SourceLoc(const SymbolContext &sc)
+      : line(sc.line_entry.line),
+        column(sc.line_entry.column ? sc.line_entry.column : UINT32_MAX) {}
+};
+
+bool operator<(const SourceLoc a, const SourceLoc b) {
+  if (a.line < b.line)
+    return true;
+  if (a.line > b.line)
+    return false;
+  uint32_t a_col = a.column ? a.column : UINT32_MAX;
+  uint32_t b_col = b.column ? b.column : UINT32_MAX;
+  return a_col < b_col;
+}
+} // namespace
+
 void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter,
                                             SymbolContextList &sc_list,
                                             bool skip_prologue,
-                                            llvm::StringRef log_ident) {
+                                            llvm::StringRef log_ident,
+                                            uint32_t line, uint32_t column) {
   llvm::SmallVector<SymbolContext, 16> all_scs;
   for (uint32_t i = 0; i < sc_list.GetSize(); ++i)
     all_scs.push_back(sc_list[i]);
 
   while (all_scs.size()) {
-    // ResolveSymbolContext will always return a number that is >= the
-    // line number you pass in. So the smaller line number is always
-    // better.
     uint32_t closest_line = UINT32_MAX;
 
     // Move all the elements with a matching file spec to the end.
@@ -202,12 +221,41 @@
           }
           return true;
         });
-    
-    // Within, remove all entries with a larger line number.
-    auto worklist_end = std::remove_if(
-        worklist_begin, all_scs.end(), [&](const SymbolContext &sc) {
-          return closest_line != sc.line_entry.line;
-        });
+
+    // (worklist_begin, worklist_end) now contains all entries for one filespec.
+    auto worklist_end = all_scs.end();
+
+    if (column) {
+      // If a column was requested, do a more precise match and only
+      // return the first location that comes after or at the
+      // requested location.
+      SourceLoc requested(line, column);
+      // First, filter out all entries left of the requested column.
+      worklist_end = std::remove_if(
+          worklist_begin, worklist_end,
+          [&](const SymbolContext &sc) { return SourceLoc(sc) < requested; });
+      // Sort the remaining entries by (line, column).
+      std::sort(worklist_begin, worklist_end,
+                [](const SymbolContext &a, const SymbolContext &b) {
+                  return SourceLoc(a) < SourceLoc(b);
+                });
+
+      // Filter out all locations with a source location after the closest match.
+      if (worklist_begin != worklist_end)
+        worklist_end = std::remove_if(
+            worklist_begin, worklist_end, [&](const SymbolContext &sc) {
+              return SourceLoc(*worklist_begin) < SourceLoc(sc);
+            });
+    } else {
+      // Remove all entries with a larger line number.
+      // ResolveSymbolContext will always return a number that is >=
+      // the line number you pass in. So the smaller line number is
+      // always better.
+      worklist_end = std::remove_if(worklist_begin, worklist_end,
+                                    [&](const SymbolContext &sc) {
+                                      return closest_line != sc.line_entry.line;
+                                    });
+    }
 
     // Sort by file address.
     std::sort(worklist_begin, worklist_end,
Index: source/API/SBTarget.cpp
===================================================================
--- source/API/SBTarget.cpp
+++ source/API/SBTarget.cpp
@@ -693,6 +693,13 @@
 SBTarget::BreakpointCreateByLocation(const SBFileSpec &sb_file_spec,
                                      uint32_t line, lldb::addr_t offset,
                                      SBFileSpecList &sb_module_list) {
+  return BreakpointCreateByLocation(sb_file_spec, line, 0, offset,
+                                    sb_module_list);
+}
+
+SBBreakpoint SBTarget::BreakpointCreateByLocation(
+    const SBFileSpec &sb_file_spec, uint32_t line, uint32_t column,
+    lldb::addr_t offset, SBFileSpecList &sb_module_list) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
 
   SBBreakpoint sb_bp;
@@ -710,8 +717,8 @@
       module_list = sb_module_list.get();
     }
     sb_bp = target_sp->CreateBreakpoint(
-        module_list, *sb_file_spec, line, offset, check_inlines, skip_prologue,
-        internal, hardware, move_to_nearest_code);
+        module_list, *sb_file_spec, line, column, offset, check_inlines,
+        skip_prologue, internal, hardware, move_to_nearest_code);
   }
 
   if (log) {
Index: scripts/interface/SBTarget.i
===================================================================
--- scripts/interface/SBTarget.i
+++ scripts/interface/SBTarget.i
@@ -623,6 +623,11 @@
     BreakpointCreateByLocation (const lldb::SBFileSpec &file_spec, uint32_t line,
                                 lldb::addr_t offset, SBFileSpecList &module_list);
 
+    lldb::SBBreakpoint
+    BreakpointCreateByLocation (const lldb::SBFileSpec &file_spec, uint32_t line,
+                                uint32_t column, lldb::addr_t offset,
+                                SBFileSpecList &module_list);
+
     lldb::SBBreakpoint
     BreakpointCreateByName (const char *symbol_name, const char *module_name = NULL);
 
Index: packages/Python/lldbsuite/test/lldbutil.py
===================================================================
--- packages/Python/lldbsuite/test/lldbutil.py
+++ packages/Python/lldbsuite/test/lldbutil.py
@@ -511,7 +511,7 @@
     patterns = [
         r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>[0-9]+) locations\.$",
         r"^Breakpoint (?P<bpno>[0-9]+): (?P<num_locations>no) locations \(pending\)\.",
-        r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+), address = (?P<address>0x[0-9a-fA-F]+)$",
+        r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>[+\-]{0,1}[^+]+)( \+ (?P<offset>[0-9]+)){0,1}( \[inlined\] (?P<inline_symbol>.*)){0,1} at (?P<file>[^:]+):(?P<line_no>[0-9]+)(?P<column>(:[0-9]+)?), address = (?P<address>0x[0-9a-fA-F]+)$",
         r"^Breakpoint (?P<bpno>[0-9]+): where = (?P<module>.*)`(?P<symbol>.*)( \+ (?P<offset>[0-9]+)){0,1}, address = (?P<address>0x[0-9a-fA-F]+)$"]
     match_object = test.match(command, patterns)
     break_results = match_object.groupdict()
@@ -819,9 +819,31 @@
     breakpoint = target.BreakpointCreateBySourceRegex(
             bkpt_pattern, source_spec, bkpt_module)
     test.assertTrue(breakpoint.GetNumLocations() > 0,
-                    'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'%(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()))
+        'No locations found for source breakpoint: "%s", file: "%s", dir: "%s"'
+        %(bkpt_pattern, source_spec.GetFilename(), source_spec.GetDirectory()))
     return run_to_breakpoint_do_run(test, target, breakpoint, launch_info)
 
+def run_to_line_breakpoint(test, source_spec, line_number, column = 0,
+                           launch_info = None, exe_name = "a.out",
+                           bkpt_module = None,
+                           in_cwd = True):
+    """Start up a target, using exe_name as the executable, and run it to
+       a breakpoint set by (source_spec, line_number(, column)).
+
+       The rest of the behavior is the same as run_to_name_breakpoint.
+    """
+
+    target = run_to_breakpoint_make_target(test, exe_name, in_cwd)
+    # Set the breakpoints
+    breakpoint = target.BreakpointCreateByLocation(
+        source_spec, line_number, column, 0, lldb.SBFileSpecList())
+    test.assertTrue(breakpoint.GetNumLocations() > 0,
+        'No locations found for line breakpoint: "%s:%d(:%d)", dir: "%s"'
+        %(source_spec.GetFilename(), line_number, column,
+          source_spec.GetDirectory()))
+    return run_to_breakpoint_do_run(test, target, breakpoint, launch_info)
+
+
 def continue_to_breakpoint(process, bkpt):
     """ Continues the process, if it stops, returns the threads stopped at bkpt; otherwise, returns None"""
     process.Continue()
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/serialize/TestBreakpointSerialization.py
@@ -180,7 +180,8 @@
         # actually have locations.
         source_bps = lldb.SBBreakpointList(self.orig_target)
 
-        bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666)
+        bkpt = self.orig_target.BreakpointCreateByLocation(
+            lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList())
         bkpt.SetEnabled(False)
         bkpt.SetOneShot(True)
         bkpt.SetThreadID(10)
@@ -226,7 +227,8 @@
         all_bps = lldb.SBBreakpointList(self.orig_target)
         source_bps = lldb.SBBreakpointList(self.orig_target)
 
-        bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666)
+        bkpt = self.orig_target.BreakpointCreateByLocation(
+            lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList())
         bkpt.SetEnabled(False)
         bkpt.SetOneShot(True)
         bkpt.SetThreadID(10)
@@ -260,7 +262,8 @@
         self.check_equivalence(all_bps)
 
     def do_check_names(self):
-        bkpt = self.orig_target.BreakpointCreateByLocation("blubby.c", 666)
+        bkpt = self.orig_target.BreakpointCreateByLocation(
+            lldb.SBFileSpec("blubby.c"), 666, 333, 0, lldb.SBFileSpecList())
         good_bkpt_name = "GoodBreakpoint"
         write_bps = lldb.SBBreakpointList(self.orig_target)
         bkpt.AddName(good_bkpt_name)
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
===================================================================
--- packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py
@@ -133,9 +133,9 @@
             patterns=[
                 "1: file = '.*main.c', line = %d, exact_match = 0, locations = 1" %
                 self.line,
-                "1.1: .+at main.c:%d, .+unresolved, hit count = 0" %
+                "1.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" %
                 self.line,
-                "2.1: .+at main.c:%d, .+unresolved, hit count = 0" %
+                "2.1: .+at main.c:%d:?[0-9]*, .+unresolved, hit count = 0" %
                 self.line])
 
         self.expect("breakpoint command list 1", "Breakpoint 1 command ok",
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/main.c
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/main.c
@@ -0,0 +1,23 @@
+//===-- main.c --------------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+int square(int x)
+{
+  return x * x;
+}
+
+int main (int argc, char const *argv[])
+{
+  int did_call = 0;
+
+  // Line 20.                                    v Column 50.
+  if(square(argc+1) != 0) { did_call = 1; return square(argc); }
+  //                                             ^
+  return square(0);
+}
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py
@@ -0,0 +1,44 @@
+"""
+Test setting a breakpoint by line and column.
+"""
+
+from __future__ import print_function
+
+
+import os
+import time
+import re
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class BreakpointByLineAndColumnTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def testBreakpointByLineAndColumn(self):
+        self.build()
+        main_c = lldb.SBFileSpec("main.c")
+        _, _, _, breakpoint = lldbutil.run_to_line_breakpoint(self,
+                                                              main_c, 20, 50)
+        self.expect("fr v did_call", substrs='1')
+        in_then = False
+        for i in range(breakpoint.GetNumLocations()):
+            b_loc = breakpoint.GetLocationAtIndex(i).GetAddress().GetLineEntry()
+            self.assertEqual(b_loc.GetLine(), 20)
+            in_then |= b_loc.GetColumn() == 50
+        self.assertTrue(in_then)
+
+    def testBreakpointByLine(self):
+        self.build()
+        main_c = lldb.SBFileSpec("main.c")
+        _, _, _, breakpoint = lldbutil.run_to_line_breakpoint(self, main_c, 20)
+        self.expect("fr v did_call", substrs='0')
+        in_condition = False
+        for i in range(breakpoint.GetNumLocations()):
+            b_loc = breakpoint.GetLocationAtIndex(i).GetAddress().GetLineEntry()
+            self.assertEqual(b_loc.GetLine(), 20)
+            in_condition |= b_loc.GetColumn() < 30
+        self.assertTrue(in_condition)
Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_by_line_and_column/Makefile
@@ -0,0 +1,6 @@
+LEVEL = ../../../make
+
+C_SOURCES := main.c
+CFLAGS_EXTRAS += -std=c99 -gcolumn-info
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Target/Target.h
===================================================================
--- include/lldb/Target/Target.h
+++ include/lldb/Target/Target.h
@@ -557,7 +557,7 @@
   // module it is nullptr
   lldb::BreakpointSP CreateBreakpoint(const FileSpecList *containingModules,
                                       const FileSpec &file, uint32_t line_no,
-                                      lldb::addr_t offset,
+                                      uint32_t column, lldb::addr_t offset,
                                       LazyBool check_inlines,
                                       LazyBool skip_prologue, bool internal,
                                       bool request_hardware,
Index: include/lldb/Breakpoint/BreakpointResolverFileLine.h
===================================================================
--- include/lldb/Breakpoint/BreakpointResolverFileLine.h
+++ include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -28,9 +28,9 @@
 class BreakpointResolverFileLine : public BreakpointResolver {
 public:
   BreakpointResolverFileLine(Breakpoint *bkpt, const FileSpec &resolver,
-                             uint32_t line_no, lldb::addr_t m_offset,
-                             bool check_inlines, bool skip_prologue,
-                             bool exact_match);
+                             uint32_t line_no, uint32_t column,
+                             lldb::addr_t m_offset, bool check_inlines,
+                             bool skip_prologue, bool exact_match);
 
   static BreakpointResolver *
   CreateFromStructuredData(Breakpoint *bkpt,
@@ -65,10 +65,11 @@
   void FilterContexts(SymbolContextList &sc_list, bool is_relative);
 
   friend class Breakpoint;
-  FileSpec m_file_spec;   // This is the file spec we are looking for.
-  uint32_t m_line_number; // This is the line number that we are looking for.
-  bool m_inlines; // This determines whether the resolver looks for inlined
-                  // functions or not.
+  FileSpec m_file_spec;   ///< This is the file spec we are looking for.
+  uint32_t m_line_number; ///< This is the line number that we are looking for.
+  uint32_t m_column;      ///< This is the column that we are looking for.
+  bool m_inlines; ///< This determines whether the resolver looks for inlined
+                  ///< functions or not.
   bool m_skip_prologue;
   bool m_exact_match;
 
Index: include/lldb/Breakpoint/BreakpointResolver.h
===================================================================
--- include/lldb/Breakpoint/BreakpointResolver.h
+++ include/lldb/Breakpoint/BreakpointResolver.h
@@ -200,6 +200,7 @@
     Inlines,
     LanguageName,
     LineNumber,
+    Column,
     ModuleName,
     NameMaskArray,
     Offset,
@@ -224,8 +225,11 @@
   /// number that matches, and then filter down the matching addresses to
   /// unique entries, and skip the prologue if asked to do so, and then set
   /// breakpoint locations in this breakpoint for all the resultant addresses.
+  /// When \p column is nonzero the \p line and \p column args are used to
+  /// filter the results to find the first breakpoint >= (line, column).
   void SetSCMatchesByLine(SearchFilter &filter, SymbolContextList &sc_list,
-                          bool skip_prologue, llvm::StringRef log_ident);
+                          bool skip_prologue, llvm::StringRef log_ident,
+                          uint32_t line = 0, uint32_t column = 0);
   void SetSCMatchesByLine(SearchFilter &, SymbolContextList &, bool,
                           const char *) = delete;
 
Index: include/lldb/API/SBTarget.h
===================================================================
--- include/lldb/API/SBTarget.h
+++ include/lldb/API/SBTarget.h
@@ -580,6 +580,12 @@
   BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line,
                              lldb::addr_t offset, SBFileSpecList &module_list);
 
+  lldb::SBBreakpoint
+  BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line,
+                             uint32_t column, lldb::addr_t offset,
+                             SBFileSpecList &module_list);
+
+  
   lldb::SBBreakpoint BreakpointCreateByName(const char *symbol_name,
                                             const char *module_name = nullptr);
 
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to