From patchwork Thu Jun 27 06:37:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Indu Bhagat X-Patchwork-Id: 1123152 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-503846-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=oracle.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="RAxZfbO2"; dkim=pass (2048-bit key; unprotected) header.d=oracle.com header.i=@oracle.com header.b="bb96kDbG"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Z9GX1jfMz9sLt for ; Thu, 27 Jun 2019 16:39:00 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:in-reply-to:references; q=dns; s= default; b=RQFMsgUZoiXcBSvdjjzrD++oM53UoIutiY9MgJ8Hcv+w1Hdsk3AJz oUGboQNBtRLu+dnEaWRTHo+9RT/D0fuRrMjUNP53GRupaE4i0kbLx5Id98ySjkkP 65IvzQfq6Zw003nnexiaacH7NHuTpuvWYuh0DQ6BLIXDq1iaBpHE/E= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:in-reply-to:references; s=default; bh=KkPaN7sfrZXHAH2s3gIhqOTd3MM=; b=RAxZfbO2cv94jYiRQlPeYa2DsbtZ NafC7JO3RaeJhF4dc1SuAUL9y2JhfzrC9Gbb86A0VtknDdlzW5B7as/FKLo29dpo vIV1CNw9Kd7oJd3ZjMreZOdjgIgaGkQAYVBkjEWS5QTa7TJEUSNshNuTNwoOa/HN LsM40Pa9KSdkx5s= Received: (qmail 110737 invoked by alias); 27 Jun 2019 06:37:52 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 110593 invoked by uid 89); 27 Jun 2019 06:37:52 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-21.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 spammy=dtd X-HELO: userp2130.oracle.com Received: from userp2130.oracle.com (HELO userp2130.oracle.com) (156.151.31.86) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 27 Jun 2019 06:37:36 +0000 Received: from pps.filterd (userp2130.oracle.com [127.0.0.1]) by userp2130.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x5R6XZnH021561; Thu, 27 Jun 2019 06:37:34 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=from : to : subject : date : message-id : in-reply-to : references; s=corp-2018-07-02; bh=JXffshC3oLRoeGVNyNhHVbh4l8Oi6MHHO228qUkvPb4=; b=bb96kDbGWi8zwX7n+bGR3gvHZ0R2VXhf3kVqUgazeqIR7Mnj9Vj+p/OsX7Tfk2XGyBkV VeeLH1hW+ZHgWQODhrX6/AHafhv3l3HJFuGuAQWnB2VaDvaHk7zsU62Fz9jGZ2v8NJy1 77G2IJGlCQvWuBIbV6xb7L2PRhvU+3Ysk9zD9fH4krD06fjp6DRbwwL0El7Ih1RK1/++ a7DkyS5SHRD/+vc+7+2ihSVX0VLoeQD8TUi+Gt4e21crR25IZQx4pzCCYs2Ur9vmhd6a KLhRJFGO3sEajm2Bs6VHwqxpD6xVlSBIUxwTprLHRqmECp8mOJdLiDAUbKO1uW/tnAYD bg== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by userp2130.oracle.com with ESMTP id 2t9brtebx3-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 27 Jun 2019 06:37:34 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x5R6Zu9m090999; Thu, 27 Jun 2019 06:37:34 GMT Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userp3030.oracle.com with ESMTP id 2t99f4u8ub-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 27 Jun 2019 06:37:33 +0000 Received: from abhmp0012.oracle.com (abhmp0012.oracle.com [141.146.116.18]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id x5R6bWOR006579; Thu, 27 Jun 2019 06:37:32 GMT Received: from ibhagatpc.us.oracle.com (/10.159.231.47) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Wed, 26 Jun 2019 23:37:32 -0700 From: Indu Bhagat To: gcc-patches@gcc.gnu.org, richard.guenther@gmail.com Subject: [PATCH,RFC,V3 4/5] CTF generation for a single compilation unit Date: Wed, 26 Jun 2019 23:37:24 -0700 Message-Id: <1561617445-9328-5-git-send-email-indu.bhagat@oracle.com> In-Reply-To: <1561617445-9328-1-git-send-email-indu.bhagat@oracle.com> References: <1561617445-9328-1-git-send-email-indu.bhagat@oracle.com> For each translation unit, a CTF container (ctf_container_t) is used to keep the CTF debug info. - ctfout.c hosts the compiler facing routines for CTF generation and emission. - ctfcreate.c contains the CTF format specific CTF creation routines. - ctfutils.c contains helper routines for CTF creation. gcc/ChangeLog : * Makefile.in: Add new object files. * ctfcreate.c: New file. * ctfout.c (ctf_dtu_d_union_selector): New helper function for garbage collection of dtd_u union in ctf_dtdef_t. (ctf_dtdef_hash::hash): New function to generate hashkey for a CTF Type record. (hash_dtd_tree_decl): New function. (ctf_dtdef_hash::equal): Likewise. (is_ctf_base_type): Likewise. (get_cvr_quals_for_type): Likewise. (get_type_name_string): Likewise. (get_decl_name_string): Likewise. (ctf_type_exists): Likewise. (init_ctf_string_table): Likewise. (new_ctf_container): Allocate contents of CTF container. (delete_ctf_container): Cleanup contents of CTF container. (init_ctf_sections): Prepare for LTO. (gen_ctf_base_type): New function. (gen_ctf_pointer_type): Likewise. (gen_ctf_array_type): Likewise. (gen_ctf_forward_type): Likewise. (gen_ctf_enum_const_list): Likewise. (gen_ctf_enum_type): Likewise. (gen_ctf_function_type): Likewise. (gen_ctf_cvrquals): Likewise. (gen_ctf_sou_type): Likewise. (gen_ctf_typedef): Likewise. (gen_ctf_variable): Likewise. (gen_ctf_function): Likewise. (gen_ctf_type): Likewise. (gen_ctf_bitfield_type_for_decl): Likewise. (gen_ctf_type_for_decl): Likewise. (ctf_preprocess_var): Likewise. (ctf_dvd_preprocess_cb): Likewise. (ctf_dtd_preprocess_cb): Likewise. (ctf_preprocess): Likewise. (ctf_asm_stype): Likewise. (ctf_asm_type): Likewise. (ctf_asm_slice): Likewise. (ctf_asm_array): Likewise. (ctf_asm_varent): Likewise. (ctf_asm_sou_lmember): Likewise. (ctf_asm_sou_member): Likewise. (ctf_asm_enum_const): Likewise. (output_ctf_header): Output the CTF section if the CTF container is not empty. (output_ctf_func_info): New function. (output_ctf_vars): Likewise. (output_ctf_strs): Likewise. (output_asm_ctf_sou_fields): Likewise. (output_asm_ctf_enum_list): Likewise. (output_asm_ctf_vlen_bytes): Likewise. (output_asm_ctf_type): Likewise. (output_ctf_types): Likewise. (ctf_decl): Likewise. (ctf_early_finish): Trigger CTF emission. (ctf_early_global_decl): Invoke CTF generation function. (ctfout_c_finalize): Add cleanup of CTF container. * ctfout.h (typedef struct GTY): New Data Structures. (struct ctf_dtdef_hash): CTF Type structure hasher. * ctfutils.c: New file. include/ChangeLog : * ctf.h: Sync with binutils. Keep ctf_slice_t aligned. --- gcc/ChangeLog | 64 +++ gcc/Makefile.in | 2 + gcc/ctfcreate.c | 526 ++++++++++++++++++ gcc/ctfout.c | 1582 ++++++++++++++++++++++++++++++++++++++++++++++++++++- gcc/ctfout.h | 312 ++++++++++- gcc/ctfutils.c | 198 +++++++ include/ChangeLog | 4 + include/ctf.h | 10 +- 8 files changed, 2683 insertions(+), 15 deletions(-) create mode 100644 gcc/ctfcreate.c create mode 100644 gcc/ctfutils.c diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 8ce2405..1851403 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1255,6 +1255,8 @@ OBJS = \ cfgloopmanip.o \ cfgrtl.o \ ctfout.o \ + ctfutils.o \ + ctfcreate.o \ symtab.o \ cgraph.o \ cgraphbuild.o \ diff --git a/gcc/ctfcreate.c b/gcc/ctfcreate.c new file mode 100644 index 0000000..0ee700f --- /dev/null +++ b/gcc/ctfcreate.c @@ -0,0 +1,526 @@ +/* Functions to create and update CTF from GCC. + Copyright (C) 2019 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 +. */ + +/* Create CTF types. The code is mostly adapted from libctf. + + 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. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "ctfout.h" + +void +ctf_dtd_insert (ctf_container_ref ctfc, ctf_dtdef_ref dtd) +{ + ctf_dtdef_ref entry = dtd; + bool existed = ctfc->ctfc_types->put (entry, dtd); + /* Duplicate CTF type records not expected to be inserted. And dtd_decl + cannot be NULL. */ + gcc_assert (dtd->dtd_decl != NULL && !existed); +} + +/* Lookup CTF type given a tree type or decl node. dtd_key_flags are not + necessary for lookup in most cases, because they are needed only for CTF + types with no corresponding tree type or decl to begin with. */ + +ctf_dtdef_ref +ctf_dtd_lookup (const ctf_container_ref ctfc, const tree type) +{ + return ctf_dtd_lookup_with_flags (ctfc, type, 0); +} + +/* Lookup CTF type given a tree type or decl node and key_flags. */ + +ctf_dtdef_ref +ctf_dtd_lookup_with_flags (const ctf_container_ref ctfc, const tree type, + const unsigned int key_flags) +{ + ctf_dtdef_ref * slot; + + ctf_dtdef_t entry; + entry.dtd_key.dtdk_key_decl = type; + entry.dtd_key.dtdk_key_flags = key_flags; + + slot = ctfc->ctfc_types->get (&entry); + + if (slot) + return (ctf_dtdef_ref) (*slot); + + return NULL; +} + +void +ctf_dvd_insert (ctf_container_ref ctfc, ctf_dvdef_ref dvd) +{ + bool existed = ctfc->ctfc_vars->put (dvd->dvd_decl, dvd); + /* Duplicate variable records not expected to be inserted. And dvd_decl + cannot be NULL. */ + gcc_assert (dvd->dvd_decl != NULL && !existed); +} + +/* Lookup CTF variable given a decl node. */ + +ctf_dvdef_ref +ctf_dvd_lookup (const ctf_container_ref ctfc, const tree decl) +{ + ctf_dvdef_ref * slot; + + slot = ctfc->ctfc_vars->get (decl); + + if (slot) + return (ctf_dvdef_ref) (*slot); + + return NULL; +} + +static ctf_id_t +ctf_add_generic (ctf_container_ref ctfc, uint32_t flag, const char * name, + ctf_dtdef_ref * rp, tree treetype, uint32_t key_flags) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (flag == CTF_ADD_NONROOT || flag == CTF_ADD_ROOT); + + dtd = ggc_cleared_alloc (); + + 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.dtdk_key_decl = treetype; + dtd->dtd_key.dtdk_key_flags = key_flags; + + 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, tree treetype) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0); + + 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); + + /* A void type has a size of zero. A power of 2 is expected otherwise. */ + gcc_assert (!roundup_nbytes + || (exact_log2 (roundup_nbytes) != -1)); + 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; +} + +static ctf_id_t +ctf_add_reftype (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + uint32_t kind, tree treetype, uint32_t cvrint) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + uint32_t key_flags = 0; + + /* dtd_key_flags are set only for const, volatile and restrict. */ + if (cvrint && (kind == CTF_K_VOLATILE || kind == CTF_K_CONST + || kind == CTF_K_RESTRICT)) + key_flags = kind; + + gcc_assert (ref > 0 && ref <= CTF_MAX_TYPE); + + type = ctf_add_generic (ctfc, flag, NULL, &dtd, treetype, key_flags); + 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, tree treetype) +{ + ctf_dtdef_ref dtd; + ctf_id_t type = 0; + + type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0); + + 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, tree treetype) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + + gcc_assert (ref > 0 && ref <= CTF_MAX_TYPE); + + type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0); + 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, + const ctf_encoding_t * ep, tree treetype) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + uint32_t roundup_nbytes; + + gcc_assert ((ep->cte_bits <= 255) && (ep->cte_offset <= 255)); + + gcc_assert (ref > 0 && ref <= CTF_MAX_TYPE); + + type = ctf_add_generic (ctfc, flag, NULL, &dtd, treetype, 0); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0); + + roundup_nbytes = (ROUND_UP (ep->cte_bits, BITS_PER_UNIT) / BITS_PER_UNIT); + gcc_assert (roundup_nbytes); + /* 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 = (1 << ceil_log2 (roundup_nbytes)); + + /* 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 = ep->cte_bits; + dtd->dtd_u.dtu_slice.cts_offset = ep->cte_offset; + + ctfc->ctfc_num_stypes++; + + return type; +} + +ctf_id_t +ctf_add_volatile (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + tree type, uint32_t cvrint) +{ + return (ctf_add_reftype (ctfc, flag, ref, CTF_K_VOLATILE, type, cvrint)); +} + +ctf_id_t +ctf_add_const (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + tree type, uint32_t cvrint) +{ + return (ctf_add_reftype (ctfc, flag, ref, CTF_K_CONST, type, cvrint)); +} + +ctf_id_t +ctf_add_restrict (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + tree type, uint32_t cvrint) +{ + return (ctf_add_reftype (ctfc, flag, ref, CTF_K_RESTRICT, type, cvrint)); +} + +ctf_id_t +ctf_add_float (ctf_container_ref ctfc, uint32_t flag, + const char * name, const ctf_encoding_t * ep, tree type) +{ + return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_FLOAT, type)); +} + +ctf_id_t +ctf_add_integer (ctf_container_ref ctfc, uint32_t flag, + const char * name, const ctf_encoding_t * ep, tree type) +{ + return (ctf_add_encoded (ctfc, flag, name, ep, CTF_K_INTEGER, type)); +} + +ctf_id_t +ctf_add_pointer (ctf_container_ref ctfc, uint32_t flag, ctf_id_t ref, + tree type) +{ + return (ctf_add_reftype (ctfc, flag, ref, CTF_K_POINTER, type, 0)); +} + +ctf_id_t +ctf_add_array (ctf_container_ref ctfc, uint32_t flag, const ctf_arinfo_t * arp, + tree treetype) +{ + 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, treetype, 0); + + 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, tree enum_type) +{ + 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. */ + + type = ctf_add_generic (ctfc, flag, name, &dtd, enum_type, 0); + + 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, tree enum_type) +{ + /* 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, enum_type); + gcc_assert (dtd); + gcc_assert (dtd->dtd_type == enid); + + ctf_dmdef_t * dmd; + + uint32_t kind, vlen, root; + + 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); + + dmd = ggc_cleared_alloc (); + + /* 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; + /* Variable value is of type HOST_WIDE_INT, dmd_value is int32_t on the other + hand. Check bounds. TBD WARN - warn instead or skip type ? */ + gcc_assert ((value <= INT_MAX) && (value >= INT_MIN)); + 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, tree sou, const char * name, + ctf_id_t type, unsigned long 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); + +#if 0 + /* Check duplicate members with the same name. May be a useful check if + members of anonymous truct or union are folded into the parent struct (if + exists); See a pending TBD in gen_ctf_sou_type for more info. */ + if (name != NULL) + { + for (dmd = dtd->dtd_u.dtu_members; + dmd != NULL; dmd = (ctf_dmdef_t *) ctf_dmd_list_next (dmd)) + { + if (dmd->dmd_name != NULL) + gcc_assert (strcmp (dmd->dmd_name, name) != 0); + } + } +#endif + + dmd = ggc_cleared_alloc (); + + /* 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, + tree decl) +{ + ctf_dvdef_ref dvd; + + gcc_assert (name); + + if (name != NULL) + { + dvd = ggc_cleared_alloc (); + /* Buffer the strings in the CTF string table. */ + dvd->dvd_name = ctf_add_string (ctfc, name, &(dvd->dvd_name_offset)); + dvd->dvd_type = ref; + dvd->dvd_decl = decl; + ctf_dvd_insert (ctfc, dvd); + + if (strcmp (name, "")) + ctfc->ctfc_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, ctf_func_arg_t * argv, + tree func_decl_or_type) +{ + ctf_dtdef_ref dtd; + ctf_id_t type; + uint32_t vlen; + + gcc_assert (ctc); + if (ctc->ctc_argc) + gcc_assert (argv); + + vlen = ctc->ctc_argc; + + /* Caller must make sure CTF types for ctc->ctc_return and function + arguements are already added. */ + + gcc_assert (vlen <= CTF_MAX_VLEN); + + type = ctf_add_generic (ctfc, flag, name, &dtd, func_decl_or_type, 0); + + dtd->dtd_data.ctti_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen); + dtd->dtd_data.ctti_type = (uint32_t) ctc->ctc_return; + + dtd->dtd_u.dtu_argv = argv; + + 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, tree treetype) +{ + 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. */ + + type = ctf_add_generic (ctfc, flag, name, &dtd, treetype, 0); + + 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; +} diff --git a/gcc/ctfout.c b/gcc/ctfout.c index 1ce9829..e7e1980 100644 --- a/gcc/ctfout.c +++ b/gcc/ctfout.c @@ -46,12 +46,16 @@ static GTY (()) section * ctf_info_section; #ifndef CTF_INFO_SECTION_NAME #define CTF_INFO_SECTION_NAME ".ctf" #endif +#ifndef CTF_LTO_INFO_SECTION_NAME +#define CTF_LTO_INFO_SECTION_NAME ".gnu.debuglto_.ctf" +#endif /* Section flags for .ctf section. */ /* CTF debug info section. */ #define CTF_INFO_SECTION_FLAGS (SECTION_DEBUG) +#define CTF_LTO_INFO_SECTION_FLAGS (SECTION_DEBUG | SECTION_EXCLUDE) /* Maximum size (in bytes) of an artificially generated CTF label. */ @@ -63,8 +67,297 @@ static char ctf_info_section_label[MAX_CTF_LABEL_BYTES]; #define CTF_INFO_SECTION_LABEL "Lctf" #endif +/* Forward declarations for some routines defined in this file. */ + +/* Generate CTF type for the given type. Types already added are skipped. */ + +static ctf_id_t gen_ctf_type (ctf_container_ref, tree); + +/* Generate CTF type for the given decl. Types already added are skipped. */ + +static ctf_id_t gen_ctf_type_for_decl (ctf_container_ref, tree); + +/* CTF preprocess callback arguments. */ + +typedef struct ctf_dtd_preprocess_arg +{ + unsigned long dtd_global_func_idx; + ctf_container_ref dtd_arg_ctfc; +} ctf_dtd_preprocess_arg_t; + +typedef struct ctf_dvd_preprocess_arg +{ + ctf_container_ref dvd_arg_ctfc; +} ctf_dvd_preprocess_arg_t; + +/* CTF cvr qualifier mask. */ + +const int ctf_cvr_qual_mask = (TYPE_QUAL_CONST + | TYPE_QUAL_VOLATILE + | TYPE_QUAL_RESTRICT); + +/* 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) +{ + unsigned int kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + switch (kind) + { + 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; + } +} + +/* Returns a hash code for CTF type records. */ + +hashval_t +ctf_dtdef_hash::hash (ctf_dtdef_ref e1) +{ + ctf_dtdef_ref e = e1; + tree e_decl = e->dtd_decl; + uint32_t key_flags = e->dtd_key_flags; + + hashval_t key = hash_dtd_tree_decl (e_decl, key_flags); + + return key; +} + +hashval_t +hash_dtd_tree_decl (tree e_decl, uint32_t key_flags) +{ + hashval_t key; + tree type = NULL; + + if ((TREE_CODE (e_decl) == FIELD_DECL) + || (TREE_CODE (e_decl) == TYPE_DECL)) + type = TREE_TYPE (e_decl); + else + type = e_decl; /* TREE_TYPE was used as dtd_key otherwise. */ + + if (TREE_CODE (e_decl) == TYPE_DECL + || TREE_CODE (e_decl) == FUNCTION_DECL + /* No CTF type de-duplication for slices. See note in + gen_ctf_bitfield_type_for_decl. */ + || ((TREE_CODE (e_decl) == FIELD_DECL) && DECL_BIT_FIELD_TYPE (e_decl))) + { + key = (hashval_t) htab_hash_pointer (e_decl); + } + else + { + gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type); + key = (hashval_t) TYPE_UID (type); + } + + if (key_flags) + key = iterative_hash (&key_flags, sizeof (key_flags), key); + + return key; +} + +/* Returns nonzero if entry1 and entry2 are the same CTF types. */ + +bool +ctf_dtdef_hash::equal (ctf_dtdef_ref entry1, ctf_dtdef_ref entry2) +{ + bool eq = 0; + tree e1_type, e2_type; + int e1_cvr_quals = 0, e2_cvr_quals = 0; + + ctf_dtdef_ref e1 = entry1; + ctf_dtdef_ref e2 = entry2; + + tree e1_decl = e1->dtd_decl; + tree e2_decl = e2->dtd_decl; + + gcc_assert (e1_decl); + gcc_assert (e2_decl); + /* This pre-check is useful because dtd_decl can be either type or decl tree + references. */ + eq = (TREE_CODE (e1_decl) == TREE_CODE (e2_decl)); + if (eq) + { + if ((TREE_CODE (e1_decl) == FIELD_DECL) + || (TREE_CODE (e1_decl) == TYPE_DECL)) + { + e1_type = TREE_TYPE (e1_decl); + e2_type = TREE_TYPE (e2_decl); + } + else + { + /* TREE_TYPE was used as dtd_key otherwise. */ + e1_type = e1_decl; + e2_type = e2_decl; + } + + if (TREE_CODE (e1_decl) == TYPE_DECL + || TREE_CODE (e1_decl) == FUNCTION_DECL + /* No CTF type de-duplication for slices. See note in + gen_ctf_bitfield_type_for_decl. */ + || ((TREE_CODE (e1_decl) == FIELD_DECL) + && DECL_BIT_FIELD_TYPE (e1_decl))) + + { + eq = (htab_hash_pointer (e1_decl) == htab_hash_pointer (e2_decl)); + } + else + { + gcc_assert (TREE_CODE_CLASS (TREE_CODE (e1_type)) == tcc_type); + gcc_assert (TREE_CODE_CLASS (TREE_CODE (e2_type)) == tcc_type); + + eq = (TYPE_UID (e1_type) == TYPE_UID (e2_type)); + + /* Always compare cvr_quals when available. */ + e1_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e1_type) + & ctf_cvr_qual_mask); + e2_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e2_type) + & ctf_cvr_qual_mask); + + if (eq && e1_cvr_quals) + { + e2_cvr_quals = (TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (e2_type) + & ctf_cvr_qual_mask); + eq = (e1_cvr_quals == e2_cvr_quals); + } + } + + if (eq) + { + /* dtd_key_flags are set only for CTF type records which have no + direct corresponding tree type or decl. They will be 0 + otherwise. */ + eq = (e1->dtd_key_flags == e2->dtd_key_flags); + } + } + + return eq; +} + +static inline int +is_ctf_base_type (tree type) +{ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + case REAL_TYPE: + case FIXED_POINT_TYPE: + case COMPLEX_TYPE: + case BOOLEAN_TYPE: + case VOID_TYPE: + return 1; + + case ARRAY_TYPE: + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + case ENUMERAL_TYPE: + case FUNCTION_TYPE: + case METHOD_TYPE: + case POINTER_TYPE: + case REFERENCE_TYPE: + case NULLPTR_TYPE: + case OFFSET_TYPE: + case LANG_TYPE: + case VECTOR_TYPE: + return 0; + + default: + gcc_unreachable (); + } + + return 0; +} + +static inline int +get_cvr_quals_for_type (tree type) +{ + int cvr_quals = 0; + + if (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type) + cvr_quals = TYPE_QUALS_NO_ADDR_SPACE_NO_ATOMIC (type); + + return cvr_quals; +} + +static const char * +get_type_name_string (tree type) +{ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type); + + tree type_name = TYPE_IDENTIFIER (type); + const char * name_string = type_name ? IDENTIFIER_POINTER (type_name) : NULL; + + return name_string; +} + +static const char * +get_decl_name_string (tree decl) +{ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == tcc_declaration); + + tree decl_name = DECL_NAME (decl); + const char * name_string = decl_name ? IDENTIFIER_POINTER (decl_name) : NULL; + + return name_string; +} + +/* 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. */ + +static bool +ctf_type_exists (ctf_container_ref ctfc, tree 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; +} + /* 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_string_table (ctf_container_ref ctfc) +{ + ctfc->ctfc_strtable.ctstab_head = NULL; + ctfc->ctfc_strtable.ctstab_tail = NULL; + ctfc->ctfc_strtable.ctstab_num = 0; + ctfc->ctfc_strtable.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; + ctfc->ctfc_strtable.ctstab_estr = ctf_add_string (ctfc, "", &estr_offset); + ctfc->ctfc_strlen++; +} + /* Allocate a new CTF container with the desired flags. */ static inline ctf_container_ref @@ -75,6 +368,15 @@ new_ctf_container (unsigned char ctp_flags) tu_ctfc->ctfc_magic = CTF_MAGIC; tu_ctfc->ctfc_version = CTF_VERSION; tu_ctfc->ctfc_flags = ctp_flags; + tu_ctfc->ctfc_nextid = CTF_INIT_TYPEID; + + tu_ctfc->ctfc_types + = hash_map::create_ggc (100); + + tu_ctfc->ctfc_vars + = hash_map::create_ggc (100); + + init_ctf_string_table (tu_ctfc); return tu_ctfc; } @@ -97,22 +399,920 @@ delete_ctf_container (ctf_container_ref ctfc) including the hash_map members etc. ? */ if (ctfc) { - ctfc = NULL; + 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; + } + + ctfc= NULL; } } /* Initialize the various sections and labels for CTF output. */ void -init_ctf_sections (void) +init_ctf_sections (bool early_lto_debug) { - ctf_info_section = get_section (CTF_INFO_SECTION_NAME, - CTF_INFO_SECTION_FLAGS, - NULL); + // TBD - If the producer is LTO, there can be multiple translation units + + if (early_lto_debug) + { + ctf_info_section = get_section (CTF_LTO_INFO_SECTION_NAME, + CTF_LTO_INFO_SECTION_FLAGS, + NULL); + } + else + { + 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++); } +/* Leaf routines for CTF type generation. + Called via the gen_ctf_type (), these APIs update the CTF container with new + CTF records. CTF type de-duplication must be done by the caller API + (See "Parent routines for CTF generation below). */ + +/* 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, tree type) +{ + ctf_id_t type_id = CTF_NULL_TYPEID; + + ctf_encoding_t ctf_encoding = {0, 0, 0}; + HOST_WIDE_INT size = int_size_in_bytes (type); + + uint32_t encoding = 0; + + const char * name_string = get_type_name_string (type); + /* Base TYPE node must have had a TYPE_IDENTIFIER node, else retrieval of + name string of the base type will need to be adjusted. */ + gcc_assert (name_string); + + /* Add the type of variable. */ + switch (TREE_CODE (type)) + { + case INTEGER_TYPE: + { + /* Note - CTF_INT_VARARGS is unused in CTF. */ + + /* Update size and encoding. */ + if (TYPE_STRING_FLAG (type)) + { + if (TYPE_UNSIGNED (type)) + encoding = CTF_INT_CHAR; + else + encoding = CTF_INT_CHAR | CTF_INT_SIGNED; + } + else if (!TYPE_UNSIGNED (type)) + encoding = CTF_INT_SIGNED; + + ctf_encoding.cte_format = encoding; + ctf_encoding.cte_bits = size * 8; + + type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string, + &ctf_encoding, type); + + break; + } + + case BOOLEAN_TYPE: + encoding = CTF_INT_BOOL; + + ctf_encoding.cte_format = encoding; + ctf_encoding.cte_bits = size * 8; + + type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string, + &ctf_encoding, type); + break; + + case REAL_TYPE: + if (size == sizeof (float)) + encoding = CTF_FP_SINGLE; + else if (size == sizeof (double)) + encoding = CTF_FP_DOUBLE; + else if (size == sizeof (long double)) + encoding = CTF_FP_LDOUBLE; + /* Encoding must be appropriately initialized by now. */ + gcc_assert (encoding && encoding <= CTF_FP_MAX); + + ctf_encoding.cte_format = encoding; + ctf_encoding.cte_bits = size * 8; + + type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string, + &ctf_encoding, type); + break; + + /* FIXME - We do not have a fixed point type in CTF yet. */ + case FIXED_POINT_TYPE: + /* TBD WARN - warn instead or skip type ? */ + gcc_assert (false); + break; + + case COMPLEX_TYPE: + encoding = 0; + + if (size == sizeof (float)) + encoding = CTF_FP_CPLX; + else if (size == sizeof (double)) + encoding = CTF_FP_DCPLX; + else if (size == sizeof (long double)) + encoding = CTF_FP_LDCPLX; + /* Encoding must be appropriately initialized by now. */ + gcc_assert (encoding && encoding != CTF_FP_MAX); + + ctf_encoding.cte_format = encoding; + ctf_encoding.cte_bits = size * 8; + + type_id = ctf_add_float (ctfc, CTF_ADD_ROOT, name_string, + &ctf_encoding, type); + break; + + case VOID_TYPE: + encoding = CTF_INT_SIGNED; + ctf_encoding.cte_format = encoding; + ctf_encoding.cte_bits = 0; + + type_id = ctf_add_integer (ctfc, CTF_ADD_ROOT, name_string, + &ctf_encoding, type); + + break; + + default: + /* No other TREE_CODEs are expected as CTF base types. */ + gcc_unreachable () ; + } + + return type_id; +} + +static ctf_id_t +gen_ctf_pointer_type (ctf_container_ref ctfc, tree ptr_type) +{ + ctf_id_t type_id = CTF_NULL_TYPEID; + ctf_id_t pointer_to_type_id = CTF_NULL_TYPEID; + + tree pointertotype = TREE_TYPE (ptr_type); + + type_id = gen_ctf_type (ctfc, pointertotype); + + /* 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. For example, a struct have a member of type + pointer to the struct, e.g., + struct link { struct link * next; } * slink; */ + if (ctf_type_exists (ctfc, ptr_type, &pointer_to_type_id)) + return pointer_to_type_id; + + pointer_to_type_id = ctf_add_pointer (ctfc, CTF_ADD_ROOT, type_id, + ptr_type); + + return pointer_to_type_id; +} + +static ctf_id_t +gen_ctf_array_type (ctf_container_ref ctfc, tree array_type) +{ + ctf_id_t type_id = CTF_NULL_TYPEID; + tree lower, upper; + ctf_arinfo_t arinfo; + HOST_WIDE_INT min_index = 0, max_index = 0; + uint32_t num_elements = 0; + ctf_id_t ctf_contents_type_id = CTF_NULL_TYPEID; + ctf_id_t ctf_index_type_id = CTF_NULL_TYPEID; + + tree type_of_array_element = TREE_TYPE (array_type); + tree type_of_index = TYPE_DOMAIN (array_type); + + /* type_of_index may be NULL in some cases, e.g., when we parse + extern const char _var_example[]; + In this case of unsized uninitialized array declaration, CTF encodes an + explicit zero for the number of elements. This is quite distinct from + DWARF which encodes no bound information in such a case. + TBD - confirm this behaviour. */ + if (type_of_index) + { + lower = TYPE_MIN_VALUE (type_of_index); + upper = TYPE_MAX_VALUE (type_of_index); + min_index = tree_to_shwi (lower); + /* TYPE_MAX_VALUE of index may be null for variable-length arrays. */ + max_index = upper ? tree_to_shwi (upper) : 0; + gcc_assert (max_index >= min_index); + /* If max_index == min_index, both the values must be zero; num_elements + set to zero in that case. */ + num_elements = (max_index != min_index) ? max_index - min_index + 1 : 0; + gcc_assert (num_elements <= CTF_MAX_SIZE); + } + + arinfo.ctr_nelems = num_elements; + + /* Overwrite the type_of_index with integer_type_node. + TYPE_DOMAIN of ARRAY_TYPE have code INTEGER_TYPE, but have no + IDENTIFIER_NODES. This causes issues in retrieving the name string of + the index type (See gen_ctf_base_type) becuase the TYPE_IDENTIFIER is NULL + in those cases. + Use integer_type_node instead. This also helps gen_ctf_base_type to not + generate crooked (and duplicate) int records with wierd "integer" size for + arrays. */ + type_of_index = integer_type_node; + + ctf_index_type_id = gen_ctf_type (ctfc, type_of_index); + arinfo.ctr_index = ctf_index_type_id; + + ctf_contents_type_id = gen_ctf_type (ctfc, type_of_array_element); + arinfo.ctr_contents = ctf_contents_type_id; + + type_id = ctf_add_array (ctfc, CTF_ADD_ROOT, &arinfo, array_type); + + return type_id; +} + +static ctf_id_t +gen_ctf_forward_type (ctf_container_ref ctfc, tree fwd_type, uint32_t kind) +{ + ctf_id_t fwd_type_id = 0; + + const char * fwd_name = get_type_name_string (fwd_type); + /* Type de-duplication is already done by now. See gen_ctf_type (). + Simple add the forward type. */ + fwd_type_id = ctf_add_forward (ctfc, CTF_ADD_ROOT, fwd_name, kind, fwd_type); + + return fwd_type_id; +} + +static void +gen_ctf_enum_const_list (ctf_container_ref ctfc, const tree enum_type, + const ctf_id_t enum_type_id) +{ + tree link; + tree enum_value; + HOST_WIDE_INT value; + /* Append the enum values to the CTF_K_ENUM record. */ + for (link = TYPE_VALUES (enum_type); link != NULL; link = TREE_CHAIN (link)) + { + enum_value = TREE_VALUE (link); + /* For now, handle enumeration constants not wider than + HOST_WIDE_INT. TBD handle this. */ + gcc_assert (int_size_in_bytes (TREE_TYPE (enum_value))*HOST_BITS_PER_CHAR + <= HOST_BITS_PER_WIDE_INT || tree_fits_shwi_p (enum_value)); + + value = TREE_INT_CST_LOW (enum_value); + const char * enum_valname = IDENTIFIER_POINTER (TREE_PURPOSE (link)); + gcc_assert (enum_valname); + + ctf_add_enumerator (ctfc, enum_type_id, enum_valname, value, enum_type); + } +} + +static ctf_id_t +gen_ctf_enum_type (ctf_container_ref ctfc, tree enum_type) +{ + ctf_id_t enum_type_id = CTF_NULL_TYPEID; + HOST_WIDE_INT size; + + gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE); + + if (!TYPE_SIZE (enum_type)) + { + /* Add CTF forward type of enum kind. */ + uint32_t kind = CTF_K_ENUM; + enum_type_id = gen_ctf_forward_type (ctfc, enum_type, kind); + return enum_type_id; + } + + const char * enum_name = get_type_name_string (enum_type); + size = int_size_in_bytes (enum_type); + + /* Add CTF enum type. */ + enum_type_id = ctf_add_enum (ctfc, CTF_ADD_ROOT, enum_name, size, enum_type); + /* Add CTF records for enum const values. */ + gen_ctf_enum_const_list (ctfc, enum_type, enum_type_id); + + return enum_type_id; +} + +static ctf_id_t +gen_ctf_function_type (ctf_container_ref ctfc, tree func_decl_or_type, + const char * func_name) +{ + ctf_id_t type_id = CTF_NULL_TYPEID, return_type_id = CTF_NULL_TYPEID; + tree func_type; + tree link; + tree first_param_type; + tree formal_type = NULL; + tree return_type = NULL; + tree param_type; + uint32_t num_args = 0; + ctf_func_arg_t * argv_ids; + ctf_funcinfo_t func_info; + + if (TREE_CODE (func_decl_or_type) == FUNCTION_TYPE) + func_type = func_decl_or_type; + else + func_type = TREE_TYPE (func_decl_or_type); + + return_type = TREE_TYPE (func_type); + first_param_type = TYPE_ARG_TYPES (func_type); + + /* Add CTF record for function return type. */ + return_type_id = gen_ctf_type (ctfc, return_type); + func_info.ctc_return = return_type_id; + + /* Make our first pass over the list of formal parameter types and count + them. */ + for (link = first_param_type; link;) + { + formal_type = TREE_VALUE (link); + if (formal_type == void_type_node) + break; + + num_args++; + + link = TREE_CHAIN (link); + } + + /* Check if this function type has an ellipsis. */ + if (formal_type != void_type_node) + { + func_info.ctc_flags |= CTF_FUNC_VARARG; + /* Increment the number of args. This is the number of args we write + after the CTF_K_FUNCTION CTF record. */ + num_args++; + } + + /* The number of typed arguments should include the ellipsis. */ + func_info.ctc_argc = num_args; + + /* Create an array of ctf_id_t to hold CTF types for args (including the + ellipsis). */ + argv_ids = ggc_vec_alloc(num_args); + + /* Make a pass over the list of formal parameter types and generate CTF for + each. */ + unsigned int i = 0; + for (link = TYPE_ARG_TYPES (func_type); + link && TREE_VALUE (link); + link = TREE_CHAIN (link)) + { + param_type = TREE_VALUE (link); + + if (param_type == void_type_node) + break; + + argv_ids[i++].farg_type = gen_ctf_type (ctfc, param_type); + } + + if (formal_type != void_type_node) + { + /* Add trailing zero to indicate varargs. */ + argv_ids[i].farg_type = 0; + gcc_assert (i == num_args - 1); + } + + type_id = ctf_add_function (ctfc, CTF_ADD_ROOT, func_name, + (const ctf_funcinfo_t *)&func_info, argv_ids, + func_decl_or_type); + + return type_id; +} + +/* Add CTF qualifier record. + + If there are multiple qualifiers, the recommended ordering for CTF qualifier + records is const, volatile, restrict (from top-most to bottom-most). */ + +static ctf_id_t +gen_ctf_cvrquals (ctf_container_ref ctfc, tree type, ctf_id_t type_id) +{ + tree qualified_type; + int flags; + uint32_t cvrint = 0; + int quals_index = 0; + + ctf_id_t qual_type_id = type_id; + int cvr_quals = get_cvr_quals_for_type (type); + + int quals_order[3] = { TYPE_QUAL_RESTRICT, + TYPE_QUAL_VOLATILE, + TYPE_QUAL_CONST }; + ctf_id_t (*func_ptrs[3]) (ctf_container_ref, uint32_t, ctf_id_t, tree, + uint32_t) = { ctf_add_restrict, + ctf_add_volatile, + ctf_add_const }; + unsigned int key_flags[3] = { CTF_K_RESTRICT, CTF_K_VOLATILE, CTF_K_CONST }; + ctf_id_t (*ctf_add_qual_func) (ctf_container_ref, uint32_t, ctf_id_t, tree, + uint32_t); + + qualified_type = get_qualified_type (type, cvr_quals); + + /* Type de-duplication for cvr records. + Do not add CTF types for the same type with the matching cvr qual + if already present. */ + if (qualified_type) + { + if (ctf_type_exists (ctfc, qualified_type, &qual_type_id)) + return qual_type_id; + } + else + /* If the qualified_type is NULL, use TREE_TYPE of the decl to add + the CTF record. CTF for unqualified type must have been added by + now. */ + gcc_assert (ctf_type_exists (ctfc, type, &qual_type_id)); + + /* CTF represents distinct type records for each qualifier (CTF_K_RESTRICT, + CTF_K_VOLATILE, CTF_K_CONST). The records can be shared between types. + Here we try to de-duplicate these records as well. */ + while (cvr_quals) + { + flags = cvr_quals & quals_order[quals_index]; + ctf_add_qual_func = func_ptrs[quals_index]; + if (flags) + { + /* Reset the corresponding cvr_qual flag so that it is not processed + again. */ + cvr_quals &= ~quals_order[quals_index]; + cvrint = (cvr_quals != 0); + + /* The dtd_decl of the all CTF type records should be non-null for + de-duplication to work. CTF records for CVR quals of a type will + have the same dtd_decl in this case. So, to prevent collisions, we + use dtd_decl and dtd_key_flags for creating the hashkey. */ + ctf_dtdef_ref qual_type_exists + = ctf_dtd_lookup_with_flags (ctfc, type, key_flags[quals_index]); + if (qual_type_exists) + qual_type_id = qual_type_exists->dtd_type; + else + qual_type_id = ctf_add_qual_func (ctfc, CTF_ADD_ROOT, qual_type_id, + type, cvrint); + } + quals_index++; + } + + /* At least one CTF record must have been added or found to be duplicate + by now. */ + gcc_assert (qual_type_id != type_id); + + return qual_type_id; +} + +static ctf_id_t +gen_ctf_sou_type (ctf_container_ref ctfc, tree sou_type) +{ + HOST_WIDE_INT sou_size; + + ctf_id_t sou_type_id = CTF_NULL_TYPEID; + ctf_id_t field_type_id = CTF_NULL_TYPEID; + + tree field; + HOST_WIDE_INT bit_offset = 0; + + gcc_assert (RECORD_OR_UNION_TYPE_P (sou_type)); + + /* Handle anonymous record or union. */ +#if 0 + if (TYPE_NAME (sou_type) == NULL) + { + /* TBD - confirm this behaviour. + The compiler will not flatten an anonymous struct or union into its + parent if one exists. Members of anonymous struct or union continue + to be wrappped by the respective anonymous record. */ + } +#endif + uint32_t kind = (TREE_CODE (sou_type) == RECORD_TYPE) + ? CTF_K_STRUCT : CTF_K_UNION; + + if (!TYPE_SIZE (sou_type)) + { + /* Add CTF forward type of struct or union kind. */ + sou_type_id = gen_ctf_forward_type (ctfc, sou_type, kind); + return sou_type_id; + } + + const char * sou_name = get_type_name_string (sou_type); + sou_size = int_size_in_bytes (sou_type); + + /* Add CTF struct/union type. */ + if ((TREE_CODE (sou_type) == RECORD_TYPE) + || (TREE_CODE (sou_type) == UNION_TYPE)) + sou_type_id = ctf_add_sou (ctfc, CTF_ADD_ROOT, sou_name, kind, sou_size, + sou_type); + /* QUAL_UNION_TYPE not expected in C. */ + else + gcc_unreachable (); + + /* Add members of the struct. */ + for (field = TYPE_FIELDS (sou_type); field != NULL_TREE; + field = TREE_CHAIN (field)) + { + /* Enum members have DECL_NAME (field) as NULL. */ + const char * field_name = get_decl_name_string (field); + + /* variable bit offsets are not handled at the moment. */ + gcc_assert (TREE_CODE (DECL_FIELD_BIT_OFFSET (field)) == INTEGER_CST); + + bit_offset = int_bit_position (field); + /* Add the CTF type record for the field, followed by the field + itself. */ + field_type_id = gen_ctf_type_for_decl (ctfc, field); + ctf_add_member_offset (ctfc, sou_type, field_name, field_type_id, + bit_offset); + } + + return sou_type_id; +} + +/* Parent routines for CTF generation. + These routines are entry points for CTF generation. Given a type or decl, + these routines perform de-duplication before invoking the Leaf CTF + generation routines for adding types. */ + +/* Generate CTF typedef records for a given declaration. Performs + de-duplication before adding typedef. */ + +static ctf_id_t +gen_ctf_typedef (ctf_container_ref ctfc, tree decl) +{ + ctf_id_t type_id = CTF_NULL_TYPEID, typedef_type_id = CTF_NULL_TYPEID; + + tree type = TREE_TYPE (decl); + const char * decl_name_string = get_type_name_string (type); + + /* CTF type de-duplication in the compiler. + Do not add duplicate typedef. */ + if (ctf_type_exists (ctfc, decl, &type_id)) + return type_id; + + /* Generate the type if not already done. */ + type_id = gen_ctf_type_for_decl (ctfc, decl); + + /* Add typedef. dtd_decl points to the typedef tree node. */ + typedef_type_id = ctf_add_typedef (ctfc, CTF_ADD_ROOT, decl_name_string, + type_id, decl); + type_id = typedef_type_id; + + return type_id; +} + +/* Generate CTF variable records for a given declaration. Performs + de-duplication before adding variable. */ + +static ctf_id_t +gen_ctf_variable (ctf_container_ref ctfc, tree decl) +{ + ctf_id_t type_id = CTF_NULL_TYPEID, var_type_id = CTF_NULL_TYPEID; + + const char* name = get_decl_name_string (decl); + + ctf_dvdef_ref var_type_seen = ctf_dvd_lookup (tu_ctfc, decl); + /* Avoid duplicates. A VAR_DECL is duplicate if it is the same decl node. + See hash_dvd_tree_decl. */ + if (!var_type_seen) + { + type_id = gen_ctf_type_for_decl (ctfc, decl); + /* Now add the variable. */ + var_type_id = ctf_add_variable (tu_ctfc, name, type_id, decl); + } + else + var_type_id = var_type_seen->dvd_type; + + return var_type_id; +} + +/* Generate CTF function records for a given declaration. */ + +static ctf_id_t +gen_ctf_function (ctf_container_ref ctfc, tree func_decl) +{ + gcc_assert (TREE_CODE (func_decl) == FUNCTION_DECL); + + ctf_id_t type_id = CTF_NULL_TYPEID; + + const char * func_name = get_decl_name_string (func_decl); + + /* Duplicate function types are expected to be seen as functions with same + signature will show the same function type. For each distinct function + declaration, however, CTF function type records must be added anew. + Duplicate function *declarations* must, however be avoided. This is + expected to happen if the gen_ctf_function API is called multiple times + for the same func_decl. */ + + bool exists = ctf_type_exists (ctfc, func_decl, &type_id); + gcc_assert (!exists); + + /* Add CTF Function type. */ + type_id = gen_ctf_function_type (ctfc, func_decl, func_name); + + /* Update global functions count. */ + if (TREE_PUBLIC (func_decl)) + ctfc->ctfc_num_global_funcs++; + + return type_id; +} + +/* Add CTF type record(s) for the given input type. */ +static ctf_id_t +gen_ctf_type (ctf_container_ref ctfc, tree type) +{ + ctf_id_t type_id = CTF_NULL_TYPEID; + + /* This API expects to handle tcc_type nodes only. + ctf_add_int/float etc == type == INTEGER_TYPE, REAL_TYPE etc + ctf_add_pointer == type == POINTER_TYPE + ctf_add_array == type == ARRAY_TYPE + ctf_add_sou == type == RECORD_TYPE, UNION_TYPE. */ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (type)) == tcc_type); + + int cvr_quals = get_cvr_quals_for_type (type); + + /* For a type of ARRAY_TYPE, type qualifiers (if any) are with + TREE_TYPE (type). TYPE_MAIN_VARIANT (type) however will not contain + these quals. Need to pass the former to gen_ctf_array_type. */ + tree gen_type = (TREE_CODE (type) == ARRAY_TYPE) + ? type : TYPE_MAIN_VARIANT (type); + + /* CTF type de-duplication in the compiler. */ + if (!ctf_type_exists (ctfc, gen_type, &type_id)) + { + /* Encountering a CTF type for the first time. Add the CTF type. */ + + if (is_ctf_base_type (gen_type)) + type_id = gen_ctf_base_type (ctfc, gen_type); + + else if (RECORD_OR_UNION_TYPE_P (gen_type)) + type_id = gen_ctf_sou_type (ctfc, gen_type); + + else if (TREE_CODE (gen_type) == ARRAY_TYPE) + type_id = gen_ctf_array_type (tu_ctfc, gen_type); + + else if (TREE_CODE (gen_type) == ENUMERAL_TYPE) + type_id = gen_ctf_enum_type (tu_ctfc, gen_type); + + else if (POINTER_TYPE_P (gen_type)) + type_id = gen_ctf_pointer_type (tu_ctfc, gen_type); + + else if (TREE_CODE (gen_type) == FUNCTION_TYPE) + /* Function pointers. */ + type_id = gen_ctf_function_type (tu_ctfc, gen_type, NULL); + + else + /* No other type is expected for C frontend. */ + gcc_unreachable (); + } + + /* Add qualifiers if any. */ + if (cvr_quals & ctf_cvr_qual_mask) + type_id = gen_ctf_cvrquals (ctfc, type, type_id); + + return type_id; +} + +/* Generate CTF records for bitfield declarations. */ + +static ctf_id_t +gen_ctf_bitfield_type_for_decl (ctf_container_ref ctfc, const tree field, + const ctf_id_t type_id) +{ + ctf_id_t bitfield_type_id = CTF_NULL_TYPEID; + + gcc_assert (TREE_CODE (field) == FIELD_DECL); + + gcc_assert (ctfc); + HOST_WIDE_INT size_in_bits = tree_to_shwi (DECL_SIZE (field)); + + ctf_encoding_t ep = {0,0,0}; + /* Assume default encoding as unsigned. */ + uint32_t encoding = 0; + tree type = TREE_TYPE (field); + + /* The type of a bit field can only be integral. */ + if (TREE_CODE (type) != INTEGER_TYPE) + gcc_unreachable (); + + /* Handle both enum bitfields and integer bitfields. */ + if (TYPE_STRING_FLAG (type)) + { + if (TYPE_UNSIGNED (type)) + encoding = CTF_INT_CHAR; + else + encoding = CTF_INT_CHAR | CTF_INT_SIGNED; + } + else if (!TYPE_UNSIGNED (type)) + encoding = CTF_INT_SIGNED; + + ep.cte_format = encoding; + /* The offset of the slice is the offset into a machine word. + TBD Handle big-endian - should the offset be byte-order dependent ? */ + ep.cte_offset = int_bit_position (field) % BITS_PER_WORD; + ep.cte_bits = size_in_bits; + + /* No type de-duplication for slices. + (Probe the CTF container with field_decl) + There is no way to de-duplicate two bitfields using just type or decl + references as dtd_key_decl. Two field declarations may share the + same TREE_TYPE and DECL_BIT_FIELD_TYPE references, but may have different + offset and num bits. */ + + bitfield_type_id = ctf_add_slice (ctfc, CTF_ADD_NONROOT, type_id, &ep, + field); + + return bitfield_type_id; +} + +static ctf_id_t +gen_ctf_type_for_decl (ctf_container_ref ctfc, tree decl) +{ + gcc_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == tcc_declaration); + + ctf_id_t type_id = CTF_NULL_TYPEID; + tree type; + tree bitfield_type = NULL; + + type = TREE_TYPE (decl); + + /* In a FIELD_DECL, this indicates whether the field was a bitfield. */ + if (TREE_CODE (decl) == FIELD_DECL) + bitfield_type = DECL_BIT_FIELD_TYPE (decl); + + /* Create CTF for the unqualified type, if it not done already. If it's a + bitfield type, use that to generate the CTF type record. */ + if (bitfield_type) + type = bitfield_type; + + /* CTF type de-duplication in the compiler. + Lookup if CTF for unqualified type has already been added. CTF slices are + not shared across declarations. */ + if (ctf_type_exists (ctfc, type, &type_id)) + { + if (!bitfield_type) + return type_id; + } + else + type_id = gen_ctf_type (ctfc, type); + + /* Now, create CTF slice if it is a bitfield. */ + if (bitfield_type) + type_id = gen_ctf_bitfield_type_for_decl (ctfc, decl, type_id); + + return type_id; +} + +/* 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. */ + list_add_ctf_vars (ctfc, var); +} + +/* CTF preprocess callback routine for CTF variables. */ + +bool +ctf_dvd_preprocess_cb (tree const & ARG_UNUSED (key), ctf_dvdef_ref * slot, + void * arg) +{ + ctf_dvd_preprocess_arg_t * dvd_arg = (ctf_dvd_preprocess_arg_t *)arg; + + ctf_container_ref arg_ctfc = dvd_arg->dvd_arg_ctfc; + ctf_dvdef_ref var = (ctf_dvdef_ref) *slot; + + ctf_preprocess_var (arg_ctfc, var); + + return 1; +} + +/* CTF preprocess callback routine for CTF types. */ + +bool +ctf_dtd_preprocess_cb (ctf_dtdef_ref const & ARG_UNUSED (key), + ctf_dtdef_ref * slot, void * arg) +{ + uint32_t kind, vlen; + tree func_decl; + + 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. */ + kind = CTF_V2_INFO_KIND (ctftype->dtd_data.ctti_info); + if (kind == CTF_K_FUNCTION) + { + func_decl = ctftype->dtd_decl; + if ((TREE_CODE_CLASS (TREE_CODE (func_decl)) == tcc_declaration) + && TREE_PUBLIC (func_decl)) + { + arg_ctfc->ctfc_gfuncs_list[dtd_arg->dtd_global_func_idx] = ctftype; + dtd_arg->dtd_global_func_idx++; + vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info); + /* Update the function info section size in bytes. Avoid using + ctf_calc_num_vbytes API, the latter is only meant to convey + the vlen bytes after CTF types in the CTF data types section. */ + arg_ctfc->ctfc_num_funcinfo_bytes += (vlen + 2) * sizeof (uint32_t); + } + } + + /* 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_vars = ctfc->ctfc_vars->elements (); + if (num_ctf_vars) + { + ctf_dvd_preprocess_arg_t dvd_arg; + dvd_arg.dvd_arg_ctfc = ctfc; + + /* Allocate CTF var list. */ + ctfc->ctfc_vars_list = ggc_vec_alloc(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 (&dvd_arg); + /* Sort the list. */ + qsort (ctfc->ctfc_vars_list, num_ctf_vars, sizeof (ctf_dvdef_ref), + ctf_varent_compare); + } + + size_t num_ctf_types = ctfc->ctfc_types->elements (); + + /* Initialize an array to keep track of the CTF functions types for global + functions in the 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(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 = tu_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(num_ctf_types + 1); + /* Pre-process CTF types. */ + ctfc->ctfc_types->traverse (&dtd_arg); + + gcc_assert (dtd_arg.dtd_global_func_idx == num_global_funcs); + } +} + +/* CTF asm helper routines. */ + /* Asm'out the CTF preamble. */ static void @@ -124,7 +1324,78 @@ ctf_asm_preamble (ctf_container_ref ctfc) dw2_asm_output_data (1, ctfc->ctfc_flags, "CTF preamble flags"); } -/* Output the CTF header. */ +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"); +} + +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"); +} + +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"); +} + +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"); +} + +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"); +} + +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"); +} + +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"); +} + +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"); +} + +/* CTF writeout to asm file. */ static void output_ctf_header (ctf_container_ref ctfc) @@ -133,6 +1404,282 @@ output_ctf_header (ctf_container_ref ctfc) 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"); + + 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 varoff = 0; + uint32_t typeoff = 0; + uint32_t stroff = 0; + + if (! is_empty_container (ctfc)) + { + gcc_assert (get_num_ctf_types (ctfc) + == (ctfc->ctfc_num_types + ctfc->ctfc_num_stypes)); + + /* Vars appear after function info. */ + varoff = funcoff + get_ctfc_num_funcinfo_bytes (ctfc); + /* CTF types appear after vars. */ + typeoff = varoff + 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)) + + get_ctfc_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 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"); +} + +static void +output_ctf_func_info (ctf_container_ref ctfc) +{ + unsigned long i, j; + ctf_dtdef_ref ctftype; + uint32_t vlen; + + /* Compiler spits out the function type, return type, and args of each global + function in the CTF funcinfo section. In no specific order. + TBD - An index needs to be added to associate these with the names. */ + for (i = 0; i < ctfc->ctfc_num_global_funcs; i++) + { + ctftype = ctfc->ctfc_gfuncs_list[i]; + vlen = CTF_V2_INFO_VLEN (ctftype->dtd_data.ctti_info); + + /* function type. */ + dw2_asm_output_data (4, ctftype->dtd_type, "funcinfo_func_type"); + + /* return type. */ + dw2_asm_output_data (4, ctftype->dtd_data.ctti_type, + "funcinfo_func_return_type"); + + /* function args types. */ + for (j = 0; j < vlen; j++) + dw2_asm_output_data (4, ctftype->dtd_u.dtu_argv[j].farg_type, + "funcinfo_func_args"); + } +} + +/* Output the CTF variables. Variables appear in the sort 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]); + } +} + +/* 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; + } +} + +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); +} + +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); +} + +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); + uint32_t i; + + 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: + { + for (i = 0; i < vlen; i++) + dw2_asm_output_data (4, ctftype->dtd_u.dtu_argv[i].farg_type, + "dtu_argv"); + /* 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); + 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; + } +} + +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); +} + +/* Output the 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]); + } +} + +static void +ctf_decl (tree decl) +{ + switch (TREE_CODE (decl)) + { + case ERROR_MARK: + return; + + case FUNCTION_DECL: + gen_ctf_function (tu_ctfc, decl); + break; + + case VAR_DECL: + gen_ctf_variable (tu_ctfc, decl); + break; + + case TYPE_DECL: + /* Stay aligned to what DWARF does. + DWARF has this check so as to not emit stubs for types unless they are + needed by other DIEs. */ + if (TYPE_DECL_SUPPRESS_DEBUG (decl)) + return; + + if (DECL_IS_BUILTIN (decl)) + return; + + /* If we are in terse mode, don't generate any CTF for types. */ + if (ctf_debug_info_level <= CTFINFO_LEVEL_TERSE) + return; + /* If function-scope tag, do not generate CTF type info for it. */ + if (decl_function_context (decl)) + return; + + gen_ctf_typedef (tu_ctfc, decl); + + break; + + default: + /* No other TREE_CODE is expected at this time. */ + gcc_unreachable (); + } } /* CTF routines interfacing to the compiler. */ @@ -149,16 +1696,32 @@ ctf_early_finish (const char * ARG_UNUSED (filename)) if (ctf_debug_info_level == CTFINFO_LEVEL_NONE) return; - init_ctf_sections (); + init_ctf_sections (false); + + /* Pre-process CTF before generating assembly. */ + ctf_preprocess (tu_ctfc); output_ctf_header (tu_ctfc); + output_ctf_func_info (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 == get_cur_ctf_str_len (tu_ctfc)); + + delete_ctf_container (tu_ctfc); } void -ctf_early_global_decl (tree ARG_UNUSED (decl)) +ctf_early_global_decl (tree decl) { /* Generate CTF type information if appropriate debug level is set - (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL). */ + to CTFINFO_LEVEL_NORMAL. */ + + if (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL) + ctf_decl (decl); } /* Reset all state within ctfout.c so that we can rerun the compiler @@ -170,6 +1733,7 @@ ctfout_c_finalize (void) ctf_info_section = NULL; delete_ctf_container (tu_ctfc); + tu_ctfc = NULL; } #include "gt-ctfout.h" diff --git a/gcc/ctfout.h b/gcc/ctfout.h index f281aaf..1ad360d 100644 --- a/gcc/ctfout.h +++ b/gcc/ctfout.h @@ -24,10 +24,189 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_CTFOUT_H #define GCC_CTFOUT_H 1 +#include "config.h" +#include "system.h" +#include "tree.h" +#include "fold-const.h" +#include "tree-hash-traits.h" #include "ctf.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 unsigned long 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 . */ + +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 except the GTY (()) tags. */ + +typedef struct GTY (()) ctf_itype +{ + unsigned int ctti_name; /* Reference to name in string table. */ + unsigned int ctti_info; /* Encoded kind, variant length (see below). */ + union GTY ((desc ("0"))) + { + unsigned int GTY ((tag ("0"))) _size;/* Size of entire type in bytes. */ + unsigned int GTY ((tag ("1"))) _type;/* Reference to another type. */ + } _u; + unsigned int ctti_lsizehi; /* High 32 bits of type size in bytes. */ + unsigned int 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). */ + unsigned int dmd_name_offset; /* Offset of the name in str table. */ + unsigned long 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; + +/* Function Argument. (Encapsulated because GTY machinery does not like + non struct/union members. See usage in ctf_dtdef_t.) */ + +typedef struct GTY (()) ctf_func_arg +{ + ctf_id_t farg_type; /* Type identifier of the argument. */ +} ctf_func_arg_t; + +typedef struct GTY (()) ctf_dtdef_key +{ + tree dtdk_key_decl; /* Tree decl corresponding to the type. */ + unsigned int dtdk_key_flags; /* Extra flags for hashing the type. */ +} ctf_dtdef_key_t; + +/* Type definition for CTF generation. */ + +typedef struct GTY (()) ctf_dtdef +{ + ctf_dtdef_key_t 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. */ + 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; +} ctf_dtdef_t; + +#define dtd_decl dtd_key.dtdk_key_decl +#define dtd_key_flags dtd_key.dtdk_key_flags + +/* Variable definition for CTF generation. */ + +typedef struct GTY (()) ctf_dvdef +{ + tree dvd_decl; /* Tree decl corresponding to the variable. */ + const char * dvd_name; /* Name associated with variable. */ + unsigned int dvd_name_offset; /* Offset of the name in str table. */ + ctf_id_t dvd_type; /* Type of variable. */ +} ctf_dvdef_t; + +typedef ctf_dvdef_t * ctf_dvdef_ref; +typedef ctf_dtdef_t * ctf_dtdef_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 ctf_dtdef_hash : ggc_ptr_hash +{ + typedef ctf_dtdef_ref compare_type; + static hashval_t hash (ctf_dtdef_ref); + static bool equal (ctf_dtdef_ref, ctf_dtdef_ref); +}; + /* CTF container structure. - It is the context passed around when generating CTF debug info. There is + It is the context passed around when generating ctf debug info. There is one container per translation unit. */ typedef struct GTY (()) ctf_container @@ -36,12 +215,63 @@ typedef struct GTY (()) ctf_container unsigned short ctfc_magic; unsigned char ctfc_version; unsigned char ctfc_flags; - /* CTF Types. */ - // hash_map * GTY (()) ctfc_types; + + /* CTF types. */ + hash_map * GTY (()) ctfc_types; + /* CTF variables. */ + hash_map * GTY (()) ctfc_vars; + /* CTF string table. */ + ctf_strtable_t ctfc_strtable; + + unsigned long ctfc_num_types; + unsigned long ctfc_num_stypes; + unsigned long ctfc_num_global_funcs; + + unsigned long ctfc_num_funcinfo_bytes; + /* 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. */ + unsigned long ctfc_num_vlen_bytes; + + /* Next CTF type id to assign. */ + ctf_id_t ctfc_nextid; + /* List of pre-processed CTF Variables. CTF requires that the variables + appear in the sorted order of their names. */ + ctf_dvdef_t ** GTY ((length ("%h.ctfc_vars ? %h.ctfc_vars->elements () : 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 ("%h.ctfc_types ? %h.ctfc_types->elements () : 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 ("%h.ctfc_num_global_funcs"))) ctfc_gfuncs_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. */ + unsigned long ctfc_numbytes_asm; + /* Total length of all strings in CTF. */ + size_t ctfc_strlen; + } ctf_container_t; typedef ctf_container_t * ctf_container_ref; +/* If the next ctf type id is still set to the init value, no ctf records to + report. */ +#define is_empty_container(ctfc) (((ctfc)->ctfc_nextid == CTF_INIT_TYPEID)) +#define get_num_ctf_vars(ctfc) (ctfc->ctfc_vars->elements ()) +#define get_num_ctf_types(ctfc) (ctfc->ctfc_types->elements ()) + +#define get_cur_ctf_str_len(ctfc) ((ctfc)->ctfc_strtable.ctstab_len) + +#define get_ctfc_num_vlen_bytes(ctfc) ((ctfc)->ctfc_num_vlen_bytes) +#define get_ctfc_num_funcinfo_bytes(ctfc) ((ctfc)->ctfc_num_funcinfo_bytes) + void ctf_debug_init (void); void ctf_early_global_decl (tree decl); @@ -50,4 +280,80 @@ void ctf_early_finish (const char * filename); void ctfout_c_finalize (void); +/* 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. */ + +/* Interface from ctfcreate.c to ctfout.c. + These APIs create CTF types and add them to the CTF container associated + with the translation unit. The return value is the typeID of the CTF type + added to the container. */ +extern ctf_id_t ctf_add_volatile (ctf_container_ref, uint32_t, ctf_id_t, tree, + uint32_t); +extern ctf_id_t ctf_add_const (ctf_container_ref, uint32_t, ctf_id_t, tree, + uint32_t); +extern ctf_id_t ctf_add_restrict (ctf_container_ref, uint32_t, ctf_id_t, tree, + uint32_t); +extern ctf_id_t ctf_add_enum (ctf_container_ref, uint32_t, const char *, + HOST_WIDE_INT, tree); +extern ctf_id_t ctf_add_slice (ctf_container_ref, uint32_t, ctf_id_t, + const ctf_encoding_t *, tree); +extern ctf_id_t ctf_add_float (ctf_container_ref, uint32_t, const char *, + const ctf_encoding_t *, tree); +extern ctf_id_t ctf_add_integer (ctf_container_ref, uint32_t, const char *, + const ctf_encoding_t *, tree); +extern ctf_id_t ctf_add_pointer (ctf_container_ref, uint32_t flag, ctf_id_t, + tree); +extern ctf_id_t ctf_add_array (ctf_container_ref, uint32_t, + const ctf_arinfo_t *, tree); +extern ctf_id_t ctf_add_forward (ctf_container_ref, uint32_t, const char *, + uint32_t, tree); +extern ctf_id_t ctf_add_typedef (ctf_container_ref, uint32_t, const char *, + ctf_id_t, tree); +extern ctf_id_t ctf_add_function (ctf_container_ref, uint32_t, const char *, + const ctf_funcinfo_t *, ctf_func_arg_t *, + tree); +extern ctf_id_t ctf_add_sou (ctf_container_ref, uint32_t, const char *, + uint32_t, size_t, tree); + +extern int ctf_add_enumerator (ctf_container_ref, ctf_id_t, const char *, + HOST_WIDE_INT, tree); +extern int ctf_add_member_offset (ctf_container_ref, tree, const char *, + ctf_id_t, unsigned long); +extern int ctf_add_variable (ctf_container_ref, const char *, ctf_id_t, tree); + +/* Interface from ctfutils.c. + Utility functions for CTF generation. */ + +#define ctf_dmd_list_next(elem) ((ctf_dmdef_t *)((elem)->dmd_next)) + +extern void ctf_dmd_list_append (ctf_dmdef_t **, ctf_dmdef_t *); + +extern void ctf_dtd_insert (ctf_container_ref, ctf_dtdef_ref); +extern void ctf_dtd_delete (ctf_container_ref, ctf_dtdef_ref); +extern ctf_dtdef_ref ctf_dtd_lookup (const ctf_container_ref, const tree); +extern ctf_dtdef_ref ctf_dtd_lookup_with_flags (const ctf_container_ref, + const tree, + const unsigned int); + +extern void ctf_dvd_insert (ctf_container_ref, ctf_dvdef_ref); +extern void ctf_dvd_delete (ctf_container_ref, ctf_dvdef_ref); +extern ctf_dvdef_ref ctf_dvd_lookup (const ctf_container_ref, const tree); + +extern int ctf_varent_compare (const void *, const void *); +extern unsigned long ctf_calc_num_vbytes (ctf_dtdef_ref); + +/* Add a str to the CTF string table. */ +extern const char * ctf_add_string (ctf_container_ref, const char *, + uint32_t *); + +extern void list_add_ctf_vars (ctf_container_ref, ctf_dvdef_ref); + +/* Interface from ctfout.c to ctfutils.c. */ + +extern hashval_t hash_dtd_tree_decl (tree, uint32_t); +extern hashval_t hash_dvd_tree_decl (tree); + #endif /* GCC_CTFOUT_H */ diff --git a/gcc/ctfutils.c b/gcc/ctfutils.c new file mode 100644 index 0000000..805c91f --- /dev/null +++ b/gcc/ctfutils.c @@ -0,0 +1,198 @@ +/* Functions to create and update CTF from GCC. + Copyright (C) 2019 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 +. */ + +/* This file contains implementation of various utility functions to collect + and keep CTF information. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "ctfout.h" + +/* Append member definition to the list. Member list is a singly-linked list + with list start pointing to the head. */ + +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; +} + +/* Compare two CTF variable definition entries. Currently used for sorting + by name. */ + +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; +} + +/* Add str to CTF string table. No de-duplication of CTF strings is done by + the compiler. */ + +static void +ctfc_strtable_add_str (ctf_strtable_t * str_table, const char * str) +{ + ctf_string_t * ctf_string = ggc_cleared_alloc (); + /* 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; +} + +const char * +ctf_add_string (ctf_container_ref ctfc, 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 = get_cur_ctf_str_len (ctfc); + + /* 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 *, ctfc->ctfc_strtable.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_add_str (&(ctfc->ctfc_strtable), ctf_string); + /* Add string to the string table. Keep number of strings updated. */ + ctfc->ctfc_strtable.ctstab_num++; + /* Keep the number of bytes contained in the CTF string table updated. */ + (ctfc)->ctfc_strtable.ctstab_len += len; + } + + *name_offset = str_offset; + + return (const char *) ctf_string; +} + +/* 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. */ + +unsigned long +ctf_calc_num_vbytes (ctf_dtdef_ref ctftype) +{ + uint32_t size; + unsigned long 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; + uint32_t size_per_member = 0; + unsigned int num_members = 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: + /* 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; +} + +void +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; +} diff --git a/include/ctf.h b/include/ctf.h index 3a6f266..5289846 100644 --- a/include/ctf.h +++ b/include/ctf.h @@ -378,13 +378,17 @@ union 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. */ + 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 char cts_offset; - unsigned char cts_bits; + unsigned short cts_offset; + unsigned short cts_bits; } ctf_slice_t; typedef struct ctf_array