mdt@YAHI.STANFORD.EDU (Michael Tiemann) (03/12/89)
Some people have noticed that GDB 3.1 does not quite replace GDB+ 2.8.1 when it comes to debugging GNU C++ code. This is more my fault than Randy's. The following diffs should go a long way toward remedying the problem. You will also need a small patch for dbxout.c for GNU C++ 1.34.0, which is enclosed at the bottom. Michael yahi% diff -c2 dbxread.c~ dbxread.c *** dbxread.c~ Mon Jan 30 08:59:56 1989 --- dbxread.c Sat Mar 11 17:59:56 1989 *************** *** 3786,3789 **** --- 3786,3794 ---- int read_possible_virtual_info = 0; + if (TYPE_CODE (type) == TYPE_CODE_UNDEF) + { + TYPE_MAIN_VARIANT (type) = type; + } + TYPE_CODE (type) = TYPE_CODE_STRUCT; *************** *** 4010,4013 **** --- 4015,4021 ---- new_sublist->fn_field.type = read_type (pp); + smash_to_method_type (new_sublist->fn_field.type, + TYPE_DOMAIN_TYPE (new_sublist->fn_field.type), + TYPE_TARGET_TYPE (new_sublist->fn_field.type)); new_sublist->fn_field.args = read_args (pp, ':'); p = *pp; yahi% diff -c2 values.c~ values.c *** values.c~ Tue Jan 31 09:55:59 1989 --- values.c Sat Mar 11 18:14:26 1989 *************** *** 659,669 **** = fill_in_vptr_fieldno (type); ! /* Pretend that this array is just an array of pointers to integers. ! This will have to change for multiple inheritance. */ ! vtbl = value_copy (value_field (arg1, TYPE_VPTR_FIELDNO (type))); ! VALUE_TYPE (vtbl) = lookup_pointer_type (builtin_type_int); /* Index into the virtual function table. */ ! vfn = value_subscript (vtbl, vi); /* Reinstantiate the function pointer with the correct type. */ --- 659,669 ---- = fill_in_vptr_fieldno (type); ! /* The virtual function table is now an array of structures ! which have the form { int16 offset, delta; void* pfn; }. */ ! vtbl = value_ind (value_field (arg1, TYPE_VPTR_FIELDNO (type))); /* Index into the virtual function table. */ ! vfn = value_struct_elt (value_subscript (vtbl, vi), 0, "pfn", ! "internal error in virtual function lookup"); /* Reinstantiate the function pointer with the correct type. */ yahi% diff -c2 symseg.h~ symseg.h *** symseg.h~ Mon Jan 23 12:42:18 1989 --- symseg.h Sat Mar 11 17:44:56 1989 *************** *** 122,125 **** --- 122,126 ---- /* C++ */ TYPE_CODE_MEMBER, /* Member type */ + TYPE_CODE_METHOD, /* Method type */ TYPE_CODE_REF, /* C++ Reference types */ }; *************** *** 147,151 **** /* For a pointer type, describes the type of object pointed to. For an array type, describes the type of the elements. ! For a function type, describes the type of the value. For a range type, describes the type of the full range. Unused otherwise. */ --- 148,152 ---- /* For a pointer type, describes the type of object pointed to. For an array type, describes the type of the elements. ! For a function or method type, describes the type of the value. For a range type, describes the type of the full range. Unused otherwise. */ *************** *** 240,244 **** char *name; #endif ! /* The type of the argument */ struct type *type; /* The argument list */ --- 241,245 ---- char *name; #endif ! /* The return value of the method */ struct type *type; /* The argument list */ yahi% diff -c2 symtab.c~ symtab.c *** symtab.c~ Tue Jan 17 11:29:19 1989 --- symtab.c Sat Mar 11 17:47:40 1989 *************** *** 362,365 **** --- 362,419 ---- } + struct type * + lookup_method_type (type, domain) + struct type *type, *domain; + { + register struct type *mtype = TYPE_MAIN_VARIANT (type); + struct type *main_type; + + main_type = mtype; + while (mtype) + { + if (TYPE_DOMAIN_TYPE (mtype) == domain) + return mtype; + mtype = TYPE_NEXT_VARIANT (mtype); + } + + /* This is the first time anyone wanted this member type. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + mtype = (struct type *) xmalloc (sizeof (struct type)); + else + mtype = (struct type *) obstack_alloc (symbol_obstack, + sizeof (struct type)); + + bzero (mtype, sizeof (struct type)); + if (main_type == 0) + main_type = mtype; + else + { + TYPE_NEXT_VARIANT (mtype) = TYPE_NEXT_VARIANT (main_type); + TYPE_NEXT_VARIANT (main_type) = mtype; + } + TYPE_MAIN_VARIANT (mtype) = main_type; + TYPE_TARGET_TYPE (mtype) = type; + TYPE_DOMAIN_TYPE (mtype) = domain; + /* New type is permanent if type pointed to is permanent. */ + if (TYPE_FLAGS (type) & TYPE_FLAG_PERM) + TYPE_FLAGS (mtype) |= TYPE_FLAG_PERM; + + /* In practice, this is never used. */ + TYPE_LENGTH (mtype) = 1; + TYPE_CODE (mtype) = TYPE_CODE_MEMBER; + + #if 0 + /* Now splice in the new member pointer type. */ + if (main_type) + { + /* This type was not "smashed". */ + TYPE_CHAIN (mtype) = TYPE_CHAIN (main_type); + TYPE_CHAIN (main_type) = mtype; + } + #endif + + return mtype; + } + /* Given a type TYPE, return a type which has offset OFFSET, via_virtual VIA_VIRTUAL, and via_public VIA_PUBLIC. *************** *** 491,494 **** --- 545,565 ---- TYPE_MAIN_VARIANT (type) = lookup_member_type (domain, to_type); + } + + /* Smash TYPE to be a type of method of DOMAIN with type TO_TYPE. */ + + void + smash_to_method_type (type, domain, to_type) + struct type *type, *domain, *to_type; + { + bzero (type, sizeof (struct type)); + TYPE_TARGET_TYPE (type) = to_type; + TYPE_DOMAIN_TYPE (type) = domain; + + /* In practice, this is never needed. */ + TYPE_LENGTH (type) = 1; + TYPE_CODE (type) = TYPE_CODE_METHOD; + + TYPE_MAIN_VARIANT (type) = lookup_method_type (domain, to_type); } yahi% diff -c2 valops.c~ valops.c *** valops.c~ Thu Jan 19 15:09:14 1989 --- valops.c Fri Mar 10 22:03:47 1989 *************** *** 525,536 **** /* If it's a member function, just look at the function part of it. */ - if (code == TYPE_CODE_MEMBER) - { - ftype = TYPE_TARGET_TYPE (ftype); - code = TYPE_CODE (ftype); - } - /* Determine address to call. */ ! if (code == TYPE_CODE_FUNC) { funaddr = VALUE_ADDRESS (function); --- 525,530 ---- /* If it's a member function, just look at the function part of it. */ /* Determine address to call. */ ! if (code == TYPE_CODE_FUNC || code == TYPE_CODE_METHOD) { funaddr = VALUE_ADDRESS (function); *************** *** 540,545 **** { funaddr = value_as_long (function); ! if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) ! == TYPE_CODE_FUNC) value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)); else --- 534,539 ---- { funaddr = value_as_long (function); ! if (TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_FUNC ! || TYPE_CODE (TYPE_TARGET_TYPE (ftype)) == TYPE_CODE_METHOD) value_type = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (ftype)); else yahi% diff -c2 valprint.c~ valprint.c *** valprint.c~ Wed Jan 11 10:51:31 1989 --- valprint.c Fri Mar 10 22:41:35 1989 *************** *** 186,190 **** break; } ! if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER) { struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)); --- 186,190 ---- break; } ! if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD) { struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)); *************** *** 195,297 **** val = unpack_long (builtin_type_int, valaddr); ! if (TYPE_CODE (target) == TYPE_CODE_FUNC) { ! if (val < 128) { ! len = TYPE_NFN_FIELDS (domain); ! for (i = 0; i < len; i++) ! { ! f = TYPE_FN_FIELDLIST1 (domain, i); ! len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); ! for (j = 0; j < len2; j++) ! { ! QUIT; ! if (TYPE_FN_FIELD_VOFFSET (f, j) == val) ! { ! kind = "virtual"; ! goto common; ! } ! } ! } ! } ! else ! { ! struct symbol *sym = find_pc_function ((CORE_ADDR) val); ! if (sym == 0) ! error ("invalid pointer to member function"); ! len = TYPE_NFN_FIELDS (domain); ! for (i = 0; i < len; i++) { ! f = TYPE_FN_FIELDLIST1 (domain, i); ! len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); ! ! for (j = 0; j < len2; j++) { ! QUIT; ! if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))) ! goto common; } } } - common: - if (i < len) - { - fputc ('&', stream); - type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0); - fprintf (stream, kind); - if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' - && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$') - type_print_method_args - (TYPE_FN_FIELD_ARGS (f, j) + 1, "~", - TYPE_FN_FIELDLIST_NAME (domain, i), stream); - else - type_print_method_args - (TYPE_FN_FIELD_ARGS (f, j), "", - TYPE_FN_FIELDLIST_NAME (domain, i), stream); - break; - } } else { ! /* VAL is a byte offset into the structure type DOMAIN. ! Find the name of the field for that offset and ! print it. */ ! int extra = 0; ! int bits = 0; ! len = TYPE_NFIELDS (domain); ! val <<= 3; /* @@ Make VAL into bit offset */ for (i = 0; i < len; i++) { ! int bitpos = TYPE_FIELD_BITPOS (domain, i); ! QUIT; ! if (val == bitpos) ! break; ! if (val < bitpos && i > 0) { ! int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target)); ! /* Somehow pointing into a field. */ ! i -= 1; ! extra = (val - TYPE_FIELD_BITPOS (domain, i)); ! if (extra & 0x3) ! bits = 1; ! else ! extra >>= 3; ! break; } } ! if (i < len) { ! fputc ('&', stream); ! type_print_base (domain, stream, 0, 0); ! fprintf (stream, "::"); ! fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i)); ! if (extra) ! fprintf (stream, " + %d bytes", extra); ! if (bits) ! fprintf (stream, " (offset in bits)"); break; } } fputc ('(', stream); type_print (type, "", stream, -1); --- 195,303 ---- val = unpack_long (builtin_type_int, valaddr); ! if (val < 128) { ! len = TYPE_NFN_FIELDS (domain); ! for (i = 0; i < len; i++) { ! f = TYPE_FN_FIELDLIST1 (domain, i); ! len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); ! for (j = 0; j < len2; j++) { ! QUIT; ! if (TYPE_FN_FIELD_VOFFSET (f, j) == val) { ! kind = "virtual"; ! goto common; } } } } else { ! struct symbol *sym = find_pc_function ((CORE_ADDR) val); ! if (sym == 0) ! error ("invalid pointer to member function"); ! len = TYPE_NFN_FIELDS (domain); for (i = 0; i < len; i++) { ! f = TYPE_FN_FIELDLIST1 (domain, i); ! len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i); ! ! for (j = 0; j < len2; j++) { ! QUIT; ! if (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j))) ! goto common; } } ! } ! common: ! if (i < len) ! { ! fputc ('&', stream); ! type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0); ! fprintf (stream, kind); ! if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' ! && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$') ! type_print_method_args ! (TYPE_FN_FIELD_ARGS (f, j) + 1, "~", ! TYPE_FN_FIELDLIST_NAME (domain, i), stream); ! else ! type_print_method_args ! (TYPE_FN_FIELD_ARGS (f, j), "", ! TYPE_FN_FIELDLIST_NAME (domain, i), stream); ! break; ! } ! fputc ('(', stream); ! type_print (type, "", stream, -1); ! fprintf (stream, ") %d", val >> 3); ! } ! else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER) ! { ! struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type)); ! struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type)); ! struct fn_field *f; ! int j, len2; ! char *kind = ""; ! ! /* VAL is a byte offset into the structure type DOMAIN. ! Find the name of the field for that offset and ! print it. */ ! int extra = 0; ! int bits = 0; ! len = TYPE_NFIELDS (domain); ! val <<= 3; /* @@ Make VAL into bit offset */ ! for (i = 0; i < len; i++) ! { ! int bitpos = TYPE_FIELD_BITPOS (domain, i); ! QUIT; ! if (val == bitpos) ! break; ! if (val < bitpos && i > 0) { ! int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target)); ! /* Somehow pointing into a field. */ ! i -= 1; ! extra = (val - TYPE_FIELD_BITPOS (domain, i)); ! if (extra & 0x3) ! bits = 1; ! else ! extra >>= 3; break; } } + if (i < len) + { + fputc ('&', stream); + type_print_base (domain, stream, 0, 0); + fprintf (stream, "::"); + fprintf (stream, "%s", TYPE_FIELD_NAME (domain, i)); + if (extra) + fprintf (stream, " + %d bytes", extra); + if (bits) + fprintf (stream, " (offset in bits)"); + break; + } fputc ('(', stream); type_print (type, "", stream, -1); *************** *** 573,576 **** --- 579,583 ---- && (code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC + || code == TYPE_CODE_METHOD || code == TYPE_CODE_ARRAY || code == TYPE_CODE_MEMBER *************** *** 702,705 **** --- 709,721 ---- break; + case TYPE_CODE_METHOD: + type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, + passed_a_ptr); + fputc (' ', stream); + type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0, + passed_a_ptr); + fprintf (stream, "::"); + break; + case TYPE_CODE_REF: type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1); *************** *** 758,761 **** --- 774,783 ---- break; + case TYPE_CODE_METHOD: + if (passed_a_ptr) + fputc (')', stream); + type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0); + break; + case TYPE_CODE_PTR: case TYPE_CODE_REF: *************** *** 819,822 **** --- 841,845 ---- case TYPE_CODE_REF: case TYPE_CODE_FUNC: + case TYPE_CODE_METHOD: type_print_base (TYPE_TARGET_TYPE (type), stream, show, level); break; *************** *** 887,891 **** if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) fprintf (stream, "virtual "); ! type_print (TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j))), "", stream, 0); if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$') --- 910,914 ---- if (TYPE_FN_FIELD_VIRTUAL_P (f, j)) fprintf (stream, "virtual "); ! type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), "", stream, 0); if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_' && TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$') yahi% gdb a.out GDB 3.1, Copyright (C) 1988 Free Software Foundation, Inc. There is ABSOLUTELY NO WARRANTY for GDB; type "info warranty" for details. GDB is free software and you are welcome to distribute copies of it under certain conditions; type "info copying" to see the conditions. Reading symbol data from /home/sioux/mdt/dist-gdb/a.out...done. Function fatal not defined. Type "help" for a list of commands. (gdb) pty a struct a { int x; int y; int f (); int f (int, int); } (gdb) pty b struct b : public a { int z; int w; int f (); int f (int, int); } (gdb) b main Breakpoint 1 at 0x21a8: file test.c, line 30. (gdb) r Starting program: /home/sioux/mdt/dist-gdb/a.out Bpt 1, main () (test.c line 33) 33 x.f (5, 6); (gdb) p x $1 = {x = 0, y = 0} (gdb) p x.f (-1, -2) $2 = -134218336 (gdb) p x.f() calling f for a(-1,-2) $3 = -134218336 (gdb) b a::f [0] cancel [1] all [2] file:test.c; line number:10 [3] file:test.c; line number:6 > 1 Breakpoint 2 at 0x2138: file test.c, line 10. Breakpoint 3 at 0x2178: file test.c, line 6. Multiple breakpoints were set. Use the "delete" command to delete unwanted breakpoints. (gdb) c Continuing. Bpt 2, f_PSa_SI_SI ($this=(struct a *) 0xf7fffda0, i=5, j=6) (test.c line 10) 10 x = i; (gdb) p x $4 = -1 (gdb) i ad this No symbol "this" in current context. (gdb) p ad $this No symbol "ad" in current context. (gdb) i ad $this Symbol "$this" is a local variable at frame offset 68. (gdb) i ad x Symbol "x" is a field of the local class variable `this' (gdb) set x = 10 (gdb) p *$this Attempt to take contents of a non-pointer value. (gdb) p $this $5 = void (gdb) p x $6 = 10 (gdb) quit The program is running. Quit anyway? (y or n) y yahi% As you can see, GDB 3.1 now behaves more like a C++ debugger. yahi% diff -c2 dbxout.c~ dbxout.c *** dbxout.c~ Mon Feb 27 17:43:02 1989 --- dbxout.c Sat Mar 11 17:24:26 1989 *************** *** 523,527 **** t = tem; /* Get to the FUNCTION_DECL */ dbxout_type (TREE_TYPE (t), 0); /* METHOD_TYPE */ - dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (t))); fprintf (asmfile, ":%s;%c%c", IDENTIFIER_POINTER (DECL_NAME (t)), --- 523,526 ---- *************** *** 575,579 **** t = tem; /* Get to the FUNCTION_DECL */ dbxout_type (TREE_TYPE (t), 0); /* METHOD_TYPE */ - dbxout_args (TYPE_ARG_TYPES (TREE_TYPE (t))); fprintf (asmfile, ":%s;%c%c", IDENTIFIER_POINTER (DECL_NAME (t)), --- 574,577 ---- *************** *** 695,698 **** --- 693,697 ---- CHARS (1); dbxout_type (TREE_TYPE (type), 0); + dbxout_args (TYPE_ARG_TYPES (type)); } else *************** *** 786,791 **** break; FORCE_TEXT; fprintf (asmfile, ".stabs \"%s:%c", ! IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (decl)), TREE_PUBLIC (decl) ? 'F' : 'f'); --- 785,792 ---- break; FORCE_TEXT; + /* For GDB 3.1, it may be better to use DECL_NAME (instead of DECL_ORIGINAL_NAME + in this case. */ fprintf (asmfile, ".stabs \"%s:%c", ! IDENTIFIER_POINTER (DECL_NAME (decl)), TREE_PUBLIC (decl) ? 'F' : 'f'); yahi% Michael