diff --git a/gdb/NEWS b/gdb/NEWS
index b82114d80b0..38c6f54564b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,13 @@
 
 *** Changes since GDB 13
 
+* New commmand "next-expression" ("ne") that steps by expression or statement
+  on a single source line if debug information is available.
+
+* New column attribute of Python type Symtab_and_line to reflect the added
+  column field on "linetable_entry". Describes what column on the source line
+  that is being executed. Columns are byte-level coordinates on a source line.
+
 * The AArch64 'org.gnu.gdb.aarch64.pauth' Pointer Authentication feature string
   has been deprecated in favor of the 'org.gnu.gdb.aarch64.pauth_v2' feature
   string.
diff --git a/gdb/buildsym-legacy.c b/gdb/buildsym-legacy.c
index 131d24fe9b5..5036fd2b48d 100644
--- a/gdb/buildsym-legacy.c
+++ b/gdb/buildsym-legacy.c
@@ -205,12 +205,12 @@ finish_block (struct symbol *symbol, struct pending_block *old_blocks,
 }
 
 void
-record_line (struct subfile *subfile, int line, unrelocated_addr pc)
+record_line (struct subfile *subfile, int line, int col, unrelocated_addr pc)
 {
   gdb_assert (buildsym_compunit != nullptr);
   /* Assume every line entry is a statement start, that is a good place to
      put a breakpoint for that line number.  */
-  buildsym_compunit->record_line (subfile, line, pc, LEF_IS_STMT);
+  buildsym_compunit->record_line (subfile, line, col, pc, LEF_IS_STMT);
 }
 
 /* Start a new compunit_symtab for a new source file in OBJFILE.  Called, for
diff --git a/gdb/buildsym-legacy.h b/gdb/buildsym-legacy.h
index 664d6320e54..be44d0f5783 100644
--- a/gdb/buildsym-legacy.h
+++ b/gdb/buildsym-legacy.h
@@ -76,7 +76,7 @@ extern struct context_stack *push_context (int desc, CORE_ADDR valu);
 
 extern struct context_stack pop_context ();
 
-extern void record_line (struct subfile *subfile, int line,
+extern void record_line (struct subfile *subfile, int line, int col,
 			 unrelocated_addr pc);
 
 extern struct compunit_symtab *start_compunit_symtab (struct objfile *objfile,
diff --git a/gdb/buildsym.c b/gdb/buildsym.c
index d12ad2187ab..6b3859ea45e 100644
--- a/gdb/buildsym.c
+++ b/gdb/buildsym.c
@@ -626,7 +626,7 @@ buildsym_compunit::pop_subfile ()
    line vector for SUBFILE.  */
 
 void
-buildsym_compunit::record_line (struct subfile *subfile, int line,
+buildsym_compunit::record_line (struct subfile *subfile, int line, int col,
 				unrelocated_addr pc, linetable_entry_flags flags)
 {
   m_have_line_numbers = true;
@@ -666,6 +666,7 @@ buildsym_compunit::record_line (struct subfile *subfile, int line,
 
   subfile->line_vector_entries.emplace_back ();
   linetable_entry &e = subfile->line_vector_entries.back ();
+  e.column = col;
   e.line = line;
   e.is_stmt = (flags & LEF_IS_STMT) != 0;
   e.set_raw_pc (pc);
diff --git a/gdb/buildsym.h b/gdb/buildsym.h
index 98dc8f02874..d3328c630d8 100644
--- a/gdb/buildsym.h
+++ b/gdb/buildsym.h
@@ -239,8 +239,8 @@ struct buildsym_compunit
 
   const char *pop_subfile ();
 
-  void record_line (struct subfile *subfile, int line, unrelocated_addr pc,
-		    linetable_entry_flags flags);
+  void record_line (struct subfile *subfile, int line, int col,
+  		    unrelocated_addr pc, linetable_entry_flags flags);
 
   struct compunit_symtab *get_compunit_symtab ()
   {
diff --git a/gdb/coffread.c b/gdb/coffread.c
index ff4d4ae5313..dfb75b12799 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -1133,7 +1133,7 @@ coff_symtab_read (minimal_symbol_reader &reader,
 		 other statement-line-number.  */
 	      if (fcn_last_line == 1)
 		record_line
-		  (get_current_subfile (), fcn_first_line,
+		  (get_current_subfile (), fcn_first_line, 0,
 		   unrelocated_addr (gdbarch_addr_bits_remove (gdbarch,
 							       fcn_first_line_addr)));
 	      else
@@ -1462,7 +1462,7 @@ enter_linenos (file_ptr file_offset, int first_line,
 	{
 	  CORE_ADDR addr = lptr.l_addr.l_paddr;
 	  record_line (get_current_subfile (),
-		       first_line + L_LNNO32 (&lptr),
+		       first_line + L_LNNO32 (&lptr), 0,
 		       unrelocated_addr (gdbarch_addr_bits_remove (gdbarch,
 								   addr)));
 	}
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 73371edd841..310ee0eef4d 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -2476,7 +2476,7 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, const char *name,
 	      CORE_ADDR addr = last_function_start + valu;
 
 	      record_line
-		(get_current_subfile (), 0,
+		(get_current_subfile (), 0, 0,
 		 unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, addr)
 				   - objfile->text_section_offset ()));
 	    }
@@ -2686,14 +2686,14 @@ process_one_symbol (int type, int desc, CORE_ADDR valu, const char *name,
 			   last_function_start : valu;
 
 	  record_line
-	    (get_current_subfile (), desc,
+	    (get_current_subfile (), desc, 0,
 	     unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, addr)
 			       - objfile->text_section_offset ()));
 	  sline_found_in_function = 1;
 	}
       else
 	record_line
-	  (get_current_subfile (), desc,
+	  (get_current_subfile (), desc, 0,
 	   unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, valu)
 			     - objfile->text_section_offset ()));
       break;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 531147f6e6b..3f779154cd7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -6359,6 +6359,20 @@ The @code{next} command only stops at the first instruction of a
 source line.  This prevents multiple stops that could otherwise occur in
 @code{switch} statements, @code{for} loops, etc.
 
+@kindex next-expression
+@kindex ne @r{(@code{next-expression})}
+@item next-expression @r{[}@var{count}@r{]}
+Continue to the next expression or statement on the current source line
+in the current (innermost) stack frame.  This is a source-level command
+and as such requires that debug information was emitted by the compiler.  If
+no such debug information could be found this command defaults to
+@code{next}.  Column meta data has been part of the DWARF standard since 2.0
+and GCC and clang both emit this information.
+
+An argument @var{count} is a repeat count, as for @code{next}.
+If the current source line doesn't have enough expressions to satisfy
+@var{count}, this command will do the same as @code{next}.
+
 @kindex set step-mode
 @item set step-mode
 @cindex functions without line info, and stepping
@@ -31313,7 +31327,7 @@ An -exec-until or similar CLI command was accomplished.
 @item watchpoint-scope
 A watchpoint has gone out of scope.
 @item end-stepping-range
-An -exec-next, -exec-next-instruction, -exec-step, -exec-step-instruction or 
+An -exec-next, -exec-next-instruction, -exec-step, -exec-step-instruction or
 similar CLI command was accomplished.
 @item exited-signalled 
 The inferior exited because of a signal.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 5d714ee1ca3..eb295fe2458 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -5899,6 +5899,12 @@ Indicates the current line number for this object.  This
 attribute is not writable.
 @end defvar
 
+@defvar Symtab_and_line.column
+Indicates the current column number for this object.  This
+attribute is not writeable.  A source-line column is it's byte position
+on that line.
+@end defvar
+
 A @code{gdb.Symtab_and_line} object has the following methods:
 
 @defun Symtab_and_line.is_valid ()
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4828409222c..9b56abc406e 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -18137,6 +18137,11 @@ class lnp_state_machine
     m_flags |= LEF_PROLOGUE_END;
   }
 
+  void handle_set_column (unsigned int col)
+  {
+    m_column = col;
+  }
+
 private:
   /* Advance the line by LINE_DELTA.  */
   void advance_line (int line_delta)
@@ -18161,6 +18166,7 @@ class lnp_state_machine
   /* The line table index of the current file.  */
   file_name_index m_file = 1;
   unsigned int m_line = 1;
+  unsigned int m_column = 1;
 
   /* These are initialized in the constructor.  */
 
@@ -18223,6 +18229,7 @@ lnp_state_machine::handle_special_opcode (unsigned char op_code)
   advance_line (line_delta);
   record_line (false);
   m_discriminator = 0;
+  m_column = 0;
   m_flags &= ~LEF_PROLOGUE_END;
 }
 
@@ -18311,9 +18318,8 @@ dwarf_record_line_p (struct dwarf2_cu *cu,
 
 static void
 dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
-		     unsigned int line, CORE_ADDR address,
-		     linetable_entry_flags flags,
-		     struct dwarf2_cu *cu)
+		     unsigned int line, unsigned int col, CORE_ADDR address,
+		     linetable_entry_flags flags, struct dwarf2_cu *cu)
 {
   unrelocated_addr addr
     = unrelocated_addr (gdbarch_addr_bits_remove (gdbarch, address));
@@ -18327,7 +18333,7 @@ dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile,
     }
 
   if (cu != nullptr)
