@@ -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.
@@ -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
@@ -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,
@@ -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);
@@ -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 ()
{
@@ -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)));
}
@@ -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;
@@ -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.
@@ -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 ()
@@ -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 ();
@@ -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'. */
@@ -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\
@@ -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))
{
@@ -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)));
}
@@ -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[] = {
@@ -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 ();
}
@@ -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)
@@ -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;