Bug 16016

Summary: ptype incorrectly shows "record" (pascal/struct) as class (if accessed via pointer) (7.6.1 regression)
Product: gdb Reporter: Martin <gdb.bugs>
Component: pascalAssignee: Not yet assigned to anyone <unassigned>
Status: REOPENED ---    
Severity: normal CC: mnalis-sourceware, muller, sergiodj, tromey
Priority: P2    
Version: 7.6   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Martin 2013-10-08 10:49:08 UTC
GDB up to and including 7.5.1 are NOT affected
GDB 7.6.0 was not tested
GDB 7.6.1 (from mingw / tested on w32 vista) has the below issue

Consider the following program (compiled with free pascal / dwarf2)

program Test_Record_var_param;
type
  TFoo = record    a,b: Integer;   end;
  PFoo = ^TFoo;
var
  r1, r2: TFoo;  p1, p2: PFoo;
begin
  P1 := @r1;  P2 := @r1;
end.
-----

"p1" and "p2" are both pointers to the record declaration. Except for the name, they point to the same dwarf information entry in .debug_info

Yet running 
gdb -i mi
-gdb-set language pascal

  
ptype p1^
&"ptype p1^\n"
~"type = TFOO = record \n"
~"    A : LONGINT;\n"
~"    B : LONGINT;\n"
~"end\n"
^done
(gdb) 

-data-evaluate-expression p1^
^done,value="{A = 0, B = 0}"
(gdb) 

ptype p2^
&"ptype p2^\n"
~"type = TFOO = class \n"
~"  public\n""
~"    A : LONGINT;\n"
~"    B : LONGINT;\n"
~"end\n"
^done
(gdb) 

-data-evaluate-expression p2^
^done,value="{A = 0, B = 0}"
(gdb) 


ptype p2^ claims p2 points to a class, which is incorrect. 
This only happens if "ptype p1^" wal run first.

Running 
ptype p2^
ptype p1^

and ptype p1^ will claim to be a class.


-data-evaluate-expression correctly returns a record in all cases (a rlass would include the class name)


---
Extract from objdump

 <1><9d>: Abbrev Number: 2 (DW_TAG_variable)
    <9e>   DW_AT_name        : P1	
    <a1>   DW_AT_location    : 5 byte block: 3 10 e0 40 0 	(DW_OP_addr: 40e010)
    <a7>   DW_AT_type        : <0xf6>	
 <1><ab>: Abbrev Number: 2 (DW_TAG_variable)
    <ac>   DW_AT_name        : P2	
    <af>   DW_AT_location    : 5 byte block: 3 20 e0 40 0 	(DW_OP_addr: 40e020)
    <b5>   DW_AT_type        : <0xf6>	

Both DW_AT_type point to the same entry

 <1><cb>: Abbrev Number: 4 (DW_TAG_typedef)
    <cc>   DW_AT_name        : TFOO	
    <d1>   DW_AT_type        : <0xd5>	
 <1><d5>: Abbrev Number: 5 (DW_TAG_structure_type)
    <d6>   DW_AT_name        : TFOO	
    <db>   DW_AT_byte_size   : 8	
 <2><dc>: Abbrev Number: 6 (DW_TAG_member)
    <dd>   DW_AT_name        : A	
    <df>   DW_AT_data_member_location: 2 byte block: 23 0 	(DW_OP_plus_uconst: 0)
    <e2>   DW_AT_type        : <0x10a>	
 <2><e6>: Abbrev Number: 6 (DW_TAG_member)
    <e7>   DW_AT_name        : B	
    <e9>   DW_AT_data_member_location: 2 byte block: 23 4 	(DW_OP_plus_uconst: 4)
    <ec>   DW_AT_type        : <0x10a>	


 <1><f6>: Abbrev Number: 4 (DW_TAG_typedef)
    <f7>   DW_AT_name        : PFOO	
    <fc>   DW_AT_type        : <0x100>	
 <1><100>: Abbrev Number: 8 (DW_TAG_pointer_type)
    <101>   DW_AT_type        : <0xcb>	

 <1><10a>: Abbrev Number: 4 (DW_TAG_typedef)
    <10b>   DW_AT_name        : LONGINT	
    <113>   DW_AT_type        : <0x117>	
 <1><117>: Abbrev Number: 9 (DW_TAG_base_type)
    <118>   DW_AT_name        : LONGINT	
    <120>   DW_AT_encoding    : 5	(signed)
    <121>   DW_AT_byte_size   : 4
Comment 1 Sergio Durigan Junior 2013-10-17 20:10:24 UTC
FWIW, I have tested this using CVS HEAD on Fedora 17 x86_64 with FPC version 2.6.0, and could not reproduce the bug.

