Calling fortran subroutines of derived types from gdb

Viewed 125

I want to call a function that takes as an argument a derived type from within the Gnu Debugger (gdb). I eventually get a segfault. Here's a "minimum" working example:

module modSimpleClass
    type Person
        character(len=20) :: Name
        contains
            procedure PrintName
    end type
    contains
        subroutine PrintName(a)
            class(Person) :: a
            print *, a%Name
        end subroutine
        subroutine Print42()
            print *, "42"
        end subroutine
        subroutine PrintNameFromOutside(a)
            class(Person) :: a
            print *, a%Name
        end subroutine
end module
program testgdb
    use modSimpleClass
    implicit none
    type(Person) :: JoeJohnson

    JoeJohnson%Name = "Joe Johnson"
    call JoeJohnson%PrintName
end program testgdb

I compile it with gfortran version 9.3.0, run it from gdb and stop it before its end. The following things work:

call Print42()
print JoeJohnson%Name

The following things don't work:

call JoeJohnson%PrintName()!There is no member named PrintName.
call PrintName(JoeJohnson)!Error then segfault
call PrintNameFromOutside(JoeJohnson)!Error then segfault

The error is as follows:

The program being debugged was signaled while in a function called from GDB. GDB remains in the frame where the signal was received. To change this behavior use "set unwindonsignal on". Evaluation of the expression containing the function (modsimpleclass::printname) will be abandoned. When the function is done executing, GDB will silently stop.

How to correctly call fortran subroutines from gdb?


Thank you for you response @Flusslauf. I am going to try to rephrase what you said:

From the point of view of gfortran, if we have the derived type Person defined in module modsimpleclass,

  • Only the scope in which the variable is initialized sees the original type.
  • Any function or subroutine which takes as an argument an object of that derived type sees the type __class_modsimpleclass_Person_t with attributes:
    1. _data: A pointer to the object.
    2. _vptr: A pointer to something that has information about the object.

So a function really takes two pointers for each object of a derived type: one which points to the object and another one which points to information about the object.

From gdb, passing to a function a pointer to the object works, but passing to it the object itself doesn't work.


@Flusslauf established

call PrintName( &JoeJohnson )!works because it is equivalent to
call PrintName( a%_data )!this, which works too
call PrintName( a )!this works and it makes sense
call PrintName( a%_data, a%_vptr )!this also works
call PrintName( a%_vptr)!this outputs something strange

call PrintName( *(a%_data) )!causes segfault since equivalent to
call PrintName( JoeJohnson )!Error then segfault

, where each instruction is executed in the correct scope for the variable.

1 Answers

The problem here is that while the normal Fortran syntax allows the call PrintName(JoeJohnson) the actual type of the passed argument seems to be (setting a breakpoint within the printname and compiling gfortran)

Breakpoint 1, modsimpleclass::printname (a=...) at ./stack.f90:10
10                  print *, a%Name
(gdb) ptype a
type = Type __class_modsimpleclass_Person_t
    PTR TO -> ( Type person :: _data )
    PTR TO -> ( Type __vtype_modsimpleclass_Person :: _vptr )
End Type __class_modsimpleclass_Person_t

while the type of JoeJohnson is of non-pointer type. I guess the above type is gfortran's way of passing type arguments in Fortran.

In the above case

PrintName(&JoeJohnson)

would work but is hacky..


Edit:

Just for completion - ifx/ifort actually seem to use a pointer for the argument passing

(gdb) ptype a
type = PTR TO -> ( Type person
character*20 :: name
    void :: printname(void)
End Type person )

so doing call modsimpleclass::printname(&JoeJohnson) would not be as hacky anymore (GDB is not able to resolve PrintName when compiling with ifx/ifort). I am not sure whether one could adapt gdb in a meaningful way to allow for this kind of calling. Since the parameter handling and calling syntax is compiler dependent.

Related