|  | /* Compact ANSI-C Type Format (CTF) support in GDB. | 
|  |  | 
|  | Copyright (C) 2019-2022 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 <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | /* 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 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" | 
|  |  | 
|  | #if ENABLE_LIBCTF | 
|  |  | 
|  | #include "ctf.h" | 
|  | #include "ctf-api.h" | 
|  |  | 
|  | static const struct objfile_key<htab, htab_deleter> ctf_tid_key; | 
|  |  | 
|  | struct ctf_fp_info | 
|  | { | 
|  | explicit ctf_fp_info (ctf_dict_t *cfp) : fp (cfp) {} | 
|  | ~ctf_fp_info (); | 
|  | ctf_dict_t *fp; | 
|  | }; | 
|  |  | 
|  | /* Cleanup function for the ctf_dict_key data.  */ | 
|  | ctf_fp_info::~ctf_fp_info () | 
|  | { | 
|  | if (fp == nullptr) | 
|  | return; | 
|  |  | 
|  | ctf_archive_t *arc = ctf_get_arc (fp); | 
|  | ctf_dict_close (fp); | 
|  | ctf_close (arc); | 
|  | } | 
|  |  | 
|  | static const objfile_key<ctf_fp_info> ctf_dict_key; | 
|  |  | 
|  | /* A CTF context consists of a file pointer and an objfile pointer.  */ | 
|  |  | 
|  | struct ctf_context | 
|  | { | 
|  | ctf_dict_t *fp; | 
|  | struct objfile *of; | 
|  | psymtab_storage *partial_symtabs; | 
|  | partial_symtab *pst; | 
|  | ctf_archive_t *arc; | 
|  | struct buildsym_compunit *builder; | 
|  | }; | 
|  |  | 
|  | /* A partial symtab, specialized for this module.  */ | 
|  | struct ctf_psymtab : public standard_psymtab | 
|  | { | 
|  | ctf_psymtab (const char *filename, | 
|  | psymtab_storage *partial_symtabs, | 
|  | objfile_per_bfd_storage *objfile_per_bfd, | 
|  | CORE_ADDR addr) | 
|  | : standard_psymtab (filename, partial_symtabs, objfile_per_bfd, addr) | 
|  | { | 
|  | } | 
|  |  | 
|  | void read_symtab (struct objfile *) override; | 
|  | void expand_psymtab (struct objfile *) override; | 
|  |  | 
|  | struct ctf_context context; | 
|  | }; | 
|  |  | 
|  | /* 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 | 
|  | ctf_field_info structure. It is derived from dwarf2read.c.  */ | 
|  |  | 
|  | struct ctf_nextfield | 
|  | { | 
|  | struct field field {}; | 
|  | }; | 
|  |  | 
|  | struct ctf_field_info | 
|  | { | 
|  | /* List of data member fields.  */ | 
|  | std::vector<struct ctf_nextfield> fields; | 
|  |  | 
|  | /* Context.  */ | 
|  | struct ctf_context *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<struct decl_field> typedef_field_list; | 
|  |  | 
|  | /* Nested types defined by this struct and the number of elements in | 
|  | this list.  */ | 
|  | std::vector<struct decl_field> nested_types_list; | 
|  | }; | 
|  |  | 
|  | /* Data held for a translation unit.  */ | 
|  |  | 
|  | struct ctf_per_tu_data | 
|  | { | 
|  | ctf_dict_t *fp; | 
|  | struct objfile *of; | 
|  | ctf_archive_t *arc; | 
|  | psymtab_storage *pss; | 
|  | psymbol_functions *psf; | 
|  | }; | 
|  |  | 
|  | /* Local function prototypes */ | 
|  |  | 
|  | static int ctf_add_type_cb (ctf_id_t tid, void *arg); | 
|  |  | 
|  | static struct type *read_array_type (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static struct type *read_pointer_type (struct ctf_context *cp, ctf_id_t tid, | 
|  | ctf_id_t btid); | 
|  |  | 
|  | static struct type *read_structure_type (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static struct type *read_enum_type (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static struct type *read_typedef_type (struct ctf_context *cp, ctf_id_t tid, | 
|  | ctf_id_t btid, const char *name); | 
|  |  | 
|  | static struct type *read_type_record (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static void process_structure_type (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static void process_struct_members (struct ctf_context *cp, ctf_id_t tid, | 
|  | struct type *type); | 
|  |  | 
|  | static struct type *read_forward_type (struct ctf_context *cp, ctf_id_t tid); | 
|  |  | 
|  | static struct symbol *new_symbol (struct ctf_context *cp, 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 == nullptr) | 
|  | *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 nullptr; | 
|  |  | 
|  | ids.tid = tid; | 
|  | ids.type = nullptr; | 
|  | slot = (struct ctf_tid_and_type *) htab_find (htab, &ids); | 
|  | if (slot) | 
|  | return slot->type; | 
|  | else | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | /* Fetch the type for TID in CCP OF's tid_and_type hash, add the type to | 
|  | *    context CCP if hash is empty or TID does not have a saved type.  */ | 
|  |  | 
|  | static struct type * | 
|  | fetch_tid_type (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | struct type *typ; | 
|  |  | 
|  | typ = get_tid_type (of, tid); | 
|  | if (typ == nullptr) | 
|  | { | 
|  | ctf_add_type_cb (tid, ccp); | 
|  | typ = get_tid_type (of, tid); | 
|  | } | 
|  |  | 
|  | return typ; | 
|  | } | 
|  |  | 
|  | /* Return the size of storage in bits for INTEGER, FLOAT, or ENUM.  */ | 
|  |  | 
|  | static int | 
|  | get_bitsize (ctf_dict_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, nullptr, of); | 
|  | if (msym.minsym != NULL) | 
|  | { | 
|  | SET_SYMBOL_VALUE_ADDRESS (sym, BMSYMBOL_VALUE_ADDRESS (msym)); | 
|  | sym->set_aclass_index (LOC_STATIC); | 
|  | sym->set_section_index (msym.minsym->section_index ()); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Create the vector of fields, and attach it to TYPE.  */ | 
|  |  | 
|  | static void | 
|  | attach_fields_to_type (struct ctf_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->set_num_fields (nfields); | 
|  | type->set_fields | 
|  | ((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 ctf_nextfield &field = fip->fields[i]; | 
|  | type->field (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 = objfile->arch (); | 
|  | const struct floatformat **format; | 
|  | struct type *type; | 
|  |  | 
|  | format = gdbarch_floatformat_for_type (gdbarch, name_hint, bits); | 
|  | if (format != nullptr) | 
|  | 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 ctf_field_info.  */ | 
|  |  | 
|  | static int | 
|  | ctf_add_member_cb (const char *name, | 
|  | ctf_id_t tid, | 
|  | unsigned long offset, | 
|  | void *arg) | 
|  | { | 
|  | struct ctf_field_info *fip = (struct ctf_field_info *) arg; | 
|  | struct ctf_context *ccp = fip->cur_context; | 
|  | struct ctf_nextfield new_field; | 
|  | struct field *fp; | 
|  | struct type *t; | 
|  | uint32_t kind; | 
|  |  | 
|  | fp = &new_field.field; | 
|  | fp->set_name (name); | 
|  |  | 
|  | kind = ctf_type_kind (ccp->fp, tid); | 
|  | t = fetch_tid_type (ccp, tid); | 
|  | if (t == nullptr) | 
|  | { | 
|  | t = read_type_record (ccp, tid); | 
|  | if (t == nullptr) | 
|  | { | 
|  | 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); | 
|  |  | 
|  | fp->set_type (t); | 
|  | fp->set_loc_bitpos (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 ctf_field_info.  */ | 
|  |  | 
|  | static int | 
|  | ctf_add_enum_member_cb (const char *name, int enum_value, void *arg) | 
|  | { | 
|  | struct ctf_field_info *fip = (struct ctf_field_info *) arg; | 
|  | struct ctf_nextfield new_field; | 
|  | struct field *fp; | 
|  | struct ctf_context *ccp = fip->cur_context; | 
|  |  | 
|  | fp = &new_field.field; | 
|  | fp->set_name (name); | 
|  | fp->set_type (nullptr); | 
|  | fp->set_loc_enumval (enum_value); | 
|  | FIELD_BITSIZE (*fp) = 0; | 
|  |  | 
|  | if (name != nullptr) | 
|  | { | 
|  | struct symbol *sym = new (&ccp->of->objfile_obstack) symbol; | 
|  | OBJSTAT (ccp->of, n_syms++); | 
|  |  | 
|  | sym->set_language (language_c, &ccp->of->objfile_obstack); | 
|  | sym->compute_and_set_names (name, false, ccp->of->per_bfd); | 
|  | sym->set_aclass_index (LOC_CONST); | 
|  | sym->set_domain (VAR_DOMAIN); | 
|  | sym->set_type (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 (struct ctf_context *ccp, struct type *type, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *objfile = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct symbol *sym = nullptr; | 
|  |  | 
|  | const char *name = ctf_type_name_raw (fp, tid); | 
|  | if (name != nullptr) | 
|  | { | 
|  | sym = new (&objfile->objfile_obstack) symbol; | 
|  | OBJSTAT (objfile, n_syms++); | 
|  |  | 
|  | sym->set_language (language_c, &objfile->objfile_obstack); | 
|  | sym->compute_and_set_names (name, false, objfile->per_bfd); | 
|  | sym->set_domain (VAR_DOMAIN); | 
|  | sym->set_aclass_index (LOC_OPTIMIZED_OUT); | 
|  |  | 
|  | if (type != nullptr) | 
|  | sym->set_type (type); | 
|  |  | 
|  | uint32_t kind = ctf_type_kind (fp, tid); | 
|  | switch (kind) | 
|  | { | 
|  | case CTF_K_STRUCT: | 
|  | case CTF_K_UNION: | 
|  | case CTF_K_ENUM: | 
|  | sym->set_aclass_index (LOC_TYPEDEF); | 
|  | sym->set_domain (STRUCT_DOMAIN); | 
|  | break; | 
|  | case CTF_K_FUNCTION: | 
|  | sym->set_aclass_index (LOC_STATIC); | 
|  | set_symbol_address (objfile, sym, sym->linkage_name ()); | 
|  | break; | 
|  | case CTF_K_CONST: | 
|  | if (sym->type ()->code () == TYPE_CODE_VOID) | 
|  | sym->set_type (objfile_type (objfile)->builtin_int); | 
|  | break; | 
|  | case CTF_K_TYPEDEF: | 
|  | case CTF_K_INTEGER: | 
|  | case CTF_K_FLOAT: | 
|  | sym->set_aclass_index (LOC_TYPEDEF); | 
|  | sym->set_domain (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_file_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 (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | ctf_encoding_t cet; | 
|  | struct type *type = nullptr; | 
|  | const 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 nullptr; | 
|  | } | 
|  |  | 
|  | name = ctf_type_name_raw (fp, tid); | 
|  | if (name == nullptr || strlen (name) == 0) | 
|  | { | 
|  | name = ctf_type_aname (fp, tid); | 
|  | if (name == nullptr) | 
|  | complaint (_("ctf_type_aname read_base_type failed - %s"), | 
|  | ctf_errmsg (ctf_errno (fp))); | 
|  | } | 
|  |  | 
|  | kind = ctf_type_kind (fp, tid); | 
|  | if (kind == CTF_K_INTEGER) | 
|  | { | 
|  | uint32_t issigned, ischar, isbool; | 
|  | struct gdbarch *gdbarch = of->arch (); | 
|  |  | 
|  | 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 (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 != nullptr && strcmp (name, "char") == 0) | 
|  | type->set_has_no_signedness (true); | 
|  |  | 
|  | return set_tid_type (of, tid, type); | 
|  | } | 
|  |  | 
|  | static void | 
|  | process_base_type (struct ctf_context *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 (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct type *type; | 
|  | uint32_t kind; | 
|  |  | 
|  | type = alloc_type (of); | 
|  |  | 
|  | const char *name = ctf_type_name_raw (fp, tid); | 
|  | if (name != nullptr && strlen (name) != 0) | 
|  | type->set_name (name); | 
|  |  | 
|  | kind = ctf_type_kind (fp, tid); | 
|  | if (kind == CTF_K_UNION) | 
|  | type->set_code (TYPE_CODE_UNION); | 
|  | else | 
|  | type->set_code (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 (struct ctf_context *ccp, | 
|  | ctf_id_t tid, | 
|  | struct type *type) | 
|  | { | 
|  | struct ctf_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 (struct ctf_context *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 (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct type *type, *rettype, *atype; | 
|  | ctf_funcinfo_t cfi; | 
|  | uint32_t argc; | 
|  |  | 
|  | type = alloc_type (of); | 
|  |  | 
|  | type->set_code (TYPE_CODE_FUNC); | 
|  | if (ctf_func_type_info (fp, tid, &cfi) < 0) | 
|  | { | 
|  | const char *fname = ctf_type_name_raw (fp, tid); | 
|  | error (_("Error getting function type info: %s"), | 
|  | fname == nullptr ? "noname" : fname); | 
|  | } | 
|  | rettype = fetch_tid_type (ccp, cfi.ctc_return); | 
|  | TYPE_TARGET_TYPE (type) = rettype; | 
|  | set_type_align (type, ctf_type_align (fp, tid)); | 
|  |  | 
|  | /* Set up function's arguments.  */ | 
|  | argc = cfi.ctc_argc; | 
|  | type->set_num_fields (argc); | 
|  | if ((cfi.ctc_flags & CTF_FUNC_VARARG) != 0) | 
|  | type->set_has_varargs (true); | 
|  |  | 
|  | if (argc != 0) | 
|  | { | 
|  | std::vector<ctf_id_t> argv (argc); | 
|  | if (ctf_func_type_args (fp, tid, argc, argv.data ()) == CTF_ERR) | 
|  | return nullptr; | 
|  |  | 
|  | type->set_fields | 
|  | ((struct field *) TYPE_ZALLOC (type, argc * sizeof (struct field))); | 
|  | struct type *void_type = objfile_type (of)->builtin_void; | 
|  | /* If failed to find the argument type, fill it with void_type.  */ | 
|  | for (int iparam = 0; iparam < argc; iparam++) | 
|  | { | 
|  | atype = fetch_tid_type (ccp, argv[iparam]); | 
|  | if (atype != nullptr) | 
|  | type->field (iparam).set_type (atype); | 
|  | else | 
|  | type->field (iparam).set_type (void_type); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct type *type; | 
|  |  | 
|  | type = alloc_type (of); | 
|  |  | 
|  | const char *name = ctf_type_name_raw (fp, tid); | 
|  | if (name != nullptr && strlen (name) != 0) | 
|  | type->set_name (name); | 
|  |  | 
|  | type->set_code (TYPE_CODE_ENUM); | 
|  | TYPE_LENGTH (type) = ctf_type_size (fp, tid); | 
|  | /* Set the underlying type based on its ctf_type_size bits.  */ | 
|  | TYPE_TARGET_TYPE (type) = objfile_int_type (of, TYPE_LENGTH (type), false); | 
|  | set_type_align (type, ctf_type_align (fp, tid)); | 
|  |  | 
|  | return set_tid_type (of, tid, type); | 
|  | } | 
|  |  | 
|  | static void | 
|  | process_enum_type (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct type *type; | 
|  | struct ctf_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 (struct ctf_context *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_TARGET_TYPE (inner_array)->code () == 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, nullptr); | 
|  |  | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *objfile = ccp->of; | 
|  | ctf_dict_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 nullptr; | 
|  | } | 
|  |  | 
|  | element_type = fetch_tid_type (ccp, ar.ctr_contents); | 
|  | if (element_type == nullptr) | 
|  | return nullptr; | 
|  |  | 
|  | idx_type = fetch_tid_type (ccp, ar.ctr_index); | 
|  | if (idx_type == nullptr) | 
|  | 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.  */ | 
|  | { | 
|  | range_type->bounds ()->high.set_undefined (); | 
|  | TYPE_LENGTH (type) = 0; | 
|  | type->set_target_is_stub (true); | 
|  | } | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid, ctf_id_t btid) | 
|  | { | 
|  | struct objfile *objfile = ccp->of; | 
|  | struct type *base_type, *cv_type; | 
|  |  | 
|  | base_type = fetch_tid_type (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | base_type = read_type_record (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid, ctf_id_t btid) | 
|  | { | 
|  | struct objfile *objfile = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct type *base_type, *cv_type; | 
|  |  | 
|  | base_type = fetch_tid_type (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | base_type = read_type_record (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid, ctf_id_t btid) | 
|  | { | 
|  | struct objfile *objfile = ccp->of; | 
|  | struct type *base_type, *cv_type; | 
|  |  | 
|  | base_type = fetch_tid_type (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | base_type = read_type_record (ccp, btid); | 
|  | if (base_type == nullptr) | 
|  | { | 
|  | 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 (struct ctf_context *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 = fetch_tid_type (ccp, btid); | 
|  | if (target_type != this_type) | 
|  | TYPE_TARGET_TYPE (this_type) = target_type; | 
|  | else | 
|  | TYPE_TARGET_TYPE (this_type) = nullptr; | 
|  |  | 
|  | this_type->set_target_is_stub (TYPE_TARGET_TYPE (this_type) != nullptr); | 
|  |  | 
|  | 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 (struct ctf_context *ccp, ctf_id_t tid, ctf_id_t btid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | struct type *target_type, *type; | 
|  |  | 
|  | target_type = fetch_tid_type (ccp, btid); | 
|  | if (target_type == nullptr) | 
|  | { | 
|  | target_type = read_type_record (ccp, btid); | 
|  | if (target_type == nullptr) | 
|  | { | 
|  | 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 from a TID of CTF_K_FORWARD.  */ | 
|  |  | 
|  | static struct type * | 
|  | read_forward_type (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | struct objfile *of = ccp->of; | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | struct type *type; | 
|  | uint32_t kind; | 
|  |  | 
|  | type = alloc_type (of); | 
|  |  | 
|  | const char *name = ctf_type_name_raw (fp, tid); | 
|  | if (name != nullptr && strlen (name) != 0) | 
|  | type->set_name (name); | 
|  |  | 
|  | kind = ctf_type_kind_forwarded (fp, tid); | 
|  | if (kind == CTF_K_UNION) | 
|  | type->set_code (TYPE_CODE_UNION); | 
|  | else | 
|  | type->set_code (TYPE_CODE_STRUCT); | 
|  |  | 
|  | TYPE_LENGTH (type) = 0; | 
|  | type->set_is_stub (true); | 
|  |  | 
|  | return set_tid_type (of, tid, type); | 
|  | } | 
|  |  | 
|  | /* Read information associated with type TID.  */ | 
|  |  | 
|  | static struct type * | 
|  | read_type_record (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | ctf_dict_t *fp = ccp->fp; | 
|  | uint32_t kind; | 
|  | struct type *type = nullptr; | 
|  | 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: | 
|  | { | 
|  | const char *name = ctf_type_name_raw (fp, tid); | 
|  | btid = ctf_type_reference (fp, tid); | 
|  | type = read_typedef_type (ccp, tid, btid, name); | 
|  | } | 
|  | 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_FORWARD: | 
|  | type = read_forward_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) | 
|  | { | 
|  | struct ctf_context *ccp = (struct ctf_context *) 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 != nullptr) | 
|  | 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) | 
|  | { | 
|  | struct ctf_context *ccp = (struct ctf_context *) arg; | 
|  | struct symbol *sym = nullptr; | 
|  | 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 != nullptr && strcmp (name, "main") == 0) | 
|  | 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 != nullptr) | 
|  | { | 
|  | sym = new_symbol (ccp, type, id); | 
|  | if (sym != nullptr) | 
|  | sym->compute_and_set_names (name, false, ccp->of->per_bfd); | 
|  | } | 
|  | break; | 
|  | case CTF_K_STRUCT: | 
|  | case CTF_K_UNION: | 
|  | case CTF_K_ENUM: | 
|  | if (type == nullptr) | 
|  | { | 
|  | complaint (_("ctf_add_var_cb: %s has NO type (%ld)"), name, id); | 
|  | type = objfile_type (ccp->of)->builtin_error; | 
|  | } | 
|  | sym = new (&ccp->of->objfile_obstack) symbol; | 
|  | OBJSTAT (ccp->of, n_syms++); | 
|  | sym->set_type (type); | 
|  | sym->set_domain (VAR_DOMAIN); | 
|  | sym->set_aclass_index (LOC_OPTIMIZED_OUT); | 
|  | sym->compute_and_set_names (name, false, ccp->of->per_bfd); | 
|  | add_symbol_to_list (sym, ccp->builder->get_file_symbols ()); | 
|  | break; | 
|  | default: | 
|  | complaint (_("ctf_add_var_cb: kind unsupported (%d)"), kind); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (sym != nullptr) | 
|  | set_symbol_address (ccp->of, sym, name); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Add entries in either data objects or function info section, controlled | 
|  | by FUNCTIONS.  */ | 
|  |  | 
|  | static void | 
|  | add_stt_entries (struct ctf_context *ccp, int functions) | 
|  | { | 
|  | ctf_next_t *i = nullptr; | 
|  | const char *tname; | 
|  | ctf_id_t tid; | 
|  | struct symbol *sym = nullptr; | 
|  | struct type *type; | 
|  |  | 
|  | while ((tid = ctf_symbol_next (ccp->fp, &i, &tname, functions)) != CTF_ERR) | 
|  | { | 
|  | type = get_tid_type (ccp->of, tid); | 
|  | if (type == nullptr) | 
|  | continue; | 
|  | sym = new (&ccp->of->objfile_obstack) symbol; | 
|  | OBJSTAT (ccp->of, n_syms++); | 
|  | sym->set_type (type); | 
|  | sym->set_domain (VAR_DOMAIN); | 
|  | sym->set_aclass_index (LOC_STATIC); | 
|  | sym->compute_and_set_names (tname, false, ccp->of->per_bfd); | 
|  | add_symbol_to_list (sym, ccp->builder->get_global_symbols ()); | 
|  | set_symbol_address (ccp->of, sym, tname); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Add entries in data objects section.  */ | 
|  |  | 
|  | static void | 
|  | add_stt_obj (struct ctf_context *ccp) | 
|  | { | 
|  | add_stt_entries (ccp, 0); | 
|  | } | 
|  |  | 
|  | /* Add entries in function info section.  */ | 
|  |  | 
|  | static void | 
|  | add_stt_func (struct ctf_context *ccp) | 
|  | { | 
|  | add_stt_entries (ccp, 1); | 
|  | } | 
|  |  | 
|  | /* Get text segment base for OBJFILE, TSIZE contains the segment size.  */ | 
|  |  | 
|  | static CORE_ADDR | 
|  | get_objfile_text_range (struct objfile *of, int *tsize) | 
|  | { | 
|  | bfd *abfd = of->obfd; | 
|  | const asection *codes; | 
|  |  | 
|  | codes = bfd_get_section_by_name (abfd, ".text"); | 
|  | *tsize = codes ? bfd_section_size (codes) : 0; | 
|  | return of->text_section_offset (); | 
|  | } | 
|  |  | 
|  | /* Start a symtab for OBJFILE in CTF format.  */ | 
|  |  | 
|  | static void | 
|  | ctf_start_symtab (ctf_psymtab *pst, | 
|  | struct objfile *of, CORE_ADDR text_offset) | 
|  | { | 
|  | struct ctf_context *ccp; | 
|  |  | 
|  | ccp = &pst->context; | 
|  | ccp->builder = new buildsym_compunit | 
|  | (of, of->original_name, nullptr, | 
|  | 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 (ctf_psymtab *pst, | 
|  | CORE_ADDR end_addr, int section) | 
|  | { | 
|  | struct ctf_context *ccp; | 
|  |  | 
|  | ccp = &pst->context; | 
|  | struct compunit_symtab *result | 
|  | = ccp->builder->end_symtab (end_addr, section); | 
|  | delete ccp->builder; | 
|  | ccp->builder = nullptr; | 
|  | return result; | 
|  | } | 
|  |  | 
|  | /* Add all members of an enum with type TID to partial symbol table.  */ | 
|  |  | 
|  | static void | 
|  | ctf_psymtab_add_enums (struct ctf_context *ccp, ctf_id_t tid) | 
|  | { | 
|  | int val; | 
|  | const char *ename; | 
|  | ctf_next_t *i = nullptr; | 
|  |  | 
|  | while ((ename = ctf_enum_next (ccp->fp, tid, &i, &val)) != nullptr) | 
|  | { | 
|  | ccp->pst->add_psymbol (ename, true, | 
|  | VAR_DOMAIN, LOC_CONST, -1, | 
|  | psymbol_placement::GLOBAL, | 
|  | 0, language_c, ccp->partial_symtabs, ccp->of); | 
|  | } | 
|  | if (ctf_errno (ccp->fp) != ECTF_NEXT_END) | 
|  | complaint (_("ctf_enum_next ctf_psymtab_add_enums failed - %s"), | 
|  | ctf_errmsg (ctf_errno (ccp->fp))); | 
|  | } | 
|  |  | 
|  | /* Add entries in either data objects or function info section, controlled | 
|  | by FUNCTIONS, to psymtab.  */ | 
|  |  | 
|  | static void | 
|  | ctf_psymtab_add_stt_entries (ctf_dict_t *cfp, ctf_psymtab *pst, | 
|  | struct objfile *of, int functions) | 
|  | { | 
|  | ctf_next_t *i = nullptr; | 
|  | ctf_id_t tid; | 
|  | const char *tname; | 
|  |  | 
|  | while ((tid = ctf_symbol_next (cfp, &i, &tname, functions)) != CTF_ERR) | 
|  | { | 
|  | 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; | 
|  |  | 
|  | pst->add_psymbol (tname, true, | 
|  | tdomain, aclass, -1, | 
|  | psymbol_placement::GLOBAL, | 
|  | 0, language_c, pst->context.partial_symtabs, of); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Add entries in data objects section to psymtab.  */ | 
|  |  | 
|  | static void | 
|  | ctf_psymtab_add_stt_obj (ctf_dict_t *cfp, ctf_psymtab *pst, | 
|  | struct objfile *of) | 
|  | { | 
|  | ctf_psymtab_add_stt_entries (cfp, pst, of, 0); | 
|  | } | 
|  |  | 
|  | /* Add entries in function info section to psymtab.  */ | 
|  |  | 
|  | static void | 
|  | ctf_psymtab_add_stt_func (ctf_dict_t *cfp, ctf_psymtab *pst, | 
|  | struct objfile *of) | 
|  | { | 
|  | ctf_psymtab_add_stt_entries (cfp, pst, of, 1); | 
|  | } | 
|  |  | 
|  | /* Read in full symbols for PST, and anything it depends on.  */ | 
|  |  | 
|  | void | 
|  | ctf_psymtab::expand_psymtab (struct objfile *objfile) | 
|  | { | 
|  | struct ctf_context *ccp; | 
|  |  | 
|  | gdb_assert (!readin); | 
|  |  | 
|  | ccp = &context; | 
|  |  | 
|  | /* 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.  */ | 
|  | add_stt_obj (ccp); | 
|  | add_stt_func (ccp); | 
|  |  | 
|  | readin = true; | 
|  | } | 
|  |  | 
|  | /* Expand partial symbol table PST into a full symbol table. | 
|  | PST is not NULL.  */ | 
|  |  | 
|  | void | 
|  | ctf_psymtab::read_symtab (struct objfile *objfile) | 
|  | { | 
|  | if (readin) | 
|  | warning (_("bug: psymtab for %s is already read in."), filename); | 
|  | else | 
|  | { | 
|  | if (info_verbose) | 
|  | { | 
|  | printf_filtered (_("Reading in CTF data for %s..."), filename); | 
|  | gdb_flush (gdb_stdout); | 
|  | } | 
|  |  | 
|  | /* Start a symtab.  */ | 
|  | CORE_ADDR offset;        /* Start of text segment.  */ | 
|  | int tsize; | 
|  |  | 
|  | offset = get_objfile_text_range (objfile, &tsize); | 
|  | ctf_start_symtab (this, objfile, offset); | 
|  | expand_psymtab (objfile); | 
|  |  | 
|  | set_text_low (offset); | 
|  | set_text_high (offset + tsize); | 
|  | compunit_symtab = ctf_end_symtab (this, offset + tsize, | 
|  | SECT_OFF_TEXT (objfile)); | 
|  |  | 
|  | /* Finish up the debug error message.  */ | 
|  | if (info_verbose) | 
|  | printf_filtered (_("done.\n")); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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 ctf_psymtab * | 
|  | create_partial_symtab (const char *name, | 
|  | ctf_archive_t *arc, | 
|  | ctf_dict_t *cfp, | 
|  | psymtab_storage *partial_symtabs, | 
|  | struct objfile *objfile) | 
|  | { | 
|  | ctf_psymtab *pst; | 
|  |  | 
|  | pst = new ctf_psymtab (name, partial_symtabs, objfile->per_bfd, 0); | 
|  |  | 
|  | pst->context.arc = arc; | 
|  | pst->context.fp = cfp; | 
|  | pst->context.of = objfile; | 
|  | pst->context.partial_symtabs = partial_symtabs; | 
|  | pst->context.pst = pst; | 
|  |  | 
|  | return pst; | 
|  | } | 
|  |  | 
|  | /* Callback to add type TID to partial symbol table.  */ | 
|  |  | 
|  | static int | 
|  | ctf_psymtab_type_cb (ctf_id_t tid, void *arg) | 
|  | { | 
|  | struct ctf_context *ccp; | 
|  | uint32_t kind; | 
|  | short section = -1; | 
|  |  | 
|  | ccp = (struct ctf_context *) arg; | 
|  |  | 
|  | domain_enum domain = UNDEF_DOMAIN; | 
|  | enum address_class aclass = LOC_UNDEF; | 
|  | kind = ctf_type_kind (ccp->fp, tid); | 
|  | switch (kind) | 
|  | { | 
|  | case CTF_K_ENUM: | 
|  | ctf_psymtab_add_enums (ccp, tid); | 
|  | /* FALL THROUGH */ | 
|  | case CTF_K_STRUCT: | 
|  | case CTF_K_UNION: | 
|  | 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; | 
|  | } | 
|  |  | 
|  | const char *name = ctf_type_name_raw (ccp->fp, tid); | 
|  | if (name == nullptr || strlen (name) == 0) | 
|  | return 0; | 
|  |  | 
|  | ccp->pst->add_psymbol (name, false, | 
|  | domain, aclass, section, | 
|  | psymbol_placement::STATIC, | 
|  | 0, language_c, ccp->partial_symtabs, 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) | 
|  | { | 
|  | struct ctf_context *ccp = (struct ctf_context *) arg; | 
|  |  | 
|  | ccp->pst->add_psymbol (name, true, | 
|  | VAR_DOMAIN, LOC_STATIC, -1, | 
|  | psymbol_placement::GLOBAL, | 
|  | 0, language_c, ccp->partial_symtabs, ccp->of); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Start a subfile for CTF. FNAME is the name of the archive.  */ | 
|  |  | 
|  | static void | 
|  | ctf_start_archive (struct ctf_context *ccx, struct objfile *of, | 
|  | const char *fname) | 
|  | { | 
|  | if (ccx->builder == nullptr) | 
|  | { | 
|  | ccx->builder = new buildsym_compunit (of, | 
|  | of->original_name, nullptr, language_c, 0); | 
|  | ccx->builder->record_debugformat ("ctf"); | 
|  | } | 
|  | ccx->builder->start_subfile (fname); | 
|  | } | 
|  |  | 
|  | /* Setup partial_symtab's describing each source file for which | 
|  | debugging information is available.  */ | 
|  |  | 
|  | static void | 
|  | scan_partial_symbols (ctf_dict_t *cfp, psymtab_storage *partial_symtabs, | 
|  | struct ctf_per_tu_data *tup, const char *fname) | 
|  | { | 
|  | struct objfile *of = tup->of; | 
|  | bool isparent = false; | 
|  |  | 
|  | if (strcmp (fname, ".ctf") == 0) | 
|  | { | 
|  | fname = bfd_get_filename (of->obfd); | 
|  | isparent = true; | 
|  | } | 
|  |  | 
|  | ctf_psymtab *pst = create_partial_symtab (fname, tup->arc, cfp, | 
|  | partial_symtabs, of); | 
|  |  | 
|  | struct ctf_context *ccx = &pst->context; | 
|  | if (isparent == false) | 
|  | { | 
|  | ctf_start_archive (ccx, of, fname); | 
|  | ccx->pst = pst; | 
|  | } | 
|  |  | 
|  | 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.  */ | 
|  | ctf_psymtab_add_stt_obj (cfp, pst, of); | 
|  | ctf_psymtab_add_stt_func (cfp, pst, of); | 
|  |  | 
|  | pst->end (); | 
|  | } | 
|  |  | 
|  | /* Callback to build the psymtab for archive member NAME.  */ | 
|  |  | 
|  | static int | 
|  | build_ctf_archive_member (ctf_dict_t *ctf, const char *name, void *arg) | 
|  | { | 
|  | struct ctf_per_tu_data *tup = (struct ctf_per_tu_data *) arg; | 
|  | ctf_dict_t *parent = tup->fp; | 
|  |  | 
|  | if (strcmp (name, ".ctf") != 0) | 
|  | ctf_import (ctf, parent); | 
|  |  | 
|  | if (info_verbose) | 
|  | { | 
|  | printf_filtered (_("Scanning archive member %s..."), name); | 
|  | gdb_flush (gdb_stdout); | 
|  | } | 
|  |  | 
|  | psymtab_storage *pss = tup->psf->get_partial_symtabs ().get (); | 
|  | scan_partial_symbols (ctf, pss, tup, name); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* 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) | 
|  | { | 
|  | struct ctf_per_tu_data pcu; | 
|  | bfd *abfd = of->obfd; | 
|  | int err; | 
|  |  | 
|  | ctf_archive_t *arc = ctf_bfdopen (abfd, &err); | 
|  | if (arc == nullptr) | 
|  | error (_("ctf_bfdopen failed on %s - %s"), | 
|  | bfd_get_filename (abfd), ctf_errmsg (err)); | 
|  |  | 
|  | ctf_dict_t *fp = ctf_dict_open (arc, NULL, &err); | 
|  | if (fp == nullptr) | 
|  | error (_("ctf_dict_open failed on %s - %s"), | 
|  | bfd_get_filename (abfd), ctf_errmsg (err)); | 
|  | ctf_dict_key.emplace (of, fp); | 
|  |  | 
|  | pcu.fp = fp; | 
|  | pcu.of = of; | 
|  | pcu.arc = arc; | 
|  |  | 
|  | psymbol_functions *psf = new psymbol_functions (); | 
|  | of->qf.emplace_front (psf); | 
|  | pcu.psf = psf; | 
|  |  | 
|  | if (ctf_archive_iter (arc, build_ctf_archive_member, &pcu) < 0) | 
|  | error (_("ctf_archive_iter failed in input file %s: - %s"), | 
|  | bfd_get_filename (abfd), ctf_errmsg (err)); | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | void | 
|  | elfctf_build_psymtabs (struct objfile *of) | 
|  | { | 
|  | /* Nothing to do if CTF is disabled.  */ | 
|  | } | 
|  |  | 
|  | #endif /* ENABLE_LIBCTF */ |