Initialize CTF container when -gtLEVEL is specified. Generate CTF debug info for global decls. Import the CTF header from binutils.
gcc/ChangeLog : * Makefile.in: Add ctfout.* files to GTFILES. * cgraphunit.c (symbol_table::finalize_compilation_unit): Generate CTF debug info for decl. Invoke CTF debug info emission. * ctfout.c: New file. * ctfout.h: Likewise. * gengtype.c (open_base_files): Add ctfout.h to ifiles. * passes.c (rest_of_decl_compilation): Generate CTF debug info for decl. * toplev.c (process_options): Warn and ignore -gtLEVEL if frontend is not C. (toplev::finalize): Finalize CTF containers. gcc/testsuite/ChangeLog : * gcc.dg/debug/ctf/ctf-1.c: New test. * gcc.dg/debug/ctf/ctf-preamble-1.c: Likewise. * gcc.dg/debug/ctf/ctf.exp: Add CTF testsuite. * gcc.dg/debug/dwarf2-ctf-1.c: New test. include/ChangeLog : * ctf.h: Import from binutils. --- gcc/ChangeLog | 14 + gcc/Makefile.in | 3 + gcc/cgraphunit.c | 12 +- gcc/ctfout.c | 175 +++++++++ gcc/ctfout.h | 53 +++ gcc/gengtype.c | 4 +- gcc/passes.c | 7 +- gcc/testsuite/ChangeLog | 7 + gcc/testsuite/gcc.dg/debug/ctf/ctf-1.c | 6 + gcc/testsuite/gcc.dg/debug/ctf/ctf-preamble-1.c | 11 + gcc/testsuite/gcc.dg/debug/ctf/ctf.exp | 41 ++ gcc/testsuite/gcc.dg/debug/dwarf2-ctf-1.c | 7 + gcc/toplev.c | 18 + include/ChangeLog | 4 + include/ctf.h | 483 ++++++++++++++++++++++++ 15 files changed, 839 insertions(+), 6 deletions(-) create mode 100644 gcc/ctfout.c create mode 100644 gcc/ctfout.h create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf-preamble-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/ctf/ctf.exp create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2-ctf-1.c create mode 100644 include/ctf.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index d9e0885..8ce2405 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1254,6 +1254,7 @@ OBJS = \ cfgloopanal.o \ cfgloopmanip.o \ cfgrtl.o \ + ctfout.o \ symtab.o \ cgraph.o \ cgraphbuild.o \ @@ -2532,6 +2533,8 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/dwarf2asm.c \ $(srcdir)/dwarf2cfi.c \ $(srcdir)/dwarf2out.c \ + $(srcdir)/ctfout.h \ + $(srcdir)/ctfout.c \ $(srcdir)/tree-vect-generic.c \ $(srcdir)/dojump.c $(srcdir)/emit-rtl.h \ $(srcdir)/emit-rtl.c $(srcdir)/except.h $(srcdir)/explow.c $(srcdir)/expr.c \ diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index f4d6688..9cf6252 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -205,6 +205,7 @@ along with GCC; see the file COPYING3. If not see #include "lto-section-names.h" #include "stringpool.h" #include "attribs.h" +#include "ctfout.h" /* Queue of cgraph nodes scheduled to be added into cgraph. This is a secondary queue used during optimization to accommodate passes that @@ -2844,17 +2845,22 @@ symbol_table::finalize_compilation_unit (void) if (!seen_error ()) { - /* Emit early debug for reachable functions, and by consequence, - locally scoped symbols. */ + /* Emit early debug and CTF debug info for reachable functions, and by + consequence, locally scoped symbols. */ struct cgraph_node *cnode; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cnode) - (*debug_hooks->early_global_decl) (cnode->decl); + { + (*debug_hooks->early_global_decl) (cnode->decl); + ctf_early_global_decl (cnode->decl); + } /* Clean up anything that needs cleaning up after initial debug generation. */ debuginfo_early_start (); (*debug_hooks->early_finish) (main_input_filename); + ctf_early_finish (main_input_filename); debuginfo_early_stop (); + } /* Finally drive the pass manager. */ diff --git a/gcc/ctfout.c b/gcc/ctfout.c new file mode 100644 index 0000000..1ce9829 --- /dev/null +++ b/gcc/ctfout.c @@ -0,0 +1,175 @@ +/* Output CTF format 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 +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "rtl.h" +#include "tree.h" +#include "memmodel.h" +#include "tm_p.h" +#include "varasm.h" +#include "output.h" +#include "dwarf2asm.h" +#include "debug.h" +#include "ctfout.h" + +/* A CTF container object - one per translation unit. */ + +static GTY (()) ctf_container_ref tu_ctfc; + +static int ctf_label_num; + +/* Pointers to various CTF sections. */ + +static GTY (()) section * ctf_info_section; + +/* Section names used to hold CTF debugging information. */ + +#ifndef CTF_INFO_SECTION_NAME +#define CTF_INFO_SECTION_NAME ".ctf" +#endif + +/* Section flags for .ctf section. */ + +/* 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 container setup and teardown routines. */ + +/* Allocate a new CTF container with the desired flags. */ + +static inline ctf_container_ref +new_ctf_container (unsigned char ctp_flags) +{ + tu_ctfc = ggc_cleared_alloc<ctf_container_t> (); + + tu_ctfc->ctfc_magic = CTF_MAGIC; + tu_ctfc->ctfc_version = CTF_VERSION; + tu_ctfc->ctfc_flags = ctp_flags; + + return tu_ctfc; +} + +/* Initialize a CTF container per translation unit. */ + +static void +init_ctf_containers (void) +{ + tu_ctfc = new_ctf_container (0); +} + +/* Delete the CTF container's resources. */ + +static void +delete_ctf_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 = NULL; + } +} + +/* Initialize the various sections and labels for CTF output. */ + +void +init_ctf_sections (void) +{ + 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++); +} + +/* 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"); +} + +/* Output the CTF header. */ + +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); +} + +/* CTF routines interfacing to the compiler. */ + +void +ctf_debug_init (void) +{ + init_ctf_containers (); +} + +void +ctf_early_finish (const char * ARG_UNUSED (filename)) +{ + if (ctf_debug_info_level == CTFINFO_LEVEL_NONE) + return; + + init_ctf_sections (); + + output_ctf_header (tu_ctfc); +} + +void +ctf_early_global_decl (tree ARG_UNUSED (decl)) +{ + /* Generate CTF type information if appropriate debug level is set + (ctf_debug_info_level == CTFINFO_LEVEL_NORMAL). */ +} + +/* Reset all state within ctfout.c so that we can rerun the compiler + within the same process. For use by toplev::finalize. */ + +void +ctfout_c_finalize (void) +{ + ctf_info_section = NULL; + + delete_ctf_container (tu_ctfc); +} + +#include "gt-ctfout.h" diff --git a/gcc/ctfout.h b/gcc/ctfout.h new file mode 100644 index 0000000..f281aaf --- /dev/null +++ b/gcc/ctfout.h @@ -0,0 +1,53 @@ +/* ctfout.h - Various declarations for functions found in ctfout.c + 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 +<http://www.gnu.org/licenses/>. */ + +/* This file defines all data structures used by the compiler to generate + CTF types. These are compiler internal representations and closely + reflect the CTF format requirements in <ctf.h>. */ + +#ifndef GCC_CTFOUT_H +#define GCC_CTFOUT_H 1 + +#include "ctf.h" + +/* 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; + /* CTF Types. */ + // hash_map <ctf_dtdef_hash, ctf_dtdefp_t> * GTY (()) ctfc_types; +} ctf_container_t; + +typedef ctf_container_t * ctf_container_ref; + +void ctf_debug_init (void); + +void ctf_early_global_decl (tree decl); + +void ctf_early_finish (const char * filename); + +void ctfout_c_finalize (void); + +#endif /* GCC_CTFOUT_H */ diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 5331733..39de737 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1724,8 +1724,8 @@ open_base_files (void) "tree-dfa.h", "tree-ssa.h", "reload.h", "cpplib.h", "tree-chrec.h", "except.h", "output.h", "cfgloop.h", "target.h", "lto-streamer.h", "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", NULL + "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "ctfout.h", + "omp-general.h", "omp-offload.h", NULL }; const char *const *ifp; outf_p gtype_desc_c; diff --git a/gcc/passes.c b/gcc/passes.c index c6331cb..c0f1e57 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -63,6 +63,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic-core.h" /* for fnotice */ #include "stringpool.h" #include "attribs.h" +#include "ctfout.h" using namespace gcc; @@ -322,7 +323,11 @@ rest_of_decl_compilation (tree decl, /* Avoid confusing the debug information machinery when there are errors. */ && !seen_error ()) - (*debug_hooks->early_global_decl) (decl); + { + (*debug_hooks->early_global_decl) (decl); + /* Generate CTF debug info. */ + ctf_early_global_decl (decl); + } } /* Called after finishing a record, union or enumeral type. */ diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-1.c b/gcc/testsuite/gcc.dg/debug/ctf/ctf-1.c new file mode 100644 index 0000000..1be0dfb --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-1.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-gt" } */ + +void func(void) +{ +} diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf-preamble-1.c b/gcc/testsuite/gcc.dg/debug/ctf/ctf-preamble-1.c new file mode 100644 index 0000000..476ca80 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf-preamble-1.c @@ -0,0 +1,11 @@ +/* Verify the CTF preamble in the CTF section. */ + +/* { dg-do compile ) */ +/* { dg-options "-O0 -gt -dA" } */ +/* { dg-final { scan-assembler "0xdff2.*CTF preamble magic number" } } */ +/* { dg-final { scan-assembler "0x4.*CTF preamble version" } } */ +/* { dg-final { scan-assembler "0.*CTF preamble flags" } } */ + +void func (void) +{ +} diff --git a/gcc/testsuite/gcc.dg/debug/ctf/ctf.exp b/gcc/testsuite/gcc.dg/debug/ctf/ctf.exp new file mode 100644 index 0000000..46055f8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/ctf/ctf.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2002-2019 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib gcc-dg.exp + +# Disable on ptx (in sync with DWARF testsuite) +if { [istarget nvptx-*-*] } { + return +} + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\] ]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2-ctf-1.c b/gcc/testsuite/gcc.dg/debug/dwarf2-ctf-1.c new file mode 100644 index 0000000..4ffa8ee --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2-ctf-1.c @@ -0,0 +1,7 @@ +/* Verify that CTF debug info can co-exist with other debug formats. */ +/* { dg-do compile } */ +/* { dg-options "-gt -dA" } */ +/* { dg-final { scan-assembler "0xdff2.*CTF preamble magic number" } } */ + +void func (void) +{ } diff --git a/gcc/toplev.c b/gcc/toplev.c index 116be7b..d150dfc 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see #include "pass_manager.h" #include "auto-profile.h" #include "dwarf2out.h" +#include "ctfout.h" #include "ipa-reference.h" #include "symbol-summary.h" #include "tree-vrp.h" @@ -1312,6 +1313,8 @@ 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; @@ -1484,6 +1487,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 () && !lang_GNU_GIMPLE () + && ctf_debug_info_level > CTFINFO_LEVEL_NONE) + { + warning_at (UNKNOWN_LOCATION, 0, + "CTF debug info requested, but not supported for %s 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"); @@ -1556,6 +1570,9 @@ process_options (void) flag_var_tracking_uninit = 0; } + if (ctf_debug_info_level > CTFINFO_LEVEL_NONE) + ctf_debug_init (); + /* The debug hooks are used to implement -fdump-go-spec because it gives a simple and stable API for all the information we need to dump. */ @@ -2391,6 +2408,7 @@ toplev::finalize (void) cgraph_c_finalize (); cgraphunit_c_finalize (); dwarf2out_c_finalize (); + ctfout_c_finalize (); gcse_c_finalize (); ipa_cp_c_finalize (); ira_costs_c_finalize (); diff --git a/include/ctf.h b/include/ctf.h new file mode 100644 index 0000000..3a6f266 --- /dev/null +++ b/include/ctf.h @@ -0,0 +1,483 @@ +/* CTF format description. + Copyright (C) 2019 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 | variable | data | string | + | header | labels | objects | info | info | types | table | + +--------+--------+---------+----------+----------+-------+--------+ + + The file header stores a magic number and version information, encoding + flags, and the byte offset of each of the sections relative to the end of the + header itself. If the CTF data has been uniquified against another set of + CTF data, a reference to that data also appears in the the header. This + reference is the name of the label corresponding to the types uniquified + against. + + Following the header is a list of labels, used to group the types included in + the data types section. Each label is accompanied by a type ID i. A given + label refers to the group of types whose IDs are in the range [0, i]. + + Data object and function records are stored in the same order as they appear + in the corresponding symbol table, except that symbols marked SHN_UNDEF are + not stored and symbols that have no type data are padded out with zeroes. + For each data object, the type ID (a small integer) is recorded. For each + function, the type ID of the return type and argument types is recorded. + + Variable records (as distinct from data objects) provide a modicum of support + for non-ELF systems, mapping a variable name to a CTF type ID. The variable + names are sorted into ASCIIbetical order, permitting binary searching. + + The data types section is a list of variable size records that represent each + type, in order by their ID. The types themselves form a directed graph, + where each node may contain one or more outgoing edges to other type nodes, + denoted by their ID. + + Strings are recorded as a string table ID (0 or 1) and a byte offset into the + string table. String table 0 is the internal CTF string table. String table + 1 is the external string table, which is the string table associated with the + ELF symbol table for this object. CTF does not record any strings that are + already in the symbol table, and the CTF string table does not contain any + duplicated strings. + + 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. There is no + notation anywhere in the child CTF file indicating which parent it is + connected to: it is the debugger's responsibility to track this. */ + +#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_lbloff; /* Offset of label section. */ + uint32_t cth_objtoff; /* Offset of object section. */ + uint32_t cth_funcoff; /* Offset of function 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 v2 is not quite the same as native v2 (the boundary between + parent and child types is different), 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 + +#define CTF_VERSION_3 4 +#define CTF_VERSION CTF_VERSION_3 /* Current version. */ + +#define CTF_F_COMPRESS 0x1 /* Data buffer is compressed by libctf. */ + +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) + +/* 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). */ +#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. */ + +typedef struct ctf_slice +{ + uint32_t cts_type; + unsigned char cts_offset; + unsigned char 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_file_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 files in the archive. */ + uint64_t ctfa_nfiles; + + /* 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_file_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_file_t. */ + +typedef struct ctf_archive_modent +{ + uint64_t name_offset; + uint64_t ctf_offset; +} ctf_archive_modent_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _CTF_H */ -- 1.8.3.1