public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 2/2] gdb: CTF support
  2019-10-04 20:25 [PATCH v4 1/2] Renaming of ctf (the trace format) files Weimin Pan
@ 2019-10-04 20:24 ` Weimin Pan
  2019-10-07 14:40   ` Simon Marchi
  2019-10-09 17:41   ` Tom Tromey
  0 siblings, 2 replies; 9+ messages in thread
From: Weimin Pan @ 2019-10-04 20:24 UTC (permalink / raw)
  To: gdb-patches

This patch adds the CTF (Compact Ansi-C Type Format) support in gdb.
Two submissions on which this gdb work depends were posted earlier
in May:

 * On the binutils mailing list - adding libctf which creates, updates,
   reads, and manipulates the CTF data.
 * On the gcc mailing list - expanding gcc to directly emit the CFT data
   with a new command line option -gt.

CTF is a reduced form of debugging information whose main purpose is to
describe the type of C entities such as structures, unions, typedefs and
function arguments at the global scope only. It does not contain debug
information about source lines, location expressions, or local variables.
For more information on CTF, see the documentation in the libdtrace-ctf
source tree, available here:

<https://raw.githubusercontent.com/oracle/libdtrace-ctf/master/doc/ctf-format>.

This patch expands struct elfinfo by adding the .ctf section, which
contains CTF debugging info, and modifies elf_symfile_read() to read it.
If both DWARF and CTF exist in a program, only DWARF will be read. CTF data
will be read only when there is no DWARF. The two-stage symbolic reading
and setting strategy, partial and full, was used.

File ctfread.c contains functions to transform CTF data into gdb's internal
symbol table structures by iterately reading entries from CTF sections
of "data objects", "function info", "variable info", and "data types"
when setting up either partial or full symbol table. If the ELF symbol table
is available, e.g. not stripped, the CTF reader will associate the found
type information with these symbol entries. Due to the proximity between DWARF
and CTF (CTF being a much simplified subset of DWARF), some DWARF implementation
was reused to support CTF.

Test cases ctf-constvars.exp, ctf-cvexpr.exp, ctf-ptype.exp, and ctf-whatis.exp
have been added to verify the correctness of this support.

This patch has missing features and limitations which we will add and
address in the future patches.

gdb/ChangeLog
+2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb/ctfread.c: New file.
+	* gdb/ctfread.h: New file.
+	* gdb/elfread.c: Include ctfread.h.
+	(struct elfinfo text_p): New member ctfsect.
+	(elf_locate_sections): Mark CTF section.
+	(elf_symfile_read): Call elfctf_build_psymtabs.
+	* gdb/Makefile.in (LIBCTF): Add.
+	(CLIBS): Use it.
+	(CDEPS): Likewise.
+	(DIST): Add ctfread.c.
+	* Makefile.def (dependencies): Add all-libctf to all-gdb
+	* Makefile.in: Add "all-gdb: maybe-all-libctf"
+
gdb/testsuite/ChangeLog
+2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb.base/ctf-whatis.exp: New file.
+	* gdb.base/ctf-whatis.c: New file.
+	* gdb.base/ctf-ptype.exp: New file.
+	* gdb.base/ctf-ptype.c: New file.
+	* gdb.base/ctf-constvars.exp: New file.
+	* gdb.base/ctf-constvars.c: New file.
+	* gdb.base/ctf-cvexpr.exp: New file.
+
---
 Makefile.def                             |    1 +
 Makefile.in                              |    1 +
 gdb/ChangeLog                            |   15 +
 gdb/Makefile.in                          |    1 +
 gdb/ctfread.c                            | 1486 ++++++++++++++++++++++++++++++
 gdb/ctfread.h                            |   25 +
 gdb/elfread.c                            |   18 +-
 gdb/testsuite/ChangeLog                  |   10 +
 gdb/testsuite/gdb.base/ctf-constvars.c   |  116 +++
 gdb/testsuite/gdb.base/ctf-constvars.exp |  114 +++
 gdb/testsuite/gdb.base/ctf-cvexpr.exp    |  495 ++++++++++
 gdb/testsuite/gdb.base/ctf-ptype.c       |  305 ++++++
 gdb/testsuite/gdb.base/ctf-ptype.exp     |  288 ++++++
 gdb/testsuite/gdb.base/ctf-whatis.c      |  282 ++++++
 gdb/testsuite/gdb.base/ctf-whatis.exp    |  413 +++++++++
 15 files changed, 3569 insertions(+), 1 deletion(-)
 create mode 100644 gdb/ctfread.c
 create mode 100644 gdb/ctfread.h
 create mode 100644 gdb/testsuite/gdb.base/ctf-constvars.c
 create mode 100644 gdb/testsuite/gdb.base/ctf-constvars.exp
 create mode 100644 gdb/testsuite/gdb.base/ctf-cvexpr.exp
 create mode 100644 gdb/testsuite/gdb.base/ctf-ptype.c
 create mode 100644 gdb/testsuite/gdb.base/ctf-ptype.exp
 create mode 100644 gdb/testsuite/gdb.base/ctf-whatis.c
 create mode 100644 gdb/testsuite/gdb.base/ctf-whatis.exp

diff --git a/Makefile.def b/Makefile.def
index 6f5e881..311feb9 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -404,6 +404,7 @@ dependencies = { module=all-gdb; on=all-build-bison; };
 dependencies = { module=all-gdb; on=all-sim; };
 dependencies = { module=all-gdb; on=all-libdecnumber; };
 dependencies = { module=all-gdb; on=all-libtermcap; };
+dependencies = { module=all-gdb; on=all-libctf; };
 
 dependencies = { module=configure-libgui; on=configure-tcl; };
 dependencies = { module=configure-libgui; on=configure-tk; };
diff --git a/Makefile.in b/Makefile.in
index 196abf0..1aabf6e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -51524,6 +51524,7 @@ all-gdb: maybe-all-libiberty
 all-gdb: maybe-all-libiconv
 all-gdb: maybe-all-opcodes
 all-gdb: maybe-all-libdecnumber
+all-gdb: maybe-all-libctf
 configure-gprof: maybe-configure-intl
 all-gprof: maybe-all-libiberty
 all-gprof: maybe-all-bfd
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 3974823..03b9474 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,20 @@
 2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
 
+	* ctfread.c: New file.
+	* ctfread.h: New file.
+	* elfread.c: Include ctfread.h.
+	(struct elfinfo text_p): New member ctfsect.
+	(elf_locate_sections): Mark CTF section.
+	(elf_symfile_read): Call elfctf_build_psymtabs.
+	* Makefile.in (LIBCTF): Add.
+	(CLIBS): Use it.
+	(CDEPS): Likewise.
+	(DIST): Add ctfread.c.
+	* ../Makefile.def (dependencies): Add all-libctf to all-gdb
+	* ../Makefile.in: Add "all-gdb: maybe-all-libctf"
+
+2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
+
 	* tracectf.h: Rename, was ctf.h.
 	* tracectf.c: Rename, was ctf.c, replace ctf.h with tracectf.h.
 	* tracefile.c: Likewise.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index cb3a403..51314d5 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -992,6 +992,7 @@ COMMON_SFILES = \
 	cp-namespace.c \
 	cp-support.c \
 	cp-valprint.c \
+	ctfread.c \
 	d-lang.c \
 	d-namespace.c \
 	d-valprint.c \
diff --git a/gdb/ctfread.c b/gdb/ctfread.c
new file mode 100644
index 0000000..3e3bd89
--- /dev/null
+++ b/gdb/ctfread.c
@@ -0,0 +1,1486 @@
+/* Compact ANSI-C Type Format (CTF) support in GDB.
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file format can be used to compactly represent the information needed
+   by a debugger to interpret the ANSI-C types used by a given program.
+   Traditionally, this kind of information is generated by the compiler when
+   invoked with the -g flag and is stored in "stabs" strings or in the more
+   modern DWARF format. A new -gtLEVEL option has been added in gcc to generate
+   such information. CTF provides a representation of only the information
+   that is relevant to debugging a complex, optimized C program such as the
+   operating system kernel in a form that is significantly more compact than
+   the equivalent stabs or DWARF representation.  The format is data-model
+   independent, so consumers do not need different code depending on whether
+   they are 32-bit or 64-bit programs.  CTF assumes that a standard ELF symbol
+   table is available for use in the debugger, and uses the structure and data
+   of the symbol table to avoid storing redundant information.  The CTF data
+   may be compressed on disk or in memory, indicated by a bit in the header.
+   CTF may be interpreted in a raw disk file, or it may be stored in an ELF
+   section, typically named .ctf.  Data structures are aligned so that a raw
+   CTF file or CTF ELF section may be manipulated using mmap(2).
+
+   The CTF file or section itself has the following structure:
+
+   +--------+--------+---------+----------+----------+-------+--------+
+   |  file  |  type  |  data   | function | variable | data  | string |
+   | header | labels | objects |   info   |   info   | types | table  |
+   +--------+--------+---------+----------+----------+-------+--------+
+
+   The file header stores a magic number and version information, encoding
+   flags, and the byte offset of each of the sections relative to the end of the
+   header itself.  If the CTF data has been uniquified against another set of
+   CTF data, a reference to that data also appears in the the header.  This
+   reference is the name of the label corresponding to the types uniquified
+   against.
+
+   Following the header is a list of labels, used to group the types included in
+   the data types section.  Each label is accompanied by a type ID i.  A given
+   label refers to the group of types whose IDs are in the range [0, i].
+
+   Data object and function records are stored in the same order as they appear
+   in the corresponding symbol table, except that symbols marked SHN_UNDEF are
+   not stored and symbols that have no type data are padded out with zeroes.
+   For each data object, the type ID (a small integer) is recorded.  For each
+   function, the type ID of the return type and argument types is recorded.
+
+   Variable records (as distinct from data objects) provide a modicum of support
+   for non-ELF systems, mapping a variable name to a CTF type ID.  The variable
+   names are sorted into ASCIIbetical order, permitting binary searching.
+
+   The data types section is a list of variable size records that represent each
+   type, in order by their ID.  The types themselves form a directed graph,
+   where each node may contain one or more outgoing edges to other type nodes,
+   denoted by their ID.
+
+   Strings are recorded as a string table ID (0 or 1) and a byte offset into the
+   string table.  String table 0 is the internal CTF string table.  String table
+   1 is the external string table, which is the string table associated with the
+   ELF symbol table for this object.  CTF does not record any strings that are
+   already in the symbol table, and the CTF string table does not contain any
+   duplicated strings.  */
+
+#include "defs.h"
+#include "buildsym.h"
+#include "complaints.h"
+#include "block.h"
+#include "ctfread.h"
+#include "psympriv.h"
+#include "ctf.h"
+#include "ctf-api.h"
+
+static const struct objfile_key<htab, htab_deleter> ctf_tid_key;
+static const struct objfile_data *ctf_file_key;
+
+/* A CTF context consists of a file pointer and an objfile pointer.  */
+
+typedef struct ctf_context
+{
+  ctf_file_t *fp;
+  struct objfile *of;
+  struct buildsym_compunit *builder;
+} ctf_context_t;
+
+/* The routines that read and process fields/members of a C struct, union,
+   or enumeration, pass lists of data member fields in an instance of a
+   field_info structure. It is derived from dwarf2read.c.  */
+
+struct nextfield
+{
+  struct field field {};
+};
+
+struct field_info
+{
+  /* List of data member fields.  */
+  std::vector<struct nextfield> fields;
+
+  /* Context.  */
+  ctf_context_t *cur_context;
+
+  /* Parent type.  */
+  struct type *ptype;
+
+  /* typedefs defined inside this class.  TYPEDEF_FIELD_LIST contains head
+     of a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements.  */
+  std::vector<struct decl_field> typedef_field_list;
+
+  /* Nested types defined by this struct and the number of elements in
+     this list.  */
+  std::vector<struct decl_field> nested_types_list;
+};
+
+
+/* Local function prototypes */
+
+static void psymtab_to_symtab (struct partial_symtab *);
+
+static int ctf_add_type_cb (ctf_id_t tid, void *arg);
+
+static struct type *read_array_type (ctf_context_t *ccp, ctf_id_t tid);
+
+static struct type *read_pointer_type (ctf_context_t *ccp, ctf_id_t tid,
+				       ctf_id_t btid);
+
+static struct type *read_structure_type (ctf_context_t *ccp, ctf_id_t tid);
+
+static struct type *read_enum_type (ctf_context_t *ccp, ctf_id_t tid);
+
+static struct type *read_typedef_type (ctf_context_t *ccp, ctf_id_t tid,
+				       ctf_id_t btid, const char *name);
+
+static struct type *read_type_record (ctf_context_t *ccp, ctf_id_t tid);
+
+static void process_structure_type (ctf_context_t *ccp, ctf_id_t tid);
+
+static void process_struct_members (ctf_context_t *ccp, ctf_id_t tid,
+				    struct type *type);
+
+static struct symbol *new_symbol (ctf_context_t *ccp, struct type *type,
+				  ctf_id_t tid);
+
+struct ctf_tid_and_type
+{
+  ctf_id_t tid;
+  struct type *type;
+};
+
+/* Hash function for a ctf_tid_and_type.  */
+
+static hashval_t
+tid_and_type_hash (const void *item)
+{
+  const struct ctf_tid_and_type *ids
+    = (const struct ctf_tid_and_type *) item;
+
+  return ids->tid;
+}
+
+/* Equality function for a ctf_tid_and_type.  */
+
+static int
+tid_and_type_eq (const void *item_lhs, const void *item_rhs)
+{
+  const struct ctf_tid_and_type *ids_lhs
+    = (const struct ctf_tid_and_type *) item_lhs;
+  const struct ctf_tid_and_type *ids_rhs
+    = (const struct ctf_tid_and_type *) item_rhs;
+
+  return ids_lhs->tid == ids_rhs->tid;
+}
+
+/* Set the type associated with TID to TYP.  */
+
+static struct type *
+set_tid_type (struct objfile *of, ctf_id_t tid, struct type *typ)
+{
+  htab_t htab;
+
+  htab = (htab_t) ctf_tid_key.get (of);
+  if (htab == NULL)
+    {
+      htab = htab_create_alloc (1, tid_and_type_hash,
+				tid_and_type_eq,
+				NULL, xcalloc, xfree);
+      ctf_tid_key.set (of, htab);
+    }
+
+  struct ctf_tid_and_type **slot, ids;
+  ids.tid = tid;
+  ids.type = typ;
+  slot = (struct ctf_tid_and_type **) htab_find_slot (htab, &ids, INSERT);
+  if (*slot)
+    complaint (_("An internal GDB problem: ctf_ id_t %ld type already set"),
+	       (tid));
+  *slot = XOBNEW (&of->objfile_obstack, struct ctf_tid_and_type);
+  **slot = ids;
+  return typ;
+}
+
+/* Look up the type for TID in tid_and_type hash, return NULL if hash is
+   empty or TID does not have a saved type.  */
+
+static struct type *
+get_tid_type (struct objfile *of, ctf_id_t tid)
+{
+  struct ctf_tid_and_type *slot, ids;
+  htab_t htab;
+
+  htab = (htab_t) ctf_tid_key.get (of);
+  if (htab == NULL)
+    return NULL;
+
+  ids.tid = tid;
+  ids.type = NULL;
+  slot = (struct ctf_tid_and_type *) htab_find (htab, &ids);
+  if (slot)
+    return slot->type;
+  else
+    return NULL;
+}
+
+/* Return the size of storage in bits for INTEGER, FLOAT, or ENUM.  */
+
+static int
+get_bitsize (ctf_file_t *fp, ctf_id_t tid, uint32_t kind)
+{
+  ctf_encoding_t cet;
+
+  if ((kind == CTF_K_INTEGER || kind == CTF_K_ENUM
+      || kind == CTF_K_FLOAT)
+      && ctf_type_reference (fp, tid) != CTF_ERR
+      && ctf_type_encoding (fp, tid, &cet) != CTF_ERR)
+    return cet.cte_bits;
+
+  return 0;
+}
+
+/* Set SYM's address, with NAME, from its minimal symbol entry.  */
+
+static void
+set_symbol_address (struct objfile *of, struct symbol *sym, const char *name)
+{
+  struct bound_minimal_symbol msym;
+
+  msym = lookup_minimal_symbol (name, NULL, of);
+  if (msym.minsym != NULL)
+    {
+      SET_SYMBOL_VALUE_ADDRESS (sym, BMSYMBOL_VALUE_ADDRESS (msym));
+      SYMBOL_ACLASS_INDEX (sym) = LOC_STATIC;
+      SYMBOL_SECTION (sym) = MSYMBOL_SECTION (msym.minsym);
+    }
+}
+
+/* Create the vector of fields, and attach it to TYPE.  */
+
+static void
+attach_fields_to_type (struct field_info *fip, struct type *type)
+{
+  int nfields = fip->fields.size ();
+
+  if (nfields == 0)
+    return;
+
+  /* Record the field count, allocate space for the array of fields.  */
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type)
+    = (struct field *) TYPE_ZALLOC (type, sizeof (struct field) * nfields);
+
+  /* Copy the saved-up fields into the field vector.  */
+  for (int i = 0; i < nfields; ++i)
+    {
+      struct nextfield &field = fip->fields[i];
+      TYPE_FIELD (type, i) = field.field;
+    }
+}
+
+/* Allocate a floating-point type of size BITS and name NAME.  Pass NAME_HINT
+   (which may be different from NAME) to the architecture back-end to allow
+   it to guess the correct format if necessary.  */
+
+static struct type *
+ctf_init_float_type (struct objfile *objfile,
+		     int bits,
+		     const char *name,
+		     const char *name_hint)
+{
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  const struct floatformat **format;
+  struct type *type;
+
+  format = gdbarch_floatformat_for_type (gdbarch, name_hint, bits);
+  if (format != NULL)
+    type = init_float_type (objfile, bits, name, format);
+  else
+    type = init_type (objfile, TYPE_CODE_ERROR, bits, name);
+
+  return type;
+}
+
+/* Callback to add member NAME to a struct/union type. TID is the type
+   of struct/union member, OFFSET is the offset of member in bits,
+   and ARG contains the field_info.  */
+
+static int
+ctf_add_member_cb (const char *name,
+		   ctf_id_t tid,
+		   unsigned long offset,
+		   void *arg)
+{
+  struct field_info *fip = (struct field_info *) arg;
+  ctf_context_t *ccp = fip->cur_context;
+  struct nextfield new_field;
+  struct field *fp;
+  struct type *t;
+  uint32_t kind;
+
+  fp = &new_field.field;
+  FIELD_NAME (*fp) = name;
+
+  kind = ctf_type_kind (ccp->fp, tid);
+  t = get_tid_type (ccp->of, tid);
+  if (t == NULL)
+    {
+      t = read_type_record (ccp, tid);
+      if (t == NULL)
+	{
+	  complaint (_("ctf_add_member_cb: %s has NO type (%ld)"), name, tid);
+	  t = objfile_type (ccp->of)->builtin_error;
+	  set_tid_type (ccp->of, tid, t);
+	}
+    }
+
+  if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
+    process_struct_members (ccp, tid, t);
+
+  FIELD_TYPE (*fp) = t;
+  SET_FIELD_BITPOS (*fp, offset / TARGET_CHAR_BIT);
+  FIELD_BITSIZE (*fp) = get_bitsize (ccp->fp, tid, kind);
+
+  fip->fields.emplace_back (new_field);
+
+  return 0;
+}
+
+/* Callback to add member NAME of EVAL to an enumeration type.
+   ARG contains the field_info.  */
+
+static int
+ctf_add_enum_member_cb (const char *name, int enum_value, void *arg)
+{
+  struct field_info *fip = (struct field_info *) arg;
+  struct nextfield new_field;
+  struct field *fp;
+  ctf_context_t *ccp = fip->cur_context;
+
+  fp = &new_field.field;
+  FIELD_NAME (*fp) = name;
+  FIELD_TYPE (*fp) = NULL;
+  SET_FIELD_ENUMVAL (*fp, enum_value);
+  FIELD_BITSIZE (*fp) = 0;
+
+  if (name != NULL)
+    {
+      struct symbol *sym = allocate_symbol (ccp->of);
+      OBJSTAT (ccp->of, n_syms++);
+
+      SYMBOL_SET_LANGUAGE (sym, language_c, &ccp->of->objfile_obstack);
+      SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of);
+      SYMBOL_ACLASS_INDEX (sym) = LOC_CONST;
+      SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+      SYMBOL_TYPE (sym) = fip->ptype;
+      add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
+    }
+
+  fip->fields.emplace_back (new_field);
+
+  return 0;
+}
+
+/* Add a new symbol entry, with its name from TID, its access index and
+   domain from TID's kind, and its type from TYPE.  */
+
+static struct symbol *
+new_symbol (ctf_context_t *ccp, struct type *type, ctf_id_t tid)
+{
+  struct objfile *objfile = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct symbol *sym = NULL;
+
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (fp, tid));
+  if (name != NULL)
+    {
+      sym = allocate_symbol (objfile);
+      OBJSTAT (objfile, n_syms++);
+
+      SYMBOL_SET_LANGUAGE (sym, language_c, &objfile->objfile_obstack);
+      SYMBOL_SET_NAMES (sym, name.get (), strlen (name.get ()), 1, objfile);
+      SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+      SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT;
+
+      if (type != NULL)
+	SYMBOL_TYPE (sym) = type;
+
+      uint32_t kind = ctf_type_kind (fp, tid);
+      switch (kind)
+	{
+	  case CTF_K_STRUCT:
+	  case CTF_K_UNION:
+	  case CTF_K_ENUM:
+	    SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF;
+	    SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN;
+	    break;
+	  case CTF_K_FUNCTION:
+	    SYMBOL_ACLASS_INDEX (sym) = LOC_STATIC;
+	    break;
+	  case CTF_K_CONST:
+	    if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_VOID)
+	      SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_int;
+	    break;
+	  case CTF_K_TYPEDEF:
+	  case CTF_K_INTEGER:
+	  case CTF_K_FLOAT:
+	    SYMBOL_ACLASS_INDEX (sym) = LOC_TYPEDEF;
+	    SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+	    break;
+	  case CTF_K_POINTER:
+	    break;
+	  case CTF_K_VOLATILE:
+	  case CTF_K_RESTRICT:
+	    break;
+	  case CTF_K_SLICE:
+	  case CTF_K_ARRAY:
+	  case CTF_K_UNKNOWN:
+	    break;
+	}
+
+      add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
+    }
+
+  return sym;
+}
+
+/* Given a TID of kind CTF_K_INTEGER or CTF_K_FLOAT, find a representation
+   and create the symbol for it.  */
+
+static struct type *
+read_base_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct objfile *of = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  ctf_encoding_t cet;
+  struct type *type = NULL;
+  char *name;
+  uint32_t kind;
+
+  if (ctf_type_encoding (fp, tid, &cet))
+    {
+      complaint (_("ctf_type_encoding read_base_type failed - %s"),
+		 ctf_errmsg (ctf_errno (fp)));
+      return NULL;
+    }
+
+  gdb::unique_xmalloc_ptr<char> copied_name (ctf_type_aname_raw (fp, tid));
+  if (copied_name == NULL || strlen (copied_name.get ()) == 0)
+    {
+      name = ctf_type_aname (fp, tid);
+      if (name == NULL)
+	complaint (_("ctf_type_aname read_base_type failed - %s"),
+		   ctf_errmsg (ctf_errno (fp)));
+    }
+  else
+    name = obstack_strdup (&of->objfile_obstack, copied_name.get ());
+
+  kind = ctf_type_kind (fp, tid);
+  if (kind == CTF_K_INTEGER)
+    {
+      uint32_t issigned, ischar, isbool;
+      struct gdbarch *gdbarch = get_objfile_arch (of);
+
+      issigned = cet.cte_format & CTF_INT_SIGNED;
+      ischar = cet.cte_format & CTF_INT_CHAR;
+      isbool = cet.cte_format & CTF_INT_BOOL;
+      if (ischar)
+	type = init_character_type (of, TARGET_CHAR_BIT, !issigned, name);
+      else if (isbool)
+	type = init_boolean_type (of, gdbarch_int_bit (gdbarch),
+				  !issigned, name);
+      else
+	{
+	  int bits;
+	  if (cet.cte_bits && ((cet.cte_bits % TARGET_CHAR_BIT) == 0))
+	    bits = cet.cte_bits;
+	  else
+	    bits = gdbarch_int_bit (gdbarch);
+	  type = init_integer_type (of, bits, !issigned, name);
+	}
+    }
+  else if (kind == CTF_K_FLOAT)
+    {
+      uint32_t isflt;
+      isflt = !((cet.cte_format & CTF_FP_IMAGRY) == CTF_FP_IMAGRY
+		 || (cet.cte_format & CTF_FP_DIMAGRY) == CTF_FP_DIMAGRY
+		 || (cet.cte_format & CTF_FP_LDIMAGRY) == CTF_FP_LDIMAGRY);
+      if (isflt)
+	type = ctf_init_float_type (of, cet.cte_bits, name, name);
+      else
+	{
+	  struct type *t
+	    = ctf_init_float_type (of, cet.cte_bits / 2, NULL, name);
+	  type = init_complex_type (of, name, t);
+	}
+    }
+  else
+    {
+      complaint (_("read_base_type: unsupported base kind (%d)"), kind);
+      type = init_type (of, TYPE_CODE_ERROR, cet.cte_bits, name);
+    }
+
+  if (name != NULL && strcmp (name, "char") == 0)
+    TYPE_NOSIGN (type) = 1;
+
+  return set_tid_type (of, tid, type);
+}
+
+static void
+process_base_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct type *type;
+
+  type = read_base_type (ccp, tid);
+  new_symbol (ccp, type, tid);
+}
+
+/* Start a structure or union scope (definition) with TID to create a type
+   for the structure or union.
+
+   Fill in the type's name and general properties. The members will not be
+   processed, nor a symbol table entry be done until process_structure_type
+   (assuming the type has a name).  */
+
+static struct type *
+read_structure_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct objfile *of = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct type *type;
+  uint32_t kind;
+
+  type = alloc_type (of);
+
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (fp, tid));
+  if (name != NULL && strlen (name.get() ) != 0)
+    TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ());
+
+  kind = ctf_type_kind (fp, tid);
+  if (kind == CTF_K_UNION)
+    TYPE_CODE (type) = TYPE_CODE_UNION;
+  else
+    TYPE_CODE (type) = TYPE_CODE_STRUCT;
+
+  TYPE_LENGTH (type) = ctf_type_size (fp, tid);
+  set_type_align (type, ctf_type_align (fp, tid));
+
+  return set_tid_type (ccp->of, tid, type);
+}
+
+/* Given a tid of CTF_K_STRUCT or CTF_K_UNION, process all its members
+   and create the symbol for it.  */
+
+static void
+process_struct_members (ctf_context_t *ccp,
+			ctf_id_t tid,
+			struct type *type)
+{
+  struct field_info fi;
+
+  fi.cur_context = ccp;
+  if (ctf_member_iter (ccp->fp, tid, ctf_add_member_cb, &fi) == CTF_ERR)
+    complaint (_("ctf_member_iter process_struct_members failed - %s"),
+	       ctf_errmsg (ctf_errno (ccp->fp)));
+
+  /* Attach fields to the type.  */
+  attach_fields_to_type (&fi, type);
+
+  new_symbol (ccp, type, tid);
+}
+
+static void
+process_structure_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct type *type;
+
+  type = read_structure_type (ccp, tid);
+  process_struct_members (ccp, tid, type);
+}
+
+/* Create a function type for TID and set its return type.  */
+
+static struct type *
+read_func_kind_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct objfile *of = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct type *type, *rettype;
+  ctf_funcinfo_t cfi;
+
+  type = alloc_type (of);
+
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (fp, tid));
+  if (name != NULL && strlen (name.get ()) != 0)
+    TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ());
+
+  TYPE_CODE (type) = TYPE_CODE_FUNC;
+  ctf_func_type_info (fp, tid, &cfi);
+  rettype = get_tid_type (of, cfi.ctc_return);
+  TYPE_TARGET_TYPE (type) = rettype;
+  set_type_align (type, ctf_type_align (fp, tid));
+
+  return set_tid_type (of, tid, type);
+}
+
+/* Given a TID of CTF_K_ENUM, process all the members of the
+   enumeration, and create the symbol for the enumeration type.  */
+
+static struct type *
+read_enum_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct objfile *of = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct type *type, *target_type;
+  ctf_funcinfo_t fi;
+
+  type = alloc_type (of);
+
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (fp, tid));
+  if (name != NULL && strlen (name.get ()) != 0)
+    TYPE_NAME (type) = obstack_strdup (&of->objfile_obstack, name.get ());
+
+  TYPE_CODE (type) = TYPE_CODE_ENUM;
+  TYPE_LENGTH (type) = ctf_type_size (fp, tid);
+  ctf_func_type_info (fp, tid, &fi);
+  target_type = get_tid_type (of, fi.ctc_return);
+  TYPE_TARGET_TYPE (type) = target_type;
+  set_type_align (type, ctf_type_align (fp, tid));
+
+  return set_tid_type (of, tid, type);
+}
+
+static void
+process_enum_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct type *type;
+  struct field_info fi;
+
+  type = read_enum_type (ccp, tid);
+
+  fi.cur_context = ccp;
+  fi.ptype = type;
+  if (ctf_enum_iter (ccp->fp, tid, ctf_add_enum_member_cb, &fi) == CTF_ERR)
+    complaint (_("ctf_enum_iter process_enum_type failed - %s"),
+	       ctf_errmsg (ctf_errno (ccp->fp)));
+
+  /* Attach fields to the type.  */
+  attach_fields_to_type (&fi, type);
+
+  new_symbol (ccp, type, tid);
+}
+
+/* Add given cv-qualifiers CNST+VOLTL to the BASE_TYPE of array TID.  */
+
+static struct type *
+add_array_cv_type (ctf_context_t *ccp,
+		   ctf_id_t tid,
+		   struct type *base_type,
+		   int cnst,
+		   int voltl)
+{
+  struct type *el_type, *inner_array;
+
+  base_type = copy_type (base_type);
+  inner_array = base_type;
+
+  while (TYPE_CODE (TYPE_TARGET_TYPE (inner_array)) == TYPE_CODE_ARRAY)
+    {
+      TYPE_TARGET_TYPE (inner_array)
+	= copy_type (TYPE_TARGET_TYPE (inner_array));
+      inner_array = TYPE_TARGET_TYPE (inner_array);
+    }
+
+  el_type = TYPE_TARGET_TYPE (inner_array);
+  cnst |= TYPE_CONST (el_type);
+  voltl |= TYPE_VOLATILE (el_type);
+  TYPE_TARGET_TYPE (inner_array) = make_cv_type (cnst, voltl, el_type, NULL);
+
+  return set_tid_type (ccp->of, tid, base_type);
+}
+
+/* Read all information from a TID of CTF_K_ARRAY.  */
+
+static struct type *
+read_array_type (ctf_context_t *ccp, ctf_id_t tid)
+{
+  struct objfile *objfile = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct type *element_type, *range_type, *idx_type;
+  struct type *type;
+  ctf_arinfo_t ar;
+
+  if (ctf_array_info (fp, tid, &ar) == CTF_ERR)
+    {
+      complaint (_("ctf_array_info read_array_type failed - %s"),
+		 ctf_errmsg (ctf_errno (fp)));
+      return NULL;
+    }
+
+  element_type = get_tid_type (objfile, ar.ctr_contents);
+  if (element_type == NULL)
+    return NULL;
+
+  idx_type = get_tid_type (objfile, ar.ctr_index);
+  if (idx_type == NULL)
+    idx_type = objfile_type (objfile)->builtin_int;
+
+  range_type = create_static_range_type (NULL, idx_type, 0, ar.ctr_nelems - 1);
+  type = create_array_type (NULL, element_type, range_type);
+  if (ar.ctr_nelems <= 1)	/* Check if undefined upper bound.  */
+    {
+      TYPE_HIGH_BOUND_KIND (range_type) = PROP_UNDEFINED;
+      TYPE_LENGTH (type) = 0;
+      TYPE_TARGET_STUB (type) = 1;
+    }
+  else
+    TYPE_LENGTH (type) = ctf_type_size (fp, tid);
+
+  set_type_align (type, ctf_type_align (fp, tid));
+
+  return set_tid_type (objfile, tid, type);
+}
+
+/* Read TID of kind CTF_K_CONST with base type BTID.  */
+
+static struct type *
+read_const_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid)
+{
+  struct objfile *objfile = ccp->of;
+  struct type *base_type, *cv_type;
+
+  base_type = get_tid_type (objfile, btid);
+  if (base_type == NULL)
+    {
+      base_type = read_type_record (ccp, btid);
+      if (base_type == NULL)
+	{
+	  complaint (_("read_const_type: NULL base type (%ld)"), btid);
+	  base_type = objfile_type (objfile)->builtin_error;
+	}
+    }
+  cv_type = make_cv_type (1, TYPE_VOLATILE (base_type), base_type, 0);
+
+  return set_tid_type (objfile, tid, cv_type);
+}
+
+/* Read TID of kind CTF_K_VOLATILE with base type BTID.  */
+
+static struct type *
+read_volatile_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid)
+{
+  struct objfile *objfile = ccp->of;
+  ctf_file_t *fp = ccp->fp;
+  struct type *base_type, *cv_type;
+
+  base_type = get_tid_type (objfile, btid);
+  if (base_type == NULL)
+    {
+      base_type = read_type_record (ccp, btid);
+      if (base_type == NULL)
+	{
+	  complaint (_("read_volatile_type: NULL base type (%ld)"), btid);
+	  base_type = objfile_type (objfile)->builtin_error;
+	}
+    }
+
+  if (ctf_type_kind (fp, btid) == CTF_K_ARRAY)
+    return add_array_cv_type (ccp, tid, base_type, 0, 1);
+  cv_type = make_cv_type (TYPE_CONST (base_type), 1, base_type, 0);
+
+  return set_tid_type (objfile, tid, cv_type);
+}
+
+/* Read TID of kind CTF_K_RESTRICT with base type BTID.  */
+
+static struct type *
+read_restrict_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid)
+{
+  struct objfile *objfile = ccp->of;
+  struct type *base_type, *cv_type;
+
+  base_type = get_tid_type (objfile, btid);
+  if (base_type == NULL)
+    {
+      base_type = read_type_record (ccp, btid);
+      if (base_type == NULL)
+	{
+	  complaint (_("read_restrict_type: NULL base type (%ld)"), btid);
+	  base_type = objfile_type (objfile)->builtin_error;
+	}
+    }
+  cv_type = make_restrict_type (base_type);
+
+  return set_tid_type (objfile, tid, cv_type);
+}
+
+/* Read TID of kind CTF_K_TYPEDEF with its NAME and base type BTID.  */
+
+static struct type *
+read_typedef_type (ctf_context_t *ccp, ctf_id_t tid,
+		   ctf_id_t btid, const char *name)
+{
+  struct objfile *objfile = ccp->of;
+  struct type *this_type, *target_type;
+
+  char *aname = obstack_strdup (&objfile->objfile_obstack, name);
+  this_type = init_type (objfile, TYPE_CODE_TYPEDEF, 0, aname);
+  set_tid_type (objfile, tid, this_type);
+  target_type = get_tid_type (objfile, btid);
+  if (target_type != this_type)
+    TYPE_TARGET_TYPE (this_type) = target_type;
+  else
+    TYPE_TARGET_TYPE (this_type) = NULL;
+  TYPE_TARGET_STUB (this_type) = TYPE_TARGET_TYPE (this_type) ? 1 : 0;
+
+  return set_tid_type (objfile, tid, this_type);
+}
+
+/* Read TID of kind CTF_K_POINTER with base type BTID.  */
+
+static struct type *
+read_pointer_type (ctf_context_t *ccp, ctf_id_t tid, ctf_id_t btid)
+{
+  struct objfile *of = ccp->of;
+  struct type *target_type, *type;
+
+  target_type = get_tid_type (of, btid);
+  if (target_type == NULL)
+    {
+      target_type = read_type_record (ccp, btid);
+      if (target_type == NULL)
+	{
+	  complaint (_("read_pointer_type: NULL target type (%ld)"), btid);
+	  target_type = objfile_type (ccp->of)->builtin_error;
+	}
+    }
+
+  type = lookup_pointer_type (target_type);
+  set_type_align (type, ctf_type_align (ccp->fp, tid));
+
+  return set_tid_type (of, tid, type);
+}
+
+/* Read information associated with type TID.  */
+
+static struct type *
+read_type_record (ctf_context_t *ccp, ctf_id_t tid)
+{
+  ctf_file_t *fp = ccp->fp;
+  uint32_t kind;
+  struct type *type = NULL;
+  ctf_id_t btid;
+
+  kind = ctf_type_kind (fp, tid);
+  switch (kind)
+    {
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+	type = read_structure_type (ccp, tid);
+	break;
+      case CTF_K_ENUM:
+	type = read_enum_type (ccp, tid);
+	break;
+      case CTF_K_FUNCTION:
+	type = read_func_kind_type (ccp, tid);
+	break;
+      case CTF_K_CONST:
+	btid = ctf_type_reference (fp, tid);
+	type = read_const_type (ccp, tid, btid);
+	break;
+      case CTF_K_TYPEDEF:
+	{
+	  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (fp, tid));
+	  btid = ctf_type_reference (fp, tid);
+	  type = read_typedef_type (ccp, tid, btid, name.get ());
+	}
+	break;
+      case CTF_K_VOLATILE:
+	btid = ctf_type_reference (fp, tid);
+	type = read_volatile_type (ccp, tid, btid);
+	break;
+      case CTF_K_RESTRICT:
+	btid = ctf_type_reference (fp, tid);
+	type = read_restrict_type (ccp, tid, btid);
+	break;
+      case CTF_K_POINTER:
+	btid = ctf_type_reference (fp, tid);
+	type = read_pointer_type (ccp, tid, btid);
+	break;
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+	type = read_base_type (ccp, tid);
+	break;
+      case CTF_K_ARRAY:
+	type = read_array_type (ccp, tid);
+	break;
+      case CTF_K_UNKNOWN:
+	break;
+      default:
+	break;
+    }
+
+  return type;
+}
+
+/* Callback to add type TID to the symbol table.  */
+
+static int
+ctf_add_type_cb (ctf_id_t tid, void *arg)
+{
+  ctf_context_t *ccp = (ctf_context_t *) arg;
+  struct type *type;
+  uint32_t kind;
+
+  /* Check if tid's type has already been defined.  */
+  type = get_tid_type (ccp->of, tid);
+  if (type != NULL)
+    return 0;
+
+  ctf_id_t btid = ctf_type_reference (ccp->fp, tid);
+  kind = ctf_type_kind (ccp->fp, tid);
+  switch (kind)
+    {
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+	process_structure_type (ccp, tid);
+	break;
+      case CTF_K_ENUM:
+	process_enum_type (ccp, tid);
+	break;
+      case CTF_K_FUNCTION:
+	type = read_func_kind_type (ccp, tid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+	process_base_type (ccp, tid);
+	break;
+      case CTF_K_TYPEDEF:
+	new_symbol (ccp, read_type_record (ccp, tid), tid);
+	break;
+      case CTF_K_CONST:
+	type = read_const_type (ccp, tid, btid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_VOLATILE:
+	type = read_volatile_type (ccp, tid, btid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_RESTRICT:
+	type = read_restrict_type (ccp, tid, btid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_POINTER:
+	type = read_pointer_type (ccp, tid, btid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_ARRAY:
+	type = read_array_type (ccp, tid);
+	new_symbol (ccp, type, tid);
+	break;
+      case CTF_K_UNKNOWN:
+	break;
+      default:
+	break;
+    }
+
+  return 0;
+}
+
+/* Callback to add variable NAME with TID to the symbol table.  */
+
+static int
+ctf_add_var_cb (const char *name, ctf_id_t id, void *arg)
+{
+  ctf_context_t *ccp = (ctf_context_t *) arg;
+  struct symbol *sym = NULL;
+  struct type *type;
+  uint32_t kind;
+
+  type = get_tid_type (ccp->of, id);
+
+  kind = ctf_type_kind (ccp->fp, id);
+  switch (kind)
+    {
+      case CTF_K_FUNCTION:
+	if (name && !strcmp(name, "main"))
+	  set_objfile_main_name (ccp->of, name, language_c);
+	break;
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+      case CTF_K_VOLATILE:
+      case CTF_K_RESTRICT:
+      case CTF_K_TYPEDEF:
+      case CTF_K_CONST:
+      case CTF_K_POINTER:
+      case CTF_K_ARRAY:
+	if (type)
+	  {
+	    sym = new_symbol (ccp, type, id);
+	    SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of);
+	  }
+	break;
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+      case CTF_K_ENUM:
+	if (type == NULL)
+	{
+	  complaint (_("ctf_add_var_cb: %s has NO type (%ld)"), name, id);
+	  type = objfile_type (ccp->of)->builtin_error;
+	}
+	sym = allocate_symbol (ccp->of);
+	OBJSTAT (ccp->of, n_syms++);
+	SYMBOL_TYPE (sym) = type;
+	SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
+	SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT;
+	SYMBOL_SET_NAMES (sym, name, strlen (name), 0, ccp->of);
+	add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
+	break;
+      default:
+	complaint (_("ctf_add_var_cb: kind unsupported (%d)"), kind);
+	break;
+    }
+
+  if (sym)
+    set_symbol_address (ccp->of, sym, name);
+
+  return 0;
+}
+
+/* Add an ELF STT_OBJ symbol with index IDX to the symbol table.  */
+
+static struct symbol *
+add_stt_obj (ctf_context_t *ccp, unsigned long idx)
+{
+  struct symbol *sym;
+  struct type *type;
+  ctf_id_t tid;
+
+  if ((tid = ctf_lookup_by_symbol (ccp->fp, idx)) == CTF_ERR)
+    return NULL;
+
+  type = get_tid_type (ccp->of, tid);
+  if (type == NULL)
+    return NULL;
+
+  sym = new_symbol (ccp, type, tid);
+
+  return sym;
+}
+
+/* Add an ELF STT_FUNC symbol with index IDX to the symbol table.  */
+
+static struct symbol *
+add_stt_func (ctf_context_t *ccp, unsigned long idx)
+{
+  struct type *ftype, *atyp, *rettyp;
+  struct symbol *sym;
+  ctf_funcinfo_t finfo;
+  ctf_id_t argv[32];
+  uint32_t argc;
+  ctf_id_t tid;
+  struct type *void_type = objfile_type (ccp->of)->builtin_void;
+
+  if (ctf_func_info (ccp->fp, idx, &finfo) == CTF_ERR)
+    return NULL;
+
+  argc = finfo.ctc_argc;
+  if (ctf_func_args (ccp->fp, idx, argc, argv) == CTF_ERR)
+    return NULL;
+
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (ccp->fp, idx));
+  if (name == NULL)
+    return NULL;
+
+  tid = ctf_lookup_by_symbol (ccp->fp, idx);
+  ftype = get_tid_type (ccp->of, tid);
+  if (finfo.ctc_flags & CTF_FUNC_VARARG)
+    TYPE_VARARGS (ftype) = 1;
+  TYPE_NFIELDS (ftype) = argc;
+
+  /* If argc is 0, it has a "void" type.  */
+  if (argc != 0)
+    TYPE_FIELDS (ftype)
+      = (struct field *) TYPE_ZALLOC (ftype, argc * sizeof (struct field));
+
+  /* TYPE_FIELD_TYPE must never be NULL.  Fill it with void_type, if failed
+     to find the argument type.  */
+  for (int iparam = 0; iparam < argc; iparam++)
+    {
+      atyp = get_tid_type (ccp->of, argv[iparam]);
+      if (atyp)
+	TYPE_FIELD_TYPE (ftype, iparam) = atyp;
+      else
+	TYPE_FIELD_TYPE (ftype, iparam) = void_type;
+    }
+
+  sym = new_symbol (ccp, ftype, tid);
+  rettyp = get_tid_type (ccp->of, finfo.ctc_return);
+  if (rettyp != NULL)
+    SYMBOL_TYPE (sym) = rettyp;
+  else
+    SYMBOL_TYPE (sym) = void_type;
+
+  return sym;
+}
+
+/* Get text segment base for OBJFILE, TSIZE contains the segment size.  */
+
+static CORE_ADDR
+get_objfile_text_range (struct objfile *of, int *tsize)
+{
+  CORE_ADDR text_base;
+  bfd *abfd = of->obfd;
+  const asection *codes;
+
+  codes = bfd_get_section_by_name (abfd, ".text");
+  if (codes == NULL)
+    {
+      text_base = 0;
+      *tsize = 0;
+    }
+  else
+    {
+      text_base = bfd_section_vma (codes);
+      *tsize = codes->size;
+    }
+
+  return text_base;
+}
+
+/* Start a symtab for OBJFILE in CTF format.  */
+
+static void
+ctf_start_symtab (struct partial_symtab *pst,
+		  struct objfile *of, CORE_ADDR text_offset)
+{
+  ctf_context_t *ccp;
+
+  ccp = (ctf_context_t *) pst->read_symtab_private;
+  ccp->builder = new buildsym_compunit
+		       (of, of->original_name, NULL,
+		       language_c, text_offset);
+  ccp->builder->record_debugformat ("ctf");
+}
+
+/* Finish reading symbol/type definitions in CTF format.
+   END_ADDR is the end address of the file's text.  SECTION is
+   the .text section number.  */
+
+static struct compunit_symtab *
+ctf_end_symtab (struct partial_symtab *pst,
+		CORE_ADDR end_addr, int section)
+{
+  ctf_context_t *ccp;
+
+  ccp = (ctf_context_t *) pst->read_symtab_private;
+  struct compunit_symtab *result
+    = ccp->builder->end_symtab (end_addr, section);
+  delete ccp->builder;
+  ccp->builder = NULL;
+  return result;
+}
+
+/* Read in full symbols for PST, and anything it depends on.  */
+
+static void
+psymtab_to_symtab (struct partial_symtab *pst)
+{
+  struct symbol *sym;
+  ctf_context_t *ccp;
+
+  gdb_assert (!pst->readin);
+
+  ccp = (ctf_context_t *) pst->read_symtab_private;
+
+  /* Iterate over entries in data types section.  */
+  if (ctf_type_iter (ccp->fp, ctf_add_type_cb, ccp) == CTF_ERR)
+    complaint (_("ctf_type_iter psymtab_to_symtab failed - %s"),
+	       ctf_errmsg (ctf_errno (ccp->fp)));
+
+
+  /* Iterate over entries in variable info section.  */
+  if (ctf_variable_iter (ccp->fp, ctf_add_var_cb, ccp) == CTF_ERR)
+    complaint (_("ctf_variable_iter psymtab_to_symtab failed - %s"),
+	       ctf_errmsg (ctf_errno (ccp->fp)));
+
+  /* Add entries in data objects and function info sections.  */
+  for (unsigned long i = 0; ; i++)
+    {
+      sym = add_stt_obj (ccp, i);
+      if (sym == NULL)
+	{
+	  if (ctf_errno (ccp->fp) == EINVAL
+	      || ctf_errno (ccp->fp) == ECTF_NOSYMTAB)
+	    break;
+	  sym = add_stt_func (ccp, i);
+	}
+      if (sym == NULL)
+	continue;
+
+      set_symbol_address (ccp->of, sym, SYMBOL_LINKAGE_NAME (sym));
+    }
+
+  pst->readin = 1;
+}
+
+/* Expand partial symbol table PST into a full symbol table.
+   PST is not NULL.  */
+
+static void
+ctf_read_symtab (struct partial_symtab *pst, struct objfile *objfile)
+{
+  if (pst->readin)
+    warning (_("bug: psymtab for %s is already read in."), pst->filename);
+  else
+    {
+      if (info_verbose)
+	{
+	  printf_filtered (_("Reading in CTF data for %s..."), pst->filename);
+	  gdb_flush (gdb_stdout);
+	}
+
+      /* Start a symtab.  */
+      CORE_ADDR text_offset;        /* Start of text segment.  */
+      int tsize;
+
+      text_offset = get_objfile_text_range (objfile, &tsize);
+      ctf_start_symtab (pst, objfile, text_offset);
+      psymtab_to_symtab (pst);
+
+      pst->set_text_low (text_offset);
+      pst->set_text_high (text_offset + tsize);
+      pst->compunit_symtab = ctf_end_symtab (pst, text_offset + tsize,
+					     SECT_OFF_TEXT (objfile));
+
+      /* Finish up the debug error message.  */
+      if (info_verbose)
+	printf_filtered (_("done.\n"));
+    }
+}
+
+/* Cleanup function for the ctf_file_key data.  */
+
+static void
+ctf_close_objfile (struct objfile *of, void *datum)
+{
+  ctf_file_t *fp = static_cast<ctf_file_t *> (datum);
+  ctf_archive_t *arc = ctf_get_arc (fp);
+  ctf_file_close (fp);
+  ctf_close (arc);
+}
+
+/* Allocate a new partial_symtab NAME.
+
+   Each source file that has not been fully read in is represented by
+   a partial_symtab.  This contains the information on where in the
+   executable the debugging symbols for a specific file are, and a
+   list of names of global symbols which are located in this file.
+   They are all chained on partial symtab lists.
+
+   Even after the source file has been read into a symtab, the
+   partial_symtab remains around.  They are allocated on an obstack,
+   objfile_obstack.  */
+
+static struct partial_symtab *
+create_partial_symtab (const char *name,
+		       ctf_file_t *cfp,
+		       struct objfile *objfile)
+{
+  struct partial_symtab *pst;
+  ctf_context_t *ccx;
+
+  pst = start_psymtab_common (objfile, name, 0);
+
+  ccx = XOBNEW (&objfile->objfile_obstack, ctf_context_t);
+  ccx->fp = cfp;
+  ccx->of = objfile;
+  pst->read_symtab_private = (void *) ccx;
+  pst->read_symtab = ctf_read_symtab;
+
+  return pst;
+}
+
+/* Callback to add type TID to partial symbol table.  */
+
+static int
+ctf_psymtab_type_cb (ctf_id_t tid, void *arg)
+{
+  ctf_context_t *ccp;
+  uint32_t kind;
+  short section = -1;
+
+  ccp = (ctf_context_t *) arg;
+  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (ccp->fp, tid));
+  if (name == NULL || strlen (name.get ()) == 0)
+    return 0;
+
+  domain_enum domain = UNDEF_DOMAIN;
+  enum address_class aclass = LOC_UNDEF;
+  kind = ctf_type_kind (ccp->fp, tid);
+  switch (kind)
+    {
+      case CTF_K_STRUCT:
+      case CTF_K_UNION:
+      case CTF_K_ENUM:
+	domain = STRUCT_DOMAIN;
+	aclass = LOC_TYPEDEF;
+	break;
+      case CTF_K_FUNCTION:
+      case CTF_K_FORWARD:
+	domain = VAR_DOMAIN;
+	aclass = LOC_STATIC;
+	section = SECT_OFF_TEXT (ccp->of);
+	break;
+      case CTF_K_CONST:
+	domain = VAR_DOMAIN;
+	aclass = LOC_STATIC;
+	break;
+      case CTF_K_TYPEDEF:
+      case CTF_K_POINTER:
+      case CTF_K_VOLATILE:
+      case CTF_K_RESTRICT:
+	domain = VAR_DOMAIN;
+	aclass = LOC_TYPEDEF;
+	break;
+      case CTF_K_INTEGER:
+      case CTF_K_FLOAT:
+	domain = VAR_DOMAIN;
+	aclass = LOC_TYPEDEF;
+	break;
+      case CTF_K_ARRAY:
+      case CTF_K_UNKNOWN:
+	return 0;
+    }
+
+    add_psymbol_to_list (name.get (), strlen (name.get ()), true,
+			 domain, aclass, section,
+			 psymbol_placement::GLOBAL,
+			 0, language_c, ccp->of);
+
+  return 0;
+}
+
+/* Callback to add variable NAME with ID to partial symbol table.  */
+
+static int
+ctf_psymtab_var_cb (const char *name, ctf_id_t id, void *arg)
+{
+  ctf_context_t *ccp = (ctf_context_t *) arg;
+
+  add_psymbol_to_list (name, strlen (name), true,
+		       VAR_DOMAIN, LOC_STATIC, -1,
+		       psymbol_placement::GLOBAL,
+		       0, language_c, ccp->of);
+  return 0;
+}
+
+/* Setup partial_symtab's describing each source file for which
+   debugging information is available.  */
+
+static void
+scan_partial_symbols (ctf_file_t *cfp, struct objfile *of)
+{
+  ctf_context_t ccx;
+  bfd *abfd = of->obfd;
+  const char *name = bfd_get_filename (abfd);
+  struct partial_symtab *pst = create_partial_symtab (name, cfp, of);
+
+  ccx.fp = cfp;
+  ccx.of = of;
+
+  if (ctf_type_iter (cfp, ctf_psymtab_type_cb, &ccx) == CTF_ERR)
+    complaint (_("ctf_type_iter scan_partial_symbols failed - %s"),
+	       ctf_errmsg (ctf_errno (cfp)));
+
+  if (ctf_variable_iter (cfp, ctf_psymtab_var_cb, &ccx) == CTF_ERR)
+    complaint (_("ctf_variable_iter scan_partial_symbols failed - %s"),
+	       ctf_errmsg (ctf_errno (cfp)));
+
+  /* Scan CTF object and function sections which correspond to each
+     STT_FUNC or STT_OBJECT entry in the symbol table,
+     pick up what init_symtab has done.  */
+  for (unsigned long idx = 0; ; idx++)
+    {
+      ctf_id_t tid;
+      if ((tid = ctf_lookup_by_symbol (cfp, idx)) == CTF_ERR)
+	{
+	if (ctf_errno (cfp) == EINVAL || ctf_errno (cfp) == ECTF_NOSYMTAB)
+	  break;	// Done, reach end of the section.
+	else
+	  continue;
+	}
+      gdb::unique_xmalloc_ptr<char> tname (ctf_type_aname_raw (cfp, tid));
+      uint32_t kind = ctf_type_kind (cfp, tid);
+      address_class aclass;
+      domain_enum tdomain;
+      switch (kind)
+	{
+	  case CTF_K_STRUCT:
+	  case CTF_K_UNION:
+	  case CTF_K_ENUM:
+	    tdomain = STRUCT_DOMAIN;
+	    break;
+	  default:
+	    tdomain = VAR_DOMAIN;
+	    break;
+	}
+
+      if (kind == CTF_K_FUNCTION)
+	aclass = LOC_STATIC;
+      else if (kind == CTF_K_CONST)
+	aclass = LOC_CONST;
+      else
+	aclass = LOC_TYPEDEF;
+
+      add_psymbol_to_list (tname.get (), strlen (tname.get ()), true,
+			   tdomain, aclass, -1,
+			   psymbol_placement::STATIC,
+			   0, language_c, of);
+    }
+
+  end_psymtab_common (of, pst);
+}
+
+/* Read CTF debugging information from a BFD section.  This is
+   called from elfread.c.  It does a quick pass through the
+   .ctf section to set up the partial symbol table.  */
+
+void
+elfctf_build_psymtabs (struct objfile *of)
+{
+  bfd *abfd = of->obfd;
+  int err;
+
+  ctf_archive_t *arc = ctf_bfdopen (abfd, &err);
+  if (arc == NULL)
+    error (_("ctf_bfdopen failed on %s - %s"),
+	   bfd_get_filename (abfd), ctf_errmsg (err));
+
+  ctf_file_t *fp = ctf_arc_open_by_name (arc, NULL, &err);
+  if (fp == NULL)
+    error (_("ctf_arc_open_by_name failed on %s - %s"),
+	   bfd_get_filename (abfd), ctf_errmsg (err));
+  set_objfile_data (of, ctf_file_key, fp);
+
+  scan_partial_symbols (fp, of);
+}
+
+void
+_initialize_ctfread (void)
+{
+  ctf_file_key
+    = register_objfile_data_with_cleanup (NULL, ctf_close_objfile);
+}
diff --git a/gdb/ctfread.h b/gdb/ctfread.h
new file mode 100644
index 0000000..632ee12
--- /dev/null
+++ b/gdb/ctfread.h
@@ -0,0 +1,25 @@
+/* CTF debugging format support for GDB.
+
+   Copyright (C) 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef CTFREAD_H
+#define CTFREAD_H
+
+extern void elfctf_build_psymtabs (struct objfile *objfile);
+
+#endif /* CTFREAD_H */
diff --git a/gdb/elfread.c b/gdb/elfread.c
index d2a7bcf..53bdd35 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -47,6 +47,7 @@
 #include "location.h"
 #include "auxv.h"
 #include "mdebugread.h"
+#include "ctfread.h"
 
 /* Forward declarations.  */
 extern const struct sym_fns elf_sym_fns_gdb_index;
@@ -61,6 +62,7 @@ struct elfinfo
   {
     asection *stabsect;		/* Section pointer for .stab section */
     asection *mdebugsect;	/* Section pointer for .mdebug section */
+    asection *ctfsect;		/* Section pointer for .ctf section */
   };
 
 /* Type for per-BFD data.  */
@@ -188,6 +190,10 @@ elf_locate_sections (bfd *ignore_abfd, asection *sectp, void *eip)
     {
       ei->mdebugsect = sectp;
     }
+  else if (strcmp (sectp->name, ".ctf") == 0)
+    {
+      ei->ctfsect = sectp;
+    }
 }
 
 static struct minimal_symbol *
@@ -1059,7 +1065,8 @@ elf_read_minimal_symbols (struct objfile *objfile, int symfile_flags,
      go away once all types of symbols are in the per-BFD object.  */
   if (objfile->per_bfd->minsyms_read
       && ei->stabsect == NULL
-      && ei->mdebugsect == NULL)
+      && ei->mdebugsect == NULL
+      && ei->ctfsect == NULL)
     {
       if (symtab_create_debug)
 	fprintf_unfiltered (gdb_stdlog,
@@ -1200,6 +1207,7 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 {
   bfd *abfd = objfile->obfd;
   struct elfinfo ei;
+  bool has_dwarf2 = true;
 
   memset ((char *) &ei, 0, sizeof (ei));
   if (!(objfile->flags & OBJF_READNEVER))
@@ -1302,6 +1310,14 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 	  symbol_file_add_separate (debug_bfd.get (), debugfile.c_str (),
 				    symfile_flags, objfile);
 	}
+	else
+	  has_dwarf2 = false;
+    }
+
+  /* Read the CTF section only if there is no DWARF info.  */
+  if (!has_dwarf2 && ei.ctfsect)
+    {
+      elfctf_build_psymtabs (objfile);
     }
 }
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index fd76144..527d857 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,13 @@
+2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb.base/ctf-whatis.exp: New file.
+	* gdb.base/ctf-whatis.c: New file.
+	* gdb.base/ctf-ptype.exp: New file.
+	* gdb.base/ctf-ptype.c: New file.
+	* gdb.base/ctf-constvars.exp: New file.
+	* gdb.base/ctf-constvars.c: New file.
+	* gdb.base/ctf-cvexpr.exp: New file.
+
 2019-10-03  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* gdb.fortran/nested-funcs-2.exp: Run tests with and without the
diff --git a/gdb/testsuite/gdb.base/ctf-constvars.c b/gdb/testsuite/gdb.base/ctf-constvars.c
new file mode 100644
index 0000000..75f4250
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-constvars.c
@@ -0,0 +1,116 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+const char            laconic = 'A';
+const char           *const lewd=&laconic;
+
+/* volatile variables */
+
+volatile char vox = 'B';
+volatile unsigned char victuals = 'C';
+volatile short vixen = 200;
+volatile unsigned short vitriol = 300;
+volatile long vellum = 1000;
+volatile unsigned long valve = 2000;
+volatile float vacuity = 3.0;
+volatile double vertigo = 10;
+
+/* pointers to volatile variables */
+
+volatile char           * vampire = &vox;
+volatile unsigned char  * viper  = &victuals;
+volatile short          * vigour = &vixen;
+volatile unsigned short * vapour = &vitriol;
+volatile long           * ventricle = &vellum;
+volatile unsigned long  * vigintillion = &valve;
+volatile float          * vocation = &vacuity;
+volatile double         * veracity = &vertigo;
+
+/* volatile pointers to volatile variables */
+
+volatile char           * volatile vapidity = &vox;
+volatile unsigned char  * volatile velocity = &victuals;
+volatile short          * volatile veneer = &vixen;
+volatile unsigned short * volatile video = &vitriol;
+volatile long           * volatile vacuum = &vellum;
+volatile unsigned long  * volatile veniality = &valve;
+volatile float          * volatile vitality = &vacuity;
+volatile double         * volatile voracity = &vertigo;
+
+/* volatile arrays */
+
+volatile char violent[2];
+volatile unsigned char violet[2];
+volatile short vips[2];
+volatile unsigned short virgen[2];
+volatile long vulgar[2];
+volatile unsigned long vulture[2];
+volatile float vilify[2];
+volatile double villar[2];
+
+/* const volatile vars */
+
+const volatile char           victor = 'Y';
+
+/* pointers to const volatiles */
+
+const volatile char              * victory = &victor;
+
+/* const pointers to const volatile vars */
+
+const volatile char              * const cavern = &victor;
+
+/* volatile pointers to const vars */
+
+const char                       * volatile caveat = &laconic;
+const unsigned char              * volatile covenant;
+
+/* volatile pointers to const volatile vars */
+
+const volatile char              * volatile vizier = &victor;
+const volatile unsigned char     * volatile vanadium;
+
+/* const volatile pointers */
+
+char                             * const volatile vane;
+unsigned char                    * const volatile veldt;
+
+/* const volatile pointers to const vars */
+
+const char                       * const volatile cove;
+const unsigned char              * const volatile cavity;
+ 
+/* const volatile pointers to volatile vars */
+
+volatile char                    * const volatile vagus;
+volatile unsigned char           * const volatile vagrancy;
+ 
+/* const volatile pointers to const volatile */
+
+const volatile char              * const volatile vagary;
+const volatile unsigned char     * const volatile vendor;
+
+/* const volatile arrays */
+
+const volatile char vindictive[2];
+const volatile unsigned char vegetation[2];
+
+int
+main (void)
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/ctf-constvars.exp b/gdb/testsuite/gdb.base/ctf-constvars.exp
new file mode 100644
index 0000000..4a81a94
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-constvars.exp
@@ -0,0 +1,114 @@
+# Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+# This file is a subset of constvars.exp, written by
+# Elena Zannoni (elz@apollo.hp.com)
+#
+# This file is part of the gdb testsuite
+#
+# tests for const variables
+#           const pointers to vars
+#           pointers to const variables
+#           const pointers to const vars
+# with mixed types
+
+#
+# test running programs
+#
+# -gt generates full-fledged CTF.
+
+standard_testfile .c
+set opts "additional_flags=-gt"
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile] [list $opts nowarnings]] } {
+    return 0
+}
+
+#
+# set it up at a breakpoint so we can play with the variable values
+#
+if ![runto_main] then {
+    perror "couldn't run to breakpoint"
+    continue
+}
+
+# test vars and pointers
+
+proc do_constvar_tests {} {
+    gdb_test "print vox" " = 66 'B'"
+    gdb_test "ptype vox" "type = volatile char"
+    gdb_test "print victuals" " = 67 'C'"
+    gdb_test "ptype victuals" "type = volatile unsigned char"
+    gdb_test "print vixen" " = 200"
+    gdb_test "ptype vixen" "type = volatile short.*"
+    gdb_test "print vitriol" " = 300"
+    gdb_test "ptype vitriol" "type = volatile (unsigned short|short unsigned)( int)?"
+    gdb_test "print vellum" " = 1000"
+    gdb_test "ptype vellum" "type = volatile long.*"
+    gdb_test "print valve" " = 2000"
+    gdb_test "ptype valve" "type = volatile (unsigned long|long unsigned)( int)?"
+    gdb_test "print vacuity" " = 3"
+    gdb_test "ptype vacuity" "type = volatile float"
+    gdb_test "print vertigo" " = 10"
+    gdb_test "ptype vertigo" "type = volatile double"
+    gdb_test "print laconic" " = 65 'A'"
+
+    gdb_test "ptype vampire" "type = volatile char.*"
+    gdb_test "ptype viper" "type = volatile unsigned char.*"
+    gdb_test "ptype vigour" "type = volatile short.*"
+    gdb_test "ptype vapour" "type = volatile (unsigned short|short unsigned)( int)?.*"
+    gdb_test "ptype ventricle" "type = volatile long.*"
+    gdb_test "ptype vigintillion" "type = volatile (unsigned long|long unsigned)( int)?.*"
+    gdb_test "ptype vocation" "type = volatile float.*"
+    gdb_test "ptype veracity" "type = volatile double.*"
+
+    gdb_test "ptype vapidity" "type = volatile char.* volatile"
+    gdb_test "ptype velocity" "type = volatile unsigned char.* volatile"
+    gdb_test "ptype veneer" "type = volatile short.* volatile"
+    gdb_test "ptype video" "type = volatile (unsigned short|short unsigned)( int)?.* volatile"
+    gdb_test "ptype vacuum" "type = volatile long.* volatile"
+    gdb_test "ptype veniality" "type = volatile (unsigned long|long unsigned)( int)?.* volatile"
+    gdb_test "ptype vitality" "type = volatile float.* volatile"
+    gdb_test "ptype voracity" "type = volatile double.* volatile"
+
+    gdb_test "ptype violent" "type = volatile char \\\[2\\\]"
+    gdb_test "ptype violet" "type = volatile unsigned char \\\[2\\\]"
+    gdb_test "ptype vips" "type = volatile short.* \\\[2\\\]"
+    gdb_test "ptype virgen" "type = volatile unsigned short.* \\\[2\\\]"
+    gdb_test "ptype vulgar" "type = volatile long.* \\\[2\\\]"
+    gdb_test "ptype vulture" "type = volatile (unsigned long|long unsigned)( int)? \\\[2\\\]"
+    gdb_test "ptype vilify" "type = volatile float \\\[2\\\]"
+    gdb_test "ptype villar" "type = volatile double \\\[2\\\]"
+
+    gdb_test "print victor" " = 89 'Y'"
+    gdb_test "ptype victor" "type = const volatile char"
+    gdb_test "ptype victory" "type = const volatile char.*"
+    gdb_test "ptype cavern" "type = const volatile char.* const"
+    gdb_test "ptype caveat" "type = const char.* volatile"
+    gdb_test "ptype covenant" "type = const unsigned char.* volatile"
+    gdb_test "ptype vanadium" "type = const volatile unsigned char.* volatile"
+
+    gdb_test "ptype cove" "type = const char.* const volatile"
+    gdb_test "ptype cavity" "type = const unsigned char.* const volatile"
+    gdb_test "ptype vagus" "type = volatile char.* const volatile"
+    gdb_test "ptype vagrancy" "type = volatile unsigned char.* const volatile"
+    gdb_test "ptype vagary" "type = const volatile char.* const volatile"
+    gdb_test "ptype vendor" "type = const volatile unsigned char.* const volatile"
+    gdb_test "ptype vindictive" "type = const volatile char \\\[2\\\]"
+    gdb_test "ptype vegetation" "type = const volatile unsigned char \\\[2\\\]"
+}
+
+do_constvar_tests
diff --git a/gdb/testsuite/gdb.base/ctf-cvexpr.exp b/gdb/testsuite/gdb.base/ctf-cvexpr.exp
new file mode 100644
index 0000000..67ceb21
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-cvexpr.exp
@@ -0,0 +1,495 @@
+#   Copyright (C) 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is a subset of cvexpr.exp written by
+# Michael Snyder, Red Hat, Inc., 9/20/2001
+
+# This file is part of the gdb testsuite
+# Tests for type expressions using const and volatile keywords.
+
+#
+# test running programs
+#
+# -gt generates full-fledged CTF.
+
+standard_testfile cvexpr.c
+set opts "additional_flags=-gt"
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     untested "failed to compile"
+     return -1
+}
+
+clean_restart ${binfile}
+
+gdb_test_no_output "set print sevenbit-strings"
+gdb_test_no_output "set print address off"
+gdb_test_no_output "set width 0"
+
+set ws  "\[ \t\]*"
+
+#
+# Test casting a scalar to const
+#
+
+gdb_test "whatis (const char) v_char" \
+	"type = const char" \
+	"(const char)"
+gdb_test "whatis (const signed char) v_signed_char" \
+	"type = const signed char" \
+	"(const signed char)"
+gdb_test "whatis (const unsigned char) v_unsigned_char" \
+	"type = const (unsigned char|char)" \
+	"(const unsigned char)"
+gdb_test "whatis (const short) v_short" \
+	"type = const (short|short int)" \
+	"(const short)"
+gdb_test "whatis (const signed short) v_signed_short" \
+	"type = const (short|short int|signed short|signed short int)" \
+	"(const signed short)"
+gdb_test "whatis (const unsigned short) v_unsigned_short" \
+	"type = const (unsigned short|short unsigned int)" \
+	"(const unsigned short)"
+gdb_test "whatis (const int) v_int" \
+	"type = const int" \
+	"(const int)"
+gdb_test "whatis (const signed int) v_signed_int" \
+	"type = const (signed int|int)" \
+	"(const signed int)"
+gdb_test "whatis (const unsigned int) v_unsigned_int" \
+	"type = const unsigned int" \
+	"(const unsigned int)"
+gdb_test "whatis (const long) v_long" \
+	"type = const (long|long int)" \
+	"(const long)"
+gdb_test "whatis (const signed long) v_signed_long" \
+	"type = const (signed |)long( int|)" \
+	"(const signed long)"
+gdb_test "whatis (const unsigned long) v_unsigned_long" \
+	"type = const (unsigned long|long unsigned int)" \
+	"(const unsigned long)"
+gdb_test "whatis (const long long) v_long_long" \
+	"type = const long long( int|)" \
+	"(const long long)"
+gdb_test "whatis (const signed long long) v_signed_long_long" \
+	"type = const (signed |)long long( int|)" \
+	"(const signed long long)"
+gdb_test "whatis (const unsigned long long) v_unsigned_long_long" \
+	"type = const (unsigned long long|long long unsigned int)" \
+	"(const unsigned long long)"
+gdb_test "whatis (const float) v_float" \
+	"type = const float" \
+	"(const float)"
+gdb_test "whatis (const double) v_double" \
+	"type = const double" \
+	"(const double)"
+
+#
+# Test casting a scalar to volatile
+#
+
+gdb_test "whatis (volatile char) v_char" \
+	"type = volatile char" \
+	"(volatile char)"
+gdb_test "whatis (volatile signed char) v_signed_char" \
+	"type = volatile signed char" \
+	"(volatile signed char)"
+gdb_test "whatis (volatile unsigned char) v_unsigned_char" \
+	"type = volatile (unsigned char|char)" \
+	"(volatile unsigned char)"
+gdb_test "whatis (volatile short) v_short" \
+	"type = volatile (short|short int)" \
+	"(volatile short)"
+gdb_test "whatis (volatile signed short) v_signed_short" \
+	"type = volatile (short|short int|signed short|signed short int)" \
+	"(volatile signed short)"
+gdb_test "whatis (volatile unsigned short) v_unsigned_short" \
+	"type = volatile (unsigned short|short unsigned int)" \
+	"(volatile unsigned short)"
+gdb_test "whatis (volatile int) v_int" \
+	"type = volatile int" \
+	"(volatile int)"
+gdb_test "whatis (volatile signed int) v_signed_int" \
+	"type = volatile (signed int|int)" \
+	"(volatile signed int)"
+gdb_test "whatis (volatile unsigned int) v_unsigned_int" \
+	"type = volatile unsigned int" \
+	"(volatile unsigned int)"
+gdb_test "whatis (volatile long) v_long" \
+	"type = volatile (long|long int)" \
+	"(volatile long)"
+gdb_test "whatis (volatile signed long) v_signed_long" \
+	"type = volatile (signed |)long( int|)" \
+	"(volatile signed long)"
+gdb_test "whatis (volatile unsigned long) v_unsigned_long" \
+	"type = volatile (unsigned long|long unsigned int)" \
+	"(volatile unsigned long)"
+gdb_test "whatis (volatile long long) v_long_long" \
+	"type = volatile long long( int|)" \
+	"(volatile long long)"
+gdb_test "whatis (volatile signed long long) v_signed_long_long" \
+	"type = volatile (signed |)long long( int|)" \
+	"(volatile signed long long)"
+gdb_test "whatis (volatile unsigned long long) v_unsigned_long_long" \
+	"type = volatile (unsigned long long|long long unsigned int)" \
+	"(volatile unsigned long long)"
+gdb_test "whatis (volatile float) v_float" \
+	"type = volatile float" \
+	"(volatile float)"
+gdb_test "whatis (volatile double) v_double" \
+	"type = volatile double" \
+	"(volatile double)"
+
+#
+# Combine const and volatile
+#
+
+gdb_test "whatis (const volatile int) v_int" \
+	"type = const volatile int" \
+	"(const volatile int)"
+gdb_test "whatis (volatile const int) v_int" \
+	"type = const volatile int" \
+	"(volatile const int)"
+gdb_test "whatis (const int volatile) v_int" \
+	"type = const volatile int" \
+	"(const int volatile)"
+gdb_test "whatis (volatile int const) v_int" \
+	"type = const volatile int" \
+	"(volatile int const)"
+gdb_test "whatis (int const volatile) v_int" \
+	"type = const volatile int" \
+	"(int const volatile)"
+gdb_test "whatis (int volatile const) v_int" \
+	"type = const volatile int" \
+	"(int volatile const)"
+
+gdb_test "whatis (const volatile int *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(const volatile int *)"
+gdb_test "whatis (volatile const int *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(volatile const int *)"
+gdb_test "whatis (const int volatile *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(const int volatile)"
+gdb_test "whatis (volatile int const *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(volatile int const *)"
+gdb_test "whatis (int const volatile *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(int const volatile *)"
+gdb_test "whatis (int volatile const *) v_int_pointer" \
+	"type = const volatile int${ws}\\*" \
+	"(int volatile const *)"
+gdb_test "whatis (int * const volatile) v_int_pointer" \
+	"type = int${ws}\\*${ws}const volatile" \
+	"(int * const volatile)"
+gdb_test "whatis (int * volatile const) v_int_pointer" \
+	"type = int${ws}\\*${ws}const volatile" \
+	"(int * volatile const)"
+
+
+#
+# Put 'signed' and 'unsigned' before const/volatile (FIXME)
+#
+
+#gdb_test "whatis (signed const char) v_signed_char" \
+#	"type = const char" \
+#	"(signed const char)"
+#gdb_test "whatis (unsigned const char) v_unsigned_char" \
+#	"type = const (unsigned char|char)" \
+#	"(unsigned const char)"
+#gdb_test "whatis (signed const short) v_signed_short" \
+#	"type = const (short|short int|signed short|signed short int)" \
+#	"(signed const short)"
+#gdb_test "whatis (unsigned const short) v_unsigned_short" \
+#	"type = const (unsigned short|short unsigned int)" \
+#	"(unsigned const short)"
+#gdb_test "whatis (signed const int) v_signed_int" \
+#	"type = const (signed int|int)" \
+#	"(signed const int)"
+#gdb_test "whatis (unsigned const int) v_unsigned_int" \
+#	"type = const unsigned int" \
+#	"(unsigned const int)"
+#gdb_test "whatis (signed const long) v_signed_long" \
+#	"type = const (signed |)long( int|)" \
+#	"(signed const long)"
+#gdb_test "whatis (unsigned const long) v_unsigned_long" \
+#	"type = const (unsigned long|long unsigned int)" \
+#	"(unsigned const long)"
+#gdb_test "whatis (signed const long long) v_signed_long_long" \
+#	"type = const (signed |)long long( int|)" \
+#	"(signed const long long)"
+#gdb_test "whatis (unsigned const long long) v_unsigned_long_long" \
+#	"type = const (unsigned long long|long long unsigned int)" \
+#	"(const unsigned long long)"
+
+#gdb_test "whatis (signed volatile char) v_signed_char" \
+#	"type = volatile char" \
+#	"(signed volatile char)"
+#gdb_test "whatis (unsigned volatile char) v_unsigned_char" \
+#	"type = volatile (unsigned char|char)" \
+#	"(unsigned volatile char)"
+#gdb_test "whatis (signed volatile short) v_signed_short" \
+#	"type = volatile (short|short int|signed short|signed short int)" \
+#	"(signed volatile short)"
+#gdb_test "whatis (unsigned volatile short) v_unsigned_short" \
+#	"type = volatile (unsigned short|short unsigned int)" \
+#	"(unsigned volatile short)"
+#gdb_test "whatis (signed volatile int) v_signed_int" \
+#	"type = volatile (signed int|int)" \
+#	"(signed volatile int)"
+#gdb_test "whatis (unsigned volatile int) v_unsigned_int" \
+#	"type = volatile unsigned int" \
+#	"(unsigned volatile int)"
+#gdb_test "whatis (signed volatile long) v_signed_long" \
+#	"type = volatile (signed |)long( int|)" \
+#	"(signed volatile long)"
+#gdb_test "whatis (unsigned volatile long) v_unsigned_long" \
+#	"type = volatile (unsigned long|long unsigned int)" \
+#	"(unsigned volatile long)"
+#gdb_test "whatis (signed volatile long long) v_signed_long_long" \
+#	"type = volatile (signed |)long long( int|)" \
+#	"(signed volatile long long)"
+#gdb_test "whatis (unsigned volatile long long) v_unsigned_long_long" \
+#	"type = volatile (unsigned long long|long long unsigned int)" \
+#	"(unsigned volatile long long)"
+
+#
+# Now put the 'const' and 'volatile' keywords after the base type.
+#
+
+gdb_test "whatis (char const) v_char" \
+	"type = const char" \
+	"(char const)"
+gdb_test "whatis (signed char const) v_signed_char" \
+	"type = const signed char" \
+	"(signed char const)"
+gdb_test "whatis (unsigned char const) v_unsigned_char" \
+	"type = const (unsigned char|char)" \
+	"(unsigned char const)"
+gdb_test "whatis (short const) v_short" \
+	"type = const (short|short int)" \
+	"(short const)"
+gdb_test "whatis (signed short const) v_signed_short" \
+	"type = const (short|short int|signed short|signed short int)" \
+	"(signed short const)"
+gdb_test "whatis (unsigned short const) v_unsigned_short" \
+	"type = const (unsigned short|short unsigned int)" \
+	"(unsigned short const)"
+gdb_test "whatis (int const) v_int" \
+	"type = const int" \
+	"(int const)"
+gdb_test "whatis (signed int const) v_signed_int" \
+	"type = const (signed int|int)" \
+	"(signed int const)"
+gdb_test "whatis (unsigned int const) v_unsigned_int" \
+	"type = const unsigned int" \
+	"(unsigned int const)"
+gdb_test "whatis (long const) v_long" \
+	"type = const (long|long int)" \
+	"(long const)"
+gdb_test "whatis (signed long const) v_signed_long" \
+	"type = const (signed |)long( int|)" \
+	"(signed long const)"
+gdb_test "whatis (unsigned long const) v_unsigned_long" \
+	"type = const (unsigned long|long unsigned int)" \
+	"(unsigned long const)"
+gdb_test "whatis (long long const) v_long_long" \
+	"type = const long long( int|)" \
+	"(long long const)"
+gdb_test "whatis (signed long long const) v_signed_long_long" \
+	"type = const (signed |)long long( int|)" \
+	"(signed long long const)"
+gdb_test "whatis (unsigned long long const) v_unsigned_long_long" \
+	"type = const (unsigned long long|long long unsigned int)" \
+	"(unsigned long long const)"
+gdb_test "whatis (float const) v_float" \
+	"type = const float" \
+	"(float const)"
+gdb_test "whatis (double const) v_double" \
+	"type = const double" \
+	"(double const)"
+
+gdb_test "whatis (char volatile) v_char" \
+	"type = volatile char" \
+	"(char volatile)"
+gdb_test "whatis (signed char volatile) v_signed_char" \
+	"type = volatile signed char" \
+	"(signed char volatile)"
+gdb_test "whatis (unsigned char volatile) v_unsigned_char" \
+	"type = volatile (unsigned char|char)" \
+	"(unsigned char volatile)"
+gdb_test "whatis (short volatile) v_short" \
+	"type = volatile (short|short int)" \
+	"(short volatile)"
+gdb_test "whatis (signed short volatile) v_signed_short" \
+	"type = volatile (short|short int|signed short|signed short int)" \
+	"(signed short volatile)"
+gdb_test "whatis (unsigned short volatile) v_unsigned_short" \
+	"type = volatile (unsigned short|short unsigned int)" \
+	"(unsigned short volatile)"
+gdb_test "whatis (int volatile) v_int" \
+	"type = volatile int" \
+	"(int volatile)"
+gdb_test "whatis (signed int volatile) v_signed_int" \
+	"type = volatile (signed int|int)" \
+	"(signed int volatile)"
+gdb_test "whatis (unsigned int volatile) v_unsigned_int" \
+	"type = volatile unsigned int" \
+	"(unsigned int volatile)"
+gdb_test "whatis (long volatile) v_long" \
+	"type = volatile (long|long int)" \
+	"(long volatile)"
+gdb_test "whatis (signed long volatile) v_signed_long" \
+	"type = volatile (signed |)long( int|)" \
+	"(signed long volatile)"
+gdb_test "whatis (unsigned long volatile) v_unsigned_long" \
+	"type = volatile (unsigned long|long unsigned int)" \
+	"(unsigned long volatile)"
+gdb_test "whatis (long long volatile) v_long_long" \
+	"type = volatile long long( int|)" \
+	"(long long volatile)"
+gdb_test "whatis (signed long long volatile) v_signed_long_long" \
+	"type = volatile (signed |)long long( int|)" \
+	"(signed long long volatile)"
+gdb_test "whatis (unsigned long long volatile) v_unsigned_long_long" \
+	"type = volatile (unsigned long long|long long unsigned int)" \
+	"(unsigned long long volatile)"
+gdb_test "whatis (float volatile) v_float" \
+	"type = volatile float" \
+	"(float volatile)"
+gdb_test "whatis (double volatile) v_double" \
+	"type = volatile double" \
+	"(double volatile)"
+
+#
+# enums
+#
+
+gdb_test "whatis (const enum misordered) v_misordered" \
+	"type = const enum misordered" \
+	"(const enum misordered)"
+gdb_test "whatis (enum misordered const) v_misordered" \
+	"type = const enum misordered" \
+	"(enum misordered const)"
+gdb_test "whatis (volatile enum misordered) v_misordered" \
+	"type = volatile enum misordered" \
+	"(volatile enum misordered)"
+gdb_test "whatis (enum misordered volatile) v_misordered" \
+	"type = volatile enum misordered" \
+	"(enum misordered volatile)"
+
+#
+# Pointers
+#
+
+gdb_test "whatis (const int *) v_int_pointer" \
+	"type = const int${ws}\\*" \
+	"(const int *)"
+gdb_test "whatis (int const *) v_int_pointer" \
+	"type = const int${ws}\\*" \
+	"(int const *)"
+gdb_test "whatis (int * const) v_int_pointer" \
+	"type = int \\*${ws}const" \
+	"(int * const)"
+gdb_test "whatis (const int * const) v_int_pointer" \
+	"type = const int${ws}\\*${ws}const" \
+	"(const int * const)"
+gdb_test "whatis (int const * const) v_int_pointer" \
+	"type = const int${ws}\\*${ws}const" \
+	"(int const * const)"
+
+gdb_test "whatis (const int **) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}\\*" \
+	"(const int **)"
+gdb_test "whatis (int const **) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}\\*" \
+	"(int const **)"
+gdb_test "whatis (int ** const) v_int_pointer_pointer" \
+	"type = int \\*${ws}\\*${ws}const" \
+	"(int ** const)"
+gdb_test "whatis (const int * const *) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}const${ws}\\*" \
+	"(const int * const *)"
+gdb_test "whatis (int const * const *) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}const${ws}\\*" \
+	"(int const * const *)"
+gdb_test "whatis (const int * const * const) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}const${ws}\\*${ws}const" \
+	"(const int * const * const)"
+gdb_test "whatis (int const * const * const) v_int_pointer_pointer" \
+	"type = const int${ws}\\*${ws}const${ws}\\*${ws}const" \
+	"(int const * const * const)"
+
+#
+# Arrays TODO
+#
+
+#
+# Pointers to arrays, arrays of pointers TODO
+#
+
+#
+# Structs and Unions
+#
+
+gdb_test "whatis (const struct t_struct) v_struct1" \
+	"type = const struct t_struct" \
+	"(const struct t_struct)"
+gdb_test "whatis (const union t_union) v_union" \
+	"type = const union t_union" \
+	"(const union t_union)"
+gdb_test "whatis (struct t_struct const) v_struct1" \
+	"type = const struct t_struct" \
+	"(struct t_struct const)"
+gdb_test "whatis (union t_union const) v_union" \
+	"type = const union t_union" \
+	"(union t_union const)"
+gdb_test "whatis (const struct t_struct *) &v_struct1" \
+	"type = const struct t_struct${ws}\\*" \
+	"(const struct t_struct *)"
+gdb_test "whatis (const union t_union *) &v_union" \
+	"type = const union t_union${ws}\\*" \
+	"(const union t_union *)"
+gdb_test "whatis (struct t_struct const *) &v_struct1" \
+	"type = const struct t_struct${ws}\\*" \
+	"(struct t_struct const *)"
+gdb_test "whatis (union t_union const *) &v_union" \
+	"type = const union t_union${ws}\\*" \
+	"(union t_union const *)"
+gdb_test "whatis (struct t_struct * const) &v_struct1" \
+	"type = struct t_struct${ws}\\*${ws}const" \
+	"(struct t_struct * const)"
+gdb_test "whatis (union t_union * const) &v_union" \
+	"type = union t_union${ws}\\*${ws}const" \
+	"(union t_union * const)"
+gdb_test "whatis (const struct t_struct * const) &v_struct1" \
+	"type = const struct t_struct${ws}\\*${ws}const" \
+	"(const struct t_struct * const)"
+gdb_test "whatis (const union t_union * const) &v_union" \
+	"type = const union t_union${ws}\\*${ws}const" \
+	"(const union t_union * const)"
+gdb_test "whatis (struct t_struct const * const) &v_struct1" \
+	"type = const struct t_struct${ws}\\*${ws}const" \
+	"(struct t_struct const * const)"
+gdb_test "whatis (union t_union const * const) &v_union" \
+	"type = const union t_union${ws}\\*${ws}const" \
+	"(union t_union const * const)"
+
+#
+# Function pointers TODO
+#
+
diff --git a/gdb/testsuite/gdb.base/ctf-ptype.c b/gdb/testsuite/gdb.base/ctf-ptype.c
new file mode 100644
index 0000000..2d2e881
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-ptype.c
@@ -0,0 +1,305 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+ *	Test file with lots of different types, for testing the
+ *	"ptype" command on CTF data. It's devired from ptype.c.
+ */
+
+/*
+ *	First the basic C types.
+ */
+
+#if !defined (__STDC__) && !defined (_AIX)
+#define signed  /**/
+#endif
+
+char		v_char;
+signed char	v_signed_char;
+unsigned char	v_unsigned_char;
+
+short		v_short;
+signed short	v_signed_short;
+unsigned short	v_unsigned_short;
+
+int		v_int;
+signed int	v_signed_int;
+unsigned int	v_unsigned_int;
+
+long		v_long;
+signed long	v_signed_long;
+unsigned long	v_unsigned_long;
+
+float		v_float;
+double		v_double;
+
+/**** arrays *******/
+
+char		v_char_array[2];
+signed char	v_signed_char_array[2];
+unsigned char	v_unsigned_char_array[2];
+
+short		v_short_array[2];
+signed short	v_signed_short_array[2];
+unsigned short	v_unsigned_short_array[2];
+
+int		v_int_array[2];
+signed int	v_signed_int_array[2];
+unsigned int	v_unsigned_int_array[2];
+
+long		v_long_array[2];
+signed long	v_signed_long_array[2];
+unsigned long	v_unsigned_long_array[2];
+
+float		v_float_array[2];
+double		v_double_array[2];
+
+/* PR 3742 */
+typedef char t_char_array[];
+t_char_array *pv_char_array;
+
+/**** pointers *******/
+
+char		*v_char_pointer;
+signed char	*v_signed_char_pointer;
+unsigned char	*v_unsigned_char_pointer;
+
+short		*v_short_pointer;
+signed short	*v_signed_short_pointer;
+unsigned short	*v_unsigned_short_pointer;
+
+int		*v_int_pointer;
+signed int	*v_signed_int_pointer;
+unsigned int	*v_unsigned_int_pointer;
+
+long		*v_long_pointer;
+signed long	*v_signed_long_pointer;
+unsigned long	*v_unsigned_long_pointer;
+
+float		*v_float_pointer;
+double		*v_double_pointer;
+
+/**** structs *******/
+
+struct t_struct {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+    float	v_float_member;
+    double	v_double_member;
+} v_struct1;
+
+struct t_struct *v_t_struct_p;
+
+struct {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+    float	v_float_member;
+    double	v_double_member;
+} v_struct2;
+
+/* typedef'd struct without a tag.  */
+typedef struct {
+  double v_double_member;
+  int v_int_member;
+} t_struct3;
+/* GCC seems to want a variable of this type, or else it won't put out
+   a symbol.  */
+t_struct3 v_struct3;
+
+/**** unions *******/
+
+union t_union {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+    float	v_float_member;
+    double	v_double_member;
+} v_union;
+
+union {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+    float	v_float_member;
+    double	v_double_member;
+} v_union2;
+
+/* typedef'd union without a tag.  */
+typedef union {
+  double v_double_member;
+  int v_int_member;
+} t_union3;
+/* GCC seems to want a variable of this type, or else it won't put out
+   a symbol.  */
+t_union3 v_union3;
+
+/**** Some misc more complicated things *******/
+
+struct outer_struct {
+	int outer_int;
+	struct inner_struct {
+		int inner_int;
+		long inner_long;
+	}inner_struct_instance;
+	union inner_union {
+		int inner_union_int;
+		long inner_union_long;
+	}inner_union_instance;
+	long outer_long;
+} nested_su;
+
+struct highest
+{
+  int a;
+  struct
+  {
+    int b;
+    struct { int c; } anonymous_level_2;
+  } anonymous_level_1;
+} the_highest;
+
+/**** Enumerations *******/
+
+enum
+/* Work around the bug for compilers which don't put out the right stabs.  */
+#if __GNUC__ < 2 && !defined (_AIX)
+primary1_tag
+#endif
+{red1, green1, blue1} primary1;
+
+enum {red, green, blue} primary;
+enum colors {yellow, purple, pink} nonprimary;
+
+enum {chevy, ford} clunker;
+enum cars {bmw, porsche} sportscar;
+
+#undef FALSE
+#undef TRUE
+typedef enum {FALSE, TRUE} boolean;
+boolean v_boolean;
+/*note: aCC has bool type predefined with 'false' and 'true'*/
+typedef enum bvals {my_false, my_true} boolean2;
+boolean2 v_boolean2;
+
+enum misordered {two = 2, one = 1, zero = 0, three = 3};
+
+/* Seems like we need a variable of this type to get the type to be put
+   in the executable, at least for AIX xlc.  */
+enum misordered v_misordered = three;
+
+/**** Pointers to functions *******/
+
+typedef int (*func_type) (int (*) (int, float), float);
+double (*old_fptr) ();
+double (*new_fptr) (void);
+int (*fptr) (int, float);
+int *(*fptr2) (int (*) (int, float), float);
+int (*xptr) (int (*) (), int (*) (void), int);
+int (*(*ffptr) (char)) (short);
+int (*(*(*fffptr) (char)) (short)) (long);
+
+func_type v_func_type;
+
+int main ()
+{
+  /* Ensure that malloc is a pointer type; avoid use of "void" and any include files. */
+/*  extern char *malloc();*/
+
+  /* Some of the tests in ptype.exp require invoking malloc, so make
+     sure it is linked in to this program.  */
+  v_char_pointer = (char *) malloc (1);
+
+  /* Some linkers (e.g. on AIX) remove unreferenced variables,
+     so make sure to reference them. */
+  primary = blue;
+  primary1 = blue1;
+  nonprimary = pink;
+  sportscar = porsche;
+  clunker = ford;
+  v_struct1.v_int_member = 5;
+  v_struct2.v_int_member = 6;
+  v_struct3.v_int_member = 7;
+
+  v_char = 0;
+  v_signed_char = 0;
+  v_unsigned_char = 0;
+
+  v_short = 0;
+  v_signed_short = 0;
+  v_unsigned_short = 0;
+
+  v_int = 0;
+  v_signed_int = 0;
+  v_unsigned_int = 0;
+
+  v_long = 0;
+  v_signed_long = 0;
+  v_unsigned_long = 0;
+
+  v_float = 0;
+  v_double = 0;
+
+  v_char_array[0] = 0;
+  v_signed_char_array[0] = 0;
+  v_unsigned_char_array[0] = 0;
+
+  v_short_array[0] = 0;
+  v_signed_short_array[0] = 0;
+  v_unsigned_short_array[0] = 0;
+
+  v_int_array[0] = 0;
+  v_signed_int_array[0] = 0;
+  v_unsigned_int_array[0] = 0;
+
+  v_long_array[0] = 0;
+  v_signed_long_array[0] = 0;
+  v_unsigned_long_array[0] = 0;
+
+  v_float_array[0] = 0;
+  v_double_array[0] = 0;
+
+  v_char_pointer = 0;
+  v_signed_char_pointer = 0;
+  v_unsigned_char_pointer = 0;
+
+  v_short_pointer = 0;
+  v_signed_short_pointer = 0;
+  v_unsigned_short_pointer = 0;
+
+  v_int_pointer = 0;
+  v_signed_int_pointer = 0;
+  v_unsigned_int_pointer = 0;
+
+  v_long_pointer = 0;
+  v_signed_long_pointer = 0;
+  v_unsigned_long_pointer = 0;
+
+  v_float_pointer = 0;
+  v_double_pointer = 0;
+
+  nested_su.outer_int = 0;
+  v_t_struct_p = 0;
+
+  the_highest.a = 0;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/ctf-ptype.exp b/gdb/testsuite/gdb.base/ctf-ptype.exp
new file mode 100644
index 0000000..9f54582
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-ptype.exp
@@ -0,0 +1,288 @@
+# Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is a subset of ptype.exp written by Rob Savoye. (rob@cygnus.com)
+
+#
+# test running programs
+#
+# -gt generates full-fledged CTF.
+
+standard_testfile .c
+set opts "additional_flags=-gt"
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+	  [list $srcfile] [list $opts nowarnings]] } {
+    return 0
+}
+
+# Create and source the file that provides information about the compiler
+# used to compile the test case.
+if [get_compiler_info] {
+    return -1
+}
+
+# Test ptype of unnamed enumeration members before any action causes
+# the partial symbol table to be expanded to full symbols.  This fails
+# with stabs compilers which fail to use a nameless stab (such as
+# pre-2.4.5 versions of gcc and most non-gcc compilers).
+
+gdb_test_multiple "ptype red1" "ptype unnamed enumeration member" {
+    -re "type = enum primary1_tag \{red1, green1, blue1\}.*$gdb_prompt $" {
+	# The workaround is in effect.  As this is a compiler, not GDB,
+	# bug, we'll make it a PASS but perhaps it should be an XFAIL.
+	pass "ptype unnamed enumeration member (worked around)"
+    }
+    -re "type = enum \{red1, green1, blue1\}.*$gdb_prompt $" {
+	pass "ptype unnamed enumeration member"
+    }
+}
+
+#
+# test ptype command with structures
+#
+# Here and elsewhere, we accept
+# "long", "long int", or "int" for long variables (whatis.exp already
+# has an XFAIL for "int" (Sun cc bug), so no need to fail it here).
+gdb_test "ptype struct t_struct" "type = struct t_struct \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype structure"
+
+
+# Test the equivalence between '.' and '->' for struct member references.
+
+if [gdb_test "ptype v_t_struct_p.v_float_member"	"type = float"]<0 then {
+    return -1
+}
+if [gdb_test "ptype v_t_struct_p->v_float_member"	"type = float"]<0 then {
+    return -1
+}
+if [gdb_test "ptype v_t_struct_p.v_float_member"	"type = float"]<0 then {
+    return -1
+}
+if [gdb_test "ptype v_t_struct_p->v_float_member"	"type = float"]<0 then {
+    return -1
+}
+
+#
+# test ptype command with unions
+#
+gdb_test "ptype union t_union" "type = union t_union \{.*\[\r\n\]    (unsigned |)char v_char_member;.*\[\r\n\]    (short|short int) v_short_member;.*\[\r\n\]    int v_int_member;.*\[\r\n\]    (long|long int|int) v_long_member;.*\[\r\n\]    float v_float_member;.*\[\r\n\]    double v_double_member;.*\[\r\n\]\}.*" "ptype union"
+
+#
+# test ptype command with enums
+#
+
+gdb_test "ptype primary" "type = enum .red, green, blue.*" "ptype unnamed enumeration"
+
+gdb_test "ptype enum colors" "type = enum colors \{yellow, purple, pink\}.*" "ptype named enumeration"
+
+
+#
+# test ptype command with enums as typedef
+#
+gdb_test "ptype boolean" "type = enum (boolean |)\{FALSE, TRUE\}.*" "ptype unnamed typedef'd enumeration"
+
+gdb_test "list main" ".*"
+
+# Same thing with struct and union.
+gdb_test "ptype t_struct3" "type = struct (t_struct3 |)\{.*
+ *double v_double_member;.*
+ *int v_int_member;.*\}" "printing typedef'd struct"
+
+gdb_test "ptype t_union3" "type = union (t_union3 |)\{.*
+ *double v_double_member;.*
+ *int v_int_member;.*\}" "printing typedef'd union"
+
+gdb_test "ptype enum bvals" "type = enum bvals \{my_false, my_true\}.*" "ptype named typedef'd enumf'd enum"
+
+#
+# test ptype command with out-of-order enum values
+#
+gdb_test "ptype enum misordered" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype misordered enumeration"
+
+#
+# test ptype command with a named enum's value
+#
+gdb_test "ptype three" "type = enum misordered \{two = 2, one = 1, zero = 0, three = 3\}.*" "ptype named enumeration member"
+
+gdb_test "ptype red" "type = enum \{red, green, blue\}.*" "ptype unnamed enumeration member #2"
+
+#
+# test ptype command with arrays
+#
+gdb_test "ptype v_char_array" "type = char .2..*" "ptype char array"
+
+gdb_test "ptype v_signed_char_array" "type = (|signed )char .2..*" "ptype signed char array"
+
+gdb_test "ptype v_unsigned_char_array" "type = unsigned char .2..*" "ptype unsigned char array"
+
+gdb_test "ptype v_int_array" "type = int .2..*" "ptype int array"
+
+gdb_test "ptype v_signed_int_array" "type = int .2..*" "ptype signed int array"
+
+gdb_test "ptype v_unsigned_int_array" "type = unsigned int .2..*" "ptype unsigned int array"
+
+gdb_test "ptype v_long_array" "type = (long|int|long int) .2..*" "ptype long array"
+
+gdb_test "ptype v_signed_long_array" "type = (long|int|long int) .2..*" "ptype signed long array"
+
+gdb_test "ptype v_unsigned_long_array" "type = unsigned long .2..*" "ptype unsigned long array"
+
+gdb_test "ptype v_float_array" "type = float .2..*" "ptype float array"
+
+gdb_test "ptype v_double_array" "type = double .2..*" "ptype double array"
+
+gdb_test "ptype pv_char_array" "type = (|unsigned )char \\(\\*\\)\\\[0?\\\]"
+
+#
+# test ptype command with pointers
+#
+gdb_test "ptype v_char_pointer" "type = char \*.*" "ptype char pointer"
+
+gdb_test "ptype v_short_pointer" "type = short \*.*" "ptype short pointer"
+
+gdb_test "ptype v_long_pointer" "type = long \*.*" "ptype long pointer"
+
+gdb_test "ptype v_int_pointer" "type = int \*.*" "ptype int pointer"
+
+gdb_test "ptype v_signed_long_pointer" "type = long \*.*" "ptype signed long pointer"
+
+gdb_test "ptype v_unsigned_long_pointer" "type = unsigned long \*.*" "ptype unsigned long pointer"
+
+gdb_test "ptype v_float_pointer" "type = float \*.*" "ptype float pointer"
+
+gdb_test "ptype v_double_pointer" "type = double \*.*" "ptype double pointer"
+
+#
+# test ptype command with basic C types
+#
+gdb_test "ptype v_short" "type = short(| int).*" "ptype short"
+
+gdb_test "ptype v_int" "type = int.*" "ptype int"
+
+#
+# test ptype command with nested structure and union
+#
+gdb_test "ptype struct outer_struct" "type = struct outer_struct \{.*\[\r\n\]+\
+.*int outer_int;.*\[\r\n\]+\
+.*(struct|) inner_struct inner_struct_instance;.*\[\r\n\]+\
+.*(union|) inner_union inner_union_instance;.*\[\r\n\]+\
+.*(long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype outer structure"
+
+gdb_test "ptype struct inner_struct" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype inner structure"
+
+gdb_test "ptype union inner_union" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype inner union"
+
+gdb_test "ptype nested_su" "type = struct outer_struct \{.*\[\r\n\]    int outer_int;.*\[\r\n\]    (struct |)inner_struct inner_struct_instance;.*\[\r\n\]    (union |)inner_union inner_union_instance;.*\[\r\n\]    (long|long int|int) outer_long;.*\[\r\n\]\}.*" "ptype nested structure"
+
+gdb_test "ptype nested_su.outer_int" "type = int.*" "ptype outer int"
+
+gdb_test "ptype nested_su.inner_struct_instance" "type = struct inner_struct \{.*\[\r\n\]    int inner_int;.*\[\r\n\]    (long|long int|int) inner_long;.*\[\r\n\]\}.*" "ptype nested structure #2"
+
+gdb_test "ptype nested_su.inner_struct_instance.inner_int" "type = int.*" "ptype inner int"
+
+gdb_test "ptype nested_su.inner_union_instance" "type = union inner_union \{.*\[\r\n\]    int inner_union_int;.*\[\r\n\]    (long|long int|int) inner_union_long;.*\[\r\n\]\}.*" "ptype nested union"
+
+# Print the type description of variable the_highest, and verify that
+# the type description for the fields whose type is anonymous are
+# correctly printed (at nesting level 1 and 2).
+
+gdb_test "ptype the_highest" \
+         "type = struct highest \{.*\[\r\n\] *int a;.*\[\r\n\] *struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{\.\.\.\} anonymous_level_2;.*\[\r\n\] *\} anonymous_level_1;.*\[\r\n\]}.*" \
+         "ptype the_highest"
+
+# Print the type descrption for one of the fields of variable the_highest.
+# The purpose is to verify that the type of a field that was printed above
+# as "struct {...}" is now printed in a more descriptive way (because the
+# nesting level is now one level less).
+
+gdb_test "ptype the_highest.anonymous_level_1" \
+         "type = struct \{.*\[\r\n\] *int b;.*\[\r\n\] *struct \{.*\[\r\n\] *int c;.*\[\r\n\] *\} anonymous_level_2;.*\[\r\n\]}.*" \
+         "ptype the_highest"
+
+# Print the type of the identifier ID, and check the response:
+# - Expect to see PROTOTYPED as the type.  PROTOTYPED is not a regular
+#   expression; it's a literal string.
+# - If we instead see the unprototyped type PLAIN, and we're using STABS
+#   generated by GCC, that's an xfail; as of 9 Feb 2002, GCC never emits
+#   prototyped function types in STABS.  Like PROTOTYPED, PLAIN is a
+#   literal string, not a regular expression.
+# - If we see OVERPROTOTYPED, it's an xfail for RealView; RealView
+#   does not distinguish prototyped and unprototyped functions, and
+#   GDB defaults to prototyped.
+# - Otherwise, it's a failure.
+proc ptype_maybe_prototyped { id prototyped plain { overprototyped "NO-MATCH" } } {
+    global gdb_prompt
+    global gcc_compiled
+
+    # Turn the arguments, which are literal strings, into
+    # regular expressions by quoting any special characters they contain.
+    foreach var { prototyped plain overprototyped } {
+	eval "set val \$$var"
+	regsub -all "\[\]\[*()\]" $val "\\\\&" val
+	regsub -all "short int" $val "short( int)?" val
+	regsub -all "long int" $val "long( int)?" val
+	eval "set $var \$val"
+    }
+
+    gdb_test_multiple "ptype $id" "ptype $id" {
+        -re "type = $prototyped\[\r\n\]+$gdb_prompt $" {
+            pass "ptype $id"
+        }
+        -re "type = $plain\[\r\n\]+$gdb_prompt $" {
+            if {$gcc_compiled} { setup_xfail_format "stabs" }
+            fail "ptype $id (compiler doesn't emit prototyped types)"
+        }
+        -re "type = $overprototyped\[\r\n\]+$gdb_prompt $" {
+            if { [test_compiler_info "armcc-*"] } {
+		setup_xfail "*-*-*"
+	    }
+            fail "ptype $id (compiler doesn't emit unprototyped types)"
+        }
+    }
+}
+
+ptype_maybe_prototyped "old_fptr" "double (*)()" "double (*)()" \
+                                  "double (*)(void)"
+
+# Test printing type of string constants and array constants, but
+# requires a running process.  These call malloc, and can take a long
+# time to execute over a slow serial link, so increase the timeout.
+
+if [runto_main] then {
+
+  if [target_info exists gdb,cannot_call_functions] {
+    unsupported "this target can not call functions"
+    continue
+  }
+
+  # We need to up this because this can be really slow on some boards.
+  # (malloc() is called as part of the test).
+  set prev_timeout $timeout
+  set timeout 60
+
+  gdb_test "ptype \"abc\""	"type = char \\\[4\\\]"
+  gdb_test "ptype {'a','b','c'}"	"type = char \\\[3\\\]"
+  gdb_test "ptype {0,1,2}"		"type = int \\\[3\\\]"
+  gdb_test "ptype {(long)0,(long)1,(long)2}"	  "type = long \\\[3\\\]"
+  gdb_test "ptype {(float)0,(float)1,(float)2}" "type = float \\\[3\\\]"
+  gdb_test "ptype {{0,1,2},{3,4,5}}"	"type = int \\\[2\\\]\\\[3\\\]"
+  gdb_test "ptype {4,5,6}\[2\]"	"type = int"
+  gdb_test "ptype *&{4,5,6}\[1\]"	"Attempt to take address of value not located in memory."
+
+  set timeout $prev_timeout
+
+  # Test ptype of user register
+  gdb_test "ptype \$pc" "void \\(\\*\\)\\(\\)" "ptype \$pc"
+}
diff --git a/gdb/testsuite/gdb.base/ctf-whatis.c b/gdb/testsuite/gdb.base/ctf-whatis.c
new file mode 100644
index 0000000..548dcbb
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-whatis.c
@@ -0,0 +1,282 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/*
+ *	Test file with lots of different types, for testing the
+ *	"whatis" command on CTF data. It's derived from whatis.c.
+ */
+ 
+/*
+ *	First the basic C types.
+ */
+
+char		v_char;
+signed char	v_signed_char;
+unsigned char	v_unsigned_char;
+
+short		v_short;
+signed short	v_signed_short;
+unsigned short	v_unsigned_short;
+
+int		v_int;
+signed int	v_signed_int;
+unsigned int	v_unsigned_int;
+
+long		v_long;
+signed long	v_signed_long;
+unsigned long	v_unsigned_long;
+
+#ifndef NO_LONG_LONG
+long long		v_long_long;
+signed long long	v_signed_long_long;
+unsigned long long	v_unsigned_long_long;
+#endif
+
+float		v_float;
+double		v_double;
+
+/*
+ *	Now some derived types, which are arrays, functions-returning,
+ *	pointers, structures, unions, and enumerations.
+ */
+
+/**** arrays *******/
+
+char		v_char_array[2];
+signed char	v_signed_char_array[2];
+unsigned char	v_unsigned_char_array[2];
+
+short		v_short_array[2];
+signed short	v_signed_short_array[2];
+unsigned short	v_unsigned_short_array[2];
+
+int		v_int_array[2];
+signed int	v_signed_int_array[2];
+unsigned int	v_unsigned_int_array[2];
+
+long		v_long_array[2];
+signed long	v_signed_long_array[2];
+unsigned long	v_unsigned_long_array[2];
+
+#ifndef NO_LONG_LONG
+long long		v_long_long_array[2];
+signed long long	v_signed_long_long_array[2];
+unsigned long long	v_unsigned_long_long_array[2];
+#endif
+
+float		v_float_array[2];
+double		v_double_array[2];
+
+/**** pointers *******/
+
+/* Make sure they still print as pointer to foo even there is a typedef
+   for that type.  Test this not just for char *, which might be
+   a special case kludge in GDB (Unix system include files like to define
+   caddr_t), but for a variety of types.  */
+typedef char *char_addr;
+char_addr a_char_addr;
+typedef unsigned short *ushort_addr;
+ushort_addr a_ushort_addr;
+typedef signed long *slong_addr;
+slong_addr a_slong_addr;
+#ifndef NO_LONG_LONG
+typedef signed long long *slong_long_addr;
+slong_long_addr a_slong_long_addr;
+#endif
+
+char		*v_char_pointer;
+signed char	*v_signed_char_pointer;
+unsigned char	*v_unsigned_char_pointer;
+
+short		*v_short_pointer;
+signed short	*v_signed_short_pointer;
+unsigned short	*v_unsigned_short_pointer;
+
+int		*v_int_pointer;
+signed int	*v_signed_int_pointer;
+unsigned int	*v_unsigned_int_pointer;
+
+long		*v_long_pointer;
+signed long	*v_signed_long_pointer;
+unsigned long	*v_unsigned_long_pointer;
+
+#ifndef NO_LONG_LONG
+long long		*v_long_long_pointer;
+signed long long	*v_signed_long_long_pointer;
+unsigned long long	*v_unsigned_long_long_pointer;
+#endif
+
+float		*v_float_pointer;
+double		*v_double_pointer;
+
+/**** structs *******/
+
+struct t_struct {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+#ifndef NO_LONG_LONG
+    long long	v_long_long_member;
+#endif
+    float	v_float_member;
+    double	v_double_member;
+} v_struct1, *v_struct_ptr1;
+
+struct {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+#ifndef NO_LONG_LONG
+    long long	v_long_long_member;
+#endif
+    float	v_float_member;
+    double	v_double_member;
+} v_struct2, *v_struct_ptr2;
+
+/**** unions *******/
+
+union t_union {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+#ifndef NO_LONG_LONG
+    long long	v_long_long_member;
+#endif
+    float	v_float_member;
+    double	v_double_member;
+} v_union, *v_union_ptr;
+
+union {
+    char	v_char_member;
+    short	v_short_member;
+    int		v_int_member;
+    long	v_long_member;
+#ifndef NO_LONG_LONG
+    long long	v_long_long_member;
+#endif
+    float	v_float_member;
+    double	v_double_member;
+} v_union2, *v_union_ptr2;
+
+/**** Some misc more complicated things *******/
+
+struct outer_struct {
+	int outer_int;
+	struct inner_struct {
+		int inner_int;
+		long inner_long;
+	}inner_struct_instance;
+	union inner_union {
+		int inner_union_int;
+		long inner_union_long;
+	}inner_union_instance;
+	long outer_long;
+} nested_su;
+
+/***********/
+
+int main ()
+{
+  /* Some linkers (e.g. on AIX) remove unreferenced variables,
+     so make sure to reference them. */
+  v_char = 0;
+  v_signed_char = 1;
+  v_unsigned_char = 2;
+
+  v_short = 3;
+  v_signed_short = 4;
+  v_unsigned_short = 5;
+
+  v_int = 6;
+  v_signed_int = 7;
+  v_unsigned_int = 8;
+
+  v_long = 9;
+  v_signed_long = 10;
+  v_unsigned_long = 11;
+
+#ifndef NO_LONG_LONG
+  v_long_long = 12;
+  v_signed_long_long = 13;
+  v_unsigned_long_long = 14;
+#endif
+
+  v_float = 100.0;
+  v_double = 200.0;
+
+
+  v_char_array[0] = v_char;
+  v_signed_char_array[0] = v_signed_char;
+  v_unsigned_char_array[0] = v_unsigned_char;
+
+  v_short_array[0] = v_short;
+  v_signed_short_array[0] = v_signed_short;
+  v_unsigned_short_array[0] = v_unsigned_short;
+
+  v_int_array[0] = v_int;
+  v_signed_int_array[0] = v_signed_int;
+  v_unsigned_int_array[0] = v_unsigned_int;
+
+  v_long_array[0] = v_long;
+  v_signed_long_array[0] = v_signed_long;
+  v_unsigned_long_array[0] = v_unsigned_long;
+
+#ifndef NO_LONG_LONG
+  v_long_long_array[0] = v_long_long;
+  v_signed_long_long_array[0] = v_signed_long_long;
+  v_unsigned_long_long_array[0] = v_unsigned_long_long;
+#endif
+
+  v_float_array[0] = v_float;
+  v_double_array[0] = v_double;
+
+  v_char_pointer = &v_char;
+  v_signed_char_pointer = &v_signed_char;
+  v_unsigned_char_pointer = &v_unsigned_char;
+
+  v_short_pointer = &v_short;
+  v_signed_short_pointer = &v_signed_short;
+  v_unsigned_short_pointer = &v_unsigned_short;
+
+  v_int_pointer = &v_int;
+  v_signed_int_pointer = &v_signed_int;
+  v_unsigned_int_pointer = &v_unsigned_int;
+
+  v_long_pointer = &v_long;
+  v_signed_long_pointer = &v_signed_long;
+  v_unsigned_long_pointer = &v_unsigned_long;
+
+#ifndef NO_LONG_LONG
+  v_long_long_pointer = &v_long_long;
+  v_signed_long_long_pointer = &v_signed_long_long;
+  v_unsigned_long_long_pointer = &v_unsigned_long_long;
+#endif
+
+  v_float_pointer = &v_float;
+  v_double_pointer = &v_double;
+
+  v_union2.v_short_member = v_union.v_short_member;
+
+  v_struct1.v_char_member = 0;
+  v_struct2.v_char_member = 0;
+
+  nested_su.outer_int = 0;
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.base/ctf-whatis.exp b/gdb/testsuite/gdb.base/ctf-whatis.exp
new file mode 100644
index 0000000..3f26fc3
--- /dev/null
+++ b/gdb/testsuite/gdb.base/ctf-whatis.exp
@@ -0,0 +1,413 @@
+# Copyright 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file is a subset of whatis.exp written by Rob Savoye. (rob@cygnus.com)
+
+#
+# test running programs
+#
+# -gt generates full-fledged CTF.
+
+standard_testfile .c
+set opts "additional_flags=-gt"
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+          [list $srcfile] [list $opts nowarnings]] } {
+    return 0
+}
+
+# Create and source the file that provides information about the compiler
+# used to compile the test case.
+if [get_compiler_info] {
+    return -1
+}
+
+# Start with a fresh gdb.
+
+clean_restart $binfile
+
+# Define a procedure to set up an xfail for all targets that put out a
+# `long' type as an `int' type.
+# Sun cc has this problem.
+# It was said that COFF targets can not distinguish int from long either.
+
+proc setup_xfail_on_long_vs_int {} {
+    global gcc_compiled
+
+    if {!$gcc_compiled} {
+	setup_xfail "*-sun-sunos4*" "i*86-sequent-bsd*"
+    }
+}
+
+#
+# Test whatis command with basic C types
+#
+# The name printed now (as of 23 May 1993) is whatever name the compiler
+# uses in the stabs.  So we need to deal with names both from gcc and
+# native compilers.
+#
+
+gdb_test "whatis v_char" \
+    "type = (unsigned char|char)" \
+    "whatis char"
+
+gdb_test "whatis v_signed_char" \
+    "type = (signed char|char)" \
+    "whatis signed char"
+
+gdb_test "whatis v_unsigned_char" \
+    "type = unsigned char" \
+    "whatis unsigned char"
+
+gdb_test "whatis v_short" \
+    "type = (short|short int)" \
+    "whatis short"
+
+gdb_test "whatis v_signed_short" \
+    "type = (short|short int|signed short|signed short int)" \
+    "whatis signed short"
+
+gdb_test "whatis v_unsigned_short" \
+    "type = (unsigned short|short unsigned int)" \
+    "whatis unsigned short"
+
+gdb_test "whatis v_int" \
+    "type = int" \
+    "whatis int"
+
+gdb_test "whatis v_signed_int" \
+    "type = (signed |)int" \
+    "whatis signed int"
+
+gdb_test "whatis v_unsigned_int" \
+    "type = unsigned int" \
+    "whatis unsigned int"
+
+setup_xfail_on_long_vs_int
+# AIX xlc gets this wrong and unsigned long right.  Go figure.
+if {!$gcc_compiled} then {setup_xfail "rs6000-*-aix*"}
+gdb_test "whatis v_long" \
+    "type = (long|long int)" \
+    "whatis long"
+
+setup_xfail_on_long_vs_int
+# AIX xlc gets this wrong and unsigned long right.  Go figure.
+if {!$gcc_compiled} then {setup_xfail "rs6000-*-aix*"}
+gdb_test "whatis v_signed_long" \
+    "type = (signed |)(long|long int)" \
+    "whatis signed long"
+
+setup_xfail_on_long_vs_int
+gdb_test "whatis v_unsigned_long" \
+    "type = (unsigned long|long unsigned int)" \
+    "whatis unsigned long"
+
+
+if ![target_info exists no_long_long] {
+    gdb_test "whatis v_unsigned_long_long" \
+	"type = (unsigned long long|long long unsigned int)" \
+	"whatis unsigned long long"
+}
+
+gdb_test "whatis v_float" \
+    "type = float" \
+    "whatis float"
+
+gdb_test "whatis v_double" \
+    "type = double" \
+    "whatis double"
+
+
+# test whatis command with arrays
+#
+# We already tested whether char prints as "char", so here we accept
+# "unsigned char", "signed char", and other perversions.  No need for more
+# than one xfail for the same thing.
+gdb_test "whatis v_char_array" \
+    "type = (signed |unsigned |)char \\\[2\\\]" \
+    "whatis char array"
+
+gdb_test "whatis v_signed_char_array" \
+    "type = (signed |unsigned |)char \\\[2\\\]" \
+    "whatis signed char array"
+
+gdb_test "whatis v_unsigned_char_array" \
+    "type = unsigned char \\\[2\\\]" \
+    "whatis unsigned char array"
+
+gdb_test "whatis v_short_array" \
+    "type = (short|short int) \\\[2\\\]" \
+    "whatis short array"
+
+gdb_test "whatis v_signed_short_array" \
+    "type = (signed |)(short|short int) \\\[2\\\]" \
+    "whatis signed short array"
+
+gdb_test "whatis v_unsigned_short_array" \
+    "type = (unsigned short|short unsigned int) \\\[2\\\]" \
+    "whatis unsigned short array"
+
+gdb_test "whatis v_int_array" \
+    "type = int \\\[2\\\]" \
+    "whatis int array"
+
+gdb_test "whatis v_signed_int_array" \
+    "type = (signed |)int \\\[2\\\]" \
+    "whatis signed int array"
+
+gdb_test "whatis v_unsigned_int_array" \
+    "type = unsigned int \\\[2\\\]" \
+    "whatis unsigned int array"
+
+# We already tested whether long prints as long, so here we accept int
+# No need for more than one xfail for the same thing.
+gdb_test "whatis v_long_array" \
+    "type = (int|long|long int) \\\[2\\\]" \
+    "whatis long array"
+
+gdb_test "whatis v_signed_long_array" \
+    "type = (signed |)(int|long|long int) \\\[2\\\]" \
+    "whatis signed long array"
+
+gdb_test "whatis v_unsigned_long_array" \
+    "type = (unsigned (int|long|long int)|long unsigned int) \\\[2\\\]" \
+    "whatis unsigned long array"
+
+if ![target_info exists no_long_long] {
+    gdb_test "whatis v_unsigned_long_long_array" \
+	"type = (unsigned long long|long long unsigned int) \\\[2\\\]" \
+	"whatis unsigned long array"
+}
+
+gdb_test "whatis v_float_array" \
+    "type = float \\\[2\\\]" \
+    "whatis float array"
+
+gdb_test "whatis v_double_array" \
+    "type = double \\\[2\\\]" \
+    "whatis double array"
+
+
+# test whatis command with pointers
+#
+# We already tested whether char prints as char, so accept various perversions
+# here.  We especially want to make sure we test that it doesn't print as
+# caddr_t.
+gdb_test "whatis v_char_pointer" \
+    "type = (unsigned |signed |)char \\*" \
+    "whatis char pointer"
+
+gdb_test "whatis v_signed_char_pointer" \
+    "type = (unsigned |signed |)char \\*" \
+    "whatis signed char pointer"
+
+gdb_test "whatis v_unsigned_char_pointer" \
+    "type = unsigned char \\*" \
+    "whatis unsigned char pointer"
+
+gdb_test "whatis v_short_pointer" \
+    "type = (short|short int) \\*" \
+    "whatis short pointer"
+
+gdb_test "whatis v_signed_short_pointer" \
+    "type = (signed |)(short|short int) \\*" \
+    "whatis signed short pointer"
+
+gdb_test "whatis v_unsigned_short_pointer" \
+    "type = (unsigned short|short unsigned int) \\*" \
+    "whatis unsigned short pointer"
+
+gdb_test "whatis v_int_pointer" \
+    "type = int \\*" \
+    "whatis int pointer"
+
+gdb_test "whatis v_signed_int_pointer" \
+    "type = (signed |)int \\*" \
+    "whatis signed int pointer"
+
+gdb_test "whatis v_unsigned_int_pointer" \
+    "type = unsigned int \\*" \
+    "whatis unsigned int pointer"
+
+# We already tested whether long prints as long, so here we accept int
+gdb_test "whatis v_long_pointer" \
+    "type = (long|int|long int) \\*" \
+    "whatis long pointer"
+
+gdb_test "whatis v_signed_long_pointer" \
+    "type = (signed |)(long|int|long int) \\*" \
+    "whatis signed long pointer"
+
+gdb_test "whatis v_unsigned_long_pointer" \
+    "type = (unsigned (int|long|long int)|long unsigned int) \\*" \
+    "whatis unsigned long pointer"
+
+if ![target_info exists no_long_long] {
+    gdb_test "whatis v_long_long_pointer" \
+	"type = long long(| int) \\*" \
+	"whatis long long pointer"
+
+    gdb_test "whatis v_signed_long_long_pointer" \
+	"type = (signed |)long long(| int) \\*" \
+	"whatis signed long long pointer"
+
+    gdb_test "whatis v_unsigned_long_long_pointer" \
+	"type = (unsigned long long|long long unsigned int) \\*" \
+	"whatis unsigned long long pointer"
+}
+
+gdb_test "whatis v_float_pointer" \
+    "type = float \\*" \
+    "whatis float pointer"
+
+gdb_test "whatis v_double_pointer" \
+    "type = double \\*" \
+    "whatis double pointer"
+
+
+# test whatis command with structure types
+
+# First with a type argument, with both "set print object" set to "on"
+# and "off", ending with "off" for the following tests.
+foreach_with_prefix print_object {"on" "off"} {
+    gdb_test_no_output "set print object $print_object"
+
+    gdb_test "whatis struct t_struct" \
+	"type = struct t_struct" \
+	"whatis named structure using type name"
+
+    gdb_test "whatis struct t_struct *" \
+	"type = struct t_struct \\*" \
+	"whatis named structure using type name and pointer"
+
+    gdb_test "whatis struct t_struct &" \
+	"type = struct t_struct &" \
+	"whatis named structure using type name and reference"
+}
+
+# Now with an expression argument.
+
+gdb_test "whatis v_struct_ptr1" \
+    "type = struct t_struct \\*"
+
+gdb_test "whatis &v_struct_ptr1" \
+    "type = struct t_struct \\*\\*"
+
+gdb_test "whatis v_struct_ptr1->v_char_member" \
+    "type = char"
+
+gdb_test "whatis v_struct_ptr2->v_char_member" \
+    "type = char"
+
+gdb_test "whatis &(v_struct_ptr1->v_char_member)" \
+    "type = char \\*"
+
+gdb_test "whatis &(v_struct_ptr2->v_char_member)" \
+    "type = char \\*"
+
+# test whatis command with union types
+
+gdb_test "whatis union t_union" \
+    "type = union t_union" \
+    "whatis named union using type name"
+
+gdb_test "whatis v_union_ptr" \
+    "type = union t_union \\*"
+
+gdb_test "whatis &v_union_ptr" \
+    "type = union t_union \\*\\*"
+
+gdb_test "whatis v_union_ptr->v_char_member" \
+    "type = char"
+
+gdb_test "whatis v_union_ptr2->v_char_member" \
+    "type = char"
+
+gdb_test "whatis &(v_union_ptr->v_char_member)" \
+    "type = char \\*"
+
+gdb_test "whatis &(v_union_ptr2->v_char_member)" \
+    "type = char \\*"
+
+# test whatis command with nested struct and union
+gdb_test "whatis nested_su" \
+    "type = struct outer_struct" \
+    "whatis outer structure"
+
+gdb_test "whatis nested_su.outer_int" \
+    "type = int" \
+    "whatis outer structure member"
+
+gdb_test "whatis nested_su.inner_struct_instance" \
+    "type = struct inner_struct" \
+    "whatis inner structure"
+
+gdb_test "whatis nested_su.inner_struct_instance.inner_int" \
+    "type = int" \
+    "whatis inner structure member"
+
+gdb_test "whatis nested_su.inner_union_instance" \
+    "type = union inner_union" \
+    "whatis inner union"
+
+gdb_test "whatis nested_su.inner_union_instance.inner_union_int" \
+    "type = int" \
+    "whatis inner union member"
+
+# Using stabs we will mark these functions as prototyped.  This
+# is harmless but causes an extra VOID to be printed.
+set void "(void|)"
+
+# Regression tests for PR 9514.
+
+gdb_test "whatis void (**)()" \
+  "type = void \\(\\*\\*\\)\\(\\)" \
+  "whatis applied to pointer to pointer to function"
+
+gdb_test "whatis void (** const)()" \
+  "type = void \\(\\*\\* const\\)\\(\\)" \
+  "whatis applied to const pointer to pointer to function"
+
+gdb_test "whatis void (* const *)()" \
+  "type = void \\(\\* const \\*\\)\\(\\)" \
+  "whatis applied to pointer to const pointer to function"
+
+gdb_test "whatis int *(*)()" \
+    "type = int \\*\\(\\*\\)\\(\\)" \
+    "whatis applied to pointer to function returning pointer to int"
+
+gdb_test "whatis int *(**)()" \
+    "type = int \\*\\(\\*\\*\\)\\(\\)" \
+    "whatis applied to pointer to pointer to function returning pointer to int"
+
+gdb_test "whatis char (*(*)())\[23\]" \
+    "type = char \\(\\*\\(\\*\\)\\(\\)\\)\\\[23\\\]" \
+    "whatis applied to pointer to function returning pointer to array"
+
+gdb_test "whatis int (*)(int, int)" \
+    "type = int \\(\\*\\)\\(int, int\\)" \
+    "whatis applied to pointer to function taking int,int and returning int"
+
+gdb_test "whatis int (*)(const int *, ...)" \
+    "type = int \\(\\*\\)\\(const int \\*, \\.\\.\\.\\)" \
+    "whatis applied to pointer to function taking const int ptr and varargs and returning int"
+
+gdb_test "whatis int (*)(void, int, int)" \
+    "parameter types following 'void'" \
+    "whatis applied to function with types trailing 'void'"
+
+gdb_test "whatis int (*)(int, void, int)" \
+    "'void' invalid as parameter type" \
+    "whatis applied to function with 'void' parameter type"
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v4 1/2] Renaming of ctf (the trace format) files
@ 2019-10-04 20:25 Weimin Pan
  2019-10-04 20:24 ` [PATCH v4 2/2] gdb: CTF support Weimin Pan
  0 siblings, 1 reply; 9+ messages in thread
From: Weimin Pan @ 2019-10-04 20:25 UTC (permalink / raw)
  To: gdb-patches

To avoid confusion with the Compact ANSI-C Type Format (CTF), rename
ctf.[ch] to tracectf.[ch].

gdb/ChangeLog
+2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
+
+	* tracectf.h: Rename, was ctf.h.
+	* tracectf.c: Rename, was ctf.c, replace ctf.h with tracectf.h.
+	* tracefile.c: Likewise.
+	* tracepoint.c: Remove unused include ctf.h.
+	* mi/mi-main.c: Likewise.
+	* Makefile.in Replace ctf.c with tracectf.c.
+
---
 gdb/ChangeLog    |    9 +
 gdb/Makefile.in  |   10 +-
 gdb/ctf.c        | 1730 ------------------------------------------------------
 gdb/mi/mi-main.c |    1 -
 gdb/tracectf.c   | 1730 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/tracectf.h   |   25 +
 gdb/tracefile.c  |    2 +-
 gdb/tracepoint.c |    1 -
 8 files changed, 1772 insertions(+), 1736 deletions(-)
 delete mode 100644 gdb/ctf.c
 create mode 100644 gdb/tracectf.c
 create mode 100644 gdb/tracectf.h

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 446c455..3974823 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,12 @@
 2019-10-03  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* f-lang.c (f_language_defn): Use cp_get_symbol_name_matcher and
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 81bed90..cb3a403 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -153,6 +153,9 @@ INCLUDE_CFLAGS = -I$(INCLUDE_DIR)
 # Where is the "-liberty" library?  Typically in ../libiberty.
 LIBIBERTY = ../libiberty/libiberty.a
 
+# Where is the CTF library?  Typically in ../libctf.
+LIBCTF = ../libctf/.libs/libctf.a
+
 # Where is the BFD library?  Typically in ../bfd.
 BFD_DIR = ../bfd
 BFD = $(BFD_DIR)/libbfd.a
@@ -588,13 +591,14 @@ INTERNAL_LDFLAGS = \
 # Libraries and corresponding dependencies for compiling gdb.
 # XM_CLIBS, defined in *config files, have host-dependent libs.
 # LIBIBERTY appears twice on purpose.
-CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
+CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
+        $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
 	$(XM_CLIBS) $(GDBTKLIBS) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
 	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
 	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
 	$(SRCHIGH_LIBS)
-CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
+CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
 
 DIST = gdb
@@ -988,7 +992,6 @@ COMMON_SFILES = \
 	cp-namespace.c \
 	cp-support.c \
 	cp-valprint.c \
-	ctf.c \
 	d-lang.c \
 	d-namespace.c \
 	d-valprint.c \
@@ -1124,6 +1127,7 @@ COMMON_SFILES = \
 	thread-iter.c \
 	tid-parse.c \
 	top.c \
+	tracectf.c \
 	tracefile.c \
 	tracefile-tfile.c \
 	tracepoint.c \
diff --git a/gdb/ctf.c b/gdb/ctf.c
deleted file mode 100644
index b3c3f0d..0000000
--- a/gdb/ctf.c
+++ /dev/null
@@ -1,1730 +0,0 @@
-/* CTF format support.
-
-   Copyright (C) 2012-2019 Free Software Foundation, Inc.
-   Contributed by Hui Zhu <hui_zhu@mentor.com>
-   Contributed by Yao Qi <yao@codesourcery.com>
-
-   This file is part of GDB.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-#include "defs.h"
-#include "ctf.h"
-#include "tracepoint.h"
-#include "regcache.h"
-#include <sys/stat.h>
-#include "exec.h"
-#include "completer.h"
-#include "inferior.h"
-#include "gdbthread.h"
-#include "tracefile.h"
-#include <ctype.h>
-#include <algorithm>
-#include "gdbsupport/filestuff.h"
-#include "gdbarch.h"
-
-/* The CTF target.  */
-
-static const target_info ctf_target_info = {
-  "ctf",
-  N_("CTF file"),
-  N_("(Use a CTF directory as a target.\n\
-Specify the filename of the CTF directory.")
-};
-
-class ctf_target final : public tracefile_target
-{
-public:
-  const target_info &info () const override
-  { return ctf_target_info; }
-
-  void close () override;
-  void fetch_registers (struct regcache *, int) override;
-  enum target_xfer_status xfer_partial (enum target_object object,
-						const char *annex,
-						gdb_byte *readbuf,
-						const gdb_byte *writebuf,
-						ULONGEST offset, ULONGEST len,
-						ULONGEST *xfered_len) override;
-  void files_info () override;
-  int trace_find (enum trace_find_type type, int num,
-			  CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override;
-  bool get_trace_state_variable_value (int tsv, LONGEST *val) override;
-  traceframe_info_up traceframe_info () override;
-};
-
-/* GDB saves trace buffers and other information (such as trace
-   status) got from the remote target into Common Trace Format (CTF).
-   The following types of information are expected to save in CTF:
-
-   1. The length (in bytes) of register cache.  Event "register" will
-   be defined in metadata, which includes the length.
-
-   2. Trace status.  Event "status" is defined in metadata, which
-   includes all aspects of trace status.
-
-   3. Uploaded trace variables.  Event "tsv_def" is defined in
-   metadata, which is about all aspects of a uploaded trace variable.
-   Uploaded tracepoints.   Event "tp_def" is defined in meta, which
-   is about all aspects of an uploaded tracepoint.  Note that the
-   "sequence" (a CTF type, which is a dynamically-sized array.) is
-   used for "actions" "step_actions" and "cmd_strings".
-
-   4. Trace frames.  Each trace frame is composed by several blocks
-   of different types ('R', 'M', 'V').  One trace frame is saved in
-   one CTF packet and the blocks of this frame are saved as events.
-   4.1: The trace frame related information (such as the number of
-   tracepoint associated with this frame) is saved in the packet
-   context.
-   4.2: The block 'M', 'R' and 'V' are saved in event "memory",
-   "register" and "tsv" respectively.
-   4.3: When iterating over events, babeltrace can't tell iterator
-   goes to a new packet, so we need a marker or anchor to tell GDB
-   that iterator goes into a new packet or frame.  We define event
-   "frame".  */
-
-#define CTF_MAGIC		0xC1FC1FC1
-#define CTF_SAVE_MAJOR		1
-#define CTF_SAVE_MINOR		8
-
-#define CTF_METADATA_NAME	"metadata"
-#define CTF_DATASTREAM_NAME	"datastream"
-
-/* Reserved event id.  */
-
-#define CTF_EVENT_ID_REGISTER 0
-#define CTF_EVENT_ID_TSV 1
-#define CTF_EVENT_ID_MEMORY 2
-#define CTF_EVENT_ID_FRAME 3
-#define CTF_EVENT_ID_STATUS 4
-#define CTF_EVENT_ID_TSV_DEF 5
-#define CTF_EVENT_ID_TP_DEF 6
-
-#define CTF_PID (2)
-
-/* The state kept while writing the CTF datastream file.  */
-
-struct trace_write_handler
-{
-  /* File descriptor of metadata.  */
-  FILE *metadata_fd;
-  /* File descriptor of traceframes.  */
-  FILE *datastream_fd;
-
-  /* This is the content size of the current packet.  */
-  size_t content_size;
-
-  /* This is the start offset of current packet.  */
-  long packet_start;
-};
-
-/* Write metadata in FORMAT.  */
-
-static void
-ctf_save_write_metadata (struct trace_write_handler *handler,
-			 const char *format, ...)
-  ATTRIBUTE_PRINTF (2, 3);
-
-static void
-ctf_save_write_metadata (struct trace_write_handler *handler,
-			 const char *format, ...)
-{
-  va_list args;
-
-  va_start (args, format);
-  if (vfprintf (handler->metadata_fd, format, args) < 0)
-    error (_("Unable to write metadata file (%s)"),
-	     safe_strerror (errno));
-  va_end (args);
-}
-
-/* Write BUF of length SIZE to datastream file represented by
-   HANDLER.  */
-
-static int
-ctf_save_write (struct trace_write_handler *handler,
-		const gdb_byte *buf, size_t size)
-{
-  if (fwrite (buf, size, 1, handler->datastream_fd) != 1)
-    error (_("Unable to write file for saving trace data (%s)"),
-	   safe_strerror (errno));
-
-  handler->content_size += size;
-
-  return 0;
-}
-
-/* Write a unsigned 32-bit integer to datastream file represented by
-   HANDLER.  */
-
-#define ctf_save_write_uint32(HANDLER, U32) \
-  ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
-
-/* Write a signed 32-bit integer to datastream file represented by
-   HANDLER.  */
-
-#define ctf_save_write_int32(HANDLER, INT32) \
-  ctf_save_write ((HANDLER), (gdb_byte *) &(INT32), 4)
-
-/* Set datastream file position.  Update HANDLER->content_size
-   if WHENCE is SEEK_CUR.  */
-
-static int
-ctf_save_fseek (struct trace_write_handler *handler, long offset,
-		int whence)
-{
-  gdb_assert (whence != SEEK_END);
-  gdb_assert (whence != SEEK_SET
-	      || offset <= handler->content_size + handler->packet_start);
-
-  if (fseek (handler->datastream_fd, offset, whence))
-    error (_("Unable to seek file for saving trace data (%s)"),
-	   safe_strerror (errno));
-
-  if (whence == SEEK_CUR)
-    handler->content_size += offset;
-
-  return 0;
-}
-
-/* Change the datastream file position to align on ALIGN_SIZE,
-   and write BUF to datastream file.  The size of BUF is SIZE.  */
-
-static int
-ctf_save_align_write (struct trace_write_handler *handler,
-		      const gdb_byte *buf,
-		      size_t size, size_t align_size)
-{
-  long offset
-    = (align_up (handler->content_size, align_size)
-       - handler->content_size);
-
-  if (ctf_save_fseek (handler, offset, SEEK_CUR))
-    return -1;
-
-  if (ctf_save_write (handler, buf, size))
-    return -1;
-
-  return 0;
-}
-
-/* Write events to next new packet.  */
-
-static void
-ctf_save_next_packet (struct trace_write_handler *handler)
-{
-  handler->packet_start += (handler->content_size + 4);
-  ctf_save_fseek (handler, handler->packet_start, SEEK_SET);
-  handler->content_size = 0;
-}
-
-/* Write the CTF metadata header.  */
-
-static void
-ctf_save_metadata_header (struct trace_write_handler *handler)
-{
-  ctf_save_write_metadata (handler, "/* CTF %d.%d */\n",
-			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 8; align = 8; "
-			   "signed = false; encoding = ascii;}"
-			   " := ascii;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 8; align = 8; "
-			   "signed = false; }"
-			   " := uint8_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 16; align = 16;"
-			   "signed = false; } := uint16_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 32; align = 32;"
-			   "signed = false; } := uint32_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 64; align = 64;"
-			   "signed = false; base = hex;}"
-			   " := uint64_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 32; align = 32;"
-			   "signed = true; } := int32_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias integer { size = 64; align = 64;"
-			   "signed = true; } := int64_t;\n");
-  ctf_save_write_metadata (handler,
-			   "typealias string { encoding = ascii;"
-			   " } := chars;\n");
-  ctf_save_write_metadata (handler, "\n");
-
-  /* Get the byte order of the host and write CTF data in this byte
-     order.  */
-#if WORDS_BIGENDIAN
-#define HOST_ENDIANNESS "be"
-#else
-#define HOST_ENDIANNESS "le"
-#endif
-
-  ctf_save_write_metadata (handler,
-			   "\ntrace {\n"
-			   "	major = %u;\n"
-			   "	minor = %u;\n"
-			   "	byte_order = %s;\n"
-			   "	packet.header := struct {\n"
-			   "		uint32_t magic;\n"
-			   "	};\n"
-			   "};\n"
-			   "\n"
-			   "stream {\n"
-			   "	packet.context := struct {\n"
-			   "		uint32_t content_size;\n"
-			   "		uint32_t packet_size;\n"
-			   "		uint16_t tpnum;\n"
-			   "	};\n"
-			   "	event.header := struct {\n"
-			   "		uint32_t id;\n"
-			   "	};\n"
-			   "};\n",
-			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
-			   HOST_ENDIANNESS);
-  ctf_save_write_metadata (handler, "\n");
-}
-
-/* CTF trace writer.  */
-
-struct ctf_trace_file_writer
-{
-  struct trace_file_writer base;
-
-  /* States related to writing CTF trace file.  */
-  struct trace_write_handler tcs;
-};
-
-/* This is the implementation of trace_file_write_ops method
-   dtor.  */
-
-static void
-ctf_dtor (struct trace_file_writer *self)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-
-  if (writer->tcs.metadata_fd != NULL)
-    fclose (writer->tcs.metadata_fd);
-
-  if (writer->tcs.datastream_fd != NULL)
-    fclose (writer->tcs.datastream_fd);
-
-}
-
-/* This is the implementation of trace_file_write_ops method
-   target_save.  */
-
-static int
-ctf_target_save (struct trace_file_writer *self,
-		 const char *dirname)
-{
-  /* Don't support save trace file to CTF format in the target.  */
-  return 0;
-}
-
-/* This is the implementation of trace_file_write_ops method
-   start.  It creates the directory DIRNAME, metadata and datastream
-   in the directory.  */
-
-static void
-ctf_start (struct trace_file_writer *self, const char *dirname)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  mode_t hmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH;
-
-  /* Create DIRNAME.  */
-  if (mkdir (dirname, hmode) && errno != EEXIST)
-    error (_("Unable to open directory '%s' for saving trace data (%s)"),
-	   dirname, safe_strerror (errno));
-
-  memset (&writer->tcs, '\0', sizeof (writer->tcs));
-
-  std::string file_name = string_printf ("%s/%s", dirname, CTF_METADATA_NAME);
-
-  writer->tcs.metadata_fd
-    = gdb_fopen_cloexec (file_name.c_str (), "w").release ();
-  if (writer->tcs.metadata_fd == NULL)
-    error (_("Unable to open file '%s' for saving trace data (%s)"),
-	   file_name.c_str (), safe_strerror (errno));
-
-  ctf_save_metadata_header (&writer->tcs);
-
-  file_name = string_printf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
-  writer->tcs.datastream_fd
-    = gdb_fopen_cloexec (file_name.c_str (), "w").release ();
-  if (writer->tcs.datastream_fd == NULL)
-    error (_("Unable to open file '%s' for saving trace data (%s)"),
-	   file_name.c_str (), safe_strerror (errno));
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_header.  Write the types of events on trace variable and
-   frame.  */
-
-static void
-ctf_write_header (struct trace_file_writer *self)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"memory\";\n\tid = %u;\n"
-			   "\tfields := struct { \n"
-			   "\t\tuint64_t address;\n"
-			   "\t\tuint16_t length;\n"
-			   "\t\tuint8_t contents[length];\n"
-			   "\t};\n"
-			   "};\n", CTF_EVENT_ID_MEMORY);
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"tsv\";\n\tid = %u;\n"
-			   "\tfields := struct { \n"
-			   "\t\tuint64_t val;\n"
-			   "\t\tuint32_t num;\n"
-			   "\t};\n"
-			   "};\n", CTF_EVENT_ID_TSV);
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"frame\";\n\tid = %u;\n"
-			   "\tfields := struct { \n"
-			   "\t};\n"
-			   "};\n", CTF_EVENT_ID_FRAME);
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			  "event {\n\tname = \"tsv_def\";\n"
-			  "\tid = %u;\n\tfields := struct { \n"
-			  "\t\tint64_t initial_value;\n"
-			  "\t\tint32_t number;\n"
-			  "\t\tint32_t builtin;\n"
-			  "\t\tchars name;\n"
-			  "\t};\n"
-			  "};\n", CTF_EVENT_ID_TSV_DEF);
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"tp_def\";\n"
-			   "\tid = %u;\n\tfields := struct { \n"
-			   "\t\tuint64_t addr;\n"
-			   "\t\tuint64_t traceframe_usage;\n"
-			   "\t\tint32_t number;\n"
-			   "\t\tint32_t enabled;\n"
-			   "\t\tint32_t step;\n"
-			   "\t\tint32_t pass;\n"
-			   "\t\tint32_t hit_count;\n"
-			   "\t\tint32_t type;\n"
-			   "\t\tchars cond;\n"
-
-			  "\t\tuint32_t action_num;\n"
-			  "\t\tchars actions[action_num];\n"
-
-			  "\t\tuint32_t step_action_num;\n"
-			  "\t\tchars step_actions[step_action_num];\n"
-
-			  "\t\tchars at_string;\n"
-			  "\t\tchars cond_string;\n"
-
-			  "\t\tuint32_t cmd_num;\n"
-			  "\t\tchars cmd_strings[cmd_num];\n"
-			  "\t};\n"
-			  "};\n", CTF_EVENT_ID_TP_DEF);
-
-  gdb_assert (writer->tcs.content_size == 0);
-  gdb_assert (writer->tcs.packet_start == 0);
-
-  /* Create a new packet to contain this event.  */
-  self->ops->frame_ops->start (self, 0);
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_regblock_type.  Write the type of register event in
-   metadata.  */
-
-static void
-ctf_write_regblock_type (struct trace_file_writer *self, int size)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"register\";\n\tid = %u;\n"
-			   "\tfields := struct { \n"
-			   "\t\tascii contents[%d];\n"
-			   "\t};\n"
-			   "};\n",
-			   CTF_EVENT_ID_REGISTER, size);
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_status.  */
-
-static void
-ctf_write_status (struct trace_file_writer *self,
-		  struct trace_status *ts)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t id;
-
-  ctf_save_write_metadata (&writer->tcs, "\n");
-  ctf_save_write_metadata (&writer->tcs,
-			   "event {\n\tname = \"status\";\n\tid = %u;\n"
-			   "\tfields := struct { \n"
-			   "\t\tint32_t stop_reason;\n"
-			   "\t\tint32_t stopping_tracepoint;\n"
-			   "\t\tint32_t traceframe_count;\n"
-			   "\t\tint32_t traceframes_created;\n"
-			   "\t\tint32_t buffer_free;\n"
-			   "\t\tint32_t buffer_size;\n"
-			   "\t\tint32_t disconnected_tracing;\n"
-			   "\t\tint32_t circular_buffer;\n"
-			   "\t};\n"
-			   "};\n",
-			   CTF_EVENT_ID_STATUS);
-
-  id = CTF_EVENT_ID_STATUS;
-  /* Event Id.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
-
-  ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
-  ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
-  ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
-  ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
-  ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
-  ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
-  ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
-  ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_uploaded_tsv.  */
-
-static void
-ctf_write_uploaded_tsv (struct trace_file_writer *self,
-			struct uploaded_tsv *tsv)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  int32_t int32;
-  int64_t int64;
-  const gdb_byte zero = 0;
-
-  /* Event Id.  */
-  int32 = CTF_EVENT_ID_TSV_DEF;
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
-
-  /* initial_value */
-  int64 = tsv->initial_value;
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
-
-  /* number */
-  ctf_save_write_int32 (&writer->tcs, tsv->number);
-
-  /* builtin */
-  ctf_save_write_int32 (&writer->tcs, tsv->builtin);
-
-  /* name */
-  if (tsv->name != NULL)
-    ctf_save_write (&writer->tcs, (gdb_byte *) tsv->name,
-		    strlen (tsv->name));
-  ctf_save_write (&writer->tcs, &zero, 1);
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_uploaded_tp.  */
-
-static void
-ctf_write_uploaded_tp (struct trace_file_writer *self,
-		       struct uploaded_tp *tp)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  int32_t int32;
-  int64_t int64;
-  uint32_t u32;
-  const gdb_byte zero = 0;
-
-  /* Event Id.  */
-  int32 = CTF_EVENT_ID_TP_DEF;
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
-
-  /* address */
-  int64 = tp->addr;
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
-
-  /* traceframe_usage */
-  int64 = tp->traceframe_usage;
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
-
-  /* number */
-  ctf_save_write_int32 (&writer->tcs, tp->number);
-
-  /* enabled */
-  ctf_save_write_int32 (&writer->tcs, tp->enabled);
-
-  /* step */
-  ctf_save_write_int32 (&writer->tcs, tp->step);
-
-  /* pass */
-  ctf_save_write_int32 (&writer->tcs, tp->pass);
-
-  /* hit_count */
-  ctf_save_write_int32 (&writer->tcs, tp->hit_count);
-
-  /* type */
-  ctf_save_write_int32 (&writer->tcs, tp->type);
-
-  /* condition  */
-  if (tp->cond != NULL)
-    ctf_save_write (&writer->tcs, (gdb_byte *) tp->cond.get (),
-		    strlen (tp->cond.get ()));
-  ctf_save_write (&writer->tcs, &zero, 1);
-
-  /* actions */
-  u32 = tp->actions.size ();
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
-  for (const auto &act : tp->actions)
-    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
-		    strlen (act.get ()) + 1);
-
-  /* step_actions */
-  u32 = tp->step_actions.size ();
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
-  for (const auto &act : tp->step_actions)
-    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
-		    strlen (act.get ()) + 1);
-
-  /* at_string */
-  if (tp->at_string != NULL)
-    ctf_save_write (&writer->tcs, (gdb_byte *) tp->at_string.get (),
-		    strlen (tp->at_string.get ()));
-  ctf_save_write (&writer->tcs, &zero, 1);
-
-  /* cond_string */
-  if (tp->cond_string != NULL)
-    ctf_save_write (&writer->tcs, (gdb_byte *) tp->cond_string.get (),
-		    strlen (tp->cond_string.get ()));
-  ctf_save_write (&writer->tcs, &zero, 1);
-
-  /* cmd_strings */
-  u32 = tp->cmd_strings.size ();
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
-  for (const auto &act : tp->cmd_strings)
-    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
-		    strlen (act.get ()) + 1);
-
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_tdesc.  */
-
-static void
-ctf_write_tdesc (struct trace_file_writer *self)
-{
-  /* Nothing so far. */
-}
-
-/* This is the implementation of trace_file_write_ops method
-   write_definition_end.  */
-
-static void
-ctf_write_definition_end (struct trace_file_writer *self)
-{
-  self->ops->frame_ops->end (self);
-}
-
-/* This is the implementation of trace_file_write_ops method
-   end.  */
-
-static void
-ctf_end (struct trace_file_writer *self)
-{
-  struct ctf_trace_file_writer *writer = (struct ctf_trace_file_writer *) self;
-
-  gdb_assert (writer->tcs.content_size == 0);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   start.  */
-
-static void
-ctf_write_frame_start (struct trace_file_writer *self, uint16_t tpnum)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t id = CTF_EVENT_ID_FRAME;
-  uint32_t u32;
-
-  /* Step 1: Write packet context.  */
-  /* magic.  */
-  u32 = CTF_MAGIC;
-  ctf_save_write_uint32 (&writer->tcs, u32);
-  /* content_size and packet_size..  We still don't know the value,
-     write it later.  */
-  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
-  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
-  /* Tracepoint number.  */
-  ctf_save_write (&writer->tcs, (gdb_byte *) &tpnum, 2);
-
-  /* Step 2: Write event "frame".  */
-  /* Event Id.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   write_r_block.  */
-
-static void
-ctf_write_frame_r_block (struct trace_file_writer *self,
-			 gdb_byte *buf, int32_t size)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t id = CTF_EVENT_ID_REGISTER;
-
-  /* Event Id.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
-
-  /* array contents.  */
-  ctf_save_align_write (&writer->tcs, buf, size, 1);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   write_m_block_header.  */
-
-static void
-ctf_write_frame_m_block_header (struct trace_file_writer *self,
-				uint64_t addr, uint16_t length)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t event_id = CTF_EVENT_ID_MEMORY;
-
-  /* Event Id.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &event_id, 4, 4);
-
-  /* Address.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &addr, 8, 8);
-
-  /* Length.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &length, 2, 2);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   write_m_block_memory.  */
-
-static void
-ctf_write_frame_m_block_memory (struct trace_file_writer *self,
-				gdb_byte *buf, uint16_t length)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-
-  /* Contents.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) buf, length, 1);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   write_v_block.  */
-
-static void
-ctf_write_frame_v_block (struct trace_file_writer *self,
-			 int32_t num, uint64_t val)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t id = CTF_EVENT_ID_TSV;
-
-  /* Event Id.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
-
-  /* val.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &val, 8, 8);
-  /* num.  */
-  ctf_save_align_write (&writer->tcs, (gdb_byte *) &num, 4, 4);
-}
-
-/* This is the implementation of trace_frame_write_ops method
-   end.  */
-
-static void
-ctf_write_frame_end (struct trace_file_writer *self)
-{
-  struct ctf_trace_file_writer *writer
-    = (struct ctf_trace_file_writer *) self;
-  uint32_t u32;
-  uint32_t t;
-
-  /* Write the content size to packet header.  */
-  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + 4,
-		  SEEK_SET);
-  u32 = writer->tcs.content_size * TARGET_CHAR_BIT;
-
-  t = writer->tcs.content_size;
-  ctf_save_write_uint32 (&writer->tcs, u32);
-
-  /* Write the packet size.  */
-  u32 += 4 * TARGET_CHAR_BIT;
-  ctf_save_write_uint32 (&writer->tcs, u32);
-
-  writer->tcs.content_size = t;
-
-  /* Write zero at the end of the packet.  */
-  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + t,
-		  SEEK_SET);
-  u32 = 0;
-  ctf_save_write_uint32 (&writer->tcs, u32);
-  writer->tcs.content_size = t;
-
-  ctf_save_next_packet (&writer->tcs);
-}
-
-/* Operations to write various types of trace frames into CTF
-   format.  */
-
-static const struct trace_frame_write_ops ctf_write_frame_ops =
-{
-  ctf_write_frame_start,
-  ctf_write_frame_r_block,
-  ctf_write_frame_m_block_header,
-  ctf_write_frame_m_block_memory,
-  ctf_write_frame_v_block,
-  ctf_write_frame_end,
-};
-
-/* Operations to write trace buffers into CTF format.  */
-
-static const struct trace_file_write_ops ctf_write_ops =
-{
-  ctf_dtor,
-  ctf_target_save,
-  ctf_start,
-  ctf_write_header,
-  ctf_write_regblock_type,
-  ctf_write_status,
-  ctf_write_uploaded_tsv,
-  ctf_write_uploaded_tp,
-  ctf_write_tdesc,
-  ctf_write_definition_end,
-  NULL,
-  &ctf_write_frame_ops,
-  ctf_end,
-};
-
-/* Return a trace writer for CTF format.  */
-
-struct trace_file_writer *
-ctf_trace_file_writer_new (void)
-{
-  struct ctf_trace_file_writer *writer = XNEW (struct ctf_trace_file_writer);
-
-  writer->base.ops = &ctf_write_ops;
-
-  return (struct trace_file_writer *) writer;
-}
-
-#if HAVE_LIBBABELTRACE
-/* Use libbabeltrace to read CTF data.  The libbabeltrace provides
-   iterator to iterate over each event in CTF data and APIs to get
-   details of event and packet, so it is very convenient to use
-   libbabeltrace to access events in CTF.  */
-
-#include <babeltrace/babeltrace.h>
-#include <babeltrace/ctf/events.h>
-#include <babeltrace/ctf/iterator.h>
-
-/* The struct pointer for current CTF directory.  */
-static int handle_id = -1;
-static struct bt_context *ctx = NULL;
-static struct bt_ctf_iter *ctf_iter = NULL;
-/* The position of the first packet containing trace frame.  */
-static struct bt_iter_pos *start_pos;
-
-/* The name of CTF directory.  */
-static char *trace_dirname;
-
-static ctf_target ctf_ops;
-
-/* Destroy ctf iterator and context.  */
-
-static void
-ctf_destroy (void)
-{
-  if (ctf_iter != NULL)
-    {
-      bt_ctf_iter_destroy (ctf_iter);
-      ctf_iter = NULL;
-    }
-  if (ctx != NULL)
-    {
-      bt_context_put (ctx);
-      ctx = NULL;
-    }
-}
-
-/* Open CTF trace data in DIRNAME.  */
-
-static void
-ctf_open_dir (const char *dirname)
-{
-  struct bt_iter_pos begin_pos;
-  unsigned int count, i;
-  struct bt_ctf_event_decl * const *list;
-
-  ctx = bt_context_create ();
-  if (ctx == NULL)
-    error (_("Unable to create bt_context"));
-  handle_id = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
-  if (handle_id < 0)
-    {
-      ctf_destroy ();
-      error (_("Unable to use libbabeltrace on directory \"%s\""),
-	     dirname);
-    }
-
-  begin_pos.type = BT_SEEK_BEGIN;
-  ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
-  if (ctf_iter == NULL)
-    {
-      ctf_destroy ();
-      error (_("Unable to create bt_iterator"));
-    }
-
-  /* Look for the declaration of register block.  Get the length of
-     array "contents" to set trace_regblock_size.  */
-
-  bt_ctf_get_event_decl_list (handle_id, ctx, &list, &count);
-  for (i = 0; i < count; i++)
-    if (strcmp ("register", bt_ctf_get_decl_event_name (list[i])) == 0)
-      {
-	const struct bt_ctf_field_decl * const *field_list;
-	const struct bt_declaration *decl;
-
-	bt_ctf_get_decl_fields (list[i], BT_EVENT_FIELDS, &field_list,
-				&count);
-
-	gdb_assert (count == 1);
-	gdb_assert (0 == strcmp ("contents",
-				 bt_ctf_get_decl_field_name (field_list[0])));
-	decl = bt_ctf_get_decl_from_field_decl (field_list[0]);
-	trace_regblock_size = bt_ctf_get_array_len (decl);
-
-	break;
-      }
-}
-
-#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD)			\
-  (VAR)->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT),	\
-							   (SCOPE),	\
-							   #FIELD))
-
-#define SET_ENUM_FIELD(EVENT, SCOPE, VAR, TYPE, FIELD)			\
-  (VAR)->FIELD = (TYPE) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT),	\
-							    (SCOPE),	\
-							    #FIELD))
-
-
-/* EVENT is the "status" event and TS is filled in.  */
-
-static void
-ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
-{
-  const struct bt_definition *scope
-    = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
-
-  SET_ENUM_FIELD (event, scope, ts, enum trace_stop_reason, stop_reason);
-  SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
-  SET_INT32_FIELD (event, scope, ts, traceframe_count);
-  SET_INT32_FIELD (event, scope, ts, traceframes_created);
-  SET_INT32_FIELD (event, scope, ts, buffer_free);
-  SET_INT32_FIELD (event, scope, ts, buffer_size);
-  SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
-  SET_INT32_FIELD (event, scope, ts, circular_buffer);
-
-  bt_iter_next (bt_ctf_get_iter (ctf_iter));
-}
-
-/* Read the events "tsv_def" one by one, extract its contents and fill
-   in the list UPLOADED_TSVS.  */
-
-static void
-ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
-{
-  gdb_assert (ctf_iter != NULL);
-
-  while (1)
-    {
-      struct bt_ctf_event *event;
-      const struct bt_definition *scope;
-      const struct bt_definition *def;
-      uint32_t event_id;
-      struct uploaded_tsv *utsv = NULL;
-
-      event = bt_ctf_iter_read_event (ctf_iter);
-      scope = bt_ctf_get_top_level_scope (event,
-					  BT_STREAM_EVENT_HEADER);
-      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
-						      "id"));
-      if (event_id != CTF_EVENT_ID_TSV_DEF)
-	break;
-
-      scope = bt_ctf_get_top_level_scope (event,
-					  BT_EVENT_FIELDS);
-
-      def = bt_ctf_get_field (event, scope, "number");
-      utsv = get_uploaded_tsv ((int32_t) bt_ctf_get_int64 (def),
-			       uploaded_tsvs);
-
-      def = bt_ctf_get_field (event, scope, "builtin");
-      utsv->builtin = (int32_t) bt_ctf_get_int64 (def);
-      def = bt_ctf_get_field (event, scope, "initial_value");
-      utsv->initial_value = bt_ctf_get_int64 (def);
-
-      def = bt_ctf_get_field (event, scope, "name");
-      utsv->name =  xstrdup (bt_ctf_get_string (def));
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-
-}
-
-/* Read the value of element whose index is NUM from CTF and write it
-   to the corresponding VAR->ARRAY. */
-
-#define SET_ARRAY_FIELD(EVENT, SCOPE, VAR, NUM, ARRAY)	\
-  do							\
-    {							\
-      uint32_t lu32, i;						\
-      const struct bt_definition *def;				\
-								\
-      lu32 = (uint32_t) bt_ctf_get_uint64 (bt_ctf_get_field ((EVENT),	\
-							     (SCOPE),	\
-							     #NUM));	\
-      def = bt_ctf_get_field ((EVENT), (SCOPE), #ARRAY);		\
-      for (i = 0; i < lu32; i++)					\
-	{								\
-	  const struct bt_definition *element				\
-	    = bt_ctf_get_index ((EVENT), def, i);			\
-									\
-	  (VAR)->ARRAY.emplace_back					\
-	    (xstrdup (bt_ctf_get_string (element)));			\
-	}								\
-    }									\
-  while (0)
-
-/* Read a string from CTF and set VAR->FIELD. If the length of string
-   is zero, set VAR->FIELD to NULL.  */
-
-#define SET_STRING_FIELD(EVENT, SCOPE, VAR, FIELD)			\
-  do									\
-    {									\
-      const char *p = bt_ctf_get_string (bt_ctf_get_field ((EVENT),	\
-							   (SCOPE),	\
-							   #FIELD));	\
-									\
-      if (strlen (p) > 0)						\
-	(VAR)->FIELD.reset (xstrdup (p));				\
-      else								\
-	(VAR)->FIELD = NULL;						\
-    }									\
-  while (0)
-
-/* Read the events "tp_def" one by one, extract its contents and fill
-   in the list UPLOADED_TPS.  */
-
-static void
-ctf_read_tp (struct uploaded_tp **uploaded_tps)
-{
-  gdb_assert (ctf_iter != NULL);
-
-  while (1)
-    {
-      struct bt_ctf_event *event;
-      const struct bt_definition *scope;
-      uint32_t u32;
-      int32_t int32;
-      uint64_t u64;
-      struct uploaded_tp *utp = NULL;
-
-      event = bt_ctf_iter_read_event (ctf_iter);
-      scope = bt_ctf_get_top_level_scope (event,
-					  BT_STREAM_EVENT_HEADER);
-      u32 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
-						 "id"));
-      if (u32 != CTF_EVENT_ID_TP_DEF)
-	break;
-
-      scope = bt_ctf_get_top_level_scope (event,
-					  BT_EVENT_FIELDS);
-      int32 = (int32_t) bt_ctf_get_int64 (bt_ctf_get_field (event,
-							    scope,
-							    "number"));
-      u64 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
-						 "addr"));
-      utp = get_uploaded_tp (int32, u64,  uploaded_tps);
-
-      SET_INT32_FIELD (event, scope, utp, enabled);
-      SET_INT32_FIELD (event, scope, utp, step);
-      SET_INT32_FIELD (event, scope, utp, pass);
-      SET_INT32_FIELD (event, scope, utp, hit_count);
-      SET_ENUM_FIELD (event, scope, utp, enum bptype, type);
-
-      /* Read 'cmd_strings'.  */
-      SET_ARRAY_FIELD (event, scope, utp, cmd_num, cmd_strings);
-      /* Read 'actions'.  */
-      SET_ARRAY_FIELD (event, scope, utp, action_num, actions);
-      /* Read 'step_actions'.  */
-      SET_ARRAY_FIELD (event, scope, utp, step_action_num,
-		       step_actions);
-
-      SET_STRING_FIELD(event, scope, utp, at_string);
-      SET_STRING_FIELD(event, scope, utp, cond_string);
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-}
-
-/* This is the implementation of target_ops method to_open.  Open CTF
-   trace data, read trace status, trace state variables and tracepoint
-   definitions from the first packet.  Set the start position at the
-   second packet which contains events on trace blocks.  */
-
-static void
-ctf_target_open (const char *dirname, int from_tty)
-{
-  struct bt_ctf_event *event;
-  uint32_t event_id;
-  const struct bt_definition *scope;
-  struct uploaded_tsv *uploaded_tsvs = NULL;
-  struct uploaded_tp *uploaded_tps = NULL;
-
-  if (!dirname)
-    error (_("No CTF directory specified."));
-
-  ctf_open_dir (dirname);
-
-  target_preopen (from_tty);
-
-  /* Skip the first packet which about the trace status.  The first
-     event is "frame".  */
-  event = bt_ctf_iter_read_event (ctf_iter);
-  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
-  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
-  if (event_id != CTF_EVENT_ID_FRAME)
-    error (_("Wrong event id of the first event"));
-  /* The second event is "status".  */
-  bt_iter_next (bt_ctf_get_iter (ctf_iter));
-  event = bt_ctf_iter_read_event (ctf_iter);
-  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
-  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
-  if (event_id != CTF_EVENT_ID_STATUS)
-    error (_("Wrong event id of the second event"));
-  ctf_read_status (event, current_trace_status ());
-
-  ctf_read_tsv (&uploaded_tsvs);
-
-  ctf_read_tp (&uploaded_tps);
-
-  event = bt_ctf_iter_read_event (ctf_iter);
-  /* EVENT can be NULL if we've already gone to the end of stream of
-     events.  */
-  if (event != NULL)
-    {
-      scope = bt_ctf_get_top_level_scope (event,
-					  BT_STREAM_EVENT_HEADER);
-      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event,
-						      scope, "id"));
-      if (event_id != CTF_EVENT_ID_FRAME)
-	error (_("Wrong event id of the first event of the second packet"));
-    }
-
-  start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-  gdb_assert (start_pos->type == BT_SEEK_RESTORE);
-
-  trace_dirname = xstrdup (dirname);
-  push_target (&ctf_ops);
-
-  inferior_appeared (current_inferior (), CTF_PID);
-  inferior_ptid = ptid_t (CTF_PID);
-  add_thread_silent (inferior_ptid);
-
-  merge_uploaded_trace_state_variables (&uploaded_tsvs);
-  merge_uploaded_tracepoints (&uploaded_tps);
-
-  post_create_inferior (&ctf_ops, from_tty);
-}
-
-/* This is the implementation of target_ops method to_close.  Destroy
-   CTF iterator and context.  */
-
-void
-ctf_target::close ()
-{
-  ctf_destroy ();
-  xfree (trace_dirname);
-  trace_dirname = NULL;
-
-  inferior_ptid = null_ptid;	/* Avoid confusion from thread stuff.  */
-  exit_inferior_silent (current_inferior ());
-
-  trace_reset_local_state ();
-}
-
-/* This is the implementation of target_ops method to_files_info.
-   Print the directory name of CTF trace data.  */
-
-void
-ctf_target::files_info ()
-{
-  printf_filtered ("\t`%s'\n", trace_dirname);
-}
-
-/* This is the implementation of target_ops method to_fetch_registers.
-   Iterate over events whose name is "register" in current frame,
-   extract contents from events, and set REGCACHE with the contents.
-   If no matched events are found, mark registers unavailable.  */
-
-void
-ctf_target::fetch_registers (struct regcache *regcache, int regno)
-{
-  struct gdbarch *gdbarch = regcache->arch ();
-  struct bt_ctf_event *event = NULL;
-  struct bt_iter_pos *pos;
-
-  /* An uninitialized reg size says we're not going to be
-     successful at getting register blocks.  */
-  if (trace_regblock_size == 0)
-    return;
-
-  gdb_assert (ctf_iter != NULL);
-  /* Save the current position.  */
-  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-  gdb_assert (pos->type == BT_SEEK_RESTORE);
-
-  while (1)
-    {
-      const char *name;
-      struct bt_ctf_event *event1;
-
-      event1 = bt_ctf_iter_read_event (ctf_iter);
-
-      name = bt_ctf_event_name (event1);
-
-      if (name == NULL || strcmp (name, "frame") == 0)
-	break;
-      else if (strcmp (name, "register") == 0)
-	{
-	  event = event1;
-	  break;
-	}
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-
-  /* Restore the position.  */
-  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-  if (event != NULL)
-    {
-      int offset, regsize, regn;
-      const struct bt_definition *scope
-	= bt_ctf_get_top_level_scope (event,
-				      BT_EVENT_FIELDS);
-      const struct bt_definition *array
-	= bt_ctf_get_field (event, scope, "contents");
-      gdb_byte *regs = (gdb_byte *) bt_ctf_get_char_array (array);
-
-      /* Assume the block is laid out in GDB register number order,
-	 each register with the size that it has in GDB.  */
-      offset = 0;
-      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
-	{
-	  regsize = register_size (gdbarch, regn);
-	  /* Make sure we stay within block bounds.  */
-	  if (offset + regsize >= trace_regblock_size)
-	    break;
-	  if (regcache->get_register_status (regn) == REG_UNKNOWN)
-	    {
-	      if (regno == regn)
-		{
-		  regcache->raw_supply (regno, regs + offset);
-		  break;
-		}
-	      else if (regno == -1)
-		{
-		  regcache->raw_supply (regn, regs + offset);
-		}
-	    }
-	  offset += regsize;
-	}
-    }
-  else
-    tracefile_fetch_registers (regcache, regno);
-}
-
-/* This is the implementation of target_ops method to_xfer_partial.
-   Iterate over events whose name is "memory" in
-   current frame, extract the address and length from events.  If
-   OFFSET is within the range, read the contents from events to
-   READBUF.  */
-
-enum target_xfer_status
-ctf_target::xfer_partial (enum target_object object,
-			  const char *annex, gdb_byte *readbuf,
-			  const gdb_byte *writebuf, ULONGEST offset,
-			  ULONGEST len, ULONGEST *xfered_len)
-{
-  /* We're only doing regular memory for now.  */
-  if (object != TARGET_OBJECT_MEMORY)
-    return TARGET_XFER_E_IO;
-
-  if (readbuf == NULL)
-    error (_("ctf_xfer_partial: trace file is read-only"));
-
-  if (get_traceframe_number () != -1)
-    {
-      struct bt_iter_pos *pos;
-      enum target_xfer_status res;
-      /* Records the lowest available address of all blocks that
-	 intersects the requested range.  */
-      ULONGEST low_addr_available = 0;
-
-      gdb_assert (ctf_iter != NULL);
-      /* Save the current position.  */
-      pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-      gdb_assert (pos->type == BT_SEEK_RESTORE);
-
-      /* Iterate through the traceframe's blocks, looking for
-	 memory.  */
-      while (1)
-	{
-	  ULONGEST amt;
-	  uint64_t maddr;
-	  uint16_t mlen;
-	  const struct bt_definition *scope;
-	  const struct bt_definition *def;
-	  struct bt_ctf_event *event
-	    = bt_ctf_iter_read_event (ctf_iter);
-	  const char *name = bt_ctf_event_name (event);
-
-	  if (name == NULL || strcmp (name, "frame") == 0)
-	    break;
-	  else if (strcmp (name, "memory") != 0)
-	    {
-	      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-		break;
-
-	      continue;
-	    }
-
-	  scope = bt_ctf_get_top_level_scope (event,
-					      BT_EVENT_FIELDS);
-
-	  def = bt_ctf_get_field (event, scope, "address");
-	  maddr = bt_ctf_get_uint64 (def);
-	  def = bt_ctf_get_field (event, scope, "length");
-	  mlen = (uint16_t) bt_ctf_get_uint64 (def);
-
-	  /* If the block includes the first part of the desired
-	     range, return as much it has; GDB will re-request the
-	     remainder, which might be in a different block of this
-	     trace frame.  */
-	  if (maddr <= offset && offset < (maddr + mlen))
-	    {
-	      const struct bt_definition *array
-		= bt_ctf_get_field (event, scope, "contents");
-	      gdb_byte *contents;
-	      int k;
-
-	      contents = (gdb_byte *) xmalloc (mlen);
-
-	      for (k = 0; k < mlen; k++)
-		{
-		  const struct bt_definition *element
-		    = bt_ctf_get_index (event, array, k);
-
-		  contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
-		}
-
-	      amt = (maddr + mlen) - offset;
-	      if (amt > len)
-		amt = len;
-
-	      memcpy (readbuf, &contents[offset - maddr], amt);
-
-	      xfree (contents);
-
-	      /* Restore the position.  */
-	      bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-	      if (amt == 0)
-		return TARGET_XFER_EOF;
-	      else
-		{
-		  *xfered_len = amt;
-		  return TARGET_XFER_OK;
-		}
-	    }
-
-	  if (offset < maddr && maddr < (offset + len))
-	    if (low_addr_available == 0 || low_addr_available > maddr)
-	      low_addr_available = maddr;
-
-	  if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	    break;
-	}
-
-      /* Restore the position.  */
-      bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-      /* Requested memory is unavailable in the context of traceframes,
-	 and this address falls within a read-only section, fallback
-	 to reading from executable, up to LOW_ADDR_AVAILABLE  */
-      if (offset < low_addr_available)
-	len = std::min (len, low_addr_available - offset);
-      res = exec_read_partial_read_only (readbuf, offset, len, xfered_len);
-
-      if (res == TARGET_XFER_OK)
-	return TARGET_XFER_OK;
-      else
-	{
-	  /* No use trying further, we know some memory starting
-	     at MEMADDR isn't available.  */
-	  *xfered_len = len;
-	  return TARGET_XFER_UNAVAILABLE;
-	}
-    }
-  else
-    {
-      /* Fallback to reading from read-only sections.  */
-      return section_table_read_available_memory (readbuf, offset, len, xfered_len);
-    }
-}
-
-/* This is the implementation of target_ops method
-   to_get_trace_state_variable_value.
-   Iterate over events whose name is "tsv" in current frame.  When the
-   trace variable is found, set the value of it to *VAL and return
-   true, otherwise return false.  */
-
-bool
-ctf_target::get_trace_state_variable_value (int tsvnum, LONGEST *val)
-{
-  struct bt_iter_pos *pos;
-  bool found = false;
-
-  gdb_assert (ctf_iter != NULL);
-  /* Save the current position.  */
-  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-  gdb_assert (pos->type == BT_SEEK_RESTORE);
-
-  /* Iterate through the traceframe's blocks, looking for 'V'
-     block.  */
-  while (1)
-    {
-      struct bt_ctf_event *event
-	= bt_ctf_iter_read_event (ctf_iter);
-      const char *name = bt_ctf_event_name (event);
-
-      if (name == NULL || strcmp (name, "frame") == 0)
-	break;
-      else if (strcmp (name, "tsv") == 0)
-	{
-	  const struct bt_definition *scope;
-	  const struct bt_definition *def;
-
-	  scope = bt_ctf_get_top_level_scope (event,
-					      BT_EVENT_FIELDS);
-
-	  def = bt_ctf_get_field (event, scope, "num");
-	  if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
-	    {
-	      def = bt_ctf_get_field (event, scope, "val");
-	      *val = bt_ctf_get_uint64 (def);
-
-	      found = true;
-	    }
-	}
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-
-  /* Restore the position.  */
-  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-  return found;
-}
-
-/* Return the tracepoint number in "frame" event.  */
-
-static int
-ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
-{
-  /* The packet context of events has a field "tpnum".  */
-  const struct bt_definition *scope
-    = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
-  uint64_t tpnum
-    = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
-
-  return (int) tpnum;
-}
-
-/* Return the address at which the current frame was collected.  */
-
-static CORE_ADDR
-ctf_get_traceframe_address (void)
-{
-  struct bt_ctf_event *event = NULL;
-  struct bt_iter_pos *pos;
-  CORE_ADDR addr = 0;
-
-  gdb_assert (ctf_iter != NULL);
-  pos  = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-  gdb_assert (pos->type == BT_SEEK_RESTORE);
-
-  while (1)
-    {
-      const char *name;
-      struct bt_ctf_event *event1;
-
-      event1 = bt_ctf_iter_read_event (ctf_iter);
-
-      name = bt_ctf_event_name (event1);
-
-      if (name == NULL)
-	break;
-      else if (strcmp (name, "frame") == 0)
-	{
-	  event = event1;
-	  break;
-	}
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-
-  if (event != NULL)
-    {
-      int tpnum = ctf_get_tpnum_from_frame_event (event);
-      struct tracepoint *tp
-	= get_tracepoint_by_number_on_target (tpnum);
-
-      if (tp && tp->loc)
-	addr = tp->loc->address;
-    }
-
-  /* Restore the position.  */
-  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-  return addr;
-}
-
-/* This is the implementation of target_ops method to_trace_find.
-   Iterate the events whose name is "frame", extract the tracepoint
-   number in it.  Return traceframe number when matched.  */
-
-int
-ctf_target::trace_find (enum trace_find_type type, int num,
-			CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
-{
-  int tfnum = 0;
-  int found = 0;
-
-  if (num == -1)
-    {
-      if (tpp != NULL)
-	*tpp = -1;
-      return -1;
-    }
-
-  gdb_assert (ctf_iter != NULL);
-  /* Set iterator back to the start.  */
-  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
-
-  while (1)
-    {
-      struct bt_ctf_event *event;
-      const char *name;
-
-      event = bt_ctf_iter_read_event (ctf_iter);
-
-      name = bt_ctf_event_name (event);
-
-      if (event == NULL || name == NULL)
-	break;
-
-      if (strcmp (name, "frame") == 0)
-	{
-	  CORE_ADDR tfaddr;
-
-	  if (type == tfind_number)
-	    {
-	      /* Looking for a specific trace frame.  */
-	      if (tfnum == num)
-		found = 1;
-	    }
-	  else
-	    {
-	      /* Start from the _next_ trace frame.  */
-	      if (tfnum > get_traceframe_number ())
-		{
-		  switch (type)
-		    {
-		    case tfind_tp:
-		      {
-			struct tracepoint *tp = get_tracepoint (num);
-
-			if (tp != NULL
-			    && (tp->number_on_target
-				== ctf_get_tpnum_from_frame_event (event)))
-			  found = 1;
-			break;
-		      }
-		    case tfind_pc:
-		      tfaddr = ctf_get_traceframe_address ();
-		      if (tfaddr == addr1)
-			found = 1;
-		      break;
-		    case tfind_range:
-		      tfaddr = ctf_get_traceframe_address ();
-		      if (addr1 <= tfaddr && tfaddr <= addr2)
-			found = 1;
-		      break;
-		    case tfind_outside:
-		      tfaddr = ctf_get_traceframe_address ();
-		      if (!(addr1 <= tfaddr && tfaddr <= addr2))
-			found = 1;
-		      break;
-		    default:
-		      internal_error (__FILE__, __LINE__, _("unknown tfind type"));
-		    }
-		}
-	    }
-	  if (found)
-	    {
-	      if (tpp != NULL)
-		*tpp = ctf_get_tpnum_from_frame_event (event);
-
-	      /* Skip the event "frame".  */
-	      bt_iter_next (bt_ctf_get_iter (ctf_iter));
-
-	      return tfnum;
-	    }
-	  tfnum++;
-	}
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-
-  return -1;
-}
-
-/* This is the implementation of target_ops method to_traceframe_info.
-   Iterate the events whose name is "memory", in current
-   frame, extract memory range information, and return them in
-   traceframe_info.  */
-
-traceframe_info_up
-ctf_target::traceframe_info ()
-{
-  traceframe_info_up info (new struct traceframe_info);
-  const char *name;
-  struct bt_iter_pos *pos;
-
-  gdb_assert (ctf_iter != NULL);
-  /* Save the current position.  */
-  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
-  gdb_assert (pos->type == BT_SEEK_RESTORE);
-
-  do
-    {
-      struct bt_ctf_event *event
-	= bt_ctf_iter_read_event (ctf_iter);
-
-      name = bt_ctf_event_name (event);
-
-      if (name == NULL || strcmp (name, "register") == 0
-	  || strcmp (name, "frame") == 0)
-	;
-      else if (strcmp (name, "memory") == 0)
-	{
-	  const struct bt_definition *scope
-	    = bt_ctf_get_top_level_scope (event,
-					  BT_EVENT_FIELDS);
-	  const struct bt_definition *def;
-
-	  def = bt_ctf_get_field (event, scope, "address");
-	  CORE_ADDR start = bt_ctf_get_uint64 (def);
-
-	  def = bt_ctf_get_field (event, scope, "length");
-	  int length = (uint16_t) bt_ctf_get_uint64 (def);
-
-	  info->memory.emplace_back (start, length);
-	}
-      else if (strcmp (name, "tsv") == 0)
-	{
-	  int vnum;
-	  const struct bt_definition *scope
-	    = bt_ctf_get_top_level_scope (event,
-					  BT_EVENT_FIELDS);
-	  const struct bt_definition *def;
-
-	  def = bt_ctf_get_field (event, scope, "num");
-	  vnum = (int) bt_ctf_get_uint64 (def);
-	  info->tvars.push_back (vnum);
-	}
-      else
-	{
-	  warning (_("Unhandled trace block type (%s) "
-		     "while building trace frame info."),
-		   name);
-	}
-
-      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
-	break;
-    }
-  while (name != NULL && strcmp (name, "frame") != 0);
-
-  /* Restore the position.  */
-  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
-
-  return info;
-}
-
-#endif
-
-/* module initialization */
-
-void
-_initialize_ctf (void)
-{
-#if HAVE_LIBBABELTRACE
-  add_target (ctf_target_info, ctf_target_open, filename_completer);
-#endif
-}
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 2ece360..9a0b7f9 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -46,7 +46,6 @@
 #include "osdata.h"
 #include "gdbsupport/gdb_splay_tree.h"
 #include "tracepoint.h"
-#include "ctf.h"
 #include "ada-lang.h"
 #include "linespec.h"
 #include "extension.h"
diff --git a/gdb/tracectf.c b/gdb/tracectf.c
new file mode 100644
index 0000000..758dd56
--- /dev/null
+++ b/gdb/tracectf.c
@@ -0,0 +1,1730 @@
+/* CTF format support.
+
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
+   Contributed by Hui Zhu <hui_zhu@mentor.com>
+   Contributed by Yao Qi <yao@codesourcery.com>
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "tracectf.h"
+#include "tracepoint.h"
+#include "regcache.h"
+#include <sys/stat.h>
+#include "exec.h"
+#include "completer.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "tracefile.h"
+#include <ctype.h>
+#include <algorithm>
+#include "gdbsupport/filestuff.h"
+#include "gdbarch.h"
+
+/* The CTF target.  */
+
+static const target_info ctf_target_info = {
+  "ctf",
+  N_("CTF file"),
+  N_("(Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.")
+};
+
+class ctf_target final : public tracefile_target
+{
+public:
+  const target_info &info () const override
+  { return ctf_target_info; }
+
+  void close () override;
+  void fetch_registers (struct regcache *, int) override;
+  enum target_xfer_status xfer_partial (enum target_object object,
+						const char *annex,
+						gdb_byte *readbuf,
+						const gdb_byte *writebuf,
+						ULONGEST offset, ULONGEST len,
+						ULONGEST *xfered_len) override;
+  void files_info () override;
+  int trace_find (enum trace_find_type type, int num,
+			  CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override;
+  bool get_trace_state_variable_value (int tsv, LONGEST *val) override;
+  traceframe_info_up traceframe_info () override;
+};
+
+/* GDB saves trace buffers and other information (such as trace
+   status) got from the remote target into Common Trace Format (CTF).
+   The following types of information are expected to save in CTF:
+
+   1. The length (in bytes) of register cache.  Event "register" will
+   be defined in metadata, which includes the length.
+
+   2. Trace status.  Event "status" is defined in metadata, which
+   includes all aspects of trace status.
+
+   3. Uploaded trace variables.  Event "tsv_def" is defined in
+   metadata, which is about all aspects of a uploaded trace variable.
+   Uploaded tracepoints.   Event "tp_def" is defined in meta, which
+   is about all aspects of an uploaded tracepoint.  Note that the
+   "sequence" (a CTF type, which is a dynamically-sized array.) is
+   used for "actions" "step_actions" and "cmd_strings".
+
+   4. Trace frames.  Each trace frame is composed by several blocks
+   of different types ('R', 'M', 'V').  One trace frame is saved in
+   one CTF packet and the blocks of this frame are saved as events.
+   4.1: The trace frame related information (such as the number of
+   tracepoint associated with this frame) is saved in the packet
+   context.
+   4.2: The block 'M', 'R' and 'V' are saved in event "memory",
+   "register" and "tsv" respectively.
+   4.3: When iterating over events, babeltrace can't tell iterator
+   goes to a new packet, so we need a marker or anchor to tell GDB
+   that iterator goes into a new packet or frame.  We define event
+   "frame".  */
+
+#define CTF_MAGIC		0xC1FC1FC1
+#define CTF_SAVE_MAJOR		1
+#define CTF_SAVE_MINOR		8
+
+#define CTF_METADATA_NAME	"metadata"
+#define CTF_DATASTREAM_NAME	"datastream"
+
+/* Reserved event id.  */
+
+#define CTF_EVENT_ID_REGISTER 0
+#define CTF_EVENT_ID_TSV 1
+#define CTF_EVENT_ID_MEMORY 2
+#define CTF_EVENT_ID_FRAME 3
+#define CTF_EVENT_ID_STATUS 4
+#define CTF_EVENT_ID_TSV_DEF 5
+#define CTF_EVENT_ID_TP_DEF 6
+
+#define CTF_PID (2)
+
+/* The state kept while writing the CTF datastream file.  */
+
+struct trace_write_handler
+{
+  /* File descriptor of metadata.  */
+  FILE *metadata_fd;
+  /* File descriptor of traceframes.  */
+  FILE *datastream_fd;
+
+  /* This is the content size of the current packet.  */
+  size_t content_size;
+
+  /* This is the start offset of current packet.  */
+  long packet_start;
+};
+
+/* Write metadata in FORMAT.  */
+
+static void
+ctf_save_write_metadata (struct trace_write_handler *handler,
+			 const char *format, ...)
+  ATTRIBUTE_PRINTF (2, 3);
+
+static void
+ctf_save_write_metadata (struct trace_write_handler *handler,
+			 const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  if (vfprintf (handler->metadata_fd, format, args) < 0)
+    error (_("Unable to write metadata file (%s)"),
+	     safe_strerror (errno));
+  va_end (args);
+}
+
+/* Write BUF of length SIZE to datastream file represented by
+   HANDLER.  */
+
+static int
+ctf_save_write (struct trace_write_handler *handler,
+		const gdb_byte *buf, size_t size)
+{
+  if (fwrite (buf, size, 1, handler->datastream_fd) != 1)
+    error (_("Unable to write file for saving trace data (%s)"),
+	   safe_strerror (errno));
+
+  handler->content_size += size;
+
+  return 0;
+}
+
+/* Write a unsigned 32-bit integer to datastream file represented by
+   HANDLER.  */
+
+#define ctf_save_write_uint32(HANDLER, U32) \
+  ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+
+/* Write a signed 32-bit integer to datastream file represented by
+   HANDLER.  */
+
+#define ctf_save_write_int32(HANDLER, INT32) \
+  ctf_save_write ((HANDLER), (gdb_byte *) &(INT32), 4)
+
+/* Set datastream file position.  Update HANDLER->content_size
+   if WHENCE is SEEK_CUR.  */
+
+static int
+ctf_save_fseek (struct trace_write_handler *handler, long offset,
+		int whence)
+{
+  gdb_assert (whence != SEEK_END);
+  gdb_assert (whence != SEEK_SET
+	      || offset <= handler->content_size + handler->packet_start);
+
+  if (fseek (handler->datastream_fd, offset, whence))
+    error (_("Unable to seek file for saving trace data (%s)"),
+	   safe_strerror (errno));
+
+  if (whence == SEEK_CUR)
+    handler->content_size += offset;
+
+  return 0;
+}
+
+/* Change the datastream file position to align on ALIGN_SIZE,
+   and write BUF to datastream file.  The size of BUF is SIZE.  */
+
+static int
+ctf_save_align_write (struct trace_write_handler *handler,
+		      const gdb_byte *buf,
+		      size_t size, size_t align_size)
+{
+  long offset
+    = (align_up (handler->content_size, align_size)
+       - handler->content_size);
+
+  if (ctf_save_fseek (handler, offset, SEEK_CUR))
+    return -1;
+
+  if (ctf_save_write (handler, buf, size))
+    return -1;
+
+  return 0;
+}
+
+/* Write events to next new packet.  */
+
+static void
+ctf_save_next_packet (struct trace_write_handler *handler)
+{
+  handler->packet_start += (handler->content_size + 4);
+  ctf_save_fseek (handler, handler->packet_start, SEEK_SET);
+  handler->content_size = 0;
+}
+
+/* Write the CTF metadata header.  */
+
+static void
+ctf_save_metadata_header (struct trace_write_handler *handler)
+{
+  ctf_save_write_metadata (handler, "/* CTF %d.%d */\n",
+			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 8; align = 8; "
+			   "signed = false; encoding = ascii;}"
+			   " := ascii;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 8; align = 8; "
+			   "signed = false; }"
+			   " := uint8_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 16; align = 16;"
+			   "signed = false; } := uint16_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 32; align = 32;"
+			   "signed = false; } := uint32_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 64; align = 64;"
+			   "signed = false; base = hex;}"
+			   " := uint64_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 32; align = 32;"
+			   "signed = true; } := int32_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 64; align = 64;"
+			   "signed = true; } := int64_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias string { encoding = ascii;"
+			   " } := chars;\n");
+  ctf_save_write_metadata (handler, "\n");
+
+  /* Get the byte order of the host and write CTF data in this byte
+     order.  */
+#if WORDS_BIGENDIAN
+#define HOST_ENDIANNESS "be"
+#else
+#define HOST_ENDIANNESS "le"
+#endif
+
+  ctf_save_write_metadata (handler,
+			   "\ntrace {\n"
+			   "	major = %u;\n"
+			   "	minor = %u;\n"
+			   "	byte_order = %s;\n"
+			   "	packet.header := struct {\n"
+			   "		uint32_t magic;\n"
+			   "	};\n"
+			   "};\n"
+			   "\n"
+			   "stream {\n"
+			   "	packet.context := struct {\n"
+			   "		uint32_t content_size;\n"
+			   "		uint32_t packet_size;\n"
+			   "		uint16_t tpnum;\n"
+			   "	};\n"
+			   "	event.header := struct {\n"
+			   "		uint32_t id;\n"
+			   "	};\n"
+			   "};\n",
+			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
+			   HOST_ENDIANNESS);
+  ctf_save_write_metadata (handler, "\n");
+}
+
+/* CTF trace writer.  */
+
+struct ctf_trace_file_writer
+{
+  struct trace_file_writer base;
+
+  /* States related to writing CTF trace file.  */
+  struct trace_write_handler tcs;
+};
+
+/* This is the implementation of trace_file_write_ops method
+   dtor.  */
+
+static void
+ctf_dtor (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  if (writer->tcs.metadata_fd != NULL)
+    fclose (writer->tcs.metadata_fd);
+
+  if (writer->tcs.datastream_fd != NULL)
+    fclose (writer->tcs.datastream_fd);
+
+}
+
+/* This is the implementation of trace_file_write_ops method
+   target_save.  */
+
+static int
+ctf_target_save (struct trace_file_writer *self,
+		 const char *dirname)
+{
+  /* Don't support save trace file to CTF format in the target.  */
+  return 0;
+}
+
+/* This is the implementation of trace_file_write_ops method
+   start.  It creates the directory DIRNAME, metadata and datastream
+   in the directory.  */
+
+static void
+ctf_start (struct trace_file_writer *self, const char *dirname)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  mode_t hmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH;
+
+  /* Create DIRNAME.  */
+  if (mkdir (dirname, hmode) && errno != EEXIST)
+    error (_("Unable to open directory '%s' for saving trace data (%s)"),
+	   dirname, safe_strerror (errno));
+
+  memset (&writer->tcs, '\0', sizeof (writer->tcs));
+
+  std::string file_name = string_printf ("%s/%s", dirname, CTF_METADATA_NAME);
+
+  writer->tcs.metadata_fd
+    = gdb_fopen_cloexec (file_name.c_str (), "w").release ();
+  if (writer->tcs.metadata_fd == NULL)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name.c_str (), safe_strerror (errno));
+
+  ctf_save_metadata_header (&writer->tcs);
+
+  file_name = string_printf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
+  writer->tcs.datastream_fd
+    = gdb_fopen_cloexec (file_name.c_str (), "w").release ();
+  if (writer->tcs.datastream_fd == NULL)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name.c_str (), safe_strerror (errno));
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_header.  Write the types of events on trace variable and
+   frame.  */
+
+static void
+ctf_write_header (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"memory\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tuint64_t address;\n"
+			   "\t\tuint16_t length;\n"
+			   "\t\tuint8_t contents[length];\n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_MEMORY);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"tsv\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tuint64_t val;\n"
+			   "\t\tuint32_t num;\n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_TSV);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"frame\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_FRAME);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			  "event {\n\tname = \"tsv_def\";\n"
+			  "\tid = %u;\n\tfields := struct { \n"
+			  "\t\tint64_t initial_value;\n"
+			  "\t\tint32_t number;\n"
+			  "\t\tint32_t builtin;\n"
+			  "\t\tchars name;\n"
+			  "\t};\n"
+			  "};\n", CTF_EVENT_ID_TSV_DEF);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"tp_def\";\n"
+			   "\tid = %u;\n\tfields := struct { \n"
+			   "\t\tuint64_t addr;\n"
+			   "\t\tuint64_t traceframe_usage;\n"
+			   "\t\tint32_t number;\n"
+			   "\t\tint32_t enabled;\n"
+			   "\t\tint32_t step;\n"
+			   "\t\tint32_t pass;\n"
+			   "\t\tint32_t hit_count;\n"
+			   "\t\tint32_t type;\n"
+			   "\t\tchars cond;\n"
+
+			  "\t\tuint32_t action_num;\n"
+			  "\t\tchars actions[action_num];\n"
+
+			  "\t\tuint32_t step_action_num;\n"
+			  "\t\tchars step_actions[step_action_num];\n"
+
+			  "\t\tchars at_string;\n"
+			  "\t\tchars cond_string;\n"
+
+			  "\t\tuint32_t cmd_num;\n"
+			  "\t\tchars cmd_strings[cmd_num];\n"
+			  "\t};\n"
+			  "};\n", CTF_EVENT_ID_TP_DEF);
+
+  gdb_assert (writer->tcs.content_size == 0);
+  gdb_assert (writer->tcs.packet_start == 0);
+
+  /* Create a new packet to contain this event.  */
+  self->ops->frame_ops->start (self, 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_regblock_type.  Write the type of register event in
+   metadata.  */
+
+static void
+ctf_write_regblock_type (struct trace_file_writer *self, int size)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"register\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tascii contents[%d];\n"
+			   "\t};\n"
+			   "};\n",
+			   CTF_EVENT_ID_REGISTER, size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_status.  */
+
+static void
+ctf_write_status (struct trace_file_writer *self,
+		  struct trace_status *ts)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id;
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"status\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tint32_t stop_reason;\n"
+			   "\t\tint32_t stopping_tracepoint;\n"
+			   "\t\tint32_t traceframe_count;\n"
+			   "\t\tint32_t traceframes_created;\n"
+			   "\t\tint32_t buffer_free;\n"
+			   "\t\tint32_t buffer_size;\n"
+			   "\t\tint32_t disconnected_tracing;\n"
+			   "\t\tint32_t circular_buffer;\n"
+			   "\t};\n"
+			   "};\n",
+			   CTF_EVENT_ID_STATUS);
+
+  id = CTF_EVENT_ID_STATUS;
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
+  ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
+  ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
+  ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
+  ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
+  ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
+  ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
+  ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_uploaded_tsv.  */
+
+static void
+ctf_write_uploaded_tsv (struct trace_file_writer *self,
+			struct uploaded_tsv *tsv)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  int32_t int32;
+  int64_t int64;
+  const gdb_byte zero = 0;
+
+  /* Event Id.  */
+  int32 = CTF_EVENT_ID_TSV_DEF;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+  /* initial_value */
+  int64 = tsv->initial_value;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* number */
+  ctf_save_write_int32 (&writer->tcs, tsv->number);
+
+  /* builtin */
+  ctf_save_write_int32 (&writer->tcs, tsv->builtin);
+
+  /* name */
+  if (tsv->name != NULL)
+    ctf_save_write (&writer->tcs, (gdb_byte *) tsv->name,
+		    strlen (tsv->name));
+  ctf_save_write (&writer->tcs, &zero, 1);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_uploaded_tp.  */
+
+static void
+ctf_write_uploaded_tp (struct trace_file_writer *self,
+		       struct uploaded_tp *tp)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  int32_t int32;
+  int64_t int64;
+  uint32_t u32;
+  const gdb_byte zero = 0;
+
+  /* Event Id.  */
+  int32 = CTF_EVENT_ID_TP_DEF;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+  /* address */
+  int64 = tp->addr;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* traceframe_usage */
+  int64 = tp->traceframe_usage;
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+  /* number */
+  ctf_save_write_int32 (&writer->tcs, tp->number);
+
+  /* enabled */
+  ctf_save_write_int32 (&writer->tcs, tp->enabled);
+
+  /* step */
+  ctf_save_write_int32 (&writer->tcs, tp->step);
+
+  /* pass */
+  ctf_save_write_int32 (&writer->tcs, tp->pass);
+
+  /* hit_count */
+  ctf_save_write_int32 (&writer->tcs, tp->hit_count);
+
+  /* type */
+  ctf_save_write_int32 (&writer->tcs, tp->type);
+
+  /* condition  */
+  if (tp->cond != NULL)
+    ctf_save_write (&writer->tcs, (gdb_byte *) tp->cond.get (),
+		    strlen (tp->cond.get ()));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* actions */
+  u32 = tp->actions.size ();
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (const auto &act : tp->actions)
+    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
+		    strlen (act.get ()) + 1);
+
+  /* step_actions */
+  u32 = tp->step_actions.size ();
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (const auto &act : tp->step_actions)
+    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
+		    strlen (act.get ()) + 1);
+
+  /* at_string */
+  if (tp->at_string != NULL)
+    ctf_save_write (&writer->tcs, (gdb_byte *) tp->at_string.get (),
+		    strlen (tp->at_string.get ()));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* cond_string */
+  if (tp->cond_string != NULL)
+    ctf_save_write (&writer->tcs, (gdb_byte *) tp->cond_string.get (),
+		    strlen (tp->cond_string.get ()));
+  ctf_save_write (&writer->tcs, &zero, 1);
+
+  /* cmd_strings */
+  u32 = tp->cmd_strings.size ();
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+  for (const auto &act : tp->cmd_strings)
+    ctf_save_write (&writer->tcs, (gdb_byte *) act.get (),
+		    strlen (act.get ()) + 1);
+
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_tdesc.  */
+
+static void
+ctf_write_tdesc (struct trace_file_writer *self)
+{
+  /* Nothing so far. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_definition_end.  */
+
+static void
+ctf_write_definition_end (struct trace_file_writer *self)
+{
+  self->ops->frame_ops->end (self);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   end.  */
+
+static void
+ctf_end (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer = (struct ctf_trace_file_writer *) self;
+
+  gdb_assert (writer->tcs.content_size == 0);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   start.  */
+
+static void
+ctf_write_frame_start (struct trace_file_writer *self, uint16_t tpnum)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_FRAME;
+  uint32_t u32;
+
+  /* Step 1: Write packet context.  */
+  /* magic.  */
+  u32 = CTF_MAGIC;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+  /* content_size and packet_size..  We still don't know the value,
+     write it later.  */
+  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+  /* Tracepoint number.  */
+  ctf_save_write (&writer->tcs, (gdb_byte *) &tpnum, 2);
+
+  /* Step 2: Write event "frame".  */
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_r_block.  */
+
+static void
+ctf_write_frame_r_block (struct trace_file_writer *self,
+			 gdb_byte *buf, int32_t size)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_REGISTER;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  /* array contents.  */
+  ctf_save_align_write (&writer->tcs, buf, size, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_m_block_header.  */
+
+static void
+ctf_write_frame_m_block_header (struct trace_file_writer *self,
+				uint64_t addr, uint16_t length)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t event_id = CTF_EVENT_ID_MEMORY;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &event_id, 4, 4);
+
+  /* Address.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &addr, 8, 8);
+
+  /* Length.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &length, 2, 2);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_m_block_memory.  */
+
+static void
+ctf_write_frame_m_block_memory (struct trace_file_writer *self,
+				gdb_byte *buf, uint16_t length)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  /* Contents.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) buf, length, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_v_block.  */
+
+static void
+ctf_write_frame_v_block (struct trace_file_writer *self,
+			 int32_t num, uint64_t val)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_TSV;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  /* val.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &val, 8, 8);
+  /* num.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &num, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   end.  */
+
+static void
+ctf_write_frame_end (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t u32;
+  uint32_t t;
+
+  /* Write the content size to packet header.  */
+  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + 4,
+		  SEEK_SET);
+  u32 = writer->tcs.content_size * TARGET_CHAR_BIT;
+
+  t = writer->tcs.content_size;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+
+  /* Write the packet size.  */
+  u32 += 4 * TARGET_CHAR_BIT;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+
+  writer->tcs.content_size = t;
+
+  /* Write zero at the end of the packet.  */
+  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + t,
+		  SEEK_SET);
+  u32 = 0;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+  writer->tcs.content_size = t;
+
+  ctf_save_next_packet (&writer->tcs);
+}
+
+/* Operations to write various types of trace frames into CTF
+   format.  */
+
+static const struct trace_frame_write_ops ctf_write_frame_ops =
+{
+  ctf_write_frame_start,
+  ctf_write_frame_r_block,
+  ctf_write_frame_m_block_header,
+  ctf_write_frame_m_block_memory,
+  ctf_write_frame_v_block,
+  ctf_write_frame_end,
+};
+
+/* Operations to write trace buffers into CTF format.  */
+
+static const struct trace_file_write_ops ctf_write_ops =
+{
+  ctf_dtor,
+  ctf_target_save,
+  ctf_start,
+  ctf_write_header,
+  ctf_write_regblock_type,
+  ctf_write_status,
+  ctf_write_uploaded_tsv,
+  ctf_write_uploaded_tp,
+  ctf_write_tdesc,
+  ctf_write_definition_end,
+  NULL,
+  &ctf_write_frame_ops,
+  ctf_end,
+};
+
+/* Return a trace writer for CTF format.  */
+
+struct trace_file_writer *
+ctf_trace_file_writer_new (void)
+{
+  struct ctf_trace_file_writer *writer = XNEW (struct ctf_trace_file_writer);
+
+  writer->base.ops = &ctf_write_ops;
+
+  return (struct trace_file_writer *) writer;
+}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data.  The libbabeltrace provides
+   iterator to iterate over each event in CTF data and APIs to get
+   details of event and packet, so it is very convenient to use
+   libbabeltrace to access events in CTF.  */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory.  */
+static int handle_id = -1;
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The position of the first packet containing trace frame.  */
+static struct bt_iter_pos *start_pos;
+
+/* The name of CTF directory.  */
+static char *trace_dirname;
+
+static ctf_target ctf_ops;
+
+/* Destroy ctf iterator and context.  */
+
+static void
+ctf_destroy (void)
+{
+  if (ctf_iter != NULL)
+    {
+      bt_ctf_iter_destroy (ctf_iter);
+      ctf_iter = NULL;
+    }
+  if (ctx != NULL)
+    {
+      bt_context_put (ctx);
+      ctx = NULL;
+    }
+}
+
+/* Open CTF trace data in DIRNAME.  */
+
+static void
+ctf_open_dir (const char *dirname)
+{
+  struct bt_iter_pos begin_pos;
+  unsigned int count, i;
+  struct bt_ctf_event_decl * const *list;
+
+  ctx = bt_context_create ();
+  if (ctx == NULL)
+    error (_("Unable to create bt_context"));
+  handle_id = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+  if (handle_id < 0)
+    {
+      ctf_destroy ();
+      error (_("Unable to use libbabeltrace on directory \"%s\""),
+	     dirname);
+    }
+
+  begin_pos.type = BT_SEEK_BEGIN;
+  ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+  if (ctf_iter == NULL)
+    {
+      ctf_destroy ();
+      error (_("Unable to create bt_iterator"));
+    }
+
+  /* Look for the declaration of register block.  Get the length of
+     array "contents" to set trace_regblock_size.  */
+
+  bt_ctf_get_event_decl_list (handle_id, ctx, &list, &count);
+  for (i = 0; i < count; i++)
+    if (strcmp ("register", bt_ctf_get_decl_event_name (list[i])) == 0)
+      {
+	const struct bt_ctf_field_decl * const *field_list;
+	const struct bt_declaration *decl;
+
+	bt_ctf_get_decl_fields (list[i], BT_EVENT_FIELDS, &field_list,
+				&count);
+
+	gdb_assert (count == 1);
+	gdb_assert (0 == strcmp ("contents",
+				 bt_ctf_get_decl_field_name (field_list[0])));
+	decl = bt_ctf_get_decl_from_field_decl (field_list[0]);
+	trace_regblock_size = bt_ctf_get_array_len (decl);
+
+	break;
+      }
+}
+
+#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD)			\
+  (VAR)->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT),	\
+							   (SCOPE),	\
+							   #FIELD))
+
+#define SET_ENUM_FIELD(EVENT, SCOPE, VAR, TYPE, FIELD)			\
+  (VAR)->FIELD = (TYPE) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT),	\
+							    (SCOPE),	\
+							    #FIELD))
+
+
+/* EVENT is the "status" event and TS is filled in.  */
+
+static void
+ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
+{
+  const struct bt_definition *scope
+    = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
+
+  SET_ENUM_FIELD (event, scope, ts, enum trace_stop_reason, stop_reason);
+  SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
+  SET_INT32_FIELD (event, scope, ts, traceframe_count);
+  SET_INT32_FIELD (event, scope, ts, traceframes_created);
+  SET_INT32_FIELD (event, scope, ts, buffer_free);
+  SET_INT32_FIELD (event, scope, ts, buffer_size);
+  SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
+  SET_INT32_FIELD (event, scope, ts, circular_buffer);
+
+  bt_iter_next (bt_ctf_get_iter (ctf_iter));
+}
+
+/* Read the events "tsv_def" one by one, extract its contents and fill
+   in the list UPLOADED_TSVS.  */
+
+static void
+ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
+{
+  gdb_assert (ctf_iter != NULL);
+
+  while (1)
+    {
+      struct bt_ctf_event *event;
+      const struct bt_definition *scope;
+      const struct bt_definition *def;
+      uint32_t event_id;
+      struct uploaded_tsv *utsv = NULL;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+      scope = bt_ctf_get_top_level_scope (event,
+					  BT_STREAM_EVENT_HEADER);
+      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+						      "id"));
+      if (event_id != CTF_EVENT_ID_TSV_DEF)
+	break;
+
+      scope = bt_ctf_get_top_level_scope (event,
+					  BT_EVENT_FIELDS);
+
+      def = bt_ctf_get_field (event, scope, "number");
+      utsv = get_uploaded_tsv ((int32_t) bt_ctf_get_int64 (def),
+			       uploaded_tsvs);
+
+      def = bt_ctf_get_field (event, scope, "builtin");
+      utsv->builtin = (int32_t) bt_ctf_get_int64 (def);
+      def = bt_ctf_get_field (event, scope, "initial_value");
+      utsv->initial_value = bt_ctf_get_int64 (def);
+
+      def = bt_ctf_get_field (event, scope, "name");
+      utsv->name =  xstrdup (bt_ctf_get_string (def));
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+}
+
+/* Read the value of element whose index is NUM from CTF and write it
+   to the corresponding VAR->ARRAY. */
+
+#define SET_ARRAY_FIELD(EVENT, SCOPE, VAR, NUM, ARRAY)	\
+  do							\
+    {							\
+      uint32_t lu32, i;						\
+      const struct bt_definition *def;				\
+								\
+      lu32 = (uint32_t) bt_ctf_get_uint64 (bt_ctf_get_field ((EVENT),	\
+							     (SCOPE),	\
+							     #NUM));	\
+      def = bt_ctf_get_field ((EVENT), (SCOPE), #ARRAY);		\
+      for (i = 0; i < lu32; i++)					\
+	{								\
+	  const struct bt_definition *element				\
+	    = bt_ctf_get_index ((EVENT), def, i);			\
+									\
+	  (VAR)->ARRAY.emplace_back					\
+	    (xstrdup (bt_ctf_get_string (element)));			\
+	}								\
+    }									\
+  while (0)
+
+/* Read a string from CTF and set VAR->FIELD. If the length of string
+   is zero, set VAR->FIELD to NULL.  */
+
+#define SET_STRING_FIELD(EVENT, SCOPE, VAR, FIELD)			\
+  do									\
+    {									\
+      const char *p = bt_ctf_get_string (bt_ctf_get_field ((EVENT),	\
+							   (SCOPE),	\
+							   #FIELD));	\
+									\
+      if (strlen (p) > 0)						\
+	(VAR)->FIELD.reset (xstrdup (p));				\
+      else								\
+	(VAR)->FIELD = NULL;						\
+    }									\
+  while (0)
+
+/* Read the events "tp_def" one by one, extract its contents and fill
+   in the list UPLOADED_TPS.  */
+
+static void
+ctf_read_tp (struct uploaded_tp **uploaded_tps)
+{
+  gdb_assert (ctf_iter != NULL);
+
+  while (1)
+    {
+      struct bt_ctf_event *event;
+      const struct bt_definition *scope;
+      uint32_t u32;
+      int32_t int32;
+      uint64_t u64;
+      struct uploaded_tp *utp = NULL;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+      scope = bt_ctf_get_top_level_scope (event,
+					  BT_STREAM_EVENT_HEADER);
+      u32 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+						 "id"));
+      if (u32 != CTF_EVENT_ID_TP_DEF)
+	break;
+
+      scope = bt_ctf_get_top_level_scope (event,
+					  BT_EVENT_FIELDS);
+      int32 = (int32_t) bt_ctf_get_int64 (bt_ctf_get_field (event,
+							    scope,
+							    "number"));
+      u64 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+						 "addr"));
+      utp = get_uploaded_tp (int32, u64,  uploaded_tps);
+
+      SET_INT32_FIELD (event, scope, utp, enabled);
+      SET_INT32_FIELD (event, scope, utp, step);
+      SET_INT32_FIELD (event, scope, utp, pass);
+      SET_INT32_FIELD (event, scope, utp, hit_count);
+      SET_ENUM_FIELD (event, scope, utp, enum bptype, type);
+
+      /* Read 'cmd_strings'.  */
+      SET_ARRAY_FIELD (event, scope, utp, cmd_num, cmd_strings);
+      /* Read 'actions'.  */
+      SET_ARRAY_FIELD (event, scope, utp, action_num, actions);
+      /* Read 'step_actions'.  */
+      SET_ARRAY_FIELD (event, scope, utp, step_action_num,
+		       step_actions);
+
+      SET_STRING_FIELD(event, scope, utp, at_string);
+      SET_STRING_FIELD(event, scope, utp, cond_string);
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+}
+
+/* This is the implementation of target_ops method to_open.  Open CTF
+   trace data, read trace status, trace state variables and tracepoint
+   definitions from the first packet.  Set the start position at the
+   second packet which contains events on trace blocks.  */
+
+static void
+ctf_target_open (const char *dirname, int from_tty)
+{
+  struct bt_ctf_event *event;
+  uint32_t event_id;
+  const struct bt_definition *scope;
+  struct uploaded_tsv *uploaded_tsvs = NULL;
+  struct uploaded_tp *uploaded_tps = NULL;
+
+  if (!dirname)
+    error (_("No CTF directory specified."));
+
+  ctf_open_dir (dirname);
+
+  target_preopen (from_tty);
+
+  /* Skip the first packet which about the trace status.  The first
+     event is "frame".  */
+  event = bt_ctf_iter_read_event (ctf_iter);
+  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+  if (event_id != CTF_EVENT_ID_FRAME)
+    error (_("Wrong event id of the first event"));
+  /* The second event is "status".  */
+  bt_iter_next (bt_ctf_get_iter (ctf_iter));
+  event = bt_ctf_iter_read_event (ctf_iter);
+  scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+  event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+  if (event_id != CTF_EVENT_ID_STATUS)
+    error (_("Wrong event id of the second event"));
+  ctf_read_status (event, current_trace_status ());
+
+  ctf_read_tsv (&uploaded_tsvs);
+
+  ctf_read_tp (&uploaded_tps);
+
+  event = bt_ctf_iter_read_event (ctf_iter);
+  /* EVENT can be NULL if we've already gone to the end of stream of
+     events.  */
+  if (event != NULL)
+    {
+      scope = bt_ctf_get_top_level_scope (event,
+					  BT_STREAM_EVENT_HEADER);
+      event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event,
+						      scope, "id"));
+      if (event_id != CTF_EVENT_ID_FRAME)
+	error (_("Wrong event id of the first event of the second packet"));
+    }
+
+  start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (start_pos->type == BT_SEEK_RESTORE);
+
+  trace_dirname = xstrdup (dirname);
+  push_target (&ctf_ops);
+
+  inferior_appeared (current_inferior (), CTF_PID);
+  inferior_ptid = ptid_t (CTF_PID);
+  add_thread_silent (inferior_ptid);
+
+  merge_uploaded_trace_state_variables (&uploaded_tsvs);
+  merge_uploaded_tracepoints (&uploaded_tps);
+
+  post_create_inferior (&ctf_ops, from_tty);
+}
+
+/* This is the implementation of target_ops method to_close.  Destroy
+   CTF iterator and context.  */
+
+void
+ctf_target::close ()
+{
+  ctf_destroy ();
+  xfree (trace_dirname);
+  trace_dirname = NULL;
+
+  inferior_ptid = null_ptid;	/* Avoid confusion from thread stuff.  */
+  exit_inferior_silent (current_inferior ());
+
+  trace_reset_local_state ();
+}
+
+/* This is the implementation of target_ops method to_files_info.
+   Print the directory name of CTF trace data.  */
+
+void
+ctf_target::files_info ()
+{
+  printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+   Iterate over events whose name is "register" in current frame,
+   extract contents from events, and set REGCACHE with the contents.
+   If no matched events are found, mark registers unavailable.  */
+
+void
+ctf_target::fetch_registers (struct regcache *regcache, int regno)
+{
+  struct gdbarch *gdbarch = regcache->arch ();
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos;
+
+  /* An uninitialized reg size says we're not going to be
+     successful at getting register blocks.  */
+  if (trace_regblock_size == 0)
+    return;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL || strcmp (name, "frame") == 0)
+	break;
+      else if (strcmp (name, "register") == 0)
+	{
+	  event = event1;
+	  break;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  if (event != NULL)
+    {
+      int offset, regsize, regn;
+      const struct bt_definition *scope
+	= bt_ctf_get_top_level_scope (event,
+				      BT_EVENT_FIELDS);
+      const struct bt_definition *array
+	= bt_ctf_get_field (event, scope, "contents");
+      gdb_byte *regs = (gdb_byte *) bt_ctf_get_char_array (array);
+
+      /* Assume the block is laid out in GDB register number order,
+	 each register with the size that it has in GDB.  */
+      offset = 0;
+      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+	{
+	  regsize = register_size (gdbarch, regn);
+	  /* Make sure we stay within block bounds.  */
+	  if (offset + regsize >= trace_regblock_size)
+	    break;
+	  if (regcache->get_register_status (regn) == REG_UNKNOWN)
+	    {
+	      if (regno == regn)
+		{
+		  regcache->raw_supply (regno, regs + offset);
+		  break;
+		}
+	      else if (regno == -1)
+		{
+		  regcache->raw_supply (regn, regs + offset);
+		}
+	    }
+	  offset += regsize;
+	}
+    }
+  else
+    tracefile_fetch_registers (regcache, regno);
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+   Iterate over events whose name is "memory" in
+   current frame, extract the address and length from events.  If
+   OFFSET is within the range, read the contents from events to
+   READBUF.  */
+
+enum target_xfer_status
+ctf_target::xfer_partial (enum target_object object,
+			  const char *annex, gdb_byte *readbuf,
+			  const gdb_byte *writebuf, ULONGEST offset,
+			  ULONGEST len, ULONGEST *xfered_len)
+{
+  /* We're only doing regular memory for now.  */
+  if (object != TARGET_OBJECT_MEMORY)
+    return TARGET_XFER_E_IO;
+
+  if (readbuf == NULL)
+    error (_("ctf_xfer_partial: trace file is read-only"));
+
+  if (get_traceframe_number () != -1)
+    {
+      struct bt_iter_pos *pos;
+      enum target_xfer_status res;
+      /* Records the lowest available address of all blocks that
+	 intersects the requested range.  */
+      ULONGEST low_addr_available = 0;
+
+      gdb_assert (ctf_iter != NULL);
+      /* Save the current position.  */
+      pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+      gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+      /* Iterate through the traceframe's blocks, looking for
+	 memory.  */
+      while (1)
+	{
+	  ULONGEST amt;
+	  uint64_t maddr;
+	  uint16_t mlen;
+	  const struct bt_definition *scope;
+	  const struct bt_definition *def;
+	  struct bt_ctf_event *event
+	    = bt_ctf_iter_read_event (ctf_iter);
+	  const char *name = bt_ctf_event_name (event);
+
+	  if (name == NULL || strcmp (name, "frame") == 0)
+	    break;
+	  else if (strcmp (name, "memory") != 0)
+	    {
+	      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+		break;
+
+	      continue;
+	    }
+
+	  scope = bt_ctf_get_top_level_scope (event,
+					      BT_EVENT_FIELDS);
+
+	  def = bt_ctf_get_field (event, scope, "address");
+	  maddr = bt_ctf_get_uint64 (def);
+	  def = bt_ctf_get_field (event, scope, "length");
+	  mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+	  /* If the block includes the first part of the desired
+	     range, return as much it has; GDB will re-request the
+	     remainder, which might be in a different block of this
+	     trace frame.  */
+	  if (maddr <= offset && offset < (maddr + mlen))
+	    {
+	      const struct bt_definition *array
+		= bt_ctf_get_field (event, scope, "contents");
+	      gdb_byte *contents;
+	      int k;
+
+	      contents = (gdb_byte *) xmalloc (mlen);
+
+	      for (k = 0; k < mlen; k++)
+		{
+		  const struct bt_definition *element
+		    = bt_ctf_get_index (event, array, k);
+
+		  contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+		}
+
+	      amt = (maddr + mlen) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      memcpy (readbuf, &contents[offset - maddr], amt);
+
+	      xfree (contents);
+
+	      /* Restore the position.  */
+	      bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+	      if (amt == 0)
+		return TARGET_XFER_EOF;
+	      else
+		{
+		  *xfered_len = amt;
+		  return TARGET_XFER_OK;
+		}
+	    }
+
+	  if (offset < maddr && maddr < (offset + len))
+	    if (low_addr_available == 0 || low_addr_available > maddr)
+	      low_addr_available = maddr;
+
+	  if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	    break;
+	}
+
+      /* Restore the position.  */
+      bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+      /* Requested memory is unavailable in the context of traceframes,
+	 and this address falls within a read-only section, fallback
+	 to reading from executable, up to LOW_ADDR_AVAILABLE  */
+      if (offset < low_addr_available)
+	len = std::min (len, low_addr_available - offset);
+      res = exec_read_partial_read_only (readbuf, offset, len, xfered_len);
+
+      if (res == TARGET_XFER_OK)
+	return TARGET_XFER_OK;
+      else
+	{
+	  /* No use trying further, we know some memory starting
+	     at MEMADDR isn't available.  */
+	  *xfered_len = len;
+	  return TARGET_XFER_UNAVAILABLE;
+	}
+    }
+  else
+    {
+      /* Fallback to reading from read-only sections.  */
+      return section_table_read_available_memory (readbuf, offset, len, xfered_len);
+    }
+}
+
+/* This is the implementation of target_ops method
+   to_get_trace_state_variable_value.
+   Iterate over events whose name is "tsv" in current frame.  When the
+   trace variable is found, set the value of it to *VAL and return
+   true, otherwise return false.  */
+
+bool
+ctf_target::get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+  struct bt_iter_pos *pos;
+  bool found = false;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  /* Iterate through the traceframe's blocks, looking for 'V'
+     block.  */
+  while (1)
+    {
+      struct bt_ctf_event *event
+	= bt_ctf_iter_read_event (ctf_iter);
+      const char *name = bt_ctf_event_name (event);
+
+      if (name == NULL || strcmp (name, "frame") == 0)
+	break;
+      else if (strcmp (name, "tsv") == 0)
+	{
+	  const struct bt_definition *scope;
+	  const struct bt_definition *def;
+
+	  scope = bt_ctf_get_top_level_scope (event,
+					      BT_EVENT_FIELDS);
+
+	  def = bt_ctf_get_field (event, scope, "num");
+	  if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+	    {
+	      def = bt_ctf_get_field (event, scope, "val");
+	      *val = bt_ctf_get_uint64 (def);
+
+	      found = true;
+	    }
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return found;
+}
+
+/* Return the tracepoint number in "frame" event.  */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+  /* The packet context of events has a field "tpnum".  */
+  const struct bt_definition *scope
+    = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+  uint64_t tpnum
+    = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+  return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected.  */
+
+static CORE_ADDR
+ctf_get_traceframe_address (void)
+{
+  struct bt_ctf_event *event = NULL;
+  struct bt_iter_pos *pos;
+  CORE_ADDR addr = 0;
+
+  gdb_assert (ctf_iter != NULL);
+  pos  = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  while (1)
+    {
+      const char *name;
+      struct bt_ctf_event *event1;
+
+      event1 = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event1);
+
+      if (name == NULL)
+	break;
+      else if (strcmp (name, "frame") == 0)
+	{
+	  event = event1;
+	  break;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  if (event != NULL)
+    {
+      int tpnum = ctf_get_tpnum_from_frame_event (event);
+      struct tracepoint *tp
+	= get_tracepoint_by_number_on_target (tpnum);
+
+      if (tp && tp->loc)
+	addr = tp->loc->address;
+    }
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+   Iterate the events whose name is "frame", extract the tracepoint
+   number in it.  Return traceframe number when matched.  */
+
+int
+ctf_target::trace_find (enum trace_find_type type, int num,
+			CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+  int tfnum = 0;
+  int found = 0;
+
+  if (num == -1)
+    {
+      if (tpp != NULL)
+	*tpp = -1;
+      return -1;
+    }
+
+  gdb_assert (ctf_iter != NULL);
+  /* Set iterator back to the start.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
+
+  while (1)
+    {
+      struct bt_ctf_event *event;
+      const char *name;
+
+      event = bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (event == NULL || name == NULL)
+	break;
+
+      if (strcmp (name, "frame") == 0)
+	{
+	  CORE_ADDR tfaddr;
+
+	  if (type == tfind_number)
+	    {
+	      /* Looking for a specific trace frame.  */
+	      if (tfnum == num)
+		found = 1;
+	    }
+	  else
+	    {
+	      /* Start from the _next_ trace frame.  */
+	      if (tfnum > get_traceframe_number ())
+		{
+		  switch (type)
+		    {
+		    case tfind_tp:
+		      {
+			struct tracepoint *tp = get_tracepoint (num);
+
+			if (tp != NULL
+			    && (tp->number_on_target
+				== ctf_get_tpnum_from_frame_event (event)))
+			  found = 1;
+			break;
+		      }
+		    case tfind_pc:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (tfaddr == addr1)
+			found = 1;
+		      break;
+		    case tfind_range:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (addr1 <= tfaddr && tfaddr <= addr2)
+			found = 1;
+		      break;
+		    case tfind_outside:
+		      tfaddr = ctf_get_traceframe_address ();
+		      if (!(addr1 <= tfaddr && tfaddr <= addr2))
+			found = 1;
+		      break;
+		    default:
+		      internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+		    }
+		}
+	    }
+	  if (found)
+	    {
+	      if (tpp != NULL)
+		*tpp = ctf_get_tpnum_from_frame_event (event);
+
+	      /* Skip the event "frame".  */
+	      bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+	      return tfnum;
+	    }
+	  tfnum++;
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+
+  return -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+   Iterate the events whose name is "memory", in current
+   frame, extract memory range information, and return them in
+   traceframe_info.  */
+
+traceframe_info_up
+ctf_target::traceframe_info ()
+{
+  traceframe_info_up info (new struct traceframe_info);
+  const char *name;
+  struct bt_iter_pos *pos;
+
+  gdb_assert (ctf_iter != NULL);
+  /* Save the current position.  */
+  pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+  gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+  do
+    {
+      struct bt_ctf_event *event
+	= bt_ctf_iter_read_event (ctf_iter);
+
+      name = bt_ctf_event_name (event);
+
+      if (name == NULL || strcmp (name, "register") == 0
+	  || strcmp (name, "frame") == 0)
+	;
+      else if (strcmp (name, "memory") == 0)
+	{
+	  const struct bt_definition *scope
+	    = bt_ctf_get_top_level_scope (event,
+					  BT_EVENT_FIELDS);
+	  const struct bt_definition *def;
+
+	  def = bt_ctf_get_field (event, scope, "address");
+	  CORE_ADDR start = bt_ctf_get_uint64 (def);
+
+	  def = bt_ctf_get_field (event, scope, "length");
+	  int length = (uint16_t) bt_ctf_get_uint64 (def);
+
+	  info->memory.emplace_back (start, length);
+	}
+      else if (strcmp (name, "tsv") == 0)
+	{
+	  int vnum;
+	  const struct bt_definition *scope
+	    = bt_ctf_get_top_level_scope (event,
+					  BT_EVENT_FIELDS);
+	  const struct bt_definition *def;
+
+	  def = bt_ctf_get_field (event, scope, "num");
+	  vnum = (int) bt_ctf_get_uint64 (def);
+	  info->tvars.push_back (vnum);
+	}
+      else
+	{
+	  warning (_("Unhandled trace block type (%s) "
+		     "while building trace frame info."),
+		   name);
+	}
+
+      if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+	break;
+    }
+  while (name != NULL && strcmp (name, "frame") != 0);
+
+  /* Restore the position.  */
+  bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+  return info;
+}
+
+#endif
+
+/* module initialization */
+
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+  add_target (ctf_target_info, ctf_target_open, filename_completer);
+#endif
+}
diff --git a/gdb/tracectf.h b/gdb/tracectf.h
new file mode 100644
index 0000000..5526e47
--- /dev/null
+++ b/gdb/tracectf.h
@@ -0,0 +1,25 @@
+/* CTF format support.
+
+   Copyright (C) 2012-2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef TRACECTF_H
+#define TRACECTF_H
+
+extern struct trace_file_writer *ctf_trace_file_writer_new (void);
+
+#endif
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
index a92104b..79ba541 100644
--- a/gdb/tracefile.c
+++ b/gdb/tracefile.c
@@ -19,7 +19,7 @@
 
 #include "defs.h"
 #include "tracefile.h"
-#include "ctf.h"
+#include "tracectf.h"
 #include "exec.h"
 #include "regcache.h"
 #include "gdbsupport/byte-vector.h"
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 843341a..4db7060 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -51,7 +51,6 @@
 #include "memrange.h"
 #include "cli/cli-utils.h"
 #include "probe.h"
-#include "ctf.h"
 #include "gdbsupport/filestuff.h"
 #include "gdbsupport/rsp-low.h"
 #include "tracefile.h"
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-04 20:24 ` [PATCH v4 2/2] gdb: CTF support Weimin Pan
@ 2019-10-07 14:40   ` Simon Marchi
  2019-10-07 16:00     ` Wei-min Pan
  2019-10-09 17:41   ` Tom Tromey
  1 sibling, 1 reply; 9+ messages in thread
From: Simon Marchi @ 2019-10-07 14:40 UTC (permalink / raw)
  To: Weimin Pan, gdb-patches

On 2019-10-04 4:23 p.m., Weimin Pan wrote:
> This patch adds the CTF (Compact Ansi-C Type Format) support in gdb.
> Two submissions on which this gdb work depends were posted earlier
> in May:
> 
>  * On the binutils mailing list - adding libctf which creates, updates,
>    reads, and manipulates the CTF data.
>  * On the gcc mailing list - expanding gcc to directly emit the CFT data
>    with a new command line option -gt.
> 
> CTF is a reduced form of debugging information whose main purpose is to
> describe the type of C entities such as structures, unions, typedefs and
> function arguments at the global scope only. It does not contain debug
> information about source lines, location expressions, or local variables.
> For more information on CTF, see the documentation in the libdtrace-ctf
> source tree, available here:
> 
> <https://raw.githubusercontent.com/oracle/libdtrace-ctf/master/doc/ctf-format>.
> 
> This patch expands struct elfinfo by adding the .ctf section, which
> contains CTF debugging info, and modifies elf_symfile_read() to read it.
> If both DWARF and CTF exist in a program, only DWARF will be read. CTF data
> will be read only when there is no DWARF. The two-stage symbolic reading
> and setting strategy, partial and full, was used.
> 
> File ctfread.c contains functions to transform CTF data into gdb's internal
> symbol table structures by iterately reading entries from CTF sections
> of "data objects", "function info", "variable info", and "data types"
> when setting up either partial or full symbol table. If the ELF symbol table
> is available, e.g. not stripped, the CTF reader will associate the found
> type information with these symbol entries. Due to the proximity between DWARF
> and CTF (CTF being a much simplified subset of DWARF), some DWARF implementation
> was reused to support CTF.
> 
> Test cases ctf-constvars.exp, ctf-cvexpr.exp, ctf-ptype.exp, and ctf-whatis.exp
> have been added to verify the correctness of this support.
> 
> This patch has missing features and limitations which we will add and
> address in the future patches.

Hi Weimin,

I got notified this morning that this patch series was pushed to master, although it
was not approved yet.  I don't think I had any remaining comments and was probably going
to approve this version anyway, but I am wondering if you pushed this version to master
by mistake instead of your personal users/ branch, since I told you to do so.

Please just fix up the ChangeLog entry below:

> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 3974823..03b9474 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,5 +1,20 @@
>  2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
>  
> +	* ctfread.c: New file.
> +	* ctfread.h: New file.
> +	* elfread.c: Include ctfread.h.
> +	(struct elfinfo text_p): New member ctfsect.
> +	(elf_locate_sections): Mark CTF section.
> +	(elf_symfile_read): Call elfctf_build_psymtabs.
> +	* Makefile.in (LIBCTF): Add.
> +	(CLIBS): Use it.
> +	(CDEPS): Likewise.
> +	(DIST): Add ctfread.c.
> +	* ../Makefile.def (dependencies): Add all-libctf to all-gdb
> +	* ../Makefile.in: Add "all-gdb: maybe-all-libctf"

As mentioned in the previous review, these last two lines must go in the top-level ChangeLog.

Simon

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-07 14:40   ` Simon Marchi
@ 2019-10-07 16:00     ` Wei-min Pan
  0 siblings, 0 replies; 9+ messages in thread
From: Wei-min Pan @ 2019-10-07 16:00 UTC (permalink / raw)
  To: Simon Marchi, gdb-patches


On 10/7/2019 7:40 AM, Simon Marchi wrote:
> On 2019-10-04 4:23 p.m., Weimin Pan wrote:
>> This patch adds the CTF (Compact Ansi-C Type Format) support in gdb.
>> Two submissions on which this gdb work depends were posted earlier
>> in May:
>>
>>   * On the binutils mailing list - adding libctf which creates, updates,
>>     reads, and manipulates the CTF data.
>>   * On the gcc mailing list - expanding gcc to directly emit the CFT data
>>     with a new command line option -gt.
>>
>> CTF is a reduced form of debugging information whose main purpose is to
>> describe the type of C entities such as structures, unions, typedefs and
>> function arguments at the global scope only. It does not contain debug
>> information about source lines, location expressions, or local variables.
>> For more information on CTF, see the documentation in the libdtrace-ctf
>> source tree, available here:
>>
>> <https://raw.githubusercontent.com/oracle/libdtrace-ctf/master/doc/ctf-format>.
>>
>> This patch expands struct elfinfo by adding the .ctf section, which
>> contains CTF debugging info, and modifies elf_symfile_read() to read it.
>> If both DWARF and CTF exist in a program, only DWARF will be read. CTF data
>> will be read only when there is no DWARF. The two-stage symbolic reading
>> and setting strategy, partial and full, was used.
>>
>> File ctfread.c contains functions to transform CTF data into gdb's internal
>> symbol table structures by iterately reading entries from CTF sections
>> of "data objects", "function info", "variable info", and "data types"
>> when setting up either partial or full symbol table. If the ELF symbol table
>> is available, e.g. not stripped, the CTF reader will associate the found
>> type information with these symbol entries. Due to the proximity between DWARF
>> and CTF (CTF being a much simplified subset of DWARF), some DWARF implementation
>> was reused to support CTF.
>>
>> Test cases ctf-constvars.exp, ctf-cvexpr.exp, ctf-ptype.exp, and ctf-whatis.exp
>> have been added to verify the correctness of this support.
>>
>> This patch has missing features and limitations which we will add and
>> address in the future patches.
> Hi Weimin,
>
> I got notified this morning that this patch series was pushed to master, although it
> was not approved yet.  I don't think I had any remaining comments and was probably going
> to approve this version anyway, but I am wondering if you pushed this version to master
> by mistake instead of your personal users/ branch, since I told you to do so.

Hi Simon,

I'm very sorry, should've pushed it to my private branch, my fault.

Weimin
>
> Please just fix up the ChangeLog entry below:
>
>> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
>> index 3974823..03b9474 100644
>> --- a/gdb/ChangeLog
>> +++ b/gdb/ChangeLog
>> @@ -1,5 +1,20 @@
>>   2019-10-04  Weimin Pan  <weimin.pan@oracle.com>
>>   
>> +	* ctfread.c: New file.
>> +	* ctfread.h: New file.
>> +	* elfread.c: Include ctfread.h.
>> +	(struct elfinfo text_p): New member ctfsect.
>> +	(elf_locate_sections): Mark CTF section.
>> +	(elf_symfile_read): Call elfctf_build_psymtabs.
>> +	* Makefile.in (LIBCTF): Add.
>> +	(CLIBS): Use it.
>> +	(CDEPS): Likewise.
>> +	(DIST): Add ctfread.c.
>> +	* ../Makefile.def (dependencies): Add all-libctf to all-gdb
>> +	* ../Makefile.in: Add "all-gdb: maybe-all-libctf"
> As mentioned in the previous review, these last two lines must go in the top-level ChangeLog.
>
> Simon

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-04 20:24 ` [PATCH v4 2/2] gdb: CTF support Weimin Pan
  2019-10-07 14:40   ` Simon Marchi
@ 2019-10-09 17:41   ` Tom Tromey
  2019-10-10 19:05     ` Wei-min Pan
  1 sibling, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2019-10-09 17:41 UTC (permalink / raw)
  To: Weimin Pan; +Cc: gdb-patches

>>>>> Weimin Pan <weimin.pan@oracle.com> writes:

> This patch adds the CTF (Compact Ansi-C Type Format) support in gdb.

This went in by mistake, but since it was on the road to going in
anyway, I guess we'll just live with that.  We all make mistakes, but at
the same time, please do try to be careful.

> diff --git a/Makefile.def b/Makefile.def
> index 6f5e881..311feb9 100644
[...]

I didn't look, did the top-level changes go in to gcc?
The top-level configury code is canonically maintained there.

> +static const struct objfile_data *ctf_file_key;

It's preferable to use the type-safe registry approach in new code.

> +typedef struct ctf_context
> +{
> +  ctf_file_t *fp;
> +  struct objfile *of;
> +  struct buildsym_compunit *builder;
> +} ctf_context_t;

gdb doesn't generally use typedefs like this, especially now that it's
in C++.

> +/* Get text segment base for OBJFILE, TSIZE contains the segment size.  */
> +
> +static CORE_ADDR
> +get_objfile_text_range (struct objfile *of, int *tsize)
> +{
> +  CORE_ADDR text_base;
> +  bfd *abfd = of->obfd;
> +  const asection *codes;
> +
> +  codes = bfd_get_section_by_name (abfd, ".text");

Instead of this function, it's more usual in gdb to use:

      CORE_ADDR baseaddr
	= ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));

Maybe this function is even wrong in some situation, I'm not sure.

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-09 17:41   ` Tom Tromey
@ 2019-10-10 19:05     ` Wei-min Pan
  2019-10-15 20:19       ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Wei-min Pan @ 2019-10-10 19:05 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 10/9/2019 10:41 AM, Tom Tromey wrote:
 >>>>>> Weimin Pan <weimin.pan@oracle.com> writes:
 >
 >> This patch adds the CTF (Compact Ansi-C Type Format) support in gdb.
 >
 > This went in by mistake, but since it was on the road to going in
 > anyway, I guess we'll just live with that.  We all make mistakes, but at
 > the same time, please do try to be careful.

I'm sure that the lesson learned from all this will be remembered and
the mistake won't be repeated.

 >
 >> diff --git a/Makefile.def b/Makefile.def
 >> index 6f5e881..311feb9 100644
 > [...]
 >
 > I didn't look, did the top-level changes go in to gcc?
 > The top-level configury code is canonically maintained there.

Given the following rules in Makefile.def:

dependencies = { module=configure-gcc; on=all-binutils; };
dependencies = { module=all-binutils; on=all-libctf; };
dependencies = { module=all-gdb; on=all-libctf; };

binutils gets built before gcc does. It's not clear why making changes
into gcc is needed?

 >
 >> +static const struct objfile_data *ctf_file_key;
 >
 > It's preferable to use the type-safe registry approach in new code.

This register key was not intended to manage the object with new/delete
but to be used to close file descriptors that are associated with the
ctf file/archive.

 >>> +typedef struct ctf_context
 >> +{
 >> +  ctf_file_t *fp;
 >> +  struct objfile *of;
 >> +  struct buildsym_compunit *builder;
 >> +} ctf_context_t;
 >
 > gdb doesn't generally use typedefs like this, especially now that it's
 > in C++.

It seems there are several places, e.g. aarch64-tdep.c, event-loop.c,
linespec.c, procfs.c, that do. We can drop "typedef" if you prefer.

 >
 >> +/* Get text segment base for OBJFILE, TSIZE contains the segment 
size.  */
 >> +
 >> +static CORE_ADDR
 >> +get_objfile_text_range (struct objfile *of, int *tsize)
 >> +{
 >> +  CORE_ADDR text_base;
 >> +  bfd *abfd = of->obfd;
 >> +  const asection *codes;
 >> +
 >> +  codes = bfd_get_section_by_name (abfd, ".text");
 >
 > Instead of this function, it's more usual in gdb to use:
 >
 >       CORE_ADDR baseaddr
 >       = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 >
 > Maybe this function is even wrong in some situation, I'm not sure.

You suspect that bfd_get_section_by_name might return a wrong *asection?
Yes, we can use ANOFFSET, as you suggested, for the text base but still
need to get the size of the text section.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-10 19:05     ` Wei-min Pan
@ 2019-10-15 20:19       ` Tom Tromey
  2019-10-17 21:18         ` Wei-min Pan
  0 siblings, 1 reply; 9+ messages in thread
From: Tom Tromey @ 2019-10-15 20:19 UTC (permalink / raw)
  To: Wei-min Pan; +Cc: Tom Tromey, gdb-patches

>>>>> Wei-min Pan <weimin.pan@oracle.com> writes:

>> I didn't look, did the top-level changes go in to gcc?
>> The top-level configury code is canonically maintained there.

> Given the following rules in Makefile.def:

> dependencies = { module=configure-gcc; on=all-binutils; };
> dependencies = { module=all-binutils; on=all-libctf; };
> dependencies = { module=all-gdb; on=all-libctf; };

> binutils gets built before gcc does. It's not clear why making changes
> into gcc is needed?

Sorry, I was not clear enough.

Most top-level files, like Makefile.def, are shared between gcc and
gdb+binutils.  However, gcc and gdb have different source repositories.
In order to reduce the possibility of long-term divergence, the gcc
repository was declared the canonical repository -- in general (there
are exceptions) -- changes are checked in first there, then brought over
to the gdb repository.

My question was whether you did this.

>> It's preferable to use the type-safe registry approach in new code.

> This register key was not intended to manage the object with new/delete
> but to be used to close file descriptors that are associated with the
> ctf file/archive.

It's still preferable to use the type-safe approach.  You can easily
introduce a new deleter object that works just as you like.  In fact the
code will nearly be identical -- just type-safe.

>> gdb doesn't generally use typedefs like this, especially now that it's
>> in C++.

> It seems there are several places, e.g. aarch64-tdep.c, event-loop.c,
> linespec.c, procfs.c, that do. We can drop "typedef" if you prefer.

Yes, I'm afraid you can't always judge the current standard in gdb by
the existing code, because the transition from C to C++ did not also
involve updating every single thing -- just the important things.

>> Instead of this function, it's more usual in gdb to use:
>> 
>>        CORE_ADDR baseaddr
>>        = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
>> 
>> Maybe this function is even wrong in some situation, I'm not sure.

> You suspect that bfd_get_section_by_name might return a wrong *asection?
> Yes, we can use ANOFFSET, as you suggested, for the text base but still
> need to get the size of the text section.

I'm not sure if it can or not.  Anyway it seems you can use
SECT_OFF_TEXT to also get the size... ?

thanks,
Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-15 20:19       ` Tom Tromey
@ 2019-10-17 21:18         ` Wei-min Pan
  2019-10-18 20:36           ` Tom Tromey
  0 siblings, 1 reply; 9+ messages in thread
From: Wei-min Pan @ 2019-10-17 21:18 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 10/15/2019 1:18 PM, Tom Tromey wrote:
 >>>>>> Wei-min Pan <weimin.pan@oracle.com> writes:
 >
 >>> I didn't look, did the top-level changes go in to gcc?
 >>> The top-level configury code is canonically maintained there.
 >
 >> Given the following rules in Makefile.def:
 >
 >> dependencies = { module=configure-gcc; on=all-binutils; };
 >> dependencies = { module=all-binutils; on=all-libctf; };
 >> dependencies = { module=all-gdb; on=all-libctf; };
 >
 >> binutils gets built before gcc does. It's not clear why making changes
 >> into gcc is needed?
 >
 > Sorry, I was not clear enough.
 >
 > Most top-level files, like Makefile.def, are shared between gcc and
 > gdb+binutils.  However, gcc and gdb have different source repositories.
 > In order to reduce the possibility of long-term divergence, the gcc
 > repository was declared the canonical repository -- in general (there
 > are exceptions) -- changes are checked in first there, then brought over
 > to the gdb repository.
 >
 > My question was whether you did this.

Thanks for the explanation. It looks like that I will need to add
gcc/Makefile.def (dependencies): all-gdb depends on all-libctf.

 >
 >>> It's preferable to use the type-safe registry approach in new code.
 >
 >> This register key was not intended to manage the object with new/delete
 >> but to be used to close file descriptors that are associated with the
 >> ctf file/archive.
 >
 > It's still preferable to use the type-safe approach.  You can easily
 > introduce a new deleter object that works just as you like. In fact the
 > code will nearly be identical -- just type-safe.

OK, will make the change.

 >
 >>> gdb doesn't generally use typedefs like this, especially now that it's
 >>> in C++.
 >
 >> It seems there are several places, e.g. aarch64-tdep.c, event-loop.c,
 >> linespec.c, procfs.c, that do. We can drop "typedef" if you prefer.
 >
 > Yes, I'm afraid you can't always judge the current standard in gdb by
 > the existing code, because the transition from C to C++ did not also
 > involve updating every single thing -- just the important things.

OK.

 >
 >>> Instead of this function, it's more usual in gdb to use:
 >>>
 >>>        CORE_ADDR baseaddr
 >>>        = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 >>>
 >>> Maybe this function is even wrong in some situation, I'm not sure.
 >
 >> You suspect that bfd_get_section_by_name might return a wrong *asection?
 >> Yes, we can use ANOFFSET, as you suggested, for the text base but still
 >> need to get the size of the text section.
 >
 > I'm not sure if it can or not.  Anyway it seems you can use
 > SECT_OFF_TEXT to also get the size... ?

You mean using SECT_OFF_TEXT to get the address?

Will send out the diffs as soon as I'm done with these changes.

Thanks again.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v4 2/2] gdb: CTF support
  2019-10-17 21:18         ` Wei-min Pan
@ 2019-10-18 20:36           ` Tom Tromey
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2019-10-18 20:36 UTC (permalink / raw)
  To: Wei-min Pan; +Cc: Tom Tromey, gdb-patches

>>>>> Wei-min Pan <weimin.pan@oracle.com> writes:

>> I'm not sure if it can or not.  Anyway it seems you can use
>> SECT_OFF_TEXT to also get the size... ?

> You mean using SECT_OFF_TEXT to get the address?

Yeah, that's what I meant.

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-10-18 20:36 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-04 20:25 [PATCH v4 1/2] Renaming of ctf (the trace format) files Weimin Pan
2019-10-04 20:24 ` [PATCH v4 2/2] gdb: CTF support Weimin Pan
2019-10-07 14:40   ` Simon Marchi
2019-10-07 16:00     ` Wei-min Pan
2019-10-09 17:41   ` Tom Tromey
2019-10-10 19:05     ` Wei-min Pan
2019-10-15 20:19       ` Tom Tromey
2019-10-17 21:18         ` Wei-min Pan
2019-10-18 20:36           ` Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).