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 &section_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;
+}