-    cu->get_builder ()->record_line (subfile, line, addr, flags);
+    cu->get_builder ()->record_line (subfile, line, (int) col, addr, flags);
 }
 
 /* Subroutine of dwarf_decode_lines_1 to simplify it.
@@ -18350,7 +18356,7 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile,
 		  paddress (gdbarch, address));
     }
 
-  dwarf_record_line_1 (gdbarch, subfile, 0, address, LEF_IS_STMT, cu);
+  dwarf_record_line_1 (gdbarch, subfile, 0, 0, address, LEF_IS_STMT, cu);
 }
 
 void
@@ -18418,10 +18424,10 @@ lnp_state_machine::record_line (bool end_sequence)
 				   m_last_subfile))
 	    {
 	      buildsym_compunit *builder = m_cu->get_builder ();
-	      dwarf_record_line_1 (m_gdbarch,
-				   builder->get_current_subfile (),
-				   m_line, m_address, lte_flags,
-				   m_currently_recording_lines ? m_cu : nullptr);
+	      dwarf_record_line_1 (m_gdbarch, builder->get_current_subfile (),
+				   m_line, m_column, m_address, lte_flags,
+				   m_currently_recording_lines ? m_cu
+							       : nullptr);
 	    }
 	  m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
 	  m_last_line = m_line;
@@ -18642,8 +18648,12 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
 	      }
 	      break;
 	    case DW_LNS_set_column:
-	      (void) read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
-	      line_ptr += bytes_read;
+	      {
+		const auto col
+		  = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		state_machine.handle_set_column (col);
+		line_ptr += bytes_read;
+	      }
 	      break;
 	    case DW_LNS_negate_stmt:
 	      state_machine.handle_negate_stmt ();
diff --git a/gdb/gdbthread.h b/gdb/gdbthread.h
index 7135515bf45..a5ad8ddddb7 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -171,6 +171,8 @@ struct thread_control_state
      command.  This is used to decide whether "set scheduler-locking
      step" behaves like "on" or "off".  */
   int stepping_command = 0;
+
+  bool step_expression = false;
 };
 
 /* Inferior thread specific part of `struct infcall_suspend_state'.  */
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index b12b58db9cb..bb9093012e4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -61,7 +61,8 @@
 
 static void until_next_command (int);
 
-static void step_1 (int, int, const char *);
+static void
+step_1 (int, int, bool, const char *);
 
 #define ERROR_NO_INFERIOR \
    if (!target_has_execution ()) error (_("The program is not being run."));
