@@ -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;
new file mode 100644
@@ -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"]
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
new file mode 100644
@@ -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 */
new file mode 100644
@@ -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]
new file mode 100644
@@ -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;
+}