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

Wei-min Pan via Gdb-patches
2021-06-10T21:19:27Z

On 6/9/2021 5:40 PM, Lancelot SIX wrote:
> Hi,
>
> I do not have much expertise on this area (and am by no mean
> maintainer), but I have few questions and remarks along the patch.
>
> I have not tested this series since I do not have a CTF capable gcc
> around. I would need to search in the GCC mailing for the required
> patches which I have not yet.
Hi,

You can find the latest gcc patch series for CTF support, which is
currently under review, here:

http://gcc.1065356.n8.nabble.com/PATCH-V9-0-7-Support-for-the-CTF-and-BTF-debug-formats-td1897109.html

Also please make sure to use a binutils version with CTF support.

>
> On Mon, May 17, 2021 at 08:20:25PM -0400, 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)
> Should be
>
> if (sym != nullptr)

OK.

>> + 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);
> I am a bit confused by this one. As far as I can see, there is no way
> it can ever be deleted. Again, I am not so familiar with the code yet
> so I might have missed something, but hopefully not.

I believe  the psymtab_discarder's dtor should take care of discarding
all built partial
symbol tables. So I'm not sure if this is a CTF specific issue.

> My goto method would be to have the 'pst' field in the struct
> ctf_context be a std::unique_ptr<ctf_psymtab>. But having the
> ctx_context on the objstack makes it difficult. Even if you allocate is
> with obstack_new instead of XOBNEW (because it would not be trivially
> constructible anymore), the dtor would not be called when the objstack
> is released. As far as I am aware, releasing the obstack “only” releases
> the underlying storage, but have no way to know that dtors should be
> called.

One way to avoid dealing with either the storage or dtor issue is to
declare:

struct ctf_context context;

in struct ctf_psymtab.

>
> For similar reasons (not being trivially_destructible), a ctf_psymtab
> should not be allocated on the obstack.
>
> Long story short, I do not see (yet) a clean way to have someone to
> claim ownership of this newly allocated memory, and that someone being
> able to free the resource at some point. I guess similar pattern have
> been faced before, and the solution should be somewhere in the codebase.
>
>>
>> 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);
> This set-up code (new buildsym_compunit then
> builder->record_debugformat) now exists here and in ctf_start_symtab. I
> am not quite familiar with how those can be called, but I am wondering
> if there is any chance for ctf_start_symtab to be called after this code
> have been executed? If so, ccx->builder will be overridden, and the
> instance created here will leak.

ctf_start_symtab gets called to handle the main CU while ctf_start_archive
gets called to handle each archive which, in the CTF context, is just a CU
and contains the CTF debugging info for conflicting types. Since the mian CU
always gets processed before its archives do. it's not possible that the
builder
field will get overridden.

> This 'naked new' raises the same question as above. ccx (a ctf_context)
> is allocated on the obstack, so no dtor is called when the memory is
> released when released. The buildsym_compunit will then end-up
> dangling. I guess this situation existed prior to this patch in
> ctf_start_symtab.
>
>> + 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);
> By removing this call, 'partial_symtabs' (declared 2 lines above) is
> now unused and should also be removed.

Good catch. It will be removed.

> I hope those remarks / questions are useful.
Thanks for taking the time and your comments.

>
> Lancelot
>
>> + 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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >.
>> +
>> +# 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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +#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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +#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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +#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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >. */
>> +
>> +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!MhtIBI8EHfJeg3wdwWXoOjZ2I2QbUeJQxEbRWW6IUFtk_iT2CdzmXh-PEdoMmFZy$ >.
>> +
>> +# 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"
>> --
>> 1.8.3.1
>>