diff mbox

[v2,PR,symtab/17391] gdb internal error: assertion fails in regcache.c:178

Message ID 047d7b6d86305fea00051d272768@google.com
State New
Headers show

Commit Message

Doug Evans Aug. 13, 2015, 1:21 a.m. UTC
Doug Evans writes:
  > Hi.

  >

  > This patch, I hope, addresses PR 17391.

  > I couldn't recreate 17391 but there is clearly a lack of robustness here:

  > gdbarch_dwarf2_reg_to_regnum can return -1 but not all callers

  > watch for that.  Some callers do watch for it but call error themselves.

  > There is already dwarf2_reg_to_regnum_or_error so this patch just

  > changes appropriate callers of gdbarch_dwarf2_reg_to_regnum to use it.

  > Sometimes a register number is stored as a ULONGEST, so I changed

  > dwarf2_reg_to_regnum_or_error to take one.

  >

  > Regression tested on amd64-linux.

  >

  > 2015-08-10  Doug Evans  <dje@google.com>

  >

  > 	PR symtab/17391

  > 	* dwarf2-frame.c (read_addr_from_reg): Call

  > 	dwarf2_reg_to_regnum_or_error instead of gdbarch_dwarf2_reg_to_regnum.

  > 	(get_reg_value): Ditto.

  > 	(dwarf2_fetch_cfa_info): Ditto.

  > 	(dwarf2_frame_prev_register): Ditto.

  > 	* dwarf2loc.c (dwarf_expr_read_addr_from_reg): Ditto.

  > 	(dwarf_expr_get_reg_value): Ditto.

  > 	(read_pieced_value): Ditto.

  > 	(write_pieced_value): Ditto.

  > 	(dwarf2_evaluate_loc_desc_full): Ditto.

  > 	(dwarf2_reg_to_regnum_or_error): Change to take a ULONGEST regnum.

  > 	(locexpr_regname): Improve text of bad register number.

  > 	* dwarf2loc.h (dwarf2_reg_to_regnum_or_error): Update prototype.

  >

  > 	testsuite/

  > 	* lib/gdb.exp (_location): Add support for DW_OP_regx.

  > 	* gdb.dwarf2/bad-regnum.c: New file.

  > 	* gdb.dwarf2/bad-regnum.exp: New file.


Hi.

This is a revised version.
Digging deeper I found several broken targets.
I'm not prepared to fix all of them,
but this fixes a lot of them and adds documentation
to actually specify what the rules are
(as opposed to targets just cut-n-pasting
and hoping it was right).

Plus, a lot of targets were issuing a warning for
bad register numbers. The warning is ok, but
having only some issue the warning and duplicating
all that code is not.
This patch adds a wrapper around the gdbarch
routine and it issues the warning (as a complaint:
s.o.p. for bad debug info).

Regression tested with --enable-targets=all,
and running the testsuite on amd64-linux.

2015-08-12  Doug Evans  <dje@google.com>

	PR symtab/17391
	* dwarf2-frame.c (dwarf2_restore_rule): Call dwarf_reg_to_regnum
	instead of gdbarch_dwarf2_reg_to_regnum.
	(dwarf2_frame_cache): Ditto.
	(read_addr_from_reg): Call dwarf_reg_to_regnum_or_error instead of
	gdbarch_dwarf2_reg_to_regnum.
	(get_reg_value): Ditto.
	(dwarf2_fetch_cfa_info): Ditto.
	(dwarf2_frame_prev_register): Ditto.
	* dwarf2loc.c: #include "complaints.h".
	(dwarf_expr_read_addr_from_reg): Call dwarf_reg_to_regnum_or_error
	instead of gdbarch_dwarf2_reg_to_regnum.
	(dwarf_expr_get_reg_value): Ditto.
	(read_pieced_value): Ditto.
	(write_pieced_value): Ditto.
	(dwarf2_evaluate_loc_desc_full): Ditto.
	(dwarf_reg_to_regnum): New function.
	(throw_bad_regnum_error): New function.
	(dwarf_reg_to_regnum_or_error): Renamed from
	dwarf2_reg_to_regnum_or_errorChange to take a ULONGEST regnum.
	All callers updated.  Call throw_bad_regnum_error.
	(locexpr_regname): Improve text of bad register number.
	* dwarf2loc.h (dwarf_reg_to_regnum): Declare.
	(dwarf_reg_to_regnum_or_error): Update prototype.
	* dwarf2expr.c: #include "dwarf2loc.h".
	(dwarf_block_to_sp_offset): Call dwarf_reg_to_regnum instead of
	gdbarch_dwarf2_reg_to_regnum.
	* gdbarch.sh (dwarf2_reg_to_regnum): Add comment.
	* gdbarch.h: Generate.
	* amd64-tdep.c (amd64_dwarf_reg_to_regnum): Remove warning for bad
	register.
	* avr-tdep.c (avr_dwarf_reg_to_regnum): Ditto.
	* cris-tdep.c (cris_dwarf2_reg_to_regnum): Ditto.
	* bfin-tdep.c (bfin_reg_to_regnum): Fix error checking.
	* hppa-linux-tdep.c (hppa_dwarf_reg_to_regnum): Improve error checking.
	Remove warning for bad register.
	* hppa-tdep.c (hppa64_dwarf_reg_to_regnum): Ditto.
	* i386-tdep.c (i386_svr4_dwarf_reg_to_regnum): Renamed from
	i386_svr4_reg_to_regnum.  Return -1 for bad registers.
	(i386_svr4_reg_to_regnum): New function.
	(i386_gdbarch_init): Update call to set_gdbarch_dwarf2_reg_to_regnum.
	* microblaze-tdep.c (microblaze_dwarf2_reg_to_regnum): Don't assert
	on bad registers, return -1.
	* msp430-tdep.c (msp430_dwarf2_reg_to_regnum): Improve error checking.
	Remove warning for bad register.
	* nios2-tdep.c: Add static assert for NIOS2_NUM_REGS.
	(nios2_dwarf_reg_to_regnum): Fix off-by-one error.
	Remove warning for bad register.  Return -1 for bad register.
	* rl78-tdep.c (rl78_dwarf_reg_to_regnum): Don't flag an internal error
	for bad register, return -1.
	* rx-tdep.c (rx_dwarf_reg_to_regnum): Ditto.

	testsuite/
	* lib/gdb.exp (_location): Add support for DW_OP_regx.
	* gdb.dwarf2/bad-regnum.c: New file.
	* gdb.dwarf2/bad-regnum.exp: New file.

Comments

Pedro Alves Aug. 17, 2015, 5:01 p.m. UTC | #1
On 08/13/2015 02:21 AM, Doug Evans wrote:
> Doug Evans writes:
>   > Hi.
>   >
>   > This patch, I hope, addresses PR 17391.
>   > I couldn't recreate 17391 but there is clearly a lack of robustness here:
>   > gdbarch_dwarf2_reg_to_regnum can return -1 but not all callers
>   > watch for that.  Some callers do watch for it but call error themselves.
>   > There is already dwarf2_reg_to_regnum_or_error so this patch just
>   > changes appropriate callers of gdbarch_dwarf2_reg_to_regnum to use it.
>   > Sometimes a register number is stored as a ULONGEST, so I changed
>   > dwarf2_reg_to_regnum_or_error to take one.
>   >
>   > Regression tested on amd64-linux.
>   >
>   > 2015-08-10  Doug Evans  <dje@google.com>
>   >
>   > 	PR symtab/17391
>   > 	* dwarf2-frame.c (read_addr_from_reg): Call
>   > 	dwarf2_reg_to_regnum_or_error instead of gdbarch_dwarf2_reg_to_regnum.
>   > 	(get_reg_value): Ditto.
>   > 	(dwarf2_fetch_cfa_info): Ditto.
>   > 	(dwarf2_frame_prev_register): Ditto.
>   > 	* dwarf2loc.c (dwarf_expr_read_addr_from_reg): Ditto.
>   > 	(dwarf_expr_get_reg_value): Ditto.
>   > 	(read_pieced_value): Ditto.
>   > 	(write_pieced_value): Ditto.
>   > 	(dwarf2_evaluate_loc_desc_full): Ditto.
>   > 	(dwarf2_reg_to_regnum_or_error): Change to take a ULONGEST regnum.
>   > 	(locexpr_regname): Improve text of bad register number.
>   > 	* dwarf2loc.h (dwarf2_reg_to_regnum_or_error): Update prototype.
>   >
>   > 	testsuite/
>   > 	* lib/gdb.exp (_location): Add support for DW_OP_regx.
>   > 	* gdb.dwarf2/bad-regnum.c: New file.
>   > 	* gdb.dwarf2/bad-regnum.exp: New file.
> 
> Hi.
> 
> This is a revised version.
> Digging deeper I found several broken targets.
> I'm not prepared to fix all of them,

OOC, was that because the fix looked complicated, or because
you wanted to avoid breaking them?  If the latter, I'd be more inclined
to avoiding leaving a wart in place that is probably going to take
a long while to address, even if that meant the fix goes in untested.
Is there an easy way to tell which targets still need fixing?  Or what
to look for?

> but this fixes a lot of them and adds documentation
> to actually specify what the rules are
> (as opposed to targets just cut-n-pasting
> and hoping it was right).

Otherwise the patch looked fine to me.

Thanks,
Pedro Alves
diff mbox

Patch

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 5e63b5e..305c75b 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -252,9 +252,7 @@  amd64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int  
reg)
    if (reg >= 0 && reg < amd64_dwarf_regmap_len)
      regnum = amd64_dwarf_regmap[reg];

-  if (regnum == -1)
-    warning (_("Unmapped DWARF Register #%d encountered."), reg);
-  else if (ymm0_regnum >= 0
+  if (ymm0_regnum >= 0
  	   && i386_xmm_regnum_p (gdbarch, regnum))
      regnum += ymm0_regnum - I387_XMM0_REGNUM (tdep);

diff --git a/gdb/avr-tdep.c b/gdb/avr-tdep.c
index dff0be9..44081fa 100644
--- a/gdb/avr-tdep.c
+++ b/gdb/avr-tdep.c
@@ -1364,9 +1364,6 @@  avr_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int  
reg)
      return reg;
    if (reg == 32)
      return AVR_SP_REGNUM;
-
-  warning (_("Unmapped DWARF Register #%d encountered."), reg);
-
    return -1;
  }

diff --git a/gdb/bfin-tdep.c b/gdb/bfin-tdep.c
index 4532e1b..0f34e64 100644
--- a/gdb/bfin-tdep.c
+++ b/gdb/bfin-tdep.c
@@ -566,8 +566,8 @@  bfin_push_dummy_call (struct gdbarch *gdbarch,
  static int
  bfin_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
-  if (reg > ARRAY_SIZE (map_gcc_gdb))
-    return 0;
+  if (reg < 0 || reg >= ARRAY_SIZE (map_gcc_gdb))
+    return -1;

    return map_gcc_gdb[reg];
  }
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index b201d13..3b4df9b 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -817,15 +817,15 @@  do_compile_dwarf_expr_to_c (int indent, struct  
ui_file *stream,
  	case DW_OP_reg31:
  	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
  	  pushf_register_address (indent, stream, registers_used, arch,
-				  dwarf2_reg_to_regnum_or_error (arch,
-							      op - DW_OP_reg0));
+				  dwarf_reg_to_regnum_or_error
+				    (arch, op - DW_OP_reg0));
  	  break;

  	case DW_OP_regx:
  	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
  	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
  	  pushf_register_address (indent, stream, registers_used, arch,
-				  dwarf2_reg_to_regnum_or_error (arch, reg));
+				  dwarf_reg_to_regnum_or_error (arch, reg));
  	  break;

  	case DW_OP_breg0:
@@ -862,8 +862,8 @@  do_compile_dwarf_expr_to_c (int indent, struct ui_file  
*stream,
  	case DW_OP_breg31:
  	  op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
  	  pushf_register (indent, stream, registers_used, arch,
-			  dwarf2_reg_to_regnum_or_error (arch,
-							 op - DW_OP_breg0),
+			  dwarf_reg_to_regnum_or_error (arch,
+							op - DW_OP_breg0),
  			  offset);
  	  break;
  	case DW_OP_bregx:
@@ -871,7 +871,7 @@  do_compile_dwarf_expr_to_c (int indent, struct ui_file  
*stream,
  	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
  	    pushf_register (indent, stream, registers_used, arch,
-			    dwarf2_reg_to_regnum_or_error (arch, reg), offset);
+			    dwarf_reg_to_regnum_or_error (arch, reg), offset);
  	  }
  	  break;
  	case DW_OP_fbreg:
diff --git a/gdb/cris-tdep.c b/gdb/cris-tdep.c
index 2273887..232f75c 100644
--- a/gdb/cris-tdep.c
+++ b/gdb/cris-tdep.c
@@ -1791,9 +1791,6 @@  cris_dwarf2_reg_to_regnum (struct gdbarch *gdbarch,  
int reg)
    if (reg >= 0 && reg < ARRAY_SIZE (cris_dwarf_regmap))
      regnum = cris_dwarf_regmap[reg];

-  if (regnum == -1)
-    warning (_("Unmapped DWARF Register #%d encountered."), reg);
-
    return regnum;
  }

diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 8fb2ac7..b42fc8a 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -292,7 +292,7 @@  read_addr_from_reg (void *baton, int reg)
  {
    struct frame_info *this_frame = (struct frame_info *) baton;
    struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
+  int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);

    return address_from_register (regnum, this_frame);
  }
@@ -304,7 +304,7 @@  get_reg_value (void *baton, struct type *type, int reg)
  {
    struct frame_info *this_frame = (struct frame_info *) baton;
    struct gdbarch *gdbarch = get_frame_arch (this_frame);
-  int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, reg);
+  int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);

    return value_from_register (type, regnum, this_frame);
  }
@@ -336,13 +336,15 @@  dwarf2_restore_rule (struct gdbarch *gdbarch,  
ULONGEST reg_num,
      fs->regs.reg[reg].how = DWARF2_FRAME_REG_UNSPECIFIED;

    if (fs->regs.reg[reg].how == DWARF2_FRAME_REG_UNSPECIFIED)
-    complaint (&symfile_complaints, _("\
+    {
+      int regnum = dwarf_reg_to_regnum (gdbarch, reg);
+
+      complaint (&symfile_complaints, _("\
  incomplete CFI data; DW_CFA_restore unspecified\n\
  register %s (#%d) at %s"),
-		       gdbarch_register_name
-		       (gdbarch, gdbarch_dwarf2_reg_to_regnum (gdbarch, reg)),
-		       gdbarch_dwarf2_reg_to_regnum (gdbarch, reg),
-		       paddress (gdbarch, fs->pc));
+		 gdbarch_register_name (gdbarch, regnum), regnum,
+		 paddress (gdbarch, fs->pc));
+    }
  }

  /* Virtual method table for execute_stack_op below.  */
@@ -936,11 +938,7 @@  dwarf2_fetch_cfa_info (struct gdbarch *gdbarch,  
CORE_ADDR pc,
      {
      case CFA_REG_OFFSET:
        {
-	int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, fs.regs.cfa_reg);
-
-	if (regnum == -1)
-	  error (_("Unable to access DWARF register number %d"),
-		 (int) fs.regs.cfa_reg); /* FIXME */
+	int regnum = dwarf_reg_to_regnum_or_error (gdbarch, fs.regs.cfa_reg);

  	*regnum_out = regnum;
  	if (fs.armcc_cfa_offsets_reversed)
@@ -1087,7 +1085,7 @@  dwarf2_frame_cache (struct frame_info *this_frame,  
void **this_cache)
  				   entry_pc, fs);

        if (fs->regs.cfa_how == CFA_REG_OFFSET
-	  && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
+	  && (dwarf_reg_to_regnum (gdbarch, fs->regs.cfa_reg)
  	      == gdbarch_sp_regnum (gdbarch)))
  	{
  	  cache->entry_cfa_sp_offset = fs->regs.cfa_offset;
@@ -1150,19 +1148,18 @@  dwarf2_frame_cache (struct frame_info *this_frame,  
void **this_cache)
    /* Go through the DWARF2 CFI generated table and save its register
       location information in the cache.  Note that we don't skip the
       return address column; it's perfectly all right for it to
-     correspond to a real register.  If it doesn't correspond to a
-     real register, or if we shouldn't treat it as such,
-     gdbarch_dwarf2_reg_to_regnum should be defined to return a number  
outside
-     the range [0, gdbarch_num_regs).  */
+     correspond to a real register.  */
    {
      int column;		/* CFI speak for "register number".  */

      for (column = 0; column < fs->regs.num_regs; column++)
        {
  	/* Use the GDB register number as the destination index.  */
-	int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, column);
+	int regnum = dwarf_reg_to_regnum (gdbarch, column);

-	/* If there's no corresponding GDB register, ignore it.  */
+	/* If there's no corresponding GDB register, ignore it.
+	   Some targets return num_regs (+ num_pseudo_regs) for bad registers.
+	   Handle them until they are fixed.  */
  	if (regnum < 0 || regnum >= num_regs)
  	  continue;

@@ -1324,8 +1321,8 @@  dwarf2_frame_prev_register (struct frame_info  
*this_frame, void **this_cache,
        return frame_unwind_got_memory (this_frame, regnum, addr);

      case DWARF2_FRAME_REG_SAVED_REG:
-      realnum
-	= gdbarch_dwarf2_reg_to_regnum (gdbarch, cache->reg[regnum].loc.reg);
+      realnum = dwarf_reg_to_regnum_or_error
+	(gdbarch, cache->reg[regnum].loc.reg);
        return frame_unwind_got_register (this_frame, regnum, realnum);

      case DWARF2_FRAME_REG_SAVED_EXP:
@@ -1368,7 +1365,7 @@  dwarf2_frame_prev_register (struct frame_info  
*this_frame, void **this_cache,

      case DWARF2_FRAME_REG_RA_OFFSET:
        addr = cache->reg[regnum].loc.offset;
-      regnum = gdbarch_dwarf2_reg_to_regnum
+      regnum = dwarf_reg_to_regnum_or_error
  	(gdbarch, cache->retaddr_reg.loc.reg);
        addr += get_frame_register_unsigned (this_frame, regnum);
        return frame_unwind_got_address (this_frame, regnum, addr);
diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c
index 862a753..1b9cbd6 100644
--- a/gdb/dwarf2expr.c
+++ b/gdb/dwarf2expr.c
@@ -26,6 +26,7 @@ 
  #include "gdbcore.h"
  #include "dwarf2.h"
  #include "dwarf2expr.h"
+#include "dwarf2loc.h"

  /* Local prototypes.  */

@@ -613,7 +614,7 @@  dwarf_block_to_sp_offset (struct gdbarch *gdbarch,  
const gdb_byte *buf,
  	return 0;
      }

-  if (gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_reg)
+  if (dwarf_reg_to_regnum (gdbarch, dwarf_reg)
        != gdbarch_sp_regnum (gdbarch))
      return 0;

diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index d8e432e..8c514bf 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -32,7 +32,7 @@ 
  #include "objfiles.h"
  #include "block.h"
  #include "gdbcmd.h"
-
+#include "complaints.h"
  #include "dwarf2.h"
  #include "dwarf2expr.h"
  #include "dwarf2loc.h"
@@ -312,7 +312,7 @@  dwarf_expr_read_addr_from_reg (void *baton, int  
dwarf_regnum)
  {
    struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
    struct gdbarch *gdbarch = get_frame_arch (debaton->frame);
-  int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum);
+  int regnum = dwarf_reg_to_regnum_or_error (gdbarch, dwarf_regnum);

    return address_from_register (regnum, debaton->frame);
  }
@@ -324,7 +324,7 @@  dwarf_expr_get_reg_value (void *baton, struct type  
*type, int dwarf_regnum)
  {
    struct dwarf_expr_baton *debaton = (struct dwarf_expr_baton *) baton;
    struct gdbarch *gdbarch = get_frame_arch (debaton->frame);
-  int regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum);
+  int regnum = dwarf_reg_to_regnum_or_error (gdbarch, dwarf_regnum);

    return value_from_register (type, regnum, debaton->frame);
  }
@@ -1682,40 +1682,31 @@  read_pieced_value (struct value *v)
  	case DWARF_VALUE_REGISTER:
  	  {
  	    struct gdbarch *arch = get_frame_arch (frame);
-	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
+	    int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, p->v.regno);
+	    int optim, unavail;
+	    int reg_offset = source_offset;

-	    if (gdb_regnum != -1)
+	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
+		&& this_size < register_size (arch, gdb_regnum))
  	      {
-		int optim, unavail;
-		int reg_offset = source_offset;
-
-		if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-		    && this_size < register_size (arch, gdb_regnum))
-		  {
-		    /* Big-endian, and we want less than full size.  */
-		    reg_offset = register_size (arch, gdb_regnum) - this_size;
-		    /* We want the lower-order THIS_SIZE_BITS of the bytes
-		       we extract from the register.  */
-		    source_offset_bits += 8 * this_size - this_size_bits;
-		 }
-
-		if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
-					       this_size, buffer,
-					       &optim, &unavail))
-		  {
-		    /* Just so garbage doesn't ever shine through.  */
-		    memset (buffer, 0, this_size);
-
-		    if (optim)
-		      mark_value_bits_optimized_out (v, offset, this_size_bits);
-		    if (unavail)
-		      mark_value_bits_unavailable (v, offset, this_size_bits);
-		  }
+		/* Big-endian, and we want less than full size.  */
+		reg_offset = register_size (arch, gdb_regnum) - this_size;
+		/* We want the lower-order THIS_SIZE_BITS of the bytes
+		   we extract from the register.  */
+		source_offset_bits += 8 * this_size - this_size_bits;
  	      }
