From 30d1f0184953478d14641c495261afd06ebfabac Mon Sep 17 00:00:00 2001 From: Weimin Pan Date: Mon, 7 Oct 2019 00:46:52 +0000 Subject: [PATCH] gdb: CTF support This patch adds the CTF (Compact Ansi-C Type Format) support in gdb. Two submissions on which this gdb work depends were posted earlier in May: * On the binutils mailing list - adding libctf which creates, updates, reads, and manipulates the CTF data. * On the gcc mailing list - expanding gcc to directly emit the CFT data with a new command line option -gt. CTF is a reduced form of debugging information whose main purpose is to describe the type of C entities such as structures, unions, typedefs and function arguments at the global scope only. It does not contain debug information about source lines, location expressions, or local variables. For more information on CTF, see the documentation in the libdtrace-ctf source tree, available here: . This patch expands struct elfinfo by adding the .ctf section, which contains CTF debugging info, and modifies elf_symfile_read() to read it. If both DWARF and CTF exist in a program, only DWARF will be read. CTF data will be read only when there is no DWARF. The two-stage symbolic reading and setting strategy, partial and full, was used. File ctfread.c contains functions to transform CTF data into gdb's internal symbol table structures by iterately reading entries from CTF sections of "data objects", "function info", "variable info", and "data types" when setting up either partial or full symbol table. If the ELF symbol table is available, e.g. not stripped, the CTF reader will associate the found type information with these symbol entries. Due to the proximity between DWARF and CTF (CTF being a much simplified subset of DWARF), some DWARF implementation was reused to support CTF. Test cases ctf-constvars.exp, ctf-cvexpr.exp, ctf-ptype.exp, and ctf-whatis.exp have been added to verify the correctness of this support. This patch has missing features and limitations which we will add and address in the future patches. gdb/ChangeLog +2019-10-07 Weimin Pan + + * gdb/ctfread.c: New file. + * gdb/ctfread.h: New file. + * gdb/elfread.c: Include ctfread.h. + (struct elfinfo text_p): New member ctfsect. + (elf_locate_sections): Mark CTF section. + (elf_symfile_read): Call elfctf_build_psymtabs. + * gdb/Makefile.in (LIBCTF): Add. + (CLIBS): Use it. + (CDEPS): Likewise. + (DIST): Add ctfread.c. + * Makefile.def (dependencies): Add all-libctf to all-gdb + * Makefile.in: Add "all-gdb: maybe-all-libctf" + gdb/testsuite/ChangeLog +2019-10-07 Weimin Pan + + * gdb.base/ctf-whatis.exp: New file. + * gdb.base/ctf-whatis.c: New file. + * gdb.base/ctf-ptype.exp: New file. + * gdb.base/ctf-ptype.c: New file. + * gdb.base/ctf-constvars.exp: New file. + * gdb.base/ctf-constvars.c: New file. + * gdb.base/ctf-cvexpr.exp: New file. + --- Makefile.def | 1 + Makefile.in | 1 + gdb/ChangeLog | 15 + gdb/Makefile.in | 9 +- gdb/ctfread.c | 1486 ++++++++++++++++++++++ gdb/ctfread.h | 25 + gdb/elfread.c | 18 +- gdb/testsuite/ChangeLog | 10 + gdb/testsuite/gdb.base/ctf-constvars.c | 116 ++ gdb/testsuite/gdb.base/ctf-constvars.exp | 114 ++ gdb/testsuite/gdb.base/ctf-cvexpr.exp | 495 +++++++ gdb/testsuite/gdb.base/ctf-ptype.c | 305 +++++ gdb/testsuite/gdb.base/ctf-ptype.exp | 288 +++++ gdb/testsuite/gdb.base/ctf-whatis.c | 282 ++++ gdb/testsuite/gdb.base/ctf-whatis.exp | 413 ++++++ 15 files changed, 3575 insertions(+), 3 deletions(-) create mode 100644 gdb/ctfread.c create mode 100644 gdb/ctfread.h create mode 100644 gdb/testsuite/gdb.base/ctf-constvars.c create mode 100644 gdb/testsuite/gdb.base/ctf-constvars.exp create mode 100644 gdb/testsuite/gdb.base/ctf-cvexpr.exp create mode 100644 gdb/testsuite/gdb.base/ctf-ptype.c create mode 100644 gdb/testsuite/gdb.base/ctf-ptype.exp create mode 100644 gdb/testsuite/gdb.base/ctf-whatis.c create mode 100644 gdb/testsuite/gdb.base/ctf-whatis.exp diff --git a/Makefile.def b/Makefile.def index 6f5e881d56e..311feb9de3b 100644 --- a/Makefile.def +++ b/Makefile.def @@ -404,6 +404,7 @@ dependencies = { module=all-gdb; on=all-build-bison; }; dependencies = { module=all-gdb; on=all-sim; }; dependencies = { module=all-gdb; on=all-libdecnumber; }; dependencies = { module=all-gdb; on=all-libtermcap; }; +dependencies = { module=all-gdb; on=all-libctf; }; dependencies = { module=configure-libgui; on=configure-tcl; }; dependencies = { module=configure-libgui; on=configure-tk; }; diff --git a/Makefile.in b/Makefile.in index 196abf01ff9..1aabf6ede44 100644 --- a/Makefile.in +++ b/Makefile.in @@ -51524,6 +51524,7 @@ all-gdb: maybe-all-libiberty all-gdb: maybe-all-libiconv all-gdb: maybe-all-opcodes all-gdb: maybe-all-libdecnumber +all-gdb: maybe-all-libctf configure-gprof: maybe-configure-intl all-gprof: maybe-all-libiberty all-gprof: maybe-all-bfd diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7d378c88fb9..af80baa2cba 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,18 @@ +2019-10-07 Weimin Pan + + * ctfread.c: New file. + * ctfread.h: New file. + * elfread.c: Include ctfread.h. + (struct elfinfo text_p): New member ctfsect. + (elf_locate_sections): Mark CTF section. + (elf_symfile_read): Call elfctf_build_psymtabs. + * Makefile.in (LIBCTF): Add. + (CLIBS): Use it. + (CDEPS): Likewise. + (DIST): Add ctfread.c. + * ../Makefile.def (dependencies): Add all-libctf to all-gdb + * ../Makefile.in: Add "all-gdb: maybe-all-libctf" + 2019-10-07 Weimin Pan * tracectf.h: Rename, was ctf.h. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index d9026719bba..36650ad555f 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -153,6 +153,9 @@ INCLUDE_CFLAGS = -I$(INCLUDE_DIR) # Where is the "-liberty" library? Typically in ../libiberty. LIBIBERTY = ../libiberty/libiberty.a +# Where is the CTF library? Typically in ../libctf. +LIBCTF = ../libctf/.libs/libctf.a + # Where is the BFD library? Typically in ../bfd. BFD_DIR = ../bfd BFD = $(BFD_DIR)/libbfd.a @@ -588,13 +591,14 @@ INTERNAL_LDFLAGS = \ # Libraries and corresponding dependencies for compiling gdb. # XM_CLIBS, defined in *config files, have host-dependent libs. # LIBIBERTY appears twice on purpose. -CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ +CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \ + $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \ $(XM_CLIBS) $(GDBTKLIBS) \ @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \ $(SRCHIGH_LIBS) -CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ +CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) DIST = gdb @@ -988,6 +992,7 @@ COMMON_SFILES = \ cp-namespace.c \ cp-support.c \ cp-valprint.c \ + ctfread.c \ d-lang.c \ d-namespace.c \ d-valprint.c \ diff --git a/gdb/ctfread.c b/gdb/ctfread.c new file mode 100644 index 00000000000..3e3bd89d5f1 --- /dev/null +++ b/gdb/ctfread.c @@ -0,0 +1,1486 @@ +/* Compact ANSI-C Type Format (CTF) support in GDB. + + Copyright (C) 2019 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* This file format can be used to compactly represent the information needed + by a debugger to interpret the ANSI-C types used by a given program. + Traditionally, this kind of information is generated by the compiler when + invoked with the -g flag and is stored in "stabs" strings or in the more + modern DWARF format. A new -gtLEVEL option has been added in gcc to generate + such information. CTF provides a representation of only the information + that is relevant to debugging a complex, optimized C program such as the + operating system kernel in a form that is significantly more compact than + the equivalent stabs or DWARF representation. The format is data-model + independent, so consumers do not need different code depending on whether + they are 32-bit or 64-bit programs. CTF assumes that a standard ELF symbol + table is available for use in the debugger, and uses the structure and data + of the symbol table to avoid storing redundant information. The CTF data + may be compressed on disk or in memory, indicated by a bit in the header. + CTF may be interpreted in a raw disk file, or it may be stored in an ELF + section, typically named .ctf. Data structures are aligned so that a raw + CTF file or CTF ELF section may be manipulated using mmap(2). + + The CTF file or section itself has the following structure: + + +--------+--------+---------+----------+----------+-------+--------+ + | file | type | data | function | variable | data | string | + | header | labels | objects | info | info | types | table | + +--------+--------+---------+----------+----------+-------+--------+ + + The file header stores a magic number and version information, encoding + flags, and the byte offset of each of the sections relative to the end of the + header itself. If the CTF data has been uniquified against another set of + CTF data, a reference to that data also appears in the the header. This + reference is the name of the label corresponding to the types uniquified + against. + + Following the header is a list of labels, used to group the types included in + the data types section. Each label is accompanied by a type ID i. A given + label refers to the group of types whose IDs are in the range [0, i]. + + Data object and function records are stored in the same order as they appear + in the corresponding symbol table, except that symbols marked SHN_UNDEF are + not stored and symbols that have no type data are padded out with zeroes. + For each data object, the type ID (a small integer) is recorded. For each + function, the type ID of the return type and argument types is recorded. + + Variable records (as distinct from data objects) provide a modicum of support + for non-ELF systems, mapping a variable name to a CTF type ID. The variable + names are sorted into ASCIIbetical order, permitting binary searching. + + The data types section is a list of variable size records that represent each + type, in order by their ID. The types themselves form a directed graph, + where each node may contain one or more outgoing edges to other type nodes, + denoted by their ID. + + Strings are recorded as a string table ID (0 or 1) and a byte offset into the + string table. String table 0 is the internal CTF string table. String table + 1 is the external string table, which is the string table associated with the + ELF symbol table for this object. CTF does not record any strings that are + already in the symbol table, and the CTF string table does not contain any + duplicated strings. */ + +#include "defs.h" +#include "buildsym.h" +#include "complaints.h" +#include "block.h" +#include "ctfread.h" +#include "psympriv.h" +#include "ctf.h" +#include "ctf-api.h" + +static const struct objfile_key ctf_tid_key; +static const struct objfile_data *ctf_file_key; + +/* A CTF context consists of a file pointer and an objfile pointer. */ + +typedef struct ctf_context +{ + ctf_file_t *fp; + struct objfile *of; + struct buildsym_compunit *builder; +} ctf_context_t; + +/* The routines that read and process fields/members of a C struct, union, + or enumeration, pass lists of data member fields in an instance of a + field_info structure. It is derived from dwarf2read.c. */ + +struct nextfield +{ + struct field field {}; +}; + +struct field_info +{ + /* List of data member fields. */ + std::vector fields; + + /* Context. */ + ctf_context_t *cur_context; + + /* Parent type. */ + struct type *ptype; + + /* typedefs defined inside this class. TYPEDEF_FIELD_LIST contains head + of a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements. */ + std::vector typedef_field_list; + + /* Nested types defined by this struct and the number of elements in + this list. */ + std::vector nested_types_list; +}; + + +/* Local function prototypes */ + +static void psymtab_to_symtab (struct partial_symtab *); + +static int ctf_add_type_cb (ctf_id_t tid, void *arg); + +static struct type *read_array_type (ctf_context_t *ccp, ctf_id_t tid); + +static struct type *read_pointer_type (ctf_context_t *ccp, ctf_id_t tid, + ctf_id_t btid); + +static struct type *read_structure_type (ctf_context_t *ccp, ctf_id_t tid); + +static struct type *read_enum_type (ctf_context_t *ccp, ctf_id_t tid); + +static struct type *read_typedef_type (ctf_context_t *ccp, ctf_id_t tid, + ctf_id_t btid, const char *name); + +static struct type *read_type_record (ctf_context_t *ccp, ctf_id_t tid); + +static void process_structure_type (ctf_context_t *ccp, ctf_id_t tid); + +static void process_struct_members (ctf_context_t *ccp, ctf_id_t tid, + struct type *type); + +static struct symbol *new_symbol (ctf_context_t *ccp, struct type *type, + ctf_id_t tid); + +struct ctf_tid_and_type +{ + ctf_id_t tid; + struct type *type; +}; + +/* Hash function for a ctf_tid_and_type. */ + +static hashval_t +tid_and_type_hash (const void *item) +{ + const struct ctf_tid_and_type *ids + = (const struct ctf_tid_and_type *) item; + + return ids->tid; +} + +/* Equality function for a ctf_tid_and_type. */ + +static int +tid_and_type_eq (const void *item_lhs, const void *item_rhs) +{ + const struct ctf_tid_and_type *ids_lhs + = (const struct ctf_tid_and_type *) item_lhs; + const struct ctf_tid_and_type *ids_rhs + = (const struct ctf_tid_and_type *) item_rhs; + + return ids_lhs->tid == ids_rhs->tid; +} + +/* Set the type associated with TID to TYP. */ + +static struct type * +set_tid_type (struct objfile *of, ctf_id_t tid, struct type *typ) +{ + htab_t htab; + + htab = (htab_t) ctf_tid_key.get (of); + if (htab == NULL) + { + htab = htab_create_alloc (1, tid_and_type_hash, + tid_and_type_eq, + NULL, xcalloc, xfree); + ctf_tid_key.set (of, htab); + } + + struct ctf_tid_and_type **slot, ids; + ids.tid = tid; + ids.type = typ; + slot = (struct ctf_tid_and_type **) htab_find_slot (htab, &ids, INSERT); + if (*slot) + complaint (_("An internal GDB problem: ctf_ id_t %ld type already set"), + (tid)); + *slot = XOBNEW (&of->objfile_obstack, struct ctf_tid_and_type); + **slot = ids; + return typ; +} + +/* Look up the type for TID in tid_and_type hash, return NULL if hash is + empty or TID does not have a saved type. */ + +static struct type * +get_tid_type (struct objfile *of, ctf_id_t tid) +{ + struct ctf_tid_and_type *slot, ids; + htab_t htab; + + htab = (htab_t) ctf_tid_key.get (of); + if (htab == NULL) + return NULL; + + ids.tid = tid; + ids.type = NULL; + slot = (struct ctf_tid_and_type *) htab_find (htab, &ids); + if (slot) + return slot->type; + else + return NULL; +} + +/* Return the size of storage in bits for INTEGER, FLOAT, or ENUM. */ + +static int +get_bitsize (ctf_file_t *fp, ctf_id_t tid, uint32_t kind) +{ + ctf_encoding_t cet; + + if ((kind == CTF_K_INTEGER || kind == CTF_K_ENUM + || kind == CTF_K_FLOAT) + && ctf_type_reference (fp, tid) != CTF_ERR + && ctf_type_encoding (fp, tid, &cet) != CTF_ERR) + return cet.cte_bits; + + return 0; +} + +/* Set SYM's address, with NAME, from its minimal symbol entry. */ + +static void +set_symbol_address (struct objfile *of, struct symbol *sym, const char *name) +{ + struct bound_minimal_symbol msym; + + msym = lookup_minimal_symbol (name, NULL, of); + if (msym.minsym != NULL) + { + SET_SYMBOL_VALUE_ADDRESS (sym, BMSYMBOL_VALUE_ADDRESS (msym)); + SYMBOL_ACLASS_INDEX (sym) = LOC_STATIC; + SYMBOL_SECTION (sym) = MSYMBOL_SECTION (msym.minsym); + } +} + +/* Create the vector of fields, and attach it to TYPE. */ + +static void +attach_fields_to_type (struct field_info *fip, struct type *type) +{ + int nfields = fip->fields.size (); + + if (nfields == 0) + return; + + /* Record the field count, allocate space for the array of fields. */ + TYPE_NFIELDS (type) = nfields; + TYPE_FIELDS (type) + = (struct field *) TYPE_ZALLOC (type, sizeof (struct field) * nfields); + + /* Copy the saved-up fields into the field vector. */ + for (int i = 0; i < nfields; ++i) + { + struct nextfield &field = fip->fields[i]; + TYPE_FIELD (type, i) = field.field; + } +} + +/* Allocate a floating-point type of size BITS and name NAME. Pass NAME_HINT + (which may be different from NAME) to the architecture back-end to allow + it to guess the correct format if necessary. */ + +static struct type * +ctf_init_float_type (struct objfile *objfile, + int bits, + const char *name, + const char *name_hint) +{ + struct gdbarch *gdbarch = get_objfile_arch (objfile); + const struct floatformat **format; + struct type *type; + + format = gdbarch_floatformat_for_type (gdbarch, name_hint, bits); + if (format != NULL) + type = init_float_type (objfile, bits, name, format); + else + type = init_type (objfile, TYPE_CODE_ERROR, bits, name); + + return type; +} + +/* Callback to add member NAME to a struct/union type. TID is the type + of struct/union member, OFFSET is the offset of member in bits, + and ARG contains the field_info. */ + +static int +ctf_add_member_cb (const char *name, + ctf_id_t tid, + unsigned long offset, + void *arg) +{ + struct field_info *fip = (struct field_info *) arg; + ctf_context_t *ccp = fip->cur_context; + struct nextfield new_field; + struct field *fp; + struct type *t; + uint32_t kind; + + fp = &new_field.field; + FIELD_NAME (*fp) = name; + + kind = ctf_type_kind (ccp->fp, tid); + t = get_tid_type (ccp->of, tid); + if (t == NULL) + { + t = read_type_record (ccp, tid); + if (t == NULL) + { + complaint (_("ctf_add_member_cb: %s has NO type (%ld)"), name, tid); + t = objfile_type (ccp->of)->builtin_error; + set_tid_type (ccp->of, tid, t); + } + } + + if (kind == CTF_K_STRUCT || kind == CTF_K_UNION) + process_struct_members (ccp, tid, t); + + FIELD_TYPE (*fp) = t; + SET_FIELD_BITPOS (*fp, offset / TARGET_CHAR_BIT); + FIELD_BITSIZE (*fp) = get_bitsize (ccp->fp, tid, kind); + + fip->fields.emplace_back (new_field); + + return 0; +} + +/* Callback to add member NAME of EVAL to an enumeration type. + ARG contains the field_info. */ + +static int +ctf_add_enum_member_cb (const char *name, int enum_value, void *arg) +{ + struct field_info *fip = (struct field_info *) arg; + struct nextfield new_field; + struct field *fp; + ctf_context_t *ccp = fip->cur_context; + + fp = &new_field.field; + FIELD_NAME (*fp) = name; + FIELD_TYPE (*fp) = NULL; + SET_FIELD_ENUMVAL (*fp, enum_value); + FIELD_BITSIZE (*fp) = 0; + + if (name != NULL) + { + struct symbol *sym = allocate_symbol (ccp->of); + OBJSTAT (ccp->of, n_syms++); + + SYMBOL_SET_LANGUAGE (sym, language_c, &ccp->of->objfile_obstack); + SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of); + SYMBOL_ACLASS_INDEX (sym) = LOC_CONST; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; + SYMBOL_TYPE (sym) = fip->ptype; + add_symbol_to_list (sym, ccp->builder->get_global_symbols ()); + } + + fip->fields.emplace_back (new_field); + + return 0; +} + +/* Add a new symbol entry, with its name from TID, its access index and + domain from TID's kind, and its type from TYPE. */ + +static struct symbol * +new_symbol (ctf_context_t *ccp, struct type *type, ctf_id_t tid) +{ + struct objfile *objfile = ccp->of; + ctf_file_t *fp = ccp->fp; + struct symbol *sym = NULL; + + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (fp, tid)); + if (name != NULL) + { + sym = allocate_symbol (objfile); + OBJSTAT (objfile, n_syms++); + + SYMBOL_SET_LANGUAGE (sym, language_c, &objfile->objfile_obstack); + SYMBOL_SET_NAMES (sym, name.get (), strlen (name.get ()), 1, objfile); + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; + SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT; + + if (type != NULL) + SYMBOL_TYPE (sym) = type; + + uint32_t kind = ctf_type_kind (fp, tid); + switch (kind) + { + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF; + SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN; + break; + case CTF_K_FUNCTION: + SYMBOL_ACLASS_INDEX (sym) = LOC_STATIC; + break; + case CTF_K_CONST: + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_VOID) + SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_int; + break; + case CTF_K_TYPEDEF: + case CTF_K_INTEGER: + case CTF_K_FLOAT: + SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; + break; + case CTF_K_POINTER: + break; + case CTF_K_VOLATILE: + case CTF_K_RESTRICT: + break; + case CTF_K_SLICE: + case CTF_K_ARRAY: + case CTF_K_UNKNOWN: + break; + } + + add_symbol_to_list (sym, ccp->builder->get_global_symbols ()); + } + + return sym; +} + +/* Given a TID of kind CTF_K_INTEGER or CTF_K_FLOAT, find a representation + and create the symbol for it. */ + +static struct type * +read_base_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct objfile *of = ccp->of; + ctf_file_t *fp = ccp->fp; + ctf_encoding_t cet; + struct type *type = NULL; + char *name; + uint32_t kind; + + if (ctf_type_encoding (fp, tid, &cet)) + { + complaint (_("ctf_type_encoding read_base_type failed - %s"), + ctf_errmsg (ctf_errno (fp))); + return NULL; + } + + gdb::unique_xmalloc_ptr copied_name (ctf_type_aname_raw (fp, tid)); + if (copied_name == NULL || strlen (copied_name.get ()) == 0) + { + name = ctf_type_aname (fp, tid); + if (name == NULL) + complaint (_("ctf_type_aname read_base_type failed - %s"), + ctf_errmsg (ctf_errno (fp))); + } + else + name = obstack_strdup (&of->objfile_obstack, copied_name.get ()); + + kind = ctf_type_kind (fp, tid); + if (kind == CTF_K_INTEGER) + { + uint32_t issigned, ischar, isbool; + struct gdbarch *gdbarch = get_objfile_arch (of); + + issigned = cet.cte_format & CTF_INT_SIGNED; + ischar = cet.cte_format & CTF_INT_CHAR; + isbool = cet.cte_format & CTF_INT_BOOL; + if (ischar) + type = init_character_type (of, TARGET_CHAR_BIT, !issigned, name); + else if (isbool) + type = init_boolean_type (of, gdbarch_int_bit (gdbarch), + !issigned, name); + else + { + int bits; + if (cet.cte_bits && ((cet.cte_bits % TARGET_CHAR_BIT) == 0)) + bits = cet.cte_bits; + else + bits = gdbarch_int_bit (gdbarch); + type = init_integer_type (of, bits, !issigned, name); + } + } + else if (kind == CTF_K_FLOAT) + { + uint32_t isflt; + isflt = !((cet.cte_format & CTF_FP_IMAGRY) == CTF_FP_IMAGRY + || (cet.cte_format & CTF_FP_DIMAGRY) == CTF_FP_DIMAGRY + || (cet.cte_format & CTF_FP_LDIMAGRY) == CTF_FP_LDIMAGRY); + if (isflt) + type = ctf_init_float_type (of, cet.cte_bits, name, name); + else + { + struct type *t + = ctf_init_float_type (of, cet.cte_bits / 2, NULL, name); + type = init_complex_type (of, name, t); + } + } + else + { + complaint (_("read_base_type: unsupported base kind (%d)"), kind); + type = init_type (of, TYPE_CODE_ERROR, cet.cte_bits, name); + } + + if (name != NULL && strcmp (name, "char") == 0) + TYPE_NOSIGN (type) = 1; + + return set_tid_type (of, tid, type); +} + +static void +process_base_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct type *type; + + type = read_base_type (ccp, tid); + new_symbol (ccp, type, tid); +} + +/* Start a structure or union scope (definition) with TID to create a type + for the structure or union. + + Fill in the type's name and general properties. The members will not be + processed, nor a symbol table entry be done until process_structure_type + (assuming the type has a name). */ + +static struct type * +read_structure_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct objfile *of = ccp->of; + ctf_file_t *fp = ccp->fp; + struct type *type; + uint32_t kind; + + type = alloc_type (of); + + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (fp, tid)); + if (name != NULL && strlen (name.get() ) != 0) + TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ()); + + kind = ctf_type_kind (fp, tid); + if (kind == CTF_K_UNION) + TYPE_CODE (type) = TYPE_CODE_UNION; + else + TYPE_CODE (type) = TYPE_CODE_STRUCT; + + TYPE_LENGTH (type) = ctf_type_size (fp, tid); + set_type_align (type, ctf_type_align (fp, tid)); + + return set_tid_type (ccp->of, tid, type); +} + +/* Given a tid of CTF_K_STRUCT or CTF_K_UNION, process all its members + and create the symbol for it. */ + +static void +process_struct_members (ctf_context_t *ccp, + ctf_id_t tid, + struct type *type) +{ + struct field_info fi; + + fi.cur_context = ccp; + if (ctf_member_iter (ccp->fp, tid, ctf_add_member_cb, &fi) == CTF_ERR) + complaint (_("ctf_member_iter process_struct_members failed - %s"), + ctf_errmsg (ctf_errno (ccp->fp))); + + /* Attach fields to the type. */ + attach_fields_to_type (&fi, type); + + new_symbol (ccp, type, tid); +} + +static void +process_structure_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct type *type; + + type = read_structure_type (ccp, tid); + process_struct_members (ccp, tid, type); +} + +/* Create a function type for TID and set its return type. */ + +static struct type * +read_func_kind_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct objfile *of = ccp->of; + ctf_file_t *fp = ccp->fp; + struct type *type, *rettype; + ctf_funcinfo_t cfi; + + type = alloc_type (of); + + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (fp, tid)); + if (name != NULL && strlen (name.get ()) != 0) + TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ()); + + TYPE_CODE (type) = TYPE_CODE_FUNC; + ctf_func_type_info (fp, tid, &cfi); + rettype = get_tid_type (of, cfi.ctc_return); + TYPE_TARGET_TYPE (type) = rettype; + set_type_align (type, ctf_type_align (fp, tid)); + + return set_tid_type (of, tid, type); +} + +/* Given a TID of CTF_K_ENUM, process all the members of the + enumeration, and create the symbol for the enumeration type. */ + +static struct type * +read_enum_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct objfile *of = ccp->of; + ctf_file_t *fp = ccp->fp; + struct type *type, *target_type; + ctf_funcinfo_t fi; + + type = alloc_type (of); + + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (fp, tid)); + if (name != NULL && strlen (name.get ()) != 0) + TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ()); + + TYPE_CODE (type) = TYPE_CODE_ENUM; + TYPE_LENGTH (type) = ctf_type_size (fp, tid); + ctf_func_type_info (fp, tid, &fi); + target_type = get_tid_type (of, fi.ctc_return); + TYPE_TARGET_TYPE (type) = target_type; + set_type_align (type, ctf_type_align (fp, tid)); + + return set_tid_type (of, tid, type); +} + +static void +process_enum_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct type *type; + struct field_info fi; + + type = read_enum_type (ccp, tid); + + fi.cur_context = ccp; + fi.ptype = type; + if (ctf_enum_iter (ccp->fp, tid, ctf_add_enum_member_cb, &fi) == CTF_ERR) + complaint (_("ctf_enum_iter process_enum_type failed - %s"), + ctf_errmsg (ctf_errno (ccp->fp))); + + /* Attach fields to the type. */ + attach_fields_to_type (&fi, type); + + new_symbol (ccp, type, tid); +} + +/* Add given cv-qualifiers CNST+VOLTL to the BASE_TYPE of array TID. */ + +static struct type * +add_array_cv_type (ctf_context_t *ccp, + ctf_id_t tid, + struct type *base_type, + int cnst, + int voltl) +{ + struct type *el_type, *inner_array; + + base_type = copy_type (base_type); + inner_array = base_type; + + while (TYPE_CODE (TYPE_TARGET_TYPE (inner_array)) == TYPE_CODE_ARRAY) + { + TYPE_TARGET_TYPE (inner_array) + = copy_type (TYPE_TARGET_TYPE (inner_array)); + inner_array = TYPE_TARGET_TYPE (inner_array); + } + + el_type = TYPE_TARGET_TYPE (inner_array); + cnst |= TYPE_CONST (el_type); + voltl |= TYPE_VOLATILE (el_type); + TYPE_TARGET_TYPE (inner_array) = make_cv_type (cnst, voltl, el_type, NULL); + + return set_tid_type (ccp->of, tid, base_type); +} + +/* Read all information from a TID of CTF_K_ARRAY. */ + +static struct type * +read_array_type (ctf_context_t *ccp, ctf_id_t tid) +{ + struct objfile *objfile = ccp->of; + ctf_file_t *fp = ccp->fp; + struct type *element_type, *range_type, *idx_type; + struct type *type; + ctf_arinfo_t ar; + + if (ctf_array_info (fp, tid, &ar) == CTF_ERR) + { + complaint (_("ctf_array_info read_array_type failed - %s"), + ctf_errmsg (ctf_errno (fp))); + return NULL; + } + + element_type = get_tid_type (objfile, ar.ctr_contents); + if (element_type == NULL) + return NULL; + + idx_type = get_tid_type (objfile, ar.ctr_index); + if (idx_type == NULL) + idx_type = objfile_type (objfile)->builtin_int; + + range_type = create_static_range_type (NULL, idx_type, 0, ar.ctr_nelems - 1); + type = create_array_type (NULL, element_type, range_type); + if (ar.ctr_nelems <= 1) /* Check if undefined upper bound. */ + { + TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED; + TYPE_LENGTH (type) = 0; + TYPE_TARGET_STUB (type) = 1; + } + else + TYPE_LENGTH (type) = ctf_type_size (fp, tid); + + set_type_align (type, ctf_type_align (fp, tid)); + + return set_tid_type (objfile, tid, type); +} + +/* Read TID of kind CTF_K_CONST with base type BTID. */ + +static struct type * +read_const_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid) +{ + struct objfile *objfile = ccp->of; + struct type *base_type, *cv_type; + + base_type = get_tid_type (objfile, btid); + if (base_type == NULL) + { + base_type = read_type_record (ccp, btid); + if (base_type == NULL) + { + complaint (_("read_const_type: NULL base type (%ld)"), btid); + base_type = objfile_type (objfile)->builtin_error; + } + } + cv_type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0); + + return set_tid_type (objfile, tid, cv_type); +} + +/* Read TID of kind CTF_K_VOLATILE with base type BTID. */ + +static struct type * +read_volatile_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid) +{ + struct objfile *objfile = ccp->of; + ctf_file_t *fp = ccp->fp; + struct type *base_type, *cv_type; + + base_type = get_tid_type (objfile, btid); + if (base_type == NULL) + { + base_type = read_type_record (ccp, btid); + if (base_type == NULL) + { + complaint (_("read_volatile_type: NULL base type (%ld)"), btid); + base_type = objfile_type (objfile)->builtin_error; + } + } + + if (ctf_type_kind (fp, btid) == CTF_K_ARRAY) + return add_array_cv_type (ccp, tid, base_type, 0, 1); + cv_type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0); + + return set_tid_type (objfile, tid, cv_type); +} + +/* Read TID of kind CTF_K_RESTRICT with base type BTID. */ + +static struct type * +read_restrict_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid) +{ + struct objfile *objfile = ccp->of; + struct type *base_type, *cv_type; + + base_type = get_tid_type (objfile, btid); + if (base_type == NULL) + { + base_type = read_type_record (ccp, btid); + if (base_type == NULL) + { + complaint (_("read_restrict_type: NULL base type (%ld)"), btid); + base_type = objfile_type (objfile)->builtin_error; + } + } + cv_type = make_restrict_type (base_type); + + return set_tid_type (objfile, tid, cv_type); +} + +/* Read TID of kind CTF_K_TYPEDEF with its NAME and base type BTID. */ + +static struct type * +read_typedef_type (ctf_context_t *ccp, ctf_id_t tid, + ctf_id_t btid, const char *name) +{ + struct objfile *objfile = ccp->of; + struct type *this_type, *target_type; + + char *aname = obstack_strdup (&objfile->objfile_obstack, name); + this_type = init_type (objfile, TYPE_CODE_TYPEDEF, 0, aname); + set_tid_type (objfile, tid, this_type); + target_type = get_tid_type (objfile, btid); + if (target_type != this_type) + TYPE_TARGET_TYPE (this_type) = target_type; + else + TYPE_TARGET_TYPE (this_type) = NULL; + TYPE_TARGET_STUB (this_type) = TYPE_TARGET_TYPE (this_type) ? 1 : 0; + + return set_tid_type (objfile, tid, this_type); +} + +/* Read TID of kind CTF_K_POINTER with base type BTID. */ + +static struct type * +read_pointer_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid) +{ + struct objfile *of = ccp->of; + struct type *target_type, *type; + + target_type = get_tid_type (of, btid); + if (target_type == NULL) + { + target_type = read_type_record (ccp, btid); + if (target_type == NULL) + { + complaint (_("read_pointer_type: NULL target type (%ld)"), btid); + target_type = objfile_type (ccp->of)->builtin_error; + } + } + + type = lookup_pointer_type (target_type); + set_type_align (type, ctf_type_align (ccp->fp, tid)); + + return set_tid_type (of, tid, type); +} + +/* Read information associated with type TID. */ + +static struct type * +read_type_record (ctf_context_t *ccp, ctf_id_t tid) +{ + ctf_file_t *fp = ccp->fp; + uint32_t kind; + struct type *type = NULL; + ctf_id_t btid; + + kind = ctf_type_kind (fp, tid); + switch (kind) + { + case CTF_K_STRUCT: + case CTF_K_UNION: + type = read_structure_type (ccp, tid); + break; + case CTF_K_ENUM: + type = read_enum_type (ccp, tid); + break; + case CTF_K_FUNCTION: + type = read_func_kind_type (ccp, tid); + break; + case CTF_K_CONST: + btid = ctf_type_reference (fp, tid); + type = read_const_type (ccp, tid, btid); + break; + case CTF_K_TYPEDEF: + { + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (fp, tid)); + btid = ctf_type_reference (fp, tid); + type = read_typedef_type (ccp, tid, btid, name.get ()); + } + break; + case CTF_K_VOLATILE: + btid = ctf_type_reference (fp, tid); + type = read_volatile_type (ccp, tid, btid); + break; + case CTF_K_RESTRICT: + btid = ctf_type_reference (fp, tid); + type = read_restrict_type (ccp, tid, btid); + break; + case CTF_K_POINTER: + btid = ctf_type_reference (fp, tid); + type = read_pointer_type (ccp, tid, btid); + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + type = read_base_type (ccp, tid); + break; + case CTF_K_ARRAY: + type = read_array_type (ccp, tid); + break; + case CTF_K_UNKNOWN: + break; + default: + break; + } + + return type; +} + +/* Callback to add type TID to the symbol table. */ + +static int +ctf_add_type_cb (ctf_id_t tid, void *arg) +{ + ctf_context_t *ccp = (ctf_context_t *) arg; + struct type *type; + uint32_t kind; + + /* Check if tid's type has already been defined. */ + type = get_tid_type (ccp->of, tid); + if (type != NULL) + return 0; + + ctf_id_t btid = ctf_type_reference (ccp->fp, tid); + kind = ctf_type_kind (ccp->fp, tid); + switch (kind) + { + case CTF_K_STRUCT: + case CTF_K_UNION: + process_structure_type (ccp, tid); + break; + case CTF_K_ENUM: + process_enum_type (ccp, tid); + break; + case CTF_K_FUNCTION: + type = read_func_kind_type (ccp, tid); + new_symbol (ccp, type, tid); + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + process_base_type (ccp, tid); + break; + case CTF_K_TYPEDEF: + new_symbol (ccp, read_type_record (ccp, tid), tid); + break; + case CTF_K_CONST: + type = read_const_type (ccp, tid, btid); + new_symbol (ccp, type, tid); + break; + case CTF_K_VOLATILE: + type = read_volatile_type (ccp, tid, btid); + new_symbol (ccp, type, tid); + break; + case CTF_K_RESTRICT: + type = read_restrict_type (ccp, tid, btid); + new_symbol (ccp, type, tid); + break; + case CTF_K_POINTER: + type = read_pointer_type (ccp, tid, btid); + new_symbol (ccp, type, tid); + break; + case CTF_K_ARRAY: + type = read_array_type (ccp, tid); + new_symbol (ccp, type, tid); + break; + case CTF_K_UNKNOWN: + break; + default: + break; + } + + return 0; +} + +/* Callback to add variable NAME with TID to the symbol table. */ + +static int +ctf_add_var_cb (const char *name, ctf_id_t id, void *arg) +{ + ctf_context_t *ccp = (ctf_context_t *) arg; + struct symbol *sym = NULL; + struct type *type; + uint32_t kind; + + type = get_tid_type (ccp->of, id); + + kind = ctf_type_kind (ccp->fp, id); + switch (kind) + { + case CTF_K_FUNCTION: + if (name && !strcmp(name, "main")) + set_objfile_main_name (ccp->of, name, language_c); + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + case CTF_K_VOLATILE: + case CTF_K_RESTRICT: + case CTF_K_TYPEDEF: + case CTF_K_CONST: + case CTF_K_POINTER: + case CTF_K_ARRAY: + if (type) + { + sym = new_symbol (ccp, type, id); + SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of); + } + break; + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + if (type == NULL) + { + complaint (_("ctf_add_var_cb: %s has NO type (%ld)"), name, id); + type = objfile_type (ccp->of)->builtin_error; + } + sym = allocate_symbol (ccp->of); + OBJSTAT (ccp->of, n_syms++); + SYMBOL_TYPE (sym) = type; + SYMBOL_DOMAIN (sym) = VAR_DOMAIN; + SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT; + SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of); + add_symbol_to_list (sym, ccp->builder->get_global_symbols ()); + break; + default: + complaint (_("ctf_add_var_cb: kind unsupported (%d)"), kind); + break; + } + + if (sym) + set_symbol_address (ccp->of, sym, name); + + return 0; +} + +/* Add an ELF STT_OBJ symbol with index IDX to the symbol table. */ + +static struct symbol * +add_stt_obj (ctf_context_t *ccp, unsigned long idx) +{ + struct symbol *sym; + struct type *type; + ctf_id_t tid; + + if ((tid = ctf_lookup_by_symbol (ccp->fp, idx)) == CTF_ERR) + return NULL; + + type = get_tid_type (ccp->of, tid); + if (type == NULL) + return NULL; + + sym = new_symbol (ccp, type, tid); + + return sym; +} + +/* Add an ELF STT_FUNC symbol with index IDX to the symbol table. */ + +static struct symbol * +add_stt_func (ctf_context_t *ccp, unsigned long idx) +{ + struct type *ftype, *atyp, *rettyp; + struct symbol *sym; + ctf_funcinfo_t finfo; + ctf_id_t argv[32]; + uint32_t argc; + ctf_id_t tid; + struct type *void_type = objfile_type (ccp->of)->builtin_void; + + if (ctf_func_info (ccp->fp, idx, &finfo) == CTF_ERR) + return NULL; + + argc = finfo.ctc_argc; + if (ctf_func_args (ccp->fp, idx, argc, argv) == CTF_ERR) + return NULL; + + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (ccp->fp, idx)); + if (name == NULL) + return NULL; + + tid = ctf_lookup_by_symbol (ccp->fp, idx); + ftype = get_tid_type (ccp->of, tid); + if (finfo.ctc_flags & CTF_FUNC_VARARG) + TYPE_VARARGS (ftype) = 1; + TYPE_NFIELDS (ftype) = argc; + + /* If argc is 0, it has a "void" type. */ + if (argc != 0) + TYPE_FIELDS (ftype) + = (struct field *) TYPE_ZALLOC (ftype, argc * sizeof (struct field)); + + /* TYPE_FIELD_TYPE must never be NULL. Fill it with void_type, if failed + to find the argument type. */ + for (int iparam = 0; iparam < argc; iparam++) + { + atyp = get_tid_type (ccp->of, argv[iparam]); + if (atyp) + TYPE_FIELD_TYPE (ftype, iparam) = atyp; + else + TYPE_FIELD_TYPE (ftype, iparam) = void_type; + } + + sym = new_symbol (ccp, ftype, tid); + rettyp = get_tid_type (ccp->of, finfo.ctc_return); + if (rettyp != NULL) + SYMBOL_TYPE (sym) = rettyp; + else + SYMBOL_TYPE (sym) = void_type; + + return sym; +} + +/* Get text segment base for OBJFILE, TSIZE contains the segment size. */ + +static CORE_ADDR +get_objfile_text_range (struct objfile *of, int *tsize) +{ + CORE_ADDR text_base; + bfd *abfd = of->obfd; + const asection *codes; + + codes = bfd_get_section_by_name (abfd, ".text"); + if (codes == NULL) + { + text_base = 0; + *tsize = 0; + } + else + { + text_base = bfd_section_vma (codes); + *tsize = codes->size; + } + + return text_base; +} + +/* Start a symtab for OBJFILE in CTF format. */ + +static void +ctf_start_symtab (struct partial_symtab *pst, + struct objfile *of, CORE_ADDR text_offset) +{ + ctf_context_t *ccp; + + ccp = (ctf_context_t *) pst->read_symtab_private; + ccp->builder = new buildsym_compunit + (of, of->original_name, NULL, + language_c, text_offset); + ccp->builder->record_debugformat ("ctf"); +} + +/* Finish reading symbol/type definitions in CTF format. + END_ADDR is the end address of the file's text. SECTION is + the .text section number. */ + +static struct compunit_symtab * +ctf_end_symtab (struct partial_symtab *pst, + CORE_ADDR end_addr, int section) +{ + ctf_context_t *ccp; + + ccp = (ctf_context_t *) pst->read_symtab_private; + struct compunit_symtab *result + = ccp->builder->end_symtab (end_addr, section); + delete ccp->builder; + ccp->builder = NULL; + return result; +} + +/* Read in full symbols for PST, and anything it depends on. */ + +static void +psymtab_to_symtab (struct partial_symtab *pst) +{ + struct symbol *sym; + ctf_context_t *ccp; + + gdb_assert (!pst->readin); + + ccp = (ctf_context_t *) pst->read_symtab_private; + + /* Iterate over entries in data types section. */ + if (ctf_type_iter (ccp->fp, ctf_add_type_cb, ccp) == CTF_ERR) + complaint (_("ctf_type_iter psymtab_to_symtab failed - %s"), + ctf_errmsg (ctf_errno (ccp->fp))); + + + /* Iterate over entries in variable info section. */ + if (ctf_variable_iter (ccp->fp, ctf_add_var_cb, ccp) == CTF_ERR) + complaint (_("ctf_variable_iter psymtab_to_symtab failed - %s"), + ctf_errmsg (ctf_errno (ccp->fp))); + + /* Add entries in data objects and function info sections. */ + for (unsigned long i = 0; ; i++) + { + sym = add_stt_obj (ccp, i); + if (sym == NULL) + { + if (ctf_errno (ccp->fp) == EINVAL + || ctf_errno (ccp->fp) == ECTF_NOSYMTAB) + break; + sym = add_stt_func (ccp, i); + } + if (sym == NULL) + continue; + + set_symbol_address (ccp->of, sym, SYMBOL_LINKAGE_NAME (sym)); + } + + pst->readin = 1; +} + +/* Expand partial symbol table PST into a full symbol table. + PST is not NULL. */ + +static void +ctf_read_symtab (struct partial_symtab *pst, struct objfile *objfile) +{ + if (pst->readin) + warning (_("bug: psymtab for %s is already read in."), pst->filename); + else + { + if (info_verbose) + { + printf_filtered (_("Reading in CTF data for %s..."), pst->filename); + gdb_flush (gdb_stdout); + } + + /* Start a symtab. */ + CORE_ADDR text_offset; /* Start of text segment. */ + int tsize; + + text_offset = get_objfile_text_range (objfile, &tsize); + ctf_start_symtab (pst, objfile, text_offset); + psymtab_to_symtab (pst); + + pst->set_text_low (text_offset); + pst->set_text_high (text_offset + tsize); + pst->compunit_symtab = ctf_end_symtab (pst, text_offset + tsize, + SECT_OFF_TEXT (objfile)); + + /* Finish up the debug error message. */ + if (info_verbose) + printf_filtered (_("done.\n")); + } +} + +/* Cleanup function for the ctf_file_key data. */ + +static void +ctf_close_objfile (struct objfile *of, void *datum) +{ + ctf_file_t *fp = static_cast (datum); + ctf_archive_t *arc = ctf_get_arc (fp); + ctf_file_close (fp); + ctf_close (arc); +} + +/* Allocate a new partial_symtab NAME. + + Each source file that has not been fully read in is represented by + a partial_symtab. This contains the information on where in the + executable the debugging symbols for a specific file are, and a + list of names of global symbols which are located in this file. + They are all chained on partial symtab lists. + + Even after the source file has been read into a symtab, the + partial_symtab remains around. They are allocated on an obstack, + objfile_obstack. */ + +static struct partial_symtab * +create_partial_symtab (const char *name, + ctf_file_t *cfp, + struct objfile *objfile) +{ + struct partial_symtab *pst; + ctf_context_t *ccx; + + pst = start_psymtab_common (objfile, name, 0); + + ccx = XOBNEW (&objfile->objfile_obstack, ctf_context_t); + ccx->fp = cfp; + ccx->of = objfile; + pst->read_symtab_private = (void *) ccx; + pst->read_symtab = ctf_read_symtab; + + return pst; +} + +/* Callback to add type TID to partial symbol table. */ + +static int +ctf_psymtab_type_cb (ctf_id_t tid, void *arg) +{ + ctf_context_t *ccp; + uint32_t kind; + short section = -1; + + ccp = (ctf_context_t *) arg; + gdb::unique_xmalloc_ptr name (ctf_type_aname_raw (ccp->fp, tid)); + if (name == NULL || strlen (name.get ()) == 0) + return 0; + + domain_enum domain = UNDEF_DOMAIN; + enum address_class aclass = LOC_UNDEF; + kind = ctf_type_kind (ccp->fp, tid); + switch (kind) + { + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + domain = STRUCT_DOMAIN; + aclass = LOC_TYPEDEF; + break; + case CTF_K_FUNCTION: + case CTF_K_FORWARD: + domain = VAR_DOMAIN; + aclass = LOC_STATIC; + section = SECT_OFF_TEXT (ccp->of); + break; + case CTF_K_CONST: + domain = VAR_DOMAIN; + aclass = LOC_STATIC; + break; + case CTF_K_TYPEDEF: + case CTF_K_POINTER: + case CTF_K_VOLATILE: + case CTF_K_RESTRICT: + domain = VAR_DOMAIN; + aclass = LOC_TYPEDEF; + break; + case CTF_K_INTEGER: + case CTF_K_FLOAT: + domain = VAR_DOMAIN; + aclass = LOC_TYPEDEF; + break; + case CTF_K_ARRAY: + case CTF_K_UNKNOWN: + return 0; + } + + add_psymbol_to_list (name.get (), strlen (name.get ()), true, + domain, aclass, section, + psymbol_placement::GLOBAL, + 0, language_c, ccp->of); + + return 0; +} + +/* Callback to add variable NAME with ID to partial symbol table. */ + +static int +ctf_psymtab_var_cb (const char *name, ctf_id_t id, void *arg) +{ + ctf_context_t *ccp = (ctf_context_t *) arg; + + add_psymbol_to_list (name, strlen (name), true, + VAR_DOMAIN, LOC_STATIC, -1, + psymbol_placement::GLOBAL, + 0, language_c, ccp->of); + return 0; +} + +/* Setup partial_symtab's describing each source file for which + debugging information is available. */ + +static void +scan_partial_symbols (ctf_file_t *cfp, struct objfile *of) +{ + ctf_context_t ccx; + bfd *abfd = of->obfd; + const char *name = bfd_get_filename (abfd); + struct partial_symtab *pst = create_partial_symtab (name, cfp, of); + + ccx.fp = cfp; + ccx.of = of; + + if (ctf_type_iter (cfp, ctf_psymtab_type_cb, &ccx) == CTF_ERR) + complaint (_("ctf_type_iter scan_partial_symbols failed - %s"), + ctf_errmsg (ctf_errno (cfp))); + + if (ctf_variable_iter (cfp, ctf_psymtab_var_cb, &ccx) == CTF_ERR) + complaint (_("ctf_variable_iter scan_partial_symbols failed - %s"), + ctf_errmsg (ctf_errno (cfp))); + + /* Scan CTF object and function sections which correspond to each + STT_FUNC or STT_OBJECT entry in the symbol table, + pick up what init_symtab has done. */ + for (unsigned long idx = 0; ; idx++) + { + ctf_id_t tid; + if ((tid = ctf_lookup_by_symbol (cfp, idx)) == CTF_ERR) + { + if (ctf_errno (cfp) == EINVAL || ctf_errno (cfp) == ECTF_NOSYMTAB) + break; // Done, reach end of the section. + else + continue; + } + gdb::unique_xmalloc_ptr tname (ctf_type_aname_raw (cfp, tid)); + uint32_t kind = ctf_type_kind (cfp, tid); + address_class aclass; + domain_enum tdomain; + switch (kind) + { + case CTF_K_STRUCT: + case CTF_K_UNION: + case CTF_K_ENUM: + tdomain = STRUCT_DOMAIN; + break; + default: + tdomain = VAR_DOMAIN; + break; + } + + if (kind == CTF_K_FUNCTION) + aclass = LOC_STATIC; + else if (kind == CTF_K_CONST) + aclass = LOC_CONST; + else + aclass = LOC_TYPEDEF; + + add_psymbol_to_list (tname.get (), strlen (tname.get ()), true, + tdomain, aclass, -1, + psymbol_placement::STATIC, + 0, language_c, of); + } + + end_psymtab_common (of, pst); +} + +/* Read CTF debugging information from a BFD section. This is + called from elfread.c. It does a quick pass through the + .ctf section to set up the partial symbol table. */ + +void +elfctf_build_psymtabs (struct objfile *of) +{ + bfd *abfd = of->obfd; + int err; + + ctf_archive_t *arc = ctf_bfdopen (abfd, &err); + if (arc == NULL) + error (_("ctf_bfdopen failed on %s - %s"), + bfd_get_filename (abfd), ctf_errmsg (err)); + + ctf_file_t *fp = ctf_arc_open_by_name (arc, NULL, &err); + if (fp == NULL) + error (_("ctf_arc_open_by_name failed on %s - %s"), + bfd_get_filename (abfd), ctf_errmsg (err)); + set_objfile_data (of, ctf_file_key, fp); + + scan_partial_symbols (fp, of); +} + +void +_initialize_ctfread (void) +{ + ctf_file_key + = register_objfile_data_with_cleanup (NULL, ctf_close_objfile); +} diff --git a/gdb/ctfread.h b/gdb/ctfread.h new file mode 100644 index 00000000000..632ee12b681 --- /dev/null +++ b/gdb/ctfread.h @@ -0,0 +1,25 @@ +/* CTF debugging format support for GDB. + + Copyright (C) 2019 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#ifndef CTFREAD_H +#define CTFREAD_H + +extern void elfctf_build_psymtabs (struct objfile *objfile); + +#endif /* CTFREAD_H */ diff --git a/gdb/elfread.c b/gdb/elfread.c index d2a7bcf8aa6..53bdd356594 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -47,6 +47,7 @@ #include "location.h" #include "auxv.h" #include "mdebugread.h" +#include "ctfread.h" /* Forward declarations. */ extern const struct sym_fns elf_sym_fns_gdb_index; @@ -61,6 +62,7 @@ struct elfinfo { asection *stabsect; /* Section pointer for .stab section */ asection *mdebugsect; /* Section pointer for .mdebug section */ + asection *ctfsect; /* Section pointer for .ctf section */ }; /* Type for per-BFD data. */ @@ -188,6 +190,10 @@ elf_locate_sections (bfd *ignore_abfd, asection *sectp, void *eip) { ei->mdebugsect = sectp; } + else if (strcmp (sectp->name, ".ctf") == 0) + { + ei->ctfsect = sectp; + } } static struct minimal_symbol * @@ -1059,7 +1065,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags, go away once all types of symbols are in the per-BFD object. */ if (objfile->per_bfd->minsyms_read && ei->stabsect == NULL - && ei->mdebugsect == NULL) + && ei->mdebugsect == NULL + && ei->ctfsect == NULL) { if (symtab_create_debug) fprintf_unfiltered (gdb_stdlog, @@ -1200,6 +1207,7 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) { bfd *abfd = objfile->obfd; struct elfinfo ei; + bool has_dwarf2 = true; memset ((char *) &ei, 0, sizeof (ei)); if (!(objfile->flags & OBJF_READNEVER)) @@ -1302,6 +1310,14 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) symbol_file_add_separate (debug_bfd.get (), debugfile.c_str (), symfile_flags, objfile); } + else + has_dwarf2 = false; + } + + /* Read the CTF section only if there is no DWARF info. */ + if (!has_dwarf2 && ei.ctfsect) + { + elfctf_build_psymtabs (objfile); } } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 0eeb8c6fbdf..0d42016edf8 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2019-10-07 Weimin Pan + + * gdb.base/ctf-whatis.exp: New file. + * gdb.base/ctf-whatis.c: New file. + * gdb.base/ctf-ptype.exp: New file. + * gdb.base/ctf-ptype.c: New file. + * gdb.base/ctf-constvars.exp: New file. + * gdb.base/ctf-constvars.c: New file. + * gdb.base/ctf-cvexpr.exp: New file. + 2019-10-04 Tom de Vries * gdb.cp/local-static.c (main): Move declaration of int i out of the diff --git a/gdb/testsuite/gdb.base/ctf-constvars.c b/gdb/testsuite/gdb.base/ctf-constvars.c new file mode 100644 index 00000000000..75f4250d474 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-constvars.c @@ -0,0 +1,116 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2019 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +const char laconic = 'A'; +const char *const lewd=&laconic; + +/* volatile variables */ + +volatile char vox = 'B'; +volatile unsigned char victuals = 'C'; +volatile short vixen = 200; +volatile unsigned short vitriol = 300; +volatile long vellum = 1000; +volatile unsigned long valve = 2000; +volatile float vacuity = 3.0; +volatile double vertigo = 10; + +/* pointers to volatile variables */ + +volatile char * vampire = &vox; +volatile unsigned char * viper = &victuals; +volatile short * vigour = &vixen; +volatile unsigned short * vapour = &vitriol; +volatile long * ventricle = &vellum; +volatile unsigned long * vigintillion = &valve; +volatile float * vocation = &vacuity; +volatile double * veracity = &vertigo; + +/* volatile pointers to volatile variables */ + +volatile char * volatile vapidity = &vox; +volatile unsigned char * volatile velocity = &victuals; +volatile short * volatile veneer = &vixen; +volatile unsigned short * volatile video = &vitriol; +volatile long * volatile vacuum = &vellum; +volatile unsigned long * volatile veniality = &valve; +volatile float * volatile vitality = &vacuity; +volatile double * volatile voracity = &vertigo; + +/* volatile arrays */ + +volatile char violent[2]; +volatile unsigned char violet[2]; +volatile short vips[2]; +volatile unsigned short virgen[2]; +volatile long vulgar[2]; +volatile unsigned long vulture[2]; +volatile float vilify[2]; +volatile double villar[2]; + +/* const volatile vars */ + +const volatile char victor = 'Y'; + +/* pointers to const volatiles */ + +const volatile char * victory = &victor; + +/* const pointers to const volatile vars */ + +const volatile char * const cavern = &victor; + +/* volatile pointers to const vars */ + +const char * volatile caveat = &laconic; +const unsigned char * volatile covenant; + +/* volatile pointers to const volatile vars */ + +const volatile char * volatile vizier = &victor; +const volatile unsigned char * volatile vanadium; + +/* const volatile pointers */ + +char * const volatile vane; +unsigned char * const volatile veldt; + +/* const volatile pointers to const vars */ + +const char * const volatile cove; +const unsigned char * const volatile cavity; + +/* const volatile pointers to volatile vars */ + +volatile char * const volatile vagus; +volatile unsigned char * const volatile vagrancy; + +/* const volatile pointers to const volatile */ + +const volatile char * const volatile vagary; +const volatile unsigned char * const volatile vendor; + +/* const volatile arrays */ + +const volatile char vindictive[2]; +const volatile unsigned char vegetation[2]; + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/ctf-constvars.exp b/gdb/testsuite/gdb.base/ctf-constvars.exp new file mode 100644 index 00000000000..4a81a94ddb4 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-constvars.exp @@ -0,0 +1,114 @@ +# Copyright 2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . */ + +# This file is a subset of constvars.exp, written by +# Elena Zannoni (elz@apollo.hp.com) +# +# This file is part of the gdb testsuite +# +# tests for const variables +# const pointers to vars +# pointers to const variables +# const pointers to const vars +# with mixed types + +# +# test running programs +# +# -gt generates full-fledged CTF. + +standard_testfile .c +set opts "additional_flags=-gt" + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile] [list $opts nowarnings]] } { + return 0 +} + +# +# set it up at a breakpoint so we can play with the variable values +# +if ![runto_main] then { + perror "couldn't run to breakpoint" + continue +} + +# test vars and pointers + +proc do_constvar_tests {} { + gdb_test "print vox" " = 66 'B'" + gdb_test "ptype vox" "type = volatile char" + gdb_test "print victuals" " = 67 'C'" + gdb_test "ptype victuals" "type = volatile unsigned char" + gdb_test "print vixen" " = 200" + gdb_test "ptype vixen" "type = volatile short.*" + gdb_test "print vitriol" " = 300" + gdb_test "ptype vitriol" "type = volatile (unsigned short|short unsigned)( int)?" + gdb_test "print vellum" " = 1000" + gdb_test "ptype vellum" "type = volatile long.*" + gdb_test "print valve" " = 2000" + gdb_test "ptype valve" "type = volatile (unsigned long|long unsigned)( int)?" + gdb_test "print vacuity" " = 3" + gdb_test "ptype vacuity" "type = volatile float" + gdb_test "print vertigo" " = 10" + gdb_test "ptype vertigo" "type = volatile double" + gdb_test "print laconic" " = 65 'A'" + + gdb_test "ptype vampire" "type = volatile char.*" + gdb_test "ptype viper" "type = volatile unsigned char.*" + gdb_test "ptype vigour" "type = volatile short.*" + gdb_test "ptype vapour" "type = volatile (unsigned short|short unsigned)( int)?.*" + gdb_test "ptype ventricle" "type = volatile long.*" + gdb_test "ptype vigintillion" "type = volatile (unsigned long|long unsigned)( int)?.*" + gdb_test "ptype vocation" "type = volatile float.*" + gdb_test "ptype veracity" "type = volatile double.*" + + gdb_test "ptype vapidity" "type = volatile char.* volatile" + gdb_test "ptype velocity" "type = volatile unsigned char.* volatile" + gdb_test "ptype veneer" "type = volatile short.* volatile" + gdb_test "ptype video" "type = volatile (unsigned short|short unsigned)( int)?.* volatile" + gdb_test "ptype vacuum" "type = volatile long.* volatile" + gdb_test "ptype veniality" "type = volatile (unsigned long|long unsigned)( int)?.* volatile" + gdb_test "ptype vitality" "type = volatile float.* volatile" + gdb_test "ptype voracity" "type = volatile double.* volatile" + + gdb_test "ptype violent" "type = volatile char \\\[2\\\]" + gdb_test "ptype violet" "type = volatile unsigned char \\\[2\\\]" + gdb_test "ptype vips" "type = volatile short.* \\\[2\\\]" + gdb_test "ptype virgen" "type = volatile unsigned short.* \\\[2\\\]" + gdb_test "ptype vulgar" "type = volatile long.* \\\[2\\\]" + gdb_test "ptype vulture" "type = volatile (unsigned long|long unsigned)( int)? \\\[2\\\]" + gdb_test "ptype vilify" "type = volatile float \\\[2\\\]" + gdb_test "ptype villar" "type = volatile double \\\[2\\\]" + + gdb_test "print victor" " = 89 'Y'" + gdb_test "ptype victor" "type = const volatile char" + gdb_test "ptype victory" "type = const volatile char.*" + gdb_test "ptype cavern" "type = const volatile char.* const" + gdb_test "ptype caveat" "type = const char.* volatile" + gdb_test "ptype covenant" "type = const unsigned char.* volatile" + gdb_test "ptype vanadium" "type = const volatile unsigned char.* volatile" + + gdb_test "ptype cove" "type = const char.* const volatile" + gdb_test "ptype cavity" "type = const unsigned char.* const volatile" + gdb_test "ptype vagus" "type = volatile char.* const volatile" + gdb_test "ptype vagrancy" "type = volatile unsigned char.* const volatile" + gdb_test "ptype vagary" "type = const volatile char.* const volatile" + gdb_test "ptype vendor" "type = const volatile unsigned char.* const volatile" + gdb_test "ptype vindictive" "type = const volatile char \\\[2\\\]" + gdb_test "ptype vegetation" "type = const volatile unsigned char \\\[2\\\]" +} + +do_constvar_tests diff --git a/gdb/testsuite/gdb.base/ctf-cvexpr.exp b/gdb/testsuite/gdb.base/ctf-cvexpr.exp new file mode 100644 index 00000000000..67ceb21f520 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-cvexpr.exp @@ -0,0 +1,495 @@ +# Copyright (C) 2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is a subset of cvexpr.exp written by +# Michael Snyder, Red Hat, Inc., 9/20/2001 + +# This file is part of the gdb testsuite +# Tests for type expressions using const and volatile keywords. + +# +# test running programs +# +# -gt generates full-fledged CTF. + +standard_testfile cvexpr.c +set opts "additional_flags=-gt" + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "failed to compile" + return -1 +} + +clean_restart ${binfile} + +gdb_test_no_output "set print sevenbit-strings" +gdb_test_no_output "set print address off" +gdb_test_no_output "set width 0" + +set ws "\[ \t\]*" + +# +# Test casting a scalar to const +# + +gdb_test "whatis (const char) v_char" \ + "type = const char" \ + "(const char)" +gdb_test "whatis (const signed char) v_signed_char" \ + "type = const signed char" \ + "(const signed char)" +gdb_test "whatis (const unsigned char) v_unsigned_char" \ + "type = const (unsigned char|char)" \ + "(const unsigned char)" +gdb_test "whatis (const short) v_short" \ + "type = const (short|short int)" \ + "(const short)" +gdb_test "whatis (const signed short) v_signed_short" \ + "type = const (short|short int|signed short|signed short int)" \ + "(const signed short)" +gdb_test "whatis (const unsigned short) v_unsigned_short" \ + "type = const (unsigned short|short unsigned int)" \ + "(const unsigned short)" +gdb_test "whatis (const int) v_int" \ + "type = const int" \ + "(const int)" +gdb_test "whatis (const signed int) v_signed_int" \ + "type = const (signed int|int)" \ + "(const signed int)" +gdb_test "whatis (const unsigned int) v_unsigned_int" \ + "type = const unsigned int" \ + "(const unsigned int)" +gdb_test "whatis (const long) v_long" \ + "type = const (long|long int)" \ + "(const long)" +gdb_test "whatis (const signed long) v_signed_long" \ + "type = const (signed |)long( int|)" \ + "(const signed long)" +gdb_test "whatis (const unsigned long) v_unsigned_long" \ + "type = const (unsigned long|long unsigned int)" \ + "(const unsigned long)" +gdb_test "whatis (const long long) v_long_long" \ + "type = const long long( int|)" \ + "(const long long)" +gdb_test "whatis (const signed long long) v_signed_long_long" \ + "type = const (signed |)long long( int|)" \ + "(const signed long long)" +gdb_test "whatis (const unsigned long long) v_unsigned_long_long" \ + "type = const (unsigned long long|long long unsigned int)" \ + "(const unsigned long long)" +gdb_test "whatis (const float) v_float" \ + "type = const float" \ + "(const float)" +gdb_test "whatis (const double) v_double" \ + "type = const double" \ + "(const double)" + +# +# Test casting a scalar to volatile +# + +gdb_test "whatis (volatile char) v_char" \ + "type = volatile char" \ + "(volatile char)" +gdb_test "whatis (volatile signed char) v_signed_char" \ + "type = volatile signed char" \ + "(volatile signed char)" +gdb_test "whatis (volatile unsigned char) v_unsigned_char" \ + "type = volatile (unsigned char|char)" \ + "(volatile unsigned char)" +gdb_test "whatis (volatile short) v_short" \ + "type = volatile (short|short int)" \ + "(volatile short)" +gdb_test "whatis (volatile signed short) v_signed_short" \ + "type = volatile (short|short int|signed short|signed short int)" \ + "(volatile signed short)" +gdb_test "whatis (volatile unsigned short) v_unsigned_short" \ + "type = volatile (unsigned short|short unsigned int)" \ + "(volatile unsigned short)" +gdb_test "whatis (volatile int) v_int" \ + "type = volatile int" \ + "(volatile int)" +gdb_test "whatis (volatile signed int) v_signed_int" \ + "type = volatile (signed int|int)" \ + "(volatile signed int)" +gdb_test "whatis (volatile unsigned int) v_unsigned_int" \ + "type = volatile unsigned int" \ + "(volatile unsigned int)" +gdb_test "whatis (volatile long) v_long" \ + "type = volatile (long|long int)" \ + "(volatile long)" +gdb_test "whatis (volatile signed long) v_signed_long" \ + "type = volatile (signed |)long( int|)" \ + "(volatile signed long)" +gdb_test "whatis (volatile unsigned long) v_unsigned_long" \ + "type = volatile (unsigned long|long unsigned int)" \ + "(volatile unsigned long)" +gdb_test "whatis (volatile long long) v_long_long" \ + "type = volatile long long( int|)" \ + "(volatile long long)" +gdb_test "whatis (volatile signed long long) v_signed_long_long" \ + "type = volatile (signed |)long long( int|)" \ + "(volatile signed long long)" +gdb_test "whatis (volatile unsigned long long) v_unsigned_long_long" \ + "type = volatile (unsigned long long|long long unsigned int)" \ + "(volatile unsigned long long)" +gdb_test "whatis (volatile float) v_float" \ + "type = volatile float" \ + "(volatile float)" +gdb_test "whatis (volatile double) v_double" \ + "type = volatile double" \ + "(volatile double)" + +# +# Combine const and volatile +# + +gdb_test "whatis (const volatile int) v_int" \ + "type = const volatile int" \ + "(const volatile int)" +gdb_test "whatis (volatile const int) v_int" \ + "type = const volatile int" \ + "(volatile const int)" +gdb_test "whatis (const int volatile) v_int" \ + "type = const volatile int" \ + "(const int volatile)" +gdb_test "whatis (volatile int const) v_int" \ + "type = const volatile int" \ + "(volatile int const)" +gdb_test "whatis (int const volatile) v_int" \ + "type = const volatile int" \ + "(int const volatile)" +gdb_test "whatis (int volatile const) v_int" \ + "type = const volatile int" \ + "(int volatile const)" + +gdb_test "whatis (const volatile int *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(const volatile int *)" +gdb_test "whatis (volatile const int *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(volatile const int *)" +gdb_test "whatis (const int volatile *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(const int volatile)" +gdb_test "whatis (volatile int const *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(volatile int const *)" +gdb_test "whatis (int const volatile *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(int const volatile *)" +gdb_test "whatis (int volatile const *) v_int_pointer" \ + "type = const volatile int${ws}\\*" \ + "(int volatile const *)" +gdb_test "whatis (int * const volatile) v_int_pointer" \ + "type = int${ws}\\*${ws}const volatile" \ + "(int * const volatile)" +gdb_test "whatis (int * volatile const) v_int_pointer" \ + "type = int${ws}\\*${ws}const volatile" \ + "(int * volatile const)" + + +# +# Put 'signed' and 'unsigned' before const/volatile (FIXME) +# + +#gdb_test "whatis (signed const char) v_signed_char" \ +# "type = const char" \ +# "(signed const char)" +#gdb_test "whatis (unsigned const char) v_unsigned_char" \ +# "type = const (unsigned char|char)" \ +# "(unsigned const char)" +#gdb_test "whatis (signed const short) v_signed_short" \ +# "type = const (short|short int|signed short|signed short int)" \ +# "(signed const short)" +#gdb_test "whatis (unsigned const short) v_unsigned_short" \ +# "type = const (unsigned short|short unsigned int)" \ +# "(unsigned const short)" +#gdb_test "whatis (signed const int) v_signed_int" \ +# "type = const (signed int|int)" \ +# "(signed const int)" +#gdb_test "whatis (unsigned const int) v_unsigned_int" \ +# "type = const unsigned int" \ +# "(unsigned const int)" +#gdb_test "whatis (signed const long) v_signed_long" \ +# "type = const (signed |)long( int|)" \ +# "(signed const long)" +#gdb_test "whatis (unsigned const long) v_unsigned_long" \ +# "type = const (unsigned long|long unsigned int)" \ +# "(unsigned const long)" +#gdb_test "whatis (signed const long long) v_signed_long_long" \ +# "type = const (signed |)long long( int|)" \ +# "(signed const long long)" +#gdb_test "whatis (unsigned const long long) v_unsigned_long_long" \ +# "type = const (unsigned long long|long long unsigned int)" \ +# "(const unsigned long long)" + +#gdb_test "whatis (signed volatile char) v_signed_char" \ +# "type = volatile char" \ +# "(signed volatile char)" +#gdb_test "whatis (unsigned volatile char) v_unsigned_char" \ +# "type = volatile (unsigned char|char)" \ +# "(unsigned volatile char)" +#gdb_test "whatis (signed volatile short) v_signed_short" \ +# "type = volatile (short|short int|signed short|signed short int)" \ +# "(signed volatile short)" +#gdb_test "whatis (unsigned volatile short) v_unsigned_short" \ +# "type = volatile (unsigned short|short unsigned int)" \ +# "(unsigned volatile short)" +#gdb_test "whatis (signed volatile int) v_signed_int" \ +# "type = volatile (signed int|int)" \ +# "(signed volatile int)" +#gdb_test "whatis (unsigned volatile int) v_unsigned_int" \ +# "type = volatile unsigned int" \ +# "(unsigned volatile int)" +#gdb_test "whatis (signed volatile long) v_signed_long" \ +# "type = volatile (signed |)long( int|)" \ +# "(signed volatile long)" +#gdb_test "whatis (unsigned volatile long) v_unsigned_long" \ +# "type = volatile (unsigned long|long unsigned int)" \ +# "(unsigned volatile long)" +#gdb_test "whatis (signed volatile long long) v_signed_long_long" \ +# "type = volatile (signed |)long long( int|)" \ +# "(signed volatile long long)" +#gdb_test "whatis (unsigned volatile long long) v_unsigned_long_long" \ +# "type = volatile (unsigned long long|long long unsigned int)" \ +# "(unsigned volatile long long)" + +# +# Now put the 'const' and 'volatile' keywords after the base type. +# + +gdb_test "whatis (char const) v_char" \ + "type = const char" \ + "(char const)" +gdb_test "whatis (signed char const) v_signed_char" \ + "type = const signed char" \ + "(signed char const)" +gdb_test "whatis (unsigned char const) v_unsigned_char" \ + "type = const (unsigned char|char)" \ + "(unsigned char const)" +gdb_test "whatis (short const) v_short" \ + "type = const (short|short int)" \ + "(short const)" +gdb_test "whatis (signed short const) v_signed_short" \ + "type = const (short|short int|signed short|signed short int)" \ + "(signed short const)" +gdb_test "whatis (unsigned short const) v_unsigned_short" \ + "type = const (unsigned short|short unsigned int)" \ + "(unsigned short const)" +gdb_test "whatis (int const) v_int" \ + "type = const int" \ + "(int const)" +gdb_test "whatis (signed int const) v_signed_int" \ + "type = const (signed int|int)" \ + "(signed int const)" +gdb_test "whatis (unsigned int const) v_unsigned_int" \ + "type = const unsigned int" \ + "(unsigned int const)" +gdb_test "whatis (long const) v_long" \ + "type = const (long|long int)" \ + "(long const)" +gdb_test "whatis (signed long const) v_signed_long" \ + "type = const (signed |)long( int|)" \ + "(signed long const)" +gdb_test "whatis (unsigned long const) v_unsigned_long" \ + "type = const (unsigned long|long unsigned int)" \ + "(unsigned long const)" +gdb_test "whatis (long long const) v_long_long" \ + "type = const long long( int|)" \ + "(long long const)" +gdb_test "whatis (signed long long const) v_signed_long_long" \ + "type = const (signed |)long long( int|)" \ + "(signed long long const)" +gdb_test "whatis (unsigned long long const) v_unsigned_long_long" \ + "type = const (unsigned long long|long long unsigned int)" \ + "(unsigned long long const)" +gdb_test "whatis (float const) v_float" \ + "type = const float" \ + "(float const)" +gdb_test "whatis (double const) v_double" \ + "type = const double" \ + "(double const)" + +gdb_test "whatis (char volatile) v_char" \ + "type = volatile char" \ + "(char volatile)" +gdb_test "whatis (signed char volatile) v_signed_char" \ + "type = volatile signed char" \ + "(signed char volatile)" +gdb_test "whatis (unsigned char volatile) v_unsigned_char" \ + "type = volatile (unsigned char|char)" \ + "(unsigned char volatile)" +gdb_test "whatis (short volatile) v_short" \ + "type = volatile (short|short int)" \ + "(short volatile)" +gdb_test "whatis (signed short volatile) v_signed_short" \ + "type = volatile (short|short int|signed short|signed short int)" \ + "(signed short volatile)" +gdb_test "whatis (unsigned short volatile) v_unsigned_short" \ + "type = volatile (unsigned short|short unsigned int)" \ + "(unsigned short volatile)" +gdb_test "whatis (int volatile) v_int" \ + "type = volatile int" \ + "(int volatile)" +gdb_test "whatis (signed int volatile) v_signed_int" \ + "type = volatile (signed int|int)" \ + "(signed int volatile)" +gdb_test "whatis (unsigned int volatile) v_unsigned_int" \ + "type = volatile unsigned int" \ + "(unsigned int volatile)" +gdb_test "whatis (long volatile) v_long" \ + "type = volatile (long|long int)" \ + "(long volatile)" +gdb_test "whatis (signed long volatile) v_signed_long" \ + "type = volatile (signed |)long( int|)" \ + "(signed long volatile)" +gdb_test "whatis (unsigned long volatile) v_unsigned_long" \ + "type = volatile (unsigned long|long unsigned int)" \ + "(unsigned long volatile)" +gdb_test "whatis (long long volatile) v_long_long" \ + "type = volatile long long( int|)" \ + "(long long volatile)" +gdb_test "whatis (signed long long volatile) v_signed_long_long" \ + "type = volatile (signed |)long long( int|)" \ + "(signed long long volatile)" +gdb_test "whatis (unsigned long long volatile) v_unsigned_long_long" \ + "type = volatile (unsigned long long|long long unsigned int)" \ + "(unsigned long long volatile)" +gdb_test "whatis (float volatile) v_float" \ + "type = volatile float" \ + "(float volatile)" +gdb_test "whatis (double volatile) v_double" \ + "type = volatile double" \ + "(double volatile)" + +# +# enums +# + +gdb_test "whatis (const enum misordered) v_misordered" \ + "type = const enum misordered" \ + "(const enum misordered)" +gdb_test "whatis (enum misordered const) v_misordered" \ + "type = const enum misordered" \ + "(enum misordered const)" +gdb_test "whatis (volatile enum misordered) v_misordered" \ + "type = volatile enum misordered" \ + "(volatile enum misordered)" +gdb_test "whatis (enum misordered volatile) v_misordered" \ + "type = volatile enum misordered" \ + "(enum misordered volatile)" + +# +# Pointers +# + +gdb_test "whatis (const int *) v_int_pointer" \ + "type = const int${ws}\\*" \ + "(const int *)" +gdb_test "whatis (int const *) v_int_pointer" \ + "type = const int${ws}\\*" \ + "(int const *)" +gdb_test "whatis (int * const) v_int_pointer" \ + "type = int \\*${ws}const" \ + "(int * const)" +gdb_test "whatis (const int * const) v_int_pointer" \ + "type = const int${ws}\\*${ws}const" \ + "(const int * const)" +gdb_test "whatis (int const * const) v_int_pointer" \ + "type = const int${ws}\\*${ws}const" \ + "(int const * const)" + +gdb_test "whatis (const int **) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}\\*" \ + "(const int **)" +gdb_test "whatis (int const **) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}\\*" \ + "(int const **)" +gdb_test "whatis (int ** const) v_int_pointer_pointer" \ + "type = int \\*${ws}\\*${ws}const" \ + "(int ** const)" +gdb_test "whatis (const int * const *) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}const${ws}\\*" \ + "(const int * const *)" +gdb_test "whatis (int const * const *) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}const${ws}\\*" \ + "(int const * const *)" +gdb_test "whatis (const int * const * const) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}const${ws}\\*${ws}const" \ + "(const int * const * const)" +gdb_test "whatis (int const * const * const) v_int_pointer_pointer" \ + "type = const int${ws}\\*${ws}const${ws}\\*${ws}const" \ + "(int const * const * const)" + +# +# Arrays TODO +# + +# +# Pointers to arrays, arrays of pointers TODO +# + +# +# Structs and Unions +# + +gdb_test "whatis (const struct t_struct) v_struct1" \ + "type = const struct t_struct" \ + "(const struct t_struct)" +gdb_test "whatis (const union t_union) v_union" \ + "type = const union t_union" \ + "(const union t_union)" +gdb_test "whatis (struct t_struct const) v_struct1" \ + "type = const struct t_struct" \ + "(struct t_struct const)" +gdb_test "whatis (union t_union const) v_union" \ + "type = const union t_union" \ + "(union t_union const)" +gdb_test "whatis (const struct t_struct *) &v_struct1" \ + "type = const struct t_struct${ws}\\*" \ + "(const struct t_struct *)" +gdb_test "whatis (const union t_union *) &v_union" \ + "type = const union t_union${ws}\\*" \ + "(const union t_union *)" +gdb_test "whatis (struct t_struct const *) &v_struct1" \ + "type = const struct t_struct${ws}\\*" \ + "(struct t_struct const *)" +gdb_test "whatis (union t_union const *) &v_union" \ + "type = const union t_union${ws}\\*" \ + "(union t_union const *)" +gdb_test "whatis (struct t_struct * const) &v_struct1" \ + "type = struct t_struct${ws}\\*${ws}const" \ + "(struct t_struct * const)" +gdb_test "whatis (union t_union * const) &v_union" \ + "type = union t_union${ws}\\*${ws}const" \ + "(union t_union * const)" +gdb_test "whatis (const struct t_struct * const) &v_struct1" \ + "type = const struct t_struct${ws}\\*${ws}const" \ + "(const struct t_struct * const)" +gdb_test "whatis (const union t_union * const) &v_union" \ + "type = const union t_union${ws}\\*${ws}const" \ + "(const union t_union * const)" +gdb_test "whatis (struct t_struct const * const) &v_struct1" \ + "type = const struct t_struct${ws}\\*${ws}const" \ + "(struct t_struct const * const)" +gdb_test "whatis (union t_union const * const) &v_union" \ + "type = const union t_union${ws}\\*${ws}const" \ + "(union t_union const * const)" + +# +# Function pointers TODO +# + diff --git a/gdb/testsuite/gdb.base/ctf-ptype.c b/gdb/testsuite/gdb.base/ctf-ptype.c new file mode 100644 index 00000000000..2d2e881f0f5 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-ptype.c @@ -0,0 +1,305 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2019 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* + * Test file with lots of different types, for testing the + * "ptype" command on CTF data. It's devired from ptype.c. + */ + +/* + * First the basic C types. + */ + +#if !defined (__STDC__) && !defined (_AIX) +#define signed /**/ +#endif + +char v_char; +signed char v_signed_char; +unsigned char v_unsigned_char; + +short v_short; +signed short v_signed_short; +unsigned short v_unsigned_short; + +int v_int; +signed int v_signed_int; +unsigned int v_unsigned_int; + +long v_long; +signed long v_signed_long; +unsigned long v_unsigned_long; + +float v_float; +double v_double; + +/**** arrays *******/ + +char v_char_array[2]; +signed char v_signed_char_array[2]; +unsigned char v_unsigned_char_array[2]; + +short v_short_array[2]; +signed short v_signed_short_array[2]; +unsigned short v_unsigned_short_array[2]; + +int v_int_array[2]; +signed int v_signed_int_array[2]; +unsigned int v_unsigned_int_array[2]; + +long v_long_array[2]; +signed long v_signed_long_array[2]; +unsigned long v_unsigned_long_array[2]; + +float v_float_array[2]; +double v_double_array[2]; + +/* PR 3742 */ +typedef char t_char_array[]; +t_char_array *pv_char_array; + +/**** pointers *******/ + +char *v_char_pointer; +signed char *v_signed_char_pointer; +unsigned char *v_unsigned_char_pointer; + +short *v_short_pointer; +signed short *v_signed_short_pointer; +unsigned short *v_unsigned_short_pointer; + +int *v_int_pointer; +signed int *v_signed_int_pointer; +unsigned int *v_unsigned_int_pointer; + +long *v_long_pointer; +signed long *v_signed_long_pointer; +unsigned long *v_unsigned_long_pointer; + +float *v_float_pointer; +double *v_double_pointer; + +/**** structs *******/ + +struct t_struct { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; + float v_float_member; + double v_double_member; +} v_struct1; + +struct t_struct *v_t_struct_p; + +struct { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; + float v_float_member; + double v_double_member; +} v_struct2; + +/* typedef'd struct without a tag. */ +typedef struct { + double v_double_member; + int v_int_member; +} t_struct3; +/* GCC seems to want a variable of this type, or else it won't put out + a symbol. */ +t_struct3 v_struct3; + +/**** unions *******/ + +union t_union { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; + float v_float_member; + double v_double_member; +} v_union; + +union { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; + float v_float_member; + double v_double_member; +} v_union2; + +/* typedef'd union without a tag. */ +typedef union { + double v_double_member; + int v_int_member; +} t_union3; +/* GCC seems to want a variable of this type, or else it won't put out + a symbol. */ +t_union3 v_union3; + +/**** Some misc more complicated things *******/ + +struct outer_struct { + int outer_int; + struct inner_struct { + int inner_int; + long inner_long; + }inner_struct_instance; + union inner_union { + int inner_union_int; + long inner_union_long; + }inner_union_instance; + long outer_long; +} nested_su; + +struct highest +{ + int a; + struct + { + int b; + struct { int c; } anonymous_level_2; + } anonymous_level_1; +} the_highest; + +/**** Enumerations *******/ + +enum +/* Work around the bug for compilers which don't put out the right stabs. */ +#if __GNUC__ < 2 && !defined (_AIX) +primary1_tag +#endif +{red1, green1, blue1} primary1; + +enum {red, green, blue} primary; +enum colors {yellow, purple, pink} nonprimary; + +enum {chevy, ford} clunker; +enum cars {bmw, porsche} sportscar; + +#undef FALSE +#undef TRUE +typedef enum {FALSE, TRUE} boolean; +boolean v_boolean; +/*note: aCC has bool type predefined with 'false' and 'true'*/ +typedef enum bvals {my_false, my_true} boolean2; +boolean2 v_boolean2; + +enum misordered {two = 2, one = 1, zero = 0, three = 3}; + +/* Seems like we need a variable of this type to get the type to be put + in the executable, at least for AIX xlc. */ +enum misordered v_misordered = three; + +/**** Pointers to functions *******/ + +typedef int (*func_type) (int (*) (int, float), float); +double (*old_fptr) (); +double (*new_fptr) (void); +int (*fptr) (int, float); +int *(*fptr2) (int (*) (int, float), float); +int (*xptr) (int (*) (), int (*) (void), int); +int (*(*ffptr) (char)) (short); +int (*(*(*fffptr) (char)) (short)) (long); + +func_type v_func_type; + +int main () +{ + /* Ensure that malloc is a pointer type; avoid use of "void" and any include files. */ +/* extern char *malloc();*/ + + /* Some of the tests in ptype.exp require invoking malloc, so make + sure it is linked in to this program. */ + v_char_pointer = (char *) malloc (1); + + /* Some linkers (e.g. on AIX) remove unreferenced variables, + so make sure to reference them. */ + primary = blue; + primary1 = blue1; + nonprimary = pink; + sportscar = porsche; + clunker = ford; + v_struct1.v_int_member = 5; + v_struct2.v_int_member = 6; + v_struct3.v_int_member = 7; + + v_char = 0; + v_signed_char = 0; + v_unsigned_char = 0; + + v_short = 0; + v_signed_short = 0; + v_unsigned_short = 0; + + v_int = 0; + v_signed_int = 0; + v_unsigned_int = 0; + + v_long = 0; + v_signed_long = 0; + v_unsigned_long = 0; + + v_float = 0; + v_double = 0; + + v_char_array[0] = 0; + v_signed_char_array[0] = 0; + v_unsigned_char_array[0] = 0; + + v_short_array[0] = 0; + v_signed_short_array[0] = 0; + v_unsigned_short_array[0] = 0; + + v_int_array[0] = 0; + v_signed_int_array[0] = 0; + v_unsigned_int_array[0] = 0; + + v_long_array[0] = 0; + v_signed_long_array[0] = 0; + v_unsigned_long_array[0] = 0; + + v_float_array[0] = 0; + v_double_array[0] = 0; + + v_char_pointer = 0; + v_signed_char_pointer = 0; + v_unsigned_char_pointer = 0; + + v_short_pointer = 0; + v_signed_short_pointer = 0; + v_unsigned_short_pointer = 0; + + v_int_pointer = 0; + v_signed_int_pointer = 0; + v_unsigned_int_pointer = 0; + + v_long_pointer = 0; + v_signed_long_pointer = 0; + v_unsigned_long_pointer = 0; + + v_float_pointer = 0; + v_double_pointer = 0; + + nested_su.outer_int = 0; + v_t_struct_p = 0; + + the_highest.a = 0; + return 0; +} diff --git a/gdb/testsuite/gdb.base/ctf-ptype.exp b/gdb/testsuite/gdb.base/ctf-ptype.exp new file mode 100644 index 00000000000..9f545824224 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-ptype.exp @@ -0,0 +1,288 @@ +# Copyright 2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is a subset of ptype.exp written by Rob Savoye. (rob@cygnus.com) + +# +# test running programs +# +# -gt generates full-fledged CTF. + +standard_testfile .c +set opts "additional_flags=-gt" + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile] [list $opts nowarnings]] } { + return 0 +} + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info] { + return -1 +} + +# Test ptype of unnamed enumeration members before any action causes +# the partial symbol table to be expanded to full symbols. This fails +# with stabs compilers which fail to use a nameless stab (such as +# pre-2.4.5 versions of gcc and most non-gcc compilers). + +gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" { + -re "type = enum primary1_tag \{red1, green1, blue1\}.*$gdb_prompt $" { + # The workaround is in effect. As this is a compiler, not GDB, + # bug, we'll make it a PASS but perhaps it should be an XFAIL. + pass "ptype unnamed enumeration member (worked around)" + } + -re "type = enum \{red1, green1, blue1\}.*$gdb_prompt $" { + pass "ptype unnamed enumeration member" + } +} + +# +# test ptype command with structures +# +# Here and elsewhere, we accept +# "long", "long int", or "int" for long variables (whatis.exp already +# has an XFAIL for "int" (Sun cc bug), so no need to fail it here). +gdb_test "ptype struct t_struct" "type = struct t_struct \{.*\[\r\n\] (unsigned |)char v_char_member;.*\[\r\n\] (short|short int) v_short_member;.*\[\r\n\] int v_int_member;.*\[\r\n\] (long|long int|int) v_long_member;.*\[\r\n\] float v_float_member;.*\[\r\n\] double v_double_member;.*\[\r\n\]\}.*" "ptype structure" + + +# Test the equivalence between '.' and '->' for struct member references. + +if [gdb_test "ptype v_t_struct_p.v_float_member" "type = float"]<0 then { + return -1 +} +if [gdb_test "ptype v_t_struct_p->v_float_member" "type = float"]<0 then { + return -1 +} +if [gdb_test "ptype v_t_struct_p.v_float_member" "type = float"]<0 then { + return -1 +} +if [gdb_test "ptype v_t_struct_p->v_float_member" "type = float"]<0 then { + return -1 +} + +# +# test ptype command with unions +# +gdb_test "ptype union t_union" "type = union t_union \{.*\[\r\n\] (unsigned |)char v_char_member;.*\[\r\n\] (short|short int) v_short_member;.*\[\r\n\] int v_int_member;.*\[\r\n\] (long|long int|int) v_long_member;.*\[\r\n\] float v_float_member;.*\[\r\n\] double v_double_member;.*\[\r\n\]\}.*" "ptype union" + +# +# test ptype command with enums +# + +gdb_test "ptype primary" "type = enum .red, green, blue.*" "ptype unnamed enumeration" + +gdb_test "ptype enum colors" "type = enum colors \{yellow, purple, pink\}.*" "ptype named enumeration" + + +# +# test ptype command with enums as typedef +# +gdb_test "ptype boolean" "type = enum (boolean |)\{FALSE, TRUE\}.*" "ptype unnamed typedef'd enumeration" + +gdb_test "list main" ".*" + +# Same thing with struct and union. +gdb_test "ptype t_struct3" "type = struct (t_struct3 |)\{.* + *double v_double_member;.* + *int v_int_member;.*\}" "printing typedef'd struct" + +gdb_test "ptype t_union3" "type = union (t_union3 |)\{.* + *double v_double_member;.* + *int v_int_member;.*\}" "printing typedef'd union" + +gdb_test "ptype enum bvals" "type = enum bvals \{my_false, my_true\}.*" "ptype named typedef'd enumf'd enum" + +# +# test ptype command with out-of-order enum values +# +gdb_test "ptype enum misordered" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype misordered enumeration" + +# +# test ptype command with a named enum's value +# +gdb_test "ptype three" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype named enumeration member" + +gdb_test "ptype red" "type = enum \{red, green, blue\}.*" "ptype unnamed enumeration member #2" + +# +# test ptype command with arrays +# +gdb_test "ptype v_char_array" "type = char .2..*" "ptype char array" + +gdb_test "ptype v_signed_char_array" "type = (|signed )char .2..*" "ptype signed char array" + +gdb_test "ptype v_unsigned_char_array" "type = unsigned char .2..*" "ptype unsigned char array" + +gdb_test "ptype v_int_array" "type = int .2..*" "ptype int array" + +gdb_test "ptype v_signed_int_array" "type = int .2..*" "ptype signed int array" + +gdb_test "ptype v_unsigned_int_array" "type = unsigned int .2..*" "ptype unsigned int array" + +gdb_test "ptype v_long_array" "type = (long|int|long int) .2..*" "ptype long array" + +gdb_test "ptype v_signed_long_array" "type = (long|int|long int) .2..*" "ptype signed long array" + +gdb_test "ptype v_unsigned_long_array" "type = unsigned long .2..*" "ptype unsigned long array" + +gdb_test "ptype v_float_array" "type = float .2..*" "ptype float array" + +gdb_test "ptype v_double_array" "type = double .2..*" "ptype double array" + +gdb_test "ptype pv_char_array" "type = (|unsigned )char \\(\\*\\)\\\[0?\\\]" + +# +# test ptype command with pointers +# +gdb_test "ptype v_char_pointer" "type = char \*.*" "ptype char pointer" + +gdb_test "ptype v_short_pointer" "type = short \*.*" "ptype short pointer" + +gdb_test "ptype v_long_pointer" "type = long \*.*" "ptype long pointer" + +gdb_test "ptype v_int_pointer" "type = int \*.*" "ptype int pointer" + +gdb_test "ptype v_signed_long_pointer" "type = long \*.*" "ptype signed long pointer" + +gdb_test "ptype v_unsigned_long_pointer" "type = unsigned long \*.*" "ptype unsigned long pointer" + +gdb_test "ptype v_float_pointer" "type = float \*.*" "ptype float pointer" + +gdb_test "ptype v_double_pointer" "type = double \*.*" "ptype double pointer" + +# +# test ptype command with basic C types +# +gdb_test "ptype v_short" "type = short(| int).*" "ptype short" + +gdb_test "ptype v_int" "type = int.*" "ptype int" + +# +# test ptype command with nested structure and union +# +gdb_test "ptype struct outer_struct" "type = struct outer_struct \{.*\[\r\n\]+\ +.*int outer_int;.*\[\r\n\]+\ +.*(struct|) inner_struct inner_struct_instance;.*\[\r\n\]+\ +.*(union|) inner_union inner_union_instance;.*\[\r\n\]+\ +.*(long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype outer structure" + +gdb_test "ptype struct inner_struct" "type = struct inner_struct \{.*\[\r\n\] int inner_int;.*\[\r\n\] (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype inner structure" + +gdb_test "ptype union inner_union" "type = union inner_union \{.*\[\r\n\] int inner_union_int;.*\[\r\n\] (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype inner union" + +gdb_test "ptype nested_su" "type = struct outer_struct \{.*\[\r\n\] int outer_int;.*\[\r\n\] (struct |)inner_struct inner_struct_instance;.*\[\r\n\] (union |)inner_union inner_union_instance;.*\[\r\n\] (long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype nested structure" + +gdb_test "ptype nested_su.outer_int" "type = int.*" "ptype outer int" + +gdb_test "ptype nested_su.inner_struct_instance" "type = struct inner_struct \{.*\[\r\n\] int inner_int;.*\[\r\n\] (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype nested structure #2" + +gdb_test "ptype nested_su.inner_struct_instance.inner_int" "type = int.*" "ptype inner int" + +gdb_test "ptype nested_su.inner_union_instance" "type = union inner_union \{.*\[\r\n\] int inner_union_int;.*\[\r\n\] (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype nested union" + +# Print the type description of variable the_highest, and verify that +# the type description for the fields whose type is anonymous are +# correctly printed (at nesting level 1 and 2). + +gdb_test "ptype the_highest" \ + "type = struct highest \{.*\[\r\n\] *int a;.*\[\r\n\] *struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{\.\.\.\} anonymous_level_2;.*\[\r\n\] *\} anonymous_level_1;.*\[\r\n\]}.*" \ + "ptype the_highest" + +# Print the type descrption for one of the fields of variable the_highest. +# The purpose is to verify that the type of a field that was printed above +# as "struct {...}" is now printed in a more descriptive way (because the +# nesting level is now one level less). + +gdb_test "ptype the_highest.anonymous_level_1" \ + "type = struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{.*\[\r\n\] *int c;.*\[\r\n\] *\} anonymous_level_2;.*\[\r\n\]}.*" \ + "ptype the_highest" + +# Print the type of the identifier ID, and check the response: +# - Expect to see PROTOTYPED as the type. PROTOTYPED is not a regular +# expression; it's a literal string. +# - If we instead see the unprototyped type PLAIN, and we're using STABS +# generated by GCC, that's an xfail; as of 9 Feb 2002, GCC never emits +# prototyped function types in STABS. Like PROTOTYPED, PLAIN is a +# literal string, not a regular expression. +# - If we see OVERPROTOTYPED, it's an xfail for RealView; RealView +# does not distinguish prototyped and unprototyped functions, and +# GDB defaults to prototyped. +# - Otherwise, it's a failure. +proc ptype_maybe_prototyped { id prototyped plain { overprototyped "NO-MATCH" } } { + global gdb_prompt + global gcc_compiled + + # Turn the arguments, which are literal strings, into + # regular expressions by quoting any special characters they contain. + foreach var { prototyped plain overprototyped } { + eval "set val \$$var" + regsub -all "\[\]\[*()\]" $val "\\\\&" val + regsub -all "short int" $val "short( int)?" val + regsub -all "long int" $val "long( int)?" val + eval "set $var \$val" + } + + gdb_test_multiple "ptype $id" "ptype $id" { + -re "type = $prototyped\[\r\n\]+$gdb_prompt $" { + pass "ptype $id" + } + -re "type = $plain\[\r\n\]+$gdb_prompt $" { + if {$gcc_compiled} { setup_xfail_format "stabs" } + fail "ptype $id (compiler doesn't emit prototyped types)" + } + -re "type = $overprototyped\[\r\n\]+$gdb_prompt $" { + if { [test_compiler_info "armcc-*"] } { + setup_xfail "*-*-*" + } + fail "ptype $id (compiler doesn't emit unprototyped types)" + } + } +} + +ptype_maybe_prototyped "old_fptr" "double (*)()" "double (*)()" \ + "double (*)(void)" + +# Test printing type of string constants and array constants, but +# requires a running process. These call malloc, and can take a long +# time to execute over a slow serial link, so increase the timeout. + +if [runto_main] then { + + if [target_info exists gdb,cannot_call_functions] { + unsupported "this target can not call functions" + continue + } + + # We need to up this because this can be really slow on some boards. + # (malloc() is called as part of the test). + set prev_timeout $timeout + set timeout 60 + + gdb_test "ptype \"abc\"" "type = char \\\[4\\\]" + gdb_test "ptype {'a','b','c'}" "type = char \\\[3\\\]" + gdb_test "ptype {0,1,2}" "type = int \\\[3\\\]" + gdb_test "ptype {(long)0,(long)1,(long)2}" "type = long \\\[3\\\]" + gdb_test "ptype {(float)0,(float)1,(float)2}" "type = float \\\[3\\\]" + gdb_test "ptype {{0,1,2},{3,4,5}}" "type = int \\\[2\\\]\\\[3\\\]" + gdb_test "ptype {4,5,6}\[2\]" "type = int" + gdb_test "ptype *&{4,5,6}\[1\]" "Attempt to take address of value not located in memory." + + set timeout $prev_timeout + + # Test ptype of user register + gdb_test "ptype \$pc" "void \\(\\*\\)\\(\\)" "ptype \$pc" +} diff --git a/gdb/testsuite/gdb.base/ctf-whatis.c b/gdb/testsuite/gdb.base/ctf-whatis.c new file mode 100644 index 00000000000..548dcbb7afd --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-whatis.c @@ -0,0 +1,282 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2019 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* + * Test file with lots of different types, for testing the + * "whatis" command on CTF data. It's derived from whatis.c. + */ + +/* + * First the basic C types. + */ + +char v_char; +signed char v_signed_char; +unsigned char v_unsigned_char; + +short v_short; +signed short v_signed_short; +unsigned short v_unsigned_short; + +int v_int; +signed int v_signed_int; +unsigned int v_unsigned_int; + +long v_long; +signed long v_signed_long; +unsigned long v_unsigned_long; + +#ifndef NO_LONG_LONG +long long v_long_long; +signed long long v_signed_long_long; +unsigned long long v_unsigned_long_long; +#endif + +float v_float; +double v_double; + +/* + * Now some derived types, which are arrays, functions-returning, + * pointers, structures, unions, and enumerations. + */ + +/**** arrays *******/ + +char v_char_array[2]; +signed char v_signed_char_array[2]; +unsigned char v_unsigned_char_array[2]; + +short v_short_array[2]; +signed short v_signed_short_array[2]; +unsigned short v_unsigned_short_array[2]; + +int v_int_array[2]; +signed int v_signed_int_array[2]; +unsigned int v_unsigned_int_array[2]; + +long v_long_array[2]; +signed long v_signed_long_array[2]; +unsigned long v_unsigned_long_array[2]; + +#ifndef NO_LONG_LONG +long long v_long_long_array[2]; +signed long long v_signed_long_long_array[2]; +unsigned long long v_unsigned_long_long_array[2]; +#endif + +float v_float_array[2]; +double v_double_array[2]; + +/**** pointers *******/ + +/* Make sure they still print as pointer to foo even there is a typedef + for that type. Test this not just for char *, which might be + a special case kludge in GDB (Unix system include files like to define + caddr_t), but for a variety of types. */ +typedef char *char_addr; +char_addr a_char_addr; +typedef unsigned short *ushort_addr; +ushort_addr a_ushort_addr; +typedef signed long *slong_addr; +slong_addr a_slong_addr; +#ifndef NO_LONG_LONG +typedef signed long long *slong_long_addr; +slong_long_addr a_slong_long_addr; +#endif + +char *v_char_pointer; +signed char *v_signed_char_pointer; +unsigned char *v_unsigned_char_pointer; + +short *v_short_pointer; +signed short *v_signed_short_pointer; +unsigned short *v_unsigned_short_pointer; + +int *v_int_pointer; +signed int *v_signed_int_pointer; +unsigned int *v_unsigned_int_pointer; + +long *v_long_pointer; +signed long *v_signed_long_pointer; +unsigned long *v_unsigned_long_pointer; + +#ifndef NO_LONG_LONG +long long *v_long_long_pointer; +signed long long *v_signed_long_long_pointer; +unsigned long long *v_unsigned_long_long_pointer; +#endif + +float *v_float_pointer; +double *v_double_pointer; + +/**** structs *******/ + +struct t_struct { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; +#ifndef NO_LONG_LONG + long long v_long_long_member; +#endif + float v_float_member; + double v_double_member; +} v_struct1, *v_struct_ptr1; + +struct { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; +#ifndef NO_LONG_LONG + long long v_long_long_member; +#endif + float v_float_member; + double v_double_member; +} v_struct2, *v_struct_ptr2; + +/**** unions *******/ + +union t_union { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; +#ifndef NO_LONG_LONG + long long v_long_long_member; +#endif + float v_float_member; + double v_double_member; +} v_union, *v_union_ptr; + +union { + char v_char_member; + short v_short_member; + int v_int_member; + long v_long_member; +#ifndef NO_LONG_LONG + long long v_long_long_member; +#endif + float v_float_member; + double v_double_member; +} v_union2, *v_union_ptr2; + +/**** Some misc more complicated things *******/ + +struct outer_struct { + int outer_int; + struct inner_struct { + int inner_int; + long inner_long; + }inner_struct_instance; + union inner_union { + int inner_union_int; + long inner_union_long; + }inner_union_instance; + long outer_long; +} nested_su; + +/***********/ + +int main () +{ + /* Some linkers (e.g. on AIX) remove unreferenced variables, + so make sure to reference them. */ + v_char = 0; + v_signed_char = 1; + v_unsigned_char = 2; + + v_short = 3; + v_signed_short = 4; + v_unsigned_short = 5; + + v_int = 6; + v_signed_int = 7; + v_unsigned_int = 8; + + v_long = 9; + v_signed_long = 10; + v_unsigned_long = 11; + +#ifndef NO_LONG_LONG + v_long_long = 12; + v_signed_long_long = 13; + v_unsigned_long_long = 14; +#endif + + v_float = 100.0; + v_double = 200.0; + + + v_char_array[0] = v_char; + v_signed_char_array[0] = v_signed_char; + v_unsigned_char_array[0] = v_unsigned_char; + + v_short_array[0] = v_short; + v_signed_short_array[0] = v_signed_short; + v_unsigned_short_array[0] = v_unsigned_short; + + v_int_array[0] = v_int; + v_signed_int_array[0] = v_signed_int; + v_unsigned_int_array[0] = v_unsigned_int; + + v_long_array[0] = v_long; + v_signed_long_array[0] = v_signed_long; + v_unsigned_long_array[0] = v_unsigned_long; + +#ifndef NO_LONG_LONG + v_long_long_array[0] = v_long_long; + v_signed_long_long_array[0] = v_signed_long_long; + v_unsigned_long_long_array[0] = v_unsigned_long_long; +#endif + + v_float_array[0] = v_float; + v_double_array[0] = v_double; + + v_char_pointer = &v_char; + v_signed_char_pointer = &v_signed_char; + v_unsigned_char_pointer = &v_unsigned_char; + + v_short_pointer = &v_short; + v_signed_short_pointer = &v_signed_short; + v_unsigned_short_pointer = &v_unsigned_short; + + v_int_pointer = &v_int; + v_signed_int_pointer = &v_signed_int; + v_unsigned_int_pointer = &v_unsigned_int; + + v_long_pointer = &v_long; + v_signed_long_pointer = &v_signed_long; + v_unsigned_long_pointer = &v_unsigned_long; + +#ifndef NO_LONG_LONG + v_long_long_pointer = &v_long_long; + v_signed_long_long_pointer = &v_signed_long_long; + v_unsigned_long_long_pointer = &v_unsigned_long_long; +#endif + + v_float_pointer = &v_float; + v_double_pointer = &v_double; + + v_union2.v_short_member = v_union.v_short_member; + + v_struct1.v_char_member = 0; + v_struct2.v_char_member = 0; + + nested_su.outer_int = 0; + return 0; +} diff --git a/gdb/testsuite/gdb.base/ctf-whatis.exp b/gdb/testsuite/gdb.base/ctf-whatis.exp new file mode 100644 index 00000000000..3f26fc326e3 --- /dev/null +++ b/gdb/testsuite/gdb.base/ctf-whatis.exp @@ -0,0 +1,413 @@ +# Copyright 2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# This file is a subset of whatis.exp written by Rob Savoye. (rob@cygnus.com) + +# +# test running programs +# +# -gt generates full-fledged CTF. + +standard_testfile .c +set opts "additional_flags=-gt" + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile] [list $opts nowarnings]] } { + return 0 +} + +# Create and source the file that provides information about the compiler +# used to compile the test case. +if [get_compiler_info] { + return -1 +} + +# Start with a fresh gdb. + +clean_restart $binfile + +# Define a procedure to set up an xfail for all targets that put out a +# `long' type as an `int' type. +# Sun cc has this problem. +# It was said that COFF targets can not distinguish int from long either. + +proc setup_xfail_on_long_vs_int {} { + global gcc_compiled + + if {!$gcc_compiled} { + setup_xfail "*-sun-sunos4*" "i*86-sequent-bsd*" + } +} + +# +# Test whatis command with basic C types +# +# The name printed now (as of 23 May 1993) is whatever name the compiler +# uses in the stabs. So we need to deal with names both from gcc and +# native compilers. +# + +gdb_test "whatis v_char" \ + "type = (unsigned char|char)" \ + "whatis char" + +gdb_test "whatis v_signed_char" \ + "type = (signed char|char)" \ + "whatis signed char" + +gdb_test "whatis v_unsigned_char" \ + "type = unsigned char" \ + "whatis unsigned char" + +gdb_test "whatis v_short" \ + "type = (short|short int)" \ + "whatis short" + +gdb_test "whatis v_signed_short" \ + "type = (short|short int|signed short|signed short int)" \ + "whatis signed short" + +gdb_test "whatis v_unsigned_short" \ + "type = (unsigned short|short unsigned int)" \ + "whatis unsigned short" + +gdb_test "whatis v_int" \ + "type = int" \ + "whatis int" + +gdb_test "whatis v_signed_int" \ + "type = (signed |)int" \ + "whatis signed int" + +gdb_test "whatis v_unsigned_int" \ + "type = unsigned int" \ + "whatis unsigned int" + +setup_xfail_on_long_vs_int +# AIX xlc gets this wrong and unsigned long right. Go figure. +if {!$gcc_compiled} then {setup_xfail "rs6000-*-aix*"} +gdb_test "whatis v_long" \ + "type = (long|long int)" \ + "whatis long" + +setup_xfail_on_long_vs_int +# AIX xlc gets this wrong and unsigned long right. Go figure. +if {!$gcc_compiled} then {setup_xfail "rs6000-*-aix*"} +gdb_test "whatis v_signed_long" \ + "type = (signed |)(long|long int)" \ + "whatis signed long" + +setup_xfail_on_long_vs_int +gdb_test "whatis v_unsigned_long" \ + "type = (unsigned long|long unsigned int)" \ + "whatis unsigned long" + + +if ![target_info exists no_long_long] { + gdb_test "whatis v_unsigned_long_long" \ + "type = (unsigned long long|long long unsigned int)" \ + "whatis unsigned long long" +} + +gdb_test "whatis v_float" \ + "type = float" \ + "whatis float" + +gdb_test "whatis v_double" \ + "type = double" \ + "whatis double" + + +# test whatis command with arrays +# +# We already tested whether char prints as "char", so here we accept +# "unsigned char", "signed char", and other perversions. No need for more +# than one xfail for the same thing. +gdb_test "whatis v_char_array" \ + "type = (signed |unsigned |)char \\\[2\\\]" \ + "whatis char array" + +gdb_test "whatis v_signed_char_array" \ + "type = (signed |unsigned |)char \\\[2\\\]" \ + "whatis signed char array" + +gdb_test "whatis v_unsigned_char_array" \ + "type = unsigned char \\\[2\\\]" \ + "whatis unsigned char array" + +gdb_test "whatis v_short_array" \ + "type = (short|short int) \\\[2\\\]" \ + "whatis short array" + +gdb_test "whatis v_signed_short_array" \ + "type = (signed |)(short|short int) \\\[2\\\]" \ + "whatis signed short array" + +gdb_test "whatis v_unsigned_short_array" \ + "type = (unsigned short|short unsigned int) \\\[2\\\]" \ + "whatis unsigned short array" + +gdb_test "whatis v_int_array" \ + "type = int \\\[2\\\]" \ + "whatis int array" + +gdb_test "whatis v_signed_int_array" \ + "type = (signed |)int \\\[2\\\]" \ + "whatis signed int array" + +gdb_test "whatis v_unsigned_int_array" \ + "type = unsigned int \\\[2\\\]" \ + "whatis unsigned int array" + +# We already tested whether long prints as long, so here we accept int +# No need for more than one xfail for the same thing. +gdb_test "whatis v_long_array" \ + "type = (int|long|long int) \\\[2\\\]" \ + "whatis long array" + +gdb_test "whatis v_signed_long_array" \ + "type = (signed |)(int|long|long int) \\\[2\\\]" \ + "whatis signed long array" + +gdb_test "whatis v_unsigned_long_array" \ + "type = (unsigned (int|long|long int)|long unsigned int) \\\[2\\\]" \ + "whatis unsigned long array" + +if ![target_info exists no_long_long] { + gdb_test "whatis v_unsigned_long_long_array" \ + "type = (unsigned long long|long long unsigned int) \\\[2\\\]" \ + "whatis unsigned long array" +} + +gdb_test "whatis v_float_array" \ + "type = float \\\[2\\\]" \ + "whatis float array" + +gdb_test "whatis v_double_array" \ + "type = double \\\[2\\\]" \ + "whatis double array" + + +# test whatis command with pointers +# +# We already tested whether char prints as char, so accept various perversions +# here. We especially want to make sure we test that it doesn't print as +# caddr_t. +gdb_test "whatis v_char_pointer" \ + "type = (unsigned |signed |)char \\*" \ + "whatis char pointer" + +gdb_test "whatis v_signed_char_pointer" \ + "type = (unsigned |signed |)char \\*" \ + "whatis signed char pointer" + +gdb_test "whatis v_unsigned_char_pointer" \ + "type = unsigned char \\*" \ + "whatis unsigned char pointer" + +gdb_test "whatis v_short_pointer" \ + "type = (short|short int) \\*" \ + "whatis short pointer" + +gdb_test "whatis v_signed_short_pointer" \ + "type = (signed |)(short|short int) \\*" \ + "whatis signed short pointer" + +gdb_test "whatis v_unsigned_short_pointer" \ + "type = (unsigned short|short unsigned int) \\*" \ + "whatis unsigned short pointer" + +gdb_test "whatis v_int_pointer" \ + "type = int \\*" \ + "whatis int pointer" + +gdb_test "whatis v_signed_int_pointer" \ + "type = (signed |)int \\*" \ + "whatis signed int pointer" + +gdb_test "whatis v_unsigned_int_pointer" \ + "type = unsigned int \\*" \ + "whatis unsigned int pointer" + +# We already tested whether long prints as long, so here we accept int +gdb_test "whatis v_long_pointer" \ + "type = (long|int|long int) \\*" \ + "whatis long pointer" + +gdb_test "whatis v_signed_long_pointer" \ + "type = (signed |)(long|int|long int) \\*" \ + "whatis signed long pointer" + +gdb_test "whatis v_unsigned_long_pointer" \ + "type = (unsigned (int|long|long int)|long unsigned int) \\*" \ + "whatis unsigned long pointer" + +if ![target_info exists no_long_long] { + gdb_test "whatis v_long_long_pointer" \ + "type = long long(| int) \\*" \ + "whatis long long pointer" + + gdb_test "whatis v_signed_long_long_pointer" \ + "type = (signed |)long long(| int) \\*" \ + "whatis signed long long pointer" + + gdb_test "whatis v_unsigned_long_long_pointer" \ + "type = (unsigned long long|long long unsigned int) \\*" \ + "whatis unsigned long long pointer" +} + +gdb_test "whatis v_float_pointer" \ + "type = float \\*" \ + "whatis float pointer" + +gdb_test "whatis v_double_pointer" \ + "type = double \\*" \ + "whatis double pointer" + + +# test whatis command with structure types + +# First with a type argument, with both "set print object" set to "on" +# and "off", ending with "off" for the following tests. +foreach_with_prefix print_object {"on" "off"} { + gdb_test_no_output "set print object $print_object" + + gdb_test "whatis struct t_struct" \ + "type = struct t_struct" \ + "whatis named structure using type name" + + gdb_test "whatis struct t_struct *" \ + "type = struct t_struct \\*" \ + "whatis named structure using type name and pointer" + + gdb_test "whatis struct t_struct &" \ + "type = struct t_struct &" \ + "whatis named structure using type name and reference" +} + +# Now with an expression argument. + +gdb_test "whatis v_struct_ptr1" \ + "type = struct t_struct \\*" + +gdb_test "whatis &v_struct_ptr1" \ + "type = struct t_struct \\*\\*" + +gdb_test "whatis v_struct_ptr1->v_char_member" \ + "type = char" + +gdb_test "whatis v_struct_ptr2->v_char_member" \ + "type = char" + +gdb_test "whatis &(v_struct_ptr1->v_char_member)" \ + "type = char \\*" + +gdb_test "whatis &(v_struct_ptr2->v_char_member)" \ + "type = char \\*" + +# test whatis command with union types + +gdb_test "whatis union t_union" \ + "type = union t_union" \ + "whatis named union using type name" + +gdb_test "whatis v_union_ptr" \ + "type = union t_union \\*" + +gdb_test "whatis &v_union_ptr" \ + "type = union t_union \\*\\*" + +gdb_test "whatis v_union_ptr->v_char_member" \ + "type = char" + +gdb_test "whatis v_union_ptr2->v_char_member" \ + "type = char" + +gdb_test "whatis &(v_union_ptr->v_char_member)" \ + "type = char \\*" + +gdb_test "whatis &(v_union_ptr2->v_char_member)" \ + "type = char \\*" + +# test whatis command with nested struct and union +gdb_test "whatis nested_su" \ + "type = struct outer_struct" \ + "whatis outer structure" + +gdb_test "whatis nested_su.outer_int" \ + "type = int" \ + "whatis outer structure member" + +gdb_test "whatis nested_su.inner_struct_instance" \ + "type = struct inner_struct" \ + "whatis inner structure" + +gdb_test "whatis nested_su.inner_struct_instance.inner_int" \ + "type = int" \ + "whatis inner structure member" + +gdb_test "whatis nested_su.inner_union_instance" \ + "type = union inner_union" \ + "whatis inner union" + +gdb_test "whatis nested_su.inner_union_instance.inner_union_int" \ + "type = int" \ + "whatis inner union member" + +# Using stabs we will mark these functions as prototyped. This +# is harmless but causes an extra VOID to be printed. +set void "(void|)" + +# Regression tests for PR 9514. + +gdb_test "whatis void (**)()" \ + "type = void \\(\\*\\*\\)\\(\\)" \ + "whatis applied to pointer to pointer to function" + +gdb_test "whatis void (** const)()" \ + "type = void \\(\\*\\* const\\)\\(\\)" \ + "whatis applied to const pointer to pointer to function" + +gdb_test "whatis void (* const *)()" \ + "type = void \\(\\* const \\*\\)\\(\\)" \ + "whatis applied to pointer to const pointer to function" + +gdb_test "whatis int *(*)()" \ + "type = int \\*\\(\\*\\)\\(\\)" \ + "whatis applied to pointer to function returning pointer to int" + +gdb_test "whatis int *(**)()" \ + "type = int \\*\\(\\*\\*\\)\\(\\)" \ + "whatis applied to pointer to pointer to function returning pointer to int" + +gdb_test "whatis char (*(*)())\[23\]" \ + "type = char \\(\\*\\(\\*\\)\\(\\)\\)\\\[23\\\]" \ + "whatis applied to pointer to function returning pointer to array" + +gdb_test "whatis int (*)(int, int)" \ + "type = int \\(\\*\\)\\(int, int\\)" \ + "whatis applied to pointer to function taking int,int and returning int" + +gdb_test "whatis int (*)(const int *, ...)" \ + "type = int \\(\\*\\)\\(const int \\*, \\.\\.\\.\\)" \ + "whatis applied to pointer to function taking const int ptr and varargs and returning int" + +gdb_test "whatis int (*)(void, int, int)" \ + "parameter types following 'void'" \ + "whatis applied to function with types trailing 'void'" + +gdb_test "whatis int (*)(int, void, int)" \ + "'void' invalid as parameter type" \ + "whatis applied to function with 'void' parameter type" -- 2.30.2