[RFC][patch] Allow to disassemble line.

Paul Pluzhnikov
2009-10-02T00:50:06Z

Greetings,

When debugging optimized code, I often need to disassemble current line
(with inlining, that could be quite a lot of assembly).

Currently, I do this by using 'info line' followed by 'disas <start> <end>',
where start and end are cut/pasted.

Needless to say, that is quite inconvenient.

Attached patch makes it so 'disas/l' will disassemble current line, and
'disas/l foo.c:22' will disassemble line 22 of foo.c

This is similar to 'set disassemble-next-line', but not exactly the same,
see below.

I'll appreciate comments.

I realize this will need documentation update as well, which I'll do if
this is considered reasonable.

Thanks,

P.S. With 'set disassemble-next-line on', current GDB appears to not work
as described in the manual. In particular, the manual for it says:

If ON, GDB will display disassembly of the next source line when
execution of the program being debugged stops.

But what GDB actually does is disassemble from *current instruction* to the
end of line.

If the reason for stopping is a breakpoint on the given line, then the
end result is the same either way. If the reason for stopping is a crash,
then you get disassembly only from crash point to end of line.

I think it's reasonable for GDB to behave either way. If it should
disassemble the *entire* current line, this code should be unified with
my patch. If the current behavior is more desirable, the manual should
be fixed instead.

--
Paul Pluzhnikov

2009-10-01 Paul Pluzhnikov <ppluzhnikov@google.com>

* cli/cli-cmds.c (disassemble_sal, disassemble_lines): New function.
(disassemble_command): Handle /l modifier.
(init_cli_cmds): Adjust help text.

Index: cli/cli-cmds.c
===================================================================
RCS file: /cvs/src/src/gdb/cli/cli-cmds.c,v
retrieving revision 1.92
diff -u -p -u -r1.92 cli-cmds.c
--- cli/cli-cmds.c 11 Jul 2009 14:04:23 -0000 1.92
+++ cli/cli-cmds.c 1 Oct 2009 22:26:49 -0000
@@ -964,6 +964,71 @@ disassemble_current_function (int flags)
print_disassembly (gdbarch, name, low, high, flags);
}

+/* Disassemble line of code identified by SAL. */
+
+static void
+disassemble_sal (struct gdbarch *gdbarch, int flags,
+ const char *error_text,
+ const struct symtab_and_line *sal)
+{
+ char *name;
+ CORE_ADDR low, high;
+
+ if (sal->line > 0 && find_line_pc_range (*sal, &low, &high)
+ && find_pc_partial_function (low, &name, NULL, NULL))
+ {
+ if (low < high)
+ print_disassembly (gdbarch, name, low, high, flags);
+ else
+ printf_filtered (_("Line %s:%d contains no code.\n"),
+ sal->symtab->filename, sal->line);
+ }
+ else
+ error ("%s", error_text);
+}
+
+/* Disassemble line LINE. If LINE is NULL, disassemle current line. */
+
+static void
+disassemble_lines (struct gdbarch *gdbarch, int flags, char *line)
+{
+ if (have_full_symbols () == 0 && have_partial_symbols () == 0)
+ error (_("No symbol table is loaded. Use the \"file\" command."));
+
+ if (line == NULL)
+ {
+ struct frame_info *frame;
+ struct symtab_and_line sal = { 0 };
+
+ frame = get_selected_frame (NULL);
+ find_frame_sal (frame, &sal);
+ disassemble_sal (gdbarch, flags,
+ _("No line information for current frame."),
+ &sal);
+ return;
+ }
+ else
+ {
+ struct cleanup *old_cleanups;
+ struct symtabs_and_lines sals;
+
+ sals = decode_line_1 (&line, 0, 0, 0, 0, 0);
+ old_cleanups = make_cleanup (xfree, sals.sals);
+ if (sals.nelts > 1)
+ {
+ printf_filtered (_("Ambiguous line specification:\n"));
+ ambiguous_line_spec (&sals);
+ }
+ else if (sals.sals->line > 0)
+ disassemble_sal (gdbarch, flags, _("Unexpected error"), sals.sals);
+ else
+ error (_("Unable to decode line specification."));
+
+ do_cleanups (old_cleanups);
+ }
+ return;
+}
+
/* Dump a specified section of assembly code.

Usage:
@@ -974,8 +1039,15 @@ disassemble_current_function (int flags)
disassemble [/mr] low high
- dump the assembly code in the range [LOW,HIGH)

+ disassemble /l[mr]
+ - dump the assembly code for current line
+ disassemble /l[mr] linespec
+ - dump the assembly code for linespec
+
A /m modifier will include source code with the assembly.
- A /r modifier will include raw instructions in hex with the assembly. */
+ A /r modifier will include raw instructions in hex with the assembly.
+ A /l modifier changes the meaning of argument to "line" instead of
+ "address". */

static void
disassemble_command (char *arg, int from_tty)
@@ -985,10 +1057,11 @@ disassemble_command (char *arg, int from
char *name;
CORE_ADDR pc, pc_masked;
char *space_index;
- int flags;
+ int flags, disassemble_line;

name = NULL;
flags = 0;
+ disassemble_line = 0;

if (arg && *arg == '/')
{
@@ -1007,6 +1080,9 @@ disassemble_command (char *arg, int from
case 'r':
flags |= DISASSEMBLY_RAW_INSN;
break;
+ case 'l':
+ disassemble_line = 1;
+ break;
default:
error (_("Invalid disassembly modifier."));
}
@@ -1018,7 +1094,10 @@ disassemble_command (char *arg, int from

if (! arg || ! *arg)
{
- disassemble_current_function (flags);
+ if (disassemble_line != 0)
+ disassemble_lines (gdbarch, flags, NULL);
+ else
+ disassemble_current_function (flags);
return;
}

@@ -1028,6 +1107,12 @@ disassemble_command (char *arg, int from
if (!(space_index = (char *) strchr (arg, ' ')))
{
/* One argument. */
+ if (disassemble_line != 0)
+ {
+ /* We are given line coordinates rather than addresses. */
+ disassemble_lines (gdbarch, flags, arg);
+ return;
+ }
pc = parse_and_eval_address (arg);
if (find_pc_partial_function (pc, &name, &low, &high) == 0)
error (_("No function contains specified address."));
@@ -1044,6 +1129,13 @@ disassemble_command (char *arg, int from
{
/* Two arguments. */
*space_index = '\0';
+ if (disassemble_line != 0)
+ {
+ /* We are given line coordinates rather than addresses. */
+ warning (_("Second parameter ignored with /l modifier.\n"));
+ disassemble_lines (gdbarch, flags, arg);
+ return;
+ }
low = parse_and_eval_address (arg);
high = parse_and_eval_address (space_index + 1);
}
@@ -1457,10 +1549,12 @@ With two args if one is empty it stands
c = add_com ("disassemble", class_vars, disassemble_command, _("\
Disassemble a specified section of memory.\n\
Default is the function surrounding the pc of the selected frame.\n\
+With a /l modifier, disassemble current line.\n\
With a /m modifier, source lines are included (if available).\n\
With a /r modifier, raw instructions in hex are included.\n\
With a single argument, the function surrounding that address is dumped.\n\
-Two arguments are taken as a range of memory to dump."));
+Two arguments are taken as a range of memory to dump.\n\
+With a /l modifier, single argument is parsed as line specification."));
set_cmd_completer (c, location_completer);
if (xdb_commands)
add_com_alias ("va", "disassemble", class_xdb, 0);