gdb: add a custom command completer for disassemble command
authorAndrew Burgess <aburgess@redhat.com>
Fri, 20 Oct 2023 13:23:40 +0000 (14:23 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Wed, 8 Nov 2023 11:18:40 +0000 (11:18 +0000)
Add a new command completer function for the disassemble command.
There are two things that this completion function changes.  First,
after the previous commit, the new function calls skip_over_slash_fmt,
which means that hitting tab after entering a /OPT flag now inserts a
space ready to start typing the address to disassemble at:

  (gdb) disassemble /r<TAB>
  (gdb) disassemble /r <CURSOR>

But also, we now get symbol completion after a /OPT option set,
previously this would do nothing:

  (gdb) disassemble /r mai<TAB>

But now:

  (gdb) disassemble /r mai<TAB>
  (gdb) disassemble /r main <CURSOR>

Which was my main motivation for working on this commit.

However, I have made a second change in the completion function.
Currently, the disassemble command calls the generic
location_completer function, however, the disassemble docs say:

     Note that the 'disassemble' command's address arguments are specified
  using expressions in your programming language (*note Expressions:
  Expressions.), not location specs (*note Location Specifications::).
  So, for example, if you want to disassemble function 'bar' in file
  'foo.c', you must type 'disassemble 'foo.c'::bar' and not 'disassemble
  foo.c:bar'.

And indeed, if I try:

  (gdb) disassemble hello.c:main
  No symbol "hello" in current context.
  (gdb) disassemble hello.c::main
  No symbol "hello" in current context.
  (gdb) disassemble 'hello.c'::main
  Dump of assembler code for function main:
  ... snip ...

But, if I do this:

  (gdb) disassemble hell<TAB>
  (gdb) disassemble hello.c:<CURSOR>

which is a consequence of using the location_completer function.  So
in this commit, after calling skip_over_slash_fmt, I forward the bulk
of the disassemble command completion to expression_completer.  Now
when I try this:

  (gdb) disassemble hell<TAB>

gives nothing, which I think is an improvement.  There is one slight
disappointment, if I do:

  (gdb) disassemble 'hell<TAB>

I still get nothing.  I had hoped that this would expand to:
'hello.c':: but I guess this is a limitation of the current
expression_completer implementation, however, I don't think this is a
regression, the previous expansion was just wrong.  Fixing
expression_completer is out of scope for this commit.

I've added some disassembler command completion tests, and also a test
that disassembling using 'FILE'::FUNC syntax works, as I don't think
that is tested anywhere.

gdb/cli/cli-cmds.c
gdb/testsuite/gdb.base/completion.exp
gdb/testsuite/gdb.disasm/basics.exp

index 90989588babc0ffdedda086ce9e651fa3e8b73ce..fd93e5b4ccbb2c14fbf0b648159a031e72b6de4d 100644 (file)
@@ -1698,6 +1698,20 @@ disassemble_command (const char *arg, int from_tty)
   print_disassembly (gdbarch, name, low, high, block, flags);
 }
 
+/* Command completion for the disassemble command.  */
+
+static void
+disassemble_command_completer (struct cmd_list_element *ignore,
+                              completion_tracker &tracker,
+                              const char *text, const char * /* word */)
+{
+  if (skip_over_slash_fmt (tracker, &text))
+    return;
+
+  const char *word = advance_to_expression_complete_word_point (tracker, text);
+  expression_completer (ignore, tracker, text, word);
+}
+
 static void
 make_command (const char *arg, int from_tty)
 {
@@ -2855,7 +2869,7 @@ Note that the address is interpreted as an expression, not as a location\n\
 like in the \"break\" command.\n\
 So, for example, if you want to disassemble function bar in file foo.c\n\
 you must type \"disassemble 'foo.c'::bar\" and not \"disassemble foo.c:bar\"."));
-  set_cmd_completer (c, location_completer);
+  set_cmd_completer_handle_brkchars (c, disassemble_command_completer);
 
   c = add_com ("make", class_support, make_command, _("\
 Run the ``make'' program using the rest of the line as arguments."));
index 4686e6f8f340591142f09a9f171b1b383ab54014..15937810d2f524033c72d8cb446f0609e0c2fe34 100644 (file)
@@ -975,3 +975,33 @@ test_gdb_complete_unique "xxx_yyy_" "xxx_yyy_zzz"
 gdb_test_no_output "alias set aaa_bbb_ccc=set debug"
 gdb_test_no_output "maint deprecate set aaa_bbb_ccc"
 test_gdb_complete_unique "set aaa_bbb_" "set aaa_bbb_ccc"
+
+# Test command completion for the disassemble command.
+test_gdb_complete_unique \
+    "disassemble multi_line_if" \
+    "disassemble multi_line_if_conditional"
+
+test_gdb_complete_multiple "disassemble " \
+    "multi_li" "ne_" {
+       "multi_line_if_conditional"
+       "multi_line_while_conditional"
+    }
+
+foreach_with_prefix spc { " " "" } {
+    test_gdb_complete_none "disassemble${spc}/"
+
+    foreach_with_prefix flg { "r" "b" "rb" "s" "m" "ms" } {
+       test_gdb_complete_unique "disassemble${spc}/${flg}" \
+           "disassemble${spc}/${flg}"
+
+       test_gdb_complete_unique \
+           "disassemble${spc}/${flg} multi_line_if" \
+           "disassemble${spc}/${flg} multi_line_if_conditional"
+
+       test_gdb_complete_multiple "disassemble${spc}/${flg} " \
+           "multi_li" "ne_" {
+               "multi_line_if_conditional"
+               "multi_line_while_conditional"
+           }
+    }
+}
index 78df18d9e96f297be3bfad737bc4d90cc8aefb94..3dfc16e04cfb9e4176563248064ce79b72a3134c 100644 (file)
@@ -37,3 +37,7 @@ gdb_test "disassemble /rb main" \
     "Cannot specify both /r and /b\\."
 gdb_test "disassemble /br main" \
     "Cannot specify both /r and /b\\."
+
+# Check disassembly using 'FILE'::FUNC syntax.
+gdb_test "disassemble '$srcfile'::main" \
+    "Dump of assembler code for function main:.*End of assembler dump\\."