在gdb中打印Fortran可分配多态变量的值非常痛苦.鉴于下面的程序,为了看到它的价值alloc_ext,我必须做以下事情:
(gdb) p alloc_ext
$1 = ( _data = 0x606260, _vptr = 0x400ce0 <__foo_MOD___vtab_foo_My_extended_type> )
(gdb) ptype alloc_ext
type = Type __class_foo_My_base_type_a
PTR TO -> ( Type my_base_type :: _data)
PTR TO -> ( Type __vtype_foo_My_base_type :: _vptr)
End Type __class_foo_My_base_type_a
(gdb) ptype alloc_ext%_data
type = PTR TO -> ( Type my_base_type
character*4 :: base_char
End Type my_base_type )
(gdb) p alloc_ext%_data
$2 = (PTR TO -> ( Type my_base_type )) 0x606260
(gdb) p *(my_extended_type*)(alloc_ext%_data)
$3 = ( my_base_type = ( base_char = 'base' ), extended_char = 'ext ' )
Run Code Online (Sandbox Code Playgroud)
如果派生类型包含,例如,其他多态派生类型的数组,这很快就会变得非常痛苦.我已经尝试过调查python漂亮的打印API,但我似乎仍然无法掌握实际的动态类型,甚至是_vptr地址上的标签,这些信息足以打印出漂亮的东西.
我正在使用gdb 8.0.1和gfortran 7.2.1.
MVCE:
module foo
implicit none
type my_base_type
character(len=4) :: base_char = "base"
end type my_base_type
type, extends(my_base_type) :: my_extended_type
character(len=4) :: extended_char = "ext "
end type my_extended_type
contains
subroutine bar(arg)
class(my_base_type), intent(in) :: arg
print*, "breakpoint here"
select type(arg)
type is (my_base_type)
print*, "my_base_type ", arg%base_char
type is (my_extended_type)
print*, "my_extended_type ", arg%base_char, " ", arg%extended_char
end select
end subroutine bar
end module foo
program mvce
use foo
implicit none
type(my_base_type) :: base
type(my_extended_type) :: ext
class(my_base_type), allocatable :: alloc_base
class(my_base_type), allocatable :: alloc_ext
allocate(alloc_base, source=base)
allocate(alloc_ext, source=ext)
call bar(alloc_base)
call bar(alloc_ext)
end program mvce
Run Code Online (Sandbox Code Playgroud)
我做了一个概念验证,让它变得更好一点: https: //github.com/ZedThree/Fortran-gdb-pp。它并不完美,但它确实演示了一种至少打印动态类型并查看其实际值而不仅仅是 和_data组件的方法_vptr。我已经包含了下面自述文件中的解释。
不幸的是,我们必须解决 gdb python API 的一些限制。首先,gdb 将dynamic_type多态变量的 报告为其基本类型,而不是其实际的动态类型!这意味着我们需要其他方式来获取其动态类型。幸运的是,组件的符号_vptr(至少在 gfortran 7.2 中)包含动态类型,因此我们可以使用它。简而言之,我们执行以下操作:
_vptr_data组件转换为指向动态类型的指针并取消引用对于1.,我们需要获取_vptr符号。我们可以在 gdb 中使用info symbol foo%_vptr. python API 缺少这样的函数,所以我们这样做:
gdb.execute("info symbol {:#x}".format(int(val['_vptr'])))
Run Code Online (Sandbox Code Playgroud)
int(val['_vptr'])获取地址_vptr
接下来,我们需要解析该符号。对于 gfortran 7.2,_vptr符号看起来像:
__<module name>_MOD___vtab_<module name>_<Dynamic type>对于模块中定义的类型,或者__vab_<program name>_<Dynamic type>.nnnn对于程序中定义的类型模块和程序名称可以包含下划线,但幸运的是类型以大写字母开头,而其他所有内容都是小写字母。
最后,我们需要将_data组件实际打印为动态类型。虽然 python API 确实提供了Value.cast(type)方法,但type参数必须是gdb.Type对象。无论如何,我们可以使用该gdb.lookup_type(name)函数...只不过这不适用于 Fortran 类型。这一次,我们回退到使用
gdb.parse_and_eval:
cast_string = "*({type}*)({address:#x})".format(
type=real_type, address=int(val['_data']))
real_val = gdb.parse_and_eval(cast_string)
Run Code Online (Sandbox Code Playgroud)
其中real_type是包含动态类型的字符串。这基本上执行*(<dynamic type>)(value%_data),然后我们可以将结果值传递给一个漂亮的打印机,它只返回
str(val),即像默认打印机一样。
| 归档时间: |
|
| 查看次数: |
348 次 |
| 最近记录: |