(gdb) 
-gdb-set language pascal
^done
(gdb) 
ptype p1^
&"ptype p1^\n"
~"type = TFOO = record \n"
~"    A : SMALLINT;\n"
~"    B : SMALLINT;\n"
~"end\n"
^done
(gdb) 
ptype p2^
&"ptype p2^\n"
~"type = TFOO = record \n"
~"    A : SMALLINT;\n"
~"    B : SMALLINT;\n"
~"end\n"
^done

Would it be possible to give it a try using CVS HEAD?  Thanks.
Comment 2 Sergio Durigan Junior 2014-09-12 23:12:11 UTC
Closing as OBSOLETE due to inactivity.  Feel free to reopen if still valid.
Comment 3 Martin 2015-01-06 01:35:35 UTC
I finally got to build 7.8.1 under mingw 32 bit windows. The issue still exists.

I only tested on Windows.


Compile the program.
gdb_781.exe -i mi project1.exe
b project1.lpr:10
r
ptype p1^
-data-evaluate-expression p1^
ptype p2^

The last ptype shows "class", but it should be record
Comment 4 Martin 2015-08-31 10:08:04 UTC
Just reconfirming, still present in gdb 7.10
Comment 5 mnalis-sourceware 2020-08-20 22:22:14 UTC
I can confirm this is still present in gdb 8.2.1-2+b3 in Debian Buster. (when using fpc 3.0.4+dfsg-22)

As a workaround, one has to manually typecast, for example:

        (gdb) p tempplan^[curplan].cache
        Type PLANARRAY is not a structure or union type.

        (gdb) ptype tempplan^[curplan]
        type = PLANETTYPE = class
          public
            SYSTEM : BYTE;
            CACHE : array [1..7] of WORD;
            AGE : LONGINT;
        end

        (gdb) p PLANETTYPE(tempplan^[curplan]).cache
        $42 = {5000, 5100, 5140, 0, 5040, 0, 5020}


(Note: PLANETTYPE is actually a RECORD, not CLASS):

type planettype=
  record
   system: byte;
   cache: array[1..7] of word;
   age: longint;
  end;
 planarray= array[1..1000] of planettype;
var tempplan: ^planarray;
Comment 6 Pierre Muller 2020-08-24 15:45:58 UTC
  Issue confirmed for gdb-7.6 also,
the problem comes from a change of the 
type.main_type.type_specific.cplus_stuff
field due to RTTI reading.
  This suggest that Free Pascal also issues RTTI
information about 'record' not only 'classes',
which is probably true, but this is a branch of Free
Pascal compiler I do not know well...

  So if someone with more knowledge about that part can go further.

It seems that:
top> f 0
#0  0x005fbe0a in gnuv3_get_vtable (gdbarch=0x276e390, container_type=0x2792090, container_addr=4243472) at ../../gdb-7.6/gdb/gnu-v3-abi.c:249
249       if (!gnuv3_dynamic_class (check_typedef (container_type)))
top> li
244       struct value *vtable_pointer;
245       CORE_ADDR vtable_address;
246
247       /* If this type does not have a virtual table, don't read the first
248          field.  */
249       if (!gnuv3_dynamic_class (check_typedef (container_type)))
250         return NULL;
here the call to gnuv3_dynamic_class  changes the cplus_stuff
from cplus_struct_default to a new 'struct', even if there
gnuv3_dynamic_class return false.
  I have no idea if this is expected behavior, but it does
indeed explain why 
pty TFOO 
generates a different output after 
p p1^
has been issued!


Pierre Muller



(gdb) p p1^
Hardware watchpoint 3: *$3