@@ -231,8 +232,7 @@ strip_bg_char (const char *args, int *bg_char_p)
 void
 post_create_inferior (int from_tty)
 {
-
-  /* Be sure we own the terminal in case write operations are performed.  */ 
+  /* Be sure we own the terminal in case write operations are performed.  */
   target_terminal::ours_for_output ();
 
   infrun_debug_show_threads ("threads in the newly created inferior",
@@ -765,7 +765,7 @@ set_step_frame (thread_info *tp)
 static void
 step_command (const char *count_string, int from_tty)
 {
-  step_1 (0, 0, count_string);
+  step_1 (0, 0, false, count_string);
 }
 
 /* Likewise, but skip over subroutine calls as if single instructions.  */
@@ -773,7 +773,7 @@ step_command (const char *count_string, int from_tty)
 static void
 next_command (const char *count_string, int from_tty)
 {
-  step_1 (1, 0, count_string);
+  step_1 (1, 0, false, count_string);
 }
 
 /* Likewise, but step only one instruction.  */
@@ -781,13 +781,13 @@ next_command (const char *count_string, int from_tty)
 static void
 stepi_command (const char *count_string, int from_tty)
 {
-  step_1 (0, 1, count_string);
+  step_1 (0, 1, false, count_string);
 }
 
 static void
 nexti_command (const char *count_string, int from_tty)
 {
-  step_1 (1, 1, count_string);
+  step_1 (1, 1, false, count_string);
 }
 
 /* Data for the FSM that manages the step/next/stepi/nexti
@@ -804,6 +804,9 @@ struct step_command_fsm : public thread_fsm
   /* If true, this is a stepi/nexti, otherwise a step/step.  */
   int single_inst;
 
+  bool step_expression;
+  breakpoint_up bp = nullptr;
+
   explicit step_command_fsm (struct interp *cmd_interp)
     : thread_fsm (cmd_interp)
   {
@@ -818,25 +821,64 @@ struct step_command_fsm : public thread_fsm
    allocated here is undone in the FSM's clean_up method.  */
 
 static void
-step_command_fsm_prepare (struct step_command_fsm *sm,
-			  int skip_subroutines, int single_inst,
-			  int count, struct thread_info *thread)
+step_command_fsm_prepare (struct step_command_fsm *sm, int skip_subroutines,
+			  int single_inst, bool step_expression, int count,
+			  struct thread_info *thread)
 {
   sm->skip_subroutines = skip_subroutines;
   sm->single_inst = single_inst;
   sm->count = count;
+  sm->step_expression = step_expression;
 
   /* Leave the si command alone.  */
   if (!sm->single_inst || sm->skip_subroutines)
     set_longjmp_breakpoint (thread, get_frame_id (get_current_frame ()));
 
   thread->control.stepping_command = 1;
+
+  if (sm->step_expression)
+    {
+      /* We might need to set a breakpoint, because the next expression
+      that is on this line, might not exist in the same frame, as for instance
+      is the case with a lambda being defined and passed into a function. The
+      normal `next instruction` command would step over this, where as
+      `next-expression` does not want that behavior. A breakpoint will in that
+      case catch us.*/
+      const auto frame = get_current_frame ();
+      const auto sal = find_frame_sal (frame);
+      const auto range = sal.symtab->linetable_entries_on_line (sal.line);
+      auto column_count = count;
+      for (const auto &entry : range)
+	{
+	  if (entry.column > sal.col)
+	    column_count--;
+	  if (column_count == 0)
+	    {
+	      const auto column_rel_addr
+		= entry.pc (sal.pspace->symfile_object_file);
+	      const auto frame_gdbarch = get_frame_arch (frame);
+	      auto bp_loc = set_momentary_breakpoint_at_pc (
+		frame_gdbarch, column_rel_addr, bp_breakpoint);
+	      sm->bp = std::move (bp_loc);
+	      return;
+	    }
+	}
+      // if we did not find suitable column; default to next
+      sm->step_expression = false;
+    }
+}
+
+static void
+next_expression (const char *count_str, int from_tty)
+{
+  step_1 (true, false, true, count_str);
 }
 
 static int prepare_one_step (thread_info *, struct step_command_fsm *sm);
 
 static void
-step_1 (int skip_subroutines, int single_inst, const char *count_string)
+step_1 (int skip_subroutines, int single_inst, bool step_expression,
+	const char *count_string)
 {
   int count;
   int async_exec;
@@ -864,8 +906,8 @@ step_1 (int skip_subroutines, int single_inst, const char *count_string)
   step_sm = new step_command_fsm (command_interp ());
   thr->set_thread_fsm (std::unique_ptr<thread_fsm> (step_sm));
 
-  step_command_fsm_prepare (step_sm, skip_subroutines,
-			    single_inst, count, thr);
+  step_command_fsm_prepare (step_sm, skip_subroutines, single_inst,
+			    step_expression, count, thr);
 
   /* Do only one step for now, before returning control to the event
      loop.  Let the continuation figure out how many other steps we
@@ -899,7 +941,18 @@ step_command_fsm::should_stop (struct thread_info *tp)
       /* There are more steps to make, and we did stop due to
 	 ending a stepping range.  Do another step.  */
       if (--count > 0)
-	return prepare_one_step (tp, this);
+	{
+	  if (bp != nullptr
+	      && bpstat_find_breakpoint (tp->control.stop_bpstat, bp.get ())
+		   != nullptr)
+	    {
+	      count = 0;
+	    }
+	  else
+	    {
+	      return prepare_one_step (tp, this);
+	    }
+	}
 
       set_finished ();
     }
@@ -914,6 +967,7 @@ step_command_fsm::clean_up (struct thread_info *thread)
 {
   if (!single_inst || skip_subroutines)
     delete_longjmp_breakpoint (thread->global_num);
+  bp = nullptr;
 }
 
 /* Implementation of the 'async_reply_reason' FSM method for stepping
@@ -1033,6 +1087,7 @@ prepare_one_step (thread_info *tp, struct step_command_fsm *sm)
       if (sm->skip_subroutines)
 	tp->control.step_over_calls = STEP_OVER_ALL;
 
+      tp->control.step_expression = sm->step_expression;
       return 0;
     }
 
@@ -3311,6 +3366,14 @@ Argument N means step N times (or till program stops for another \
 reason)."));
   add_com_alias ("s", step_cmd, class_run, 1);
 
+  cmd_list_element *ne_cmd
+    = add_com ("next-expression", class_run, next_expression, _ ("\
+Step program by expressions info, proceeding through subroutine calls.\n\
+Usage: next-expression [N]\n\
+This is a source-level command and if no debug information was emitted by\n\
+the compiler this command will default to behaving like 'next'"));
+  add_com_alias ("ne", ne_cmd, class_run, 1);
+
   cmd_list_element *until_cmd
     = add_com ("until", class_run, until_command, _("\
 Execute until past the current line or past a LOCATION.\n\
diff --git a/gdb/infrun.c b/gdb/infrun.c
index efe2c00c489..6fe4230b634 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -7561,8 +7561,16 @@ process_event_stop_test (struct execution_control_state *ecs)
       return;
     }
 
+  if ((ecs->event_thread->stop_pc () == stop_pc_sal.pc)
+      && ecs->event_thread->control.step_expression)
+    {
+      infrun_debug_printf ("stepped to next expression");
+      return end_stepping_range (ecs);
+    }
+
   bool refresh_step_info = true;
   if ((ecs->event_thread->stop_pc () == stop_pc_sal.pc)
+      && (ecs->event_thread->control.step_expression == false)
       && (ecs->event_thread->current_line != stop_pc_sal.line
 	  || ecs->event_thread->current_symtab != stop_pc_sal.symtab))
     {
diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
index 697ce0b5b1a..aaf4878de25 100644
--- a/gdb/mdebugread.c
+++ b/gdb/mdebugread.c
@@ -4012,7 +4012,7 @@ mdebug_expand_psymtab (legacy_psymtab *pst, struct objfile *objfile)
 		{
 		  /* Handle encoded stab line number.  */
 		  record_line
-		    (get_current_subfile (), sh.index,
+		    (get_current_subfile (), sh.index, 0,
 		     unrelocated_addr (gdbarch_addr_bits_remove (gdbarch,
 								 valu)));
 		}
diff --git a/gdb/python/py-symtab.c b/gdb/python/py-symtab.c
index 26aa8b2fb04..89a86cc136b 100644
--- a/gdb/python/py-symtab.c
+++ b/gdb/python/py-symtab.c
@@ -286,8 +286,12 @@ salpy_str (PyObject *self)
       filename = symtab_to_filename_for_display (symtab);
     }
 
-  return PyUnicode_FromFormat ("symbol and line for %s, line %d", filename,
-			       sal->line);
+  if (sal->col > 0)
+    return PyUnicode_FromFormat ("symbol and line:col for %s, line %d:%d",
+				 filename, sal->line, sal->col);
+  else
+    return PyUnicode_FromFormat ("symbol and line for %s, line %d", filename,
+				 sal->line);
 }
 
 static void
@@ -343,6 +347,16 @@ salpy_get_line (PyObject *self, void *closure)
   return gdb_py_object_from_longest (sal->line).release ();
 }
 
