The state of GDB in Fortran

GDB and GFortran are two amazing tools, that have helped many of us with our research and work. Personally, without them my MSc and PhD research would not have been possible. Unfortunately, even though GFortran has made great strides in implementing F2003, F2008 and a good part of F2018 GDB[1] for Fortran has been lagging behind, specifically the pretty printing of OOP constructs and the Python API. This causes a cascade effect and ultimately affects the Fortran debugging tools that we are able to create, like interactive visualisation of arrays, trees, images, etc., features that users of a high performance computational science language like Fortran would find useful.

I am making this post in an attempt to raise awareness, document the missing features and ideally form an action plan for tackling them.

Why this matters

Great compilers and debuggers, like GFortran and GDB, objectively make programming easier while decreasing the barrier to entry in Fortran. I also firmly believe that a programming language’s tooling ecosystem greatly affects the users’ sentiment about the language and ultimately the number of new users. Finally, as individual users we need to ensure the continuous and active development of such free tools to simply accomplish our daily job/research tasks with Fortran software.

Intel should also care (and any other compiler vendor using GDB). High performance products like IntelOne API make use of GDB for debugging on Linux and MacOS and ensuring that GDB can easily debug code containing features from the latest Fortran Standard is crucial. I am not sure what the future holds for Intel’s compilers and GDB with the move to LLVM, but this brings me to my last point.

LFortran and Flang should care too. Even though GDB and LLDB pretty printers are not identical and hence one cannot be used in the other’s debugger, authors of pretty printers for LLDB should keep in mind that they are bound to face most, if not all, of the problems GDB is currently facing[2]. Therefore, authors of the two should attempt to find some common ground and see if it is possible to simultaneously improve pretty printing in GDB and LLDB.


Existing filed Issues for GDB

These are issues I found already submitted to GDB and relevant to this discussion.

Python API related

  1. 22424 – gdb.lookup_type fails for Fortran

GFortran and/or pretty-printers related

  1. 22497 – Unable to access base type of derived types
  2. 24305 – Fortran function parameters tagged with the VALUE attribute are not passed by value by GDB and its parent issue 24147 – Unable to call Fortran functions with optional parameters missing

Issues to be submitted

Issues that you can encounter in the recent releases of GDB

Pretty-printers

Issues believed to be able to get resolved by improving the pretty-printers Python script distributed by gdb.

NOTE: Some of the issues here might require changes to be made in GFortran, please indicate if that’s the case and mention what the changes should be in case you know.

Displaying strings with allocation on assignment

program str_allog_assign
    implicit none
    character(len=:), allocatable :: str
    str = "some string"
    print*, str
end program str_allog_assign

GDB Output:

(gdb) p str
$1 = (PTR TO -> ( character*(*) )) 0x55555555c910

NOTE: Seems to be specific to GFortran (v11.3.0) + GDB (12.1) , since it’s not present in ifort (2021.5.0 20211109) + GDB (10.2)

Displaying 2D matrices as tables

2D arrays of intrinsic types in Fortran would make more sense if they could be displayed as matrices.

program mat_2d
    implicit none
    integer :: ar(2,2)
    ar = reshape([1,2,3,4], shape(ar))
end program mat_2d

GDB Output:

(gdb) p ar
$1 = ((1, 2) (3, 4))

Potential caveat: I am not sure if editors and IDEs are capable of displaying that in their watch windows but for GDB run from a terminal should be okay

This does not have to be included to the default pretty-printers distributed by GDB, it could be a pretty-printers extension (hosted under Fortran-lang?).

CLASS statement

As far as I can tell there are not pretty-printers for CLASS and more over invoking CLASS pollutes the local scope with cryptically named variables. This heavily affects the ability to debug with ease OOP Fortran and SELECT TYPE constructs.

