[PING 3][PATCH V5] CTF: multi-CU and archive support

Wei-min Pan via Gdb-patches
2021-06-09T00:37:57Z

On 6/1/2021 5:05 PM, Wei-min Pan via Gdb-patches wrote:
>
> On 5/24/2021 5:52 PM, Wei-min Pan wrote:
>>
>> On 5/17/2021 5:20 PM, Weimin Pan via Gdb-patches wrote:
>>> [Changes from V4:
>>>   - Treat CTF archives as CUs over dependencies to avoid over-expanding
>>>     psymtabs, as Tom Tromey pointed out.
>>>   - Avoid calling ctf_dict_close more than once on a dictionary.]
>>>
>>> Now gdb is capable of debugging executable, which consists of multiple
>>> compilation units (CUs) with the CTF debug info. An executable could
>>> potentially have one or more archives, which, in CTF context, contain
>>> conflicting types.
>>>
>>> all changes were made in ctfread.c in which elfctf_build_psymtabs was
>>> modified to handle archives, via the ctf archive iterator and its
>>> callback
>>> build_ctf_archive_member and scan_partial_symbols was modified to scan
>>> archives, which are treated as subfiles, to build the psymtabs.
>>>
>>> Also changes were made to handle CTF's data object section and function
>>> info section which now share the same format of their contents - an
>>> array
>>> of type IDs. New functions ctf_psymtab_add_stt_entries, which is
>>> called by
>>> ctf_psymtab_add_stt_obj and ctf_psymtab_add_stt_func, and
>>> add_stt_entries,
>>> which is called by add_stt_obj and add_stt_func when setting up
>>> psymtabs
>>> and full symtab, respectively.
>>> ---
>>>   gdb/ctfread.c                             | 311
>>> +++++++++++++++++-------------
>>>   gdb/testsuite/gdb.ctf/cross-tu-cyclic-1.c |  18 ++
>>>   gdb/testsuite/gdb.ctf/cross-tu-cyclic-2.c |  16 ++
>>>   gdb/testsuite/gdb.ctf/cross-tu-cyclic-3.c |   3 +
>>>   gdb/testsuite/gdb.ctf/cross-tu-cyclic-4.c |   4 +
>>>   gdb/testsuite/gdb.ctf/cross-tu-cyclic.exp |  43 +++++
>>>   gdb/testsuite/gdb.ctf/ctf-a.c             |  32 +++
>>>   gdb/testsuite/gdb.ctf/ctf-a.h             |  22 +++
>>>   gdb/testsuite/gdb.ctf/ctf-b.c             |  25 +++
>>>   gdb/testsuite/gdb.ctf/ctf-b.h             |  22 +++
>>>   gdb/testsuite/gdb.ctf/ctf-c.c             |  25 +++
>>>   gdb/testsuite/gdb.ctf/ctf-c.h             |  21 ++
>>>   gdb/testsuite/gdb.ctf/multi.exp           |  42 ++++
>>>   13 files changed, 453 insertions(+), 131 deletions(-)
>>>   create mode 100644 gdb/testsuite/gdb.ctf/cross-tu-cyclic-1.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/cross-tu-cyclic-2.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/cross-tu-cyclic-3.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/cross-tu-cyclic-4.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/cross-tu-cyclic.exp
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-a.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-a.h
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-b.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-b.h
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-c.c
>>>   create mode 100644 gdb/testsuite/gdb.ctf/ctf-c.h
>>>   create mode 100644 gdb/testsuite/gdb.ctf/multi.exp
>>>
>>> diff --git a/gdb/ctfread.c b/gdb/ctfread.c
>>> index 23e859a..1939f40 100644
>>> --- a/gdb/ctfread.c
>>> +++ b/gdb/ctfread.c
>>> @@ -117,6 +117,7 @@ struct ctf_context
>>>     struct objfile *of;
>>>     psymtab_storage *partial_symtabs;
>>>     partial_symtab *pst;
>>> +  ctf_archive_t *arc;
>>>     struct buildsym_compunit *builder;
>>>   };
>>>   @@ -166,6 +167,16 @@ struct ctf_field_info
>>>     std::vector<struct decl_field> nested_types_list;
>>>   };
>>>   +/* Data held for a translation unit.  */
>>> +
>>> +struct ctf_per_tu_data
>>> +{
>>> +  ctf_dict_t *fp;
>>> +  struct objfile *of;
>>> +  ctf_archive_t *arc;
>>> +  psymtab_storage *pss;
>>> +  psymbol_functions *psf;
>>> +};
>>>     /* Local function prototypes */
>>>   @@ -245,10 +256,8 @@ struct ctf_tid_and_type
>>>     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);
>>> +  if (*slot == nullptr)
>>> +    *slot = XOBNEW (&of->objfile_obstack, struct ctf_tid_and_type);
>>>     **slot = ids;
>>>     return typ;
>>>   }
>>> @@ -510,7 +519,7 @@ struct ctf_tid_and_type
>>>           break;
>>>       }
>>>   -      add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
>>> +      add_symbol_to_list (sym, ccp->builder->get_file_symbols ());
>>>       }
>>>       return sym;
>>> @@ -1143,7 +1152,8 @@ struct ctf_tid_and_type
>>>       if (type)
>>>         {
>>>           sym = new_symbol (ccp, type, id);
>>> -        sym->compute_and_set_names (name, false, ccp->of->per_bfd);
>>> +        if (sym)
>>> +          sym->compute_and_set_names (name, false, ccp->of->per_bfd);
>>>         }
>>>       break;
>>>         case CTF_K_STRUCT:
>>> @@ -1160,7 +1170,7 @@ struct ctf_tid_and_type
>>>       SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
>>>       SYMBOL_ACLASS_INDEX (sym) = LOC_OPTIMIZED_OUT;
>>>       sym->compute_and_set_names (name, false, ccp->of->per_bfd);
>>> -    add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
>>> +    add_symbol_to_list (sym, ccp->builder->get_file_symbols ());
>>>       break;
>>>         default:
>>>       complaint (_("ctf_add_var_cb: kind unsupported (%d)"), kind);
>>> @@ -1173,81 +1183,48 @@ struct ctf_tid_and_type
>>>     return 0;
>>>   }
>>>   -/* Add an ELF STT_OBJ symbol with index IDX to the symbol table.  */
>>> +/* Add entries in either data objects or function info section,
>>> controlled
>>> +   by FUNCTIONS.  */
>>>   -static struct symbol *
>>> -add_stt_obj (struct ctf_context *ccp, unsigned long idx)
>>> +static void
>>> +add_stt_entries (struct ctf_context *ccp, int functions)
>>>   {
>>> -  struct symbol *sym;
>>> -  struct type *type;
>>> +  ctf_next_t *i = nullptr;
>>> +  const char *tname;
>>>     ctf_id_t tid;
>>> +  struct symbol *sym = nullptr;
>>> +  struct type *type;
>>>   -  if ((tid = ctf_lookup_by_symbol (ccp->fp, idx)) == CTF_ERR)
>>> -    return nullptr;
>>> -
>>> -  type = fetch_tid_type (ccp, tid);
>>> -  if (type == nullptr)
>>> -    return nullptr;
>>> -
>>> -  sym = new_symbol (ccp, type, tid);
>>> -
>>> -  return sym;
>>> +  while ((tid = ctf_symbol_next (ccp->fp, &i, &tname, functions))
>>> != CTF_ERR)
>>> +    {
>>> +      type = get_tid_type (ccp->of, tid);
>>> +      if (type == nullptr)
>>> +    continue;
>>> +      sym = new (&ccp->of->objfile_obstack) symbol;
>>> +      OBJSTAT (ccp->of, n_syms++);
>>> +      SYMBOL_TYPE (sym) = type;
>>> +      SYMBOL_DOMAIN (sym) = VAR_DOMAIN;
>>> +      SYMBOL_ACLASS_INDEX (sym) = LOC_STATIC;
>>> +      sym->compute_and_set_names (tname, false, ccp->of->per_bfd);
>>> +      add_symbol_to_list (sym, ccp->builder->get_global_symbols ());
>>> +      set_symbol_address (ccp->of, sym, tname);
>>> +    }
>>>   }
>>>   -/* Add an ELF STT_FUNC symbol with index IDX to the symbol
>>> table.  */
>>> +/* Add entries in data objects section.  */
>>>   -static struct symbol *
>>> -add_stt_func (struct ctf_context *ccp, unsigned long idx)
>>> +static void
>>> +add_stt_obj (struct ctf_context *ccp)
>>>   {
>>> -  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 nullptr;
>>> -
>>> -  argc = finfo.ctc_argc;
>>> -  if (ctf_func_args (ccp->fp, idx, argc, argv) == CTF_ERR)
>>> -    return nullptr;
>>> -
>>> -  gdb::unique_xmalloc_ptr<char> name (ctf_type_aname_raw (ccp->fp,
>>> idx));
>>> -  if (name == nullptr)
>>> -    return nullptr;
>>> -
>>> -  tid = ctf_lookup_by_symbol (ccp->fp, idx);
>>> -  ftype = fetch_tid_type (ccp, tid);
>>> -  if ((finfo.ctc_flags & CTF_FUNC_VARARG) != 0)
>>> -    ftype->set_has_varargs (true);
>>> -  ftype->set_num_fields (argc);
>>> -
>>> -  /* If argc is 0, it has a "void" type.  */
>>> -  if (argc != 0)
>>> -    ftype->set_fields
>>> -      ((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 = fetch_tid_type (ccp, argv[iparam]);
>>> -      if (atyp)
>>> -    ftype->field (iparam).set_type (atyp);
>>> -      else
>>> -    ftype->field (iparam).set_type (void_type);
>>> -    }
>>> +  add_stt_entries (ccp, 0);
>>> +}
>>>   -  sym = new_symbol (ccp, ftype, tid);
>>> -  rettyp = fetch_tid_type (ccp, finfo.ctc_return);
>>> -  if (rettyp != nullptr)
>>> -    SYMBOL_TYPE (sym) = rettyp;
>>> -  else
>>> -    SYMBOL_TYPE (sym) = void_type;
>>> +/* Add entries in function info section.  */
>>>   -  return sym;
>>> +static void
>>> +add_stt_func (struct ctf_context *ccp)
>>> +{
>>> +  add_stt_entries (ccp, 1);
>>>   }
>>>     /* Get text segment base for OBJFILE, TSIZE contains the segment
>>> size.  */
>>> @@ -1317,12 +1294,71 @@ struct ctf_tid_and_type
>>>              ctf_errmsg (ctf_errno (ccp->fp)));
>>>   }
>>>   +/* Add entries in either data objects or function info section,
>>> controlled
>>> +   by FUNCTIONS, to psymtab.  */
>>> +
>>> +static void
>>> +ctf_psymtab_add_stt_entries (ctf_dict_t *cfp, ctf_psymtab *pst,
>>> +                 struct objfile *of, int functions)
>>> +{
>>> +  ctf_next_t *i = nullptr;
>>> +  ctf_id_t tid;
>>> +  const char *tname;
>>> +
>>> +  while ((tid = ctf_symbol_next (cfp, &i, &tname, functions)) !=
>>> CTF_ERR)
>>> +    {
>>> +      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;
>>> +
>>> +      pst->add_psymbol (tname, true,
>>> +            tdomain, aclass, -1,
>>> +            psymbol_placement::GLOBAL,
>>> +            0, language_c, pst->context->partial_symtabs, of);
>>> +    }
>>> +}
>>> +
>>> +/* Add entries in data objects section to psymtab.  */
>>> +
>>> +static void
>>> +ctf_psymtab_add_stt_obj (ctf_dict_t *cfp, ctf_psymtab *pst,
>>> +             struct objfile *of)
>>> +{
>>> +  ctf_psymtab_add_stt_entries (cfp, pst, of, 0);
>>> +}
>>> +
>>> +/* Add entries in function info section to psymtab.  */
>>> +
>>> +static void
>>> +ctf_psymtab_add_stt_func (ctf_dict_t *cfp, ctf_psymtab *pst,
>>> +              struct objfile *of)
>>> +{
>>> +  ctf_psymtab_add_stt_entries (cfp, pst, of, 1);
>>> +}
>>> +
>>>   /* Read in full symbols for PST, and anything it depends on. */
>>>     void
>>>   ctf_psymtab::expand_psymtab (struct objfile *objfile)
>>>   {
>>> -  struct symbol *sym;
>>>     struct ctf_context *ccp;
>>>       gdb_assert (!readin);
>>> @@ -1341,21 +1377,8 @@ struct ctf_tid_and_type
>>>              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 == nullptr)
>>> -    {
>>> -      if (ctf_errno (ccp->fp) == EINVAL
>>> -          || ctf_errno (ccp->fp) == ECTF_NOSYMTAB)
>>> -        break;
>>> -      sym = add_stt_func (ccp, i);
>>> -    }
>>> -      if (sym == nullptr)
>>> -    continue;
>>> -
>>> -      set_symbol_address (ccp->of, sym, sym->linkage_name ());
>>> -    }
>>> +  add_stt_obj (ccp);
>>> +  add_stt_func (ccp);
>>>       readin = true;
>>>   }
>>> @@ -1409,6 +1432,7 @@ struct ctf_tid_and_type
>>>     static ctf_psymtab *
>>>   create_partial_symtab (const char *name,
>>> +               ctf_archive_t *arc,
>>>                  ctf_dict_t *cfp,
>>>                  psymtab_storage *partial_symtabs,
>>>                  struct objfile *objfile)
>>> @@ -1419,11 +1443,12 @@ struct ctf_tid_and_type
>>>     pst = new ctf_psymtab (name, partial_symtabs, objfile->per_bfd, 0);
>>>       ccx = XOBNEW (&objfile->objfile_obstack, struct ctf_context);
>>> +  ccx->arc = arc;
>>>     ccx->fp = cfp;
>>> +  ctf_ref (cfp);
>>>     ccx->of = objfile;
>>>     ccx->partial_symtabs = partial_symtabs;
>>>     ccx->pst = pst;
>>> -  ccx->builder = nullptr;
>>>     pst->context = ccx;
>>>       return pst;
>>> @@ -1486,7 +1511,7 @@ struct ctf_tid_and_type
>>>       ccp->pst->add_psymbol (name, false,
>>>                domain, aclass, section,
>>> -             psymbol_placement::GLOBAL,
>>> +             psymbol_placement::STATIC,
>>>                0, language_c, ccp->partial_symtabs, ccp->of);
>>>       return 0;
>>> @@ -1506,18 +1531,46 @@ struct ctf_tid_and_type
>>>     return 0;
>>>   }
>>>   +/* Start a subfile for CTF. FNAME is the name of the archive.  */
>>> +
>>> +static void
>>> +ctf_start_archive (struct ctf_context *ccx, struct objfile *of,
>>> +           const char *fname)
>>> +{
>>> +  if (ccx->builder == nullptr)
>>> +    {
>>> +      ccx->builder = new buildsym_compunit (of,
>>> +              of->original_name, nullptr, language_c, 0);
>>> +      ccx->builder->record_debugformat ("ctf");
>>> +    }
>>> +  ccx->builder->start_subfile (fname);
>>> +}
>>> +
>>>   /* Setup partial_symtab's describing each source file for which
>>>      debugging information is available.  */
>>>     static void
>>>   scan_partial_symbols (ctf_dict_t *cfp, psymtab_storage
>>> *partial_symtabs,
>>> -              struct objfile *of)
>>> +              struct ctf_per_tu_data *tup, const char *fname)
>>>   {
>>> -  bfd *abfd = of->obfd;
>>> -  const char *name = bfd_get_filename (abfd);
>>> -  ctf_psymtab *pst = create_partial_symtab (name, cfp,
>>> partial_symtabs, of);
>>> +  struct objfile *of = tup->of;
>>> +  bool isparent = false;
>>> +
>>> +  if (strcmp (fname, ".ctf") == 0)
>>> +    {
>>> +      fname = bfd_get_filename (of->obfd);
>>> +      isparent = true;
>>> +    }
>>> +
>>> +  ctf_psymtab *pst = create_partial_symtab (fname, tup->arc, cfp,
>>> +                        partial_symtabs, of);
>>>       struct ctf_context *ccx = pst->context;
>>> +  if (isparent == false)
>>> +    {
>>> +      ctf_start_archive (ccx, of, fname);
>>> +      ccx->pst = pst;
>>> +    }
>>>       if (ctf_type_iter (cfp, ctf_psymtab_type_cb, ccx) == CTF_ERR)
>>>       complaint (_("ctf_type_iter scan_partial_symbols failed - %s"),
>>> @@ -1530,46 +1583,33 @@ struct ctf_tid_and_type
>>>     /* 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;
>>> -    }
>>> -      const char *tname = ctf_type_name_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;
>>> -    }
>>> +  ctf_psymtab_add_stt_obj (cfp, pst, of);
>>> +  ctf_psymtab_add_stt_func (cfp, pst, of);
>>>   -      if (kind == CTF_K_FUNCTION)
>>> -    aclass = LOC_STATIC;
>>> -      else if (kind == CTF_K_CONST)
>>> -    aclass = LOC_CONST;
>>> -      else
>>> -    aclass = LOC_TYPEDEF;
>>> +  pst->end ();
>>> +}
>>>   -      pst->add_psymbol (tname, false,
>>> -            tdomain, aclass, -1,
>>> -            psymbol_placement::STATIC,
>>> -            0, language_c, partial_symtabs, of);
>>> +/* Callback to build the psymtab for archive member NAME.  */
>>> +
>>> +static int
>>> +build_ctf_archive_member (ctf_dict_t *ctf, const char *name, void
>>> *arg)
>>> +{
>>> +  struct ctf_per_tu_data *tup = (struct ctf_per_tu_data *) arg;
>>> +  ctf_dict_t *parent = tup->fp;
>>> +
>>> +  if (strcmp (name, ".ctf") != 0)
>>> +    ctf_import (ctf, parent);
>>> +
>>> +  if (info_verbose)
>>> +    {
>>> +      printf_filtered (_("Scanning archive member %s..."), name);
>>> +      gdb_flush (gdb_stdout);
>>>       }
>>>   -  pst->end ();
>>> +  psymtab_storage *pss = tup->psf->get_partial_symtabs ().get ();
>>> +  scan_partial_symbols (ctf, pss, tup, name);
>>> +
>>> +  return 0;
>>>   }
>>>     /* Read CTF debugging information from a BFD section. This is
>>> @@ -1579,6 +1619,7 @@ struct ctf_tid_and_type
>>>   void
>>>   elfctf_build_psymtabs (struct objfile *of)
>>>   {
>>> +  struct ctf_per_tu_data pcu;
>>>     bfd *abfd = of->obfd;
>>>     int err;
>>>   @@ -1593,10 +1634,18 @@ struct ctf_tid_and_type
>>>          bfd_get_filename (abfd), ctf_errmsg (err));
>>>     ctf_dict_key.emplace (of, fp);
>>>   +  pcu.fp = fp;
>>> +  pcu.of = of;
>>> +  pcu.arc = arc;
>>> +
>>>     psymbol_functions *psf = new psymbol_functions ();
>>>     psymtab_storage *partial_symtabs = psf->get_partial_symtabs
>>> ().get ();
>>>     of->qf.emplace_front (psf);
>>> -  scan_partial_symbols (fp, partial_symtabs, of);
>>> +  pcu.psf = psf;
>>> +
>>> +  if (ctf_archive_iter (arc, build_ctf_archive_member, &pcu) < 0)
>>> +    error (_("ctf_archive_iter failed in input file %s: - %s"),
>>> +       bfd_get_filename (abfd), ctf_errmsg (err));
>>>   }
>>>     #else
>>> diff --git a/gdb/testsuite/gdb.ctf/cross-tu-cyclic-1.c
>>> b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-1.c
>>> new file mode 100644
>>> index 0000000..fe52b9e
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-1.c
>>> @@ -0,0 +1,18 @@
>>> +struct A;
>>> +struct B
>>> +{
>>> +  int foo;
>>> +  struct A *bar;
>>> +};
>>> +
>>> +struct A
>>> +{
>>> +  long a;
>>> +  struct B *foo;
>>> +};
>>> +
>>> +static struct A *foo __attribute__((used));
>>> +
>>> +int main()
>>> +{
>>> +}
>>> diff --git a/gdb/testsuite/gdb.ctf/cross-tu-cyclic-2.c
>>> b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-2.c
>>> new file mode 100644
>>> index 0000000..aa2d177
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-2.c
>>> @@ -0,0 +1,16 @@
>>> +struct B;
>>> +struct A
>>> +{
>>> +  long a;
>>> +  struct B *foo;
>>> +  struct C *bar;
>>> +};
>>> +
>>> +struct C
>>> +{
>>> +  struct B *foo;
>>> +  int b;
>>> +};
>>> +
>>> +static struct C *foo __attribute__((used));
>>> +static struct A *bar __attribute__((used));
>>> diff --git a/gdb/testsuite/gdb.ctf/cross-tu-cyclic-3.c
>>> b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-3.c
>>> new file mode 100644
>>> index 0000000..19947e8
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-3.c
>>> @@ -0,0 +1,3 @@
>>> +struct A { struct B *foo; };
>>> +static struct A *a __attribute__((__used__));
>>> +static struct A *conflicty __attribute__((__used__));
>>> diff --git a/gdb/testsuite/gdb.ctf/cross-tu-cyclic-4.c
>>> b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-4.c
>>> new file mode 100644
>>> index 0000000..6e0c957
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/cross-tu-cyclic-4.c
>>> @@ -0,0 +1,4 @@
>>> +struct A { struct B *foo; };
>>> +struct B { struct B *next; };
>>> +static struct A *a __attribute__((__used__));
>>> +static struct B *conflicty __attribute__((__used__));
>>> diff --git a/gdb/testsuite/gdb.ctf/cross-tu-cyclic.exp
>>> b/gdb/testsuite/gdb.ctf/cross-tu-cyclic.exp
>>> new file mode 100644
>>> index 0000000..b6e640e
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/cross-tu-cyclic.exp
>>> @@ -0,0 +1,43 @@
>>> +# Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.
>>> +
>>> +# This file is a subset of ptype.exp written by Rob Savoye.
>>> (rob@cygnus.com)
>>> +
>>> +if [skip_ctf_tests] {
>>> +    unsupported "no CTF debug format support, or CTF disabled in GDB"
>>> +    return 0
>>> +}
>>> +
>>> +standard_testfile cross-tu-cyclic-1.c  cross-tu-cyclic-2.c \
>>> +    cross-tu-cyclic-3.c  cross-tu-cyclic-4.c
>>> +
>>> +# Using `-gt` generates full-fledged CTF debug information.
>>> +set opts "additional_flags=-gt -Wl,--export-dynamic"
>>> +if { [prepare_for_testing "failed to prepare" ${testfile} \
>>> +      [list $srcfile $srcfile2 $srcfile3 $srcfile4] \
>>> +      [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
>>> +}
>>> +
>>> +# Same thing with struct and union.
>>> +gdb_test "ptype struct A" "type = struct A \{\[\r\n\]+\[
>>> \t\]+struct B \\*foo;\[\r\n\]+\}.*" "ptype structure A"
>>> +gdb_test "ptype struct B" "type = struct B \{\[\r\n\]+\[
>>> \t\]+struct B \\*next;\[\r\n\]+\}.*" "ptype structure B"
>>> +gdb_test "ptype struct C" "type = struct C \{\[\r\n\]+\[
>>> \t\]+struct B \\*foo;\[\r\n\]+\[ \t\]+int b;\[\r\n\]+\}.*" "ptype
>>> structure C"
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-a.c
>>> b/gdb/testsuite/gdb.ctf/ctf-a.c
>>> new file mode 100644
>>> index 0000000..9aa2a8f
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-a.c
>>> @@ -0,0 +1,32 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +#include "ctf-a.h"
>>> +
>>> +static struct A a __attribute__((used));
>>> +
>>> +extern struct C *foo ();
>>> +extern int bar ();
>>> +
>>> +int main ()
>>> +{
>>> +  struct C *cp;
>>> +  cp = foo ();
>>> +  if (cp)
>>> +    return bar ();
>>> +  return 0;
>>> +}
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-a.h
>>> b/gdb/testsuite/gdb.ctf/ctf-a.h
>>> new file mode 100644
>>> index 0000000..297d740
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-a.h
>>> @@ -0,0 +1,22 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +struct A {
>>> +  struct B *b;
>>> +  struct A *next;
>>> +};
>>> +
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-b.c
>>> b/gdb/testsuite/gdb.ctf/ctf-b.c
>>> new file mode 100644
>>> index 0000000..c3a8ce5
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-b.c
>>> @@ -0,0 +1,25 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +#include "ctf-b.h"
>>> +
>>> +static struct B b __attribute__((used));
>>> +
>>> +int bar ()
>>> +{
>>> +  return b.wombat;
>>> +}
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-b.h
>>> b/gdb/testsuite/gdb.ctf/ctf-b.h
>>> new file mode 100644
>>> index 0000000..9dbdd7d
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-b.h
>>> @@ -0,0 +1,22 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +struct B {
>>> +  struct C *c;
>>> +  int wombat;
>>> +};
>>> +
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-c.c
>>> b/gdb/testsuite/gdb.ctf/ctf-c.c
>>> new file mode 100644
>>> index 0000000..b4051b3
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-c.c
>>> @@ -0,0 +1,25 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +#include "ctf-c.h"
>>> +
>>> +static struct C c __attribute__((used));
>>> +
>>> +struct C * foo ()
>>> +{
>>> +  return &c;
>>> +}
>>> diff --git a/gdb/testsuite/gdb.ctf/ctf-c.h
>>> b/gdb/testsuite/gdb.ctf/ctf-c.h
>>> new file mode 100644
>>> index 0000000..fb18157
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/ctf-c.h
>>> @@ -0,0 +1,21 @@
>>> +/* This test program is part of GDB, the GNU debugger.
>>> +
>>> +   Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.  */
>>> +
>>> +struct C {
>>> +  struct A *a;
>>> +  int b;
>>> +};
>>> diff --git a/gdb/testsuite/gdb.ctf/multi.exp
>>> b/gdb/testsuite/gdb.ctf/multi.exp
>>> new file mode 100644
>>> index 0000000..973115e
>>> --- /dev/null
>>> +++ b/gdb/testsuite/gdb.ctf/multi.exp
>>> @@ -0,0 +1,42 @@
>>> +# Copyright 2021 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
>>> <https://urldefense.com/v3/__http://www.gnu.org/licenses/__;!!GqivPVa7Brio!KfrttasFsnIw1ZHq2B1VVTIQZbEXNf8botBC8BmTRvyeUnbHs4wvBeakioqQKyuK$
>>> >.
>>> +
>>> +# This file is a subset of ptype.exp written by Rob Savoye.
>>> (rob@cygnus.com)
>>> +
>>> +if [skip_ctf_tests] {
>>> +    unsupported "no CTF debug format support, or CTF disabled in GDB"
>>> +    return 0
>>> +}
>>> +
>>> +standard_testfile ctf-a.c ctf-b.c ctf-c.c
>>> +
>>> +# Using `-gt` generates full-fledged CTF debug information.
>>> +set opts "additional_flags=-gt -Wl,--export-dynamic"
>>> +if { [prepare_for_testing "failed to prepare" ${testfile} \
>>> +      [list $srcfile $srcfile2 $srcfile3] \
>>> +      [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
>>> +}
>>> +
>>> +# Same thing with struct and union.
>>> +gdb_test "ptype struct A" "type = struct A \{\[\r\n\]+\[
>>> \t\]+struct B \\*b;\[\r\n\]+\[ \t\]+struct A \\*next;\[\r\n\]+\}.*"
>>> "ptype structure A"
>>> +gdb_test "ptype struct B" "type = struct B \{\[\r\n\]+\[
>>> \t\]+struct C \\*c;\[\r\n\]+\[ \t\]+int \\wombat;\[\r\n\]+\}.*"
>>> "ptype structure B"
>>> +gdb_test "ptype struct C" "type = struct C \{\[\r\n\]+\[
>>> \t\]+struct A \\*a;\[\r\n\]+\[ \t\]+int b;\[\r\n\]+\}.*" "ptype
>>> structure C"