本文介绍了在gdb中漂亮的打印Fortran动态类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 限时删除!! 在gdb中打印Fortran可分配多态变量的值是非常痛苦的。给定下面的程序,为了看到 alloc_ext 的值,我必须做以下事情: )(gdb)ptype alloc_ext type = Type __class_foo_My_base_type_a PTR TO - > (类型my_base_type :: _data) PTR TO - > (类型__vtype_foo_My_base_type :: _vptr)结束类型__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') 如果派生类型包含其他多态派生类型的数组,这很快就会非常痛苦。我试着调查python漂亮的打印API,但我似乎仍然无法获得实际的动态类型,甚至不知道 _vptr 地址上的标签,它将足够的信息打印出来。 我使用gdb 8.0.1和gfortran 7.2.1。 MVCE: module foo 隐式无 类型my_base_type 字符(len = 4):: base_char =base结束类型my_base_type 类型,extends(my_base_type):: my_extended_type 字符(len = 4):: extended_char =ext结束类型my_extended_type 包含 子程序栏(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 类型是(my_extended_type) print *,my_extended_type,arg%base_char, ,arg%extended_char 结束选择结束子程序bar 结束模块foo 程序mvce 使用foo 隐含无 类型(my_base_type):: base 类型(my_extended_type):: ext class(my_base_type),allocatable :: alloc_base $ b $ class(my_base_type),allocatable :: alloc_ext allocate(alloc_base,source = base) allocate(alloc_ext,source = ext) 调用栏(alloc_base)调用栏(alloc_ext) end program mvce 解决方案概念,使这个更好一点: 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。 format(int(val ['_ vptr']))) $ b $(info symbol {:#x} b int(val ['_ vptr'])得到 _vptr $ b的地址 $ b 接下来,我们需要解析符号。使用gfortran 7.2, _vptr 符号看起来像是: 在模块中定义的类型code $ __<模块名称> _MOD ___ vtab_<模块名称> _<动态类型> 程序中定义的类型的code> __ vab_<程序名称> _<动态类型> .nnnn 模块和程序名称可以包含下划线,但幸运的是,类型以大写字母开头,其他所有内容都以小写字母开头。 最后,我们需要实际打印 _data 组件作为动态类型。虽然python API提供了一个 Value.cast(type)方法,但是 类型参数必须是一个 gdb.Type 对象。无论如何,我们可以使用 gdb.lookup_type(name)函数...,但这不适用于Fortran类型的。这一次,我们回退到使用 gdb.parse_and_eval : $ b cast_string =*({type} *)({address:#x})格式( type = real_type,address = int(val ['_ data']) ) real_val = gdb.parse_and_eval(cast_string) 其中 real_type 是一个包含动态类型的字符串。这基本上执行 *(<动态类型>)(值%_data),然后我们可以将传递给一个漂亮的打印机只是返回 str(val),就像默认打印机一样。 Printing the values of Fortran allocatable polymorphic variables in gdb is very painful. Given the program below, in order to see the value of alloc_ext, I have to do the following:(gdb) p alloc_ext$1 = ( _data = 0x606260, _vptr = 0x400ce0 <__foo_MOD___vtab_foo_My_extended_type> )(gdb) ptype alloc_exttype = Type __class_foo_My_base_type_aPTR 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%_datatype = PTR TO -> ( Type my_base_typecharacter*4 :: base_charEnd 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 ' )This quickly gets very painful if a derived type contains, say, an array of other polymorphic derived types. I've tried investigating the python pretty printing API, but I still can't seem to get hold of the actual dynamic type, or even the label on the _vptr address, which would be enough information to pretty print something.I'm using gdb 8.0.1 and 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_typecontains 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 barend module fooprogram 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 解决方案 I've made a proof-of-concept that makes this a bit nicer: https://github.com/ZedThree/Fortran-gdb-pp. It's not perfect, but it does demonstrate a way of at least printing dynamic types and see their actual values instead of just the _data and _vptr components. I've included the explanation from the README below.How does it work?Unfortunately, we have to work around several limitations of the gdbpython API. Firstly, gdb reports the dynamic_type of a polymorphicvariable as being its base type, and not its actual dynamic type! Thismeans we need some other way of getting its dynamic type. Luckily, thesymbol for the _vptr component (at least with gfortran 7.2) containsthe dynamic type, so we can use this. Briefly, we do the following:Look up symbol for the value's _vptrParse the symbol to get the dynamic typeCast the _data component to a pointer to the dynamic type anddereferenceFor 1., we need to get the _vptr symbol. We can do thisin gdb with info symbol foo%_vptr. The python API lacks such afunction, so instead we do:gdb.execute("info symbol {:#x}".format(int(val['_vptr'])))int(val['_vptr']) gets the address of _vptrNext, we need to parse the symbol. With gfortran 7.2, _vptr symbolslook like either:__<module name>_MOD___vtab_<module name>_<Dynamic type> for typesdefined in modules, or__vab_<program name>_<Dynamic type>.nnnn for types defined inprogramsModule and program names can contain underscores, but luckily the typestarts with a capital letter while everything else is in lower case.Lastly, we need to actually print the _data component as the dynamictype. While the python API does provide a Value.cast(type) method,the type argument must be a gdb.Type object. No matter, we can usethe gdb.lookup_type(name) function... except that this doesn't workwith Fortran types. This time, we fallback to usinggdb.parse_and_eval:cast_string = "*({type}*)({address:#x})".format( type=real_type, address=int(val['_data']))real_val = gdb.parse_and_eval(cast_string)where real_type is a string containing the dynamic type. Thisbasically executes *(<dynamic type>)(value%_data) and then we canpass the resulting value to a pretty printer that just returnsstr(val), i.e. like the default printer. 这篇关于在gdb中漂亮的打印Fortran动态类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 1403页,肝出来的..
09-07 02:29