-	    else
+
+	    if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+					   this_size, buffer,
+					   &optim, &unavail))
  	      {
-		error (_("Unable to access DWARF register number %s"),
-		       paddress (arch, p->v.regno));
+		/* Just so garbage doesn't ever shine through.  */
+		memset (buffer, 0, this_size);
+
+		if (optim)
+		  mark_value_bits_optimized_out (v, offset, this_size_bits);
+		if (unavail)
+		  mark_value_bits_unavailable (v, offset, this_size_bits);
  	      }
  	  }
  	  break;
@@ -1874,52 +1865,43 @@  write_pieced_value (struct value *to, struct value  
*from)
  	case DWARF_VALUE_REGISTER:
  	  {
  	    struct gdbarch *arch = get_frame_arch (frame);
-	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, p->v.regno);
+	    int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, p->v.regno);
+	    int reg_offset = dest_offset;

-	    if (gdb_regnum != -1)
+	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
+		&& this_size <= register_size (arch, gdb_regnum))
  	      {
-		int reg_offset = dest_offset;
+		/* Big-endian, and we want less than full size.  */
+		reg_offset = register_size (arch, gdb_regnum) - this_size;
+	      }

-		if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-		    && this_size <= register_size (arch, gdb_regnum))
-		  {
-		    /* Big-endian, and we want less than full size.  */
-		    reg_offset = register_size (arch, gdb_regnum) - this_size;
-		  }
+	    if (need_bitwise)
+	      {
+		int optim, unavail;

-		if (need_bitwise)
+		if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
+					       this_size, buffer,
+					       &optim, &unavail))
  		  {
-		    int optim, unavail;
-
-		    if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
-						   this_size, buffer,
-						   &optim, &unavail))
-		      {
-			if (optim)
-			  throw_error (OPTIMIZED_OUT_ERROR,
-				       _("Can't do read-modify-write to "
-					 "update bitfield; containing word "
-					 "has been optimized out"));
-			if (unavail)
-			  throw_error (NOT_AVAILABLE_ERROR,
-				       _("Can't do read-modify-write to update "
-					 "bitfield; containing word "
-					 "is unavailable"));
-		      }
-		    copy_bitwise (buffer, dest_offset_bits,
-				  contents, source_offset_bits,
-				  this_size_bits,
-				  bits_big_endian);
+		    if (optim)
+		      throw_error (OPTIMIZED_OUT_ERROR,
+				   _("Can't do read-modify-write to "
+				     "update bitfield; containing word "
+				     "has been optimized out"));
+		    if (unavail)
+		      throw_error (NOT_AVAILABLE_ERROR,
+				   _("Can't do read-modify-write to update "
+				     "bitfield; containing word "
+				     "is unavailable"));
  		  }
-
-		put_frame_register_bytes (frame, gdb_regnum, reg_offset,
-					  this_size, source_buffer);
-	      }
-	    else
-	      {
-		error (_("Unable to write to DWARF register number %s"),
-		       paddress (arch, p->v.regno));
+		copy_bitwise (buffer, dest_offset_bits,
+			      contents, source_offset_bits,
+			      this_size_bits,
+			      bits_big_endian);
  	      }
+
+	    put_frame_register_bytes (frame, gdb_regnum, reg_offset,
+				      this_size, source_buffer);
  	  }
  	  break;
  	case DWARF_VALUE_MEMORY:
@@ -2260,30 +2242,27 @@  dwarf2_evaluate_loc_desc_full (struct type *type,  
struct frame_info *frame,
  	    struct gdbarch *arch = get_frame_arch (frame);
  	    int dwarf_regnum
  	      = longest_to_int (value_as_long (dwarf_expr_fetch (ctx, 0)));
-	    int gdb_regnum = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_regnum);
+	    int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, dwarf_regnum);

  	    if (byte_offset != 0)
  	      error (_("cannot use offset on synthetic pointer to register"));
  	    do_cleanups (value_chain);
-	   if (gdb_regnum == -1)
-	      error (_("Unable to access DWARF register number %d"),
-		     dwarf_regnum);
-	   retval = value_from_register (type, gdb_regnum, frame);
-	   if (value_optimized_out (retval))
-	     {
-	       struct value *tmp;
-
-	       /* This means the register has undefined value / was
-		  not saved.  As we're computing the location of some
-		  variable etc. in the program, not a value for
-		  inspecting a register ($pc, $sp, etc.), return a
-		  generic optimized out value instead, so that we show
-		  <optimized out> instead of <not saved>.  */
-	       do_cleanups (value_chain);
-	       tmp = allocate_value (type);
-	       value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type));
-	       retval = tmp;
-	     }
+	    retval = value_from_register (type, gdb_regnum, frame);
+	    if (value_optimized_out (retval))
+	      {
+		struct value *tmp;
+
+		/* This means the register has undefined value / was
+		   not saved.  As we're computing the location of some
+		   variable etc. in the program, not a value for
+		   inspecting a register ($pc, $sp, etc.), return a
+		   generic optimized out value instead, so that we show
+		   <optimized out> instead of <not saved>.  */
+		do_cleanups (value_chain);
+		tmp = allocate_value (type);
+		value_contents_copy (tmp, 0, retval, 0, TYPE_LENGTH (type));
+		retval = tmp;
+	      }
  	  }
  	  break;

@@ -2774,14 +2753,54 @@  unimplemented (unsigned int op)
  	   op);
  }

