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
GFortran and/or pretty-printers related
- 22497 – Unable to access base type of derived types
- 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:
- Ability to parse type of implicit variables if
KIND
andLEN
are provided - Ability to resolve type of variable if non-standard variable lengths are provided e.g.
integer*8 var
- Ability to resolve intrinsic Fortran pointers to their corresponding intrinsic type
- Ability to resolve Fortran arrays
- 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.
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. ↩︎
AFAIK there are no pretty printers for LLDB in Fortran. ↩︎