| /* Compact ANSI-C Type Format (CTF) support in GDB. |
| |
| Copyright (C) 2019-2020 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 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<htab, htab_deleter> ctf_tid_key; |
| |
| struct ctf_fp_info |
| { |
| explicit ctf_fp_info (ctf_file_t *cfp) : fp (cfp) {} |
| ~ctf_fp_info (); |
| ctf_file_t *fp; |
| }; |
| |
| /* Cleanup function for the ctf_file_key data. */ |
| ctf_fp_info::~ctf_fp_info () |
| { |
| if (!fp) |
| return; |
| |
| ctf_archive_t *arc = ctf_get_arc (fp); |
| ctf_file_close (fp); |
| ctf_close (arc); |
| } |
| |
| static const objfile_key<ctf_fp_info> ctf_file_key; |
| |
| /* A CTF context consists of a file pointer and an objfile pointer. */ |
| |
| struct ctf_context |
| { |
| ctf_file_t *fp; |
| struct objfile *of; |
| struct buildsym_compunit *builder; |
| }; |
| |
| /* A partial symtab, specialized for this module. */ |
| struct ctf_psymtab : public standard_psymtab |
| { |
| ctf_psymtab (const char *filename, struct objfile *objfile, CORE_ADDR addr) |
| : standard_psymtab (filename, objfile, 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; |
| }; |
| |
| |
| /* 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 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) |
| 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 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_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 ctf_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 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; |
| 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 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; |
| 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++); |
| |
| sym->set_language (language_c, &ccp->of->objfile_obstack); |
| sym->compute_and_set_names (name, false, ccp->of->per_bfd); |
| 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 (struct ctf_context *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<char> name (ctf_type_aname_raw (fp, tid)); |
| if (name != NULL) |
| { |
| sym = allocate_symbol (objfile); |
| OBJSTAT (objfile, n_syms++); |
| |
| sym->set_language (language_c, &objfile->objfile_obstack); |
| sym->compute_and_set_names (name.get (), true, objfile->per_bfd); |
| 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 (struct ctf_context *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<char> 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 (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_file_t *fp = ccp->fp; |
| struct type *type; |
| uint32_t kind; |
| |
| type = alloc_type (of); |
| |
| gdb::unique_xmalloc_ptr<char> 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 (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_file_t *fp = ccp->fp; |
| struct type *type, *rettype; |
| ctf_funcinfo_t cfi; |
| |
| type = alloc_type (of); |
| |
| gdb::unique_xmalloc_ptr<char> 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 (struct ctf_context *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<char> 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 (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_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 (struct ctf_context *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 (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 = 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 (struct ctf_context *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 (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 = 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 (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 = 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 (struct ctf_context *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 (struct ctf_context *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<char> 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) |
| { |
| 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 != 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) |
| { |
| struct ctf_context *ccp = (struct ctf_context *) 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); |
| 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 == 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; |
| sym->compute_and_set_names (name, false, ccp->of->per_bfd); |
| 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 (struct ctf_context *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 (struct ctf_context *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<char> 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) |
| { |
| 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, 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 (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 = NULL; |
| return result; |
| } |
| |
| /* Read in full symbols for PST, and anything it depends on. */ |
| |
| void |
| ctf_psymtab::expand_psymtab (struct objfile *objfile) |
| { |
| struct symbol *sym; |
| 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. */ |
| 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, sym->linkage_name ()); |
| } |
| |
| 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_file_t *cfp, |
| struct objfile *objfile) |
| { |
| ctf_psymtab *pst; |
| struct ctf_context *ccx; |
| |
| pst = new ctf_psymtab (name, objfile, 0); |
| |
| ccx = XOBNEW (&objfile->objfile_obstack, struct ctf_context); |
| ccx->fp = cfp; |
| ccx->of = objfile; |
| pst->context = ccx; |
| |
| 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; |
| gdb::unique_xmalloc_ptr<char> 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 (), 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) |
| { |
| struct ctf_context *ccp = (struct ctf_context *) arg; |
| |
| add_psymbol_to_list (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) |
| { |
| struct ctf_context ccx; |
| bfd *abfd = of->obfd; |
| const char *name = bfd_get_filename (abfd); |
| ctf_psymtab *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<char> 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 (), 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)); |
| ctf_file_key.emplace (of, fp); |
| |
| scan_partial_symbols (fp, of); |
| } |