-/* See dwarf2loc.h.  */
+/* See dwarf2loc.h.
+
+   This is basically a wrapper on gdbarch_dwarf2_reg_to_regnum so that we
+   can issue a complaint, which is better than having every target's
+   implementation of dwarf2_reg_to_regnum do it.  */

  int
-dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, int dwarf_reg)
+dwarf_reg_to_regnum (struct gdbarch *arch, int dwarf_reg)
  {
    int reg = gdbarch_dwarf2_reg_to_regnum (arch, dwarf_reg);
+
    if (reg == -1)
-    error (_("Unable to access DWARF register number %d"), dwarf_reg);
+    {
+      complaint (&symfile_complaints,
+		 _("bad DWARF register number %d"), dwarf_reg);
+    }
+  return reg;
+}
+
+/* Subroutine of dwarf_reg_to_regnum_or_error to simplify it.
+   Throw an error because DWARF_REG is bad.  */
+
+static void
+throw_bad_regnum_error (ULONGEST dwarf_reg)
+{
+  /* Still want to print -1 as "-1".
+     We *could* have int and ULONGEST versions of  
dwarf2_reg_to_regnum_or_error
+     but that's overkill for now.  */
+  if ((int) dwarf_reg == dwarf_reg)
+    error (_("Unable to access DWARF register number %d"), (int)  
dwarf_reg);
+  error (_("Unable to access DWARF register number %s"),
+	 pulongest (dwarf_reg));
+}
+
+/* See dwarf2loc.h.  */
+
+int
+dwarf_reg_to_regnum_or_error (struct gdbarch *arch, ULONGEST dwarf_reg)
+{
+  int reg;
+
+  if (dwarf_reg > INT_MAX)
+    throw_bad_regnum_error (dwarf_reg);
+  /* Yes, we will end up issuing a complaint and an error if DWARF_REG is
+     bad, but that's ok.  */
+  reg = dwarf_reg_to_regnum (arch, (int) dwarf_reg);
+  if (reg == -1)
+    throw_bad_regnum_error (dwarf_reg);
    return reg;
  }

@@ -3028,14 +3047,14 @@  dwarf2_compile_expr_to_ax (struct agent_expr *expr,  
struct axs_value *loc,
  	case DW_OP_reg30:
  	case DW_OP_reg31:
  	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
-	  loc->u.reg = dwarf2_reg_to_regnum_or_error (arch, op - DW_OP_reg0);
+	  loc->u.reg = dwarf_reg_to_regnum_or_error (arch, op - DW_OP_reg0);
  	  loc->kind = axs_lvalue_register;
  	  break;

  	case DW_OP_regx:
  	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
  	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
-	  loc->u.reg = dwarf2_reg_to_regnum_or_error (arch, reg);
+	  loc->u.reg = dwarf_reg_to_regnum_or_error (arch, reg);
  	  loc->kind = axs_lvalue_register;
  	  break;

@@ -3098,7 +3117,7 @@  dwarf2_compile_expr_to_ax (struct agent_expr *expr,  
struct axs_value *loc,
  	case DW_OP_breg30:
  	case DW_OP_breg31:
  	  op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	  i = dwarf2_reg_to_regnum_or_error (arch, op - DW_OP_breg0);
+	  i = dwarf_reg_to_regnum_or_error (arch, op - DW_OP_breg0);
  	  ax_reg (expr, i);
  	  if (offset != 0)
  	    {
@@ -3110,7 +3129,7 @@  dwarf2_compile_expr_to_ax (struct agent_expr *expr,  
struct axs_value *loc,
  	  {
  	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	    i = dwarf2_reg_to_regnum_or_error (arch, reg);
+	    i = dwarf_reg_to_regnum_or_error (arch, reg);
  	    ax_reg (expr, i);
  	    if (offset != 0)
  	      {
@@ -3572,7 +3591,17 @@  locexpr_regname (struct gdbarch *gdbarch, int  
dwarf_regnum)
  {
    int regnum;

-  regnum = gdbarch_dwarf2_reg_to_regnum (gdbarch, dwarf_regnum);
+  /* This doesn't use dwarf_reg_to_regnum_or_error on purpose.
+     We'd rather print *something* here than throw an error.  */
+  regnum = dwarf_reg_to_regnum (gdbarch, dwarf_regnum);
+  /* gdbarch_register_name may just return "", return something more
+     descriptive for bad register numbers.  */
+  if (regnum == -1)
+    {
+      /* The text is output as "$bad_register_number".
+	 That is why we use the underscores.  */
+      return _("bad_register_number");
+    }
    return gdbarch_register_name (gdbarch, regnum);
  }

diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index f3630ac..c3375e4 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -286,9 +286,18 @@  extern struct call_site_chain *call_site_find_chain  
(struct gdbarch *gdbarch,
  /* A helper function to convert a DWARF register to an arch register.
     ARCH is the architecture.
     DWARF_REG is the register.
-   This will throw an exception if the DWARF register cannot be
-   translated to an architecture register.  */
+   If DWARF_REG is bad then a complaint is issued and -1 is returned.
+   Note: Some targets get this wrong.  */

-extern int dwarf2_reg_to_regnum_or_error (struct gdbarch *arch, int  
dwarf_reg);
+extern int dwarf_reg_to_regnum (struct gdbarch *arch, int dwarf_reg);
+
+/* A wrapper on dwarf_reg_to_regnum to throw an exception if the
+   DWARF register cannot be translated to an architecture register.
+   This takes a ULONGEST instead of an int because some callers actually  
have
+   a ULONGEST.  Negative values passed as ints will still be flagged as
+   invalid.  */
+
+extern int dwarf_reg_to_regnum_or_error (struct gdbarch *arch,
+					 ULONGEST dwarf_reg);

  #endif /* dwarf2loc.h */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index c1e2c1a..d74a157 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -335,7 +335,8 @@  typedef int (gdbarch_sdb_reg_to_regnum_ftype) (struct  
gdbarch *gdbarch, int sdb_
  extern int gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch, int  
sdb_regnr);
  extern void set_gdbarch_sdb_reg_to_regnum (struct gdbarch *gdbarch,  
gdbarch_sdb_reg_to_regnum_ftype *sdb_reg_to_regnum);

-/* Provide a default mapping from a DWARF2 register number to a gdb  
REGNUM. */
+/* Provide a default mapping from a DWARF2 register number to a gdb REGNUM.
+   Return -1 for bad REGNUM.  Note: Several targets get this wrong. */

  typedef int (gdbarch_dwarf2_reg_to_regnum_ftype) (struct gdbarch *gdbarch,  
int dwarf2_regnr);
  extern int gdbarch_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int  
dwarf2_regnr);
@@ -924,7 +925,7 @@  extern void set_gdbarch_max_insn_length (struct gdbarch  
*gdbarch, ULONGEST max_i
     If your architecture doesn't need to adjust instructions before
     single-stepping them, consider using simple_displaced_step_copy_insn
     here.
-
+
     If the instruction cannot execute out of line, return NULL.  The
     core falls back to stepping past the instruction in-line instead in
     that case. */
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 994a87b..ddd4edd 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -461,6 +461,7 @@  m:int:ecoff_reg_to_regnum:int  
ecoff_regnr:ecoff_regnr::no_op_reg_to_regnum::0
  # Convert from an sdb register number to an internal gdb register number.
  m:int:sdb_reg_to_regnum:int sdb_regnr:sdb_regnr::no_op_reg_to_regnum::0
  # Provide a default mapping from a DWARF2 register number to a gdb REGNUM.
+# Return -1 for bad REGNUM.  Note: Several targets get this wrong.
  m:int:dwarf2_reg_to_regnum:int  
dwarf2_regnr:dwarf2_regnr::no_op_reg_to_regnum::0
  m:const char *:register_name:int regnr:regnr::0

diff --git a/gdb/hppa-linux-tdep.c b/gdb/hppa-linux-tdep.c
index 6dc2e84..db6abc6 100644
--- a/gdb/hppa-linux-tdep.c
+++ b/gdb/hppa-linux-tdep.c
@@ -39,14 +39,13 @@  static int
  hppa_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
    /* The general registers and the sar are the same in both sets.  */
-  if (reg <= 32)
+  if (reg >= 0 && reg <= 32)
      return reg;

    /* fr4-fr31 (left and right halves) are mapped from 72.  */
    if (reg >= 72 && reg <= 72 + 28 * 2)
      return HPPA_FP4_REGNUM + (reg - 72);

-  warning (_("Unmapped DWARF DBX Register #%d encountered."), reg);
    return -1;
  }

diff --git a/gdb/hppa-tdep.c b/gdb/hppa-tdep.c
index 01a7c80..60c0312 100644
--- a/gdb/hppa-tdep.c
+++ b/gdb/hppa-tdep.c
@@ -694,14 +694,13 @@  static int
  hppa64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
    /* The general registers and the sar are the same in both sets.  */
-  if (reg <= 32)
+  if (reg >= 0 && reg <= 32)
      return reg;

    /* fr4-fr31 are mapped from 72 in steps of 2.  */
    if (reg >= 72 && reg < 72 + 28 * 2 && !(reg & 1))
      return HPPA64_FP4_REGNUM + (reg - 72) / 2;

-  warning (_("Unmapped DWARF DBX Register #%d encountered."), reg);
    return -1;
  }

diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index 9d52d4a..396e17f 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -502,11 +502,11 @@  i386_dbx_reg_to_regnum (struct gdbarch *gdbarch, int  
reg)
    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
  }

-/* Convert SVR4 register number REG to the appropriate register number
+/* Convert SVR4 DWARF register number REG to the appropriate register  
number
     used by GDB.  */

  static int
-i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+i386_svr4_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
    struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);

@@ -544,8 +544,20 @@  i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int  
reg)
      case 45: return I386_GS_REGNUM;
      }

-  /* This will hopefully provoke a warning.  */
-  return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+  return -1;
+}
+
+/* Wrapper on i386_svr4_dwarf_reg_to_regnum to return
+   num_regs + num_pseudo_regs for other debug formats.  */
+
+static int
+i386_svr4_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+  int regnum = i386_svr4_dwarf_reg_to_regnum (gdbarch, reg);
+
+  if (regnum == -1)
+    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
+  return regnum;
  }

  
@@ -8349,7 +8361,7 @@  i386_gdbarch_init (struct gdbarch_info info, struct  
gdbarch_list *arches)
    set_gdbarch_sdb_reg_to_regnum (gdbarch, i386_dbx_reg_to_regnum);

    /* Use the SVR4 register numbering scheme for DWARF 2.  */
-  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch,  
i386_svr4_dwarf_reg_to_regnum);

    /* We don't set gdbarch_stab_reg_to_regnum, since ECOFF doesn't seem to
       be in use on any of the supported i386 targets.  */
diff --git a/gdb/microblaze-tdep.c b/gdb/microblaze-tdep.c
index 8cc1df2..b09cd03 100644
--- a/gdb/microblaze-tdep.c
+++ b/gdb/microblaze-tdep.c
@@ -638,8 +638,9 @@  static int dwarf2_to_reg_map[78] =
  static int
  microblaze_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