+static PyObject *
+salpy_get_col (PyObject *self, void *closure)
+{
+  struct symtab_and_line *sal = NULL;
+
+  SALPY_REQUIRE_VALID (self, sal);
+
+  return gdb_py_object_from_longest (sal->col).release ();
+}
+
 static PyObject *
 salpy_get_symtab (PyObject *self, void *closure)
 {
@@ -597,11 +611,12 @@ PyTypeObject symtab_object_type = {
 static gdb_PyGetSetDef sal_object_getset[] = {
   { "symtab", salpy_get_symtab, NULL, "Symtab object.", NULL },
   { "pc", salpy_get_pc, NULL, "Return the symtab_and_line's pc.", NULL },
-  { "last", salpy_get_last, NULL,
-    "Return the symtab_and_line's last address.", NULL },
-  { "line", salpy_get_line, NULL,
-    "Return the symtab_and_line's line.", NULL },
-  {NULL}  /* Sentinel */
+  { "last", salpy_get_last, NULL, "Return the symtab_and_line's last address.",
+    NULL },
+  { "line", salpy_get_line, NULL, "Return the symtab_and_line's line.", NULL },
+  { "column", salpy_get_col, NULL, "Return the symtab_and_line's column.",
+    NULL },
+  { NULL } /* Sentinel */
 };
 
 static PyMethodDef sal_object_methods[] = {
diff --git a/gdb/stack.c b/gdb/stack.c
index b1b25aa1c7e..590862236b7 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1418,6 +1418,13 @@ print_frame (const frame_print_options &fp_opts,
 	uiout->text (":");
 	annotate_frame_source_line ();
 	uiout->field_signed ("line", sal.line);
+
+	/* Only print column if we have column meta data. */
+	if (sal.col > 0)
+	  {
+	    uiout->text (":");
+	    uiout->field_signed ("column", sal.col);
+	  }
 	annotate_frame_source_end ();
       }
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 4f28667b1b3..3265756a637 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -3247,6 +3247,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc (objfile);
+      val.col = best->column;
       if (best_end && (!alt || best_end < alt->pc (objfile)))
 	val.end = best_end;
       else if (alt)
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d8e3c273f85..ce6444a5a71 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1615,6 +1615,9 @@ struct linetable_entry
   /* The line number for this entry.  */
   int line;
 
+  /* The column number for this entry. 0 means it has no column data. */
+  int column;
+
   /* True if this PC is a good location to place a breakpoint for LINE.  */
   bool is_stmt : 1;
 
@@ -1651,6 +1654,10 @@ struct linetable
      `struct hack', you can shove it up your ANSI (seriously, if the
      committee tells us how to do it, we can probably go along).  */
   struct linetable_entry item[1];
+  gdb::array_view<const linetable_entry> items () const
+  {
+    return gdb::array_view<const linetable_entry>{ item, item + nitems };
+  }
 };
 
 /* How to relocate the symbols from each section in a symbol file.
@@ -1681,6 +1688,17 @@ struct symtab
     return m_linetable;
   }
 
+  std::vector<linetable_entry> linetable_entries_on_line (int line)
+  {
+    std::vector<linetable_entry> entries;
+    for (const auto &entry : m_linetable->items ())
+      {
+	if (entry.line == line)
+	  entries.push_back (entry);
+      }
+    return entries;
+  }
+
   void set_linetable (const struct linetable *linetable)
   {
     m_linetable = linetable;
@@ -2330,6 +2348,10 @@ struct symtab_and_line
      information is not available.  */
   int line = 0;
 
+  /* Column number of this particular SAL. 0 indidcates no available column
+   * information */
+  int col = 0;
+
   CORE_ADDR pc = 0;
   CORE_ADDR end = 0;
   bool explicit_pc = false;
