| /* Compact ANSI-C Type Format (CTF) support in GDB. |
| |
| Copyright (C) 2019-2021 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)); |
| SYMBOL_ACLASS_INDEX (sym) = 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); |
| 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_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); |
| SYMBOL_DOMAIN (sym) = VAR_DOMAIN; |
| SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT; |
| |
| if (type != nullptr) |
| 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; |
| set_symbol_address (objfile, sym, sym->linkage_name ()); |
| break; |
| case CTF_K_CONST: |
| if (SYMBOL_TYPE (sym)->code () == 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_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); |
| ctf_func_type_info (fp, tid, &cfi); |
| 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, *target_type; |
| ctf_funcinfo_t fi; |
| |
| 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); |
| 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_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++); |
| 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_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++); |
| SYMBOL_TYPE (sym) = type; |
| SYMBOL_DOMAIN (sym) = VAR_DOMAIN; |
| SYMBOL_ACLASS_INDEX (sym) = 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 */ |