-  gdb_assert ((size_t) reg < sizeof (dwarf2_to_reg_map));
-  return dwarf2_to_reg_map[reg];
+  if (reg >= 0 && reg < sizeof (dwarf2_to_reg_map))
+    return dwarf2_to_reg_map[reg];
+  return -1;
  }

  static void
diff --git a/gdb/msp430-tdep.c b/gdb/msp430-tdep.c
index 622ce55..62e6973 100644
--- a/gdb/msp430-tdep.c
+++ b/gdb/msp430-tdep.c
@@ -581,13 +581,9 @@  static const struct frame_unwind msp430_unwind = {
  static int
  msp430_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int reg)
  {
-  if (reg < MSP430_NUM_REGS)
+  if (reg >= 0 && reg < MSP430_NUM_REGS)
      return reg + MSP430_NUM_REGS;
-  else
-    {
-      warning (_("Unmapped DWARF Register #%d encountered."), reg);
-      return -1;
-    }
+  return -1;
  }

  /* Implement the "return_value" gdbarch method.  */
diff --git a/gdb/nios2-tdep.c b/gdb/nios2-tdep.c
index 11073ee..ca64d4f 100644
--- a/gdb/nios2-tdep.c
+++ b/gdb/nios2-tdep.c
@@ -138,17 +138,15 @@  static int nios2_dwarf2gdb_regno_map[] =
    NIOS2_MPUACC_REGNUM     /* 48 */
  };

+gdb_static_assert (ARRAY_SIZE (nios2_dwarf2gdb_regno_map) ==  
NIOS2_NUM_REGS);

  /* Implement the dwarf2_reg_to_regnum gdbarch method.  */

  static int
  nios2_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int dw_reg)
  {
-  if (dw_reg < 0 || dw_reg > NIOS2_NUM_REGS)
-    {
-      warning (_("Dwarf-2 uses unmapped register #%d"), dw_reg);
-      return dw_reg;
-    }
+  if (dw_reg < 0 || dw_reg >= NIOS2_NUM_REGS)
+    return -1;

    return nios2_dwarf2gdb_regno_map[dw_reg];
  }
diff --git a/gdb/rl78-tdep.c b/gdb/rl78-tdep.c
index a5861d8..5ccc55c 100644
--- a/gdb/rl78-tdep.c
+++ b/gdb/rl78-tdep.c
@@ -1215,9 +1215,7 @@  rl78_dwarf_reg_to_regnum (struct gdbarch *gdbarch,  
int reg)
    else if (reg == 37)
      return RL78_PC_REGNUM;
    else
-    internal_error (__FILE__, __LINE__,
-                    _("Undefined dwarf2 register mapping of reg %d"),
-		    reg);
+    return -1;
  }

  /* Implement the `register_sim_regno' gdbarch method.  */
diff --git a/gdb/rx-tdep.c b/gdb/rx-tdep.c
index 0bd91ff..7189168 100644
--- a/gdb/rx-tdep.c
+++ b/gdb/rx-tdep.c
@@ -1010,9 +1010,7 @@  rx_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int  
reg)
    else if (reg == 17)
      return RX_PC_REGNUM;
    else
-    internal_error (__FILE__, __LINE__,
-                    _("Undefined dwarf2 register mapping of reg %d"),
-		    reg);
+    return -1;
  }

  /* Allocate and initialize a gdbarch object.  */
diff --git a/gdb/testsuite/gdb.dwarf2/bad-regnum.c  
b/gdb/testsuite/gdb.dwarf2/bad-regnum.c
new file mode 100644
index 0000000..35230f2
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/bad-regnum.c
@@ -0,0 +1,22 @@ 
+/* Copyright 2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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
+main ()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/bad-regnum.exp  
b/gdb/testsuite/gdb.dwarf2/bad-regnum.exp
new file mode 100644
index 0000000..749d721
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/bad-regnum.exp
@@ -0,0 +1,76 @@ 
+# Copyright 2015 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/>.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+standard_testfile bad-regnum.c bad-regnum-dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_language @DW_LANG_C}
+	    {DW_AT_name     bad-regnum-dw.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels integer_label
+
+	    integer_label: DW_TAG_base_type {
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+		{DW_AT_encoding  @DW_ATE_signed}
+		{DW_AT_name      integer}
+	    }
+
+	    DW_TAG_variable {
+		{DW_AT_name foo1}
+		{DW_AT_type :$integer_label}
+		{DW_AT_location {
+		    DW_OP_regx 2147483647
+		} SPECIAL_expr}
+		{external 1 flag}
+	    }
+
+	    DW_TAG_variable {
+		{DW_AT_name foo2}
+		{DW_AT_type :$integer_label}
+		{DW_AT_location {
+		    DW_OP_regx -1
+		} SPECIAL_expr}
+		{external 1 flag}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+	  [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "info addr foo1" \
+    "Symbol \"foo1\" is a variable in \\\$bad_register_number."
+
+gdb_test "info addr foo2" \
+    "Symbol \"foo2\" is a variable in \\\$bad_register_number."
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 515334e..df7a36d 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -836,6 +836,10 @@  namespace eval Dwarf {
  		    _op .${_cu_addr_size}byte [lindex $line 1]
  		}

+		DW_OP_regx {
+		    _op .uleb128 [lindex $line 1]
+		}
+
  		DW_OP_pick -
  		DW_OP_const1u -
  		DW_OP_const1s {