Old value = (struct cplus_struct_type *) 0x7b07c0 <cplus_struct_default>
New value = (struct cplus_struct_type *) 0x2792500
allocate_cplus_struct_type (type=0x2792090) at ../../gdb-7.6/gdb/gdbtypes.c:1932
1932      *(TYPE_RAW_CPLUS_SPECIFIC (type)) = cplus_struct_default;
top> bt
#0  allocate_cplus_struct_type (type=0x2792090) at ../../gdb-7.6/gdb/gdbtypes.c:1932
#1  0x005fbae0 in gnuv3_dynamic_class (type=0x2792090) at ../../gdb-7.6/gdb/gnu-v3-abi.c:206
#2  0x005fbe0a in gnuv3_get_vtable (gdbarch=0x276e390, container_type=0x2792090, container_addr=4243472) at ../../gdb-7.6/gdb/gnu-v3-abi.c:249
#3  0x005fbf37 in gnuv3_rtti_type (value=0x2795f68, full_p=0x1e7f5e4, top_p=0x1e7f5e0, using_enc_p=0x1e7f5dc) at ../../gdb-7.6/gdb/gnu-v3-abi.c:301
#4  0x005fdf21 in value_rtti_type (v=0x2795f68, full=0x1e7f5e4, top=0x1e7f5e0, using_enc=0x1e7f5dc) at ../../gdb-7.6/gdb/cp-abi.c:120
#5  0x004c619c in value_full_object (argp=0x2795f68, rtype=0x0, xfull=0, xtop=0, xusing_enc=0) at ../../gdb-7.6/gdb/valops.c:3604
#6  0x004b6e81 in readjust_indirect_value_type (value=0x2795f68, enc_type=0x2792090, original_type=0x2792148, original_value=0x4656798) at ../../gdb-7.6/gdb/value.c:3277
#7  0x004c28db in value_ind (arg1=0x4656798) at ../../gdb-7.6/gdb/valops.c:1776
#8  0x004bda86 in evaluate_subexp_standard (expect_type=0x0, exp=0x279d7e0, pos=0x1e7f99c, noside=EVAL_NORMAL) at ../../gdb-7.6/gdb/eval.c:2550
#9  0x004b71ee in evaluate_subexp (expect_type=0x0, exp=0x279d7e0, pos=0x1e7f99c, noside=EVAL_NORMAL) at ../../gdb-7.6/gdb/eval.c:71
#10 0x004b736d in evaluate_expression (exp=0x279d7e0) at ../../gdb-7.6/gdb/eval.c:146
#11 0x004d10fa in print_command_1 (exp=0x2866f02 "p1^", voidprint=1) at ../../gdb-7.6/gdb/printcmd.c:965
#12 0x004d123f in print_command (exp=0x2866f02 "p1^", from_tty=1) at ../../gdb-7.6/gdb/printcmd.c:1006
#13 0x00449a90 in do_cfunc (c=0x2745890, args=0x2866f02 "p1^", from_tty=1) at ../../gdb-7.6/gdb/cli/cli-decode.c:113
#14 0x0044c263 in cmd_func (cmd=0x2745890, args=0x2866f02 "p1^", from_tty=1) at ../../gdb-7.6/gdb/cli/cli-decode.c:1859
#15 0x005ebf00 in execute_command (p=0x2866f04 "^", from_tty=1) at ../../gdb-7.6/gdb/top.c:484
#16 0x00516a4b in command_handler (command=0x2866f00 "p p1^") at ../../gdb-7.6/gdb/event-top.c:431
#17 0x00516f47 in command_line_handler (rl=0x4587840 "") at ../../gdb-7.6/gdb/event-top.c:629
#18 0x0062885e in rl_callback_read_char () at ../../gdb-7.6/readline/callback.c:220
#19 0x005165ff in rl_callback_read_char_wrapper (client_data=0x0) at ../../gdb-7.6/gdb/event-top.c:163
#20 0x00516972 in stdin_event_handler (error=0, client_data=0x0) at ../../gdb-7.6/gdb/event-top.c:371
#21 0x00515bab in handle_file_event (data=...) at ../../gdb-7.6/gdb/event-loop.c:768
#22 0x005152c8 in process_event () at ../../gdb-7.6/gdb/event-loop.c:342
#23 0x0051538d in gdb_do_one_event () at ../../gdb-7.6/gdb/event-loop.c:406
#24 0x005153de in start_event_loop () at ../../gdb-7.6/gdb/event-loop.c:431
#25 0x00516628 in cli_command_loop () at ../../gdb-7.6/gdb/event-top.c:176
#26 0x0050de2d in current_interp_command_loop () at ../../gdb-7.6/gdb/interps.c:331
#27 0x0050ee3c in captured_command_loop (data=0x0) at ../../gdb-7.6/gdb/main.c:258
#28 0x0050ce7a in catch_errors (func=0x50ee27 <captured_command_loop>, func_args=0x0, errstring=0x7a6a04 <__PRETTY_FUNCTION__.12659+138> "", mask=6) at ../../gdb-7.6/gdb/exceptions.c:546
#29 0x00510060 in captured_main (data=0x1e7fe90) at ../../gdb-7.6/gdb/main.c:1041
#30 0x0050ce7a in catch_errors (func=0x50f087 <captured_main>, func_args=0x1e7fe90, errstring=0x7a6a04 <__PRETTY_FUNCTION__.12659+138> "", mask=6) at ../../gdb-7.6/gdb/exceptions.c:546
#31 0x00510096 in gdb_main (args=0x1e7fe90) at ../../gdb-7.6/gdb/main.c:1050
#32 0x004015b4 in main (argc=2, argv=0x2866710) at ../../gdb-7.6/gdb/gdb.c:34