PROGRAM class_pp
  TYPE POINT
    REAL :: X, Y
  END TYPE POINT
  TYPE, EXTENDS(POINT) :: COLOR_POINT
    INTEGER :: COLOR
  END TYPE COLOR_POINT

  TYPE(COLOR_POINT), TARGET :: CP
  CLASS(POINT), POINTER :: P_OR_CP
  P_OR_CP=> CP
END PROGRAM class_pp

GDB + GFortran output gets the P_OR_CP pointer wrong as if it is pointing to a TYPE(POINT):

(gdb) info locals
__def_init_class_pp_Color_point = ( point = ( x = 0, y = 0 ), color = 0 )
__def_init_class_pp_Point = ( x = 0, y = 0 )
__vtab_class_pp_Color_point = ( _hash = 56164092, _size = 12, _extends = 0x555555558060 <__vtab_class_pp_Point.5>, _def_init = 0x5555555580a8 <__def_init_class_pp_Color_point.3>, _copy = 0x555555555149 <class_pp::__copy_class_pp_Color_point>, _final = 0x0, _deallocate = 0x0 )
__vtab_class_pp_Point = ( _hash = 31389112, _size = 8, _extends = 0x0, _def_init = 0x5555555580a0 <__def_init_class_pp_Point.4>, _copy = 0x555555555191 <class_pp::__copy_class_pp_Point>, _final = 0x0, _deallocate = 0x0 )
cp = ( point = ( x = 0, y = -3.99237121e-16 ), color = -1706574553 )
p_or_cp = ( _data = 0x7fffffffb924, _vptr = 0x555555558020 <__vtab_class_pp_Color_point.6> )

GDB + ifort output actually gets P_OR_CP wrong, it should be pointing to a type of color_point:

(gdb) info locals
p_or_cp = 0x4bd280 <class_pp_$CP>
cp = ( point = ( x = 0, y = 0 ), color = 0 )

Non-default kind strings

As far as I am aware of, there are no pretty-printers for these kind of strings

program str_kind_pp
  implicit none
  character(len=10) :: str
  character(kind=4, len=2), dimension(3) :: a_char_4_arr
  a_char_4_arr(1:3) = "12"; str = "1234567890"
  print *, a_char_4_arr, str
end program str_kind_pp

GDB output:

(gdb) info locals
a_char_4_arr = ((49 '1', 50 '2') (49 '1', 50 '2') (49 '1', 50 '2'))
str = '1234567890'

Python API

The Python API for Fortran types is lacking the ability to resolve a multitude of Fortran intrinsic types and structures. Here is a list of “missing” Fortran features from the API I was able to compile:

  1. Ability to parse type of implicit variables if KIND and LEN are provided
  2. Ability to resolve type of variable if non-standard variable lengths are provided e.g. integer*8 var
  3. Ability to resolve intrinsic Fortran pointers to their corresponding intrinsic type
  4. Ability to resolve Fortran arrays
  5. No intuitive way to traverse OOP objects

Technically, these issues can be addressed outside of GDB’s Python API by extending the API in a Python module. I already have a very early stage library that does so, but in my opinion these it would be both simpler and more logical if they were included by default in the main GDB Python API.

Existing tools

For Polymorphic objects @zedthree wrote a pretty printer a while ago that seems to work for most cases: GitHub - ZedThree/Fortran-gdb-pp: Pretty printer for Fortran dynamic types in gdb

Notice

Please do not file any issues in this thread on my behalf. Some, if not all, of these issues will need serious work to be fixed, posting them on Bugzilla without a rough plan on how to address them will do little to resolve them.

If you want to get involved in my Python module extending the Fortran pretty printers (even though I firmly believe these printers should ship by default with GDB) please contact me.


  1. Sometimes it can be GFortran that needs to implement the DWARF info, but I don’t know enough about the inner workings of GDB and GFortran to be able to distinguish when that is the case. Please correct me if I have erroneously assigned the issue origin to either one. ↩︎

  2. AFAIK there are no pretty printers for LLDB in Fortran. ↩︎

6 Likes