From: Zeck S <zeck654321@gmail.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>, tom@tromey.com
Subject: Re: [RFC][PATCH?] fixed some segfaults and bugs in mdebug support
Date: Tue, 12 Mar 2024 21:09:43 -0500 [thread overview]
Message-ID: <CAMeZSLCSiYrLDPyh_F+U-V0DPQCr-9iG8xs8rNiO_Q801T-2dw@mail.gmail.com> (raw)
In-Reply-To: <20240216024523.227437-3-zeck654321@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 95030 bytes --]
Just checking to see if there is still interest in taking this patch. I
could split it up somehow or remove parts of it if I need to.
On Thu, Feb 15, 2024 at 8:48 PM Zeck S <zeck654321@gmail.com> wrote:
> Tried to send this a week ago, but I see somehow send email did not thread
> it correctly.
> Trying again, I think it was because the subject line was messed up.
>
> Addressed comments, adapted some core tests, fixed more bugs.
> In addition to the modified tests, I specifically also got
> gdb.base/relocate.exp working to sort out some problems.
>
> As always, glad to address feedback, and thanks for the patience.
>
> I reverted some of my code around parse_lines addresses.
> The Procedure Descriptor Record format is weird.
> The File Descriptor Record has the final correct address
> of the LOWEST PDR, only. This is used as a base address
> for a kind of janky fixup/relocation system.
> I suspect originally the PDR addresses were directly useful in simpler
> formats.
>
> Based on comments in bfd ecofflink and documentation about something
> similar in
> "MIPS Mdebug Debugging Information" by David Anderson
> that describes HDRR offsets as offsets from the beginning of the a.out
> as a "design mistake" I think some compilers
> set the PDR address to a location in an object file.
>
> This means there's basically a garbage offset added to all the PDRs.
> So all PDRs have their addresses subtracted from the lowest to kind
> treat it as 0, and then the lowest PDRs REAL correct address
> is used from the FDR, as an offset.
>
> IDO actually always outputs the lowest PDR's address as 0
> so subtracting it out does nothing, but hurts nothing.
>
> I can find no real documentation about this.
>
> I did find precedent for what my reverted code was doing in
> section 5.3.4.1 of ""Tru64 UNIX Object File and Symbol Table Format
> Specification"
> but after I figured out what the original code was doing I
> reverted those changes to distrub the code less.
>
> ---
> gdb/mdebugread.c | 230 ++++--
> gdb/testsuite/boards/qemu-user.exp | 267 +++++++
> gdb/testsuite/gdb.mdebug/README | 67 ++
> gdb/testsuite/gdb.mdebug/break.c | 92 +++
> gdb/testsuite/gdb.mdebug/break.exp | 921 ++++++++++++++++++++++
> gdb/testsuite/gdb.mdebug/break1.c | 59 ++
> gdb/testsuite/gdb.mdebug/info-types-c.exp | 67 ++
> gdb/testsuite/gdb.mdebug/info-types.c | 116 +++
> 8 files changed, 1770 insertions(+), 49 deletions(-)
> create mode 100644 gdb/testsuite/boards/qemu-user.exp
> create mode 100644 gdb/testsuite/gdb.mdebug/README
> create mode 100644 gdb/testsuite/gdb.mdebug/break.c
> create mode 100644 gdb/testsuite/gdb.mdebug/break.exp
> create mode 100644 gdb/testsuite/gdb.mdebug/break1.c
> create mode 100644 gdb/testsuite/gdb.mdebug/info-types-c.exp
> create mode 100644 gdb/testsuite/gdb.mdebug/info-types.c
>
> diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c
> index cd6638224e7..0118507a8f3 100644
> --- a/gdb/mdebugread.c
> +++ b/gdb/mdebugread.c
> @@ -237,7 +237,7 @@ static struct type *new_type (char *);
> enum block_type { FUNCTION_BLOCK, NON_FUNCTION_BLOCK };
>
> static struct block *new_block (struct objfile *objfile,
> - enum block_type, enum language);
> + enum block_type, enum language, bool
> is_global);
>
> static struct compunit_symtab *new_symtab (const char *, int, struct
> objfile *);
>
> @@ -246,7 +246,7 @@ static struct linetable *new_linetable (int);
> static struct blockvector *new_bvect (int);
>
> static struct type *parse_type (int, union aux_ext *, unsigned int, int *,
> - int, const char *);
> + int, const char *, bool);
>
> static struct symbol *mylookup_symbol (const char *, const struct block *,
> domain_enum, enum address_class);
> @@ -572,7 +572,7 @@ add_data_symbol (SYMR *sh, union aux_ext *ax, int
> bigend,
> || sh->sc == scNil || sh->index == indexNil)
> s->set_type (builtin_type (objfile)->nodebug_data_symbol);
> else
> - s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name));
> + s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name,
> false));
> /* Value of a data symbol is its memory address. */
> }
>
> @@ -624,8 +624,17 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> break;
> }
>
> - if (section_index != -1)
> - sh->value += section_offsets[section_index];
> + if (section_index != -1) {
> + int offset = section_offsets[section_index];
> + if ((bfd_get_file_flags (objfile->obfd.get ()) & (EXEC_P | DYNAMIC))
> == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and the offset is put
> in the vma. */
> + offset +=
> objfile->sections_start[section_index].the_bfd_section->vma;
> + }
> + sh->value += offset;
> + }
>
> switch (sh->st)
> {
> @@ -705,7 +714,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> break;
> }
> s->set_value_longest (svalue);
> - s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name));
> + s->set_type (parse_type (cur_fd, ax, sh->index, 0, bigend, name,
> false));
> add_symbol (s, top_stack->cur_st, top_stack->cur_block);
> break;
>
> @@ -761,7 +770,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> t = builtin_type (objfile)->builtin_int;
> else
> {
> - t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name);
> + t = parse_type (cur_fd, ax, sh->index + 1, 0, bigend, name,
> false);
> if (strcmp (name, "malloc") == 0
> && t->code () == TYPE_CODE_VOID)
> {
> @@ -805,7 +814,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> s->type ()->set_is_prototyped (true);
>
> /* Create and enter a new lexical context. */
> - b = new_block (objfile, FUNCTION_BLOCK, s->language ());
> + b = new_block (objfile, FUNCTION_BLOCK, s->language (), false);
> s->set_value_block (b);
> b->set_function (s);
> b->set_start (sh->value);
> @@ -1135,7 +1144,13 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> }
>
> top_stack->blocktype = stBlock;
> - b = new_block (objfile, NON_FUNCTION_BLOCK, psymtab_language);
> +
> + /* Using psymtab_langauge fixes commit 76fc0f62138e.
> + This file does not use buildsym-lecacy.
> + start_compunit_symtab () is never called.
> + get_current_subfile () will crash because
> + buildsym_compunit has never been initialized. */
> + b = new_block (objfile, NON_FUNCTION_BLOCK, psymtab_language,
> false);
> b->set_start (sh->value + top_stack->procadr);
> b->set_superblock (top_stack->cur_block);
> top_stack->cur_block = b;
> @@ -1247,7 +1262,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> f->set_loc_bitpos (sh->value);
> bitsize = 0;
> f->set_type (parse_type (cur_fd, ax, sh->index, &bitsize, bigend,
> - name));
> + name, false));
> f->set_bitsize (bitsize);
> }
> break;
> @@ -1269,7 +1284,7 @@ parse_symbol (SYMR *sh, union aux_ext *ax, char
> *ext_sh, int bigend,
> pend = is_pending_symbol (cur_fdr, ext_sh);
> if (pend == NULL)
> {
> - t = parse_type (cur_fd, ax, sh->index, NULL, bigend, name);
> + t = parse_type (cur_fd, ax, sh->index, NULL, bigend, name, true);
> add_pending (cur_fdr, ext_sh, t);
> }
> else
> @@ -1382,7 +1397,7 @@ basic_type (int bt, struct objfile *objfile)
> if (map_bt[bt])
> return map_bt[bt];
>
> - type_allocator alloc (objfile, get_current_subfile ()->language);
> + type_allocator alloc (objfile, psymtab_language);
>
> switch (bt)
> {
> @@ -1514,7 +1529,7 @@ basic_type (int bt, struct objfile *objfile)
>
> static struct type *
> parse_type (int fd, union aux_ext *ax, unsigned int aux_index, int *bs,
> - int bigend, const char *sym_name)
> + int bigend, const char *sym_name, bool is_stTypedef)
> {
> TIR t[1];
> struct type *tp = 0;
> @@ -1571,7 +1586,7 @@ parse_type (int fd, union aux_ext *ax, unsigned int
> aux_index, int *bs,
> }
> }
>
> - type_allocator alloc (mdebugread_objfile, get_current_subfile
> ()->language);
> + type_allocator alloc (mdebugread_objfile, psymtab_language);
>
> /* Move on to next aux. */
> ax++;
> @@ -1628,7 +1643,7 @@ parse_type (int fd, union aux_ext *ax, unsigned int
> aux_index, int *bs,
> xref_fh = get_rfd (fd, rf);
> xref_fd = xref_fh - debug_info->fdr;
> tp = parse_type (xref_fd, debug_info->external_aux +
> xref_fh->iauxBase,
> - rn->index, NULL, xref_fh->fBigendian, sym_name);
> + rn->index, NULL, xref_fh->fBigendian, sym_name, false);
> }
>
> /* All these types really point to some (common) MIPS type
> @@ -1785,6 +1800,13 @@ parse_type (int fd, union aux_ext *ax, unsigned int
> aux_index, int *bs,
> if (t->continued)
> complaint (_("illegal TIR continued for %s"), sym_name);
>
> + if (is_stTypedef)
> + {
> + struct type *wrap = alloc.new_type (TYPE_CODE_TYPEDEF, 0,
> sym_name);
> + wrap->set_target_type(tp);
> + tp = wrap;
> + }
> +
> return tp;
> }
>
> @@ -1839,7 +1861,7 @@ upgrade_type (int fd, struct type **tpp, int tq,
> union aux_ext *ax, int bigend,
>
> indx = parse_type (fh - debug_info->fdr,
> debug_info->external_aux + fh->iauxBase,
> - id, NULL, bigend, sym_name);
> + id, NULL, bigend, sym_name, false);
>
> /* The bounds type should be an integer type, but might be anything
> else due to corrupt aux entries. */
> @@ -2155,7 +2177,7 @@ parse_external (EXTR *es, int bigend, const
> section_offsets §ion_offsets,
>
> static void
> parse_lines (FDR *fh, PDR *pr, struct linetable *lt, int maxlines,
> - CORE_ADDR lowest_pdr_addr)
> + CORE_ADDR textlow, CORE_ADDR lowest_pdr_addr)
> {
> unsigned char *base;
> int j, k;
> @@ -2169,7 +2191,6 @@ parse_lines (FDR *fh, PDR *pr, struct linetable *lt,
> int maxlines,
> for (j = 0; j < fh->cpd; j++, pr++)
> {
> CORE_ADDR l;
> - CORE_ADDR adr;
> unsigned char *halt;
>
> /* No code for this one. */
> @@ -2186,9 +2207,15 @@ parse_lines (FDR *fh, PDR *pr, struct linetable
> *lt, int maxlines,
> halt = base + fh->cbLine;
> base += pr->cbLineOffset;
>
> - adr = pr->adr - lowest_pdr_addr;
> -
> - l = adr >> 2; /* in words */
> + /* textlow is the FDR->adr, for the file containing these PDRs.
> + FDR->adr is the absolute address of the lowest PDR.
> + PDR->adr's themselves, are relative offsets.
> + The PDR->adr's may start at 0, or they could have an offset
> + based on the PDRs position in an object file.
> + This is why the lowest PDR address is subtracted
> + from all other PDRs addresses, to subtract out the potential
> offset.
> + See bfd/ecofflink.c comments. */
> + l = (textlow + pr->adr - lowest_pdr_addr) >> 2; /* in
> words */
> for (lineno = pr->lnLow; base < halt;)
> {
> count = *base & 0x0f;
> @@ -3047,28 +3074,49 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> index into the namestring which indicates the
> debugging type symbol. */
>
> + int section;
> + bfd_vma address;
> +
> switch (p[1])
> {
> case 'S':
> + section = SECT_OFF_DATA (objfile);
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> pst->add_psymbol (gdb::string_view (namestring,
> p -
> namestring),
> true, VAR_DOMAIN, LOC_STATIC,
> - SECT_OFF_DATA (objfile),
> + section,
> psymbol_placement::STATIC,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> continue;
> case 'G':
> + section = SECT_OFF_DATA (objfile);
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and the
> offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> /* The addresses in these entries are reported
> to be wrong. See the code that reads 'G's
> for symtabs. */
> pst->add_psymbol (gdb::string_view (namestring,
> p -
> namestring),
> true, VAR_DOMAIN, LOC_STATIC,
> - SECT_OFF_DATA (objfile),
> + section,
> psymbol_placement::GLOBAL,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> continue;
> @@ -3215,12 +3263,21 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> function_outside_compilation_unit_complaint
> (copy.c_str ());
> }
> + section = SECT_OFF_TEXT (objfile);
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> pst->add_psymbol (gdb::string_view (namestring,
> p -
> namestring),
> true, VAR_DOMAIN, LOC_BLOCK,
> - SECT_OFF_TEXT (objfile),
> + section,
> psymbol_placement::STATIC,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> continue;
> @@ -3236,12 +3293,21 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> function_outside_compilation_unit_complaint
> (copy.c_str ());
> }
> + section = SECT_OFF_TEXT (objfile);
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> pst->add_psymbol (gdb::string_view (namestring,
> p -
> namestring),
> true, VAR_DOMAIN, LOC_BLOCK,
> - SECT_OFF_TEXT (objfile),
> + section,
> psymbol_placement::GLOBAL,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> continue;
> @@ -3419,6 +3485,9 @@ parse_partial_symbols (minimal_symbol_reader &reader,
> break;
> }
>
> + bfd_vma address;
> + /* some symbols don't use the above section */
> + int section_override;
> switch (sh.st)
> {
> unrelocated_addr high;
> @@ -3426,9 +3495,18 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> int new_sdx;
>
> case stStaticProc:
> - reader.record_with_info (sym_name, minsym_value,
> + section_override = SECT_OFF_TEXT (objfile);
> + address = (bfd_vma)minsym_value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section_override].the_bfd_section->vma;
> + }
> + reader.record_with_info (sym_name,
> (unrelocated_addr)address,
> mst_file_text,
> - SECT_OFF_TEXT (objfile));
> + section_override);
>
> /* FALLTHROUGH */
>
> @@ -3476,12 +3554,21 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> still able to find the PROGRAM name via the partial
> symbol table, and the MAIN__ symbol via the minimal
> symbol table. */
> +
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) & (EXEC_P
> | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and the
> offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> if (sh.st == stProc)
> pst->add_psymbol (sym_name, true,
> VAR_DOMAIN, LOC_BLOCK,
> section,
> psymbol_placement::GLOBAL,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> else
> @@ -3489,7 +3576,7 @@ parse_partial_symbols (minimal_symbol_reader &reader,
> VAR_DOMAIN, LOC_BLOCK,
> section,
> psymbol_placement::STATIC,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
>
> @@ -3517,13 +3604,36 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
>
> case stStatic: /* Variable */
> if (SC_IS_DATA (sh.sc))
> - reader.record_with_info (sym_name, minsym_value,
> + {
> + section_override = SECT_OFF_DATA (objfile);
> + address = 0;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section_override].the_bfd_section->vma;
> + }
> + reader.record_with_info (sym_name,
> (unrelocated_addr)(((bfd_vma)minsym_value + address)),
> mst_file_data,
> - SECT_OFF_DATA (objfile));
> + section_override);
> + }
> else
> - reader.record_with_info (sym_name, minsym_value,
> + {
> + section_override = SECT_OFF_BSS (objfile);
> + address = 0;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section_override].the_bfd_section->vma;
> + }
> + reader.record_with_info (sym_name,
> (unrelocated_addr)(((bfd_vma)minsym_value + address)),
> mst_file_bss,
> - SECT_OFF_BSS (objfile));
> + section_override);
> + }
> +
> theclass = LOC_STATIC;
> break;
>
> @@ -3596,11 +3706,19 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> cur_sdx++;
> continue;
> }
> + address = sh.value;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> /* Use this gdb symbol. */
> pst->add_psymbol (sym_name, true,
> VAR_DOMAIN, theclass, section,
> psymbol_placement::STATIC,
> - unrelocated_addr (sh.value),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> skip:
> @@ -3676,12 +3794,20 @@ parse_partial_symbols (minimal_symbol_reader
> &reader,
> theclass = LOC_STATIC;
> break;
> }
> + bfd_vma address = svalue;
> char *sym_name = debug_info->ssext + psh->iss;
> + if ((bfd_get_file_flags (objfile->obfd.get ()) &
> (EXEC_P | DYNAMIC)) == 0)
> + {
> + /* This is attempting to detect .o files.
> + Their sections are relocated in symfile.c
> default_symfile_offsets
> + but section_offsets are set to 0 there and
> the offset is put in the vma. */
> + address +=
> objfile->sections_start[section].the_bfd_section->vma;
> + }
> pst->add_psymbol (sym_name, true,
> VAR_DOMAIN, theclass,
> section,
> psymbol_placement::GLOBAL,
> - unrelocated_addr (svalue),
> + unrelocated_addr (address),
> psymtab_language,
> partial_symtabs, objfile);
> }
> @@ -4163,7 +4289,7 @@ mdebug_expand_psymtab (legacy_psymtab *pst, struct
> objfile *objfile)
> }
>
> parse_lines (fh, pr_block.data (), lines, maxlines,
> - lowest_pdr_addr);
> + (CORE_ADDR) pst->unrelocated_text_low (),
> lowest_pdr_addr);
> if (lines->nitems < fh->cline)
> lines = shrink_linetable (lines);
>
> @@ -4291,7 +4417,7 @@ cross_ref (int fd, union aux_ext *ax, struct type
> **tpp,
> rf = rn->rfd;
> }
>
> - type_allocator alloc (mdebugread_objfile, get_current_subfile
> ()->language);
> + type_allocator alloc (mdebugread_objfile, psymtab_language);
>
> /* mips cc uses a rf of -1 for opaque struct definitions.
> Set TYPE_STUB for these types so that check_typedef will
> @@ -4412,7 +4538,8 @@ cross_ref (int fd, union aux_ext *ax, struct type
> **tpp,
> sh.index,
> NULL,
> fh->fBigendian,
> - debug_info->ss + fh->issBase + sh.iss);
> + debug_info->ss + fh->issBase + sh.iss,
> + sh.st == stTypedef);
> add_pending (fh, esh, *tpp);
> break;
>
> @@ -4438,7 +4565,8 @@ cross_ref (int fd, union aux_ext *ax, struct type
> **tpp,
> sh.index,
> NULL,
> fh->fBigendian,
> - debug_info->ss + fh->issBase + sh.iss);
> + debug_info->ss + fh->issBase + sh.iss,
> + true);
> }
> else
> {
> @@ -4542,6 +4670,8 @@ add_line (struct linetable *lt, int lineno,
> CORE_ADDR adr, int last)
> return lineno;
>
> lt->item[lt->nitems].line = lineno;
> + lt->item[lt->nitems].is_stmt = 1;
> + lt->item[lt->nitems].prologue_end = 1;
> lt->item[lt->nitems++].set_unrelocated_pc (unrelocated_addr (adr << 2));
> return lineno;
> }
> @@ -4634,9 +4764,10 @@ new_symtab (const char *name, int maxlines, struct
> objfile *objfile)
>
> /* All symtabs must have at least two blocks. */
> bv = new_bvect (2);
> - bv->set_block (GLOBAL_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK,
> lang));
> - bv->set_block (STATIC_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK,
> lang));
> + bv->set_block (GLOBAL_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK,
> lang, true));
> + bv->set_block (STATIC_BLOCK, new_block (objfile, NON_FUNCTION_BLOCK,
> lang, false));
> bv->static_block ()->set_superblock (bv->global_block ());
> + bv->global_block ()->set_compunit_symtab(cust);
> cust->set_blockvector (bv);
>
> cust->set_debugformat ("ECOFF");
> @@ -4723,9 +4854,11 @@ new_bvect (int nblocks)
>
> static struct block *
> new_block (struct objfile *objfile, enum block_type type,
> - enum language language)
> + enum language language, bool is_global)
> {
> - struct block *retval = new (&objfile->objfile_obstack) block;
> + struct block *retval = (is_global
> + ? new (&objfile->objfile_obstack) global_block
> + : new (&objfile->objfile_obstack) block);
>
> if (type == FUNCTION_BLOCK)
> retval->set_multidict (mdict_create_linear_expandable (language));
> @@ -4754,8 +4887,7 @@ new_type (char *name)
> {
> struct type *t;
>
> - t = type_allocator (mdebugread_objfile,
> - get_current_subfile ()->language).new_type ();
> + t = type_allocator (mdebugread_objfile, psymtab_language).new_type ();
> t->set_name (name);
> INIT_CPLUS_SPECIFIC (t);
> return t;
> diff --git a/gdb/testsuite/boards/qemu-user.exp
> b/gdb/testsuite/boards/qemu-user.exp
> new file mode 100644
> index 00000000000..8a48ab7f6d4
> --- /dev/null
> +++ b/gdb/testsuite/boards/qemu-user.exp
> @@ -0,0 +1,267 @@
> +# Copyright 2020-2023 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/>.
> +
> +# NOTICE:
> +# QEMU user mode gdbstub has multithreading problems
> +# https://gitlab.com/qemu-project/qemu/-/issues/1671
> +# run with --ignore gdb.threads/access-mem-running-thread-exit.exp
> +# since this test in particular seems to hang. Could be related.
> +
> +# This technique is from native-extended-gdbserver.exp
> +# We must load this explicitly here, and rename the procedures we want
> +# to override. If we didn't do this, given that mi-support.exp is
> +# loaded later in the test files, the procedures loaded then would
> +# override our definitions.
> +load_lib mi-support.exp
> +
> +set qemu ""
> +set qemu_arch ""
> +set qemu_user_spawn_id ""
> +set qemu_user_last_load_file ""
> +set port "2345"
> +
> +# add sections for other architectures
> +# as needed
> +case "$target_triplet" in {
> + { "mips" } {
> + set qemu "qemu-mips"
> + set qemu_arch "mips"
> + }
> + default {
> + puts "No target hardware for $target_triplet"
> + }
> +}
> +
> +# QEMU supports some of extended-remote, but not the run command
> +# which causes problems for the test suite
> +set_board_info gdb_protocol "remote"
> +set_board_info use_gdb_stub 1
> +set_board_info gdb,do_reload_on_run 1
> +set_board_info exit_is_reliable 1
> +# static link so we do not need to configure an QEMU LD prefix and install
> +# libraries for the target architecture
> +set_board_info ldflags "-static"
> +
> +# technique from simavr.exp
> +#
> +# Load executable into GDB
> +#
> +proc gdb_load { arg } {
> + global gdb_prompt
> + global verbose
> + global spawn_id
> + global qemu
> + global qemu_user_last_load_file
> + global qemu_user_spawn_id
> + global port
> +
> + # keep track of last loaded file
> + # to simulate run restart like behavior
> + if { $arg == "" } {
> + set arg $qemu_user_last_load_file
> + if { $arg == "" } {
> + global last_loaded_file
> + # this fallback is needed
> + # for tests like gdb.base/break-unload-file.exp
> + set arg $last_loaded_file
> + }
> + } else {
> + set qemu_user_last_load_file $arg
> + }
> +
> + if { $arg != "" } {
> + if {[gdb_file_cmd $arg]} then { return -1 }
> + }
> +
> + # Close any previous qemu user instance.
> + if { $qemu_user_spawn_id != "" } {
> + verbose -log "qemu user: closing previous spawn id
> $qemu_user_spawn_id"
> + if [catch { close -i $qemu_user_spawn_id } != 0] {
> + warning "qemu user: failed to close connection to
> previous qemu user instance"
> + }
> +
> + # some tests get QEMU
> + # into a state where the process doesn't want to die
> + # so -nowait to not hang the entire test run
> + wait -nowait -i $qemu_user_spawn_id
> + set qemu_user_spawn_id ""
> + }
> +
> + # technique from gdbserver-support.exp
> + # Loop till we find a free port.
> + # This is to cope with qemu sometimes getting
> + # into a bad state and not closing.
> + # Do a pkill -f qemu-mips -9 after running tests
> + # to remove stragglers
> + while 1 {
> + # Run QEMU user
> + set cmd "spawn -noecho $qemu -g $port $arg"
> + verbose -log "Spawning qemu user: $cmd"
> + eval $cmd
> + set qemu_user_spawn_id $spawn_id
> +
> + # without inferior_spawn_id
> + # tests such as gdb.base/a2-run.exp
> + # can't look at the right process output
> + global inferior_spawn_id
> + set inferior_spawn_id $spawn_id
> +
> + expect {
> + -i $qemu_user_spawn_id
> + -timeout 1
> + -re ".*qemu: could not open gdbserver on.*" {
> + verbose -log "Port $port is already in
> use."
> + if [catch { close -i $qemu_user_spawn_id }
> != 0] {
> + warning "qemu user: failed to
> close connection to previous qemu user instance"
> + }
> + # Bump the port number to avoid the
> conflict.
> + wait -i $qemu_user_spawn_id
> + incr port
> + continue
> + }
> + }
> + break
> + }
> +
> + # arch needs set because some tests
> + # take actions that need arch to be correct
> + # immediately, before file command loads the binary
> + # for example gdb.base/break-unload-file.exp
> + global qemu_arch
> + send_gdb "set arch $qemu_arch\n"
> +
> + # Connect to qemu user.
> + send_gdb "target remote :$port\n"
> + gdb_expect {
> + # qemu user mode gdb stub does not support non stop mode
> + # this is so tests that attempt it die quickly
> + -re ".*Non-stop mode requested, but remote does not
> support non-stop.*" {
> + error "qemu user does not support non-stop"
> + }
> + # cannot have multiple targets connected
> + # some tests end up causing this to be attempted in
> gdb.multi
> + -re ".*Already connected to a remote target.
> Disconnect?.*" {
> + send_gdb "y\n"
> + gdb_expect {
> + -re ".*$gdb_prompt $" {
> + error "connected to new target
> while connected to existing"
> + }
> + }
> + }
> + -re ".*$gdb_prompt $" {
> + if $verbose>1 then {
> + send_user "Connected to QEMU target\n"
> + }
> + }
> + -re "Remote debugging using .*$gdb_prompt $" {
> + verbose "Set target to remote for QEMU"
> + }
> + timeout {
> + verbose -log "qemu-user: unable to connect to qemu
> user, closing qemu user spawn id"
> + close -i $qemu_user_spawn_id
> + verbose -log "qemu-user: unable to connect to qemu
> user, waiting for qemu user process exit"
> + wait -i $qemu_user_spawn_id
> + set qemu_user_spawn_id ""
> + error "unable to connect to qemu user stub"
> + }
> + }
> +
> + return 0
> +}
> +
> +# technique from native-extended-gdbserver.exp
> +# for overriding mi-support.exp procs
> +if { [info procs original_mi_gdb_load] == "" } {
> + rename mi_gdb_load original_gdbserver_mi_gdb_load
> +}
> +
> +# same ideas as gdb_load, but adapted for mi
> +proc mi_gdb_load { arg } {
> + global gdb_prompt
> + global verbose
> + global spawn_id
> + global qemu
> + global qemu_user_last_load_file
> + global qemu_user_spawn_id
> + global port
> +
> + if { $arg == "" } {
> + set arg $qemu_user_last_load_file
> + if { $arg == "" } {
> + global last_loaded_file
> + set arg $last_loaded_file
> + }
> + } else {
> + set qemu_user_last_load_file $arg
> + }
> +
> + if { $arg != "" } {
> + if {[mi_gdb_file_cmd $arg]} then { return -1 }
> + }
> +
> + #Close any previous qemu user instance.
> + if { $qemu_user_spawn_id != "" } {
> + verbose -log "qemu user: closing previous spawn id
> $qemu_user_spawn_id"
> + if [catch { close -i $qemu_user_spawn_id } != 0] {
> + warning "qemu user: failed to close previous qemu
> user instance"
> + }
> +
> + # some tests get QEMU/its gdb stub
> + # into a state where the process doesn't want to die
> + # so -nowait to not hang the entire test run
> + wait -nowait -i $qemu_user_spawn_id
> + set qemu_user_spawn_id ""
> + }
> +
> + # technique from gdbserver-support.exp
> + # Loop till we find a free port.
> + while 1 {
> + # Run QEMU user
> + set cmd "spawn -noecho $qemu -g $port $arg"
> + verbose -log "Spawning qemu user: $cmd"
> + eval $cmd
> + set qemu_user_spawn_id $spawn_id
> +
> + # without inferior_spawn_id
> + # tests such as gdb.base/a2-run.exp
> + # can't look at the right process output
> + global inferior_spawn_id
> + set inferior_spawn_id $spawn_id
> +
> + expect {
> + -i $qemu_user_spawn_id
> + -timeout 1
> + -re ".*qemu: could not open gdbserver on.*" {
> + verbose -log "Port $port is already in
> use."
> + if [catch { close -i $qemu_user_spawn_id }
> != 0] {
> + warning "qemu user: failed to
> close connection to previous qemu user instance"
> + }
> + # Bump the port number to avoid the
> conflict.
> + wait -i $qemu_user_spawn_id
> + incr port
> + continue
> + }
> + }
> + break
> + }
> +
> + return 0
> +}
> +
> +# technique from stdio-gdb-server-base.exp
> +proc mi_gdb_target_load { } {
> + global port
> + return [mi_gdb_target_cmd "remote" ":$port"]
> +}
> diff --git a/gdb/testsuite/gdb.mdebug/README
> b/gdb/testsuite/gdb.mdebug/README
> new file mode 100644
> index 00000000000..f749d3e1cbc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/README
> @@ -0,0 +1,67 @@
> +These tests are adapted for dealing with the limitations of old compilers
> and the mdebug format.
> +
> +Execute the mdebug tests with something like:
> +runtest gdb.mdebug/info-types-c.exp CC_FOR_TARGET=idowrapper MDEBUG=1
> --target mips --target_board qemu-user
> +
> +The CC_FOR_TARGET is probably going to be a wrapper script
> +for an old compiler running in an emulator.
> +Example at the end of this readme.
> +Put it somewhere in your PATH.
> +Do not give the path to the script as CC_FOR_TARGET, that does not work.
> +
> +The qemu-user board will run mips programs in qemu user mode
> +and connect gdb to QEMU's gdb stub.
> +
> +mdebug does not record line numbers for type definitions.
> +This is why the info types tests are modified
> +
> +mdebug output can be odd in how line mappings deal with the start of
> functions.
> +This is why the break tests are modified.
> +
> +Most compilers outputting mdebug data are so old they cannot deal with
> C99 features.
> +This makes parsing standard library headers for modern implementations a
> problem.
> +Also, even past that, the headers may eventually lead to compiler
> specific code
> +in things like stddef.h that may not be appriopriate for your old
> compiler.
> +This is why break.c has some modified standard function signatures at the
> beginning.
> +
> +A few of the break tests *sometimes* fail still.
> +Several memory initialization bugs were fixed but whatever is causing that
> +is very inconsistent. Or it could be some issue with the exp file.
> +
> +The best documentation on mdebug are these documents:
> +
> +"Tru64 UNIX Object File and Symbol Table Format Specification"
> +Sections 5, 9, and 10
> +Note, the word "mdebug" is never used, but it is that format
> +carried through from DEC to Compaq.
> +
> +"MIPS Mdebug Debugging Information" by David Anderson
> +
> +A wrapper script like this was used to create .o files with IDO running
> in an emulator.
> +The final link commands are run with regular linux gcc.
> +
> +#!/bin/sh
> +
> +echo "$@" >> theargs
> +
> +for arg do
> + if [ "$arg" = "-static" ]
> + then
> + link=1
> + fi
> +done
> +
> +if [ "$link" = 1 ]
> +then
> + mips-unknown-linux-gnu-gcc "$@" -fno-exceptions
> +else
> +for arg do
> + shift
> + [ "$arg" = "-fdiagnostics-color=never" ] && continue
> + [ "$arg" = "-g" ] && continue
> + set -- "$@" "$arg"
> +done
> +
> +/home/someuser/qemu-irix/build/irix-linux-user/qemu-irix -L
> /home/someuser/ido/ido7.1_compiler
> /home/someuser/ido/ido7.1_compiler/usr/bin/cc -Xcpluscomm -nostdlib
> -nostdinc -mips2
> +-g2 "$@" 2>/dev/null
> +fi
> diff --git a/gdb/testsuite/gdb.mdebug/break.c
> b/gdb/testsuite/gdb.mdebug/break.c
> new file mode 100644
> index 00000000000..d0b26998c77
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/break.c
> @@ -0,0 +1,92 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 1992-2023 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/>.
> */
> +
> +int printf (const char *__format, ...);
> +int fprintf (void *__stream, const char *__format, ...);
> +int atoi(const char *_Str);
> +void *malloc(int size);
> +
> +extern void * stderr;
> +
> +extern int marker1 (void);
> +extern int marker2 (int a);
> +extern void marker3 (char *a, char *b);
> +extern void marker4 (long d);
> +
> +/* We're used by a test that requires malloc, so make sure it is in
> + the executable. */
> +void *need_malloc ()
> +{
> + return malloc (1);
> +}
> +
> +/*
> + * This simple classical example of recursion is useful for
> + * testing stack backtraces and such.
> + */
> +
> +int factorial(int);
> +
> +int
> +main (int argc, char **argv, char **envp)
> +{ /* set breakpoint 6 here */
> + if (argc == 12345) { /* an unlikely value < 2^16, in case uninited */
> + fprintf (stderr, "usage: factorial <number>\n");
> + return 1;
> + }
> + printf ("%d\n", factorial (atoi ("6"))); /* set breakpoint 1 here */
> + /* set breakpoint 12 here */
> + marker1 (); /* set breakpoint 11 here */
> + marker2 (43); /* set breakpoint 20 here */
> + marker3 ("stack", "trace"); /* set breakpoint 21 here */
> + marker4 (177601976L);
> + /* We're used by a test that requires malloc, so make sure it is
> + in the executable. */
> + (void)malloc (1);
> +
> + argc = (argc == 12345); /* This is silly, but we can step off of it
> */ /* set breakpoint 2 here */
> + return argc; /* set breakpoint 10 here */
> +} /* set breakpoint 10a here */
> +
> +int factorial (int value)
> +{ /* set breakpoint 7 here */
> + if (value > 1) { /* set breakpoint 7a here */
> + value *= factorial (value - 1);
> + }
> + return (value); /* set breakpoint 19 here */
> +}
> +
> +int multi_line_if_conditional (int a, int b, int c)
> +{ /* set breakpoint 3 here */
> + if (a
> + && b
> + && c)
> + return 0;
> + else
> + return 1;
> +}
> +
> +int multi_line_while_conditional (int a, int b, int c)
> +{ /* set breakpoint 4 here */
> + while (a
> + && b
> + && c)
> + {
> + a--, b--, c--;
> + }
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.mdebug/break.exp
> b/gdb/testsuite/gdb.mdebug/break.exp
> new file mode 100644
> index 00000000000..cb74c1b0081
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/break.exp
> @@ -0,0 +1,921 @@
> +# Copyright 1988-2023 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 was written by Rob Savoye. (rob@cygnus.com)
> +
> +if { [build_executable "failed to prepare" "break" {break.c break1.c}
> {debug nowarnings}] } {
> + return -1
> +}
> +set srcfile break.c
> +set srcfile1 break1.c
> +
> +set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
> +set bp_location2 [gdb_get_line_number "set breakpoint 2 here"]
> +set bp_location3 [gdb_get_line_number "set breakpoint 3 here"]
> +set bp_location4 [gdb_get_line_number "set breakpoint 4 here"]
> +set bp_location6 [gdb_get_line_number "set breakpoint 6 here"]
> +set bp_location7 [gdb_get_line_number "set breakpoint 7 here"]
> +set bp_location8 [gdb_get_line_number "set breakpoint 8 here" $srcfile1]
> +set bp_location11 [gdb_get_line_number "set breakpoint 11 here"]
> +
> +set main_line $bp_location6
> +
> +# In C++ mode, we see a full prototype; in C mode, we only see the
> +# function name, with no parameter info.
> +proc func {name} {
> + return "${name}(?:\(\[^\r\n\]*\))?"
> +}
> +
> +# test simple breakpoint setting commands
> +
> +proc_with_prefix test_break {} {
> + clean_restart break
> +
> + # Test deleting all breakpoints when there are none installed,
> + # GDB should not prompt for confirmation.
> + # Note that lib/gdb.exp provides a "delete_breakpoints" proc
> + # for general use elsewhere.
> + send_gdb "delete breakpoints\n"
> + gdb_expect {
> + -re "Delete all breakpoints.*$" {
> + send_gdb "y\n"
> + gdb_expect {
> + -re "$::gdb_prompt $" {
> + fail "delete all breakpoints when none (unexpected
> prompt)"
> + }
> + timeout { fail "delete all breakpoints when none
> (timeout after unexpected prompt)" }
> + }
> + }
> + -re ".*$::gdb_prompt $" { pass "delete all breakpoints when
> none" }
> + timeout { fail "delete all breakpoints when none
> (timeout)" }
> + }
> +
> + # test break at function
> + gdb_test "break -q main" \
> + "Breakpoint.*at.* file .*$::srcfile, line.*" \
> + "breakpoint function"
> +
> + # test break at quoted function
> + gdb_test "break \"marker2\"" \
> + "Breakpoint.*at.* file .*$::srcfile1, line.*" \
> + "breakpoint quoted function"
> +
> + # test break at function in file
> + gdb_test "break $::srcfile:factorial" \
> + "Breakpoint.*at.* file .*$::srcfile, line.*" \
> + "breakpoint function in file"
> +
> + # test break at line number
> + #
> + # Note that the default source file is the last one whose source text
> + # was printed. For native debugging, before we've executed the
> + # program, this is the file containing main, but for remote debugging,
> + # it's wherever the processor was stopped when we connected to the
> + # board. So, to be sure, we do a list command.
> + gdb_test "list -q main" \
> + ".*main \\(int argc, char \\*\\*argv, char \\*\\*envp\\).*" \
> + "use `list' to establish default source file"
> +
> + gdb_test "break $::bp_location1" \
> + "Breakpoint.*at.* file .*$::srcfile, line $::bp_location1\\." \
> + "breakpoint line number"
> +
> + # test duplicate breakpoint
> + gdb_test "break $::bp_location1" \
> + "Note: breakpoint \[0-9\]+ also set at pc.*Breakpoint \[0-9\]+
> at.* file .*$::srcfile, line $::bp_location1\\." \
> + "breakpoint duplicate"
> +
> + # test break at line number in file
> + gdb_test "break $::srcfile:$::bp_location2" \
> + "Breakpoint.*at.* file .*$::srcfile, line $::bp_location2\\." \
> + "breakpoint line number in file"
> +
> + # Test putting a break at the start of a multi-line if conditional.
> + # Verify the breakpoint was put at the start of the conditional.
> + gdb_test "break multi_line_if_conditional" \
> + "Breakpoint.*at.* file .*$::srcfile, line $::bp_location3\\." \
> + "breakpoint at start of multi line if conditional"
> +
> + gdb_test "break multi_line_while_conditional" \
> + "Breakpoint.*at.* file .*$::srcfile, line $::bp_location4\\." \
> + "breakpoint at start of multi line while conditional"
> +
> + gdb_test "info break" \
> + [multi_line "Num Type\[ \]+Disp Enb Address\[ \]+What.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> main] at .*$::srcfile:$::main_line.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> marker2] at .*$::srcfile1:$::bp_location8.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> factorial] at .*$::srcfile:$::bp_location7.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> main] at .*$::srcfile:$::bp_location1.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> main] at .*$::srcfile:$::bp_location1.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> main] at .*$::srcfile:$::bp_location2.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> multi_line_if_conditional] at .*$::srcfile:$::bp_location3.*" \
> + "$::decimal\[\t \]+breakpoint keep y.* in [func
> multi_line_while_conditional] at .*$::srcfile:$::bp_location4"] \
> + "breakpoint info"
> +
> + #
> + # Test info breakpoint with arguments
> + #
> +
> + set see1 0
> + set see2 0
> + set see3 0
> + set see4 0
> + set see5 0
> + set see6 0
> +
> + gdb_test_multiple "info break 2 4 6" "info break 2 4 6" {
> + -re "1\[\t \]+breakpoint *keep y\[^\r\n\]*:$::main_line\[^\r\n\]*"
> {
> + set see1 1
> + exp_continue
> + }
> + -re "2\[\t \]+breakpoint *keep y\[^\r\n\]* in [func marker2] at
> \[^\r\n\]*" {
> + set see2 1
> + exp_continue
> + }
> + -re "3\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location7\[^\r\n\]*" {
> + set see3 1
> + exp_continue
> + }
> + -re "4\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see4 1
> + exp_continue
> + }
> + -re "5\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see5 1
> + exp_continue
> + }
> + -re "6\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location2\[^\r\n\]*" {
> + set see6 1
> + exp_continue
> + }
> + -re ".*$::gdb_prompt $" {
> + if {!$see1 && $see2 && !$see3 && $see4 && !$see5 && $see6} {
> + pass "info break 2 4 6"
> + } else {
> + fail "info break 2 4 6"
> + }
> + }
> + }
> +
> + set see1 0
> + set see2 0
> + set see3 0
> + set see4 0
> + set see5 0
> + set see6 0
> +
> + gdb_test_multiple "info break 3-5" "info break 3-5" {
> + -re "1\[\t \]+breakpoint *keep y.* in [func main] at
> .*:$::main_line\[^\r\n\]*" {
> + set see1 1
> + exp_continue
> + }
> + -re "2\[\t \]+breakpoint *keep y\[^\r\n\]* in [func marker2] at
> \[^\r\n\]*" {
> + set see2 1
> + exp_continue
> + }
> + -re "3\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location7\[^\r\n\]*" {
> + set see3 1
> + exp_continue
> + }
> + -re "4\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see4 1
> + exp_continue
> + }
> + -re "5\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see5 1
> + exp_continue
> + }
> + -re "6\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location2\[^\r\n\]*" {
> + set see6 1
> + exp_continue
> + }
> + -re ".*$::gdb_prompt $" {
> + if {!$see1 && !$see2 && $see3 && $see4 && $see5 && !$see6} {
> + pass "info break 3-5"
> + } else {
> + fail "info break 3-5"
> + }
> + }
> + }
> +
> + #
> + # Test disable/enable with arguments
> + #
> +
> + # Test with value history
> +
> + with_test_prefix "with value history" {
> + gdb_test "print 1"
> + gdb_test "print 2"
> + gdb_test "print 3"
> + gdb_test "print 4"
> + gdb_test "print 5"
> + gdb_test "print 6"
> +
> + # $2 is 2 and $$ is 5
> + gdb_test_no_output "disable \$2 \$\$" "disable using history
> values"
> +
> + set see1 0
> + set see2 0
> + set see3 0
> + set see4 0
> + set see5 0
> + set see6 0
> +
> + gdb_test_multiple "info break" "check disable with history values"
> {
> + -re "1\[\t \]+breakpoint *keep y.* in [func main] at
> .*:$::main_line\[^\r\n\]*" {
> + set see1 1
> + exp_continue
> + }
> + -re "2\[\t \]+breakpoint *keep n\[^\r\n\]* in [func marker2]
> at \[^\r\n\]*" {
> + set see2 1
> + exp_continue
> + }
> + -re "3\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location7\[^\r\n\]*" {
> + set see3 1
> + exp_continue
> + }
> + -re "4\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see4 1
> + exp_continue
> + }
> + -re "5\[\t \]+breakpoint *keep
> n\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see5 1
> + exp_continue
> + }
> + -re "6\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location2\[^\r\n\]*" {
> + set see6 1
> + exp_continue
> + }
> + -re ".*$::gdb_prompt $" {
> + if {$see1 && $see2 && $see3 && $see4 && $see5 && $see6} {
> + pass "check disable with history values"
> + } else {
> + fail "check disable with history values"
> + }
> + }
> + }
> + }
> +
> + with_test_prefix "with convenience vars" {
> + gdb_test "enable"
> + gdb_test "set \$foo = 3"
> + gdb_test "set \$bar = 6"
> + gdb_test_no_output "disable \$foo \$bar" "disable with convenience
> values"
> +
> + set see1 0
> + set see2 0
> + set see3 0
> + set see4 0
> + set see5 0
> + set see6 0
> +
> + gdb_test_multiple "info break" "check disable with convenience
> values" {
> + -re "1\[\t \]+breakpoint *keep y.* in [func main] at
> .*:$::main_line\[^\r\n\]*" {
> + set see1 1
> + exp_continue
> + }
> + -re "2\[\t \]+breakpoint *keep y\[^\r\n\]* in [func marker2]
> at \[^\r\n\]*" {
> + set see2 1
> + exp_continue
> + }
> + -re "3\[\t \]+breakpoint *keep
> n\[^\r\n\]*$::bp_location7\[^\r\n\]*" {
> + set see3 1
> + exp_continue
> + }
> + -re "4\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see4 1
> + exp_continue
> + }
> + -re "5\[\t \]+breakpoint *keep
> y\[^\r\n\]*$::bp_location1\[^\r\n\]*" {
> + set see5 1
> + exp_continue
> + }
> + -re "6\[\t \]+breakpoint *keep
> n\[^\r\n\]*$::bp_location2\[^\r\n\]*" {
> + set see6 1
> + exp_continue
> + }
> + -re ".*$::gdb_prompt $" {
> + if {$see1 && $see2 && $see3 && $see4 && $see5 && $see6} {
> + pass "check disable with convenience values"
> + } else {
> + fail "check disable with convenience values"
> + }
> + }
> + }
> + }
> +
> + # test with bad values
> +
> + with_test_prefix "bad values" {
> + gdb_test "enable"
> + gdb_test "disable 10" "No breakpoint number 10." \
> + "disable non-existent breakpoint 10"
> +
> + gdb_test_no_output "set \$baz = 1.234"
> + gdb_test "disable \$baz" \
> + "Convenience variable must have integer value.*" \
> + "disable with non-integer convenience var"
> + gdb_test "disable \$grbx" \
> + "Convenience variable must have integer value.*" \
> + "disable with non-existent convenience var"
> + gdb_test "disable \$10" \
> + "History has not yet reached .10." \
> + "disable with non-existent history value"
> + gdb_test "disable \$1foo" \
> + "Convenience variable must have integer value.*" \
> + "disable with badly formed history value"
> + }
> +
> + # FIXME: The rest of this test doesn't work with anything that can't
> + # handle arguments.
> + # Huh? There doesn't *appear* to be anything that passes arguments
> + # below.
> +
> + #
> + # run until the breakpoint at main is hit. For non-stubs-using
> targets.
> + #
> + gdb_run_cmd
> + gdb_test "" \
> + "Breakpoint \[0-9\]+,.*main .*argc.*argv.* at
> .*$::srcfile:$::bp_location6.*$::bp_location6\[\t \]+\{.*" \
> + "run until function breakpoint"
> +
> + # Test the 'list' commands sets current file for the 'break LINENO'
> command.
> + set bp_marker1 [gdb_get_line_number "set breakpoint 15 here"
> $::srcfile1]
> + gdb_test "list marker1" ".*"
> + gdb_test "break $bp_marker1" "Breakpoint \[0-9\]+ at 0x\[0-9a-f\]+:
> file .*$::srcfile1, line ${bp_marker1}\\." \
> + "break lineno"
> + gdb_test_no_output {delete $bpnum}
> +
> + #
> + # run until the breakpoint at a line number
> + #
> + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, main
> \\(argc=.*, argv=.*, envp=.*\\) at
> .*$::srcfile:$::bp_location1.*$::bp_location1\[\t \]+printf.*factorial.*" \
> + "run until breakpoint set at a line number"
> +
> + #
> + # Run until the breakpoint set in a function in a file
> + #
> + set bp_location7a [gdb_get_line_number "set breakpoint 7a here"]
> + send_gdb "del 3\n"
> + send_gdb "del 7\n"
> + gdb_test "break $bp_location7a" \
> + "Breakpoint.*at.* file .*$::srcfile, line $bp_location7a\\." \
> + "setting breakpoint at 7a"
> +
> + for {set i 6} {$i >= 1} {incr i -1} {
> + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+,
> factorial \\(value=$i\\) at .*$::srcfile:$bp_location7a.*$bp_location7a\[\t
> \]+.*if .value > 1. \{.*" \
> + "run until file:function($i) breakpoint"
> + }
> +
> + send_gdb "break $::bp_location3\n"
> +
> + send_gdb "break $::bp_location7\n"
> +
> + send_gdb "del 2\n"
> +
> + #
> + # run until the file:function breakpoint at a line number in a file
> + #
> + gdb_test continue "Continuing\\..*Breakpoint \[0-9\]+, main
> \\(argc=.*, argv=.*, envp=.*\\) at
> .*$::srcfile:$::bp_location2.*$::bp_location2\[\t \]+argc = \\(argc ==
> 12345\\);.*" \
> + "run until file:linenum breakpoint"
> +
> + # Test break at offset +1
> + set bp_location10 [gdb_get_line_number "set breakpoint 10 here"]
> +
> + gdb_test "break +1" \
> + "Breakpoint.*at.* file .*$::srcfile, line $bp_location10\\." \
> + "breakpoint offset +1"
> +
> + # Check to see if breakpoint is hit when stepped onto
> +
> + gdb_test "step" \
> + ".*Breakpoint \[0-9\]+, main \\(argc=.*, argv=.*, envp=.*\\) at
> .*$::srcfile:$bp_location10.*$bp_location10\[\t \]+return argc;.*breakpoint
> 10 here.*" \
> + "step onto breakpoint"
> +}
> +
> +test_break
> +
> +proc_with_prefix test_tbreak {} {
> + clean_restart break
> +
> + # test temporary breakpoint at function
> + gdb_test "tbreak -q main" "Temporary breakpoint.*at.* file
> .*$::srcfile, line.*" "temporary breakpoint function"
> +
> + # test break at function in file
> + gdb_test "tbreak $::srcfile:factorial" "Temporary breakpoint.*at.*
> file .*$::srcfile, line.*" \
> + "Temporary breakpoint function in file"
> +
> + # test break at line number
> + gdb_test "tbreak $::bp_location1" \
> + "Temporary breakpoint.*at.* file .*$::srcfile, line
> $::bp_location1.*" \
> + "temporary breakpoint line number #1"
> +
> + gdb_test "tbreak $::bp_location6" "Temporary breakpoint.*at.* file
> .*$::srcfile, line $::bp_location6.*" "temporary breakpoint line number #2"
> +
> + # test break at line number in file
> + gdb_test "tbreak $::srcfile:$::bp_location2" \
> + "Temporary breakpoint.*at.* file .*$::srcfile, line
> $::bp_location2.*" \
> + "temporary breakpoint line number in file #1"
> +
> + gdb_test "tbreak $::srcfile:$::bp_location11" "Temporary
> breakpoint.*at.* file .*$::srcfile, line $::bp_location11.*" "Temporary
> breakpoint line number in file #2"
> +
> + # check to see what breakpoints are set (temporary this time)
> + gdb_test "info break" \
> + [multi_line "Num Type.*Disp Enb Address.*What.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> main] at .*$::srcfile:$::main_line.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> factorial] at .*$::srcfile:$::bp_location7.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> main] at .*$::srcfile:$::bp_location1.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> main] at .*$::srcfile:$::bp_location6.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> main] at .*$::srcfile:$::bp_location2.*" \
> + "$::decimal\[\t \]+breakpoint del.*y.*in [func
> main] at .*$::srcfile:$::bp_location11.*"] \
> + "Temporary breakpoint info"
> +}
> +
> +test_tbreak
> +
> +# Verify that GDB responds gracefully when asked to set a breakpoint
> +# on a nonexistent source line.
> +
> +proc_with_prefix test_break_nonexistent_line {} {
> + clean_restart break
> +
> + if {![runto_main]} {
> + return
> + }
> +
> + gdb_test_no_output "set breakpoint pending off"
> + gdb_test "break 999" \
> + "No line 999 in the current file." \
> + "break on non-existent source line"
> +}
> +
> +test_break_nonexistent_line
> +
> +proc_with_prefix test_break_default {} {
> + clean_restart break
> +
> + if {![runto_main]} {
> + return
> + }
> +
> + # Run to the desired default location. If not positioned here, the
> + # tests below don't work.
> + #
> + gdb_test "until $::bp_location1" "main .* at .*:$::bp_location1.*" \
> + "until bp_location1"
> +
> + # Verify that GDB allows one to just say "break", which is treated
> + # as the "default" breakpoint. Note that GDB gets cute when printing
> + # the informational message about other breakpoints at the same
> + # location. We'll hit that bird with this stone too.
> + #
> + gdb_test "break" "Breakpoint \[0-9\]*.*" \
> + "break on default location, 1st time"
> +
> + gdb_test "break" \
> + "Note: breakpoint \[0-9\]* also set at .*Breakpoint \[0-9\]*.*" \
> + "break on default location, 2nd time"
> +
> + gdb_test "break" \
> + "Note: breakpoints \[0-9\]* and \[0-9\]* also set at .*Breakpoint
> \[0-9\]*.*" \
> + "break on default location, 3rd time"
> +
> + gdb_test "break" \
> + "Note: breakpoints \[0-9\]*, \[0-9\]* and \[0-9\]* also set at
> .*Breakpoint \[0-9\]*.*" \
> + "break on default location, 4th time"
> +
> + # Check setting a breakpoint at the default location with a condition
> attached.
> + gdb_test "break if (1)" \
> + "Note: breakpoints \[0-9\]*, \[0-9\]*, \[0-9\]* and \[0-9\]* also
> set at .*Breakpoint \[0-9\]*.*" \
> + "break on the default location, 5th time, but with a condition"
> +}
> +
> +test_break_default
> +
> +# Verify that a "silent" breakpoint can be set, and that GDB is indeed
> +# "silent" about its triggering.
> +
> +proc_with_prefix test_break_silent_and_more {} {
> + clean_restart break
> +
> + if {![runto_main]} {
> + return
> + }
> +
> + gdb_test_multiple "break $::bp_location1" \
> + "set to-be-silent break bp_location1" {
> + -re "Breakpoint (\[0-9\]*) at .*, line
> $::bp_location1.*$::gdb_prompt $" {
> + set bpno $expect_out(1,string)
> + pass "set to-be-silent break bp_location1"
> + }
> + }
> +
> + gdb_test "commands $bpno\nsilent\nend" ">end" "set silent break
> bp_location1"
> +
> + gdb_test "info break $bpno" \
> + "\[0-9\]*\[ \t\]*breakpoint.*:$::bp_location1\r\n\[ \t\]*silent.*"
> \
> + "info silent break bp_location1"
> +
> + gdb_test "continue" "Continuing." \
> + "hit silent break bp_location1"
> +
> + gdb_test "bt" "#0 main .* at .*:$::bp_location1.*" \
> + "stopped for silent break bp_location1"
> +
> + # Verify the $_hit_bpnum convenience variable is set to the silent
> hit bpno.
> + gdb_test "printf \"%d\\n\", \$_hit_bpnum" "$bpno" \
> + "Silent breakpoint hit \$_hit_bpnum is silent $bpno"
> +
> + # Verify that GDB can at least parse a breakpoint with the
> + # "thread" keyword. (We won't attempt to test here that a
> + # thread-specific breakpoint really triggers appropriately.
> + # The gdb.threads subdirectory contains tests for that.)
> + #
> + set bp_location12 [gdb_get_line_number "set breakpoint 12 here"]
> + gdb_test "break $bp_location12 thread 999" "Unknown thread 999.*" \
> + "thread-specific breakpoint on non-existent thread disallowed"
> +
> + gdb_test "break $bp_location12 thread foo" \
> + "Invalid thread ID: foo" \
> + "thread-specific breakpoint on bogus thread ID disallowed"
> +
> + # Verify that GDB responds gracefully to a breakpoint command with
> + # trailing garbage.
> + #
> + gdb_test "break $bp_location12 foo" \
> + "malformed linespec error: unexpected string, \"foo\".*" \
> + "breakpoint with trailing garbage disallowed"
> +
> + # Verify that GDB responds gracefully to a "clear" command that has
> + # no matching breakpoint. (First, get us off the current source line,
> + # which we know has a breakpoint.)
> + #
> + gdb_test "next" "marker1.*" "step over breakpoint"
> +
> + gdb_test "clear 81" "No breakpoint at 81.*" \
> + "clear line has no breakpoint disallowed"
> +
> + gdb_test "clear" "No breakpoint at this line.*" \
> + "clear current line has no breakpoint disallowed"
> +
> + # Verify that we can set and clear multiple breakpoints.
> + #
> + # We don't test that it deletes the correct breakpoints. We do at
> + # least test that it deletes more than one breakpoint.
> + #
> + gdb_test "break marker3" "Breakpoint.*at.*" "break marker3 #1"
> + gdb_test "break marker3" "Breakpoint.*at.*" "break marker3 #2"
> + gdb_test "clear marker3" {Deleted breakpoints [0-9]+ [0-9]+.*}
> +}
> +
> +test_break_silent_and_more
> +
> +# Verify that a breakpoint can be set via a convenience variable.
> +
> +proc_with_prefix test_break_line_convenience_var {} {
> + clean_restart break
> +
> + if { ![runto_main] } {
> + return
> + }
> +
> + gdb_test_no_output "set \$foo=$::bp_location11" \
> + "set convenience variable \$foo to bp_location11"
> +
> + gdb_test "break \$foo" \
> + "Breakpoint (\[0-9\]*) at .*, line $::bp_location11.*"
> +
> + # Verify that GDB responds gracefully to an attempt to set a
> + # breakpoint via a convenience variable whose type is not integer.
> +
> + gdb_test_no_output "set \$foo=81.5" \
> + "set convenience variable \$foo to 81.5"
> +
> + gdb_test "break \$foo" \
> + "Convenience variables used in line specs must have integer
> values.*" \
> + "non-integer convenience variable disallowed"
> +}
> +
> +test_break_line_convenience_var
> +
> +# Verify that we can set and trigger a breakpoint in a user-called
> function.
> +
> +proc_with_prefix test_break_user_call {} {
> + clean_restart break
> +
> + if { ![runto_main] } {
> + return
> + }
> +
> + gdb_test "break marker2" \
> + "Breakpoint (\[0-9\]*) at .*, line $::bp_location8.*" \
> + "set breakpoint on to-be-called function"
> +
> + gdb_test "print marker2(99)" \
> + "The program being debugged stopped while in a function called
> from GDB.\r\nEvaluation of the expression containing the function\r\n.[func
> marker2]. will be abandoned.\r\nWhen the function is done executing, GDB
> will silently stop.*" \
> + "hit breakpoint on called function"
> +
> + # As long as we're stopped (breakpointed) in a called function,
> + # verify that we can successfully backtrace & such from here.
> + gdb_test "bt" \
> + "#0\[ \t\]*($::hex in )?marker2.*:$::bp_location8\r\n#1\[
> \t\]*<function called from gdb>.*" \
> + "backtrace while in called function"
> +
> + # Return from the called function. For remote targets, it's
> important to do
> + # this before runto_main, which otherwise may silently stop on the
> dummy
> + # breakpoint inserted by GDB at the program's entry point.
> + #
> + gdb_test_multiple "finish" "finish from called function" {
> + -re "Run till exit from .*marker2.* at
> .*$::bp_location8\r\n.*function called from gdb.*$::gdb_prompt $" {
> + pass "finish from called function"
> + }
> + -re "Run till exit from .*marker2.* at
> .*$::bp_location8\r\n.*Value returned.*$::gdb_prompt $" {
> + pass "finish from called function"
> + }
> + }
> +}
> +
> +test_break_user_call
> +
> +# Verify that GDB responds gracefully to a "finish" command with
> +# arguments.
> +
> +proc_with_prefix test_finish_arguments {} {
> + clean_restart break
> +
> + if {![runto_main]} {
> + return
> + }
> +
> + send_gdb "finish 123\n"
> + gdb_expect {
> + -re "The \"finish\" command does not take any
> arguments.\r\n$::gdb_prompt $"\
> + {pass "finish with arguments disallowed"}
> + -re "$::gdb_prompt $"\
> + {fail "finish with arguments disallowed"}
> + timeout {fail "(timeout) finish with arguments disallowed"}
> + }
> +
> + # Verify that GDB responds gracefully to a request to "finish" from
> + # the outermost frame. On a stub that never exits, this will just
> + # run to the stubs routine, so we don't get this error... Thus the
> + # second condition.
> + #
> +
> + gdb_test_multiple "finish" "finish from outermost frame disallowed" {
> + -re "\"finish\" not meaningful in the outermost
> frame.\r\n$::gdb_prompt $" {
> + pass "finish from outermost frame disallowed"
> + }
> + -re "Run till exit from.*\r\n$::gdb_prompt $" {
> + pass "finish from outermost frame disallowed"
> + }
> + }
> +}
> +
> +test_finish_arguments
> +
> +#********
> +
> +
> +#
> +# Test "next" over recursive function call.
> +#
> +
> +proc_with_prefix test_next_with_recursion {} {
> + global gdb_prompt
> + global decimal
> + global binfile
> +
> + gdb_test "kill" "" "kill program" "Kill the program being debugged.*y
> or n. $" "y"
> + delete_breakpoints
> +
> + set bp_location7a [gdb_get_line_number "set breakpoint 7a here"]
> + gdb_test "break $bp_location7a" \
> + "Breakpoint.*at.* file .*$::srcfile, line $bp_location7a\\." \
> + "setting breakpoint at 7a"
> +
> + # Run until we call factorial with 6
> +
> + gdb_run_cmd
> + gdb_test "" "Break.* factorial .value=6. .*" "run to factorial(6)"
> +
> + # Continue until we call factorial recursively with 5.
> +
> + gdb_test "continue" \
> + "Continuing.*Break.* factorial .value=5. .*" \
> + "continue to factorial(5)"
> +
> + # Do a backtrace just to confirm how many levels deep we are.
> +
> + gdb_test "backtrace" \
> + "#0\[ \t\]+ factorial .value=5..*" \
> + "backtrace from factorial(5)"
> +
> + # Now a "next" should position us at the recursive call, which
> + # we will be performing with 4.
> +
> + gdb_test "next" \
> + ".* factorial .value - 1.;.*" \
> + "next to recursive call"
> +
> + # Disable the breakpoint at the entry to factorial by deleting them
> all.
> + # The "next" should run until we return to the next line from this
> + # recursive call to factorial with 4.
> + # Buggy versions of gdb will stop instead at the innermost frame on
> + # the line where we are trying to "next" to.
> +
> + delete_breakpoints
> +
> + if [istarget "mips*tx39-*"] {
> + set timeout 60
> + }
> + # We used to set timeout here for all other targets as well. This
> + # is almost certainly wrong. The proper timeout depends on the
> + # target system in use, and how we communicate with it, so there
> + # is no single value appropriate for all targets. The timeout
> + # should be established by the Dejagnu config file(s) for the
> + # board, and respected by the test suite.
> + #
> + # For example, if I'm running GDB over an SSH tunnel talking to a
> + # portmaster in California talking to an ancient 68k board running
> + # a crummy ROM monitor (a situation I can only wish were
> + # hypothetical), then I need a large timeout. But that's not the
> + # kind of knowledge that belongs in this file.
> +
> + gdb_test next "\[0-9\]*\[\t \]+return \\(value\\);.*" \
> + "next over recursive call"
> +
> + # OK, we should be back in the same stack frame we started from.
> + # Do a backtrace just to confirm.
> +
> + gdb_test "backtrace" \
> + "#0\[ \t\]+ factorial .value=120.*\r\n#1\[ \t\]+ \[0-9a-fx\]+
> in factorial .value=6..*" \
> + "backtrace from factorial(5.1)"
> +
> + if { ![target_info exists gdb,noresults] } {
> + gdb_continue_to_end "recursive next test"
> + }
> +}
> +
> +test_next_with_recursion
> +
> +
> +#********
> +
> +# build a new file with optimization enabled so that we can try
> breakpoints
> +# on targets with optimized prologues
> +
> +if { [build_executable "failed to prepare" "breako2" {break.c break1.c}
> {debug nowarnings optimize=-O2}] } {
> + return -1
> +}
> +
> +proc_with_prefix test_break_optimized_prologue {} {
> + clean_restart breako2
> +
> + # test break at function
> + gdb_test "break -q main" \
> + "Breakpoint.*at.* file .*, line.*" \
> + "breakpoint function, optimized file"
> +
> + # test break at function
> + gdb_test "break marker4" \
> + "Breakpoint.*at.* file .*$::srcfile1, line.*" \
> + "breakpoint small function, optimized file"
> +
> + # run until the breakpoint at main is hit. For non-stubs-using
> targets.
> + gdb_run_cmd
> +
> + set test "run until function breakpoint, optimized file"
> + gdb_test_multiple "" $test {
> + -re "Breakpoint \[0-9\]+,.*main .*argc.*argv.* at
> .*$::srcfile:$::bp_location6.*$::bp_location6\[\t \]+\{ if .argc.*
> \{.*$::gdb_prompt $" {
> + pass $test
> + }
> + -re "Breakpoint \[0-9\]+,.*main .*argc.*argv.* at .*$::gdb_prompt
> $" {
> + pass "$test (code motion)"
> + }
> + }
> +
> + # run until the breakpoint at a small function
> + #
> + # Add a second pass pattern. The behavior differs here between stabs
> + # and dwarf for one-line functions. Stabs preserves two line symbols
> + # (one before the prologue and one after) with the same line number,
> + # but dwarf regards these as duplicates and discards one of them.
> + # Therefore the address after the prologue (where the breakpoint is)
> + # has no exactly matching line symbol, and GDB reports the breakpoint
> + # as if it were in the middle of a line rather than at the beginning.
> +
> + set bp_location14 [gdb_get_line_number "set breakpoint 14 here"
> $::srcfile1]
> +
> + gdb_test_multiple "continue" \
> + "run until breakpoint set at small function, optimized file" {
> + -re "Breakpoint $::decimal, marker4 \\(d=(d@entry=)?177601976\\)
> at .*$::srcfile1:$bp_location14\[\r\n\]+$bp_location14\[\t \]+void
> marker4.*" {
> + pass "run until breakpoint set at small function,
> optimized file (line bp_location14)"
> + }
> + -re "Breakpoint $::decimal, factorial \\(.*\\)
> .*\{\r\n$::gdb_prompt" {
> + # GCC 4.3 emits bad line number information - see
> gcc/36748.
> + if { [test_compiler_info "gcc-4-3-*"] } {
> + setup_xfail *-*-*
> + }
> + fail "run until breakpoint set at small function,
> optimized file"
> + }
> + }
> +}
> +
> +test_break_optimized_prologue
> +
> +# test that 'rbreak' on a symbol that may be from a shared library doesn't
> +# cause a "Junk at end of arguments." error.
> +#
> +# On x86 GNU/Linux, this test will choke on e.g. __libc_start_main@plt.
> +#
> +# Note that this test won't necessarily choke on all targets even if
> +# all the rbreak issue is present. rbreak needs to match and set a
> +# breakpoint on a symbol causes 'break' to choke.
> +
> +proc_with_prefix test_rbreak_shlib {} {
> + clean_restart breako2
> +
> + gdb_test_no_output "set breakpoint pending on" "rbreak junk pending
> setup"
> +
> + # We expect at least one breakpoint to be set when we "rbreak main".
> + gdb_test "rbreak main" \
> + ".*Breakpoint.*at.* file .*$::srcfile, line.*"
> +
> + # Run to a breakpoint. Fail if we see "Junk at end of arguments".
> + gdb_run_cmd
> +
> + gdb_test_multiple "" "rbreak junk" {
> + -re -wrap "Junk at end of arguments.*" {
> + fail $gdb_test_name
> + }
> + -re -wrap ".*Breakpoint \[0-9\]+,.*" {
> + pass $gdb_test_name
> + }
> + }
> +}
> +
> +test_rbreak_shlib
> +
> +# Test break via convenience variable with file name
> +
> +proc_with_prefix test_break_file_line_convenience_var {} {
> + clean_restart breako2
> +
> + set line [gdb_get_line_number "set breakpoint 1 here"]
> + gdb_test_no_output "set \$l = $line"
> +
> + set line_actual "-1"
> + set test "break $::srcfile:\$l"
> + gdb_test_multiple "$test" $test {
> + -re "Breakpoint $::decimal at $::hex: file .*break\\.c, line
> ($::decimal)\\.\r\n$::gdb_prompt $" {
> + # Save the actual line number on which the breakpoint was
> + # actually set. On some systems (Eg: Ubuntu 16.04 with GCC
> + # version 5.4.0), that line gets completely inlined, including
> + # the call to printf, and so we end up inserting the breakpoint
> + # on one of the following lines instead.
> + set line_actual $expect_out(1,string)
> + pass $test
> + }
> + }
> +
> + gdb_test_no_output "set \$foo=81.5" \
> + "set convenience variable \$foo to 81.5"
> + gdb_test "break $::srcfile:\$foo" \
> + "Convenience variables used in line specs must have integer
> values.*" \
> + "non-integer convenience variable disallowed"
> +}
> +
> +test_break_file_line_convenience_var
> +
> +# Test that commands can be cleared without error.
> +
> +proc_with_prefix test_break_commands_clear {} {
> + clean_restart breako2
> +
> + set line [gdb_get_line_number "set breakpoint 1 here"]
> + gdb_breakpoint $line
> +
> + gdb_test "commands\nprint 232323\nend" ">end" "set some breakpoint
> commands"
> + gdb_test "commands\nend" ">end" "clear breakpoint commands"
> +
> + # We verify that the commands were cleared by ensuring that the last
> + # breakpoint's location ends the output -- if there were commands,
> + # they would have been printed after the location.
> + gdb_test "info break" "$::srcfile:$::decimal" "verify that they were
> cleared"
> +}
> +
> +test_break_commands_clear
> diff --git a/gdb/testsuite/gdb.mdebug/break1.c
> b/gdb/testsuite/gdb.mdebug/break1.c
> new file mode 100644
> index 00000000000..5382ec06fa9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/break1.c
> @@ -0,0 +1,59 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 1992-2023 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/>.
> */
> +
> +/* The code for this file was extracted from the gdb testsuite
> + testcase "break.c". */
> +
> +/* A structure we use for field name completion tests. */
> +struct some_struct
> +{
> + int a_field;
> + int b_field;
> + union { int z_field; };
> +};
> +
> +struct some_struct values[50];
> +
> +/* Some definitions for tag completion. */
> +enum some_enum { VALUE };
> +
> +enum some_enum some_enum_global;
> +
> +union some_union
> +{
> + int f1;
> + double f2;
> +};
> +
> +union some_union some_union_global;
> +
> +/* A variable with a name "similar" to the above struct, to test that
> + tag completion works ok. */
> +int some_variable;
> +
> +/* The following functions do nothing useful. They are included
> + simply as places to try setting breakpoints at. They are
> + explicitly "one-line functions" to verify that this case works
> + (some versions of gcc have or have had problems with this).
> +
> + These functions are in a separate source file to prevent an
> + optimizing compiler from inlining them and optimizing them away. */
> +
> +int marker1 (void) { return (0); } /* set breakpoint 15 here */
> +int marker2 (int a) { return (1); } /* set breakpoint 8 here */
> +void marker3 (char *a, char *b) {} /* set breakpoint 17 here */
> +void marker4 (long d) { values[0].a_field = d; } /* set breakpoint
> 14 here */
> diff --git a/gdb/testsuite/gdb.mdebug/info-types-c.exp
> b/gdb/testsuite/gdb.mdebug/info-types-c.exp
> new file mode 100644
> index 00000000000..d8c3abeade0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/info-types-c.exp
> @@ -0,0 +1,67 @@
> +# Copyright 2019-2023 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/>.
> +
> +require {info exists MDEBUG}
> +
> +global testfile
> +global srcfile
> +global binfile
> +global subdir
> +global srcdir
> +global compile_flags
> +
> +standard_testfile info-types.c
> +
> +if {[prepare_for_testing "failed to prepare" \
> + "${testfile}" $srcfile "debug c"]} {
> +return -1
> +}
> +
> +gdb_test_no_output "set auto-solib-add off"
> +
> +if ![runto_main] then {
> +return 0
> +}
> +
> +set file_re "File .*[string_to_regexp $srcfile]:"\
> +
> +set output_lines \
> + [list \
> + "^All defined types:" \
> + ".*" \
> + $file_re \
> + "\[\t \]+typedef enum {\\.\\.\\.} anon_enum_t;" \
> + "\[\t \]+typedef struct {\\.\\.\\.} anon_struct_t;" \
> + "\[\t \]+typedef union {\\.\\.\\.} anon_union_t;" \
> + "\[\t \]+typedef struct baz_t baz;" \
> + "\[\t \]+typedef struct baz_t \\* baz_ptr;" \
> + "\[\t \]+typedef struct baz_t baz_t;" \
> + "\[\t \]+enum enum_t;" \
> + "\[\t \]+typedef enum enum_t my_enum_t;" \
> + "\[\t \]+typedef float my_float_t;" \
> + "\[\t \]+typedef int my_int_t;" \
> + "\[\t \]+typedef enum {\\.\\.\\.} nested_anon_enum_t;" \
> + "\[\t \]+typedef struct {\\.\\.\\.} nested_anon_struct_t;" \
> + "\[\t \]+typedef union {\\.\\.\\.} nested_anon_union_t;" \
> + "\[\t \]+typedef struct baz_t nested_baz;" \
> + "\[\t \]+typedef struct baz_t nested_baz_t;" \
> + "\[\t \]+typedef enum enum_t nested_enum_t;" \
> + "\[\t \]+typedef float nested_float_t;" \
> + "\[\t \]+typedef int nested_int_t;" \
> + "\[\t \]+typedef union union_t nested_union_t;" \
> + "\[\t \]+union union_t;" \
> + "($|\r\n.*)"]
> +
> +gdb_test_lines "info types" "" [multi_line {*}$output_lines]
> diff --git a/gdb/testsuite/gdb.mdebug/info-types.c
> b/gdb/testsuite/gdb.mdebug/info-types.c
> new file mode 100644
> index 00000000000..15a74b3016a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mdebug/info-types.c
> @@ -0,0 +1,116 @@
> +/* Copyright 2019-2023 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/>.
> */
> +
> +typedef int my_int_t;
> +typedef float my_float_t;
> +typedef my_int_t nested_int_t;
> +typedef my_float_t nested_float_t;
> +
> +struct baz_t
> +{
> + float f;
> + double d;
> +};
> +
> +typedef struct baz_t baz_t;
> +typedef struct baz_t baz;
> +typedef baz_t nested_baz_t;
> +typedef baz nested_baz;
> +typedef struct baz_t *baz_ptr;
> +
> +enum enum_t
> +{
> + AA, BB, CC
> +};
> +
> +typedef enum enum_t my_enum_t;
> +typedef my_enum_t nested_enum_t;
> +
> +typedef struct
> +{
> + double d;
> + float f;
> +} anon_struct_t;
> +
> +typedef anon_struct_t nested_anon_struct_t;
> +
> +typedef enum
> +{
> + DD, EE, FF
> +} anon_enum_t;
> +
> +typedef anon_enum_t nested_anon_enum_t;
> +
> +union union_t
> +{
> + int i;
> + float f;
> +};
> +
> +typedef union union_t nested_union_t;
> +
> +typedef union
> +{
> + int i;
> + double d;
> +} anon_union_t;
> +
> +typedef anon_union_t nested_anon_union_t;
> +
> +volatile int var_a;
> +volatile float var_b;
> +volatile my_int_t var_c;
> +volatile my_float_t var_d;
> +volatile nested_int_t var_e;
> +volatile nested_float_t var_f;
> +volatile struct baz_t var_g;
> +volatile baz_t var_h;
> +volatile baz var_i;
> +volatile nested_baz_t var_j;
> +volatile nested_baz var_k;
> +volatile baz_ptr var_l;
> +volatile enum enum_t var_m;
> +volatile my_enum_t var_n;
> +volatile nested_enum_t var_o;
> +volatile anon_struct_t var_p;
> +volatile nested_anon_struct_t var_q;
> +volatile anon_enum_t var_r;
> +volatile nested_anon_enum_t var_s;
> +volatile union union_t var_t;
> +volatile nested_union_t var_u;
> +volatile anon_union_t var_v;
> +volatile nested_anon_union_t var_w;
> +
> +#ifdef __cplusplus
> +
> +class CL
> +{
> + int a;
> +};
> +
> +typedef CL my_cl;
> +typedef CL *my_ptr;
> +
> +volatile CL var_cpp_a;
> +volatile my_cl var_cpp_b;
> +volatile my_ptr var_cpp_c;
> +
> +#endif /* __cplusplus */
> +
> +int
> +main ()
> +{
> + return 0;
> +}
> --
> 2.41.0
>
>
[-- Attachment #2: Type: text/html, Size: 114795 bytes --]
next prev parent reply other threads:[~2024-03-13 2:11 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-22 8:13 Zeck S
2023-10-23 9:40 ` Andrew Burgess
2023-10-24 0:25 ` Zeck S
2023-11-11 3:07 ` Zeck S
2023-12-04 3:36 ` Zeck S
2023-12-11 11:42 ` Zeck S
2023-12-11 14:03 ` Andrew Burgess
2023-12-11 14:48 ` Zeck S
2023-12-15 19:26 ` Tom Tromey
2023-12-18 15:50 ` Andrew Burgess
2023-12-25 5:42 ` Zeck S
2024-02-07 13:33 ` [PATCH] mdebug fix Zeck S
2024-02-16 2:45 ` [RFC][PATCH?] fixed some segfaults and bugs in mdebug support Zeck S
2024-03-13 2:09 ` Zeck S [this message]
2023-12-15 19:27 ` Tom Tromey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAMeZSLCSiYrLDPyh_F+U-V0DPQCr-9iG8xs8rNiO_Q801T-2dw@mail.gmail.com \
--to=zeck654321@gmail.com \
--cc=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=tom@tromey.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox