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.
This commit is contained in:
parent
532617d636
commit
b7e215a8ee
19 changed files with 5346 additions and 39 deletions
|
@ -1319,6 +1319,9 @@ OBJS = \
|
|||
cfgloopanal.o \
|
||||
cfgloopmanip.o \
|
||||
cfgrtl.o \
|
||||
ctfc.o \
|
||||
ctfout.o \
|
||||
btfout.o \
|
||||
symtab.o \
|
||||
symtab-thunks.o \
|
||||
symtab-clones.o \
|
||||
|
@ -1359,6 +1362,7 @@ OBJS = \
|
|||
dumpfile.o \
|
||||
dwarf2asm.o \
|
||||
dwarf2cfi.o \
|
||||
dwarf2ctf.o \
|
||||
dwarf2out.o \
|
||||
early-remat.o \
|
||||
emit-rtl.o \
|
||||
|
@ -2655,7 +2659,11 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
|||
$(srcdir)/dwarf2out.h \
|
||||
$(srcdir)/dwarf2asm.c \
|
||||
$(srcdir)/dwarf2cfi.c \
|
||||
$(srcdir)/dwarf2ctf.c \
|
||||
$(srcdir)/dwarf2out.c \
|
||||
$(srcdir)/ctfc.h \
|
||||
$(srcdir)/ctfout.c \
|
||||
$(srcdir)/btfout.c \
|
||||
$(srcdir)/tree-vect-generic.c \
|
||||
$(srcdir)/gimple-isel.cc \
|
||||
$(srcdir)/dojump.c $(srcdir)/emit-rtl.h \
|
||||
|
|
1129
gcc/btfout.c
Normal file
1129
gcc/btfout.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -122,6 +122,11 @@ enum debug_info_levels debug_info_level = DINFO_LEVEL_NONE
|
|||
Variable
|
||||
bool use_gnu_debug_info_extensions
|
||||
|
||||
; Level of CTF debugging information we are producing. See flag-types.h
|
||||
; for the definitions of the different possible levels.
|
||||
Variable
|
||||
enum ctf_debug_info_levels ctf_debug_info_level = CTFINFO_LEVEL_NONE
|
||||
|
||||
; Original value of maximum field alignment in bytes, specified via
|
||||
; -fpack-struct=<value>.
|
||||
Variable
|
||||
|
@ -3183,6 +3188,16 @@ gcolumn-info
|
|||
Common Driver Var(debug_column_info,1) Init(1)
|
||||
Record DW_AT_decl_column and DW_AT_call_column in DWARF.
|
||||
|
||||
; The CTF generation process feeds off DWARF dies. This option implicitly
|
||||
; updates the debug_info_level to DINFO_LEVEL_NORMAL.
|
||||
gctf
|
||||
Common Driver RejectNegative JoinedOrMissing
|
||||
Generate CTF debug information at default level.
|
||||
|
||||
gbtf
|
||||
Common Driver RejectNegative JoinedOrMissing
|
||||
Generate BTF debug information at default level.
|
||||
|
||||
gdwarf
|
||||
Common Driver JoinedOrMissing Negative(gdwarf-)
|
||||
Generate debug information in default version of DWARF format.
|
||||
|
|
969
gcc/ctfc.c
Normal file
969
gcc/ctfc.c
Normal file
|
@ -0,0 +1,969 @@
|
|||
/* Generate CTF.
|
||||
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 "toplev.h"
|
||||
#include "ctfc.h"
|
||||
#include "diagnostic-core.h"
|
||||
|
||||
/* A CTF container object - one per translation unit. */
|
||||
|
||||
ctf_container_ref tu_ctfc;
|
||||
|
||||
ctf_container_ref
|
||||
ctf_get_tu_ctfc (void)
|
||||
{
|
||||
return tu_ctfc;
|
||||
}
|
||||
|
||||
/* If the next ctf type id is still set to the init value, no ctf records to
|
||||
report. */
|
||||
bool
|
||||
ctfc_is_empty_container (ctf_container_ref ctfc)
|
||||
{
|
||||
return ((ctfc)->ctfc_nextid == CTF_INIT_TYPEID);
|
||||
}
|
||||
|
||||
/* Get the total number of CTF types in the container. */
|
||||
|
||||
unsigned int
|
||||
ctfc_get_num_ctf_types (ctf_container_ref ctfc)
|
||||
{
|
||||
return ctfc->ctfc_types->elements ();
|
||||
}
|
||||
|
||||
/* Get the total number of CTF variables in the container. */
|
||||
|
||||
unsigned int ctfc_get_num_ctf_vars (ctf_container_ref ctfc)
|
||||
{
|
||||
return ctfc->ctfc_vars->elements ();
|
||||
}
|
||||
|
||||
/* Get reference to the CTF string table or the CTF auxilliary
|
||||
string table. */
|
||||
|
||||
ctf_strtable_t *
|
||||
ctfc_get_strtab (ctf_container_ref ctfc, int aux)
|
||||
{
|
||||
return aux ? &(ctfc)->ctfc_aux_strtable : &(ctfc->ctfc_strtable);
|
||||
}
|
||||
|
||||
/* Get the length of the specified string table of the CTF container. */
|
||||
|
||||
size_t
|
||||
ctfc_get_strtab_len (ctf_container_ref ctfc, int aux)
|
||||
{
|
||||
ctf_strtable_t * strtab = ctfc_get_strtab (ctfc, aux);
|
||||
return strtab->ctstab_len;
|
||||
}
|
||||
|
||||
/* Get the number of bytes to represent the variable length portion of all CTF
|
||||
types in the CTF container. */
|
||||
|
||||
size_t ctfc_get_num_vlen_bytes (ctf_container_ref ctfc)
|
||||
{
|
||||
return ctfc->ctfc_num_vlen_bytes;
|
||||
}
|
||||
|
||||
/* Return which member of the union is used in CTFTYPE. Used for garbage
|
||||
collection. */
|
||||
|
||||
enum ctf_dtu_d_union_enum
|
||||
ctf_dtu_d_union_selector (ctf_dtdef_ref ctftype)
|
||||
{
|
||||
uint32_t kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info);
|
||||
switch (kind)
|
||||
{
|
||||
case CTF_K_UNKNOWN:
|
||||
case CTF_K_INTEGER:
|
||||
case CTF_K_FLOAT:
|
||||
return CTF_DTU_D_ENCODING;
|
||||
case CTF_K_STRUCT:
|
||||
case CTF_K_UNION:
|
||||
case CTF_K_ENUM:
|
||||
return CTF_DTU_D_MEMBERS;
|
||||
case CTF_K_ARRAY:
|
||||
return CTF_DTU_D_ARRAY;
|
||||
case CTF_K_FUNCTION:
|
||||
return CTF_DTU_D_ARGUMENTS;
|
||||
case CTF_K_SLICE:
|
||||
return CTF_DTU_D_SLICE;
|
||||
default:
|
||||
/* The largest member as default. */
|
||||
return CTF_DTU_D_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert CTF type into the CTF container. */
|
||||
|
||||
static void
|
||||
ctf_dtd_insert (ctf_container_ref ctfc, ctf_dtdef_ref dtd)
|
||||
{
|
||||
bool existed = false;
|
||||
ctf_dtdef_ref entry = dtd;
|
||||
|
||||
ctf_dtdef_ref * item = ctfc->ctfc_types->find_slot (entry, INSERT);
|
||||
if (*item == NULL)
|
||||
*item = dtd;
|
||||
else
|
||||
existed = true;
|
||||
/* Duplicate CTF type records not expected to be inserted. */
|
||||
gcc_assert (!existed);
|
||||
}
|
||||
|
||||
/* Lookup CTF type given a DWARF die for the type. */
|
||||
|
||||
static ctf_dtdef_ref
|
||||
ctf_dtd_lookup (const ctf_container_ref ctfc, const dw_die_ref type)
|
||||
{
|
||||
ctf_dtdef_t entry;
|
||||
entry.dtd_key = type;
|
||||
|
||||
ctf_dtdef_ref * slot = ctfc->ctfc_types->find_slot (&entry, NO_INSERT);
|
||||
|
||||
if (slot)
|
||||
return (ctf_dtdef_ref)*slot;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Insert CTF variable into the CTF container. */
|
||||
|
||||
static void
|
||||
ctf_dvd_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd)
|
||||
{
|
||||
bool existed = false;
|
||||
ctf_dvdef_ref entry = dvd;
|
||||
|
||||
ctf_dvdef_ref * item = ctfc->ctfc_vars->find_slot (entry, INSERT);
|
||||
if (*item == NULL)
|
||||
*item = dvd;
|
||||
else
|
||||
existed = true;
|
||||
/* Duplicate variable records not expected to be inserted. */
|
||||
gcc_assert (!existed);
|
||||
}
|
||||
|
||||
/* Lookup CTF variable given a DWARF die for the decl. */
|
||||
|
||||
ctf_dvdef_ref
|
||||
ctf_dvd_lookup (const ctf_container_ref ctfc, dw_die_ref die)
|
||||
{
|
||||
ctf_dvdef_t entry;
|
||||
entry.dvd_key = die;
|
||||
|
||||
ctf_dvdef_ref * slot = ctfc->ctfc_vars->find_slot (&entry, NO_INSERT);
|
||||
|
||||
if (slot)
|
||||
return (ctf_dvdef_ref)*slot;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Append member definition to the list. Member list is a singly-linked list
|
||||
with list start pointing to the head. */
|
||||
|
||||
static void
|
||||
ctf_dmd_list_append (ctf_dmdef_t ** dmd, ctf_dmdef_t * elem)
|
||||
{
|
||||
ctf_dmdef_t * tail = (dmd && *dmd) ? *dmd : NULL;
|
||||
if (tail)
|
||||
{
|
||||
while (tail->dmd_next)
|
||||
tail = tail->dmd_next;
|
||||
|
||||
tail->dmd_next = elem;
|
||||
}
|
||||
else
|
||||
*dmd = elem;
|
||||
|
||||
elem->dmd_next = NULL;
|
||||
}
|
||||
|
||||
/* Append function argument to the list. Member list is a singly-linked list
|
||||
with list start pointing to the head. */
|
||||
|
||||
static void
|
||||
ctf_farg_list_append (ctf_func_arg_t ** farg, ctf_func_arg_t * elem)
|
||||
{
|
||||
ctf_func_arg_t * tail = (farg && *farg) ? *farg : NULL;
|
||||
if (tail)
|
||||
{
|
||||
while (tail->farg_next)
|
||||
tail = tail->farg_next;
|
||||
|
||||
tail->farg_next = elem;
|
||||
}
|
||||
else
|
||||
*farg = elem;
|
||||
|
||||
elem->farg_next = NULL;
|
||||
}
|
||||
|
||||
/* Append str to the CTF string table. */
|
||||
|
||||
static void
|
||||
ctfc_strtable_append_str (ctf_strtable_t * str_table, const char * str)
|
||||
{
|
||||
ctf_string_t * ctf_string = ggc_cleared_alloc<ctf_string_t> ();
|
||||
/* Keep a reference to the input STR. */
|
||||
ctf_string->cts_str = str;
|
||||
ctf_string->cts_next = NULL;
|
||||
|
||||
if (!str_table->ctstab_head)
|
||||
str_table->ctstab_head = ctf_string;
|
||||
|
||||
/* Append to the end of the list. */
|
||||
if (str_table->ctstab_tail)
|
||||
str_table->ctstab_tail->cts_next = ctf_string;
|
||||
|
||||
str_table->ctstab_tail = ctf_string;
|
||||
}
|
||||
|
||||
/* Wrapper function to add str to the CTF string table. No de-duplication of
|
||||
CTF strings is done by the compiler. */
|
||||
|
||||
static const char *
|
||||
ctfc_strtable_add_str (ctf_strtable_t * str_table, const char * name,
|
||||
uint32_t * name_offset)
|
||||
{
|
||||
size_t len;
|
||||
char * ctf_string;
|
||||
/* Return value is the offset to the string in the string table. */
|
||||
uint32_t str_offset = str_table->ctstab_len;
|
||||
|
||||
/* Add empty string only once at the beginning of the string table. Also, do
|
||||
not add null strings, return the offset to the empty string for them. */
|
||||
if ((!name || (name != NULL && !strcmp (name, ""))) && str_offset)
|
||||
{
|
||||
ctf_string = CONST_CAST (char *, str_table->ctstab_estr);
|
||||
str_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert (name);
|
||||
/* Add null-terminated strings to the string table. */
|
||||
len = strlen (name) + 1;
|
||||
ctf_string = CONST_CAST (char *, ggc_strdup (name));
|
||||
|
||||
ctfc_strtable_append_str (str_table, ctf_string);
|
||||
/* Add string to the string table. Keep number of strings updated. */
|
||||
str_table->ctstab_num++;
|
||||
/* Keep the number of bytes contained in the string table updated. */
|
||||
str_table->ctstab_len += len;
|
||||
}
|
||||
|
||||
*name_offset = str_offset;
|
||||
|
||||
return (const char *) ctf_string;
|
||||
|
||||
}
|
||||
|
||||
/* Add string to the appropriate string table in the CTF container. */
|
||||
|
||||
const char *
|
||||
ctf_add_string (ctf_container_ref ctfc, const char * name,
|
||||
uint32_t * name_offset, int aux_str = CTF_STRTAB)
|
||||
{
|
||||
/* Get the CTF string table or the CTF auxilliary string table,
|
||||
as applicable. */
|
||||
ctf_strtable_t *str_table = ctfc_get_strtab (ctfc, aux_str);
|
||||
return ctfc_strtable_add_str (str_table, name, name_offset);
|
||||
}
|
||||
|
||||
/* Add the compilation unit (CU) name string to the the CTF string table. The
|
||||
CU name has a prepended pwd string if it is a relative path. Also set the
|
||||
CU name offset in the CTF container. */
|
||||
|
||||
void
|
||||
ctf_add_cuname (ctf_container_ref ctfc, const char * filename)
|
||||
{
|
||||
char * cuname = NULL;
|
||||
|
||||
/* (filename at this point of compilation cannot be null). */
|
||||
|
||||
if (!IS_DIR_SEPARATOR (filename[0]))
|
||||
{
|
||||
/* Filename is a relative path. */
|
||||
const char * cu_pwd = get_src_pwd ();
|
||||
const int cu_pwd_len = strlen (cu_pwd);
|
||||
|
||||
/* Add a DIR_SEPARATOR char before the filename. */
|
||||
const int len = cu_pwd_len + 2 + strlen (filename);
|
||||
|
||||
cuname = (char *) ggc_alloc_atomic (len);
|
||||
memset (cuname, 0, len);
|
||||
|
||||
strcpy (cuname, cu_pwd);
|
||||
cuname[cu_pwd_len] = DIR_SEPARATOR;
|
||||
cuname[cu_pwd_len+1] = 0;
|
||||
strcat (cuname, filename);
|
||||
}
|
||||
else
|
||||
/* Filename is an absolute path. */
|
||||
cuname = CONST_CAST (char *, ggc_strdup (filename));
|
||||
|
||||
ctf_add_string (ctfc, cuname, &(ctfc->ctfc_cuname_offset));
|
||||
/* Add 1 as CTF strings in the CTF string table are null-terminated
|
||||
strings. */
|
||||
ctfc->ctfc_strlen += strlen (cuname) + 1;
|
||||
|
||||
/* Mark cuname for garbage collection. */
|
||||
cuname = NULL;
|
||||
}
|
||||
|
||||
/* Functions to create CTF types.
|
||||
|
||||
These functions perform the task of adding CTF types to the CTF container.
|
||||
No de-duplication is done by them; the onus is on the calling function to do
|
||||
so. The caller must first do a lookup via ctf_dtd_lookup or
|
||||
ctf_dvd_lookup, as applicable, to ascertain that the CTF type or the CTF
|
||||
variable respectively does not already exist, and then add it. */
|
||||
|
||||
static ctf_id_t
|
||||
ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
ctf_dtdef_ref * rp, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
gcc_assert (flag == CTF_ADD_NONROOT || flag == CTF_ADD_ROOT);
|
||||
|
||||
dtd = ggc_cleared_alloc<ctf_dtdef_t> ();
|
||||
|
||||
type = ctfc->ctfc_nextid++;
|
||||
gcc_assert (type < CTF_MAX_TYPE); /* CTF type ID overflow. */
|
||||
|
||||
/* Buffer the strings in the CTF string table. */
|
||||
dtd->dtd_name = ctf_add_string (ctfc, name, &(dtd->dtd_data.ctti_name));
|
||||
dtd->dtd_type = type;
|
||||
dtd->dtd_key = die;
|
||||
|
||||
if ((name != NULL) && strcmp (name, ""))
|
||||
ctfc->ctfc_strlen += strlen (name) + 1;
|
||||
|
||||
ctf_dtd_insert (ctfc, dtd);
|
||||
|
||||
*rp = dtd;
|
||||
return type;
|
||||
}
|
||||
|
||||
static ctf_id_t
|
||||
ctf_add_encoded (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
const ctf_encoding_t * ep, uint32_t kind, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
|
||||
|
||||
uint32_t roundup_nbytes = (ROUND_UP (ep->cte_bits, BITS_PER_UNIT)
|
||||
/ BITS_PER_UNIT);
|
||||
|
||||
/* FIXME, stay close to what libctf does. But by getting next power of two,
|
||||
aren't we conveying less precise information. E.g. floating point mode
|
||||
XF has a size of 12 bytes. */
|
||||
dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes))
|
||||
: roundup_nbytes;
|
||||
dtd->dtd_u.dtu_enc = *ep;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
|
||||
uint32_t kind, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
gcc_assert (ref <= CTF_MAX_TYPE);
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
|
||||
/* Caller of this API must guarantee that a CTF type with id = ref already
|
||||
exists. This will also be validated for us at link-time. */
|
||||
dtd->dtd_data.ctti_type = (uint32_t) ref;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_forward (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
uint32_t kind, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type = 0;
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
|
||||
dtd->dtd_data.ctti_type = kind;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_typedef (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
ctf_id_t ref, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
gcc_assert (ref <= CTF_MAX_TYPE);
|
||||
/* Nameless Typedefs are not expected. */
|
||||
gcc_assert ((name != NULL) && strcmp (name, ""));
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0);
|
||||
/* Caller of this API must guarantee that a CTF type with id = ref already
|
||||
exists. This will also be validated for us at link-time. */
|
||||
dtd->dtd_data.ctti_type = (uint32_t) ref;
|
||||
|
||||
gcc_assert (dtd->dtd_type != dtd->dtd_data.ctti_type);
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_slice (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
|
||||
uint32_t bit_offset, uint32_t bit_size, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
uint32_t roundup_nbytes;
|
||||
|
||||
gcc_assert ((bit_size <= 255) && (bit_offset <= 255));
|
||||
|
||||
gcc_assert (ref <= CTF_MAX_TYPE);
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
|
||||
|
||||
roundup_nbytes = (ROUND_UP (bit_size, BITS_PER_UNIT) / BITS_PER_UNIT);
|
||||
/* FIXME, stay close to what libctf does. But by getting next power of two,
|
||||
aren't we conveying less precise information, especially for bitfields.
|
||||
For example, cte_bits = 33, roundup_nbytes = 5, ctti_size = 8 in the
|
||||
implementation below. */
|
||||
dtd->dtd_data.ctti_size = roundup_nbytes ? (1 << ceil_log2 (roundup_nbytes))
|
||||
: 0;
|
||||
|
||||
/* Caller of this API must guarantee that a CTF type with id = ref already
|
||||
exists. This will also be validated for us at link-time. */
|
||||
dtd->dtd_u.dtu_slice.cts_type = (uint32_t) ref;
|
||||
dtd->dtd_u.dtu_slice.cts_bits = bit_size;
|
||||
dtd->dtd_u.dtu_slice.cts_offset = bit_offset;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_float (ctf_container_ref ctfc, uint32_t flag,
|
||||
const char * name, const ctf_encoding_t * ep, dw_die_ref die)
|
||||
{
|
||||
return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, die));
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_integer (ctf_container_ref ctfc, uint32_t flag,
|
||||
const char * name, const ctf_encoding_t * ep, dw_die_ref die)
|
||||
{
|
||||
return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, die));
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_unknown (ctf_container_ref ctfc, uint32_t flag,
|
||||
const char * name, const ctf_encoding_t * ep, dw_die_ref die)
|
||||
{
|
||||
return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_UNKNOWN, die));
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref,
|
||||
dw_die_ref die)
|
||||
{
|
||||
return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, die));
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp,
|
||||
dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
gcc_assert (arp);
|
||||
|
||||
/* Caller of this API must make sure CTF type for arp->ctr_contents and
|
||||
arp->ctr_index are already added. This will also be validated for us at
|
||||
link-time. */
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, NULL, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
|
||||
dtd->dtd_data.ctti_size = 0;
|
||||
dtd->dtd_u.dtu_arr = *arp;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_enum (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
HOST_WIDE_INT size, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
|
||||
/* In the compiler, no need to handle the case of promoting forwards to
|
||||
enums. This comment is simply to note a divergence from libctf. */
|
||||
|
||||
/* The compiler does, however, update any previously existing forward types
|
||||
to non-root. CTF does not allow existence of two root types with the same
|
||||
name. */
|
||||
ctf_dtdef_ref enum_fwd_type = ctf_dtd_lookup (ctfc, die);
|
||||
if (enum_fwd_type)
|
||||
{
|
||||
enum_fwd_type->dtd_data.ctti_info
|
||||
= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
|
||||
}
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
|
||||
|
||||
/* Size in bytes should always fit, of course.
|
||||
TBD WARN - warn instead? */
|
||||
gcc_assert (size <= CTF_MAX_SIZE);
|
||||
|
||||
dtd->dtd_data.ctti_size = size;
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
int
|
||||
ctf_add_enumerator (ctf_container_ref ctfc, ctf_id_t enid, const char * name,
|
||||
HOST_WIDE_INT value, dw_die_ref die)
|
||||
{
|
||||
ctf_dmdef_t * dmd;
|
||||
uint32_t kind, vlen, root;
|
||||
|
||||
/* Callers of this API must make sure that CTF_K_ENUM with enid has been
|
||||
addded. This will also be validated for us at link-time. */
|
||||
ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, die);
|
||||
gcc_assert (dtd);
|
||||
gcc_assert (dtd->dtd_type == enid);
|
||||
gcc_assert (name);
|
||||
|
||||
kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
|
||||
root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info);
|
||||
vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
|
||||
|
||||
gcc_assert (kind == CTF_K_ENUM && vlen < CTF_MAX_VLEN);
|
||||
|
||||
/* Enum value is of type HOST_WIDE_INT in the compiler, dmd_value is int32_t
|
||||
on the other hand. Check bounds and skip adding this enum value if out of
|
||||
bounds. */
|
||||
if ((value > INT_MAX) || (value < INT_MIN))
|
||||
{
|
||||
/* FIXME - Note this TBD_CTF_REPRESENTATION_LIMIT. */
|
||||
return (1);
|
||||
}
|
||||
|
||||
dmd = ggc_cleared_alloc<ctf_dmdef_t> ();
|
||||
|
||||
/* Buffer the strings in the CTF string table. */
|
||||
dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset));
|
||||
dmd->dmd_type = CTF_NULL_TYPEID;
|
||||
dmd->dmd_offset = 0;
|
||||
|
||||
dmd->dmd_value = value;
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1);
|
||||
ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd);
|
||||
|
||||
if ((name != NULL) && strcmp (name, ""))
|
||||
ctfc->ctfc_strlen += strlen (name) + 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ctf_add_member_offset (ctf_container_ref ctfc, dw_die_ref sou,
|
||||
const char * name, ctf_id_t type,
|
||||
uint64_t bit_offset)
|
||||
{
|
||||
ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, sou);
|
||||
ctf_dmdef_t * dmd;
|
||||
|
||||
uint32_t kind, vlen, root;
|
||||
|
||||
/* The type of the member being added must already exist. */
|
||||
gcc_assert (dtd);
|
||||
|
||||
kind = CTF_V2_INFO_KIND (dtd->dtd_data.ctti_info);
|
||||
root = CTF_V2_INFO_ISROOT (dtd->dtd_data.ctti_info);
|
||||
vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
|
||||
|
||||
gcc_assert (kind == CTF_K_STRUCT || kind == CTF_K_UNION);
|
||||
gcc_assert (vlen < CTF_MAX_VLEN);
|
||||
|
||||
dmd = ggc_cleared_alloc<ctf_dmdef_t> ();
|
||||
|
||||
/* Buffer the strings in the CTF string table. */
|
||||
dmd->dmd_name = ctf_add_string (ctfc, name, &(dmd->dmd_name_offset));
|
||||
dmd->dmd_type = type;
|
||||
dmd->dmd_value = -1;
|
||||
|
||||
if (kind == CTF_K_STRUCT && vlen != 0)
|
||||
dmd->dmd_offset = bit_offset;
|
||||
else
|
||||
dmd->dmd_offset = 0;
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, root, vlen + 1);
|
||||
ctf_dmd_list_append (&dtd->dtd_u.dtu_members, dmd);
|
||||
|
||||
if ((name != NULL) && strcmp (name, ""))
|
||||
ctfc->ctfc_strlen += strlen (name) + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ctf_add_variable (ctf_container_ref ctfc, const char * name, ctf_id_t ref,
|
||||
dw_die_ref die, unsigned int external_vis)
|
||||
{
|
||||
ctf_dvdef_ref dvd;
|
||||
|
||||
gcc_assert (name);
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
dvd = ggc_cleared_alloc<ctf_dvdef_t> ();
|
||||
dvd->dvd_key = die;
|
||||
/* Buffer the strings in the CTF string table. */
|
||||
dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset));
|
||||
dvd->dvd_visibility = external_vis;
|
||||
dvd->dvd_type = ref;
|
||||
ctf_dvd_insert (ctfc, dvd);
|
||||
|
||||
if (strcmp (name, ""))
|
||||
ctfc->ctfc_strlen += strlen (name) + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ctf_add_function_arg (ctf_container_ref ctfc, dw_die_ref func,
|
||||
const char * name, ctf_id_t type)
|
||||
{
|
||||
ctf_dtdef_ref dtd = ctf_dtd_lookup (ctfc, func);
|
||||
ctf_func_arg_t * farg;
|
||||
uint32_t vlen;
|
||||
|
||||
/* The function to which argument is being added must already exist. */
|
||||
gcc_assert (dtd);
|
||||
/* The number of args must have been non-zero. */
|
||||
vlen = CTF_V2_INFO_VLEN (dtd->dtd_data.ctti_info);
|
||||
gcc_assert (vlen);
|
||||
|
||||
farg = ggc_cleared_alloc<ctf_func_arg_t> ();
|
||||
|
||||
/* Buffer the strings in the auxilliary string table. CTF V3 format does not
|
||||
require function argument names. Use auxilliary string table to keep
|
||||
these strings to avoid unnecessary bloat in CTF section in CTF V3. */
|
||||
farg->farg_name = ctf_add_string (ctfc, name, &(farg->farg_name_offset),
|
||||
CTF_AUX_STRTAB);
|
||||
farg->farg_type = type;
|
||||
|
||||
ctf_farg_list_append (&dtd->dtd_u.dtu_argv, farg);
|
||||
|
||||
/* For aux_str, keep ctfc_aux_strlen updated for debugging. */
|
||||
if ((name != NULL) && strcmp (name, ""))
|
||||
ctfc->ctfc_aux_strlen += strlen (name) + 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_function (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
const ctf_funcinfo_t * ctc, dw_die_ref die,
|
||||
bool from_global_func)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type;
|
||||
uint32_t vlen;
|
||||
|
||||
gcc_assert (ctc);
|
||||
|
||||
vlen = ctc->ctc_argc;
|
||||
gcc_assert (vlen <= CTF_MAX_VLEN);
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
|
||||
dtd->from_global_func = from_global_func;
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
|
||||
/* Caller must make sure CTF types for ctc->ctc_return are already added. */
|
||||
dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return;
|
||||
/* Caller must make sure CTF types for function arguments are already added
|
||||
via ctf_add_function_arg () API. */
|
||||
|
||||
ctfc->ctfc_num_stypes++;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
ctf_id_t
|
||||
ctf_add_sou (ctf_container_ref ctfc, uint32_t flag, const char * name,
|
||||
uint32_t kind, size_t size, dw_die_ref die)
|
||||
{
|
||||
ctf_dtdef_ref dtd;
|
||||
ctf_id_t type = 0;
|
||||
|
||||
gcc_assert ((kind == CTF_K_STRUCT) || (kind == CTF_K_UNION));
|
||||
|
||||
/* In the compiler, no need to handle the case of promoting forwards to
|
||||
structs. This comment is simply to note a divergence from libctf. */
|
||||
|
||||
/* The compiler does, however, update any previously existing forward types
|
||||
to non-root. CTF does not allow existence of two root types with the same
|
||||
name. */
|
||||
ctf_dtdef_ref sou_fwd_type = ctf_dtd_lookup (ctfc, die);
|
||||
if (sou_fwd_type)
|
||||
{
|
||||
sou_fwd_type->dtd_data.ctti_info
|
||||
= CTF_TYPE_INFO (CTF_K_FORWARD, CTF_ADD_NONROOT, 0);
|
||||
}
|
||||
|
||||
type = ctf_add_generic (ctfc, flag, name, &dtd, die);
|
||||
|
||||
dtd->dtd_data.ctti_info = CTF_TYPE_INFO (kind, flag, 0);
|
||||
|
||||
if (size > CTF_MAX_SIZE)
|
||||
{
|
||||
dtd->dtd_data.ctti_size = CTF_LSIZE_SENT;
|
||||
dtd->dtd_data.ctti_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
|
||||
dtd->dtd_data.ctti_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
|
||||
ctfc->ctfc_num_types++;
|
||||
}
|
||||
else
|
||||
{
|
||||
dtd->dtd_data.ctti_size = (uint32_t) size;
|
||||
ctfc->ctfc_num_stypes++;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Check if CTF for TYPE has already been generated. Mainstay for
|
||||
de-duplication. If CTF type already exists, returns TRUE and updates
|
||||
the TYPE_ID for the caller. */
|
||||
|
||||
bool
|
||||
ctf_type_exists (ctf_container_ref ctfc, dw_die_ref type,
|
||||
ctf_id_t * type_id)
|
||||
{
|
||||
bool exists = false;
|
||||
ctf_dtdef_ref ctf_type_seen = ctf_dtd_lookup (ctfc, type);
|
||||
|
||||
if (ctf_type_seen)
|
||||
{
|
||||
exists = true;
|
||||
/* CTF type for this type exists. */
|
||||
*type_id = ctf_type_seen->dtd_type;
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
/* Location information for CTF Types and CTF Variables. CTF section does not
|
||||
emit location information; at this time, location information is needed for
|
||||
BTF CO-RE use-cases. */
|
||||
|
||||
int
|
||||
ctfc_get_dtd_srcloc (ctf_dtdef_ref dtd, ctf_srcloc_ref loc)
|
||||
{
|
||||
loc->ctsloc_file = ctf_get_die_loc_file (dtd->dtd_key);
|
||||
loc->ctsloc_line = ctf_get_die_loc_line (dtd->dtd_key);
|
||||
loc->ctsloc_col = ctf_get_die_loc_col (dtd->dtd_key);
|
||||
|
||||
if (loc->ctsloc_file == NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ctfc_get_dvd_srcloc (ctf_dvdef_ref dvd, ctf_srcloc_ref loc)
|
||||
{
|
||||
loc->ctsloc_file = ctf_get_die_loc_file (dvd->dvd_key);
|
||||
loc->ctsloc_line = ctf_get_die_loc_line (dvd->dvd_key);
|
||||
loc->ctsloc_col = ctf_get_die_loc_col (dvd->dvd_key);
|
||||
|
||||
if (loc->ctsloc_file == NULL)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* CTF container setup and teardown routines. */
|
||||
|
||||
/* Initialize the CTF string table.
|
||||
The first entry in the CTF string table (empty string) is added. */
|
||||
|
||||
static void
|
||||
init_ctf_strtable (ctf_strtable_t * strtab)
|
||||
{
|
||||
strtab->ctstab_head = NULL;
|
||||
strtab->ctstab_tail = NULL;
|
||||
strtab->ctstab_num = 0;
|
||||
strtab->ctstab_len = 0;
|
||||
|
||||
/* The first entry in the CTF string table is an empty string. E.g., CTF
|
||||
type records with no name (like CTF_K_CONST, CTF_K_VOLATILE etc) point to
|
||||
this string. */
|
||||
uint32_t estr_offset = 0;
|
||||
strtab->ctstab_estr = ctfc_strtable_add_str (strtab, "", &estr_offset);
|
||||
}
|
||||
|
||||
/* Initialize the string tables in the CTF container. */
|
||||
|
||||
static void
|
||||
init_ctf_string_table (ctf_container_ref ctfc)
|
||||
{
|
||||
init_ctf_strtable (&ctfc->ctfc_strtable);
|
||||
ctfc->ctfc_strlen++;
|
||||
|
||||
init_ctf_strtable (&ctfc->ctfc_aux_strtable);
|
||||
ctfc->ctfc_aux_strlen++;
|
||||
}
|
||||
|
||||
/* Allocate a new CTF container with the desired flags. */
|
||||
|
||||
static inline ctf_container_ref
|
||||
new_ctf_container (void)
|
||||
{
|
||||
tu_ctfc = ggc_cleared_alloc<ctf_container_t> ();
|
||||
tu_ctfc->ctfc_types
|
||||
= hash_table<ctfc_dtd_hasher>::create_ggc (100);
|
||||
tu_ctfc->ctfc_vars
|
||||
= hash_table<ctfc_dvd_hasher>::create_ggc (100);
|
||||
|
||||
return tu_ctfc;
|
||||
}
|
||||
|
||||
/* Initialize a CTF container per translation unit. */
|
||||
|
||||
static void
|
||||
init_ctf_container (void)
|
||||
{
|
||||
tu_ctfc = new_ctf_container ();
|
||||
|
||||
tu_ctfc->ctfc_magic = CTF_MAGIC;
|
||||
tu_ctfc->ctfc_version = CTF_VERSION;
|
||||
tu_ctfc->ctfc_flags = CTF_F_NEWFUNCINFO;
|
||||
tu_ctfc->ctfc_nextid = CTF_INIT_TYPEID;
|
||||
|
||||
init_ctf_string_table (tu_ctfc);
|
||||
}
|
||||
|
||||
void
|
||||
ctfc_delete_strtab (ctf_strtable_t * strtab)
|
||||
{
|
||||
ctf_string_t * str = NULL;
|
||||
ctf_string_t * next_str = NULL;
|
||||
|
||||
str = strtab->ctstab_head;
|
||||
next_str = str;
|
||||
while (next_str != NULL)
|
||||
{
|
||||
next_str = str->cts_next;
|
||||
ggc_free (str);
|
||||
str = next_str;
|
||||
}
|
||||
|
||||
strtab->ctstab_head = NULL;
|
||||
strtab->ctstab_tail = NULL;
|
||||
strtab->ctstab_estr = NULL;
|
||||
}
|
||||
|
||||
/* Delete the CTF container's resources. */
|
||||
|
||||
void
|
||||
ctfc_delete_container (ctf_container_ref ctfc)
|
||||
{
|
||||
/* FIXME - CTF container can be cleaned up now.
|
||||
Will the ggc machinery take care of cleaning up the container structure
|
||||
including the hash_map members etc. ? */
|
||||
if (ctfc)
|
||||
{
|
||||
ctfc_delete_strtab (&ctfc->ctfc_strtable);
|
||||
ctfc_delete_strtab (&ctfc->ctfc_aux_strtable);
|
||||
if (ctfc->ctfc_vars_list)
|
||||
{
|
||||
ggc_free (ctfc->ctfc_vars_list);
|
||||
ctfc->ctfc_vars_list = NULL;
|
||||
}
|
||||
if (ctfc->ctfc_types_list)
|
||||
{
|
||||
ggc_free (ctfc->ctfc_types_list);
|
||||
ctfc->ctfc_types_list = NULL;
|
||||
}
|
||||
if (ctfc->ctfc_gfuncs_list)
|
||||
{
|
||||
ggc_free (ctfc->ctfc_gfuncs_list);
|
||||
ctfc->ctfc_gfuncs_list = NULL;
|
||||
}
|
||||
if (ctfc->ctfc_gobjts_list)
|
||||
{
|
||||
ggc_free (ctfc->ctfc_gobjts_list);
|
||||
ctfc->ctfc_gobjts_list = NULL;
|
||||
}
|
||||
|
||||
ctfc= NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* CTF routines interfacing to the compiler. */
|
||||
|
||||
void
|
||||
ctf_init (void)
|
||||
{
|
||||
init_ctf_container ();
|
||||
}
|
436
gcc/ctfc.h
Normal file
436
gcc/ctfc.h
Normal file
|
@ -0,0 +1,436 @@
|
|||
/* ctfc.h - Declarations and definitions related to the CTF container.
|
||||
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/>. */
|
||||
|
||||
/* This file defines the data structures and functions used by the compiler
|
||||
to generate the CTF debug info. The definitions below are compiler internal
|
||||
representations and closely reflect the CTF format requirements in <ctf.h>.
|
||||
|
||||
The contents of the CTF container are used eventually for emission of both
|
||||
CTF (ctfout.c) and BTF debug info (btfout.c), as the two type debug formats
|
||||
are close cousins. */
|
||||
|
||||
#ifndef GCC_CTFC_H
|
||||
#define GCC_CTFC_H 1
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "tree.h"
|
||||
#include "fold-const.h"
|
||||
#include "dwarf2ctf.h"
|
||||
#include "ctf.h"
|
||||
#include "btf.h"
|
||||
|
||||
/* Invalid CTF type ID definition. */
|
||||
|
||||
#define CTF_NULL_TYPEID 0
|
||||
|
||||
/* Value to start generating the CTF type ID from. */
|
||||
|
||||
#define CTF_INIT_TYPEID 1
|
||||
|
||||
/* CTF type ID. */
|
||||
|
||||
typedef uint64_t ctf_id_t;
|
||||
|
||||
/* CTF string table element (list node). */
|
||||
|
||||
typedef struct GTY ((chain_next ("%h.cts_next"))) ctf_string
|
||||
{
|
||||
const char * cts_str; /* CTF string. */
|
||||
struct ctf_string * cts_next; /* A list node. */
|
||||
} ctf_string_t;
|
||||
|
||||
/* Internal representation of CTF string table. */
|
||||
|
||||
typedef struct GTY (()) ctf_strtable
|
||||
{
|
||||
ctf_string_t * ctstab_head; /* Head str ptr. */
|
||||
ctf_string_t * ctstab_tail; /* Tail. new str appended to tail. */
|
||||
int ctstab_num; /* Number of strings in the table. */
|
||||
size_t ctstab_len; /* Size of string table in bytes. */
|
||||
const char * ctstab_estr; /* Empty string "". */
|
||||
} ctf_strtable_t;
|
||||
|
||||
/* Encoding information for integers, floating-point values etc. The flags
|
||||
field will contain values appropriate for the type defined in <ctf.h>. */
|
||||
|
||||
typedef struct GTY (()) ctf_encoding
|
||||
{
|
||||
unsigned int cte_format; /* Data format (CTF_INT_* or CTF_FP_* flags). */
|
||||
unsigned int cte_offset; /* Offset of value in bits. */
|
||||
unsigned int cte_bits; /* Size of storage in bits. */
|
||||
} ctf_encoding_t;
|
||||
|
||||
/* Array information for CTF generation. */
|
||||
|
||||
typedef struct GTY (()) ctf_arinfo
|
||||
{
|
||||
ctf_id_t ctr_contents; /* Type of array contents. */
|
||||
ctf_id_t ctr_index; /* Type of array index. */
|
||||
unsigned int ctr_nelems; /* Number of elements. */
|
||||
} ctf_arinfo_t;
|
||||
|
||||
/* Function information for CTF generation. */
|
||||
|
||||
typedef struct GTY (()) ctf_funcinfo
|
||||
{
|
||||
ctf_id_t ctc_return; /* Function return type. */
|
||||
unsigned int ctc_argc; /* Number of typed arguments to function. */
|
||||
unsigned int ctc_flags; /* Function attributes (see below). */
|
||||
} ctf_funcinfo_t;
|
||||
|
||||
typedef struct GTY (()) ctf_sliceinfo
|
||||
{
|
||||
unsigned int cts_type; /* Reference CTF type. */
|
||||
unsigned short cts_offset; /* Offset in bits of the first bit. */
|
||||
unsigned short cts_bits; /* Size in bits. */
|
||||
} ctf_sliceinfo_t;
|
||||
|
||||
/* CTF type representation internal to the compiler. It closely reflects the
|
||||
ctf_type_t type node in <ctf.h> except the GTY (()) tags. */
|
||||
|
||||
typedef struct GTY (()) ctf_itype
|
||||
{
|
||||
uint32_t ctti_name; /* Reference to name in string table. */
|
||||
uint32_t ctti_info; /* Encoded kind, variant length (see below). */
|
||||
union GTY ((desc ("0")))
|
||||
{
|
||||
uint32_t GTY ((tag ("0"))) _size;/* Size of entire type in bytes. */
|
||||
uint32_t GTY ((tag ("1"))) _type;/* Reference to another type. */
|
||||
} _u;
|
||||
uint32_t ctti_lsizehi; /* High 32 bits of type size in bytes. */
|
||||
uint32_t ctti_lsizelo; /* Low 32 bits of type size in bytes. */
|
||||
} ctf_itype_t;
|
||||
|
||||
#define ctti_size _u._size
|
||||
#define ctti_type _u._type
|
||||
|
||||
/* Function arguments end with varargs. */
|
||||
|
||||
#define CTF_FUNC_VARARG 0x1
|
||||
|
||||
/* Struct/union/enum member definition for CTF generation. */
|
||||
|
||||
typedef struct GTY ((chain_next ("%h.dmd_next"))) ctf_dmdef
|
||||
{
|
||||
const char * dmd_name; /* Name of this member. */
|
||||
ctf_id_t dmd_type; /* Type of this member (for sou). */
|
||||
uint32_t dmd_name_offset; /* Offset of the name in str table. */
|
||||
uint64_t dmd_offset; /* Offset of this member in bits (for sou). */
|
||||
int dmd_value; /* Value of this member (for enum). */
|
||||
struct ctf_dmdef * dmd_next; /* A list node. */
|
||||
} ctf_dmdef_t;
|
||||
|
||||
#define ctf_dmd_list_next(elem) ((ctf_dmdef_t *)((elem)->dmd_next))
|
||||
|
||||
/* Function Argument. */
|
||||
|
||||
typedef struct GTY (()) ctf_func_arg
|
||||
{
|
||||
ctf_id_t farg_type; /* Type identifier of the argument. */
|
||||
const char * farg_name; /* Name of the the argument. */
|
||||
uint32_t farg_name_offset; /* Offset of the name in str table. */
|
||||
struct ctf_func_arg * farg_next;/* A list node. */
|
||||
} ctf_func_arg_t;
|
||||
|
||||
#define ctf_farg_list_next(elem) ((ctf_func_arg_t *)((elem)->farg_next))
|
||||
|
||||
/* Type definition for CTF generation. */
|
||||
|
||||
struct GTY ((for_user)) ctf_dtdef
|
||||
{
|
||||
dw_die_ref dtd_key; /* Type key for hashing. */
|
||||
const char * dtd_name; /* Name associated with definition (if any). */
|
||||
ctf_id_t dtd_type; /* Type identifier for this definition. */
|
||||
ctf_itype_t dtd_data; /* Type node. */
|
||||
bool from_global_func; /* Whether this type was added from a global
|
||||
function. */
|
||||
union GTY ((desc ("ctf_dtu_d_union_selector (&%1)")))
|
||||
{
|
||||
/* struct, union, or enum. */
|
||||
ctf_dmdef_t * GTY ((tag ("CTF_DTU_D_MEMBERS"))) dtu_members;
|
||||
/* array. */
|
||||
ctf_arinfo_t GTY ((tag ("CTF_DTU_D_ARRAY"))) dtu_arr;
|
||||
/* integer or float. */
|
||||
ctf_encoding_t GTY ((tag ("CTF_DTU_D_ENCODING"))) dtu_enc;
|
||||
/* function. */
|
||||
ctf_func_arg_t * GTY ((tag ("CTF_DTU_D_ARGUMENTS"))) dtu_argv;
|
||||
/* slice. */
|
||||
ctf_sliceinfo_t GTY ((tag ("CTF_DTU_D_SLICE"))) dtu_slice;
|
||||
} dtd_u;
|
||||
};
|
||||
|
||||
typedef struct ctf_dtdef ctf_dtdef_t;
|
||||
|
||||
/* Variable definition for CTF generation. */
|
||||
|
||||
struct GTY ((for_user)) ctf_dvdef
|
||||
{
|
||||
dw_die_ref dvd_key; /* DWARF DIE corresponding to the variable. */
|
||||
const char * dvd_name; /* Name associated with variable. */
|
||||
uint32_t dvd_name_offset; /* Offset of the name in str table. */
|
||||
unsigned int dvd_visibility; /* External visibility. 0=static,1=global. */
|
||||
ctf_id_t dvd_type; /* Type of variable. */
|
||||
};
|
||||
|
||||
typedef struct ctf_dvdef ctf_dvdef_t;
|
||||
|
||||
typedef ctf_dvdef_t * ctf_dvdef_ref;
|
||||
typedef ctf_dtdef_t * ctf_dtdef_ref;
|
||||
|
||||
/* Location information for CTF Types and CTF Variables. */
|
||||
|
||||
typedef struct GTY (()) ctf_srcloc
|
||||
{
|
||||
const char * ctsloc_file;
|
||||
unsigned int ctsloc_line;
|
||||
unsigned int ctsloc_col;
|
||||
} ctf_srcloc_t;
|
||||
|
||||
typedef ctf_srcloc_t * ctf_srcloc_ref;
|
||||
|
||||
/* Helper enum and api for the GTY machinery to work on union dtu_d. */
|
||||
|
||||
enum ctf_dtu_d_union_enum {
|
||||
CTF_DTU_D_MEMBERS,
|
||||
CTF_DTU_D_ARRAY,
|
||||
CTF_DTU_D_ENCODING,
|
||||
CTF_DTU_D_ARGUMENTS,
|
||||
CTF_DTU_D_SLICE,
|
||||
};
|
||||
|
||||
enum ctf_dtu_d_union_enum
|
||||
ctf_dtu_d_union_selector (ctf_dtdef_ref);
|
||||
|
||||
struct ctfc_dtd_hasher : ggc_ptr_hash <ctf_dtdef_t>
|
||||
{
|
||||
typedef ctf_dtdef_ref compare_type;
|
||||
|
||||
static hashval_t hash (ctf_dtdef_ref);
|
||||
static bool equal (ctf_dtdef_ref, ctf_dtdef_ref);
|
||||
};
|
||||
|
||||
inline hashval_t
|
||||
ctfc_dtd_hasher::hash (ctf_dtdef_ref dtd)
|
||||
{
|
||||
return htab_hash_pointer (dtd->dtd_key);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ctfc_dtd_hasher::equal (ctf_dtdef_ref dtd, ctf_dtdef_ref dtd2)
|
||||
{
|
||||
return (dtd->dtd_key == dtd2->dtd_key);
|
||||
}
|
||||
|
||||
struct ctfc_dvd_hasher : ggc_ptr_hash <ctf_dvdef_t>
|
||||
{
|
||||
typedef ctf_dvdef_ref compare_type;
|
||||
|
||||
static hashval_t hash (ctf_dvdef_ref);
|
||||
static bool equal (ctf_dvdef_ref, ctf_dvdef_ref);
|
||||
};
|
||||
|
||||
inline hashval_t
|
||||
ctfc_dvd_hasher::hash (ctf_dvdef_ref dvd)
|
||||
{
|
||||
return htab_hash_pointer (dvd->dvd_key);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ctfc_dvd_hasher::equal (ctf_dvdef_ref dvd, ctf_dvdef_ref dvd2)
|
||||
{
|
||||
return (dvd->dvd_key == dvd2->dvd_key);
|
||||
}
|
||||
|
||||
/* CTF container structure.
|
||||
It is the context passed around when generating ctf debug info. There is
|
||||
one container per translation unit. */
|
||||
|
||||
typedef struct GTY (()) ctf_container
|
||||
{
|
||||
/* CTF Preamble. */
|
||||
unsigned short ctfc_magic;
|
||||
unsigned char ctfc_version;
|
||||
unsigned char ctfc_flags;
|
||||
uint32_t ctfc_cuname_offset;
|
||||
|
||||
/* CTF types. */
|
||||
hash_table <ctfc_dtd_hasher> * GTY (()) ctfc_types;
|
||||
/* CTF variables. */
|
||||
hash_table <ctfc_dvd_hasher> * GTY (()) ctfc_vars;
|
||||
|
||||
/* CTF string table. */
|
||||
ctf_strtable_t ctfc_strtable;
|
||||
/* Auxilliary string table. At this time, used for keeping func arg names
|
||||
for BTF. */
|
||||
ctf_strtable_t ctfc_aux_strtable;
|
||||
|
||||
uint64_t ctfc_num_types;
|
||||
uint64_t ctfc_num_stypes;
|
||||
uint64_t ctfc_num_global_funcs;
|
||||
uint64_t ctfc_num_global_objts;
|
||||
|
||||
/* Number of vlen bytes - the variable length portion after ctf_type_t and
|
||||
ctf_stype_t in the CTF section. This is used to calculate the offsets in
|
||||
the CTF header. */
|
||||
uint64_t ctfc_num_vlen_bytes;
|
||||
|
||||
/* Next CTF type id to assign. */
|
||||
ctf_id_t ctfc_nextid;
|
||||
|
||||
/* Specify an explicit length of 0 so that the GC marking routines steer
|
||||
clear of marking the CTF vars and CTF types twice. These lists below do
|
||||
not own the pointed to objects, they simply hold references to them. */
|
||||
|
||||
/* List of pre-processed CTF Variables. CTF requires that the variables
|
||||
appear in the sorted order of their names. */
|
||||
ctf_dvdef_t ** GTY ((length ("0"))) ctfc_vars_list;
|
||||
/* List of pre-processed CTF types. CTF requires that a shared type must
|
||||
appear before the type that uses it. For the compiler, this means types
|
||||
are emitted in sorted order of their type IDs. */
|
||||
ctf_dtdef_t ** GTY ((length ("0"))) ctfc_types_list;
|
||||
/* List of CTF function types for global functions. The order of global
|
||||
function entries in the CTF funcinfo section is undefined by the
|
||||
compiler. */
|
||||
ctf_dtdef_t ** GTY ((length ("0"))) ctfc_gfuncs_list;
|
||||
/* List of CTF variables at global scope. The order of global object entries
|
||||
in the CTF objinfo section is undefined by the compiler. */
|
||||
ctf_dvdef_t ** GTY ((length ("0"))) ctfc_gobjts_list;
|
||||
|
||||
/* Following members are for debugging only. They do not add functional
|
||||
value to the task of CTF creation. These can be cleaned up once CTF
|
||||
generation stabilizes. */
|
||||
|
||||
/* Keep a count of the number of bytes dumped in asm for debugging
|
||||
purposes. */
|
||||
uint64_t ctfc_numbytes_asm;
|
||||
/* Total length of all strings in CTF. */
|
||||
size_t ctfc_strlen;
|
||||
/* Total length of all strings in aux string table. */
|
||||
size_t ctfc_aux_strlen;
|
||||
|
||||
} ctf_container_t;
|
||||
|
||||
/* Markers for which string table from the CTF container to use. */
|
||||
|
||||
#define CTF_STRTAB 0 /* CTF string table. */
|
||||
#define CTF_AUX_STRTAB 1 /* CTF auxilliary string table. */
|
||||
|
||||
typedef ctf_container_t * ctf_container_ref;
|
||||
|
||||
extern GTY (()) ctf_container_ref tu_ctfc;
|
||||
|
||||
extern void ctfc_delete_container (ctf_container_ref);
|
||||
|
||||
/* If the next ctf type id is still set to the init value, no ctf records to
|
||||
report. */
|
||||
extern bool ctfc_is_empty_container (ctf_container_ref);
|
||||
|
||||
/* Get the total number of CTF types in the container. */
|
||||
|
||||
extern unsigned int ctfc_get_num_ctf_types (ctf_container_ref);
|
||||
|
||||
/* Get the total number of CTF variables in the container. */
|
||||
|
||||
extern unsigned int ctfc_get_num_ctf_vars (ctf_container_ref);
|
||||
|
||||
/* Get reference to the CTF string table or the CTF auxilliary
|
||||
string table. */
|
||||
|
||||
extern ctf_strtable_t * ctfc_get_strtab (ctf_container_ref, int);
|
||||
|
||||
/* Get the length of the specified string table in the CTF container. */
|
||||
|
||||
extern size_t ctfc_get_strtab_len (ctf_container_ref, int);
|
||||
|
||||
/* Get the number of bytes to represent the variable length portion of all CTF
|
||||
types in the CTF container. */
|
||||
|
||||
extern size_t ctfc_get_num_vlen_bytes (ctf_container_ref);
|
||||
|
||||
/* The compiler demarcates whether types are visible at top-level scope or not.
|
||||
The only example so far of a type not visible at top-level scope is slices.
|
||||
CTF_ADD_NONROOT is used to indicate the latter. */
|
||||
#define CTF_ADD_NONROOT 0 /* CTF type only visible in nested scope. */
|
||||
#define CTF_ADD_ROOT 1 /* CTF type visible at top-level scope. */
|
||||
|
||||
/* These APIs allow to initialize and finalize the CTF machinery and
|
||||
to add types to the CTF container associated to the current
|
||||
translation unit. Used in dwarf2ctf.c. */
|
||||
|
||||
extern void ctf_init (void);
|
||||
extern void ctf_output (const char * filename);
|
||||
extern void ctf_finalize (void);
|
||||
|
||||
extern void btf_output (const char * filename);
|
||||
extern void btf_init_postprocess (void);
|
||||
extern void btf_finalize (void);
|
||||
|
||||
extern ctf_container_ref ctf_get_tu_ctfc (void);
|
||||
|
||||
extern bool ctf_type_exists (ctf_container_ref, dw_die_ref, ctf_id_t *);
|
||||
|
||||
extern void ctf_add_cuname (ctf_container_ref, const char *);
|
||||
|
||||
extern ctf_dvdef_ref ctf_dvd_lookup (const ctf_container_ref, dw_die_ref);
|
||||
|
||||
extern const char * ctf_add_string (ctf_container_ref, const char *,
|
||||
uint32_t *, int);
|
||||
|
||||
extern ctf_id_t ctf_add_reftype (ctf_container_ref, uint32_t, ctf_id_t,
|
||||
uint32_t, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *,
|
||||
HOST_WIDE_INT, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t,
|
||||
uint32_t, uint32_t, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_float (ctf_container_ref, uint32_t, const char *,
|
||||
const ctf_encoding_t *, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_integer (ctf_container_ref, uint32_t, const char *,
|
||||
const ctf_encoding_t *, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_unknown (ctf_container_ref, uint32_t, const char *,
|
||||
const ctf_encoding_t *, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_pointer (ctf_container_ref, uint32_t, ctf_id_t,
|
||||
dw_die_ref);
|
||||
extern ctf_id_t ctf_add_array (ctf_container_ref, uint32_t,
|
||||
const ctf_arinfo_t *, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *,
|
||||
uint32_t, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *,
|
||||
ctf_id_t, dw_die_ref);
|
||||
extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *,
|
||||
const ctf_funcinfo_t *, dw_die_ref, bool);
|
||||
extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *,
|
||||
uint32_t, size_t, dw_die_ref);
|
||||
|
||||
extern int ctf_add_enumerator (ctf_container_ref, ctf_id_t, const char *,
|
||||
HOST_WIDE_INT, dw_die_ref);
|
||||
extern int ctf_add_member_offset (ctf_container_ref, dw_die_ref, const char *,
|
||||
ctf_id_t, uint64_t);
|
||||
extern int ctf_add_function_arg (ctf_container_ref, dw_die_ref,
|
||||
const char *, ctf_id_t);
|
||||
extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t,
|
||||
dw_die_ref, unsigned int);
|
||||
|
||||
/* CTF section does not emit location information; at this time, location
|
||||
information is needed for BTF CO-RE use-cases. */
|
||||
|
||||
extern int ctfc_get_dtd_srcloc (ctf_dtdef_ref, ctf_srcloc_ref);
|
||||
extern int ctfc_get_dvd_srcloc (ctf_dvdef_ref, ctf_srcloc_ref);
|
||||
|
||||
#endif /* GCC_CTFC_H */
|
830
gcc/ctfout.c
Normal file
830
gcc/ctfout.c
Normal file
|
@ -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"
|
|
@ -3558,7 +3558,7 @@ dwarf2out_do_frame (void)
|
|||
/* We want to emit correct CFA location expressions or lists, so we
|
||||
have to return true if we're going to generate debug info, even if
|
||||
we're not going to output frame or unwind info. */
|
||||
if (dwarf_debuginfo_p ())
|
||||
if (dwarf_debuginfo_p () || dwarf_based_debuginfo_p ())
|
||||
return true;
|
||||
|
||||
if (saved_do_cfi_asm > 0)
|
||||
|
|
990
gcc/dwarf2ctf.c
Normal file
990
gcc/dwarf2ctf.c
Normal file
|
@ -0,0 +1,990 @@
|
|||
/* Generate CTF types and objects from the GCC DWARF.
|
||||
Copyright (C) 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 "dwarf2out.h"
|
||||
#include "dwarf2out.h"
|
||||
|
||||
#include "dwarf2ctf.h"
|
||||
#include "ctfc.h"
|
||||
|
||||
/* Forward declarations for some routines defined in this file. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_type (ctf_container_ref, dw_die_ref);
|
||||
|
||||
/* All the DIE structures we handle come from the DWARF information
|
||||
generated by GCC. However, there are two situations where we need
|
||||
to create our own created DIE structures because GCC doesn't
|
||||
provide them.
|
||||
|
||||
The DWARF spec suggests using a DIE with DW_TAG_unspecified_type
|
||||
and name "void" in order to denote the void type. But GCC doesn't
|
||||
follow this advice. Still we need a DIE to act as a key for void
|
||||
types, we use ctf_void_die.
|
||||
|
||||
Also, if a subrange type corresponding to an array index does not
|
||||
specify a type then we assume it is `int'.
|
||||
|
||||
Finally, for types unrepresentable in CTF, we need a DIE to anchor
|
||||
them to a CTF type of kind unknown.
|
||||
|
||||
The variables below are initialized in ctf_debug_init and hold
|
||||
references to the proper DIEs. */
|
||||
|
||||
static GTY (()) dw_die_ref ctf_void_die;
|
||||
static GTY (()) dw_die_ref ctf_array_index_die;
|
||||
static GTY (()) dw_die_ref ctf_unknown_die;
|
||||
|
||||
/* Some DIEs have a type description attribute, stored in a DW_AT_type
|
||||
attribute. However, GCC generates no attribute to signify a `void'
|
||||
type.
|
||||
|
||||
This can happen in many contexts (return type of a function,
|
||||
pointed or qualified type, etc) so we use the `ctf_get_AT_type'
|
||||
function below abstracts this. */
|
||||
|
||||
static dw_die_ref
|
||||
ctf_get_AT_type (dw_die_ref die)
|
||||
{
|
||||
dw_die_ref type_die = get_AT_ref (die, DW_AT_type);
|
||||
return (type_die ? type_die : ctf_void_die);
|
||||
}
|
||||
|
||||
/* Some data member DIEs have location specified as a DWARF expression
|
||||
(specifically in DWARF2). Luckily, the expression is a simple
|
||||
DW_OP_plus_uconst with one operand set to zero.
|
||||
|
||||
Sometimes the data member location may also be negative. In yet some other
|
||||
cases (specifically union data members), the data member location is
|
||||
non-existent. Handle all these scenarios here to abstract this. */
|
||||
|
||||
static HOST_WIDE_INT
|
||||
ctf_get_AT_data_member_location (dw_die_ref die)
|
||||
{
|
||||
HOST_WIDE_INT field_location = 0;
|
||||
dw_attr_node * attr;
|
||||
|
||||
/* The field location (in bits) can be determined from
|
||||
either a DW_AT_data_member_location attribute or a
|
||||
DW_AT_data_bit_offset attribute. */
|
||||
if (get_AT (die, DW_AT_data_bit_offset))
|
||||
field_location = get_AT_unsigned (die, DW_AT_data_bit_offset);
|
||||
else
|
||||
{
|
||||
attr = get_AT (die, DW_AT_data_member_location);
|
||||
if (attr && AT_class (attr) == dw_val_class_loc)
|
||||
{
|
||||
dw_loc_descr_ref descr = AT_loc (attr);
|
||||
/* Operand 2 must be zero; the structure is assumed to be on the
|
||||
stack in DWARF2. */
|
||||
gcc_assert (!descr->dw_loc_oprnd2.v.val_unsigned);
|
||||
gcc_assert (descr->dw_loc_oprnd2.val_class
|
||||
== dw_val_class_unsigned_const);
|
||||
field_location = descr->dw_loc_oprnd1.v.val_unsigned;
|
||||
}
|
||||
else
|
||||
{
|
||||
attr = get_AT (die, DW_AT_data_member_location);
|
||||
if (attr && AT_class (attr) == dw_val_class_const)
|
||||
field_location = AT_int (attr);
|
||||
else
|
||||
field_location = (get_AT_unsigned (die,
|
||||
DW_AT_data_member_location)
|
||||
* 8);
|
||||
}
|
||||
}
|
||||
|
||||
return field_location;
|
||||
}
|
||||
|
||||
/* CTF Types' and CTF Variables' Location Information. CTF section does not
|
||||
emit location information, this is provided for BTF CO-RE use-cases. These
|
||||
functions fetch information from DWARF Die directly, as such the location
|
||||
information is not buffered in the CTF container. */
|
||||
|
||||
const char *
|
||||
ctf_get_die_loc_file (dw_die_ref die)
|
||||
{
|
||||
if (!die)
|
||||
return NULL;
|
||||
|
||||
struct dwarf_file_data * file;
|
||||
file = get_AT_file (die, DW_AT_decl_file);
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
return file->filename;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ctf_get_die_loc_line (dw_die_ref die)
|
||||
{
|
||||
if (!die)
|
||||
return 0;
|
||||
|
||||
return get_AT_unsigned (die, DW_AT_decl_line);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ctf_get_die_loc_col (dw_die_ref die)
|
||||
{
|
||||
if (!die)
|
||||
return 0;
|
||||
|
||||
return get_AT_unsigned (die, DW_AT_decl_column);
|
||||
}
|
||||
|
||||
/* Generate CTF for the void type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_void_type (ctf_container_ref ctfc)
|
||||
{
|
||||
ctf_encoding_t ctf_encoding = {0, 0, 0};
|
||||
|
||||
/* In CTF the void type is encoded as a 0-byte signed integer
|
||||
type. */
|
||||
|
||||
ctf_encoding.cte_bits = 0;
|
||||
ctf_encoding.cte_format = CTF_INT_SIGNED;
|
||||
|
||||
gcc_assert (ctf_void_die != NULL);
|
||||
return ctf_add_integer (ctfc, CTF_ADD_ROOT, "void",
|
||||
&ctf_encoding, ctf_void_die);
|
||||
}
|
||||
|
||||
/* Generate CTF type of unknown kind. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_unknown_type (ctf_container_ref ctfc)
|
||||
{
|
||||
ctf_id_t unknown_type_id;
|
||||
|
||||
/* In CTF, the unknown type is encoded as a 0 byte sized type with kind
|
||||
CTF_K_UNKNOWN. Create an encoding object merely to reuse the underlying
|
||||
ctf_add_encoded interface; the CTF encoding object is not 'used' any more
|
||||
than just the generation of size from. */
|
||||
ctf_encoding_t ctf_encoding = {0, 0, 0};
|
||||
|
||||
gcc_assert (ctf_unknown_die != NULL);
|
||||
/* Type de-duplication. */
|
||||
if (!ctf_type_exists (ctfc, ctf_unknown_die, &unknown_type_id))
|
||||
unknown_type_id = ctf_add_unknown (ctfc, CTF_ADD_ROOT, "unknown",
|
||||
&ctf_encoding, ctf_unknown_die);
|
||||
|
||||
return unknown_type_id;
|
||||
}
|
||||
|
||||
/* Sizes of entities can be given in bytes or bits. This function
|
||||
abstracts this by returning the size in bits of the given entity.
|
||||
If no DW_AT_byte_size nor DW_AT_bit_size are defined, this function
|
||||
returns 0. */
|
||||
|
||||
static uint32_t
|
||||
ctf_die_bitsize (dw_die_ref die)
|
||||
{
|
||||
dw_attr_node *attr_byte_size = get_AT (die, DW_AT_byte_size);
|
||||
dw_attr_node *attr_bit_size = get_AT (die, DW_AT_bit_size);
|
||||
|
||||
if (attr_bit_size)
|
||||
return AT_unsigned (attr_bit_size);
|
||||
else if (attr_byte_size)
|
||||
return (AT_unsigned (attr_byte_size) * 8);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate CTF for base type (integer, boolean, real, fixed point and complex).
|
||||
Important: the caller of this API must make sure that duplicate types are
|
||||
not added. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_base_type (ctf_container_ref ctfc, dw_die_ref type)
|
||||
{
|
||||
ctf_id_t type_id = CTF_NULL_TYPEID;
|
||||
|
||||
ctf_encoding_t ctf_encoding = {0, 0, 0};
|
||||
|
||||
unsigned int encoding = get_AT_unsigned (type, DW_AT_encoding);
|
||||
unsigned int bit_size = ctf_die_bitsize (type);
|
||||
const char * name_string = get_AT_string (type, DW_AT_name);
|
||||
|
||||
switch (encoding)
|
||||
{
|
||||
case DW_ATE_void:
|
||||
|
||||
ctf_encoding.cte_format = CTF_INT_SIGNED;
|
||||
ctf_encoding.cte_bits = 0;
|
||||
|
||||
gcc_assert (name_string);
|
||||
type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
|
||||
&ctf_encoding, type);
|
||||
|
||||
break;
|
||||
case DW_ATE_boolean:
|
||||
|
||||
ctf_encoding.cte_format = CTF_INT_BOOL;
|
||||
ctf_encoding.cte_bits = bit_size;
|
||||
|
||||
gcc_assert (name_string);
|
||||
type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
|
||||
&ctf_encoding, type);
|
||||
break;
|
||||
case DW_ATE_float:
|
||||
{
|
||||
unsigned int float_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (float_type_node));
|
||||
unsigned int double_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (double_type_node));
|
||||
unsigned int long_double_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (long_double_type_node));
|
||||
|
||||
if (bit_size == float_bit_size)
|
||||
ctf_encoding.cte_format = CTF_FP_SINGLE;
|
||||
else if (bit_size == double_bit_size)
|
||||
ctf_encoding.cte_format = CTF_FP_DOUBLE;
|
||||
else if (bit_size == long_double_bit_size)
|
||||
ctf_encoding.cte_format = CTF_FP_LDOUBLE;
|
||||
else
|
||||
/* CTF does not have representation for other types. Skip them. */
|
||||
break;
|
||||
|
||||
ctf_encoding.cte_bits = bit_size;
|
||||
type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
|
||||
&ctf_encoding, type);
|
||||
|
||||
break;
|
||||
}
|
||||
case DW_ATE_signed_char:
|
||||
/* FALLTHROUGH */
|
||||
case DW_ATE_unsigned_char:
|
||||
/* FALLTHROUGH */
|
||||
case DW_ATE_signed:
|
||||
/* FALLTHROUGH */
|
||||
case DW_ATE_unsigned:
|
||||
|
||||
if (encoding == DW_ATE_signed_char
|
||||
|| encoding == DW_ATE_unsigned_char)
|
||||
ctf_encoding.cte_format |= CTF_INT_CHAR;
|
||||
|
||||
if (encoding == DW_ATE_signed
|
||||
|| encoding == DW_ATE_signed_char)
|
||||
ctf_encoding.cte_format |= CTF_INT_SIGNED;
|
||||
|
||||
ctf_encoding.cte_bits = bit_size;
|
||||
type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string,
|
||||
&ctf_encoding, type);
|
||||
break;
|
||||
|
||||
case DW_ATE_complex_float:
|
||||
{
|
||||
unsigned int float_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (float_type_node));
|
||||
unsigned int double_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (double_type_node));
|
||||
unsigned int long_double_bit_size
|
||||
= tree_to_uhwi (TYPE_SIZE (long_double_type_node));
|
||||
|
||||
if (bit_size == float_bit_size * 2)
|
||||
ctf_encoding.cte_format = CTF_FP_CPLX;
|
||||
else if (bit_size == double_bit_size * 2)
|
||||
ctf_encoding.cte_format = CTF_FP_DCPLX;
|
||||
else if (bit_size == long_double_bit_size * 2)
|
||||
ctf_encoding.cte_format = CTF_FP_LDCPLX;
|
||||
else
|
||||
/* CTF does not have representation for other types. Skip them. */
|
||||
break;
|
||||
|
||||
ctf_encoding.cte_bits = bit_size;
|
||||
type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string,
|
||||
&ctf_encoding, type);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Ignore. */
|
||||
break;
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for a pointer type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_pointer_type (ctf_container_ref ctfc, dw_die_ref ptr_type)
|
||||
{
|
||||
ctf_id_t type_id = CTF_NULL_TYPEID;
|
||||
ctf_id_t ptr_type_id = CTF_NULL_TYPEID;
|
||||
dw_die_ref pointed_type_die = ctf_get_AT_type (ptr_type);
|
||||
|
||||
type_id = gen_ctf_type (ctfc, pointed_type_die);
|
||||
|
||||
/* Type de-duplication.
|
||||
Consult the ctfc_types hash again before adding the CTF pointer type
|
||||
because there can be cases where a pointer type may have been added by
|
||||
the gen_ctf_type call above. */
|
||||
if (ctf_type_exists (ctfc, ptr_type, &ptr_type_id))
|
||||
return ptr_type_id;
|
||||
|
||||
ptr_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id, ptr_type);
|
||||
return ptr_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for an array type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_array_type (ctf_container_ref ctfc, dw_die_ref array_type)
|
||||
{
|
||||
dw_die_ref c;
|
||||
ctf_id_t array_elems_type_id = CTF_NULL_TYPEID;
|
||||
|
||||
int vector_type_p = get_AT_flag (array_type, DW_AT_GNU_vector);
|
||||
if (vector_type_p)
|
||||
return array_elems_type_id;
|
||||
|
||||
dw_die_ref array_elems_type = ctf_get_AT_type (array_type);
|
||||
|
||||
/* First, register the type of the array elements if needed. */
|
||||
array_elems_type_id = gen_ctf_type (ctfc, array_elems_type);
|
||||
|
||||
/* DWARF array types pretend C supports multi-dimensional arrays.
|
||||
So for the type int[N][M], the array type DIE contains two
|
||||
subrange_type children, the first iwth upper bound N-1 and the
|
||||
second with upper bound M-1.
|
||||
|
||||
CTF, on the other hand, just encodes each array type in its own
|
||||
array type CTF struct. Therefore we have to iterate on the
|
||||
children and create all the needed types. */
|
||||
|
||||
c = dw_get_die_child (array_type);
|
||||
gcc_assert (c);
|
||||
do
|
||||
{
|
||||
ctf_arinfo_t arinfo;
|
||||
dw_die_ref array_index_type;
|
||||
uint32_t array_num_elements;
|
||||
|
||||
c = dw_get_die_sib (c);
|
||||
|
||||
if (dw_get_die_tag (c) == DW_TAG_subrange_type)
|
||||
{
|
||||
dw_attr_node *upper_bound_at;
|
||||
|
||||
array_index_type = ctf_get_AT_type (c);
|
||||
|
||||
/* When DW_AT_upper_bound is used to specify the size of an
|
||||
array in DWARF, it is usually an unsigned constant
|
||||
specifying the upper bound index of the array. However,
|
||||
for unsized arrays, such as foo[] or bar[0],
|
||||
DW_AT_upper_bound is a signed integer constant
|
||||
instead. */
|
||||
|
||||
upper_bound_at = get_AT (c, DW_AT_upper_bound);
|
||||
if (upper_bound_at
|
||||
&& AT_class (upper_bound_at) == dw_val_class_unsigned_const)
|
||||
/* This is the upper bound index. */
|
||||
array_num_elements = get_AT_unsigned (c, DW_AT_upper_bound) + 1;
|
||||
else if (get_AT (c, DW_AT_count))
|
||||
array_num_elements = get_AT_unsigned (c, DW_AT_count);
|
||||
else
|
||||
{
|
||||
/* This is a VLA of some kind. */
|
||||
array_num_elements = 0;
|
||||
}
|
||||
}
|
||||
else if (dw_get_die_tag (c) == DW_TAG_enumeration_type)
|
||||
{
|
||||
array_index_type = 0;
|
||||
array_num_elements = 0;
|
||||
/* XXX writeme. */
|
||||
gcc_assert (1);
|
||||
}
|
||||
else
|
||||
gcc_unreachable ();
|
||||
|
||||
/* Ok, mount and register the array type. Note how the array
|
||||
type we register here is the type of the elements in
|
||||
subsequent "dimensions", if there are any. */
|
||||
|
||||
arinfo.ctr_nelems = array_num_elements;
|
||||
if (array_index_type)
|
||||
arinfo.ctr_index = gen_ctf_type (ctfc, array_index_type);
|
||||
else
|
||||
arinfo.ctr_index = gen_ctf_type (ctfc, ctf_array_index_die);
|
||||
|
||||
arinfo.ctr_contents = array_elems_type_id;
|
||||
if (!ctf_type_exists (ctfc, c, &array_elems_type_id))
|
||||
array_elems_type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo,
|
||||
c);
|
||||
}
|
||||
while (c != dw_get_die_child (array_type));
|
||||
|
||||
#if 0
|
||||
/* Type de-duplication.
|
||||
Consult the ctfc_types hash again before adding the CTF array type because
|
||||
there can be cases where an array_type type may have been added by the
|
||||
gen_ctf_type call above. */
|
||||
if (!ctf_type_exists (ctfc, array_type, &type_id))
|
||||
type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, array_type);
|
||||
#endif
|
||||
|
||||
return array_elems_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for a typedef. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_typedef (ctf_container_ref ctfc, dw_die_ref tdef)
|
||||
{
|
||||
ctf_id_t tdef_type_id, tid;
|
||||
const char *tdef_name = get_AT_string (tdef, DW_AT_name);
|
||||
dw_die_ref tdef_type = ctf_get_AT_type (tdef);
|
||||
|
||||
tid = gen_ctf_type (ctfc, tdef_type);
|
||||
|
||||
/* Type de-duplication.
|
||||
This is necessary because the ctf for the typedef may have been already
|
||||
added due to the gen_ctf_type call above. */
|
||||
if (!ctf_type_exists (ctfc, tdef, &tdef_type_id))
|
||||
{
|
||||
tdef_type_id = ctf_add_typedef (ctfc, CTF_ADD_ROOT,
|
||||
tdef_name,
|
||||
tid,
|
||||
tdef);
|
||||
}
|
||||
return tdef_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for a type modifier.
|
||||
|
||||
If the given DIE contains a valid C modifier (like _Atomic), which is not
|
||||
supported by CTF, then this function skips the modifier die and continues
|
||||
with the underlying type.
|
||||
|
||||
For all other cases, this function returns a CTF_NULL_TYPEID;
|
||||
*/
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_modifier_type (ctf_container_ref ctfc, dw_die_ref modifier)
|
||||
{
|
||||
uint32_t kind = CTF_K_MAX;
|
||||
ctf_id_t modifier_type_id, qual_type_id;
|
||||
dw_die_ref qual_type = ctf_get_AT_type (modifier);
|
||||
|
||||
switch (dw_get_die_tag (modifier))
|
||||
{
|
||||
case DW_TAG_const_type: kind = CTF_K_CONST; break;
|
||||
case DW_TAG_volatile_type: kind = CTF_K_VOLATILE; break;
|
||||
case DW_TAG_restrict_type: kind = CTF_K_RESTRICT; break;
|
||||
case DW_TAG_atomic_type: break;
|
||||
default:
|
||||
return CTF_NULL_TYPEID;
|
||||
}
|
||||
|
||||
/* Register the type for which this modifier applies. */
|
||||
qual_type_id = gen_ctf_type (ctfc, qual_type);
|
||||
|
||||
/* Skip generating a CTF modifier record for _Atomic as there is no
|
||||
representation for it. */
|
||||
if (dw_get_die_tag (modifier) == DW_TAG_atomic_type)
|
||||
return qual_type_id;
|
||||
|
||||
gcc_assert (kind != CTF_K_MAX);
|
||||
/* Now register the modifier itself. */
|
||||
if (!ctf_type_exists (ctfc, modifier, &modifier_type_id))
|
||||
modifier_type_id = ctf_add_reftype (ctfc, CTF_ADD_ROOT,
|
||||
qual_type_id, kind,
|
||||
modifier);
|
||||
|
||||
return modifier_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for a struct type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_sou_type (ctf_container_ref ctfc, dw_die_ref sou, uint32_t kind)
|
||||
{
|
||||
uint32_t bit_size = ctf_die_bitsize (sou);
|
||||
int declaration_p = get_AT_flag (sou, DW_AT_declaration);
|
||||
const char *sou_name = get_AT_string (sou, DW_AT_name);
|
||||
|
||||
ctf_id_t sou_type_id;
|
||||
|
||||
/* An incomplete structure or union type is represented in DWARF by
|
||||
a structure or union DIE that does not have a size attribute and
|
||||
that has a DW_AT_declaration attribute. This corresponds to a
|
||||
CTF forward type with kind CTF_K_STRUCT. */
|
||||
if (bit_size == 0 && declaration_p)
|
||||
return ctf_add_forward (ctfc, CTF_ADD_ROOT,
|
||||
sou_name, kind, sou);
|
||||
|
||||
/* This is a complete struct or union type. Generate a CTF type for
|
||||
it if it doesn't exist already. */
|
||||
if (!ctf_type_exists (ctfc, sou, &sou_type_id))
|
||||
sou_type_id = ctf_add_sou (ctfc, CTF_ADD_ROOT,
|
||||
sou_name, kind, bit_size / 8,
|
||||
sou);
|
||||
|
||||
/* Now process the struct members. */
|
||||
{
|
||||
dw_die_ref c;
|
||||
|
||||
c = dw_get_die_child (sou);
|
||||
if (c)
|
||||
do
|
||||
{
|
||||
const char *field_name;
|
||||
dw_die_ref field_type;
|
||||
HOST_WIDE_INT field_location;
|
||||
ctf_id_t field_type_id;
|
||||
|
||||
c = dw_get_die_sib (c);
|
||||
|
||||
field_name = get_AT_string (c, DW_AT_name);
|
||||
field_type = ctf_get_AT_type (c);
|
||||
field_location = ctf_get_AT_data_member_location (c);
|
||||
|
||||
/* Generate the field type. */
|
||||
field_type_id = gen_ctf_type (ctfc, field_type);
|
||||
|
||||
/* If this is a bit-field, then wrap the field type
|
||||
generated above with a CTF slice. */
|
||||
if (get_AT (c, DW_AT_bit_offset)
|
||||
|| get_AT (c, DW_AT_data_bit_offset))
|
||||
{
|
||||
dw_attr_node *attr;
|
||||
HOST_WIDE_INT bitpos = 0;
|
||||
HOST_WIDE_INT bitsize = ctf_die_bitsize (c);
|
||||
HOST_WIDE_INT bit_offset;
|
||||
|
||||
/* The bit offset is given in bits and it may be
|
||||
negative. */
|
||||
attr = get_AT (c, DW_AT_bit_offset);
|
||||
if (attr)
|
||||
{
|
||||
if (AT_class (attr) == dw_val_class_unsigned_const)
|
||||
bit_offset = AT_unsigned (attr);
|
||||
else
|
||||
bit_offset = AT_int (attr);
|
||||
|
||||
if (BYTES_BIG_ENDIAN)
|
||||
bitpos = field_location + bit_offset;
|
||||
else
|
||||
{
|
||||
HOST_WIDE_INT bit_size;
|
||||
|
||||
attr = get_AT (c, DW_AT_byte_size);
|
||||
if (attr)
|
||||
/* Explicit size given in bytes. */
|
||||
bit_size = AT_unsigned (attr) * 8;
|
||||
else
|
||||
/* Infer the size from the member type. */
|
||||
bit_size = ctf_die_bitsize (field_type);
|
||||
|
||||
bitpos = (field_location
|
||||
+ bit_size
|
||||
- bit_offset
|
||||
- bitsize);
|
||||
}
|
||||
}
|
||||
|
||||
/* In DWARF5 a data_bit_offset attribute is given with
|
||||
the offset of the data from the beginning of the
|
||||
struct. Acknowledge it if present. */
|
||||
attr = get_AT (c, DW_AT_data_bit_offset);
|
||||
if (attr)
|
||||
bitpos += AT_unsigned (attr);
|
||||
|
||||
field_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT,
|
||||
field_type_id,
|
||||
bitpos - field_location,
|
||||
bitsize,
|
||||
c);
|
||||
}
|
||||
|
||||
/* Add the field type to the struct or union type. */
|
||||
ctf_add_member_offset (ctfc, sou,
|
||||
field_name,
|
||||
field_type_id,
|
||||
field_location);
|
||||
}
|
||||
while (c != dw_get_die_child (sou));
|
||||
}
|
||||
|
||||
return sou_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for a function type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_function_type (ctf_container_ref ctfc, dw_die_ref function,
|
||||
bool from_global_func)
|
||||
{
|
||||
const char *function_name = get_AT_string (function, DW_AT_name);
|
||||
dw_die_ref return_type = ctf_get_AT_type (function);
|
||||
|
||||
ctf_funcinfo_t func_info;
|
||||
uint32_t num_args = 0;
|
||||
|
||||
ctf_id_t return_type_id;
|
||||
ctf_id_t function_type_id;
|
||||
|
||||
/* First, add the return type. */
|
||||
return_type_id = gen_ctf_type (ctfc, return_type);
|
||||
func_info.ctc_return = return_type_id;
|
||||
|
||||
/* Type de-duplication.
|
||||
Consult the ctfc_types hash before adding the CTF function type. */
|
||||
if (ctf_type_exists (ctfc, function, &function_type_id))
|
||||
return function_type_id;
|
||||
|
||||
/* Do a first pass on the formals to determine the number of
|
||||
arguments, and whether the function type gets a varargs. */
|
||||
{
|
||||
dw_die_ref c;
|
||||
|
||||
c = dw_get_die_child (function);
|
||||
if (c)
|
||||
do
|
||||
{
|
||||
c = dw_get_die_sib (c);
|
||||
|
||||
if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
|
||||
num_args += 1;
|
||||
else if (dw_get_die_tag (c) == DW_TAG_unspecified_parameters)
|
||||
{
|
||||
func_info.ctc_flags |= CTF_FUNC_VARARG;
|
||||
num_args += 1;
|
||||
}
|
||||
}
|
||||
while (c != dw_get_die_child (function));
|
||||
}
|
||||
|
||||
/* Note the number of typed arguments _includes_ the vararg. */
|
||||
func_info.ctc_argc = num_args;
|
||||
|
||||
/* Type de-duplication has already been performed by now. */
|
||||
function_type_id = ctf_add_function (ctfc, CTF_ADD_ROOT,
|
||||
function_name,
|
||||
(const ctf_funcinfo_t *)&func_info,
|
||||
function,
|
||||
from_global_func);
|
||||
|
||||
/* Second pass on formals: generate the CTF types corresponding to
|
||||
them and add them as CTF function args. */
|
||||
{
|
||||
dw_die_ref c;
|
||||
unsigned int i = 0;
|
||||
const char *arg_name;
|
||||
ctf_id_t arg_type;
|
||||
|
||||
c = dw_get_die_child (function);
|
||||
if (c)
|
||||
do
|
||||
{
|
||||
c = dw_get_die_sib (c);
|
||||
|
||||
if (dw_get_die_tag (c) == DW_TAG_unspecified_parameters)
|
||||
{
|
||||
gcc_assert (i == num_args - 1);
|
||||
/* Add an argument with type 0 and no name. */
|
||||
ctf_add_function_arg (ctfc, function, "", 0);
|
||||
}
|
||||
else if (dw_get_die_tag (c) == DW_TAG_formal_parameter)
|
||||
{
|
||||
i++;
|
||||
arg_name = get_AT_string (c, DW_AT_name);
|
||||
arg_type = gen_ctf_type (ctfc, ctf_get_AT_type (c));
|
||||
/* Add the argument to the existing CTF function type. */
|
||||
ctf_add_function_arg (ctfc, function, arg_name, arg_type);
|
||||
}
|
||||
else
|
||||
/* This is a local variable. Ignore. */
|
||||
continue;
|
||||
}
|
||||
while (c != dw_get_die_child (function));
|
||||
}
|
||||
|
||||
return function_type_id;
|
||||
}
|
||||
|
||||
/* Generate CTF for an enumeration type. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_enumeration_type (ctf_container_ref ctfc, dw_die_ref enumeration)
|
||||
{
|
||||
const char *enum_name = get_AT_string (enumeration, DW_AT_name);
|
||||
unsigned int bit_size = ctf_die_bitsize (enumeration);
|
||||
int declaration_p = get_AT_flag (enumeration, DW_AT_declaration);
|
||||
|
||||
ctf_id_t enumeration_type_id;
|
||||
|
||||
/* If this is an incomplete enum, generate a CTF forward for it and
|
||||
be done. */
|
||||
if (declaration_p)
|
||||
{
|
||||
gcc_assert (enum_name);
|
||||
return ctf_add_forward (ctfc, CTF_ADD_ROOT, enum_name,
|
||||
CTF_K_ENUM, enumeration);
|
||||
}
|
||||
|
||||
/* If the size the enumerators is not specified then use the size of
|
||||
the underlying type, which must be a base type. */
|
||||
if (bit_size == 0)
|
||||
{
|
||||
dw_die_ref type = ctf_get_AT_type (enumeration);
|
||||
bit_size = ctf_die_bitsize (type);
|
||||
}
|
||||
|
||||
/* Generate a CTF type for the enumeration. */
|
||||
enumeration_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT,
|
||||
enum_name, bit_size / 8, enumeration);
|
||||
|
||||
/* Process the enumerators. */
|
||||
{
|
||||
dw_die_ref c;
|
||||
|
||||
c = dw_get_die_child (enumeration);
|
||||
if (c)
|
||||
do
|
||||
{
|
||||
const char *enumerator_name;
|
||||
dw_attr_node *enumerator_value;
|
||||
HOST_WIDE_INT value_wide_int;
|
||||
|
||||
c = dw_get_die_sib (c);
|
||||
|
||||
enumerator_name = get_AT_string (c, DW_AT_name);
|
||||
enumerator_value = get_AT (c, DW_AT_const_value);
|
||||
|
||||
/* enumerator_value can be either a signed or an unsigned
|
||||
constant value. */
|
||||
if (AT_class (enumerator_value) == dw_val_class_unsigned_const
|
||||
|| (AT_class (enumerator_value)
|
||||
== dw_val_class_unsigned_const_implicit))
|
||||
value_wide_int = AT_unsigned (enumerator_value);
|
||||
else
|
||||
value_wide_int = AT_int (enumerator_value);
|
||||
|
||||
ctf_add_enumerator (ctfc, enumeration_type_id,
|
||||
enumerator_name, value_wide_int, enumeration);
|
||||
}
|
||||
while (c != dw_get_die_child (enumeration));
|
||||
}
|
||||
|
||||
return enumeration_type_id;
|
||||
}
|
||||
|
||||
/* Add a CTF variable record for the given input DWARF DIE. */
|
||||
|
||||
static void
|
||||
gen_ctf_variable (ctf_container_ref ctfc, dw_die_ref die)
|
||||
{
|
||||
const char *var_name = get_AT_string (die, DW_AT_name);
|
||||
dw_die_ref var_type = ctf_get_AT_type (die);
|
||||
unsigned int external_vis = get_AT_flag (die, DW_AT_external);
|
||||
ctf_id_t var_type_id;
|
||||
|
||||
/* Avoid duplicates. */
|
||||
if (ctf_dvd_lookup (ctfc, die))
|
||||
return;
|
||||
|
||||
/* Add the type of the variable. */
|
||||
var_type_id = gen_ctf_type (ctfc, var_type);
|
||||
|
||||
/* Generate the new CTF variable and update global counter. */
|
||||
(void) ctf_add_variable (ctfc, var_name, var_type_id, die, external_vis);
|
||||
ctfc->ctfc_num_global_objts += 1;
|
||||
}
|
||||
|
||||
/* Add a CTF function record for the given input DWARF DIE. */
|
||||
|
||||
static void
|
||||
gen_ctf_function (ctf_container_ref ctfc, dw_die_ref die)
|
||||
{
|
||||
ctf_id_t function_type_id;
|
||||
/* Type de-duplication.
|
||||
Consult the ctfc_types hash before adding the CTF function type. */
|
||||
if (ctf_type_exists (ctfc, die, &function_type_id))
|
||||
return;
|
||||
|
||||
/* Add the type of the function and update the global functions
|
||||
counter. Note that DWARF encodes function types in both
|
||||
DW_TAG_subroutine_type and DW_TAG_subprogram in exactly the same
|
||||
way. */
|
||||
(void) gen_ctf_function_type (ctfc, die, true /* from_global_func */);
|
||||
ctfc->ctfc_num_global_funcs += 1;
|
||||
}
|
||||
|
||||
/* Add CTF type record(s) for the given input DWARF DIE and return its type id.
|
||||
|
||||
If there is already a CTF type corresponding to the given DIE, then
|
||||
this function returns the type id of the existing type.
|
||||
|
||||
If the given DIE is not recognized as a type, then this function
|
||||
returns CTF_NULL_TYPEID. */
|
||||
|
||||
static ctf_id_t
|
||||
gen_ctf_type (ctf_container_ref ctfc, dw_die_ref die)
|
||||
{
|
||||
ctf_id_t type_id;
|
||||
int unrecog_die = false;
|
||||
|
||||
if (ctf_type_exists (ctfc, die, &type_id))
|
||||
return type_id;
|
||||
|
||||
switch (dw_get_die_tag (die))
|
||||
{
|
||||
case DW_TAG_base_type:
|
||||
type_id = gen_ctf_base_type (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_pointer_type:
|
||||
type_id = gen_ctf_pointer_type (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_typedef:
|
||||
type_id = gen_ctf_typedef (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_array_type:
|
||||
type_id = gen_ctf_array_type (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_structure_type:
|
||||
type_id = gen_ctf_sou_type (ctfc, die, CTF_K_STRUCT);
|
||||
break;
|
||||
case DW_TAG_union_type:
|
||||
type_id = gen_ctf_sou_type (ctfc, die, CTF_K_UNION);
|
||||
break;
|
||||
case DW_TAG_subroutine_type:
|
||||
type_id = gen_ctf_function_type (ctfc, die,
|
||||
false /* from_global_func */);
|
||||
break;
|
||||
case DW_TAG_enumeration_type:
|
||||
type_id = gen_ctf_enumeration_type (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_atomic_type:
|
||||
/* FALLTHROUGH */
|
||||
case DW_TAG_const_type:
|
||||
/* FALLTHROUGH */
|
||||
case DW_TAG_restrict_type:
|
||||
/* FALLTHROUGH */
|
||||
case DW_TAG_volatile_type:
|
||||
type_id = gen_ctf_modifier_type (ctfc, die);
|
||||
break;
|
||||
case DW_TAG_unspecified_type:
|
||||
{
|
||||
const char *name = get_AT_string (die, DW_AT_name);
|
||||
|
||||
if (name && strcmp (name, "void") == 0)
|
||||
type_id = gen_ctf_void_type (ctfc);
|
||||
else
|
||||
type_id = CTF_NULL_TYPEID;
|
||||
|
||||
break;
|
||||
}
|
||||
case DW_TAG_reference_type:
|
||||
type_id = CTF_NULL_TYPEID;
|
||||
break;
|
||||
default:
|
||||
/* Unrecognized DIE. */
|
||||
unrecog_die = true;
|
||||
type_id = CTF_NULL_TYPEID;
|
||||
break;
|
||||
}
|
||||
|
||||
/* For all types unrepresented in CTF, use an explicit CTF type of kind
|
||||
CTF_K_UNKNOWN. */
|
||||
if ((type_id == CTF_NULL_TYPEID) && (!unrecog_die))
|
||||
type_id = gen_ctf_unknown_type (ctfc);
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
bool
|
||||
ctf_do_die (dw_die_ref die)
|
||||
{
|
||||
ctf_container_ref tu_ctfc = ctf_get_tu_ctfc ();
|
||||
|
||||
/* Note how we tell the caller to continue traversing children DIEs
|
||||
if this DIE didn't result in CTF records being added. */
|
||||
if (dw_get_die_tag (die) == DW_TAG_variable)
|
||||
{
|
||||
gen_ctf_variable (tu_ctfc, die);
|
||||
return false;
|
||||
}
|
||||
else if (dw_get_die_tag (die) == DW_TAG_subprogram)
|
||||
{
|
||||
gen_ctf_function (tu_ctfc, die);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return gen_ctf_type (tu_ctfc, die) == CTF_NULL_TYPEID;
|
||||
}
|
||||
|
||||
/* Initialize CTF subsystem for CTF debug info generation. */
|
||||
|
||||
void
|
||||
ctf_debug_init (void)
|
||||
{
|
||||
/* First, initialize the CTF subsystem. */
|
||||
ctf_init ();
|
||||
|
||||
/* Create a couple of DIE structures that we may need. */
|
||||
ctf_void_die = new_die_raw (DW_TAG_unspecified_type);
|
||||
add_name_attribute (ctf_void_die, "void");
|
||||
ctf_array_index_die
|
||||
= base_type_die (integer_type_node, 0 /* reverse */);
|
||||
add_name_attribute (ctf_array_index_die, "int");
|
||||
ctf_unknown_die = new_die_raw (DW_TAG_unspecified_type);
|
||||
add_name_attribute (ctf_unknown_die, "unknown");
|
||||
}
|
||||
|
||||
/* Preprocess the CTF debug information after initialization. */
|
||||
|
||||
void
|
||||
ctf_debug_init_postprocess (bool btf)
|
||||
{
|
||||
/* Only BTF requires postprocessing right after init. */
|
||||
if (btf)
|
||||
btf_init_postprocess ();
|
||||
}
|
||||
|
||||
/* Prepare for output and write out the CTF debug information. */
|
||||
|
||||
void
|
||||
ctf_debug_finalize (const char *filename, bool btf)
|
||||
{
|
||||
if (btf)
|
||||
{
|
||||
btf_output (filename);
|
||||
btf_finalize ();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* Emit the collected CTF information. */
|
||||
ctf_output (filename);
|
||||
|
||||
/* Reset the CTF state. */
|
||||
ctf_finalize ();
|
||||
}
|
||||
}
|
||||
|
||||
#include "gt-dwarf2ctf.h"
|
53
gcc/dwarf2ctf.h
Normal file
53
gcc/dwarf2ctf.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* dwarf2ctf.h - DWARF interface for CTF/BTF generation.
|
||||
Copyright (C) 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/>. */
|
||||
|
||||
/* This file contains declarations and prototypes to define an interface
|
||||
between DWARF and CTF/BTF generation. */
|
||||
|
||||
#ifndef GCC_DWARF2CTF_H
|
||||
#define GCC_DWARF2CTF_H 1
|
||||
|
||||
#include "dwarf2out.h"
|
||||
|
||||
/* Debug Format Interface. Used in dwarf2out.c. */
|
||||
|
||||
extern void ctf_debug_init (void);
|
||||
extern void ctf_debug_init_postprocess (bool);
|
||||
extern bool ctf_do_die (dw_die_ref);
|
||||
extern void ctf_debug_finalize (const char *, bool);
|
||||
|
||||
/* Wrappers for CTF/BTF to fetch information from GCC DWARF DIE. Used in
|
||||
ctfc.c.
|
||||
|
||||
A CTF container does not store all debug information internally. Some of
|
||||
the info is fetched indirectly via the DIE reference available in each CTF
|
||||
container entry.
|
||||
|
||||
These functions will be used by the CTF container to give access to its
|
||||
consumers (CTF/BTF) to various debug information available in DWARF DIE.
|
||||
Direct access to debug information in GCC dwarf structures by the consumers
|
||||
of CTF/BTF information is not ideal. */
|
||||
|
||||
/* Source location information. */
|
||||
|
||||
extern const char * ctf_get_die_loc_file (dw_die_ref);
|
||||
extern unsigned int ctf_get_die_loc_line (dw_die_ref);
|
||||
extern unsigned int ctf_get_die_loc_col (dw_die_ref);
|
||||
|
||||
#endif /* GCC_DWARF2CTF_H */
|
|
@ -79,6 +79,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "output.h"
|
||||
#include "expr.h"
|
||||
#include "dwarf2out.h"
|
||||
#include "dwarf2ctf.h"
|
||||
#include "dwarf2asm.h"
|
||||
#include "toplev.h"
|
||||
#include "md5.h"
|
||||
|
@ -28332,7 +28333,10 @@ dwarf2out_source_line (unsigned int line, unsigned int column,
|
|||
dw_line_info_table *table;
|
||||
static var_loc_view lvugid;
|
||||
|
||||
if (debug_info_level < DINFO_LEVEL_TERSE)
|
||||
/* 'line_info_table' information gathering is not needed when the debug
|
||||
info level is set to the lowest value. Also, the current DWARF-based
|
||||
debug formats do not use this info. */
|
||||
if (debug_info_level < DINFO_LEVEL_TERSE || !dwarf_debuginfo_p ())
|
||||
return;
|
||||
|
||||
table = cur_line_info_table;
|
||||
|
@ -31876,6 +31880,10 @@ dwarf2out_finish (const char *filename)
|
|||
unsigned char checksum[16];
|
||||
char dl_section_ref[MAX_ARTIFICIAL_LABEL_BYTES];
|
||||
|
||||
/* Skip emitting DWARF if not required. */
|
||||
if (!dwarf_debuginfo_p ())
|
||||
return;
|
||||
|
||||
/* Flush out any latecomers to the limbo party. */
|
||||
flush_limbo_die_list ();
|
||||
|
||||
|
@ -32631,6 +32639,19 @@ note_variable_value (dw_die_ref die)
|
|||
FOR_EACH_CHILD (die, c, note_variable_value (c));
|
||||
}
|
||||
|
||||
/* Process DWARF dies for CTF generation. */
|
||||
|
||||
static void
|
||||
ctf_debug_do_cu (dw_die_ref die)
|
||||
{
|
||||
dw_die_ref c;
|
||||
|
||||
if (!ctf_do_die (die))
|
||||
return;
|
||||
|
||||
FOR_EACH_CHILD (die, c, ctf_do_die (c));
|
||||
}
|
||||
|
||||
/* Perform any cleanups needed after the early debug generation pass
|
||||
has run. */
|
||||
|
||||
|
@ -32753,6 +32774,20 @@ dwarf2out_early_finish (const char *filename)
|
|||
print_die (comp_unit_die (), dump_file);
|
||||
}
|
||||
|
||||
/* Generate CTF/BTF debug info. */
|
||||
if ((ctf_debug_info_level > CTFINFO_LEVEL_NONE
|
||||
|| btf_debuginfo_p ()) && lang_GNU_C ())
|
||||
{
|
||||
ctf_debug_init ();
|
||||
ctf_debug_do_cu (comp_unit_die ());
|
||||
for (limbo_die_node *node = limbo_die_list; node; node = node->next)
|
||||
ctf_debug_do_cu (node->die);
|
||||
/* Post process the debug data in the CTF container if necessary. */
|
||||
ctf_debug_init_postprocess (btf_debuginfo_p ());
|
||||
/* Emit CTF/BTF debug info. */
|
||||
ctf_debug_finalize (filename, btf_debuginfo_p ());
|
||||
}
|
||||
|
||||
/* Do not generate DWARF assembler now when not producing LTO bytecode. */
|
||||
if ((!flag_generate_lto && !flag_generate_offload)
|
||||
/* FIXME: Disable debug info generation for (PE-)COFF targets since the
|
||||
|
|
|
@ -1429,7 +1429,7 @@ static bool
|
|||
dwarf2_debug_info_emitted_p (tree decl)
|
||||
{
|
||||
/* When DWARF2 debug info is not generated internally. */
|
||||
if (!dwarf_debuginfo_p ())
|
||||
if (!dwarf_debuginfo_p () && !dwarf_based_debuginfo_p ())
|
||||
return false;
|
||||
|
||||
if (DECL_IGNORED_P (decl))
|
||||
|
|
|
@ -29,7 +29,9 @@ enum debug_info_type
|
|||
DINFO_TYPE_DWARF2 = 2, /* Dwarf v2 debug info. */
|
||||
DINFO_TYPE_XCOFF = 3, /* IBM/Xcoff debug info. */
|
||||
DINFO_TYPE_VMS = 4, /* VMS debug info. */
|
||||
DINFO_TYPE_MAX = DINFO_TYPE_VMS /* Marker only. */
|
||||
DINFO_TYPE_CTF = 5, /* CTF debug info. */
|
||||
DINFO_TYPE_BTF = 6, /* BTF debug info. */
|
||||
DINFO_TYPE_MAX = DINFO_TYPE_BTF /* Marker only. */
|
||||
};
|
||||
|
||||
#define NO_DEBUG (0U)
|
||||
|
@ -41,6 +43,10 @@ enum debug_info_type
|
|||
#define XCOFF_DEBUG (1U << DINFO_TYPE_XCOFF)
|
||||
/* Write VMS debug info (using vmsdbgout.c). */
|
||||
#define VMS_DEBUG (1U << DINFO_TYPE_VMS)
|
||||
/* Write CTF debug info (using ctfout.c). */
|
||||
#define CTF_DEBUG (1U << DINFO_TYPE_CTF)
|
||||
/* Write BTF debug info (using btfout.c). */
|
||||
#define BTF_DEBUG (1U << DINFO_TYPE_BTF)
|
||||
/* Note: Adding new definitions to handle -combination- of debug formats,
|
||||
like VMS_AND_DWARF2_DEBUG is not recommended. This definition remains
|
||||
here for historical reasons. */
|
||||
|
@ -56,6 +62,19 @@ enum debug_info_levels
|
|||
DINFO_LEVEL_VERBOSE /* Write normal info plus #define/#undef info. */
|
||||
};
|
||||
|
||||
/* CTF debug info levels.
|
||||
CTF debug info levels are untied with DWARF debug info levels because CTF
|
||||
may co-exist with DWARF. */
|
||||
enum ctf_debug_info_levels
|
||||
{
|
||||
CTFINFO_LEVEL_NONE = 0, /* Write no CTF debug info. */
|
||||
CTFINFO_LEVEL_TERSE = 1, /* Write CTF information to support tracebacks
|
||||
only. Not Implemented. */
|
||||
CTFINFO_LEVEL_NORMAL = 2 /* Write CTF type information for all entities
|
||||
(functions, data objects, variables etc.)
|
||||
at file-scope or global-scope only. */
|
||||
};
|
||||
|
||||
/* A major contribution to object and executable size is debug
|
||||
information size. A major contribution to debug information
|
||||
size is struct descriptions replicated in several object files.
|
||||
|
|
|
@ -40,10 +40,19 @@ unsigned int debug_set_count (uint32_t w_symbols);
|
|||
|
||||
const char * debug_set_names (uint32_t w_symbols);
|
||||
|
||||
/* Return true iff BTF debug info is enabled. */
|
||||
|
||||
extern bool btf_debuginfo_p ();
|
||||
|
||||
/* Return true iff DWARF2 debug info is enabled. */
|
||||
|
||||
extern bool dwarf_debuginfo_p ();
|
||||
|
||||
/* Return true iff the debug info format is to be generated based on DWARF
|
||||
DIEs (like CTF and BTF debug info formats). */
|
||||
|
||||
extern bool dwarf_based_debuginfo_p ();
|
||||
|
||||
extern void strip_off_ending (char *, int);
|
||||
extern int base_of_path (const char *path, const char **base_out);
|
||||
|
||||
|
|
|
@ -1727,7 +1727,7 @@ open_base_files (void)
|
|||
"target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
|
||||
"ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-general.h",
|
||||
"omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h", "symtab-thunks.h",
|
||||
"symtab-clones.h", "diagnostic-spec.h",
|
||||
"symtab-clones.h", "diagnostic-spec.h", "ctfc.h",
|
||||
NULL
|
||||
};
|
||||
const char *const *ifp;
|
||||
|
@ -5202,6 +5202,7 @@ main (int argc, char **argv)
|
|||
POS_HERE (do_scalar_typedef ("poly_int64", &pos));
|
||||
POS_HERE (do_scalar_typedef ("poly_uint64", &pos));
|
||||
POS_HERE (do_scalar_typedef ("uint64_t", &pos));
|
||||
POS_HERE (do_scalar_typedef ("uint32_t", &pos));
|
||||
POS_HERE (do_scalar_typedef ("uint8", &pos));
|
||||
POS_HERE (do_scalar_typedef ("uintptr_t", &pos));
|
||||
POS_HERE (do_scalar_typedef ("jword", &pos));
|
||||
|
|
143
gcc/opts.c
143
gcc/opts.c
|
@ -42,7 +42,7 @@ static void set_Wstrict_aliasing (struct gcc_options *opts, int onoff);
|
|||
|
||||
const char *const debug_type_names[] =
|
||||
{
|
||||
"none", "stabs", "dwarf-2", "xcoff", "vms"
|
||||
"none", "stabs", "dwarf-2", "xcoff", "vms", "ctf", "btf"
|
||||
};
|
||||
|
||||
/* Bitmasks of fundamental debug info formats indexed by enum
|
||||
|
@ -50,13 +50,14 @@ const char *const debug_type_names[] =
|
|||
|
||||
static uint32_t debug_type_masks[] =
|
||||
{
|
||||
NO_DEBUG, DBX_DEBUG, DWARF2_DEBUG, XCOFF_DEBUG, VMS_DEBUG
|
||||
NO_DEBUG, DBX_DEBUG, DWARF2_DEBUG, XCOFF_DEBUG, VMS_DEBUG,
|
||||
CTF_DEBUG, BTF_DEBUG
|
||||
};
|
||||
|
||||
/* Names of the set of debug formats requested by user. Updated and accessed
|
||||
via debug_set_names. */
|
||||
|
||||
static char df_set_names[sizeof "none stabs dwarf-2 xcoff vms"];
|
||||
static char df_set_names[sizeof "none stabs dwarf-2 xcoff vms ctf btf"];
|
||||
|
||||
/* Get enum debug_info_type of the specified debug format, for error messages.
|
||||
Can be used only for individual debug format types. */
|
||||
|
@ -126,6 +127,14 @@ debug_set_names (uint32_t w_symbols)
|
|||
return df_set_names;
|
||||
}
|
||||
|
||||
/* Return TRUE iff BTF debug info is enabled. */
|
||||
|
||||
bool
|
||||
btf_debuginfo_p ()
|
||||
{
|
||||
return (write_symbols & BTF_DEBUG);
|
||||
}
|
||||
|
||||
/* Return TRUE iff dwarf2 debug info is enabled. */
|
||||
|
||||
bool
|
||||
|
@ -134,6 +143,15 @@ dwarf_debuginfo_p ()
|
|||
return (write_symbols & DWARF2_DEBUG);
|
||||
}
|
||||
|
||||
/* Return true iff the debug info format is to be generated based on DWARF
|
||||
DIEs (like CTF and BTF debug info formats). */
|
||||
|
||||
bool dwarf_based_debuginfo_p ()
|
||||
{
|
||||
return ((write_symbols & CTF_DEBUG)
|
||||
|| (write_symbols & BTF_DEBUG));
|
||||
}
|
||||
|
||||
/* Parse the -femit-struct-debug-detailed option value
|
||||
and set the flag variables. */
|
||||
|
||||
|
@ -2868,6 +2886,24 @@ common_handle_option (struct gcc_options *opts,
|
|||
loc);
|
||||
break;
|
||||
|
||||
case OPT_gbtf:
|
||||
set_debug_level (BTF_DEBUG, false, arg, opts, opts_set, loc);
|
||||
/* set the debug level to level 2, but if already at level 3,
|
||||
don't lower it. */
|
||||
if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
|
||||
opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
|
||||
break;
|
||||
|
||||
case OPT_gctf:
|
||||
set_debug_level (CTF_DEBUG, false, arg, opts, opts_set, loc);
|
||||
/* CTF generation feeds off DWARF dies. For optimal CTF, switch debug
|
||||
info level to 2. If off or at level 1, set it to level 2, but if
|
||||
already at level 3, don't lower it. */
|
||||
if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL
|
||||
&& opts->x_ctf_debug_info_level > CTFINFO_LEVEL_NONE)
|
||||
opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
|
||||
break;
|
||||
|
||||
case OPT_gdwarf:
|
||||
if (arg && strlen (arg) != 0)
|
||||
{
|
||||
|
@ -3116,7 +3152,10 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
|
|||
if (extended == 2)
|
||||
{
|
||||
#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_LINENO_DEBUGGING_INFO
|
||||
opts->x_write_symbols = DWARF2_DEBUG;
|
||||
if (opts->x_write_symbols & CTF_DEBUG)
|
||||
opts->x_write_symbols |= DWARF2_DEBUG;
|
||||
else
|
||||
opts->x_write_symbols = DWARF2_DEBUG;
|
||||
#elif defined DBX_DEBUGGING_INFO
|
||||
opts->x_write_symbols = DBX_DEBUG;
|
||||
#endif
|
||||
|
@ -3125,41 +3164,81 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
|
|||
if (opts->x_write_symbols == NO_DEBUG)
|
||||
warning_at (loc, 0, "target system does not support debug output");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Does it conflict with an already selected debug format? */
|
||||
if (opts_set->x_write_symbols != NO_DEBUG
|
||||
&& opts->x_write_symbols != NO_DEBUG
|
||||
&& dinfo != opts->x_write_symbols)
|
||||
else if ((opts->x_write_symbols & CTF_DEBUG)
|
||||
|| (opts->x_write_symbols & BTF_DEBUG))
|
||||
{
|
||||
gcc_assert (debug_set_count (dinfo) <= 1);
|
||||
error_at (loc, "debug format %qs conflicts with prior selection",
|
||||
debug_type_names[debug_set_to_format (dinfo)]);
|
||||
opts->x_write_symbols |= DWARF2_DEBUG;
|
||||
opts_set->x_write_symbols |= DWARF2_DEBUG;
|
||||
}
|
||||
|
||||
opts->x_write_symbols = dinfo;
|
||||
opts_set->x_write_symbols = dinfo;
|
||||
}
|
||||
|
||||
/* A debug flag without a level defaults to level 2.
|
||||
If off or at level 1, set it to level 2, but if already
|
||||
at level 3, don't lower it. */
|
||||
if (*arg == '\0')
|
||||
{
|
||||
if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
|
||||
opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int argval = integral_argument (arg);
|
||||
if (argval == -1)
|
||||
error_at (loc, "unrecognized debug output level %qs", arg);
|
||||
else if (argval > 3)
|
||||
error_at (loc, "debug output level %qs is too high", arg);
|
||||
/* Make and retain the choice if both CTF and DWARF debug info are to
|
||||
be generated. */
|
||||
if (((dinfo == DWARF2_DEBUG) || (dinfo == CTF_DEBUG))
|
||||
&& ((opts->x_write_symbols == (DWARF2_DEBUG|CTF_DEBUG))
|
||||
|| (opts->x_write_symbols == DWARF2_DEBUG)
|
||||
|| (opts->x_write_symbols == CTF_DEBUG)))
|
||||
{
|
||||
opts->x_write_symbols |= dinfo;
|
||||
opts_set->x_write_symbols |= dinfo;
|
||||
}
|
||||
/* However, CTF and BTF are not allowed together at this time. */
|
||||
else if (((dinfo == DWARF2_DEBUG) || (dinfo == BTF_DEBUG))
|
||||
&& ((opts->x_write_symbols == (DWARF2_DEBUG|BTF_DEBUG))
|
||||
|| (opts->x_write_symbols == DWARF2_DEBUG)
|
||||
|| (opts->x_write_symbols == BTF_DEBUG)))
|
||||
{
|
||||
opts->x_write_symbols |= dinfo;
|
||||
opts_set->x_write_symbols |= dinfo;
|
||||
}
|
||||
else
|
||||
opts->x_debug_info_level = (enum debug_info_levels) argval;
|
||||
{
|
||||
/* Does it conflict with an already selected debug format? */
|
||||
if (opts_set->x_write_symbols != NO_DEBUG
|
||||
&& opts->x_write_symbols != NO_DEBUG
|
||||
&& dinfo != opts->x_write_symbols)
|
||||
{
|
||||
gcc_assert (debug_set_count (dinfo) <= 1);
|
||||
error_at (loc, "debug format %qs conflicts with prior selection",
|
||||
debug_type_names[debug_set_to_format (dinfo)]);
|
||||
}
|
||||
opts->x_write_symbols = dinfo;
|
||||
opts_set->x_write_symbols = dinfo;
|
||||
}
|
||||
}
|
||||
|
||||
if (dinfo != BTF_DEBUG)
|
||||
{
|
||||
/* A debug flag without a level defaults to level 2.
|
||||
If off or at level 1, set it to level 2, but if already
|
||||
at level 3, don't lower it. */
|
||||
if (*arg == '\0')
|
||||
{
|
||||
if (dinfo == CTF_DEBUG)
|
||||
opts->x_ctf_debug_info_level = CTFINFO_LEVEL_NORMAL;
|
||||
else if (opts->x_debug_info_level < DINFO_LEVEL_NORMAL)
|
||||
opts->x_debug_info_level = DINFO_LEVEL_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int argval = integral_argument (arg);
|
||||
if (argval == -1)
|
||||
error_at (loc, "unrecognized debug output level %qs", arg);
|
||||
else if (argval > 3)
|
||||
error_at (loc, "debug output level %qs is too high", arg);
|
||||
else
|
||||
{
|
||||
if (dinfo == CTF_DEBUG)
|
||||
opts->x_ctf_debug_info_level
|
||||
= (enum ctf_debug_info_levels) argval;
|
||||
else
|
||||
opts->x_debug_info_level = (enum debug_info_levels) argval;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*arg != '\0')
|
||||
error_at (loc, "unrecognized btf debug output level %qs", arg);
|
||||
}
|
||||
|
||||
/* Arrange to dump core on error for diagnostic context DC. (The
|
||||
|
|
19
gcc/toplev.c
19
gcc/toplev.c
|
@ -1232,6 +1232,7 @@ parse_alignment_opts (void)
|
|||
static void
|
||||
process_options (void)
|
||||
{
|
||||
const char *language_string = lang_hooks.name;
|
||||
/* Just in case lang_hooks.post_options ends up calling a debug_hook.
|
||||
This can happen with incorrect pre-processed input. */
|
||||
debug_hooks = &do_nothing_debug_hooks;
|
||||
|
@ -1415,6 +1416,17 @@ process_options (void)
|
|||
debug_info_level = DINFO_LEVEL_NONE;
|
||||
}
|
||||
|
||||
/* CTF is supported for only C at this time.
|
||||
Compiling with -flto results in frontend language of GNU GIMPLE. */
|
||||
if (!lang_GNU_C ()
|
||||
&& ctf_debug_info_level > CTFINFO_LEVEL_NONE)
|
||||
{
|
||||
inform (UNKNOWN_LOCATION,
|
||||
"CTF debug info requested, but not supported for %qs frontend",
|
||||
language_string);
|
||||
ctf_debug_info_level = CTFINFO_LEVEL_NONE;
|
||||
}
|
||||
|
||||
if (flag_dump_final_insns && !flag_syntax_only && !no_backend)
|
||||
{
|
||||
FILE *final_output = fopen (flag_dump_final_insns, "w");
|
||||
|
@ -1436,7 +1448,8 @@ process_options (void)
|
|||
|
||||
/* A lot of code assumes write_symbols == NO_DEBUG if the debugging
|
||||
level is 0. */
|
||||
if (debug_info_level == DINFO_LEVEL_NONE)
|
||||
if (debug_info_level == DINFO_LEVEL_NONE
|
||||
&& ctf_debug_info_level == CTFINFO_LEVEL_NONE)
|
||||
write_symbols = NO_DEBUG;
|
||||
|
||||
if (write_symbols == NO_DEBUG)
|
||||
|
@ -1450,7 +1463,8 @@ process_options (void)
|
|||
debug_hooks = &xcoff_debug_hooks;
|
||||
#endif
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
else if (write_symbols == DWARF2_DEBUG)
|
||||
else if (dwarf_debuginfo_p ()
|
||||
|| dwarf_based_debuginfo_p ())
|
||||
debug_hooks = &dwarf2_debug_hooks;
|
||||
#endif
|
||||
#ifdef VMS_DEBUGGING_INFO
|
||||
|
@ -1472,6 +1486,7 @@ process_options (void)
|
|||
/* We know which debug output will be used so we can set flag_var_tracking
|
||||
and flag_var_tracking_uninit if the user has not specified them. */
|
||||
if (debug_info_level < DINFO_LEVEL_NORMAL
|
||||
|| !dwarf_debuginfo_p ()
|
||||
|| debug_hooks->var_location == do_nothing_debug_hooks.var_location)
|
||||
{
|
||||
if (flag_var_tracking == 1
|
||||
|
|
196
include/btf.h
Normal file
196
include/btf.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/* Declarations and definitions relating to the BPF Type Format (BTF).
|
||||
Copyright (C) 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/>. */
|
||||
|
||||
/* This file is derived from the BTF specification described in the
|
||||
Linux kernel source tree (linux/Documentation/bpf/btf.rst). */
|
||||
|
||||
#ifndef _BTF_H_
|
||||
#define _BTF_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* BTF magic number to identify header, endianness. */
|
||||
#define BTF_MAGIC 0xeb9f
|
||||
/* Data format version number. */
|
||||
#define BTF_VERSION 1
|
||||
|
||||
struct btf_header
|
||||
{
|
||||
uint16_t magic; /* Magic number (BTF_MAGIC). */
|
||||
uint8_t version; /* Data format version (BTF_VERSION). */
|
||||
uint8_t flags; /* Flags. Currently unused. */
|
||||
uint32_t hdr_len; /* Length of this header (sizeof (struct btf_header)). */
|
||||
|
||||
/* Following offsets are relative to the end of this header. */
|
||||
uint32_t type_off; /* Offset of type section, in bytes. */
|
||||
uint32_t type_len; /* Length of type section, in bytes. */
|
||||
uint32_t str_off; /* Offset of string section, in bytes. */
|
||||
uint32_t str_len; /* Length of string section, in bytes. */
|
||||
};
|
||||
|
||||
/* Maximum type identifier. */
|
||||
#define BTF_MAX_TYPE 0x000fffff
|
||||
/* Maximum offset into the string section. */
|
||||
#define BTF_MAX_NAME_OFFSET 0x00ffffff
|
||||
/* Maximum number of struct, union, enum members or func args. */
|
||||
#define BTF_MAX_VLEN 0xffff
|
||||
|
||||
struct btf_type
|
||||
{
|
||||
uint32_t name_off; /* Offset in string section of type name. */
|
||||
uint32_t info; /* Encoded kind, variant length, kind flag:
|
||||
- bits 0-15: vlen
|
||||
- bits 16-23: unused
|
||||
- bits 24-27: kind
|
||||
- bits 28-30: unused
|
||||
- bit 31: kind_flag
|
||||
See accessor macros below. */
|
||||
|
||||
/* SIZE is used by INT, ENUM, STRUCT, UNION, DATASEC kinds.
|
||||
TYPE is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT, FUNC,
|
||||
FUNC_PROTO and VAR kinds. */
|
||||
union
|
||||
{
|
||||
uint32_t size; /* Size of the entire type, in bytes. */
|
||||
uint32_t type; /* A type_id referring to another type. */
|
||||
};
|
||||
};
|
||||
|
||||
/* The folloing macros access the information encoded in btf_type.info. */
|
||||
/* Type kind. See below. */
|
||||
#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
|
||||
/* Number of entries of variable length data following certain type kinds.
|
||||
For example, number of structure members, number of function parameters. */
|
||||
#define BTF_INFO_VLEN(info) ((info) & 0xffff)
|
||||
/* For BTF_KIND_FWD, 1 if forward to union, 0 if forward to struct.
|
||||
For BTF_KIND_STRUCT and BTF_KIND_UNION, 1 if the struct/union contains
|
||||
a bitfield. */
|
||||
#define BTF_INFO_KFLAG(info) ((info) >> 31)
|
||||
|
||||
/* Encoding for struct btf_type.info. */
|
||||
#define BTF_TYPE_INFO(kind, kflag, vlen) \
|
||||
((((kflag) ? 1 : 0 ) << 31) | ((kind) << 24) | ((vlen) & 0xffff))
|
||||
|
||||
#define BTF_KIND_UNKN 0 /* Unknown or invalid. */
|
||||
#define BTF_KIND_INT 1 /* Integer. */
|
||||
#define BTF_KIND_PTR 2 /* Pointer. */
|
||||
#define BTF_KIND_ARRAY 3 /* Array. */
|
||||
#define BTF_KIND_STRUCT 4 /* Struct. */
|
||||
#define BTF_KIND_UNION 5 /* Union. */
|
||||
#define BTF_KIND_ENUM 6 /* Enumeration. */
|
||||
#define BTF_KIND_FWD 7 /* Forward. */
|
||||
#define BTF_KIND_TYPEDEF 8 /* Typedef. */
|
||||
#define BTF_KIND_VOLATILE 9 /* Referenced type is volatile. */
|
||||
#define BTF_KIND_CONST 10 /* Referenced type is const. */
|
||||
#define BTF_KIND_RESTRICT 11 /* Restrict. */
|
||||
#define BTF_KIND_FUNC 12 /* Subprogram. */
|
||||
#define BTF_KIND_FUNC_PROTO 13 /* Function Prototype. */
|
||||
#define BTF_KIND_VAR 14 /* Variable. */
|
||||
#define BTF_KIND_DATASEC 15 /* Section such as .bss or .data. */
|
||||
#define BTF_KIND_MAX BTF_KIND_DATASEC
|
||||
#define NR_BTF_KINDS (BTF_KIND_MAX + 1)
|
||||
|
||||
/* For some BTF_KINDs, struct btf_type is immediately followed by
|
||||
additional data describing the type. */
|
||||
|
||||
/* BTF_KIND_INT is followed by a 32-bit word, with the following
|
||||
bit arrangement. */
|
||||
#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
|
||||
#define BTF_INT_OFFSET(VAL) (((VAL) & 0x00ff0000) >> 16)
|
||||
#define BTF_INT_BITS(VAL) ((VAL) & 0x000000ff)
|
||||
|
||||
#define BTF_INT_DATA(encoding, offset, bits) \
|
||||
((((encoding) & 0x0f) << 24) | (((offset) & 0xff) << 16) | ((bits) & 0xff))
|
||||
|
||||
/* BTF_INT_ENCODING holds the following attribute flags. */
|
||||
#define BTF_INT_SIGNED (1 << 0)
|
||||
#define BTF_INT_CHAR (1 << 1)
|
||||
#define BTF_INT_BOOL (1 << 2)
|
||||
|
||||
/* BTF_KIND_ENUM is followed by VLEN struct btf_enum entries,
|
||||
which describe the enumerators. Note that BTF currently only
|
||||
supports signed 32-bit enumerator values. */
|
||||
struct btf_enum
|
||||
{
|
||||
uint32_t name_off; /* Offset in string section of enumerator name. */
|
||||
int32_t val; /* Enumerator value. */
|
||||
};
|
||||
|
||||
/* BTF_KIND_ARRAY is followed by a single struct btf_array. */
|
||||
struct btf_array
|
||||
{
|
||||
uint32_t type; /* Type of array elements. */
|
||||
uint32_t index_type; /* Type of array index. */
|
||||
uint32_t nelems; /* Number of elements. 0 for unsized/variable length. */
|
||||
};
|
||||
|
||||
/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed by VLEN
|
||||
struct btf_member. */
|
||||
struct btf_member
|
||||
{
|
||||
uint32_t name_off; /* Offset in string section of member name. */
|
||||
uint32_t type; /* Type of member. */
|
||||
uint32_t offset; /* If the type info kind_flag is set, this contains
|
||||
both the member bitfield size and bit offset,
|
||||
according to the macros below. If kind_flag is not
|
||||
set, offset contains only the bit offset (from the
|
||||
beginning of the struct). */
|
||||
};
|
||||
|
||||
/* If struct or union type info kind_flag is set, used to access member
|
||||
bitfield size from btf_member.offset. */
|
||||
#define BTF_MEMBER_BITFIELD_SIZE (val) ((val) >> 24)
|
||||
/* If struct or union type info kind_flag is set, used to access member
|
||||
bit offset from btf_member.offset. */
|
||||
#define BTF_MEMBER_BIT_OFFSET (val) ((val) & 0x00ffffff)
|
||||
|
||||
/* BTF_KIND_FUNC_PROTO is followed by VLEN struct btf_param entries, which
|
||||
describe the types of the function parameters. */
|
||||
struct btf_param
|
||||
{
|
||||
uint32_t name_off; /* Offset in string section of parameter name. */
|
||||
uint32_t type; /* Type of parameter. */
|
||||
};
|
||||
|
||||
/* BTF_KIND_VAR is followed by a single struct btf_var, which describes
|
||||
information about the variable. */
|
||||
struct btf_var
|
||||
{
|
||||
uint32_t linkage; /* Currently only 0=static or 1=global. */
|
||||
};
|
||||
|
||||
/* BTF_KIND_DATASEC is followed by VLEN struct btf_var_secinfo entries,
|
||||
which describe all BTF_KIND_VAR types contained in the section. */
|
||||
struct btf_var_secinfo
|
||||
{
|
||||
uint32_t type; /* Type of variable. */
|
||||
uint32_t offset; /* In-section offset of variable (in bytes). */
|
||||
uint32_t size; /* Size (in bytes) of variable. */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _BTF_H_ */
|
520
include/ctf.h
Normal file
520
include/ctf.h
Normal file
|
@ -0,0 +1,520 @@
|
|||
/* CTF format description.
|
||||
Copyright (C) 2021 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of libctf.
|
||||
|
||||
libctf 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.
|
||||
|
||||
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; see the file COPYING. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef _CTF_H
|
||||
#define _CTF_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/* CTF - Compact ANSI-C Type Format
|
||||
|
||||
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. 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; libctf automatically compensates for
|
||||
endianness variations. 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 | object | function |...
|
||||
| header | labels | objects | info | index | index |...
|
||||
+--------+--------+---------+----------+--------+----------+...
|
||||
|
||||
...+----------+-------+--------+
|
||||
...| variable | data | string |
|
||||
...| 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 (collectively, "symtypetabs") 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 entry in these tables, the type ID (a
|
||||
small integer) is recorded. (Functions get CTF_K_FUNCTION types, just like
|
||||
data objects that are function pointers.)
|
||||
|
||||
For situations in which the order of the symbols in the symtab is not known,
|
||||
or most symbols have no type in this dict and most entries would be
|
||||
zero-pads, a pair of optional indexes follow the data object and function
|
||||
info sections: each of these is an array of strtab indexes, mapped 1:1 to the
|
||||
corresponding data object / function info section, giving each entry in those
|
||||
sections a name so that the linker can correlate them with final symtab
|
||||
entries and reorder them accordingly (dropping the indexes in the process).
|
||||
|
||||
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. We do
|
||||
not define how the consumer maps these variable names to addresses or
|
||||
anything else, or indeed what these names represent: they might be names
|
||||
looked up at runtime via dlsym() or names extracted at runtime by a debugger
|
||||
or anything else the consumer likes. Variable records with identically-
|
||||
named entries in the data object section are removed.
|
||||
|
||||
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. Most type nodes are standalone or point backwards to
|
||||
earlier nodes, but this is not required: nodes can point to later nodes,
|
||||
particularly structure and union members.
|
||||
|
||||
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 dynamic 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.
|
||||
|
||||
If the CTF data has been merged with another parent CTF object, some outgoing
|
||||
edges may refer to type nodes that exist in another CTF object. The debugger
|
||||
and libctf library are responsible for connecting the appropriate objects
|
||||
together so that the full set of types can be explored and manipulated.
|
||||
|
||||
This connection is done purely using the ctf_import() function. The
|
||||
ctf_archive machinery (and thus ctf_open et al) automatically imports archive
|
||||
members named ".ctf" into child dicts if available in the same archive, to
|
||||
match the relationship set up by the linker, but callers can call ctf_import
|
||||
themselves as well if need be, if they know a different relationship is in
|
||||
force. */
|
||||
|
||||
#define CTF_MAX_TYPE 0xfffffffe /* Max type identifier value. */
|
||||
#define CTF_MAX_PTYPE 0x7fffffff /* Max parent type identifier value. */
|
||||
#define CTF_MAX_NAME 0x7fffffff /* Max offset into a string table. */
|
||||
#define CTF_MAX_VLEN 0xffffff /* Max struct, union, enum members or args. */
|
||||
|
||||
/* See ctf_type_t */
|
||||
#define CTF_MAX_SIZE 0xfffffffe /* Max size of a v2 type in bytes. */
|
||||
#define CTF_LSIZE_SENT 0xffffffff /* Sentinel for v2 ctt_size. */
|
||||
|
||||
/* Start of actual data structure definitions.
|
||||
|
||||
Every field in these structures must have corresponding code in the
|
||||
endianness-swapping machinery in libctf/ctf-open.c. */
|
||||
|
||||
typedef struct ctf_preamble
|
||||
{
|
||||
unsigned short ctp_magic; /* Magic number (CTF_MAGIC). */
|
||||
unsigned char ctp_version; /* Data format version number (CTF_VERSION). */
|
||||
unsigned char ctp_flags; /* Flags (see below). */
|
||||
} ctf_preamble_t;
|
||||
|
||||
typedef struct ctf_header
|
||||
{
|
||||
ctf_preamble_t cth_preamble;
|
||||
uint32_t cth_parlabel; /* Ref to name of parent lbl uniq'd against. */
|
||||
uint32_t cth_parname; /* Ref to basename of parent. */
|
||||
uint32_t cth_cuname; /* Ref to CU name (may be 0). */
|
||||
uint32_t cth_lbloff; /* Offset of label section. */
|
||||
uint32_t cth_objtoff; /* Offset of object section. */
|
||||
uint32_t cth_funcoff; /* Offset of function section. */
|
||||
uint32_t cth_objtidxoff; /* Offset of object index section. */
|
||||
uint32_t cth_funcidxoff; /* Offset of function index section. */
|
||||
uint32_t cth_varoff; /* Offset of variable section. */
|
||||
uint32_t cth_typeoff; /* Offset of type section. */
|
||||
uint32_t cth_stroff; /* Offset of string section. */
|
||||
uint32_t cth_strlen; /* Length of string section in bytes. */
|
||||
} ctf_header_t;
|
||||
|
||||
#define cth_magic cth_preamble.ctp_magic
|
||||
#define cth_version cth_preamble.ctp_version
|
||||
#define cth_flags cth_preamble.ctp_flags
|
||||
|
||||
#define CTF_MAGIC 0xdff2 /* Magic number identifying header. */
|
||||
|
||||
/* Data format version number. */
|
||||
|
||||
/* v1 upgraded to a later version is not quite the same as the native form,
|
||||
because the boundary between parent and child types is different but not
|
||||
recorded anywhere, and you can write it out again via ctf_compress_write(),
|
||||
so we must track whether the thing was originally v1 or not. If we were
|
||||
writing the header from scratch, we would add a *pair* of version number
|
||||
fields to allow for this, but this will do for now. (A flag will not do,
|
||||
because we need to encode both the version we came from and the version we
|
||||
went to, not just "we were upgraded".) */
|
||||
|
||||
# define CTF_VERSION_1 1
|
||||
# define CTF_VERSION_1_UPGRADED_3 2
|
||||
# define CTF_VERSION_2 3
|
||||
|
||||
/* Note: some flags may be valid only in particular format versions. */
|
||||
|
||||
#define CTF_VERSION_3 4
|
||||
#define CTF_VERSION CTF_VERSION_3 /* Current version. */
|
||||
|
||||
#define CTF_F_COMPRESS 0x1 /* Data buffer is compressed by libctf. */
|
||||
#define CTF_F_NEWFUNCINFO 0x2 /* New v3 func info section format. */
|
||||
|
||||
typedef struct ctf_lblent
|
||||
{
|
||||
uint32_t ctl_label; /* Ref to name of label. */
|
||||
uint32_t ctl_type; /* Last type associated with this label. */
|
||||
} ctf_lblent_t;
|
||||
|
||||
typedef struct ctf_varent
|
||||
{
|
||||
uint32_t ctv_name; /* Reference to name in string table. */
|
||||
uint32_t ctv_type; /* Index of type of this variable. */
|
||||
} ctf_varent_t;
|
||||
|
||||
/* In format v2, type sizes, measured in bytes, come in two flavours. Nearly
|
||||
all of them fit into a (UINT_MAX - 1), and thus can be stored in the ctt_size
|
||||
member of a ctf_stype_t. The maximum value for these sizes is CTF_MAX_SIZE.
|
||||
Types larger than this must be stored in the ctf_lsize member of a
|
||||
ctf_type_t. Use of this member is indicated by the presence of
|
||||
CTF_LSIZE_SENT in ctt_size. */
|
||||
|
||||
typedef struct ctf_stype
|
||||
{
|
||||
uint32_t ctt_name; /* Reference to name in string table. */
|
||||
uint32_t ctt_info; /* Encoded kind, variant length (see below). */
|
||||
#ifndef __GNUC__
|
||||
union
|
||||
{
|
||||
uint32_t _size; /* Size of entire type in bytes. */
|
||||
uint32_t _type; /* Reference to another type. */
|
||||
} _u;
|
||||
#else
|
||||
__extension__
|
||||
union
|
||||
{
|
||||
uint32_t ctt_size; /* Size of entire type in bytes. */
|
||||
uint32_t ctt_type; /* Reference to another type. */
|
||||
};
|
||||
#endif
|
||||
} ctf_stype_t;
|
||||
|
||||
typedef struct ctf_type
|
||||
{
|
||||
uint32_t ctt_name; /* Reference to name in string table. */
|
||||
uint32_t ctt_info; /* Encoded kind, variant length (see below). */
|
||||
#ifndef __GNUC__
|
||||
union
|
||||
{
|
||||
uint32_t _size; /* Always CTF_LSIZE_SENT. */
|
||||
uint32_t _type; /* Do not use. */
|
||||
} _u;
|
||||
#else
|
||||
__extension__
|
||||
union
|
||||
{
|
||||
uint32_t ctt_size; /* Always CTF_LSIZE_SENT. */
|
||||
uint32_t ctt_type; /* Do not use. */
|
||||
};
|
||||
#endif
|
||||
uint32_t ctt_lsizehi; /* High 32 bits of type size in bytes. */
|
||||
uint32_t ctt_lsizelo; /* Low 32 bits of type size in bytes. */
|
||||
} ctf_type_t;
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define ctt_size _u._size /* For fundamental types that have a size. */
|
||||
#define ctt_type _u._type /* For types that reference another type. */
|
||||
#endif
|
||||
|
||||
/* The following macros and inline functions compose and decompose values for
|
||||
ctt_info and ctt_name, as well as other structures that contain name
|
||||
references. Use outside libdtrace-ctf itself is explicitly for access to CTF
|
||||
files directly: types returned from the library will always appear to be
|
||||
CTF_V2.
|
||||
|
||||
v1: (transparently upgraded to v2 at open time: may be compiled out of the
|
||||
library)
|
||||
------------------------
|
||||
ctt_info: | kind | isroot | vlen |
|
||||
------------------------
|
||||
15 11 10 9 0
|
||||
|
||||
v2:
|
||||
------------------------
|
||||
ctt_info: | kind | isroot | vlen |
|
||||
------------------------
|
||||
31 26 25 24 0
|
||||
|
||||
CTF_V1 and V2 _INFO_VLEN have the same interface:
|
||||
|
||||
kind = CTF_*_INFO_KIND(c.ctt_info); <-- CTF_K_* value (see below)
|
||||
vlen = CTF_*_INFO_VLEN(fp, c.ctt_info); <-- length of variable data list
|
||||
|
||||
stid = CTF_NAME_STID(c.ctt_name); <-- string table id number (0 or 1)
|
||||
offset = CTF_NAME_OFFSET(c.ctt_name); <-- string table byte offset
|
||||
|
||||
c.ctt_info = CTF_TYPE_INFO(kind, vlen);
|
||||
c.ctt_name = CTF_TYPE_NAME(stid, offset); */
|
||||
|
||||
#define CTF_V1_INFO_KIND(info) (((info) & 0xf800) >> 11)
|
||||
#define CTF_V1_INFO_ISROOT(info) (((info) & 0x0400) >> 10)
|
||||
#define CTF_V1_INFO_VLEN(info) (((info) & CTF_MAX_VLEN_V1))
|
||||
|
||||
#define CTF_V2_INFO_KIND(info) (((info) & 0xfc000000) >> 26)
|
||||
#define CTF_V2_INFO_ISROOT(info) (((info) & 0x2000000) >> 25)
|
||||
#define CTF_V2_INFO_VLEN(info) (((info) & CTF_MAX_VLEN))
|
||||
|
||||
#define CTF_NAME_STID(name) ((name) >> 31)
|
||||
#define CTF_NAME_OFFSET(name) ((name) & CTF_MAX_NAME)
|
||||
#define CTF_SET_STID(name, stid) ((name) | ((unsigned int) stid) << 31)
|
||||
|
||||
/* V2 only. */
|
||||
#define CTF_TYPE_INFO(kind, isroot, vlen) \
|
||||
(((kind) << 26) | (((isroot) ? 1 : 0) << 25) | ((vlen) & CTF_MAX_VLEN))
|
||||
|
||||
#define CTF_TYPE_NAME(stid, offset) \
|
||||
(((stid) << 31) | ((offset) & CTF_MAX_NAME))
|
||||
|
||||
/* The next set of macros are for public consumption only. Not used internally,
|
||||
since the relevant type boundary is dependent upon the version of the file at
|
||||
*opening* time, not the version after transparent upgrade. Use
|
||||
ctf_type_isparent() / ctf_type_ischild() for that. */
|
||||
|
||||
#define CTF_V2_TYPE_ISPARENT(fp, id) ((id) <= CTF_MAX_PTYPE)
|
||||
#define CTF_V2_TYPE_ISCHILD(fp, id) ((id) > CTF_MAX_PTYPE)
|
||||
#define CTF_V2_TYPE_TO_INDEX(id) ((id) & CTF_MAX_PTYPE)
|
||||
#define CTF_V2_INDEX_TO_TYPE(id, child) ((child) ? ((id) | (CTF_MAX_PTYPE+1)) : (id))
|
||||
|
||||
#define CTF_V1_TYPE_ISPARENT(fp, id) ((id) <= CTF_MAX_PTYPE_V1)
|
||||
#define CTF_V1_TYPE_ISCHILD(fp, id) ((id) > CTF_MAX_PTYPE_V1)
|
||||
#define CTF_V1_TYPE_TO_INDEX(id) ((id) & CTF_MAX_PTYPE_V1)
|
||||
#define CTF_V1_INDEX_TO_TYPE(id, child) ((child) ? ((id) | (CTF_MAX_PTYPE_V1+1)) : (id))
|
||||
|
||||
/* Valid for both V1 and V2. */
|
||||
#define CTF_TYPE_LSIZE(cttp) \
|
||||
(((uint64_t)(cttp)->ctt_lsizehi) << 32 | (cttp)->ctt_lsizelo)
|
||||
#define CTF_SIZE_TO_LSIZE_HI(size) ((uint32_t)((uint64_t)(size) >> 32))
|
||||
#define CTF_SIZE_TO_LSIZE_LO(size) ((uint32_t)(size))
|
||||
|
||||
#define CTF_STRTAB_0 0 /* String table id 0 (in-CTF). */
|
||||
#define CTF_STRTAB_1 1 /* String table id 1 (ELF strtab). */
|
||||
|
||||
/* Values for CTF_TYPE_KIND(). If the kind has an associated data list,
|
||||
CTF_INFO_VLEN() will extract the number of elements in the list, and
|
||||
the type of each element is shown in the comments below. */
|
||||
|
||||
#define CTF_K_UNKNOWN 0 /* Unknown type (used for padding and
|
||||
unrepresentable types). */
|
||||
#define CTF_K_INTEGER 1 /* Variant data is CTF_INT_DATA (see below). */
|
||||
#define CTF_K_FLOAT 2 /* Variant data is CTF_FP_DATA (see below). */
|
||||
#define CTF_K_POINTER 3 /* ctt_type is referenced type. */
|
||||
#define CTF_K_ARRAY 4 /* Variant data is single ctf_array_t. */
|
||||
#define CTF_K_FUNCTION 5 /* ctt_type is return type, variant data is
|
||||
list of argument types (unsigned short's for v1,
|
||||
uint32_t's for v2). */
|
||||
#define CTF_K_STRUCT 6 /* Variant data is list of ctf_member_t's. */
|
||||
#define CTF_K_UNION 7 /* Variant data is list of ctf_member_t's. */
|
||||
#define CTF_K_ENUM 8 /* Variant data is list of ctf_enum_t's. */
|
||||
#define CTF_K_FORWARD 9 /* No additional data; ctt_name is tag. */
|
||||
#define CTF_K_TYPEDEF 10 /* ctt_type is referenced type. */
|
||||
#define CTF_K_VOLATILE 11 /* ctt_type is base type. */
|
||||
#define CTF_K_CONST 12 /* ctt_type is base type. */
|
||||
#define CTF_K_RESTRICT 13 /* ctt_type is base type. */
|
||||
#define CTF_K_SLICE 14 /* Variant data is a ctf_slice_t. */
|
||||
|
||||
#define CTF_K_MAX 63 /* Maximum possible (V2) CTF_K_* value. */
|
||||
|
||||
/* Values for ctt_type when kind is CTF_K_INTEGER. The flags, offset in bits,
|
||||
and size in bits are encoded as a single word using the following macros.
|
||||
(However, you can also encode the offset and bitness in a slice.) */
|
||||
|
||||
#define CTF_INT_ENCODING(data) (((data) & 0xff000000) >> 24)
|
||||
#define CTF_INT_OFFSET(data) (((data) & 0x00ff0000) >> 16)
|
||||
#define CTF_INT_BITS(data) (((data) & 0x0000ffff))
|
||||
|
||||
#define CTF_INT_DATA(encoding, offset, bits) \
|
||||
(((encoding) << 24) | ((offset) << 16) | (bits))
|
||||
|
||||
#define CTF_INT_SIGNED 0x01 /* Integer is signed (otherwise unsigned). */
|
||||
#define CTF_INT_CHAR 0x02 /* Character display format. */
|
||||
#define CTF_INT_BOOL 0x04 /* Boolean display format. */
|
||||
#define CTF_INT_VARARGS 0x08 /* Varargs display format. */
|
||||
|
||||
/* Use CTF_CHAR to produce a char that agrees with the system's native
|
||||
char signedness. */
|
||||
#if CHAR_MIN == 0
|
||||
# define CTF_CHAR (CTF_INT_CHAR)
|
||||
#else
|
||||
# define CTF_CHAR (CTF_INT_CHAR | CTF_INT_SIGNED)
|
||||
#endif
|
||||
|
||||
/* Values for ctt_type when kind is CTF_K_FLOAT. The encoding, offset in bits,
|
||||
and size in bits are encoded as a single word using the following macros.
|
||||
(However, you can also encode the offset and bitness in a slice.) */
|
||||
|
||||
#define CTF_FP_ENCODING(data) (((data) & 0xff000000) >> 24)
|
||||
#define CTF_FP_OFFSET(data) (((data) & 0x00ff0000) >> 16)
|
||||
#define CTF_FP_BITS(data) (((data) & 0x0000ffff))
|
||||
|
||||
#define CTF_FP_DATA(encoding, offset, bits) \
|
||||
(((encoding) << 24) | ((offset) << 16) | (bits))
|
||||
|
||||
/* Variant data when kind is CTF_K_FLOAT is an encoding in the top eight bits. */
|
||||
#define CTF_FP_ENCODING(data) (((data) & 0xff000000) >> 24)
|
||||
|
||||
#define CTF_FP_SINGLE 1 /* IEEE 32-bit float encoding. */
|
||||
#define CTF_FP_DOUBLE 2 /* IEEE 64-bit float encoding. */
|
||||
#define CTF_FP_CPLX 3 /* Complex encoding. */
|
||||
#define CTF_FP_DCPLX 4 /* Double complex encoding. */
|
||||
#define CTF_FP_LDCPLX 5 /* Long double complex encoding. */
|
||||
#define CTF_FP_LDOUBLE 6 /* Long double encoding. */
|
||||
#define CTF_FP_INTRVL 7 /* Interval (2x32-bit) encoding. */
|
||||
#define CTF_FP_DINTRVL 8 /* Double interval (2x64-bit) encoding. */
|
||||
#define CTF_FP_LDINTRVL 9 /* Long double interval (2x128-bit) encoding. */
|
||||
#define CTF_FP_IMAGRY 10 /* Imaginary (32-bit) encoding. */
|
||||
#define CTF_FP_DIMAGRY 11 /* Long imaginary (64-bit) encoding. */
|
||||
#define CTF_FP_LDIMAGRY 12 /* Long double imaginary (128-bit) encoding. */
|
||||
|
||||
#define CTF_FP_MAX 12 /* Maximum possible CTF_FP_* value */
|
||||
|
||||
/* A slice increases the offset and reduces the bitness of the referenced
|
||||
ctt_type, which must be a type which has an encoding (fp, int, or enum). We
|
||||
also store the referenced type in here, because it is easier to keep the
|
||||
ctt_size correct for the slice than to shuffle the size into here and keep
|
||||
the ctt_type where it is for other types.
|
||||
|
||||
In a future version, where we loosen requirements on alignment in the CTF
|
||||
file, the cts_offset and cts_bits will be chars: but for now they must be
|
||||
shorts or everything after a slice will become unaligned. */
|
||||
|
||||
typedef struct ctf_slice
|
||||
{
|
||||
uint32_t cts_type;
|
||||
unsigned short cts_offset;
|
||||
unsigned short cts_bits;
|
||||
} ctf_slice_t;
|
||||
|
||||
typedef struct ctf_array
|
||||
{
|
||||
uint32_t cta_contents; /* Reference to type of array contents. */
|
||||
uint32_t cta_index; /* Reference to type of array index. */
|
||||
uint32_t cta_nelems; /* Number of elements. */
|
||||
} ctf_array_t;
|
||||
|
||||
/* Most structure members have bit offsets that can be expressed using a short.
|
||||
Some don't. ctf_member_t is used for structs which cannot contain any of
|
||||
these large offsets, whereas ctf_lmember_t is used in the latter case. If
|
||||
any member of a given struct has an offset that cannot be expressed using a
|
||||
uint32_t, all members will be stored as type ctf_lmember_t. This is expected
|
||||
to be very rare (but nonetheless possible). */
|
||||
|
||||
#define CTF_LSTRUCT_THRESH 536870912
|
||||
|
||||
typedef struct ctf_member_v2
|
||||
{
|
||||
uint32_t ctm_name; /* Reference to name in string table. */
|
||||
uint32_t ctm_offset; /* Offset of this member in bits. */
|
||||
uint32_t ctm_type; /* Reference to type of member. */
|
||||
} ctf_member_t;
|
||||
|
||||
typedef struct ctf_lmember_v2
|
||||
{
|
||||
uint32_t ctlm_name; /* Reference to name in string table. */
|
||||
uint32_t ctlm_offsethi; /* High 32 bits of member offset in bits. */
|
||||
uint32_t ctlm_type; /* Reference to type of member. */
|
||||
uint32_t ctlm_offsetlo; /* Low 32 bits of member offset in bits. */
|
||||
} ctf_lmember_t;
|
||||
|
||||
#define CTF_LMEM_OFFSET(ctlmp) \
|
||||
(((uint64_t)(ctlmp)->ctlm_offsethi) << 32 | (ctlmp)->ctlm_offsetlo)
|
||||
#define CTF_OFFSET_TO_LMEMHI(offset) ((uint32_t)((uint64_t)(offset) >> 32))
|
||||
#define CTF_OFFSET_TO_LMEMLO(offset) ((uint32_t)(offset))
|
||||
|
||||
typedef struct ctf_enum
|
||||
{
|
||||
uint32_t cte_name; /* Reference to name in string table. */
|
||||
int32_t cte_value; /* Value associated with this name. */
|
||||
} ctf_enum_t;
|
||||
|
||||
/* The ctf_archive is a collection of ctf_dict_t's stored together. The format
|
||||
is suitable for mmap()ing: this control structure merely describes the
|
||||
mmap()ed archive (and overlaps the first few bytes of it), hence the
|
||||
greater care taken with integral types. All CTF files in an archive
|
||||
must have the same data model. (This is not validated.)
|
||||
|
||||
All integers in this structure are stored in little-endian byte order.
|
||||
|
||||
The code relies on the fact that everything in this header is a uint64_t
|
||||
and thus the header needs no padding (in particular, that no padding is
|
||||
needed between ctfa_ctfs and the unnamed ctfa_archive_modent array
|
||||
that follows it).
|
||||
|
||||
This is *not* the same as the data structure returned by the ctf_arc_*()
|
||||
functions: this is the low-level on-disk representation. */
|
||||
|
||||
#define CTFA_MAGIC 0x8b47f2a4d7623eeb /* Random. */
|
||||
struct ctf_archive
|
||||
{
|
||||
/* Magic number. (In loaded files, overwritten with the file size
|
||||
so ctf_arc_close() knows how much to munmap()). */
|
||||
uint64_t ctfa_magic;
|
||||
|
||||
/* CTF data model. */
|
||||
uint64_t ctfa_model;
|
||||
|
||||
/* Number of CTF dicts in the archive. */
|
||||
uint64_t ctfa_ndicts;
|
||||
|
||||
/* Offset of the name table. */
|
||||
uint64_t ctfa_names;
|
||||
|
||||
/* Offset of the CTF table. Each element starts with a size (a uint64_t
|
||||
in network byte order) then a ctf_dict_t of that size. */
|
||||
uint64_t ctfa_ctfs;
|
||||
};
|
||||
|
||||
/* An array of ctfa_nnamed of this structure lies at
|
||||
ctf_archive[ctf_archive->ctfa_modents] and gives the ctfa_ctfs or
|
||||
ctfa_names-relative offsets of each name or ctf_dict_t. */
|
||||
|
||||
typedef struct ctf_archive_modent
|
||||
{
|
||||
uint64_t name_offset;
|
||||
uint64_t ctf_offset;
|
||||
} ctf_archive_modent_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CTF_H */
|
|
@ -304,6 +304,9 @@ handle_lto_debug_sections (const char *name, int rename)
|
|||
/* Copy over .GCC.command.line section under the same name if present. */
|
||||
else if (strcmp (name, ".GCC.command.line") == 0)
|
||||
return strcpy (newname, name);
|
||||
/* Copy over .ctf section under the same name if present. */
|
||||
else if (strcmp (name, ".ctf") == 0)
|
||||
return strcpy (newname, name);
|
||||
free (newname);
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue