[PATCH v2 1/2] ISA bit treatment on the MIPS platform

Maciej W. Rozycki macro@codesourcery.com
Mon Oct 6 00:42:00 GMT 2014


Joel,

 I'd like to get back to this review, this change is important for 
reliable debugging compressed code, as test results quoted below indicate.

On Mon, 11 Jun 2012, Joel Brobecker wrote:

> >  I propose therefore to accept the existing inconsistencies and deal
> >  with them entirely within GDB.  I have figured out that the ISA bit
> >  lost in various places can still be recovered as long as we have
> >  symbol information -- that'll have the st_other attribute correctly
> >  set to one of standard MIPS/MIPS16/microMIPS.
> 
> That seems reasonable to me.

 Great!

> Just some minor comments below:
> 
> > gdb-mips16-isa-bit.diff
> > Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
> > ===================================================================
> > --- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c	2012-05-14 16:00:33.000000000 +0100
> > +++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c	2012-05-14 16:02:02.235560558 +0100
> > @@ -358,9 +358,15 @@ mips_elf_make_msymbol_special (asymbol *
> >      return;
> >  
> >    if (ELF_ST_IS_MICROMIPS (elfsym->internal_elf_sym.st_other))
> > -    MSYMBOL_TARGET_FLAG_2 (msym) = 1;
> > +    {
> > +      MSYMBOL_TARGET_FLAG_2 (msym) = 1;
> > +      SYMBOL_VALUE_ADDRESS (msym) |= 1;
> > +    }
> >    else if (ELF_ST_IS_MIPS16 (elfsym->internal_elf_sym.st_other))
> > -    MSYMBOL_TARGET_FLAG_1 (msym) = 1;
> > +    {
> > +      MSYMBOL_TARGET_FLAG_1 (msym) = 1;
> > +      SYMBOL_VALUE_ADDRESS (msym) |= 1;
> > +    }
> 
> This remark is not to be considered as part of this patch's review,
> since this is already an established practice, but I think we could do
> better than using magic numbers for those flags. I understand they have
> to be that way in the common code, but perhaps mips-tdep could define
> aliases? Something like MSYMBOL_MIPS_TARGET_FLAG_BLAH?

 Good point, I'll push such a change as a followup; I have it ready now.

> > Index: gdb-fsf-trunk-quilt/gdb/arch-utils.c
> [...]
> > +void
> > +default_make_symbol_special (struct symbol *sym, struct objfile *objfile)
> 
> Can you put a comment at the start of all these new functions to say
> that the documentation is in the header file? For instance, I think
> we typically say:
> 
>         /* See arch-utils.h.  */
> 
> This is to help someone reviewing the code to know that there is
> in fact documentation.

 Done now; please note there's no prior example of such commentary in 
arch-utils.c, so it's easy to fall in the trap of following surrounding 
code.

> > +/* Do nothing version of make_symbol_special.  */
> > +
> > +void default_make_symbol_special (struct symbol *sym, struct objfile *objfile);
> > +
> > +/* Do nothing version of adjust_dwarf2_addr.  */
> > +
> > +CORE_ADDR default_adjust_dwarf2_addr (CORE_ADDR pc);
> > +
> > +/* Do nothing version of adjust_dwarf2_line.  */
> > +
> > +CORE_ADDR default_adjust_dwarf2_line (CORE_ADDR addr, int rel);
> 
> I would definitely mention gdbarch in the function comment.
> Prior art uses:
> 
>     /* Default implementation of gdbarch_displaced_hw_singlestep.  */
> 
> Should we remain consistent with that? It can be a mix of both,
> saying what method it implements, and then what it actually does, Eg:
> 
>     /* Default version of gdbarch_make_symbol_special (does nothing).  */

 Like above, e.g.:

/* Do nothing version of coff_make_msymbol_special.  */

but again I find your suggestion very reasonable.  I decided upon wording 
like:

/* Do nothing default implementation of gdbarch_make_symbol_special.  */

> > Index: gdb-fsf-trunk-quilt/gdb/solib.c
> > ===================================================================
> > --- gdb-fsf-trunk-quilt.orig/gdb/solib.c	2012-05-14 15:56:45.000000000 +0100
> > +++ gdb-fsf-trunk-quilt/gdb/solib.c	2012-05-14 16:01:34.645558637 +0100
> > @@ -1384,8 +1384,27 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *
> >  
> >  	  if (match_sym (sym, data))
> >  	    {
> > +	      symaddr = sym->value;
> > +
> > +	      /* macro/2012-04-20: Some ELF targets fiddle with addresses
> > +	         of symbols they consider special.  They use minimal symbols
> > +	         to do that and this is needed for correct breakpoint
> > +	         placement, but we do not have full data here to build a
> > +	         complete minimal symbol, so just set the address and let the
> > +	         targets cope with that.  */
> > +	      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
> > +		{
> > +		  struct minimal_symbol msym;
> > +
> > +		  memset (&msym, 0, sizeof (msym));
> > +		  SYMBOL_VALUE_ADDRESS (&msym) = symaddr;
> > +		  gdbarch_elf_make_msymbol_special (target_gdbarch,
> > +						    sym, &msym);
> > +		  symaddr = SYMBOL_VALUE_ADDRESS (&msym);
> > +		}
> 
> Is there a way we could avoid that block if
> gdbarch_elf_make_msymbol_special points to the default implementation?
> It just seems sad to be doing all this work of creating a temporary symbol
> for every solib symbol on non-mips targets...
> 
> One possible way would have been to provide no default value for
> gdbarch_elf_make_msymbol_special, but then it makes the calling
> of that method a little trickier. That could be worked around by
> changing the default value of gdbarch_elf_make_msymbol_special to NULL,
> and then having an extra wrapper function that call the gdbarch
> method if not NULL or else does nothing.

 The only other call sites are in `elf_symtab_read' in gdb/elfread.c, so 
while I agree the block in gdb/solib.c will best be avoided, I'd call your 
proposal to make a wrapper an overkill and actually a pessimisation.  

 Instead I propose the change I included below, where 
`gdbarch_elf_make_msymbol_special_p' is called once per `elf_symtab_read' 
invocation only, avoiding all the `gdbarch_elf_make_msymbol_special_p' or 
`gdbarch_elf_make_msymbol_special' indirection being called for nothing 
where the latter function doesn't do anything.  This is actually an 
improvement over our current trunk as it is.  We can think of something 
fancier if a need arises in the future.

 Here's an updated change.  Beside the changes above I have made an update 
to `micromips_linux_sigframe_validate' in gdb/mips-linux-tdep.c, to take 
the change to support microMIPS signal frames posted separately into 
account.  Also I have updated numerous places in gdb/dwarf2read.c so that 
the ISA bit is applied to the PC consistently.  This cured some 
regressions the original change caused, so that there are no regressions 
after this change and the test suite fix sent as a complement.  Finally a 
test case is now also included that covers scenarios this fix addresses; 
the test case fails for MIPS16 and microMIPS multilibs with our current 
trunk as it is.  It is quite possible that the test case will reveal 
issues on other targets too.

 For those who have already forgotten what it is all about, the original 
description is available here:

http://sourceware.org/ml/gdb-patches/2012-05/msg00515.html

 I have regression tested this updated version with the mips-linux-gnu 
target and the following multilibs:

-EB
-EB -msoft-float
-EB -mips16
-EB -mips16 -msoft-float
-EB -mmicromips
-EB -mmicromips -msoft-float
-EB -mabi=n32
-EB -mabi=n32 -msoft-float
-EB -mabi=64
-EB -mabi=64 -msoft-float

and the -EL variants of same, reducing the total number of failures 
counted across all multilibs from ~8500 to ~3750.  Numbers are indicative 
because of intermittent errors; gdb.threads/schedlock.exp is particularly 
notorious with fluctuations in the range of 50 total across all multilibs 
being normal.  These numbers include fixes made with the other change.

 An indicative test summary change for a single multilib, -EB -mmicromips, 
before:

		=== gdb Summary ===

# of expected passes		16585
# of unexpected failures	1272
# of unexpected successes	1
# of expected failures		29
# of known failures		54
# of unresolved testcases	5
# of untested testcases		50
# of unsupported tests		257

and after:

		=== gdb Summary ===

# of expected passes		17717
# of unexpected failures	175
# of unexpected successes	1
# of expected failures		29
# of known failures		56
# of unresolved testcases	5
# of untested testcases		50
# of unsupported tests		268

 This change does cause regressions, across all multilibs, in some test 
cases that use artificial DWARF-2 records.  These include:

gdb.cp/nsalias.exp
gdb.dwarf2/dw2-canonicalize-type.exp
gdb.dwarf2/dw2-empty-pc-range.exp
gdb.dwarf2/pr11465.exp

It also causes regressions across compressed ISA multilibs only in:

gdb.cp/expand-psymtabs-cxx.exp
gdb.dwarf2/dw2-case-insensitive.exp

These tests just make wrong assumptions that can't stand for the MIPS 
target, e.g. that a function can be 1-byte long (wrong, the smallest MIPS 
instruction takes 2 bytes).  The other patch sent as a complement 
addresses these issues, which are all test case deficiencies rather than 
problems with this change.

 OK to apply?

2014-10-06  Maciej W. Rozycki  <macro@codesourcery.com>
            Maciej W. Rozycki  <macro@mips.com>
            Pedro Alves  <pedro@codesourcery.com>

	* gdbarch.sh (elf_make_msymbol_special): Change type to `F',
	remove `predefault' and `invalid_p' initializers.
	(make_symbol_special): New architecture method.
	(adjust_dwarf2_addr, adjust_dwarf2_line): Likewise.
	(objfile, symbol): New declarations.
	* arch-utils.h (default_elf_make_msymbol_special): Remove
	prototype.
	(default_make_symbol_special): New prototype.
	(default_adjust_dwarf2_addr): Likewise.
	(default_adjust_dwarf2_line): Likewise.
	* mips-tdep.h (mips_unmake_compact_addr): New prototype.
	* arch-utils.c (default_elf_make_msymbol_special): Remove
	function.
	(default_make_symbol_special): New function.
	(default_adjust_dwarf2_addr): Likewise.
	(default_adjust_dwarf2_line): Likewise.
	* dwarf2-frame.c (decode_frame_entry_1): Call
	`gdbarch_adjust_dwarf2_addr'.
	* dwarf2loc.c (dwarf2_find_location_expression): Likewise.
	* dwarf2read.c (create_addrmap_from_index): Likewise.
	(process_psymtab_comp_unit_reader): Likewise.
	(add_partial_symbol): Likewise.
	(add_partial_subprogram): Likewise.
	(process_full_comp_unit): Likewise.
	(read_file_scope): Likewise.
	(read_func_scope): Likewise.  Call `gdbarch_make_symbol_special'.
	(read_lexical_block_scope): Call `gdbarch_adjust_dwarf2_addr'.
	(read_call_site_scope): Likewise.
	(dwarf2_ranges_read): Likewise.
	(dwarf2_record_block_ranges): Likewise.
	(read_attribute_value): Likewise.
	(dwarf_decode_lines_1): Call `gdbarch_adjust_dwarf2_line'.
	(new_symbol_full): Call `gdbarch_adjust_dwarf2_addr'.
	* elfread.c (elf_symtab_read): Don't call
	`gdbarch_elf_make_msymbol_special' if unset.
	* mips-linux-tdep.c (micromips_linux_sigframe_validate): Strip
	the ISA bit from the PC.
	* mips-tdep.c (mips_unmake_compact_addr): New function.
	(mips_elf_make_msymbol_special): Set the ISA bit in the symbol's
	address appropriately.
	(mips_make_symbol_special): New function.
	(mips_pc_is_mips): Set the ISA bit before symbol lookup.
	(mips_pc_is_mips16): Likewise.
	(mips_pc_is_micromips): Likewise.
	(mips_pc_isa): Likewise.
	(mips_adjust_dwarf2_addr): New function.
	(mips_adjust_dwarf2_line): Likewise.
	(mips_read_pc, mips_unwind_pc): Keep the ISA bit.
	(mips_addr_bits_remove): Likewise.
	(mips_skip_trampoline_code): Likewise.
	(mips_write_pc): Don't set the ISA bit.
	(mips_eabi_push_dummy_call): Likewise.
	(mips_o64_push_dummy_call): Likewise.
	(mips_gdbarch_init): Install `mips_make_symbol_special',
	`mips_adjust_dwarf2_addr' and `mips_adjust_dwarf2_line' gdbarch
	handlers.
	* solib.c (gdb_bfd_lookup_symbol_from_symtab): Get
	target-specific symbol address adjustments.
	* gdbarch.h: Regenerate.
	* gdbarch.c: Regenerate.

2014-10-06  Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/testsuite/
	* gdb.base/func-ptrs.c: New file.
	* gdb.base/func-ptrs.exp: New file.

  Maciej

gdb-mips16-isa-bit.diff
Index: gdb-fsf-trunk-quilt/gdb/arch-utils.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/arch-utils.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/arch-utils.c	2014-10-03 14:50:26.000000000 +0100
@@ -31,6 +31,7 @@
 #include "target-descriptions.h"
 #include "objfiles.h"
 #include "language.h"
+#include "symtab.h"
 
 #include "version.h"
 
@@ -167,17 +168,35 @@ no_op_reg_to_regnum (struct gdbarch *gdb
 }
 
 void
-default_elf_make_msymbol_special (asymbol *sym, struct minimal_symbol *msym)
+default_coff_make_msymbol_special (int val, struct minimal_symbol *msym)
 {
   return;
 }
 
+/* See arch-utils.h.  */
+
 void
-default_coff_make_msymbol_special (int val, struct minimal_symbol *msym)
+default_make_symbol_special (struct symbol *sym, struct objfile *objfile)
 {
   return;
 }
 
+/* See arch-utils.h.  */
+
+CORE_ADDR
+default_adjust_dwarf2_addr (CORE_ADDR pc)
+{
+  return pc;
+}
+
+/* See arch-utils.h.  */
+
+CORE_ADDR
+default_adjust_dwarf2_line (CORE_ADDR addr, int rel)
+{
+  return addr;
+}
+
 int
 cannot_register_not (struct gdbarch *gdbarch, int regnum)
 {
Index: gdb-fsf-trunk-quilt/gdb/arch-utils.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/arch-utils.h	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/arch-utils.h	2014-10-03 14:50:26.000000000 +0100
@@ -68,15 +68,22 @@ extern gdbarch_convert_from_func_ptr_add
 
 extern int no_op_reg_to_regnum (struct gdbarch *gdbarch, int reg);
 
-/* Do nothing version of elf_make_msymbol_special.  */
-
-void default_elf_make_msymbol_special (asymbol *sym,
-				       struct minimal_symbol *msym);
-
 /* Do nothing version of coff_make_msymbol_special.  */
 
 void default_coff_make_msymbol_special (int val, struct minimal_symbol *msym);
 
+/* Do nothing default implementation of gdbarch_make_symbol_special.  */
+
+void default_make_symbol_special (struct symbol *sym, struct objfile *objfile);
+
+/* Do nothing default implementation of gdbarch_adjust_dwarf2_addr.  */
+
+CORE_ADDR default_adjust_dwarf2_addr (CORE_ADDR pc);
+
+/* Do nothing default implementation of gdbarch_adjust_dwarf2_line.  */
+
+CORE_ADDR default_adjust_dwarf2_line (CORE_ADDR addr, int rel);
+
 /* Version of cannot_fetch_register() / cannot_store_register() that
    always fails.  */
 
Index: gdb-fsf-trunk-quilt/gdb/dwarf2-frame.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/dwarf2-frame.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/dwarf2-frame.c	2014-10-03 14:50:26.398945943 +0100
@@ -2067,6 +2067,7 @@ decode_frame_entry_1 (struct comp_unit *
     {
       /* This is a FDE.  */
       struct dwarf2_fde *fde;
+      CORE_ADDR addr;
 
       /* Check that an FDE was expected.  */
       if ((entry_type & EH_FDE_TYPE_ID) == 0)
@@ -2100,14 +2101,16 @@ decode_frame_entry_1 (struct comp_unit *
 
       gdb_assert (fde->cie != NULL);
 
-      fde->initial_location =
-	read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size,
-			    buf, &bytes_read, 0);
+      addr = read_encoded_value (unit, fde->cie->encoding, fde->cie->ptr_size,
+				 buf, &bytes_read, 0);
+      fde->initial_location = gdbarch_adjust_dwarf2_addr (gdbarch, addr);
       buf += bytes_read;
 
       fde->address_range =
 	read_encoded_value (unit, fde->cie->encoding & 0x0f,
 			    fde->cie->ptr_size, buf, &bytes_read, 0);
+      addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + fde->address_range);
+      fde->address_range = addr - fde->initial_location;
       buf += bytes_read;
 
       /* A 'z' augmentation in the CIE implies the presence of an
Index: gdb-fsf-trunk-quilt/gdb/dwarf2loc.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/dwarf2loc.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/dwarf2loc.c	2014-10-03 14:50:26.398945943 +0100
@@ -4294,6 +4294,9 @@ loclist_describe_location (struct symbol
       low += base_address;
       high += base_address;
 
+      low = gdbarch_adjust_dwarf2_addr (gdbarch, low);
+      high = gdbarch_adjust_dwarf2_addr (gdbarch, high);
+
       length = extract_unsigned_integer (loc_ptr, 2, byte_order);
       loc_ptr += 2;
 
Index: gdb-fsf-trunk-quilt/gdb/dwarf2read.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/dwarf2read.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/dwarf2read.c	2014-10-06 00:13:56.039006986 +0100
@@ -2824,6 +2824,7 @@ create_signatured_type_table_from_index 
 static void
 create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
 {
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   const gdb_byte *iter, *end;
   struct obstack temp_obstack;
   struct addrmap *mutable_map;
@@ -2865,8 +2866,9 @@ create_addrmap_from_index (struct objfil
 	  continue;
 	}
 
-      addrmap_set_empty (mutable_map, lo + baseaddr, hi + baseaddr - 1,
-			 dw2_get_cutu (cu_index));
+      lo = gdbarch_adjust_dwarf2_addr (gdbarch, lo + baseaddr);
+      hi = gdbarch_adjust_dwarf2_addr (gdbarch, hi + baseaddr);
+      addrmap_set_empty (mutable_map, lo, hi - 1, dw2_get_cutu (cu_index));
     }
 
   objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
@@ -5848,6 +5850,7 @@ process_psymtab_comp_unit_reader (const 
 {
   struct dwarf2_cu *cu = reader->cu;
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct dwarf2_per_cu_data *per_cu = cu->per_cu;
   struct attribute *attr;
   CORE_ADDR baseaddr;
@@ -5892,8 +5895,11 @@ process_psymtab_comp_unit_reader (const 
     /* Store the contiguous range if it is not empty; it can be empty for
        CUs with no code.  */
     addrmap_set_empty (objfile->psymtabs_addrmap,
-		       best_lowpc + baseaddr,
-		       best_highpc + baseaddr - 1, pst);
+		       gdbarch_adjust_dwarf2_addr (gdbarch,
+						   best_lowpc + baseaddr),
+		       gdbarch_adjust_dwarf2_addr (gdbarch,
+						   best_highpc + baseaddr) - 1,
+		       pst);
 
   /* Check if comp unit has_children.
      If so, read the rest of the partial symbols from this comp unit.
@@ -5924,8 +5930,8 @@ process_psymtab_comp_unit_reader (const 
 	  best_highpc = highpc;
 	}
     }
-  pst->textlow = best_lowpc + baseaddr;
-  pst->texthigh = best_highpc + baseaddr;
+  pst->textlow = gdbarch_adjust_dwarf2_addr (gdbarch, best_lowpc + baseaddr);
+  pst->texthigh = gdbarch_adjust_dwarf2_addr (gdbarch, best_highpc + baseaddr);
 
   pst->n_global_syms = objfile->global_psymbols.next -
     (objfile->global_psymbols.list + pst->globals_offset);
@@ -6788,6 +6794,7 @@ static void
 add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   CORE_ADDR addr = 0;
   const char *actual_name = NULL;
   CORE_ADDR baseaddr;
@@ -6805,31 +6812,30 @@ add_partial_symbol (struct partial_die_i
   switch (pdi->tag)
     {
     case DW_TAG_subprogram:
+      addr = gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr);
       if (pdi->is_external || cu->language == language_ada)
 	{
           /* brobecker/2007-12-26: Normally, only "external" DIEs are part
              of the global scope.  But in Ada, we want to be able to access
              nested procedures globally.  So all Ada subprograms are stored
              in the global scope.  */
-	  /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr,
-	     mst_text, objfile); */
+	  /* prim_record_minimal_symbol (actual_name, addr, mst_text,
+	     objfile); */
 	  add_psymbol_to_list (actual_name, strlen (actual_name),
 			       built_actual_name != NULL,
 			       VAR_DOMAIN, LOC_BLOCK,
 			       &objfile->global_psymbols,
-			       0, pdi->lowpc + baseaddr,
-			       cu->language, objfile);
+			       0, addr, cu->language, objfile);
 	}
       else
 	{
-	  /* prim_record_minimal_symbol (actual_name, pdi->lowpc + baseaddr,
-	     mst_file_text, objfile); */
+	  /* prim_record_minimal_symbol (actual_name, addr, mst_file_text,
+	     objfile); */
 	  add_psymbol_to_list (actual_name, strlen (actual_name),
 			       built_actual_name != NULL,
 			       VAR_DOMAIN, LOC_BLOCK,
 			       &objfile->static_psymbols,
-			       0, pdi->lowpc + baseaddr,
-			       cu->language, objfile);
+			       0, addr, cu->language, objfile);
 	}
       break;
     case DW_TAG_constant:
@@ -7020,6 +7026,9 @@ add_partial_subprogram (struct partial_d
 			CORE_ADDR *lowpc, CORE_ADDR *highpc,
 			int set_addrmap, struct dwarf2_cu *cu)
 {
+  struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
   if (pdi->tag == DW_TAG_subprogram)
     {
       if (pdi->has_pc_info)
@@ -7030,14 +7039,18 @@ add_partial_subprogram (struct partial_d
             *highpc = pdi->highpc;
 	  if (set_addrmap)
 	    {
-	      CORE_ADDR baseaddr;
 	      struct objfile *objfile = cu->objfile;
+	      CORE_ADDR baseaddr;
+	      CORE_ADDR highpc;
+	      CORE_ADDR lowpc;
 
 	      baseaddr = ANOFFSET (objfile->section_offsets,
 				   SECT_OFF_TEXT (objfile));
-	      addrmap_set_empty (objfile->psymtabs_addrmap,
-				 pdi->lowpc + baseaddr,
-				 pdi->highpc - 1 + baseaddr,
+	      lowpc = gdbarch_adjust_dwarf2_addr (gdbarch,
+						  pdi->lowpc + baseaddr);
+	      highpc = gdbarch_adjust_dwarf2_addr (gdbarch,
+						   pdi->highpc + baseaddr);
+	      addrmap_set_empty (objfile->psymtabs_addrmap, lowpc, highpc - 1,
 				 cu->per_cu->v.psymtab);
 	    }
         }
@@ -7921,11 +7934,13 @@ process_full_comp_unit (struct dwarf2_pe
 {
   struct dwarf2_cu *cu = per_cu->cu;
   struct objfile *objfile = per_cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   CORE_ADDR lowpc, highpc;
   struct symtab *symtab;
   struct cleanup *back_to, *delayed_list_cleanup;
   CORE_ADDR baseaddr;
   struct block *static_block;
+  CORE_ADDR addr;
 
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
@@ -7956,8 +7971,8 @@ process_full_comp_unit (struct dwarf2_pe
      it, by scanning the DIE's below the compilation unit.  */
   get_scope_pc_bounds (cu->dies, &lowpc, &highpc, cu);
 
-  static_block
-    = end_symtab_get_static_block (highpc + baseaddr, objfile, 0, 1);
+  addr = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr);
+  static_block = end_symtab_get_static_block (addr, objfile, 0, 1);
 
   /* If the comp unit has DW_AT_ranges, it may have discontiguous ranges.
      Also, DW_AT_ranges may record ranges not belonging to any child DIEs
@@ -9001,6 +9016,7 @@ static void
 read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct cleanup *back_to = make_cleanup (null_cleanup, 0);
   CORE_ADDR lowpc = ((CORE_ADDR) -1);
   CORE_ADDR highpc = ((CORE_ADDR) 0);
@@ -9019,8 +9035,7 @@ read_file_scope (struct die_info *die, s
      from finish_block.  */
   if (lowpc == ((CORE_ADDR) -1))
     lowpc = highpc;
-  lowpc += baseaddr;
-  highpc += baseaddr;
+  lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
 
   find_file_and_directory (die, cu, &name, &comp_dir);
 
@@ -11131,6 +11146,7 @@ static void
 read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct context_stack *new;
   CORE_ADDR lowpc;
   CORE_ADDR highpc;
@@ -11183,8 +11199,8 @@ read_func_scope (struct die_info *die, s
       return;
     }
 
-  lowpc += baseaddr;
-  highpc += baseaddr;
+  lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
+  highpc = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr);
 
   /* If we have any template arguments, then we must allocate a
      different sort of symbol.  */
@@ -11271,6 +11287,8 @@ read_func_scope (struct die_info *die, s
   /* If we have address ranges, record them.  */
   dwarf2_record_block_ranges (die, block, baseaddr, cu);
 
+  gdbarch_make_symbol_special (gdbarch, new->name, objfile);
+
   /* Attach template arguments to function.  */
   if (! VEC_empty (symbolp, template_args))
     {
@@ -11307,6 +11325,7 @@ static void
 read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct context_stack *new;
   CORE_ADDR lowpc, highpc;
   struct die_info *child_die;
@@ -11321,8 +11340,8 @@ read_lexical_block_scope (struct die_inf
      describe ranges.  */
   if (!dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL))
     return;
-  lowpc += baseaddr;
-  highpc += baseaddr;
+  lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
+  highpc = gdbarch_adjust_dwarf2_addr (gdbarch, highpc + baseaddr);
 
   push_context (0, lowpc);
   if (die->child != NULL)
@@ -11384,6 +11403,7 @@ read_call_site_scope (struct die_info *d
       return;
     }
   pc = attr_value_as_address (attr) + baseaddr;
+  pc = gdbarch_adjust_dwarf2_addr (gdbarch, pc);
 
   if (cu->call_site_htab == NULL)
     cu->call_site_htab = htab_create_alloc_ex (16, core_addr_hash, core_addr_eq,
@@ -11532,7 +11552,10 @@ read_call_site_scope (struct die_info *d
 		         "low pc, for referencing DIE 0x%x [in module %s]"),
 		       die->offset.sect_off, objfile_name (objfile));
 	  else
-	    SET_FIELD_PHYSADDR (call_site->target, lowpc + baseaddr);
+	    {
+	      lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
+	      SET_FIELD_PHYSADDR (call_site->target, lowpc);
+	    }
 	}
     }
   else
@@ -11660,6 +11683,7 @@ dwarf2_ranges_read (unsigned offset, COR
 		    struct partial_symtab *ranges_pst)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct comp_unit_head *cu_header = &cu->header;
   bfd *obfd = objfile->obfd;
   unsigned int addr_size = cu_header->addr_size;
@@ -11767,10 +11791,17 @@ dwarf2_ranges_read (unsigned offset, COR
 	}
 
       if (ranges_pst != NULL)
-	addrmap_set_empty (objfile->psymtabs_addrmap,
-			   range_beginning + baseaddr,
-			   range_end - 1 + baseaddr,
-			   ranges_pst);
+	{
+	  CORE_ADDR lowpc;
+	  CORE_ADDR highpc;
+
+	  lowpc = gdbarch_adjust_dwarf2_addr (gdbarch,
+					      range_beginning + baseaddr);
+	  highpc = gdbarch_adjust_dwarf2_addr (gdbarch,
+					       range_end + baseaddr);
+	  addrmap_set_empty (objfile->psymtabs_addrmap, lowpc, highpc - 1,
+			     ranges_pst);
+	}
 
       /* FIXME: This is recording everything as a low-high
 	 segment of consecutive addresses.  We should have a
@@ -11984,6 +12015,7 @@ dwarf2_record_block_ranges (struct die_i
                             CORE_ADDR baseaddr, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct attribute *attr;
   struct attribute *attr_high;
 
@@ -11999,7 +12031,9 @@ dwarf2_record_block_ranges (struct die_i
 	  if (cu->header.version >= 4 && attr_form_is_constant (attr_high))
 	    high += low;
 
-          record_block_range (block, baseaddr + low, baseaddr + high - 1);
+	  low = gdbarch_adjust_dwarf2_addr (gdbarch, low + baseaddr);
+	  high = gdbarch_adjust_dwarf2_addr (gdbarch, high + baseaddr);
+	  record_block_range (block, low, high - 1);
         }
     }
 
@@ -12103,6 +12137,8 @@ dwarf2_record_block_ranges (struct die_i
 		  continue;
 		}
 
+	      start = gdbarch_adjust_dwarf2_addr (gdbarch, start);
+	      end = gdbarch_adjust_dwarf2_addr (gdbarch, end);
               record_block_range (block, start, end - 1);
             }
         }
@@ -15926,6 +15962,8 @@ read_attribute_value (const struct die_r
 		      const gdb_byte *info_ptr)
 {
   struct dwarf2_cu *cu = reader->cu;
+  struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   bfd *abfd = reader->abfd;
   struct comp_unit_head *cu_header = &cu->header;
   unsigned int bytes_read;
@@ -15948,6 +15986,7 @@ read_attribute_value (const struct die_r
       break;
     case DW_FORM_addr:
       DW_ADDR (attr) = read_address (abfd, info_ptr, cu, &bytes_read);
+      DW_ADDR (attr) = gdbarch_adjust_dwarf2_addr (gdbarch, DW_ADDR (attr));
       info_ptr += bytes_read;
       break;
     case DW_FORM_block2:
@@ -17278,7 +17317,7 @@ dwarf_decode_lines_1 (struct line_header
   while (line_ptr < line_end)
     {
       /* state machine registers  */
-      CORE_ADDR address = 0;
+      CORE_ADDR address = gdbarch_adjust_dwarf2_line (gdbarch, 0, 0);
       unsigned int file = 1;
       unsigned int line = 1;
       int is_stmt = lh->default_is_stmt;
@@ -17321,12 +17360,14 @@ dwarf_decode_lines_1 (struct line_header
 	    {
 	      /* Special opcode.  */
 	      unsigned char adj_opcode;
+	      CORE_ADDR addr_adj;
 	      int line_delta;
 
 	      adj_opcode = op_code - lh->opcode_base;
-	      address += (((op_index + (adj_opcode / lh->line_range))
+	      addr_adj = (((op_index + (adj_opcode / lh->line_range))
 			   / lh->maximum_ops_per_instruction)
 			  * lh->minimum_instruction_length);
+	      address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
 	      op_index = ((op_index + (adj_opcode / lh->line_range))
 			  % lh->maximum_ops_per_instruction);
 	      line_delta = lh->line_base + (adj_opcode % lh->line_range);
@@ -17403,6 +17444,7 @@ dwarf_decode_lines_1 (struct line_header
 		  op_index = 0;
 		  line_ptr += bytes_read;
 		  address += baseaddr;
+		  address = gdbarch_adjust_dwarf2_line (gdbarch, address, 0);
 		  break;
 		case DW_LNE_define_file:
                   {
@@ -17480,10 +17522,12 @@ dwarf_decode_lines_1 (struct line_header
 	      {
 		CORE_ADDR adjust
 		  = read_unsigned_leb128 (abfd, line_ptr, &bytes_read);
+		CORE_ADDR addr_adj;
 
-		address += (((op_index + adjust)
+		addr_adj = (((op_index + adjust)
 			     / lh->maximum_ops_per_instruction)
 			    * lh->minimum_instruction_length);
+		address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
 		op_index = ((op_index + adjust)
 			    % lh->maximum_ops_per_instruction);
 		line_ptr += bytes_read;
@@ -17543,18 +17587,25 @@ dwarf_decode_lines_1 (struct line_header
 	    case DW_LNS_const_add_pc:
 	      {
 		CORE_ADDR adjust = (255 - lh->opcode_base) / lh->line_range;
+		CORE_ADDR addr_adj;
 
-		address += (((op_index + adjust)
+		addr_adj = (((op_index + adjust)
 			     / lh->maximum_ops_per_instruction)
 			    * lh->minimum_instruction_length);
+		address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
 		op_index = ((op_index + adjust)
 			    % lh->maximum_ops_per_instruction);
 	      }
 	      break;
 	    case DW_LNS_fixed_advance_pc:
-	      address += read_2_bytes (abfd, line_ptr);
-	      op_index = 0;
-	      line_ptr += 2;
+	      {
+		CORE_ADDR addr_adj;
+
+		addr_adj = read_2_bytes (abfd, line_ptr);
+		address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1);
+		op_index = 0;
+		line_ptr += 2;
+	      }
 	      break;
 	    default:
 	      {
@@ -17811,6 +17862,7 @@ new_symbol_full (struct die_info *die, s
 		 struct symbol *space)
 {
   struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
   struct symbol *sym = NULL;
   const char *name;
   struct attribute *attr = NULL;
@@ -17888,8 +17940,13 @@ new_symbol_full (struct die_info *die, s
 	case DW_TAG_label:
 	  attr = dwarf2_attr (die, DW_AT_low_pc, cu);
 	  if (attr)
-	    SYMBOL_VALUE_ADDRESS (sym)
-	      = attr_value_as_address (attr) + baseaddr;
+	    {
+	      CORE_ADDR addr;
+
+	      addr = attr_value_as_address (attr);
+	      addr = gdbarch_adjust_dwarf2_addr (gdbarch, addr + baseaddr);
+	      SYMBOL_VALUE_ADDRESS (sym) = addr;
+	    }
 	  SYMBOL_TYPE (sym) = objfile_type (objfile)->builtin_core_addr;
 	  SYMBOL_DOMAIN (sym) = LABEL_DOMAIN;
 	  SYMBOL_ACLASS_INDEX (sym) = LOC_LABEL;
Index: gdb-fsf-trunk-quilt/gdb/elfread.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/elfread.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/elfread.c	2014-10-03 14:50:26.398945943 +0100
@@ -247,6 +247,8 @@ elf_symtab_read (struct objfile *objfile
   const char *filesymname = "";
   struct dbx_symfile_info *dbx = DBX_SYMFILE_INFO (objfile);
   int stripped = (bfd_get_symcount (objfile->obfd) == 0);
+  int elf_make_msymbol_special_p
+    = gdbarch_elf_make_msymbol_special_p (gdbarch);
 
   for (i = 0; i < number_of_symbols; i++)
     {
@@ -330,7 +332,8 @@ elf_symtab_read (struct objfile *objfile
 	  if (msym != NULL)
 	    {
 	      msym->filename = filesymname;
-	      gdbarch_elf_make_msymbol_special (gdbarch, sym, msym);
+	      if (elf_make_msymbol_special_p)
+		gdbarch_elf_make_msymbol_special (gdbarch, sym, msym);
 	    }
 	  continue;
 	}
@@ -558,7 +561,8 @@ elf_symtab_read (struct objfile *objfile
 		}
 
 	      msym->filename = filesymname;
-	      gdbarch_elf_make_msymbol_special (gdbarch, sym, msym);
+	      if (elf_make_msymbol_special_p)
+		gdbarch_elf_make_msymbol_special (gdbarch, sym, msym);
 	    }
 
 	  /* If we see a default versioned symbol, install it under
@@ -597,7 +601,9 @@ elf_symtab_read (struct objfile *objfile
 		      SET_MSYMBOL_SIZE (mtramp, MSYMBOL_SIZE (msym));
 		      mtramp->created_by_gdb = 1;
 		      mtramp->filename = filesymname;
-		      gdbarch_elf_make_msymbol_special (gdbarch, sym, mtramp);
+		      if (elf_make_msymbol_special_p)
+			gdbarch_elf_make_msymbol_special (gdbarch,
+							  sym, mtramp);
 		    }
 		}
 	    }
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.c	2014-10-03 14:50:26.000000000 +0100
@@ -252,6 +252,9 @@ struct gdbarch
   gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p;
   gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special;
   gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special;
+  gdbarch_make_symbol_special_ftype *make_symbol_special;
+  gdbarch_adjust_dwarf2_addr_ftype *adjust_dwarf2_addr;
+  gdbarch_adjust_dwarf2_line_ftype *adjust_dwarf2_line;
   int cannot_step_breakpoint;
   int have_nonsteppable_watchpoint;
   gdbarch_address_class_type_flags_ftype *address_class_type_flags;
@@ -390,8 +393,10 @@ gdbarch_alloc (const struct gdbarch_info
   gdbarch->skip_solib_resolver = generic_skip_solib_resolver;
   gdbarch->in_solib_return_trampoline = generic_in_solib_return_trampoline;
   gdbarch->in_function_epilogue_p = generic_in_function_epilogue_p;
-  gdbarch->elf_make_msymbol_special = default_elf_make_msymbol_special;
   gdbarch->coff_make_msymbol_special = default_coff_make_msymbol_special;
+  gdbarch->make_symbol_special = default_make_symbol_special;
+  gdbarch->adjust_dwarf2_addr = default_adjust_dwarf2_addr;
+  gdbarch->adjust_dwarf2_line = default_adjust_dwarf2_line;
   gdbarch->register_reggroup_p = default_register_reggroup_p;
   gdbarch->displaced_step_hw_singlestep = default_displaced_step_hw_singlestep;
   gdbarch->displaced_step_fixup = NULL;
@@ -561,8 +566,11 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of skip_solib_resolver, invalid_p == 0 */
   /* Skip verify of in_solib_return_trampoline, invalid_p == 0 */
   /* Skip verify of in_function_epilogue_p, invalid_p == 0 */
-  /* Skip verify of elf_make_msymbol_special, invalid_p == 0 */
+  /* Skip verify of elf_make_msymbol_special, has predicate.  */
   /* Skip verify of coff_make_msymbol_special, invalid_p == 0 */
+  /* Skip verify of make_symbol_special, invalid_p == 0 */
+  /* Skip verify of adjust_dwarf2_addr, invalid_p == 0 */
+  /* Skip verify of adjust_dwarf2_line, invalid_p == 0 */
   /* Skip verify of cannot_step_breakpoint, invalid_p == 0 */
   /* Skip verify of have_nonsteppable_watchpoint, invalid_p == 0 */
   /* Skip verify of address_class_type_flags, has predicate.  */
@@ -684,6 +692,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: adjust_breakpoint_address = <%s>\n",
                       host_address_to_string (gdbarch->adjust_breakpoint_address));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: adjust_dwarf2_addr = <%s>\n",
+                      host_address_to_string (gdbarch->adjust_dwarf2_addr));
+  fprintf_unfiltered (file,
+                      "gdbarch_dump: adjust_dwarf2_line = <%s>\n",
+                      host_address_to_string (gdbarch->adjust_dwarf2_line));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: auto_charset = <%s>\n",
                       host_address_to_string (gdbarch->auto_charset));
   fprintf_unfiltered (file,
@@ -834,6 +848,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: ecoff_reg_to_regnum = <%s>\n",
                       host_address_to_string (gdbarch->ecoff_reg_to_regnum));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: gdbarch_elf_make_msymbol_special_p() = %d\n",
+                      gdbarch_elf_make_msymbol_special_p (gdbarch));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: elf_make_msymbol_special = <%s>\n",
                       host_address_to_string (gdbarch->elf_make_msymbol_special));
   fprintf_unfiltered (file,
@@ -1008,6 +1025,9 @@ gdbarch_dump (struct gdbarch *gdbarch, s
                       "gdbarch_dump: make_corefile_notes = <%s>\n",
                       host_address_to_string (gdbarch->make_corefile_notes));
   fprintf_unfiltered (file,
+                      "gdbarch_dump: make_symbol_special = <%s>\n",
+                      host_address_to_string (gdbarch->make_symbol_special));
+  fprintf_unfiltered (file,
                       "gdbarch_dump: gdbarch_max_insn_length_p() = %d\n",
                       gdbarch_max_insn_length_p (gdbarch));
   fprintf_unfiltered (file,
@@ -3055,6 +3075,13 @@ set_gdbarch_in_function_epilogue_p (stru
   gdbarch->in_function_epilogue_p = in_function_epilogue_p;
 }
 
+int
+gdbarch_elf_make_msymbol_special_p (struct gdbarch *gdbarch)
+{
+  gdb_assert (gdbarch != NULL);
+  return gdbarch->elf_make_msymbol_special != NULL;
+}
+
 void
 gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym)
 {
@@ -3089,6 +3116,57 @@ set_gdbarch_coff_make_msymbol_special (s
   gdbarch->coff_make_msymbol_special = coff_make_msymbol_special;
 }
 
+void
+gdbarch_make_symbol_special (struct gdbarch *gdbarch, struct symbol *sym, struct objfile *objfile)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->make_symbol_special != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_make_symbol_special called\n");
+  gdbarch->make_symbol_special (sym, objfile);
+}
+
+void
+set_gdbarch_make_symbol_special (struct gdbarch *gdbarch,
+                                 gdbarch_make_symbol_special_ftype make_symbol_special)
+{
+  gdbarch->make_symbol_special = make_symbol_special;
+}
+
+CORE_ADDR
+gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->adjust_dwarf2_addr != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_adjust_dwarf2_addr called\n");
+  return gdbarch->adjust_dwarf2_addr (pc);
+}
+
+void
+set_gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch,
+                                gdbarch_adjust_dwarf2_addr_ftype adjust_dwarf2_addr)
+{
+  gdbarch->adjust_dwarf2_addr = adjust_dwarf2_addr;
+}
+
+CORE_ADDR
+gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, CORE_ADDR addr, int rel)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->adjust_dwarf2_line != NULL);
+  if (gdbarch_debug >= 2)
+    fprintf_unfiltered (gdb_stdlog, "gdbarch_adjust_dwarf2_line called\n");
+  return gdbarch->adjust_dwarf2_line (addr, rel);
+}
+
+void
+set_gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch,
+                                gdbarch_adjust_dwarf2_line_ftype adjust_dwarf2_line)
+{
+  gdbarch->adjust_dwarf2_line = adjust_dwarf2_line;
+}
+
 int
 gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch)
 {
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.h	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.h	2014-10-03 14:50:26.000000000 +0100
@@ -51,6 +51,8 @@ struct target_ops;
 struct obstack;
 struct bp_target_info;
 struct target_desc;
+struct objfile;
+struct symbol;
 struct displaced_step_closure;
 struct core_regset_section;
 struct syscall;
@@ -682,6 +684,8 @@ typedef int (gdbarch_in_function_epilogu
 extern int gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr);
 extern void set_gdbarch_in_function_epilogue_p (struct gdbarch *gdbarch, gdbarch_in_function_epilogue_p_ftype *in_function_epilogue_p);
 
+extern int gdbarch_elf_make_msymbol_special_p (struct gdbarch *gdbarch);
+
 typedef void (gdbarch_elf_make_msymbol_special_ftype) (asymbol *sym, struct minimal_symbol *msym);
 extern void gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, asymbol *sym, struct minimal_symbol *msym);
 extern void set_gdbarch_elf_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_elf_make_msymbol_special_ftype *elf_make_msymbol_special);
@@ -690,6 +694,18 @@ typedef void (gdbarch_coff_make_msymbol_
 extern void gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, int val, struct minimal_symbol *msym);
 extern void set_gdbarch_coff_make_msymbol_special (struct gdbarch *gdbarch, gdbarch_coff_make_msymbol_special_ftype *coff_make_msymbol_special);
 
+typedef void (gdbarch_make_symbol_special_ftype) (struct symbol *sym, struct objfile *objfile);
+extern void gdbarch_make_symbol_special (struct gdbarch *gdbarch, struct symbol *sym, struct objfile *objfile);
+extern void set_gdbarch_make_symbol_special (struct gdbarch *gdbarch, gdbarch_make_symbol_special_ftype *make_symbol_special);
+
+typedef CORE_ADDR (gdbarch_adjust_dwarf2_addr_ftype) (CORE_ADDR pc);
+extern CORE_ADDR gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_adjust_dwarf2_addr (struct gdbarch *gdbarch, gdbarch_adjust_dwarf2_addr_ftype *adjust_dwarf2_addr);
+
+typedef CORE_ADDR (gdbarch_adjust_dwarf2_line_ftype) (CORE_ADDR addr, int rel);
+extern CORE_ADDR gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, CORE_ADDR addr, int rel);
+extern void set_gdbarch_adjust_dwarf2_line (struct gdbarch *gdbarch, gdbarch_adjust_dwarf2_line_ftype *adjust_dwarf2_line);
+
 extern int gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch);
 extern void set_gdbarch_cannot_step_breakpoint (struct gdbarch *gdbarch, int cannot_step_breakpoint);
 
Index: gdb-fsf-trunk-quilt/gdb/gdbarch.sh
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/gdbarch.sh	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/gdbarch.sh	2014-10-03 14:50:26.000000000 +0100
@@ -635,8 +635,11 @@ m:int:in_solib_return_trampoline:CORE_AD
 # which don't suffer from that problem could just let this functionality
 # untouched.
 m:int:in_function_epilogue_p:CORE_ADDR addr:addr:0:generic_in_function_epilogue_p::0
-f:void:elf_make_msymbol_special:asymbol *sym, struct minimal_symbol *msym:sym, msym::default_elf_make_msymbol_special::0
+F:void:elf_make_msymbol_special:asymbol *sym, struct minimal_symbol *msym:sym, msym
 f:void:coff_make_msymbol_special:int val, struct minimal_symbol *msym:val, msym::default_coff_make_msymbol_special::0
+f:void:make_symbol_special:struct symbol *sym, struct objfile *objfile:sym, objfile::default_make_symbol_special::0
+f:CORE_ADDR:adjust_dwarf2_addr:CORE_ADDR pc:pc::default_adjust_dwarf2_addr::0
+f:CORE_ADDR:adjust_dwarf2_line:CORE_ADDR addr, int rel:addr, rel::default_adjust_dwarf2_line::0
 v:int:cannot_step_breakpoint:::0:0::0
 v:int:have_nonsteppable_watchpoint:::0:0::0
 F:int:address_class_type_flags:int byte_size, int dwarf2_addr_class:byte_size, dwarf2_addr_class
@@ -1140,6 +1143,8 @@ struct target_ops;
 struct obstack;
 struct bp_target_info;
 struct target_desc;
+struct objfile;
+struct symbol;
 struct displaced_step_closure;
 struct core_regset_section;
 struct syscall;
Index: gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-linux-tdep.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-linux-tdep.c	2014-10-03 14:50:26.398945943 +0100
@@ -1372,7 +1372,13 @@ micromips_linux_sigframe_validate (const
 				   struct frame_info *this_frame,
 				   CORE_ADDR *pc)
 {
-  return mips_pc_is_micromips (get_frame_arch (this_frame), *pc);
+  if (mips_pc_is_micromips (get_frame_arch (this_frame), *pc))
+    {
+      *pc = mips_unmake_compact_addr (*pc);
+      return 1;
+    }
+  else
+    return 0;
 }
 
 /* Implement the "write_pc" gdbarch method.  */
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c	2014-10-06 00:11:55.028611249 +0100
@@ -333,6 +333,15 @@ make_compact_addr (CORE_ADDR addr)
   return ((addr) | (CORE_ADDR) 1);
 }
 
+/* Extern version of unmake_compact_addr; we use a separate function
+   so that unmake_compact_addr can be inlined throughout this file.  */
+
+CORE_ADDR
+mips_unmake_compact_addr (CORE_ADDR addr)
+{
+  return unmake_compact_addr (addr);
+}
+
 /* Functions for setting and testing a bit in a minimal symbol that
    marks it as MIPS16 or microMIPS function.  The MSB of the minimal
    symbol's "info" field is used for this purpose.
@@ -362,9 +371,15 @@ mips_elf_make_msymbol_special (asymbol *
     return;
 
   if (ELF_ST_IS_MICROMIPS (st_other))
-    MSYMBOL_TARGET_FLAG_2 (msym) = 1;
+    {
+      MSYMBOL_TARGET_FLAG_2 (msym) = 1;
+      SET_MSYMBOL_VALUE_ADDRESS (msym, MSYMBOL_VALUE_RAW_ADDRESS (msym) | 1);
+    }
   else if (ELF_ST_IS_MIPS16 (st_other))
-    MSYMBOL_TARGET_FLAG_1 (msym) = 1;
+    {
+      MSYMBOL_TARGET_FLAG_1 (msym) = 1;
+      SET_MSYMBOL_VALUE_ADDRESS (msym, MSYMBOL_VALUE_RAW_ADDRESS (msym) | 1);
+    }
 }
 
 /* Return one iff MSYM refers to standard ISA code.  */
@@ -391,6 +406,29 @@ msymbol_is_micromips (struct minimal_sym
   return MSYMBOL_TARGET_FLAG_2 (msym);
 }
 
+/* Set the ISA bit in the main symbol too, complementing the corresponding
+   minimal symbol setting and reflecting the run-time value of the symbol.  */
+
+static void
+mips_make_symbol_special (struct symbol *sym, struct objfile *objfile)
+{
+  if (SYMBOL_CLASS (sym) == LOC_BLOCK)
+    {
+      CORE_ADDR compact_block_start;
+      struct bound_minimal_symbol msym;
+
+      compact_block_start = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)) | 1;
+      msym = lookup_minimal_symbol_by_pc (compact_block_start);
+      if (msym.minsym && !msymbol_is_mips (msym.minsym))
+	{
+	  /* We are in symbol reading so it is OK to cast away constness.  */
+	  struct block *block = (struct block *) SYMBOL_BLOCK_VALUE (sym);
+
+	  BLOCK_START (block) = compact_block_start;
+	}
+    }
+}
+
 /* XFER a value from the big/little/left end of the register.
    Depending on the size of the value it might occupy the entire
    register or just part of it.  Make an allowance for this, aligning
@@ -1125,7 +1163,7 @@ mips_pc_is_mips (CORE_ADDR memaddr)
      stored by elfread.c in the high bit of the info field.  Use this
      to decide if the function is standard MIPS.  Otherwise if bit 0
      of the address is clear, then this is a standard MIPS function.  */
-  sym = lookup_minimal_symbol_by_pc (memaddr);
+  sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
     return msymbol_is_mips (sym.minsym);
   else
@@ -1143,7 +1181,7 @@ mips_pc_is_mips16 (struct gdbarch *gdbar
      elfread.c in the high bit of the info field.  Use this to decide
      if the function is MIPS16.  Otherwise if bit 0 of the address is
      set, then ELF file flags will tell if this is a MIPS16 function.  */
-  sym = lookup_minimal_symbol_by_pc (memaddr);
+  sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
     return msymbol_is_mips16 (sym.minsym);
   else
@@ -1162,7 +1200,7 @@ mips_pc_is_micromips (struct gdbarch *gd
      if the function is microMIPS.  Otherwise if bit 0 of the address
      is set, then ELF file flags will tell if this is a microMIPS
      function.  */
-  sym = lookup_minimal_symbol_by_pc (memaddr);
+  sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
     return msymbol_is_micromips (sym.minsym);
   else
@@ -1182,7 +1220,7 @@ mips_pc_isa (struct gdbarch *gdbarch, CO
      this to decide if the function is MIPS16 or microMIPS or normal
      MIPS.  Otherwise if bit 0 of the address is set, then ELF file
      flags will tell if this is a MIPS16 or a microMIPS function.  */
-  sym = lookup_minimal_symbol_by_pc (memaddr);
+  sym = lookup_minimal_symbol_by_pc (make_compact_addr (memaddr));
   if (sym.minsym)
     {
       if (msymbol_is_micromips (sym.minsym))
@@ -1203,6 +1241,32 @@ mips_pc_isa (struct gdbarch *gdbarch, CO
     }
 }
 
+/* Set the ISA bit correctly in the PC, used by DWARF-2 machinery.  */
+
+static CORE_ADDR
+mips_adjust_dwarf2_addr (CORE_ADDR pc)
+{
+  pc = unmake_compact_addr (pc);
+  return mips_pc_is_mips (pc) ? pc : make_compact_addr (pc);
+}
+
+/* Recalculate the line record requested so that the resulting PC has the
+   ISA bit set correctly, used by DWARF-2 machinery.  */
+
+static CORE_ADDR
+mips_adjust_dwarf2_line (CORE_ADDR addr, int rel)
+{
+  static CORE_ADDR adj_pc;
+  static CORE_ADDR pc;
+  CORE_ADDR isa_pc;
+
+  pc = rel ? pc + addr : addr;
+  isa_pc = mips_adjust_dwarf2_addr (pc);
+  addr = rel ? isa_pc - adj_pc : isa_pc;
+  adj_pc = isa_pc;
+  return addr;
+}
+
 /* Various MIPS16 thunk (aka stub or trampoline) names.  */
 
 static const char mips_str_mips16_call_stub[] = "__mips16_call_stub_";
@@ -1252,8 +1316,6 @@ mips_read_pc (struct regcache *regcache)
   LONGEST pc;
 
   regcache_cooked_read_signed (regcache, regnum, &pc);
-  if (is_compact_addr (pc))
-    pc = unmake_compact_addr (pc);
   return pc;
 }
 
@@ -1263,8 +1325,6 @@ mips_unwind_pc (struct gdbarch *gdbarch,
   CORE_ADDR pc;
 
   pc = frame_unwind_register_signed (next_frame, gdbarch_pc_regnum (gdbarch));
-  if (is_compact_addr (pc))
-    pc = unmake_compact_addr (pc);
   /* macro/2012-04-20: This hack skips over MIPS16 call thunks as
      intermediate frames.  In this case we can get the caller's address
      from $ra, or if $ra contains an address within a thunk as well, then
@@ -1274,15 +1334,9 @@ mips_unwind_pc (struct gdbarch *gdbarch,
     {
       pc = frame_unwind_register_signed
 	     (next_frame, gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM);
-      if (is_compact_addr (pc))
-	pc = unmake_compact_addr (pc);
       if (mips_in_frame_stub (pc))
-	{
-	  pc = frame_unwind_register_signed
-		 (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
-	  if (is_compact_addr (pc))
-	    pc = unmake_compact_addr (pc);
-	}
+	pc = frame_unwind_register_signed
+	       (next_frame, gdbarch_num_regs (gdbarch) + MIPS_S2_REGNUM);
     }
   return pc;
 }
@@ -1316,10 +1370,7 @@ mips_write_pc (struct regcache *regcache
 {
   int regnum = gdbarch_pc_regnum (get_regcache_arch (regcache));
 
-  if (mips_pc_is_mips (pc))
-    regcache_cooked_write_unsigned (regcache, regnum, pc);
-  else
-    regcache_cooked_write_unsigned (regcache, regnum, make_compact_addr (pc));
+  regcache_cooked_write_unsigned (regcache, regnum, pc);
 }
 
 /* Fetch and return instruction from the specified location.  Handle
@@ -3650,9 +3701,6 @@ mips_addr_bits_remove (struct gdbarch *g
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (is_compact_addr (addr))
-    addr = unmake_compact_addr (addr);
-
   if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL))
     /* This hack is a work-around for existing boards using PMON, the
        simulator, and any other 64-bit targets that doesn't have true
@@ -4351,25 +4399,9 @@ mips_eabi_push_dummy_call (struct gdbarc
 			    "mips_eabi_push_dummy_call: %d len=%d type=%d",
 			    argnum + 1, len, (int) typecode);
 
-      /* Function pointer arguments to mips16 code need to be made into
-         mips16 pointers.  */
-      if (typecode == TYPE_CODE_PTR
-          && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC)
-	{
-	  CORE_ADDR addr = extract_signed_integer (value_contents (arg),
-						   len, byte_order);
-	  if (mips_pc_is_mips (addr))
-	    val = value_contents (arg);
-	  else
-	    {
-	      store_signed_integer (valbuf, len, byte_order, 
-				    make_compact_addr (addr));
-	      val = valbuf;
-	    }
-	}
       /* The EABI passes structures that do not fit in a register by
          reference.  */
-      else if (len > regsize
+      if (len > regsize
 	  && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
 	{
 	  store_unsigned_integer (valbuf, regsize, byte_order,
@@ -5734,7 +5766,6 @@ mips_o64_push_dummy_call (struct gdbarch
   for (argnum = 0; argnum < nargs; argnum++)
     {
       const gdb_byte *val;
-      gdb_byte valbuf[MAX_REGISTER_SIZE];
       struct value *arg = args[argnum];
       struct type *arg_type = check_typedef (value_type (arg));
       int len = TYPE_LENGTH (arg_type);
@@ -5747,21 +5778,6 @@ mips_o64_push_dummy_call (struct gdbarch
 
       val = value_contents (arg);
 
-      /* Function pointer arguments to mips16 code need to be made into
-         mips16 pointers.  */
-      if (typecode == TYPE_CODE_PTR
-          && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC)
-	{
-	  CORE_ADDR addr = extract_signed_integer (value_contents (arg),
-						   len, byte_order);
-	  if (!mips_pc_is_mips (addr))
-	    {
-	      store_signed_integer (valbuf, len, byte_order, 
-				    make_compact_addr (addr));
-	      val = valbuf;
-	    }
-	}
-
       /* Floating point arguments passed in registers have to be
          treated specially.  On 32-bit architectures, doubles are
          passed in register pairs; the even FP register gets the
@@ -7678,27 +7694,15 @@ mips_skip_trampoline_code (struct frame_
 
       new_pc = mips_skip_mips16_trampoline_code (frame, pc);
       if (new_pc)
-	{
-	  pc = new_pc;
-	  if (is_compact_addr (pc))
-	    pc = unmake_compact_addr (pc);
-	}
+	pc = new_pc;
 
       new_pc = find_solib_trampoline_target (frame, pc);
       if (new_pc)
-	{
-	  pc = new_pc;
-	  if (is_compact_addr (pc))
-	    pc = unmake_compact_addr (pc);
-	}
+	pc = new_pc;
 
       new_pc = mips_skip_pic_trampoline_code (frame, pc);
       if (new_pc)
-	{
-	  pc = new_pc;
-	  if (is_compact_addr (pc))
-	    pc = unmake_compact_addr (pc);
-	}
+	pc = new_pc;
     }
   while (pc != target_pc);
 
@@ -8354,6 +8358,9 @@ mips_gdbarch_init (struct gdbarch_info i
 
   set_gdbarch_elf_make_msymbol_special (gdbarch,
 					mips_elf_make_msymbol_special);
+  set_gdbarch_make_symbol_special (gdbarch, mips_make_symbol_special);
+  set_gdbarch_adjust_dwarf2_addr (gdbarch, mips_adjust_dwarf2_addr);
+  set_gdbarch_adjust_dwarf2_line (gdbarch, mips_adjust_dwarf2_line);
 
   regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct mips_regnum);
   *regnum = mips_regnum;
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.h
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.h	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.h	2014-10-05 23:03:19.088958183 +0100
@@ -155,6 +155,9 @@ enum
 /* Single step based on where the current instruction will take us.  */
 extern int mips_software_single_step (struct frame_info *frame);
 
+/* Strip the ISA (compression) bit off from ADDR.  */
+extern CORE_ADDR mips_unmake_compact_addr (CORE_ADDR addr);
+
 /* Tell if the program counter value in MEMADDR is in a standard
    MIPS function.  */
 extern int mips_pc_is_mips (bfd_vma memaddr);
Index: gdb-fsf-trunk-quilt/gdb/solib.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/solib.c	2014-10-03 13:52:46.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/solib.c	2014-10-03 14:50:26.398945943 +0100
@@ -1444,8 +1444,28 @@ gdb_bfd_lookup_symbol_from_symtab (bfd *
 
 	  if (match_sym (sym, data))
 	    {
+	      struct gdbarch *gdbarch = target_gdbarch ();
+	      symaddr = sym->value;
+
+	      /* Some ELF targets fiddle with addresses of symbols they
+	         consider special.  They use minimal symbols to do that
+	         and this is needed for correct breakpoint placement,
+	         but we do not have full data here to build a complete
+	         minimal symbol, so just set the address and let the
+	         targets cope with that.  */
+	      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+		  && gdbarch_elf_make_msymbol_special_p (gdbarch))
+		{
+		  struct minimal_symbol msym;
+
+		  memset (&msym, 0, sizeof (msym));
+		  SET_MSYMBOL_VALUE_ADDRESS (&msym, symaddr);
+		  gdbarch_elf_make_msymbol_special (gdbarch, sym, &msym);
+		  symaddr = MSYMBOL_VALUE_RAW_ADDRESS (&msym);
+		}
+
 	      /* BFD symbols are section relative.  */
-	      symaddr = sym->value + sym->section->vma;
+	      symaddr += sym->section->vma;
 	      break;
 	    }
 	}
Index: gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/func-ptrs.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/func-ptrs.c	2014-10-03 14:50:26.398945943 +0100
@@ -0,0 +1,50 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2014 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/>.  */
+
+void
+sentinel (void)
+{
+  return;
+}
+
+int
+incr (int i)
+{
+  sentinel ();
+  return i + 1;
+}
+
+int
+decr (int i)
+{
+  sentinel ();
+  return i - 1;
+}
+
+int (*calc) (int) = incr;
+
+int
+main (void)
+{
+  int i = -1;
+
+  i = calc (i);
+  i = calc (i);
+  i = calc (i);
+
+  return i;
+}
Index: gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/func-ptrs.exp
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/func-ptrs.exp	2014-10-03 14:50:26.398945943 +0100
@@ -0,0 +1,95 @@
+# Copyright 2014 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/>.
+
+set testname func-ptrs
+set srcfile ${testname}.c
+if { [prepare_for_testing ${testname}.exp ${testname} ${srcfile}] } {
+    return -1
+}
+
+if { ![runto_main] } {
+    untested ${testname}.exp
+    return -1
+}
+
+
+# First set our breakpoints.
+
+set fp_breakpoint_re \
+    "Breakpoint $decimal at $hex: file .*${srcfile}, line $decimal\\."
+gdb_test "break sentinel if calc == decr" \
+    "${fp_breakpoint_re}" \
+    "breakpoint at sentinel"
+gdb_test "break incr" \
+    "${fp_breakpoint_re}" \
+    "breakpoint at incr"
+gdb_test "break decr" \
+    "${fp_breakpoint_re}" \
+    "breakpoint at decr"
+
+
+# Check if we run through to the breakpoint in incr.
+
+gdb_test "continue" \
+    "Breakpoint $decimal, incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \
+    "continue to incr, first time"
+
+
+# Go back up, make sure the return value is 0.
+
+gdb_test "finish" \
+    "Run till exit from #0 +incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = 0" \
+    "go back to main from incr, first time"
+
+
+# Redirect calc and see if we run to the breakpoint in decr instead.
+
+gdb_test_no_output "set calc = decr" "set calc to decr"
+gdb_test "continue" \
+    "Breakpoint $decimal, decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \
+    "continue to decr"
+
+
+# Go back up, check if we stop in sentinel instead.
+
+gdb_test "finish" \
+    "Run till exit from #0 +decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+Breakpoint $decimal, sentinel \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \
+    "stop in sentinel"
+
+
+# Go back all the way up to main, make sure the return value is -1.
+
+gdb_test_no_output "up-silently" "move up to decr"
+gdb_test "finish" \
+    "Run till exit from #1 +($hex in )?decr \\(i=0\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = -1" \
+    "go back to main from decr"
+
+
+# Reset calc and see if we run to the breakpoint in incr again.
+
+gdb_test_no_output "set calc = incr" "set calc to incr"
+gdb_test "continue" \
+    "Breakpoint $decimal, incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*" \
+    "continue to incr, second time"
+
+
+# Go back up again, make sure the return value is 0.
+
+gdb_test "finish" \
+    "Run till exit from #0 +incr \\(i=-1\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+($hex in )?main \\(\\)\[ \r\n\]+at .*${srcfile}:$decimal\[\r\n\]+.*Value returned is \\$$decimal = 0" \
+    "go back to main from incr, second time"
+
+
+# All done!



More information about the Gdb-patches mailing list