2016-01-01 04:33:14 +00:00
|
|
|
# Copyright (C) 2014-2016 Free Software Foundation, Inc.
|
PR python/16699: GDB Python command completion with overriden complete vs. completer class
This PR came from a Red Hat bug that was filed recently. I checked and
it still exists on HEAD, so here's a proposed fix. Although this is
marked as a Python backend bug, this is really about the completion
mechanism used by GDB. Since this code reminds me of my first attempt
to make a good noodle, it took me quite some time to fix it in a
non-intrusive way.
The problem is triggered when one registers a completion method inside a
class in a Python script, rather than registering the command using a
completer class directly. For example, consider the following script:
class MyFirstCommand(gdb.Command):
def __init__(self):
gdb.Command.__init__(self,'myfirstcommand',gdb.COMMAND_USER,gdb.COMPLETE_FILENAME)
def invoke(self,argument,from_tty):
raise gdb.GdbError('not implemented')
class MySecondCommand(gdb.Command):
def __init__(self):
gdb.Command.__init__(self,'mysecondcommand',gdb.COMMAND_USER)
def invoke(self,argument,from_tty):
raise gdb.GdbError('not implemented')
def complete(self,text,word):
return gdb.COMPLETE_FILENAME
MyFirstCommand ()
MySecondCommand ()
When one loads this into GDB and tries to complete filenames for both
myfirstcommand and mysecondcommand, she gets:
(gdb) myfirstcommand /hom<TAB>
(gdb) myfirstcommand /home/
^
...
(gdb) mysecondcommand /hom<TAB>
(gdb) mysecondcommand /home
^
(The "^" marks the final position of the cursor after the TAB).
So we see that myfirstcommand honors the COMPLETE_FILENAME class (as
specified in the command creation), but mysecondcommand does not. After
some investigation, I found that the problem lies with the set of word
break characters that is used for each case. The set should be the same
for both commands, but it is not.
During the process of deciding which type of completion should be used,
the code in gdb/completer.c:complete_line_internal analyses the command
that requested the completion and tries to determine the type of
completion wanted by checking which completion function will be called
(e.g., filename_completer for filenames, location_completer for
locations, etc.).
This all works fine for myfirstcommand, because immediately after the
command registration the Python backend already sets its completion
function to filename_completer (which then causes the
complete_line_internal function to choose the right set of word break
chars). However, for mysecondcommand, this decision is postponed to
when the completer function is evaluated, and the Python backend uses an
internal completer (called cmdpy_completer). complete_line_internal
doesn't know about this internal completer, and can't choose the right
set of word break chars in time, which then leads to a bad decision when
completing the "/hom" word.
So, after a few attempts, I decided to create another callback in
"struct cmd_list_element" that will be responsible for handling the case
when there is an unknown completer function for complete_line_internal
to work with. So far, only the Python backend uses this callback, and
only when the user provides a completer method instead of registering
the command directly with a completer class. I think this is the best
option because it not very intrusive (all the other commands will still
work normally), but especially because the whole completion code is so
messy that it would be hard to fix this without having to redesign
things.
I have regtested this on Fedora 18 x86_64, without regressions. I also
included a testcase.
gdb/ChangeLog:
2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* cli/cli-decode.c (set_cmd_completer_handle_brkchars): New
function.
(add_cmd): Set "completer_handle_brkchars" to NULL.
* cli/cli-decode.h (struct cmd_list_element)
<completer_handle_brkchars>: New field.
* command.h (completer_ftype_void): New typedef.
(set_cmd_completer_handle_brkchars): New prototype.
* completer.c (set_gdb_completion_word_break_characters): New
function.
(complete_line_internal): Call "completer_handle_brkchars"
callback from command.
* completer.h: Include "command.h".
(set_gdb_completion_word_break_characters): New prototype.
* python/py-cmd.c (cmdpy_completer_helper): New function.
(cmdpy_completer_handle_brkchars): New function.
(cmdpy_completer): Adjust to use cmdpy_completer_helper.
(cmdpy_init): Set completer_handle_brkchars to
cmdpy_completer_handle_brkchars.
gdb/testsuite/ChangeLog:
2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* gdb.python/py-completion.exp: New file.
* gdb.python/py-completion.py: Likewise.
2014-09-03 20:30:28 +00:00
|
|
|
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
|
|
# (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
# This testcase tests PR python/16699
|
|
|
|
|
|
|
|
import gdb
|
|
|
|
|
|
|
|
class CompleteFileInit(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completefileinit',gdb.COMMAND_USER,gdb.COMPLETE_FILENAME)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
class CompleteFileMethod(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completefilemethod',gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return gdb.COMPLETE_FILENAME
|
|
|
|
|
|
|
|
class CompleteFileCommandCond(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completefilecommandcond',gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
# This is a test made to know if the command
|
|
|
|
# completion still works fine. When the user asks to
|
|
|
|
# complete something like "completefilecommandcond
|
|
|
|
# /path/to/py-completion-t", it should not complete to
|
|
|
|
# "/path/to/py-completion-test/", but instead just
|
|
|
|
# wait for input.
|
|
|
|
if "py-completion-t" in text:
|
|
|
|
return gdb.COMPLETE_COMMAND
|
|
|
|
else:
|
|
|
|
return gdb.COMPLETE_FILENAME
|
|
|
|
|
Fix Python completion when using the "complete" command
This patch is related to PR python/16699, and is an improvement over the
patch posted here:
<https://sourceware.org/ml/gdb-patches/2014-03/msg00301.html>
Keith noticed that, when using the "complete" command on GDB to complete
a Python command, some strange things could happen. In order to
understand what can go wrong, I need to explain how the Python
completion mechanism works.
When the user requests a completion of a Python command by using TAB,
GDB will first try to determine the right set of "brkchars" that will be
used when doing the completion. This is done by actually calling the
"complete" method of the Python class. Then, when we already know the
"brkchars" that will be used, we call the "complete" method again, for
the same values.
If you read the thread mentioned above, you will see that one of the
design decisions was to make the "cmdpy_completer_helper" (which is the
function the does the actual calling of the "complete" method) cache the
first result of the completion, since this result will be used in the
second call, to do the actual completion.
The problem is that the "complete" command does not process the
brkchars, and the current Python completion mechanism (improved by the
patch mentioned above) relies on GDB trying to determine the brkchars,
and then doing the completion itself. Therefore, when we use the
"complete" command instead of doing a TAB-completion on GDB, there is a
scenario where we can use the invalid cache of a previous Python command
that was completed before. For example:
(gdb) A <TAB>
(gdb) complete B
B value1
B value10
B value2
B value3
B value4
B value5
B value6
B value7
B value8
B value9
(gdb) B <TAB>
comp1 comp2 comp4 comp6 comp8
comp10 comp3 comp5 comp7 comp9
Here, we see that "complete B " gave a different result than "B <TAB>".
The reason for that is because "A <TAB>" was called before, and its
completion results were "value*", so when GDB tried to "complete B " it
wrongly answered with the results for A. The problem here is using a
wrong cache (A's cache) for completing B.
We tried to come up with a solution that would preserve the caching
mechanism, but it wasn't really possible. So I decided to completely
remove the cache, and doing the method calling twice for every
completion. This is not optimal, but I do not think it will impact
users noticeably.
It is worth mentioning another small issue that I found. The code was
doing:
wordobj = PyUnicode_Decode (word, sizeof (word), host_charset (), NULL);
which is totally wrong, because using "sizeof" here will lead to always
the same result. So I changed this to use "strlen". The testcase also
catches this problem.
Keith kindly expanded the existing testcase to cover the problem
described above, and everything is passing.
gdb/ChangeLog:
2015-04-08 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* python/py-cmd.c (cmdpy_completer_helper): Adjust function to not
use a caching mechanism. Adjust comments and code to reflect
that. Replace 'sizeof' by 'strlen' when fetching 'wordobj'.
(cmdpy_completer_handle_brkchars): Adjust call to
cmdpy_completer_helper. Call Py_XDECREF for 'resultobj'.
(cmdpy_completer): Likewise.
gdb/testsuite/ChangeLog:
2015-04-08 Keith Seitz <keiths@redhat.com>
PR python/16699
* gdb.python/py-completion.exp: New tests for completion.
* gdb.python/py-completion.py (CompleteLimit1): New class.
(CompleteLimit2): Likewise.
(CompleteLimit3): Likewise.
(CompleteLimit4): Likewise.
(CompleteLimit5): Likewise.
(CompleteLimit6): Likewise.
(CompleteLimit7): Likewise.
2015-04-08 22:27:10 +00:00
|
|
|
class CompleteLimit1(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit1',gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl11", "cl12", "cl13"]
|
|
|
|
|
|
|
|
class CompleteLimit2(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit2',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl21", "cl23", "cl25", "cl27", "cl29",
|
|
|
|
"cl22", "cl24", "cl26", "cl28", "cl210"]
|
|
|
|
|
|
|
|
class CompleteLimit3(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit3',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl31", "cl33", "cl35", "cl37", "cl39",
|
|
|
|
"cl32", "cl34", "cl36", "cl38", "cl310"]
|
|
|
|
|
|
|
|
class CompleteLimit4(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit4',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl41", "cl43", "cl45", "cl47", "cl49",
|
|
|
|
"cl42", "cl44", "cl46", "cl48", "cl410"]
|
|
|
|
|
|
|
|
class CompleteLimit5(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit5',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl51", "cl53", "cl55", "cl57", "cl59",
|
|
|
|
"cl52", "cl54", "cl56", "cl58", "cl510"]
|
|
|
|
|
|
|
|
class CompleteLimit6(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit6',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl61", "cl63", "cl65", "cl67", "cl69",
|
|
|
|
"cl62", "cl64", "cl66", "cl68", "cl610"]
|
|
|
|
|
|
|
|
class CompleteLimit7(gdb.Command):
|
|
|
|
def __init__(self):
|
|
|
|
gdb.Command.__init__(self,'completelimit7',
|
|
|
|
gdb.COMMAND_USER)
|
|
|
|
|
|
|
|
def invoke(self,argument,from_tty):
|
|
|
|
raise gdb.GdbError('not implemented')
|
|
|
|
|
|
|
|
def complete(self,text,word):
|
|
|
|
return ["cl71", "cl73", "cl75", "cl77", "cl79",
|
|
|
|
"cl72", "cl74", "cl76", "cl78", "cl710"]
|
|
|
|
|
PR python/16699: GDB Python command completion with overriden complete vs. completer class
This PR came from a Red Hat bug that was filed recently. I checked and
it still exists on HEAD, so here's a proposed fix. Although this is
marked as a Python backend bug, this is really about the completion
mechanism used by GDB. Since this code reminds me of my first attempt
to make a good noodle, it took me quite some time to fix it in a
non-intrusive way.
The problem is triggered when one registers a completion method inside a
class in a Python script, rather than registering the command using a
completer class directly. For example, consider the following script:
class MyFirstCommand(gdb.Command):
def __init__(self):
gdb.Command.__init__(self,'myfirstcommand',gdb.COMMAND_USER,gdb.COMPLETE_FILENAME)
def invoke(self,argument,from_tty):
raise gdb.GdbError('not implemented')
class MySecondCommand(gdb.Command):
def __init__(self):
gdb.Command.__init__(self,'mysecondcommand',gdb.COMMAND_USER)
def invoke(self,argument,from_tty):
raise gdb.GdbError('not implemented')
def complete(self,text,word):
return gdb.COMPLETE_FILENAME
MyFirstCommand ()
MySecondCommand ()
When one loads this into GDB and tries to complete filenames for both
myfirstcommand and mysecondcommand, she gets:
(gdb) myfirstcommand /hom<TAB>
(gdb) myfirstcommand /home/
^
...
(gdb) mysecondcommand /hom<TAB>
(gdb) mysecondcommand /home
^
(The "^" marks the final position of the cursor after the TAB).
So we see that myfirstcommand honors the COMPLETE_FILENAME class (as
specified in the command creation), but mysecondcommand does not. After
some investigation, I found that the problem lies with the set of word
break characters that is used for each case. The set should be the same
for both commands, but it is not.
During the process of deciding which type of completion should be used,
the code in gdb/completer.c:complete_line_internal analyses the command
that requested the completion and tries to determine the type of
completion wanted by checking which completion function will be called
(e.g., filename_completer for filenames, location_completer for
locations, etc.).
This all works fine for myfirstcommand, because immediately after the
command registration the Python backend already sets its completion
function to filename_completer (which then causes the
complete_line_internal function to choose the right set of word break
chars). However, for mysecondcommand, this decision is postponed to
when the completer function is evaluated, and the Python backend uses an
internal completer (called cmdpy_completer). complete_line_internal
doesn't know about this internal completer, and can't choose the right
set of word break chars in time, which then leads to a bad decision when
completing the "/hom" word.
So, after a few attempts, I decided to create another callback in
"struct cmd_list_element" that will be responsible for handling the case
when there is an unknown completer function for complete_line_internal
to work with. So far, only the Python backend uses this callback, and
only when the user provides a completer method instead of registering
the command directly with a completer class. I think this is the best
option because it not very intrusive (all the other commands will still
work normally), but especially because the whole completion code is so
messy that it would be hard to fix this without having to redesign
things.
I have regtested this on Fedora 18 x86_64, without regressions. I also
included a testcase.
gdb/ChangeLog:
2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* cli/cli-decode.c (set_cmd_completer_handle_brkchars): New
function.
(add_cmd): Set "completer_handle_brkchars" to NULL.
* cli/cli-decode.h (struct cmd_list_element)
<completer_handle_brkchars>: New field.
* command.h (completer_ftype_void): New typedef.
(set_cmd_completer_handle_brkchars): New prototype.
* completer.c (set_gdb_completion_word_break_characters): New
function.
(complete_line_internal): Call "completer_handle_brkchars"
callback from command.
* completer.h: Include "command.h".
(set_gdb_completion_word_break_characters): New prototype.
* python/py-cmd.c (cmdpy_completer_helper): New function.
(cmdpy_completer_handle_brkchars): New function.
(cmdpy_completer): Adjust to use cmdpy_completer_helper.
(cmdpy_init): Set completer_handle_brkchars to
cmdpy_completer_handle_brkchars.
gdb/testsuite/ChangeLog:
2014-09-03 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* gdb.python/py-completion.exp: New file.
* gdb.python/py-completion.py: Likewise.
2014-09-03 20:30:28 +00:00
|
|
|
CompleteFileInit()
|
|
|
|
CompleteFileMethod()
|
|
|
|
CompleteFileCommandCond()
|
Fix Python completion when using the "complete" command
This patch is related to PR python/16699, and is an improvement over the
patch posted here:
<https://sourceware.org/ml/gdb-patches/2014-03/msg00301.html>
Keith noticed that, when using the "complete" command on GDB to complete
a Python command, some strange things could happen. In order to
understand what can go wrong, I need to explain how the Python
completion mechanism works.
When the user requests a completion of a Python command by using TAB,
GDB will first try to determine the right set of "brkchars" that will be
used when doing the completion. This is done by actually calling the
"complete" method of the Python class. Then, when we already know the
"brkchars" that will be used, we call the "complete" method again, for
the same values.
If you read the thread mentioned above, you will see that one of the
design decisions was to make the "cmdpy_completer_helper" (which is the
function the does the actual calling of the "complete" method) cache the
first result of the completion, since this result will be used in the
second call, to do the actual completion.
The problem is that the "complete" command does not process the
brkchars, and the current Python completion mechanism (improved by the
patch mentioned above) relies on GDB trying to determine the brkchars,
and then doing the completion itself. Therefore, when we use the
"complete" command instead of doing a TAB-completion on GDB, there is a
scenario where we can use the invalid cache of a previous Python command
that was completed before. For example:
(gdb) A <TAB>
(gdb) complete B
B value1
B value10
B value2
B value3
B value4
B value5
B value6
B value7
B value8
B value9
(gdb) B <TAB>
comp1 comp2 comp4 comp6 comp8
comp10 comp3 comp5 comp7 comp9
Here, we see that "complete B " gave a different result than "B <TAB>".
The reason for that is because "A <TAB>" was called before, and its
completion results were "value*", so when GDB tried to "complete B " it
wrongly answered with the results for A. The problem here is using a
wrong cache (A's cache) for completing B.
We tried to come up with a solution that would preserve the caching
mechanism, but it wasn't really possible. So I decided to completely
remove the cache, and doing the method calling twice for every
completion. This is not optimal, but I do not think it will impact
users noticeably.
It is worth mentioning another small issue that I found. The code was
doing:
wordobj = PyUnicode_Decode (word, sizeof (word), host_charset (), NULL);
which is totally wrong, because using "sizeof" here will lead to always
the same result. So I changed this to use "strlen". The testcase also
catches this problem.
Keith kindly expanded the existing testcase to cover the problem
described above, and everything is passing.
gdb/ChangeLog:
2015-04-08 Sergio Durigan Junior <sergiodj@redhat.com>
PR python/16699
* python/py-cmd.c (cmdpy_completer_helper): Adjust function to not
use a caching mechanism. Adjust comments and code to reflect
that. Replace 'sizeof' by 'strlen' when fetching 'wordobj'.
(cmdpy_completer_handle_brkchars): Adjust call to
cmdpy_completer_helper. Call Py_XDECREF for 'resultobj'.
(cmdpy_completer): Likewise.
gdb/testsuite/ChangeLog:
2015-04-08 Keith Seitz <keiths@redhat.com>
PR python/16699
* gdb.python/py-completion.exp: New tests for completion.
* gdb.python/py-completion.py (CompleteLimit1): New class.
(CompleteLimit2): Likewise.
(CompleteLimit3): Likewise.
(CompleteLimit4): Likewise.
(CompleteLimit5): Likewise.
(CompleteLimit6): Likewise.
(CompleteLimit7): Likewise.
2015-04-08 22:27:10 +00:00
|
|
|
CompleteLimit1()
|
|
|
|
CompleteLimit2()
|
|
|
|
CompleteLimit3()
|
|
|
|
CompleteLimit4()
|
|
|
|
CompleteLimit5()
|
|
|
|
CompleteLimit6()
|
|
|
|
CompleteLimit7()
|