Skip to content
Snippets Groups Projects
  1. Mar 15, 2023
  2. Mar 14, 2023
    • Tom Tromey's avatar
      Implement DAP variables, scopes, and evaluate requests · 8900a92e
      Tom Tromey authored
      The DAP code already claimed to implement "scopes" and "evaluate", but
      this wasn't done completely correctly.  This patch implements these
      and also implements the "variables" request.
      
      After this patch, variables and scopes correctly report their
      sub-structure.  This also interfaces with the gdb pretty-printer API,
      so the output of pretty-printers is available.
      
      8900a92e
    • Tom Tromey's avatar
      Fix DAP frame bug with older versions of Python · 85c72d70
      Tom Tromey authored
      
      Tom de Vries pointed out that one DAP test failed on Python 3.6
      because gdb.Frame is not hashable.
      
      This patch fixes the problem by using a list to hold the frames.  This
      is less efficient but there normally won't be that many frames.
      
      Tested-by: default avatarTom de Vries <tdevries@suse.de>
      85c72d70
  3. Mar 06, 2023
    • Tom Tromey's avatar
      Fix DAP stackTrace through frames without debuginfo · 68ca7890
      Tom Tromey authored
      The DAP stackTrace implementation did not fully account for frames
      without debuginfo.  Attemping this would yield a result like:
      
      {"request_seq": 5, "type": "response", "command": "stackTrace", "success": false, "message": "'NoneType' object has no attribute 'filename'", "seq": 11}
      
      This patch fixes the problem by adding another check for None.
      68ca7890
  4. Mar 02, 2023
    • Simon Marchi's avatar
      gdb: update some copyright years (2022 -> 2023) · 14ade916
      Simon Marchi authored
      
      The copyright years in the ROCm files (e.g. solib-rocm.c) are wrong,
      they end in 2022 instead of 2023.  I suppose because I posted (or at
      least prepared) the patches in 2022 but merged them in 2023, and forgot
      to update the year.  I found a bunch of other files that are in the same
      situation.  Fix them all up.
      
      Change-Id: Ia55f5b563606c2ba6a89046f22bc0bf1c0ff2e10
      Reviewed-By: default avatarTom Tromey <tom@tromey.com>
      14ade916
  5. Feb 27, 2023
  6. Feb 13, 2023
  7. Feb 10, 2023
    • Tom Tromey's avatar
      Ensure all DAP requests are keyword-only · 5036bde9
      Tom Tromey authored
      Python functions implementing DAP requests should not use positional
      parameters -- it only makes sense to call them with keyword arguments.
      This patch changes the few remaining cases to start with the special
      "*" parameter, following this rule.
      
      5036bde9
  8. Jan 05, 2023
    • Tom de Vries's avatar
      [gdb/python] Avoid queue.SimpleQueue for python 3.6 · 954a1f91
      Tom de Vries authored
      On openSUSE Leap 15.4 with python 3.6, the gdb.dap/basic-dap.exp test-case
      fails as follows:
      ...
      ERROR: eof reading json header
          while executing
      "error "eof reading json header""
          invoked from within
      "expect {
      -i exp19 -timeout 10
              -re "^Content-Length: (\[0-9\]+)\r\n" {
                  set length $expect_out(1,string)
                  exp_continue
              }
              -re "^(\[^\r\n\]+)..."
          ("uplevel" body line 1)
          invoked from within
      "uplevel $body" NONE eof reading json header
      UNRESOLVED: gdb.dap/basic-dap.exp: startup - initialize
      ...
      
      Investigation using a "catch throw" shows that:
      ...
      (gdb)
          at gdb/python/py-utils.c:396
      396             error (_("Error occurred in Python: %s"), msg.get ());
      (gdb) p msg.get ()
      $1 = 0x2b91d10 "module 'queue' has no attribute 'SimpleQueue'"
      ...
      
      The python class queue.SimpleQueue was introduced in python 3.7.
      
      Fix this by falling back to queue.Queue for python <= 3.6.
      
      Tested on x86_64-linux, by successfully running the test-case:
      ...
       # of expected passes            47
      ...
      954a1f91
  9. Jan 02, 2023
    • Tom Tromey's avatar
      Initial implementation of Debugger Adapter Protocol · de7d7cb5
      Tom Tromey authored
      The Debugger Adapter Protocol is a JSON-RPC protocol that IDEs can use
      to communicate with debuggers.  You can find more information here:
      
          https://microsoft.github.io/debug-adapter-protocol/
      
      Frequently this is implemented as a shim, but it seemed to me that GDB
      could implement it directly, via the Python API.  This patch is the
      initial implementation.
      
      DAP is implemented as a new "interp".  This is slightly weird, because
      it doesn't act like an ordinary interpreter -- for example it doesn't
      implement a command syntax, and doesn't use GDB's ordinary event loop.
      However, this seemed like the best approach overall.
      
      To run GDB in this mode, use:
      
          gdb -i=dap
      
      The DAP code will accept JSON-RPC messages on stdin and print
      responses to stdout.  GDB redirects the inferior's stdout to a new
      pipe so that output can be encapsulated by the protocol.
      
      The Python code uses multiple threads to do its work.  Separate
      threads are used for reading JSON from the client and for writing JSON
      to the client.  All GDB work is done in the main thread.  (The first
      implementation used asyncio, but this had some limitations, and so I
      rewrote it to use threads instead.)
      
      This is not a complete implementation of the protocol, but it does
      implement enough to demonstrate that the overall approach works.
      
      There is a rudimentary test suite.  It uses a JSON parser written in
      pure Tcl.  This parser is under the same license as Tcl itself, so I
      felt it was acceptable to simply import it into the tree.
      
      There is also a bit of documentation -- just documenting the new
      interpreter name.
      de7d7cb5
  10. Jan 01, 2023
  11. Oct 21, 2022
    • Maciej W. Rozycki's avatar
      GDB/Python: Make `None' stand for `unlimited' in setting integer parameters · c506be7d
      Maciej W. Rozycki authored
      
      Similarly to booleans and following the fix for PR python/29217 make
      `gdb.parameter' accept `None' for `unlimited' with parameters of the
      PARAM_UINTEGER, PARAM_INTEGER, and PARAM_ZUINTEGER_UNLIMITED types, as
      `None' is already returned by parameters of the two former types, so
      one might expect to be able to feed it back.  It also makes it possible
      to avoid the need to know what the internal integer representation is
      for the special setting of `unlimited'.
      
      Expand the testsuite accordingly.
      
      Approved-By: default avatarSimon Marchi <simon.marchi@polymtl.ca>
      c506be7d
  12. Oct 02, 2022
    • Andrew Burgess's avatar
      gdb/disasm: better intel flavour disassembly styling with Pygments · 6deb7a81
      Andrew Burgess authored
      This commit was inspired by this stackoverflow post:
      
        https://stackoverflow.com/questions/73491793/why-is-there-a-%C2%B1-in-lea-rax-rip-%C2%B1-0xeb3
      
      One of the comments helpfully links to this Python test case:
      
        from pygments import formatters, lexers, highlight
      
        def colorize_disasm(content, gdbarch):
            try:
                lexer = lexers.get_lexer_by_name("asm")
                formatter = formatters.TerminalFormatter()
                return highlight(content, lexer, formatter).rstrip().encode()
            except:
                return None
      
        print(colorize_disasm("lea [rip+0x211]  # COMMENT", None).decode())
      
      Run the test case and you should see that the '+' character is
      underlined, and could be confused with a combined +/- symbol.
      
      What's happening is that Pygments is failing to parse the input text,
      and the '+' is actually being marked in the error style.  The error
      style is red and underlined.
      
      It is worth noting that the assembly instruction being disassembled
      here is an x86-64 instruction in the 'intel' disassembly style, rather
      than the default att style.  Clearly the Pygments module expects the
      att syntax by default.
      
      If we change the test case to this:
      
        from pygments import formatters, lexers, highlight
      
        def colorize_disasm(content, gdbarch):
            try:
                lexer = lexers.get_lexer_by_name("asm")
                lexer.add_filter('raiseonerror')
                formatter = formatters.TerminalFormatter()
                return highlight(content, lexer, formatter).rstrip().encode()
            except:
                return None
      
        res = colorize_disasm("lea rax,[rip+0xeb3] # COMMENT", None)
        if res:
            print(res.decode())
        else:
            print("No result!")
      
      Here I've added the call: lexer.add_filter('raiseonerror'), and I am
      now checking to see if the result is None or not.  Running this and
      the test now print 'No result!' - instead of styling the '+' in the
      error style, we instead give up on the styling attempt.
      
      There are two things we need to fix relating to this disassembly
      text.  First, Pygments is expecting att style disassembly, not the
      intel style that this example uses.  Fortunately, Pygments also
      supports the intel style, all we need to do is use the 'nasm' lexer
      instead of the 'asm' lexer.
      
      However, this leads to the second problem; in our disassembler line we
      have '# COMMENT'.  The "official" Intel disassembler style uses ';'
      for its comment character, however, gas and libopcodes use '#' as the
      comment character, as gas uses ';' for an instruction separator.
      
      Unfortunately, Pygments expects ';' as the comment character, and
      treats '#' as an error, which means, with the addition of the
      'raiseonerror' filter, that any line containing a '#' comment, will
      not get styled correctly.
      
      However, as the i386 disassembler never produces a '#' character other
      than for comments, we can easily "fix" Pygments parsing of the
      disassembly line.  This is done by creating a filter.  This filter
      looks for an Error token with the value '#', we then change this into
      a comment token.  Every token after this (until the end of the line)
      is also converted into a comment.
      
      In this commit I do the following:
      
        1. Check the 'disassembly-flavor' setting and select between the
        'asm' and 'nasm' lexers based on the setting.  If the setting is not
        available then the 'asm' lexer is used by default,
      
        2. Use "add_filter('raiseonerror')" to ensure that the formatted
        output will not include any error text, which would be underlined,
        and might be confusing,
      
        3. If the 'nasm' lexer is selected, then add an additional filter
        that will format '#' and all other text on the line, as a comment,
        and
      
        4. If Pygments throws an exception, instead of returning None,
        return the original, unmodified content.  This will mean that this
        one instruction is printed without styling, but GDB will continue to
        call into the Python code to style later instructions.
      
      I haven't included a test specifically for the above error case,
      though I have manually check that the above case now styles
      correctly (with no underline).  The existing style tests check that
      the disassembler styling still works though, so I know I've not
      generally broken things.
      
      One final thought I have after looking at this issue is that I wonder
      now if using Pygments for styling disassembly from every architecture
      is actually a good idea?
      
      Clearly, the 'asm' lexer is OK with att style x86-64, but not OK with
      intel style x86-64, so who knows how well it will handle other random
      architectures?
      
      When I first added this feature I tested it against some random
      RISC-V, ARM, and X86-64 (att style) code, and it seemed fine, but I
      never tried to make an exhaustive check of all instructions, so its
      quite possible that there are corner cases where things are styled
      incorrectly.
      
      With the above changes I think that things should be a bit better
      now.  If a particular instruction doesn't parse correctly then our
      Pygments based styling code will just not style that one instruction.
      This is combined with the fact that many architectures are now moving
      to libopcodes based styling, which is much more reliable.
      
      So, I think it is fine to keep using Pygments as a fallback mechanism
      for styling all architectures, even if we know it might not be perfect
      in all cases.
      6deb7a81
  13. Aug 30, 2022
    • Tom Tromey's avatar
      Fix flush for sys.stderr · 2d83dd69
      Tom Tromey authored
      GDB overwrites Python's sys.stdout and sys.stderr, but does not
      properly implement the 'flush' method -- it only ever will flush
      stdout.  This patch fixes the bug.  I couldn't find a straightforward
      way to write a test for this.
      
      2d83dd69
  14. Jul 15, 2022
    • Tom Tromey's avatar
      Run 'black' on gdb · bf4d777d
      Tom Tromey authored
      Running 'black' on gdb fixed a couple of small issues.  This patch is
      the result.
      bf4d777d
  15. Jul 08, 2022
  16. Jul 05, 2022
  17. Jun 15, 2022
    • Andrew Burgess's avatar
      gdb/python: implement the print_insn extension language hook · 15e15b2d
      Andrew Burgess authored
      This commit extends the Python API to include disassembler support.
      
      The motivation for this commit was to provide an API by which the user
      could write Python scripts that would augment the output of the
      disassembler.
      
      To achieve this I have followed the model of the existing libopcodes
      disassembler, that is, instructions are disassembled one by one.  This
      does restrict the type of things that it is possible to do from a
      Python script, i.e. all additional output has to fit on a single line,
      but this was all I needed, and creating something more complex would,
      I think, require greater changes to how GDB's internal disassembler
      operates.
      
      The disassembler API is contained in the new gdb.disassembler module,
      which defines the following classes:
      
        DisassembleInfo
      
            Similar to libopcodes disassemble_info structure, has read-only
        properties: address, architecture, and progspace.  And has methods:
        __init__, read_memory, and is_valid.
      
            Each time GDB wants an instruction disassembled, an instance of
        this class is passed to a user written disassembler function, by
        reading the properties, and calling the methods (and other support
        methods in the gdb.disassembler module) the user can perform and
        return the disassembly.
      
        Disassembler
      
            This is a base-class which user written disassemblers should
        inherit from.  This base class provides base implementations of
        __init__ and __call__ which the user written disassembler should
        override.
      
        DisassemblerResult
      
            This class can be used to hold the result of a call to the
        disassembler, it's really just a wrapper around a string (the text
        of the disassembled instruction) and a length (in bytes).  The user
        can return an instance of this class from Disassembler.__call__ to
        represent the newly disassembled instruction.
      
      The gdb.disassembler module also provides the following functions:
      
        register_disassembler
      
            This function registers an instance of a Disassembler sub-class
        as a disassembler, either for one specific architecture, or, as a
        global disassembler for all architectures.
      
        builtin_disassemble
      
            This provides access to GDB's builtin disassembler.  A common
        use case that I see is augmenting the existing disassembler output.
        The user code can call this function to have GDB disassemble the
        instruction in the normal way.  The user gets back a
        DisassemblerResult object, which they can then read in order to
        augment the disassembler output in any way they wish.
      
            This function also provides a mechanism to intercept the
        disassemblers reads of memory, thus the user can adjust what GDB
        sees when it is disassembling.
      
      The included documentation provides a more detailed description of the
      API.
      
      There is also a new CLI command added:
      
        maint info python-disassemblers
      
      This command is defined in the Python gdb.disassemblers module, and
      can be used to list the currently registered Python disassemblers.
      15e15b2d
  18. Apr 04, 2022
  19. Mar 23, 2022
    • Simon Marchi's avatar
      gdb/python: remove Python 2 support · edae3fd6
      Simon Marchi authored
      New in this version:
      
       - Add a PY_MAJOR_VERSION check in configure.ac / AC_TRY_LIBPYTHON.  If
         the user passes --with-python=python2, this will cause a configure
         failure saying that GDB only supports Python 3.
      
      Support for Python 2 is a maintenance burden for any patches touching
      Python support.  Among others, the differences between Python 2 and 3
      string and integer types are subtle.  It requires a lot of effort and
      thinking to get something that behaves correctly on both.  And that's if
      the author and reviewer of the patch even remember to test with Python
      2.
      
      See this thread for an example:
      
        https://sourceware.org/pipermail/gdb-patches/2021-December/184260.html
      
      So, remove Python 2 support.  Update the documentation to state that GDB
      can be built against Python 3 (as opposed to Python 2 or 3).
      
      Update all the spots that use:
      
       - sys.version_info
       - IS_PY3K
       - PY_MAJOR_VERSION
       - gdb_py_is_py3k
      
      ... to only keep the Python 3 portions and drop the use of some
      now-removed compatibility macros.
      
      I did not update the configure script more than just removing the
      explicit references to Python 2.  We could maybe do more there, like
      check the Python version and reject it if that version is not
      supported.  Otherwise (with this patch), things will only fail at
      compile time, so it won't really be clear to the user that they are
      trying to use an unsupported Python version.  But I'm a bit lost in the
      configure code that checks for Python, so I kept that for later.
      
      Change-Id: I75b0f79c148afbe3c07ac664cfa9cade052c0c62
      edae3fd6
  20. Mar 19, 2022
    • Simon Marchi's avatar
      gdb/python: remove gdb._mi_commands dict · 6f3dfea0
      Simon Marchi authored
      
      The motivation for this patch is the fact that py-micmd.c doesn't build
      with Python 2, due to PyDict_GetItemWithError being a Python 3-only
      function:
      
            CXX    python/py-micmd.o
          /home/smarchi/src/binutils-gdb/gdb/python/py-micmd.c: In function ‘int micmdpy_uninstall_command(micmdpy_object*)’:
          /home/smarchi/src/binutils-gdb/gdb/python/py-micmd.c:430:20: error: ‘PyDict_GetItemWithError’ was not declared in this scope; did you mean ‘PyDict_GetItemString’?
            430 |   PyObject *curr = PyDict_GetItemWithError (mi_cmd_dict.get (),
                |                    ^~~~~~~~~~~~~~~~~~~~~~~
                |                    PyDict_GetItemString
      
      A first solution to fix this would be to try to replace
      PyDict_GetItemWithError equivalent Python 2 code.  But I looked at why
      we are doing this in the first place: it is to maintain the
      `gdb._mi_commands` Python dictionary that we use as a `name ->
      gdb.MICommand object` map.  Since the `gdb._mi_commands` dictionary is
      never actually used in Python, it seems like a lot of trouble to use a
      Python object for this.
      
      My first idea was to replace it with a C++ map
      (std::unordered_map<std::string, gdbpy_ref<micmdpy_object>>).  While
      implementing this, I realized we don't really need this map at all.  The
      mi_command_py objects registered in the main MI command table can own
      their backing micmdpy_object (that's a gdb.MICommand, but seen from the
      C++ code).  To know whether an mi_command is an mi_command_py, we can
      use a dynamic cast.  Since there's one less data structure to maintain,
      there are less chances of messing things up.
      
       - Change mi_command_py::m_pyobj to a gdbpy_ref, the mi_command_py is
         now what keeps the MICommand alive.
       - Set micmdpy_object::mi_command in the constructor of mi_command_py.
         If mi_command_py manages setting/clearing that field in
         swap_python_object, I think it makes sense that it also takes care of
         setting it initially.
       - Move a bunch of checks from micmdpy_install_command to
         swap_python_object, and make them gdb_asserts.
       - In micmdpy_install_command, start by doing an mi_cmd_lookup.  This is
         needed to know whether there's a Python MI command already registered
         with that name.  But we can already tell if there's a non-Python
         command registered with that name.  Return an error if that happens,
         rather than waiting for insert_mi_cmd_entry to fail.  Change the
         error message to "name is already in use" rather than "may already be
         in use", since it's more precise.
      
      I asked Andrew about the original intent of using a Python dictionary
      object to hold the command objects.  The reason was to make sure the
      objects get destroyed when the Python runtime gets finalized, not later.
      Holding the objects in global C++ data structures and not doing anything
      more means that the held Python objects will be decref'd after the
      Python interpreter has been finalized.  That's not desirable.  I tried
      it and it indeed segfaults.
      
      Handle this by adding a gdbpy_finalize_micommands function called in
      finalize_python.  This is the mirror of gdbpy_initialize_micommands
      called in do_start_initialization.  In there, delete all Python MI
      commands.  I think it makes sense to do it this way: if it was somehow
      possible to unload Python support from GDB in the middle of a session
      we'd want to unregister any Python MI command.  Otherwise, these MI
      commands would be backed with a stale PyObject or simply nothing.
      
      Delete tests that were related to `gdb._mi_commands`.
      
      Co-Authored-By: default avatarAndrew Burgess <aburgess@redhat.com>
      Change-Id: I060d5ebc7a096c67487998a8a4ca1e8e56f12cd3
      6f3dfea0
  21. Mar 14, 2022
    • Andrew Burgess's avatar
      gdb/python/mi: create MI commands using python · 740b42ce
      Andrew Burgess authored
      This commit allows a user to create custom MI commands using Python
      similarly to what is possible for Python CLI commands.
      
      A new subclass of mi_command is defined for Python MI commands,
      mi_command_py. A new file, gdb/python/py-micmd.c contains the logic
      for Python MI commands.
      
      This commit is based on work linked too from this mailing list thread:
      
        https://sourceware.org/pipermail/gdb/2021-November/049774.html
      
      Which has also been previously posted to the mailing list here:
      
        https://sourceware.org/pipermail/gdb-patches/2019-May/158010.html
      
      And was recently reposted here:
      
        https://sourceware.org/pipermail/gdb-patches/2022-January/185190.html
      
      The version in this patch takes some core code from the previously
      posted patches, but also has some significant differences, especially
      after the feedback given here:
      
        https://sourceware.org/pipermail/gdb-patches/2022-February/185767.html
      
      
      
      A new MI command can be implemented in Python like this:
      
        class echo_args(gdb.MICommand):
            def invoke(self, args):
                return { 'args': args }
      
        echo_args("-echo-args")
      
      The 'args' parameter (to the invoke method) is a list
      containing (almost) all command line arguments passed to the MI
      command (--thread and --frame are handled before the Python code is
      called, and removed from the args list).  This list can be empty if
      the MI command was passed no arguments.
      
      When used within gdb the above command produced output like this:
      
        (gdb)
        -echo-args a b c
        ^done,args=["a","b","c"]
        (gdb)
      
      The 'invoke' method of the new command must return a dictionary.  The
      keys of this dictionary are then used as the field names in the mi
      command output (e.g. 'args' in the above).
      
      The values of the result returned by invoke can be dictionaries,
      lists, iterators, or an object that can be converted to a string.
      These are processed recursively to create the mi output.  And so, this
      is valid:
      
        class new_command(gdb.MICommand):
            def invoke(self,args):
                return { 'result_one': { 'abc': 123, 'def': 'Hello' },
                         'result_two': [ { 'a': 1, 'b': 2 },
                                         { 'c': 3, 'd': 4 } ] }
      
      Which produces output like:
      
        (gdb)
        -new-command
        ^done,result_one={abc="123",def="Hello"},result_two=[{a="1",b="2"},{c="3",d="4"}]
        (gdb)
      
      I have required that the fields names used in mi result output must
      match the regexp: "^[a-zA-Z][-_a-zA-Z0-9]*$" (without the quotes).
      This restriction was never written down anywhere before, but seems
      sensible to me, and we can always loosen this rule later if it proves
      to be a problem.  Much harder to try and add a restriction later, once
      people are already using the API.
      
      What follows are some details about how this implementation differs
      from the original patch that was posted to the mailing list.
      
      In this patch, I have changed how the lifetime of the Python
      gdb.MICommand objects is managed.  In the original patch, these object
      were kept alive by an owned reference within the mi_command_py object.
      As such, the Python object would not be deleted until the
      mi_command_py object itself was deleted.
      
      This caused a problem, the mi_command_py were held in the global mi
      command table (in mi/mi-cmds.c), which, as a global, was not cleared
      until program shutdown.  By this point the Python interpreter has
      already been shutdown.  Attempting to delete the mi_command_py object
      at this point was causing GDB to try and invoke Python code after
      finalising the Python interpreter, and we would crash.
      
      To work around this problem, the original patch added code in
      python/python.c that would search the mi command table, and delete the
      mi_command_py objects before the Python environment was finalised.
      
      In contrast, in this patch, I have added a new global dictionary to
      the gdb module, gdb._mi_commands.  We already have several such global
      data stores related to pretty printers, and frame unwinders.
      
      The MICommand objects are placed into the new gdb.mi_commands
      dictionary, and it is this reference that keeps the objects alive.
      When GDB's Python interpreter is shut down gdb._mi_commands is deleted,
      and any MICommand objects within it are deleted at this point.
      
      This change avoids having to make the mi_cmd_table global, and walk
      over it from within GDB's python related code.
      
      This patch handles command redefinition entirely within GDB's python
      code, though this does impose one small restriction which is not
      present in the original code (detailed below), I don't think this is a
      big issue.  However, the original patch relied on being able to
      finish executing the mi_command::do_invoke member function after the
      mi_command object had been deleted.  Though continuing to execute a
      member function after an object is deleted is well defined, it is
      also (IMHO) risky, its too easy for someone to later add a use of the
      object without realising that the object might sometimes, have been
      deleted.  The new patch avoids this issue.
      
      The one restriction that is added to avoid this, is that an MICommand
      object can't be reinitialised with a different command name, so:
      
        (gdb) python cmd = MyMICommand("-abc")
        (gdb) python cmd.__init__("-def")
        can't reinitialize object with a different command name
      
      This feels like a pretty weird edge case, and I'm happy to live with
      this restriction.
      
      I have also changed how the memory is managed for the command name.
      In the most recently posted patch series, the command name is moved
      into a subclass of mi_command, the python mi_command_py, which
      inherits from mi_command is then free to use a smart pointer to manage
      the memory for the name.
      
      In this patch, I leave the mi_command class unchanged, and instead
      hold the memory for the name within the Python object, as the lifetime
      of the Python object always exceeds the c++ object stored in the
      mi_cmd_table.  This adds a little more complexity in py-micmd.c, but
      leaves the mi_command class nice and simple.
      
      Next, this patch adds some extra functionality, there's a
      MICommand.name read-only attribute containing the name of the command,
      and a read-write MICommand.installed attribute that can be used to
      install (make the command available for use) and uninstall (remove the
      command from the mi_cmd_table so it can't be used) the command.  This
      attribute will be automatically updated if a second command replaces
      an earlier command.
      
      This patch adds additional error handling, and makes more use the
      gdbpy_handle_exception function.
      
      Co-Authored-By: default avatarJan Vrany <jan.vrany@labware.com>
      740b42ce
  22. Feb 14, 2022
    • Andrew Burgess's avatar
      gdb/python: move styling support to gdb.styling · 7b8c55af
      Andrew Burgess authored
      This commit moves the two Python functions that are used for styling
      into a new module, gdb.styling, there's then a small update in
      python.c so GDB can find the functions in their new location.
      
      The motivation for this change is purely to try and reduce the clutter
      in the top-level gdb module, and encapsulate related functions into
      modules.  I did ponder documenting these functions as part of the
      Python API, however, doing so would effectively "fix" the API, and I'm
      still wondering if there's improvements that could be made, also, the
      colorize function is only called in some cases now that GDB prefers
      libsource-highlight, so it's not entirely sure how this would work as
      part of a user facing API.
      
      Still, despite these functions never having been part of a documented
      API, it is possible that a user out there has overridden these to, in
      some way, customize how GDB performs styling.  Moving the function as
      I propose in this patch could break things for that user, however,
      fixing this breakage is trivial, and, as these functions were never
      documented, I don't think we should be obliged to not break user code
      that relies on them.
      7b8c55af
    • Andrew Burgess's avatar
      gdb: use python to colorize disassembler output · e867795e
      Andrew Burgess authored
      This commit adds styling support to the disassembler output, as such
      two new commands are added to GDB:
      
        set style disassembler enabled on|off
        show style disassembler enabled
      
      In this commit I make use of the Python Pygments package to provide
      the styling.  I did investigate making use of libsource-highlight,
      however, I found the highlighting results to be inferior to those of
      Pygments; only some mnemonics were highlighted, and highlighting of
      register names such as r9d and r8d (on x86-64) was incorrect.
      
      To enable disassembler highlighting via Pygments, I've added a new
      extension language hook, which is then implemented for Python.  This
      hook is very similar to the existing hook for source code
      colorization.
      
      One possibly odd choice I made with the new hook is to pass a
      gdb.Architecture through, even though this is currently unused.  The
      reason this argument is not used is that, currently, styling is
      performed identically for all architectures.
      
      However, even though the Python function used to perform styling of
      disassembly output is not part of any documented API, I don't want
      to close the door on a user overriding this function to provide
      architecture specific styling.  To do this, the user would inevitably
      require access to the gdb.Architecture, and so I decided to add this
      field now.
      
      The styling is applied within gdb_disassembler::print_insn, to achieve
      this, gdb_disassembler now writes its output into a temporary buffer,
      styling is then applied to the contents of this buffer.  Finally the
      gdb_disassembler buffer is copied out to its final destination stream.
      
      There's a new test to check that the disassembler output includes some
      escape sequences, though I don't check for specific colours; the
      precise colors will depend on which instructions are in the
      disassembler output, and, I guess, how pygments is configured.
      
      The only negative change with this commit is how we currently style
      addresses in GDB.
      
      Currently, when the disassembler wants to print an address, we call
      back into GDB, and GDB prints the address value using the `address`
      styling, and the symbol name using `function` styling.  After this
      commit, if pygments is used, then all disassembler styling is done
      through pygments, and this include the address and symbol name parts
      of the disassembler output.
      
      I don't know how much of an issue this will be for people.  There's
      already some precedent for this in GDB when we look at source styling.
      For example, function names in styled source listings are not styled
      using the `function` style, but instead, either GNU Source Highlight,
      or pygments gets to decide how the function name should be styled.
      
      If the Python pygments library is not present then GDB will continue
      to behave as it always has, the disassembler output is mostly
      unstyled, but the address and symbols are styled using the `address`
      and `function` styles, as they are today.
      
      However, if the user does `set style disassembler enabled off`, then
      all disassembler styling is switched off.  This obviously covers the
      use of pygments, but also includes the minimal styling done by GDB
      when pygments is not available.
      e867795e
  23. Feb 02, 2022
    • Andrew Burgess's avatar
      gdb: fix formatting for help set/show extended-prompt · 2f6b20e2
      Andrew Burgess authored
      The formatting of the help text for 'help set extended-prompt' and
      'help show extended-prompt' is a little off.
      
      Here's the offending snippet:
      
          Substitutions are applied to VALUE to compute the real prompt.
      
          The currently defined substitutions are:
            \[	Begins a sequence of non-printing characters.
        \\	A backslash.
        \]	Ends a sequence of non-printing characters.
        \e	The ESC character.
      
      Notice that the line for '\[' is indented more that the others.
      
      Turns out this is due to how we build this help text, something which
      is done in Python.  We extended a classes __doc__ string with some
      dynamically generated text.
      
      The classes doc string looks like this:
      
          """Set the extended prompt.
      
          Usage: set extended-prompt VALUE
      
          Substitutions are applied to VALUE to compute the real prompt.
      
          The currently defined substitutions are:
          """
      
      Notice the closing """ are in a line of their own, and include some
      white space just before.  It's this extra white space that's causing
      the problem.
      
      Fix the formatting issue by moving the """ to the end of the previous
      line.  I then add the extra newline in at the point where the doc
      string is merged with the dynamically generated text.
      
      Now everything lines up correctly.
      2f6b20e2
  24. Jan 27, 2022
    • Andrew Burgess's avatar
      gdb/python: handle non utf-8 characters when source highlighting · 299953ca
      Andrew Burgess authored
      This commit adds support for source files that contain non utf-8
      characters when performing source styling using the Python pygments
      package.  This does not change the behaviour of GDB when the GNU
      Source Highlight library is used.
      
      For the following problem description, assume that either GDB is built
      without GNU Source Highlight support, of that this has been disabled
      using 'maintenance set gnu-source-highlight enabled off'.
      
      The initial problem reported was that a source file containing non
      utf-8 characters would cause GDB to print a Python exception, and then
      display the source without styling, e.g.:
      
        Python Exception <class 'UnicodeDecodeError'>: 'utf-8' codec can't decode byte 0xc0 in position 142: invalid start byte
        /* Source code here, without styling...  */
      
      Further, as the user steps through different source files, each time
      the problematic source file was evicted from the source cache, and
      then later reloaded, the exception would be printed again.
      
      Finally, this problem is only present when using Python 3, this issue
      is not present for Python 2.
      
      What makes this especially frustrating is that GDB can clearly print
      the source file contents, they're right there...  If we disable
      styling completely, or make use of the GNU Source Highlight library,
      then everything is fine.  So why is there an error when we try to
      apply styling using Python?
      
      The problem is the use of PyString_FromString (which is an alias for
      PyUnicode_FromString in Python 3), this function converts a C string
      into a either a Unicode object (Py3) or a str object (Py2).  For
      Python 2 there is no unicode encoding performed during this function
      call, but for Python 3 the input is assumed to be a uft-8 encoding
      string for the purpose of the conversion.  And here of course, is the
      problem, if the source file contains non utf-8 characters, then it
      should not be treated as utf-8, but that's what we do, and that's why
      we get an error.
      
      My first thought when looking at this was to spot when the
      PyString_FromString call failed with a UnicodeDecodeError and silently
      ignore the error.  This would mean that GDB would print the source
      without styling, but would also avoid the annoying exception message.
      
      However, I also make use of `pygmentize`, a command line wrapper
      around the Python pygments module, which I use to apply syntax
      highlighting in the output of `less`.  And this command line wrapper
      is quite happy to syntax highlight my source file that contains non
      utf-8 characters, so it feels like the problem should be solvable.
      
      It turns out that inside the pygments module there is already support
      for guessing the encoding of the incoming file content, if the
      incoming content is not already a Unicode string.  This is what
      happens for Python 2 where the incoming content is of `str` type.
      
      We could try and make GDB smarter when it comes to converting C
      strings into Python Unicode objects; this would probably require us to
      just try a couple of different encoding schemes rather than just
      giving up after utf-8.
      
      However, I figure, why bother?  The pygments module already does this
      for us, and the colorize API is not part of the documented external
      API of GDB.  So, why not just change the colorize API, instead of the
      content being a Unicode string (for Python 3), lets just make the
      content be a bytes object.  The pygments module can then take
      responsibility for guessing the encoding.
      
      So, currently, the colorize API receives a unicode object, and returns
      a unicode object.  I propose that the colorize API receive a bytes
      object, and return a bytes object.
      299953ca
  25. Jan 26, 2022
    • Tom Tromey's avatar
      Add a way to temporarily set a gdb parameter from Python · b583c328
      Tom Tromey authored
      It's sometimes useful to temporarily set some gdb parameter from
      Python.  Now that the 'endian' crash is fixed, and now that the
      current language is no longer captured by the Python layer, it seems
      reasonable to add a helper function for this situation.
      
      This adds a new gdb.with_parameter function.  This creates a context
      manager which temporarily sets some parameter to a specified value.
      The old value is restored when the context is exited.  This is most
      useful with the Python "with" statement:
      
         with gdb.with_parameter('language', 'ada'):
            ... do Ada stuff
      
      This also adds a simple function to set a parameter,
      gdb.set_parameter, as suggested by Andrew.
      
      This is PR python/10790.
      
      Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=10790
      
      
      b583c328
  26. Jan 01, 2022
  27. Dec 16, 2021
  28. Oct 02, 2021
    • Simon Marchi's avatar
      gdb/python: fix a few flake8 warnings · 1e9983e7
      Simon Marchi authored
      Fix these rather obvious warnings reported by flake8:
      
          ./lib/gdb/FrameIterator.py:16:1: F401 'gdb' imported but unused
          ./lib/gdb/FrameIterator.py:17:1: F401 'itertools' imported but unused
          ./lib/gdb/command/prompt.py:55:26: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
          ./lib/gdb/command/explore.py:526:9: F841 local variable 'has_explorable_fields' is assigned to but never used
          ./lib/gdb/command/explore.py:697:56: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
          ./lib/gdb/command/explore.py:736:62: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
          ./lib/gdb/command/explore.py:767:61: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
          ./lib/gdb/command/frame_filters.py:21:1: F401 'copy' imported but unused
          ./lib/gdb/command/frame_filters.py:22:1: F401 'gdb.FrameIterator.FrameIterator' imported but unused
          ./lib/gdb/command/frame_filters.py:23:1: F401 'gdb.FrameDecorator.FrameDecorator' imported but unused
          ./lib/gdb/command/frame_filters.py:25:1: F401 'itertools' imported but unused
          ./lib/gdb/command/frame_filters.py:179:17: E712 comparison to True should be 'if cond is True:' or 'if cond:'
      
      Change-Id: I4f49c0cb430359ee872222600c61d9c5283b09ab
      1e9983e7
  29. Jun 22, 2021
    • Simon Marchi's avatar
      gdb: fix python/lib/gdb/__init__.py formatting · 224506e9
      Simon Marchi authored
      Run black to fix this formatting.
      
      gdb/ChangeLog:
      
      	* python/lib/gdb/__init__.py: Format.
      
      Change-Id: I68ea306d1991bf7243b2c8aeeb11719d668851e5
      224506e9
    • Simon Marchi's avatar
      gdb/python: print name of unwinder that claimed frame in debug message · 4e317a76
      Simon Marchi authored
      If we have multiple registered unwinders, this will helps identify which
      unwinder was chosen and make it easier to track down potential problems.
      Unwinders have a mandatory name argument, which we can use in the
      message.
      
      First, make gdb._execute_unwinders return a tuple containing the name,
      in addition to the UnwindInfo.  Then, make pyuw_sniffer include the name
      in the debug message.
      
      I moved the debug message earlier.  I think it's good to print it as
      early as possible, so that we see it in case an assert is hit in the
      loop below, for example.
      
      gdb/ChangeLog:
      
      	* python/lib/gdb/__init__.py (_execute_unwinders): Return tuple
      	with name of chosen unwinder.
      	* python/py-unwind.c (pyuw_sniffer): Print name of chosen
      	unwinder in debug message.
      
      Change-Id: Id603545b44a97df2a39dd1872fe1f38ad5059f03
      4e317a76
  30. Jun 09, 2021
    • Lancelot SIX's avatar
      Use is/is not to check for None in python code. · f9e59d06
      Lancelot SIX authored
      While reviewing a patch sent to the mailing list, I noticed there are few
      places where python code checks if a variable is 'None' or not by using the
      comparison operators '==' and '!='.  PEP8[1], which is used as coding standard
      in GDB coding standards, recommends using 'is' / 'is not' when comparing to a
      singleton such as 'None'.
      
      This patch proposes to change the instances of '== None' by 'is None' and
      '!= None' by 'is not None'.
      
      [1] https://www.python.org/dev/peps/pep-0008/
      
      gdb/doc/ChangeLog:
      
      	* python.texi (Writing a Pretty-Printer): Use 'is None' instead of
      	'== None'.
      
      gdb/ChangeLog:
      
      	* python/lib/gdb/FrameDecorator.py (FrameDecorator): Use 'is None' instead of
      	'== None'.
      	(FrameVars): Use 'is not None' instead of '!= None'.
      	* python/lib/gdb/command/frame_filters.py (SetFrameFilterPriority): Use 'is None'
      	instead of '== None' and 'is not None' instead of '!= None'.
      
      gdb/testsuite/ChangeLog:
      
      	* gdb.base/premature-dummy-frame-removal.py (TestUnwinder): Use
      	'is None' instead of '== None' and 'is not None' instead of
      	'!= None'.
      	* gdb.python/py-frame-args.py (lookup_function): Same.
      	* gdb.python/py-framefilter-invalidarg.py (Reverse_Function): Same.
      	* gdb.python/py-framefilter.py (Reverse_Function): Same.
      	* gdb.python/py-nested-maps.py (lookup_function): Same.
      	* gdb.python/py-objfile-script-gdb.py (lookup_function): Same.
      	* gdb.python/py-prettyprint.py (lookup_function): Same.
      	* gdb.python/py-section-script.py (lookup_function): Same.
      	* gdb.python/py-unwind-inline.py (dummy_unwinder): Same.
      	* gdb.python/python.exp: Same.
      	* gdb.rust/pp.py (lookup_function): Same.
      f9e59d06
  31. May 07, 2021
    • Simon Marchi's avatar
      gdb: re-format Python files using black 21.4b0 · 13123da8
      Simon Marchi authored
      Re-format all Python files using black [1] version 21.4b0.  The goal is
      that from now on, we keep all Python files formatted using black.  And
      that we never have to discuss formatting during review (for these files
      at least) ever again.
      
      One change is needed in gdb.python/py-prettyprint.exp, because it
      matches the string representation of an exception, which shows source
      code.  So the change in formatting must be replicated in the expected
      regexp.
      
      To document our usage of black I plan on adding this to the "GDB Python
      Coding Standards" wiki page [2]:
      
      --8<--
      
      All Python source files under the `gdb/` directory must be formatted
      using black version 21.4b0.
      
      This specific version can be installed using:
      
          $ pip3 install 'black == 21.4b0'
      
      All you need to do to re-format files is run `black <file/directory>`,
      and black will re-format any Python file it finds in there.  It runs
      quite fast, so the simplest is to do:
      
          $ black gdb/
      
      from the top-level.
      
      If you notice that black produces changes unrelated to your patch, it's
      probably because someone forgot to run it before you.  In this case,
      don't include unrelated hunks in your patch.  Push an obvious patch
      fixing the formatting and rebase your work on top of that.
      
      -->8--
      
      Once this is merged, I plan on setting a up an `ignoreRevsFile`
      config so that git-blame ignores this commit, as described here:
      
        https://github.com/psf/black#migrating-your-code-style-without-ruining-git-blame
      
      I also plan on working on a git commit hook (checked in the repo) to
      automatically check the formatting of the Python files on commit.
      
      [1] https://pypi.org/project/black/
      [2] https://sourceware.org/gdb/wiki/Internals%20GDB-Python-Coding-Standards
      
      gdb/ChangeLog:
      
      	* Re-format all Python files using black.
      
      gdb/testsuite/ChangeLog:
      
      	* Re-format all Python files using black.
      	* gdb.python/py-prettyprint.exp (run_lang_tests): Adjust.
      
      Change-Id: I28588a22c2406afd6bc2703774ddfff47cd61919
      13123da8
  32. Apr 01, 2021
    • Boris Staletic's avatar
      Use importlib instead of imp module on python 3.4+ · bfb9f5dc
      Boris Staletic authored
      Python 3.4 has deprecated the imp module in favour of importlib. This
      patch avoids the DeprecationWarning. This warning is visible to users
      whose libpython.so has been compiled with --with-pydebug.
      
      Considering that even python 3.5 has reached end of life, would it be
      better to just use importlib and drop support for python 3.0 to 3.3?
      
      2021-02-28  Boris Staletic  <boris.staletic@gmail.com>
      
      	* gdb/python/lib/gdb/__init__.py: Use importlib on python 3.4+
      	to avoid deprecation warnings.
      bfb9f5dc
  33. Jan 01, 2021
  34. Apr 10, 2020
    • Tom de Vries's avatar
      [gdb/cli] Don't let python colorize strip leading newlines · bdfc1e8a
      Tom de Vries authored
      Consider the test-case gdb.base/async.exp.  Using the executable, I run to
      main, and land on a line advertised as line 26:
      ...
      $ gdb outputs/gdb.base/async/async -ex start
      Reading symbols from outputs/gdb.base/async/async...
      Temporary breakpoint 1 at 0x4004e4: file gdb.base/async.c, line 26.
      Starting program: outputs/gdb.base/async/async
      
      Temporary breakpoint 1, main () at gdb.base/async.c:26
      26       y = foo ();
      ...
      
      But actually, the line turns out to be line 28:
      ...
      $ cat -n gdb.base/async.c
          ...
          26   y = 2;
          27   z = 9;
          28   y = foo ();
      ...
      
      This is caused by the following: the python colorizer initializes the lexer
      with default options (no second argument to get_lexer_for_filename):
      ...
          def colorize(filename, contents):
              # Don't want any errors.
              try:
                  lexer = lexers.get_lexer_for_filename(filename)
                  formatter = formatters.TerminalFormatter()
                  return highlight(contents, lexer, formatter)
      ...
      which include option stripnl=True, which strips leading and trailing newlines.
      
      This causes the python colorizer to strip the two leading newlines of async.c.
      
      Fix this by initializing the lexer with stripnl=False.
      
      Build and reg-tested on x86_64-linux.
      
      gdb/ChangeLog:
      
      2020-04-10  Tom de Vries  <tdevries@suse.de>
      
      	PR cli/25808
      	* python/lib/gdb/__init__.py: Initialize lexer with stripnl=False.
      
      gdb/testsuite/ChangeLog:
      
      2020-04-10  Tom de Vries  <tdevries@suse.de>
      
      	PR cli/25808
      	* gdb.base/style.c: Add leading newlines.
      	* gdb.base/style.exp: Use gdb_get_line_number to get specific lines.
      	Check listing of main's one-line body.
      bdfc1e8a
  35. Jan 21, 2020
    • Tom Tromey's avatar
      Allow use of Pygments to colorize source code · f6474de9
      Tom Tromey authored
      While GNU Source Highlight is good, it's also difficult to build and
      distribute.  For one thing, it needs Boost.  For another, it has an
      unusual configuration and installation setup.
      
      Pygments, a Python library, doesn't suffer from these issues, and so I
      thought it would be a reasonable fallback.
      
      This patch implements this idea.  GNU Source Highlight is preferred,
      but if it is unavailable (or fails), the extension languages are
      tried.  This patch also implements support for Pygments.
      
      Something similar could be done for Guile, using:
      
          https://dthompson.us/projects/guile-syntax-highlight.html
      
      However, I don't know enough about Guile internals to make this
      happen, so I have not done it here.
      
      gdb/ChangeLog
      2020-01-21  Tom Tromey  <tromey@adacore.com>
      
      	* source-cache.c (source_cache::ensure): Call ext_lang_colorize.
      	* python/python.c (python_extension_ops): Update.
      	(gdbpy_colorize): New function.
      	* python/lib/gdb/__init__.py (colorize): New function.
      	* extension.h (ext_lang_colorize): Declare.
      	* extension.c (ext_lang_colorize): New function.
      	* extension-priv.h (struct extension_language_ops) <colorize>: New
      	member.
      	* cli/cli-style.c (_initialize_cli_style): Update help text.
      
      Change-Id: I5e21623ee05f1f66baaa6deaeca78b578c031bf4
      f6474de9
  36. Jan 01, 2020
  37. Oct 09, 2019
    • Tom de Vries's avatar
      [gdb/target] Fix pretty-printer for MPX bnd registers · cff32449
      Tom de Vries authored
      I'm seeing this failure:
      ...
      (gdb) print /x $bnd0 = {0x10, 0x20}^M
      $23 = {lbound = 0x10, ubound = 0x20}^M
      (gdb) FAIL: gdb.arch/i386-mpx.exp: verify size for bnd0
      ...
      
      The test expects a pretty printer to be actived printing 'size 17':
      ...
      set test_string ".*\\\: size 17.*"
      gdb_test "print /x \$bnd0 = {0x10, 0x20}" "$test_string" "verify size for bnd0"
      ...
      but that doesn't happen.
      
      The pretty printer is for the type of the $bnd0 register, which is created
      here in i386_bnd_type:
      ...
            t = arch_composite_type (gdbarch,
                                     "__gdb_builtin_type_bound128", TYPE_CODE_STRUCT);
      
            append_composite_type_field (t, "lbound", bt->builtin_data_ptr);
            append_composite_type_field (t, "ubound", bt->builtin_data_ptr);
      
            TYPE_NAME (t) = "builtin_type_bound128";
      ...
      
      And the pretty-printer is registered here in
      gdb/python/lib/gdb/printer/bound_registers.py:
      ...
      gdb.printing.add_builtin_pretty_printer ('mpx_bound128',
                                               '^__gdb_builtin_type_bound128',
                                               MpxBound128Printer)
      ...
      
      Fix the pretty printer by changing the regexp argument of
      add_builtin_pretty_printer to match "builtin_type_bound128", the TYPE_NAME.
      
      Tested on x86_64-linux.
      
      gdb/ChangeLog:
      
      2019-10-09  Tom de Vries  <tdevries@suse.de>
      
      	* python/lib/gdb/printer/bound_registers.py: Use
      	'^builtin_type_bound128' as regexp argument for
      	add_builtin_pretty_printer.
      cff32449
Loading