diff options
author | Indu Bhagat <indu.bhagat@oracle.com> | 2021-05-20 11:15:52 -0700 |
---|---|---|
committer | Jose E. Marchesi <jose.marchesi@oracle.com> | 2021-06-28 18:47:20 +0200 |
commit | b7e215a8ee81d44281d9e0a2a25eceb47b6911dd (patch) | |
tree | 121afbbec2428c85a68b6119ac8c0f25f6cd9fab /gcc/ctfout.c | |
parent | 532617d6367c29803d5909f2432b1ebfb9ee1886 (diff) | |
download | gcc-b7e215a8ee81d44281d9e0a2a25eceb47b6911dd.zip gcc-b7e215a8ee81d44281d9e0a2a25eceb47b6911dd.tar.gz gcc-b7e215a8ee81d44281d9e0a2a25eceb47b6911dd.tar.bz2 |
CTF/BTF debug formats
This commit introduces support for generating CTF debugging
information and BTF debugging information from GCC.
2021-06-28 Indu Bhagat <indu.bhagat@oracle.com>
David Faust <david.faust@oracle.com>
Jose E. Marchesi <jose.marchesi@oracle.com>
Weimin Pan <weimin.pan@oracle.com>
gcc/
* Makefile.in: Add ctfc.*, ctfout.c and btfout.c files to
GTFILES. Add new object files.
* common.opt: Add CTF and BTF debug info options.
* btfout.c: New file.
* ctfc.c: Likewise.
* ctfc.h: Likewise.
* ctfout.c: Likewise.
* dwarf2ctf.c: Likewise.
* dwarf2ctf.h: Likewise.
* dwarf2cfi.c (dwarf2out_do_frame): Acknowledge CTF_DEBUG and
BTF_DEBUG.
* dwarf2out.c (dwarf2out_source_line): Likewise.
(dwarf2out_finish): Skip emitting DWARF if CTF or BTF are to
be generated.
(debug_format_do_cu): New function.
(dwarf2out_early_finish): Traverse DIEs and emit CTF/BTF for
them if requested.
Include dwarf2ctf.c.
* final.c (dwarf2_debug_info_emitted_p): Acknowledge DWARF-based debug
formats.
* flag-types.h (enum debug_info_type): Add CTF_DEBUG and BTF_DEBUG.
(CTF_DEBUG): New bitmask.
(BTF_DEBUG): Likewise.
(enum ctf_debug_info_levels): New enum.
* gengtype.c (open_base_files): Handle ctfc.h.
(main): Handle uint32_t type.
* flags.h (btf_debuginfo_p): New definition.
(dwarf_based_debuginfo_p): Likewise.
* opts.c (debug_type_names): Add entries for CTF and BTF.
(btf_debuginfo_p): New function.
(dwarf_based_debuginfo_p): Likewise.
(common_handle_option): Handle -gctfN and -gbtf options.
(set_debug_level): Set CTF_DEBUG, BTF_DEBUG whenever appropriate.
* toplev.c (process_options): Inform the user and ignore -gctfLEVEL if
frontend is not C.
include/
* ctf.h: New file.
* btf.h: Likewise.
libiberty/
* simple-object.c (handle_lto_debug_sections): Copy over .ctf
sections.
Diffstat (limited to 'gcc/ctfout.c')
-rw-r--r-- | gcc/ctfout.c | 830 |
1 files changed, 830 insertions, 0 deletions
diff --git a/gcc/ctfout.c b/gcc/ctfout.c new file mode 100644 index 0000000..c264fd6 --- /dev/null +++ b/gcc/ctfout.c @@ -0,0 +1,830 @@ +/* Output CTF format from GCC. + Copyright (C) 2019,2021 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC 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, or (at your option) any later +version. + +GCC 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 GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "output.h" +#include "dwarf2asm.h" +#include "debug.h" +#include "ctfc.h" +#include "diagnostic-core.h" + +static int ctf_label_num; + +/* Pointers to various CTF sections. */ + +static GTY (()) section * ctf_info_section; + +/* Section names used to hold CTF debugging information. */ + +/* CTF debug info section. */ + +#ifndef CTF_INFO_SECTION_NAME +#define CTF_INFO_SECTION_NAME ".ctf" +#endif + +/* Section flags for the CTF debug info section. */ + +#define CTF_INFO_SECTION_FLAGS (SECTION_DEBUG) + +/* Maximum size (in bytes) of an artificially generated CTF label. */ + +#define MAX_CTF_LABEL_BYTES 40 + +static char ctf_info_section_label[MAX_CTF_LABEL_BYTES]; + +#ifndef CTF_INFO_SECTION_LABEL +#define CTF_INFO_SECTION_LABEL "Lctf" +#endif + +/* CTF preprocess callback arguments. */ + +typedef struct ctf_dtd_preprocess_arg +{ + uint64_t dtd_global_func_idx; + ctf_container_ref dtd_arg_ctfc; +} ctf_dtd_preprocess_arg_t; + +typedef struct ctf_dvd_preprocess_arg +{ + uint64_t dvd_global_obj_idx; + ctf_container_ref dvd_arg_ctfc; +} ctf_dvd_preprocess_arg_t; + +/* Compare two CTF variable definition entries. Currently used for sorting + by name. */ + +static int +ctf_varent_compare (const void * entry1, const void * entry2) +{ + int result; + const ctf_dvdef_t * e1 = *(const ctf_dvdef_t * const*) entry1; + const ctf_dvdef_t * e2 = *(const ctf_dvdef_t * const*) entry2; + + result = strcmp (e1->dvd_name, e2->dvd_name); + + return result; +} + +/* A CTF type record may be followed by variable-length of bytes to encode the + CTF type completely. This routine calculates the number of bytes, in the + final binary CTF format, which are used to encode information about the type + completely. + + This function must always be in sync with the CTF header. */ + +static uint64_t +ctf_calc_num_vbytes (ctf_dtdef_ref ctftype) +{ + uint32_t size; + uint64_t vlen_bytes = 0; + + uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + uint32_t vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info); + + ctf_dmdef_t * dmd; + ctf_func_arg_t * farg; + uint32_t size_per_member = 0; + unsigned int num_members = 0; + unsigned int num_fargs = 0; + + switch (kind) + { + case CTF_K_FORWARD: + case CTF_K_UNKNOWN: + case CTF_K_POINTER: + case CTF_K_TYPEDEF: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + /* These types have no vlen data. */ + break; + + case CTF_K_INTEGER: + case CTF_K_FLOAT: + /* 4 bytes to represent encoding CTF_INT_DATA, CTF_FP_DATA. */ + vlen_bytes += sizeof (uint32_t); + break; + case CTF_K_FUNCTION: + /* Sanity check - number of function args must be the same as + vlen. */ + for (farg = ctftype->dtd_u.dtu_argv; + farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg)) + num_fargs++; + gcc_assert (vlen == num_fargs); + + /* FIXME - CTF_PADDING_FOR_ALIGNMENT. */ + vlen_bytes += (vlen + (vlen & 1)) * sizeof (uint32_t); + break; + case CTF_K_ARRAY: + /* This has a single ctf_array_t. */ + vlen_bytes += sizeof (ctf_array_t); + break; + case CTF_K_SLICE: + vlen_bytes += sizeof (ctf_slice_t); + break; + case CTF_K_STRUCT: + case CTF_K_UNION: + /* Count the number and type of members. */ + size = ctftype->dtd_data.ctti_size; + size_per_member = size >= CTF_LSTRUCT_THRESH + ? sizeof (ctf_lmember_t) : sizeof (ctf_member_t); + + /* Sanity check - number of members of struct must be the same as + vlen. */ + for (dmd = ctftype->dtd_u.dtu_members; + dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd)) + num_members++; + gcc_assert (vlen == num_members); + + vlen_bytes += (num_members * size_per_member); + break; + case CTF_K_ENUM: + vlen_bytes += vlen * sizeof (ctf_enum_t); + break; + default : + break; + } + return vlen_bytes; +} + +/* Add a CTF variable to the end of the list. */ + +static void +ctf_list_add_ctf_vars (ctf_container_ref ctfc, ctf_dvdef_ref var) +{ + /* FIXME - static may not fly with multiple CUs. */ + static int num_vars_added = 0; + ctfc->ctfc_vars_list[num_vars_added++] = var; +} + +/* Initialize the various sections and labels for CTF output. */ + +void +init_ctf_sections (void) +{ + /* Note : Even in case of LTO, the compiler continues to generate a single + CTF section for each compilation unit "early". Unlike other debug + sections, CTF sections are non-LTO sections, and do not take the + .gnu.debuglto_ prefix. The linker will de-duplicate the types in the CTF + sections, in case of LTO or otherwise. */ + ctf_info_section = get_section (CTF_INFO_SECTION_NAME, CTF_INFO_SECTION_FLAGS, + NULL); + + ASM_GENERATE_INTERNAL_LABEL (ctf_info_section_label, + CTF_INFO_SECTION_LABEL, ctf_label_num++); +} + +/* Routines for CTF pre-processing. */ + +static void +ctf_preprocess_var (ctf_container_ref ctfc, ctf_dvdef_ref var) +{ + /* Add it to the list of types. This array of types will be sorted before + assembling into output. */ + ctf_list_add_ctf_vars (ctfc, var); +} + +/* CTF preprocess callback routine for CTF variables. */ + +int +ctf_dvd_preprocess_cb (ctf_dvdef_ref * slot, void * arg) +{ + ctf_dvd_preprocess_arg_t * dvd_arg = (ctf_dvd_preprocess_arg_t *)arg; + ctf_dvdef_ref var = (ctf_dvdef_ref) *slot; + ctf_container_ref arg_ctfc = dvd_arg->dvd_arg_ctfc; + + ctf_preprocess_var (arg_ctfc, var); + + /* Keep track of global objts. */ + arg_ctfc->ctfc_gobjts_list[dvd_arg->dvd_global_obj_idx] = var; + dvd_arg->dvd_global_obj_idx++; + + return 1; +} + +/* CTF preprocess callback routine for CTF types. */ + +int +ctf_dtd_preprocess_cb (ctf_dtdef_ref * slot, void * arg) +{ + uint32_t kind; + + ctf_dtdef_ref ctftype = (ctf_dtdef_ref) *slot; + ctf_dtd_preprocess_arg_t * dtd_arg = (ctf_dtd_preprocess_arg_t *)arg; + ctf_container_ref arg_ctfc = dtd_arg->dtd_arg_ctfc; + + size_t index = ctftype->dtd_type; + gcc_assert (index <= arg_ctfc->ctfc_types->elements ()); + + /* CTF types need to be output in the order of their type IDs. In other + words, if type A is used to define type B, type ID of type A must + appear before type ID of type B. */ + arg_ctfc->ctfc_types_list[index] = ctftype; + + /* Keep track of the CTF type if it's a function type and the type + was generated from a function object. */ + kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + if (kind == CTF_K_FUNCTION && ctftype->from_global_func) + { + arg_ctfc->ctfc_gfuncs_list[dtd_arg->dtd_global_func_idx] = ctftype; + dtd_arg->dtd_global_func_idx++; + } + + /* Calculate the vlen bytes. */ + arg_ctfc->ctfc_num_vlen_bytes += ctf_calc_num_vbytes (ctftype); + + return 1; +} + +/* CTF preprocessing. + After the CTF types for the compilation unit have been generated fully, the + compiler writes out the asm for the CTF types. + + CTF writeout in the compiler requires two passes over the CTF types. In the + first pass, the CTF preprocess pass: + 1. CTF types are sorted in the order of their type IDs. + 2. The variable number of bytes after each CTF type record are calculated. + This is used to calculate the offsets in the ctf_header_t. + 3. If the CTF type is of CTF_K_FUNCTION, the number of bytes in the + funcinfo sub-section are calculated. This is used to calculate the + offsets in the ctf_header_t. + 4. Keep the list of CTF variables in ASCIIbetical order of their names. + + In the second pass, the CTF writeout pass, asm tags are written out using + the compiler's afore-generated internal pre-processed CTF types. */ + +static void +ctf_preprocess (ctf_container_ref ctfc) +{ + size_t num_ctf_types = ctfc->ctfc_types->elements (); + + /* Initialize an array to keep track of the CTF variables at global + scope. */ + size_t num_global_objts = ctfc->ctfc_num_global_objts; + if (num_global_objts) + { + ctfc->ctfc_gobjts_list = ggc_vec_alloc<ctf_dvdef_t*>(num_global_objts); + } + + size_t num_ctf_vars = ctfc->ctfc_vars->elements (); + if (num_ctf_vars) + { + ctf_dvd_preprocess_arg_t dvd_arg; + dvd_arg.dvd_global_obj_idx = 0; + dvd_arg.dvd_arg_ctfc = ctfc; + + /* Allocate CTF var list. */ + ctfc->ctfc_vars_list = ggc_vec_alloc<ctf_dvdef_ref>(num_ctf_vars); + /* Variables appear in the sort ASCIIbetical order of their names. This + permits binary searching in the CTF reader. Add the variables to a + list for sorting. */ + ctfc->ctfc_vars->traverse<void *, ctf_dvd_preprocess_cb> (&dvd_arg); + /* Sort the list. */ + qsort (ctfc->ctfc_vars_list, num_ctf_vars, sizeof (ctf_dvdef_ref), + ctf_varent_compare); + } + + /* Initialize an array to keep track of the CTF functions types for global + functions in the CTF data section. */ + size_t num_global_funcs = ctfc->ctfc_num_global_funcs; + if (num_global_funcs) + { + ctfc->ctfc_gfuncs_list = ggc_vec_alloc<ctf_dtdef_t*>(num_global_funcs); + gcc_assert (num_ctf_types); + } + + if (num_ctf_types) + { + ctf_dtd_preprocess_arg_t dtd_arg; + dtd_arg.dtd_global_func_idx = 0; + dtd_arg.dtd_arg_ctfc = ctfc; + /* Allocate the CTF types list. Add 1 because type ID 0 is never a valid + CTF type ID. No CTF type record should appear at that offset, this + eases debugging and readability. */ + ctfc->ctfc_types_list = ggc_vec_alloc<ctf_dtdef_ref>(num_ctf_types + 1); + /* Pre-process CTF types. */ + ctfc->ctfc_types->traverse<void *, ctf_dtd_preprocess_cb> (&dtd_arg); + + gcc_assert (dtd_arg.dtd_global_func_idx == num_global_funcs); + } +} + +/* CTF asm helper routines. */ + +/* Asm'out the CTF preamble. */ + +static void +ctf_asm_preamble (ctf_container_ref ctfc) +{ + dw2_asm_output_data (2, ctfc->ctfc_magic, + "CTF preamble magic number"); + dw2_asm_output_data (1, ctfc->ctfc_version, "CTF preamble version"); + dw2_asm_output_data (1, ctfc->ctfc_flags, "CTF preamble flags"); +} + +/* Asm'out a CTF type which is represented by ctf_stype_t. */ + +static void +ctf_asm_stype (ctf_dtdef_ref type) +{ + dw2_asm_output_data (4, type->dtd_data.ctti_name, "ctt_name"); + dw2_asm_output_data (4, type->dtd_data.ctti_info, "ctt_info"); + /* union. */ + dw2_asm_output_data (4, type->dtd_data.ctti_size, "ctt_size or ctt_type"); +} + +/* Asm'out a CTF type which is represented by ctf_type_t. */ + +static void +ctf_asm_type (ctf_dtdef_ref type) +{ + dw2_asm_output_data (4, type->dtd_data.ctti_name, "ctt_name"); + dw2_asm_output_data (4, type->dtd_data.ctti_info, "ctt_info"); + /* union. */ + dw2_asm_output_data (4, type->dtd_data.ctti_size, "ctt_size"); + dw2_asm_output_data (4, type->dtd_data.ctti_lsizehi, "ctt_lsizehi"); + dw2_asm_output_data (4, type->dtd_data.ctti_lsizelo, "ctt_lsizelo"); +} + +/* Asm'out a CTF type of kind CTF_K_SLICE. */ + +static void +ctf_asm_slice (ctf_dtdef_ref type) +{ + dw2_asm_output_data (4, type->dtd_u.dtu_slice.cts_type, "cts_type"); + dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_offset, "cts_offset"); + dw2_asm_output_data (2, type->dtd_u.dtu_slice.cts_bits, "cts_bits"); +} + +/* Asm'out a CTF type of kind CTF_K_ARRAY. */ + +static void +ctf_asm_array (ctf_dtdef_ref dtd) +{ + dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_contents, "cta_contents"); + dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_index, "cta_index"); + dw2_asm_output_data (4, dtd->dtd_u.dtu_arr.ctr_nelems, "cta_nelems"); +} + +/* Asm'out a CTF variable. */ + +static void +ctf_asm_varent (ctf_dvdef_ref var) +{ + /* Output the reference to the name in the string table. */ + dw2_asm_output_data (4, var->dvd_name_offset, "ctv_name"); + /* Output the type index. */ + dw2_asm_output_data (4, var->dvd_type, "ctv_typeidx"); +} + +/* Asm'out a member of CTF struct or union, represented by ctf_lmember_t. */ + +static void +ctf_asm_sou_lmember (ctf_dmdef_t * dmd) +{ + dw2_asm_output_data (4, dmd->dmd_name_offset, "ctlm_name"); + dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset), + "ctlm_offsethi"); + dw2_asm_output_data (4, dmd->dmd_type, "ctlm_type"); + dw2_asm_output_data (4, CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset), + "ctlm_offsetlo"); +} + +/* Asm'out a member of a CTF sruct or union, represented by ctf_member_t. */ + +static void +ctf_asm_sou_member (ctf_dmdef_t * dmd) +{ + dw2_asm_output_data (4, dmd->dmd_name_offset, "ctm_name"); + dw2_asm_output_data (4, dmd->dmd_offset, "ctm_offset"); + dw2_asm_output_data (4, dmd->dmd_type, "ctm_type"); +} + +/* Asm'out an enumerator constant. */ + +static void +ctf_asm_enum_const (ctf_dmdef_t * dmd) +{ + dw2_asm_output_data (4, dmd->dmd_name_offset, "cte_name"); + dw2_asm_output_data (4, dmd->dmd_value, "cte_value"); +} + +/* Asm'out a function argument. */ + +static void +ctf_asm_func_arg (ctf_func_arg_t * farg) +{ + dw2_asm_output_data (4, farg->farg_type, "dtu_argv"); +} + +/* CTF writeout to asm file. */ + +static void +output_ctf_header (ctf_container_ref ctfc) +{ + switch_to_section (ctf_info_section); + ASM_OUTPUT_LABEL (asm_out_file, ctf_info_section_label); + + ctf_asm_preamble (ctfc); + + /* For a single compilation unit, the parent container's name and label are + NULL. */ + dw2_asm_output_data (4, 0, "cth_parlabel"); + dw2_asm_output_data (4, 0, "cth_parname"); + dw2_asm_output_data (4, ctfc->ctfc_cuname_offset, "cth_cuname"); + + int typeslen = 0; + /* Initialize the offsets. The offsets are from after the CTF header. */ + uint32_t lbloff = 0; + uint32_t objtoff = 0; + uint32_t funcoff = 0; + uint32_t objtidxoff = 0; + uint32_t funcidxoff = 0; + uint32_t varoff = 0; + uint32_t typeoff = 0; + uint32_t stroff = 0; + + if (!ctfc_is_empty_container (ctfc)) + { + gcc_assert (ctfc_get_num_ctf_types (ctfc) + == (ctfc->ctfc_num_types + ctfc->ctfc_num_stypes)); + + funcoff = objtoff + ctfc->ctfc_num_global_objts * sizeof (uint32_t); + /* Object index appears after function info. */ + objtidxoff = funcoff + ctfc->ctfc_num_global_funcs * sizeof (uint32_t); + /* Funxtion index goes next. */ + funcidxoff = objtidxoff + ctfc->ctfc_num_global_objts * sizeof (uint32_t); + /* Vars appear after function index. */ + varoff = funcidxoff + ctfc->ctfc_num_global_funcs * sizeof (uint32_t); + /* CTF types appear after vars. */ + typeoff = varoff + ctfc_get_num_ctf_vars (ctfc) * sizeof (ctf_varent_t); + /* The total number of bytes for CTF types is the sum of the number of + times struct ctf_type_t, struct ctf_stype_t are written, plus the + amount of variable length data after each one of these. */ + typeslen = ctfc->ctfc_num_types * sizeof (ctf_type_t) + + ctfc->ctfc_num_stypes * (sizeof (ctf_stype_t)) + + ctfc_get_num_vlen_bytes (ctfc); + + /* Strings appear after types. */ + stroff = typeoff + typeslen; + } + + /* Offset of label section. */ + dw2_asm_output_data (4, lbloff, "cth_lbloff"); + /* Offset of object section. */ + dw2_asm_output_data (4, objtoff, "cth_objtoff"); + /* Offset of function section. */ + dw2_asm_output_data (4, funcoff, "cth_funcoff"); + /* Offset of object index section. */ + dw2_asm_output_data (4, objtidxoff, "cth_objtidxoff"); + /* Offset of function index section. */ + dw2_asm_output_data (4, funcidxoff, "cth_funcidxoff"); + + /* Offset of variable section. */ + dw2_asm_output_data (4, varoff, "cth_varoff"); + /* Offset of type section. */ + dw2_asm_output_data (4, typeoff, "cth_typeoff"); + /* Offset of string section. */ + dw2_asm_output_data (4, stroff, "cth_stroff"); + /* Length of string section in bytes. */ + dw2_asm_output_data (4, ctfc->ctfc_strlen, "cth_strlen"); +} + +/* Output the CTF object info section. */ + +static void +output_ctf_obj_info (ctf_container_ref ctfc) +{ + uint64_t i; + ctf_dvdef_ref var; + + if (!ctfc->ctfc_num_global_objts) return; + + /* Compiler spits out the objts (at global scope) in the CTF obj info section. + In no specific order. In an object file, the CTF object index section is + used to associate the objts to their corresponding names. */ + for (i = 0; i < ctfc->ctfc_num_global_objts; i++) + { + var = ctfc->ctfc_gobjts_list[i]; + + /* CTF type ID corresponding to the type of the variable. */ + dw2_asm_output_data (4, var->dvd_type, "objtinfo_var_type"); + } + +} + +/* Output the CTF function info section. */ + +static void +output_ctf_func_info (ctf_container_ref ctfc) +{ + uint64_t i; + ctf_dtdef_ref ctftype; + + if (!ctfc->ctfc_num_global_funcs) return; + + /* The CTF funcinfo section is simply an array of CTF_K_FUNCTION type IDs in + the type section. In an object file, the CTF function index section is + used to associate functions to their corresponding names. */ + for (i = 0; i < ctfc->ctfc_num_global_funcs; i++) + { + ctftype = ctfc->ctfc_gfuncs_list[i]; + dw2_asm_output_data (4, ctftype->dtd_type, "funcinfo_func_type"); + } +} + +/* Output the CTF object index section. */ + +static void +output_ctf_objtidx (ctf_container_ref ctfc) +{ + uint64_t i; + ctf_dvdef_ref var; + + if (!ctfc->ctfc_num_global_objts) return; + + for (i = 0; i < ctfc->ctfc_num_global_objts; i++) + { + var = ctfc->ctfc_gobjts_list[i]; + /* Offset to the name in CTF string table. */ + dw2_asm_output_data (4, var->dvd_name_offset, "objtinfo_name"); + } +} + +/* Output the CTF function index section. */ + +static void +output_ctf_funcidx (ctf_container_ref ctfc) +{ + uint64_t i; + ctf_dtdef_ref ctftype; + + if (!ctfc->ctfc_num_global_funcs) return; + + for (i = 0; i < ctfc->ctfc_num_global_funcs; i++) + { + ctftype = ctfc->ctfc_gfuncs_list[i]; + /* Offset to the name in CTF string table. */ + dw2_asm_output_data (4, ctftype->dtd_data.ctti_name, "funcinfo_name"); + } +} + +/* Output the CTF variables. Variables appear in the sorted ASCIIbetical + order of their names. This permits binary searching in the CTF reader. */ + +static void +output_ctf_vars (ctf_container_ref ctfc) +{ + size_t i; + size_t num_ctf_vars = ctfc->ctfc_vars->elements (); + if (num_ctf_vars) + { + /* Iterate over the list of sorted vars and output the asm. */ + for (i = 0; i < num_ctf_vars; i++) + { + ctf_asm_varent (ctfc->ctfc_vars_list[i]); + /* The type of variable must be a valid one. */ + gcc_assert (ctfc->ctfc_vars_list[i]->dvd_type != CTF_NULL_TYPEID); + } + } +} + +/* Output the CTF string records. */ + +static void +output_ctf_strs (ctf_container_ref ctfc) +{ + ctf_string_t * ctf_string = ctfc->ctfc_strtable.ctstab_head; + + while (ctf_string) + { + dw2_asm_output_nstring (ctf_string->cts_str, -1, "ctf_string"); + ctf_string = ctf_string->cts_next; + } +} + +/* Output the members of the CTF struct or union. */ + +static void +output_asm_ctf_sou_fields (ctf_container_ref ARG_UNUSED (ctfc), + ctf_dtdef_ref dtd) +{ + ctf_dmdef_t * dmd; + + /* Function pointer to dump struct/union members. */ + void (*ctf_asm_sou_field_func) (ctf_dmdef_t *); + + uint32_t size = dtd->dtd_data.ctti_size; + + /* The variable length data struct/union CTF types is an array of + ctf_member or ctf_lmember, depending on size of the member. */ + if (size >= CTF_LSTRUCT_THRESH) + ctf_asm_sou_field_func = ctf_asm_sou_lmember; + else + ctf_asm_sou_field_func = ctf_asm_sou_member; + + for (dmd = dtd->dtd_u.dtu_members; + dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd)) + { + ctf_asm_sou_field_func (dmd); + /* Sanity Check - Unrepresented types appear as explicit types. */ + gcc_assert (dmd->dmd_type != CTF_NULL_TYPEID); + } +} + +/* Output the list of enumerator constants of the CTF enum type. */ + +static void +output_asm_ctf_enum_list (ctf_container_ref ARG_UNUSED (ctfc), + ctf_dtdef_ref dtd) +{ + ctf_dmdef_t * dmd; + + for (dmd = dtd->dtd_u.dtu_members; + dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd)) + ctf_asm_enum_const (dmd); +} + +/* Output the list of function arguments of the CTF function type. */ + +static void +output_asm_func_args_list (ctf_container_ref ARG_UNUSED (ctfc), + ctf_dtdef_ref dtd) +{ + ctf_func_arg_t * farg; + + for (farg = dtd->dtd_u.dtu_argv; + farg != NULL; farg = (ctf_func_arg_t *) ctf_farg_list_next (farg)) + ctf_asm_func_arg (farg); +} + +/* Output the variable length portion of the CTF type record. */ + +static void +output_asm_ctf_vlen_bytes (ctf_container_ref ctfc, ctf_dtdef_ref ctftype) +{ + uint32_t encoding; + uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + uint32_t vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info); + + switch (kind) + { + case CTF_K_INTEGER: + case CTF_K_FLOAT: + if (kind == CTF_K_INTEGER) + { + encoding = CTF_INT_DATA (ctftype->dtd_u.dtu_enc.cte_format, + ctftype->dtd_u.dtu_enc.cte_offset, + ctftype->dtd_u.dtu_enc.cte_bits); + } + else + { + encoding = CTF_FP_DATA (ctftype->dtd_u.dtu_enc.cte_format, + ctftype->dtd_u.dtu_enc.cte_offset, + ctftype->dtd_u.dtu_enc.cte_bits); + } + dw2_asm_output_data (4, encoding, "ctf_encoding_data"); + break; + case CTF_K_FUNCTION: + { + output_asm_func_args_list (ctfc, ctftype); + /* FIXME - CTF_PADDING_FOR_ALIGNMENT. + libctf expects this padding for alignment reasons. Expected to + be redundant in CTF_VERSION_4. */ + if (vlen & 1) + dw2_asm_output_data (4, 0, "dtu_argv_padding"); + + break; + } + case CTF_K_ARRAY: + ctf_asm_array (ctftype); + break; + case CTF_K_SLICE: + { + ctf_asm_slice (ctftype); + /* Type of the slice must be a valid CTF type. */ + gcc_assert (ctftype->dtd_u.dtu_slice.cts_type != CTF_NULL_TYPEID); + break; + } + case CTF_K_STRUCT: + case CTF_K_UNION: + output_asm_ctf_sou_fields (ctfc, ctftype); + break; + case CTF_K_ENUM: + output_asm_ctf_enum_list (ctfc, ctftype); + break; + + default: + /* CTF types of kind CTF_K_VOLATILE, CTF_K_CONST, CTF_K_RESTRICT, + etc have no vlen data to write. */ + break; + } +} + +/* Output a CTF Type. */ + +static void +output_asm_ctf_type (ctf_container_ref ctfc, ctf_dtdef_ref type) +{ + if (type->dtd_data.ctti_size <= CTF_MAX_SIZE) + ctf_asm_stype (type); + else + ctf_asm_type (type); + /* Now comes the variable-length portion for defining types completely. + E.g., encoding follows CTF_INT_DATA, CTF_FP_DATA types, + struct ctf_array_t follows CTF_K_ARRAY types, or a bunch of + struct ctf_member / ctf_lmember ctf_enum sit in there for CTF_K_STRUCT or + CTF_K_UNION. */ + output_asm_ctf_vlen_bytes (ctfc, type); + + uint32_t kind = CTF_V2_INFO_KIND (type->dtd_data.ctti_info); + /* The underlying type must be a valid CTF type. */ + if (kind == CTF_K_POINTER || kind == CTF_K_TYPEDEF + || kind == CTF_K_VOLATILE || kind == CTF_K_CONST + || kind == CTF_K_RESTRICT) + gcc_assert (type->dtd_data.ctti_type != CTF_NULL_TYPEID); +} + +/* Output all CTF type records. */ + +static void +output_ctf_types (ctf_container_ref ctfc) +{ + size_t i; + size_t num_ctf_types = ctfc->ctfc_types->elements (); + if (num_ctf_types) + { + /* Type ID = 0 is used as sentinel value; not a valid type. */ + for (i = 1; i <= num_ctf_types; i++) + output_asm_ctf_type (ctfc, ctfc->ctfc_types_list[i]); + } +} + +/* CTF routines interfacing to the compiler. */ + +/* Prepare and output the CTF section. */ + +void +ctf_output (const char * filename) +{ + if (ctf_debug_info_level == CTFINFO_LEVEL_NONE) + return; + + /* Get the CTF container for the current translation unit. */ + ctf_container_ref tu_ctfc = ctf_get_tu_ctfc (); + + init_ctf_sections (); + + ctf_add_cuname (tu_ctfc, filename); + + /* Pre-process CTF before generating assembly. */ + ctf_preprocess (tu_ctfc); + output_ctf_header (tu_ctfc); + output_ctf_obj_info (tu_ctfc); + output_ctf_func_info (tu_ctfc); + output_ctf_objtidx (tu_ctfc); + output_ctf_funcidx (tu_ctfc); + output_ctf_vars (tu_ctfc); + output_ctf_types (tu_ctfc); + output_ctf_strs (tu_ctfc); + + /* The total number of string bytes must be equal to those processed out to + the str subsection. */ + gcc_assert (tu_ctfc->ctfc_strlen + == ctfc_get_strtab_len (tu_ctfc, CTF_STRTAB)); + +} + +/* Reset all state for CTF generation so that we can rerun the compiler within + the same process. */ + +void +ctf_finalize (void) +{ + ctf_info_section = NULL; + + ctf_container_ref tu_ctfc = ctf_get_tu_ctfc (); + ctfc_delete_container (tu_ctfc); + tu_ctfc = NULL; +} + +#include "gt-ctfout.h" |