This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch] unwind support for gdb/ia64


David Mosberger wrote:
> 
> I'd like to submit the attached patch for inclusion in the gdb source
> tree.  It adds support for determining the frame chain based on unwind
> information (which is supplied by the libunwind library).  The patch
> is relative to today's CVS tree (July 10th) and should be safe for all
> platforms:
> 
>  - it adds only one new function to blockframe.c (generic_dummy_frame_chain())
>  - it adds one new file (unwind-common.h)
>  - all other non-trivial changes are contained in ia64-tdep.c; even for the
>    ia64 case, the patch has no effect _unless_ the libunwind header file
>    and library are installed on the build machine
> 
> For the sake of completeness, I'd like to point out that libunwind is
> built in a fashion that support gdb-style multi-arch'ing, so there are
> no issues in building a cross-gdb or a gdb that supports multiple
> targets that use libunwind (though at the moment, there is only an
> ia64 version of libunwind; hopefully that will change over time).
> 
> Thanks,
> 
>         --david

I don't see any replies to this patch.  Has it been resolved?


> 
> ChangeLog
> ===================================================================
> 
> 2002-05-08  David Mosberger-Tang  <David.Mosberger@acm.org>
> 
>         * ia64-tdep.c (NEED_PROLOGUE_SCANNING): New macro.
>         (instruction_type): Move inside NEED_PROLOGUE_SCANNING.
>         (template_encoding_table): Ditto.
>         (extract_bit_field): Ditto.
>         (slotN_contents): Ditto.
>         (fetch_instruction): Ditto.
>         (refine_prologue_limit): Ditto.
>         (isScratch): Ditto.
>         (imm9): Ditto.
>         (getunwind) [HAVE_LIBUNWIND_IA64_H]: New function.
>         (struct ia64_unwind_table_entry) [HAVE_LIBUNWIND_IA64_H]: New
>         type.
>         (ia64_rse_slot_num) [HAVE_LIBUNWIND_IA64_H]: New function.
>         (ia64_rse_skip_regs) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (gdb2uw_regnum) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (uw2gdb_regnum) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (access_reg) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (access_fpreg) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (get_kernel_table) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (map_segment) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (acquire_unwind_info) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (release_unwind_info) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (min_examine_prologue)
>         [HAVE_LIBUNWIND_IA64_H,NEED_PROLOGUE_SCANNING]: Ditto.
>         (ia64_skip_prologue)
>         [HAVE_LIBUNWIND_IA64_H,NEED_PROLOGUE_SCANNING]: Ditto.
>         (ia64_frame_init_saved_regs) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (ia64_frameless_function_invocation) [HAVE_LIBUNWIND_IA64_H]:
>         Ditto.
>         (ia64_frame_args_address) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (ia64_frame_locals_address) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (ia64_frame_unchanged) [HAVE_LIBUNWIND_IA64_H]: Ditto.
>         (struct frame_extra_info): Move inside !HAVE_LIBUNWIND_IA64_H.
>         (lr_regnum): Ditto.
>         (read_sigcontext_register): Ditto.
>         (ia64_frame_chain): Ditto.
>         (ia64_frame_saved_pc): Ditto.
>         (examine_prologue): Ditto.
>         (ia64_frame_init_saved_regs): Ditto.
>         (ia64_get_saved_register): Ditto.
>         (ia64_frameless_function_invocation): Ditto.
>         (ia64_frame_args_address): Ditto.
>         (ia64_frame_locals_address): Ditto.
>         (ia64_init_extra_frame_info): Ditto.
>         (ia64_pop_frame): Ditto.
>         (ia64_pop_frame_regular): Ditto.
>         (ia64_frame_unchanged): Ditto.
>         (ia64_gdbarch_init): Set FRAME_CHAIN, FRAME_SAVED_PC,
>         GET_SAVED_REGISTER, POP_FRAME, and INIT_EXTRA_FRAME_INFO callbacks
>         based on whether or not HAVE_LIBUNWIND_IA64_H is defined.
> 
>         * unwind-common.h: New file.
> 
>         * configure.in: Add checks for libunwind-$TARGET.h and
>         unwind-$TARGET library.
> 
>         * config.in: Mention HAVE_LIBUNWIND_IA64_H.
> 
>         * blockframe.c (generic_dummy_frame_chain): New function.
> 
>         * Makefile.in (ia64-tdep.o): Depend on unwind-common.h.
> 
> 2002-04-19  David Mosberger-Tang  <David.Mosberger@acm.org>
> 
>         * ia64-tdep.c (ia64_push_arguments): Don't call
>         generic_save_dummy_frame_tos() directly...
>         (ia64_gdbarch_init): ...use set_gdbarch_save_dummy_frame_tos()
>         instead.
> 
> Index: Makefile.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/Makefile.in,v
> retrieving revision 1.218
> diff -u -r1.218 Makefile.in
> --- Makefile.in 3 Jul 2002 20:36:54 -0000       1.218
> +++ Makefile.in 10 Jul 2002 22:38:11 -0000
> @@ -1685,9 +1685,9 @@
> 
>  ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(arch_utils_h)
> 
> -ia64-tdep.o: ia64-tdep.c $(defs_h) $(inferior_h) $(symfile_h) $(gdbcore_h) \
> -       $(arch_utils_h) $(floatformat_h) $(objfiles_h) $(value_h) \
> -       $(INCLUDE_DIR)/elf/common.h $(regcache_h) $(doublest_h)
> +ia64-tdep.o: ia64-tdep.c unwind-common.h $(defs_h) $(inferior_h) $(symfile_h) \
> +       $(gdbcore_h) $(arch_utils_h) $(floatformat_h) $(objfiles_h) \
> +       $(value_h) $(INCLUDE_DIR)/elf/common.h $(regcache_h) $(doublest_h)
> 
>  infcmd.o: infcmd.c $(defs_h) environ.h $(gdbcmd_h) $(gdbcore_h) \
>         $(inferior_h) $(target_h) $(language_h) $(symfile_h) $(gdb_string_h) \
> Index: blockframe.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/blockframe.c,v
> retrieving revision 1.32
> diff -u -r1.32 blockframe.c
> --- blockframe.c        2 Jul 2002 19:08:55 -0000       1.32
> +++ blockframe.c        10 Jul 2002 22:38:12 -0000
> @@ -1180,6 +1189,25 @@
>    if (regcache == NULL)
>      return NULL;
>    return deprecated_grub_regcache_for_registers (regcache);
> +}
> +
> +CORE_ADDR
> +generic_dummy_frame_chain (CORE_ADDR pc, CORE_ADDR fp)
> +{
> +  struct dummy_frame *dummyframe;
> +
> +  if (pc != entry_point_address ())
> +    return 0;
> +
> +  for (dummyframe = dummy_frame_stack; dummyframe != NULL;
> +       dummyframe = dummyframe->next)
> +    if (/*fp == dummyframe->fp
> +       || fp == dummyframe->sp
> +       ||*/ fp == dummyframe->top)
> +      /* The frame in question lies between the saved fp and sp, inclusive */
> +      return dummyframe->fp;
> +
> +  return 0;
>  }
> 
>  /* Function: pc_in_call_dummy (pc, sp, fp)
> Index: config.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/config.in,v
> retrieving revision 1.40
> diff -u -r1.40 config.in
> --- config.in   9 Jul 2002 22:59:36 -0000       1.40
> +++ config.in   10 Jul 2002 22:38:12 -0000
> @@ -514,3 +514,5 @@
>  /* Define if <sys/procfs.h> has pr_siginfo64_t. */
>  #undef HAVE_PR_SIGINFO64_T
> 
> +/* Define if <libunwind-ia64.h> exists.  */
> +#undef HAVE_LIBUNWIND_IA64_H
> Index: configure.in
> ===================================================================
> RCS file: /cvs/src/src/gdb/configure.in,v
> retrieving revision 1.89
> diff -u -r1.89 configure.in
> --- configure.in        9 Jul 2002 22:59:36 -0000       1.89
> +++ configure.in        10 Jul 2002 22:38:22 -0000
> @@ -232,6 +232,10 @@
>    AC_DEFINE(HAVE_PT_GETXMMREGS)
>  fi
> 
> +# To build for multiple target architectures, we would have to
> +# do the next two checks once for each architecture:
> +AC_CHECK_HEADERS(libunwind-${gdb_target_cpu}.h)
> +AC_CHECK_LIB(unwind-${gdb_target_cpu}, main)
> 
>  AC_CHECK_LIB(socket, socketpair)
>  AC_CHECK_FUNCS(socketpair)
> Index: frame.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/frame.h,v
> retrieving revision 1.22
> diff -u -r1.22 frame.h
> --- frame.h     2 Jul 2002 19:08:53 -0000       1.22
> +++ frame.h     10 Jul 2002 22:38:23 -0000
> @@ -319,6 +325,7 @@
>     get_saved_register to the next outer frame.  */
> 
>  extern char *deprecated_generic_find_dummy_frame (CORE_ADDR pc, CORE_ADDR fp);
> +extern CORE_ADDR generic_dummy_frame_chain (CORE_ADDR pc, CORE_ADDR fp);
> 
>  extern void generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun,
>                                     int nargs, struct value **args,
> Index: ia64-tdep.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/ia64-tdep.c,v
> retrieving revision 1.32
> diff -u -r1.32 ia64-tdep.c
> --- ia64-tdep.c 17 Jun 2002 23:32:31 -0000      1.32
> +++ ia64-tdep.c 10 Jul 2002 22:38:35 -0000
> @@ -33,31 +33,6 @@
>  #include "elf/common.h"                /* for DT_PLTGOT value */
>  #include "elf-bfd.h"
> 
> -/* Hook for determining the global pointer when calling functions in
> -   the inferior under AIX.  The initialization code in ia64-aix-nat.c
> -   sets this hook to the address of a function which will find the
> -   global pointer for a given address.
> -
> -   The generic code which uses the dynamic section in the inferior for
> -   finding the global pointer is not of much use on AIX since the
> -   values obtained from the inferior have not been relocated.  */
> -
> -CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0;
> -
> -/* An enumeration of the different IA-64 instruction types.  */
> -
> -typedef enum instruction_type
> -{
> -  A,                   /* Integer ALU ;    I-unit or M-unit */
> -  I,                   /* Non-ALU integer; I-unit */
> -  M,                   /* Memory ;         M-unit */
> -  F,                   /* Floating-point ; F-unit */
> -  B,                   /* Branch ;         B-unit */
> -  L,                   /* Extended (L+X) ; I-unit */
> -  X,                   /* Extended (L+X) ; I-unit */
> -  undefined            /* undefined or reserved */
> -} instruction_type;
> -
>  /* We represent IA-64 PC addresses as the value of the instruction
>     pointer or'd with some bit combination in the low nibble which
>     represents the slot number in the bundle addressed by the
> @@ -65,7 +40,7 @@
>     multiplies its slot numbers (for exceptions) by one while the
>     disassembler multiplies its slot numbers by 6.  In addition, I've
>     heard it said that the simulator uses 1 as the multiplier.
> -
> +
>     I've fixed the disassembler so that the bytes_per_line field will
>     be the slot multiplier.  If bytes_per_line comes in as zero, it
>     is set to six (which is how it was set up initially). -- objdump
> @@ -75,6 +50,50 @@
> 
>  #define SLOT_MULTIPLIER 1
> 
> +CORE_ADDR
> +ia64_read_pc (ptid_t ptid)
> +{
> +  CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
> +  CORE_ADDR pc_value   = read_register_pid (IA64_IP_REGNUM, ptid);
> +  int slot_num = (psr_value >> 41) & 3;
> +
> +  return pc_value | (slot_num * SLOT_MULTIPLIER);
> +}
> +
> +void
> +ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
> +{
> +  int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
> +  CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
> +  psr_value &= ~(3LL << 41);
> +  psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
> +
> +  new_pc &= ~0xfLL;
> +
> +  write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
> +  write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
> +}
> +
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +  /* Some day, gdb will be fixed so that skip_prologue () can be an
> +     identity function.  Until then, we need to examine the prologue
> +     to get a reasonable estimate of where it ends.  C'est la vie.  */
> +# define NEED_PROLOGUE_SCANNING
> +#else
> +# define NEED_PROLOGUE_SCANNING
> +#endif
> +
> +/* Hook for determining the global pointer when calling functions in
> +   the inferior under AIX.  The initialization code in ia64-aix-nat.c
> +   sets this hook to the address of a function which will find the
> +   global pointer for a given address.
> +
> +   The generic code which uses the dynamic section in the inferior for
> +   finding the global pointer is not of much use on AIX since the
> +   values obtained from the inferior have not been relocated.  */
> +
> +CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0;
> +
>  /* Length in bytes of an instruction bundle */
> 
>  #define BUNDLE_LEN 16
> @@ -91,8 +110,6 @@
>  static gdbarch_register_virtual_type_ftype ia64_register_virtual_type;
>  static gdbarch_register_byte_ftype ia64_register_byte;
>  static gdbarch_breakpoint_from_pc_ftype ia64_breakpoint_from_pc;
> -static gdbarch_frame_chain_ftype ia64_frame_chain;
> -static gdbarch_frame_saved_pc_ftype ia64_frame_saved_pc;
>  static gdbarch_skip_prologue_ftype ia64_skip_prologue;
>  static gdbarch_frame_init_saved_regs_ftype ia64_frame_init_saved_regs;
>  static gdbarch_get_saved_register_ftype ia64_get_saved_register;
> @@ -100,14 +117,11 @@
>  static gdbarch_deprecated_extract_struct_value_address_ftype ia64_extract_struct_value_address;
>  static gdbarch_use_struct_convention_ftype ia64_use_struct_convention;
>  static gdbarch_frameless_function_invocation_ftype ia64_frameless_function_invocation;
> -static gdbarch_init_extra_frame_info_ftype ia64_init_extra_frame_info;
>  static gdbarch_store_return_value_ftype ia64_store_return_value;
>  static gdbarch_store_struct_return_ftype ia64_store_struct_return;
>  static gdbarch_push_arguments_ftype ia64_push_arguments;
>  static gdbarch_push_return_address_ftype ia64_push_return_address;
> -static gdbarch_pop_frame_ftype ia64_pop_frame;
>  static gdbarch_saved_pc_after_call_ftype ia64_saved_pc_after_call;
> -static void ia64_pop_frame_regular (struct frame_info *frame);
>  static struct type *is_float_or_hfa_type (struct type *t);
> 
>  static int ia64_num_regs = 590;
> @@ -115,14 +129,13 @@
>  static int pc_regnum = IA64_IP_REGNUM;
>  static int sp_regnum = IA64_GR12_REGNUM;
>  static int fp_regnum = IA64_VFP_REGNUM;
> -static int lr_regnum = IA64_VRAP_REGNUM;
> 
>  static LONGEST ia64_call_dummy_words[] = {0};
> 
>  /* Array of register names; There should be ia64_num_regs strings in
>     the initializer.  */
> 
> -static char *ia64_register_names[] =
> +static char *ia64_register_names[] =
>  { "r0",   "r1",   "r2",   "r3",   "r4",   "r5",   "r6",   "r7",
>    "r8",   "r9",   "r10",  "r11",  "r12",  "r13",  "r14",  "r15",
>    "r16",  "r17",  "r18",  "r19",  "r20",  "r21",  "r22",  "r23",
> @@ -207,25 +220,6 @@
>    "nat120","nat121","nat122","nat123","nat124","nat125","nat126","nat127",
>  };
> 
> -struct frame_extra_info
> -  {
> -    CORE_ADDR bsp;     /* points at r32 for the current frame */
> -    CORE_ADDR cfm;     /* cfm value for current frame */
> -    int sof;           /* Size of frame  (decoded from cfm value) */
> -    int        sol;            /* Size of locals (decoded from cfm value) */
> -    CORE_ADDR after_prologue;
> -                       /* Address of first instruction after the last
> -                          prologue instruction;  Note that there may
> -                          be instructions from the function's body
> -                          intermingled with the prologue. */
> -    int mem_stack_frame_size;
> -                       /* Size of the memory stack frame (may be zero),
> -                          or -1 if it has not been determined yet. */
> -    int        fp_reg;         /* Register number (if any) used a frame pointer
> -                          for this frame.  0 if no register is being used
> -                          as the frame pointer. */
> -  };
> -
>  struct gdbarch_tdep
>    {
>      int os_ident;      /* From the ELF header, one of the ELFOSABI_
> @@ -243,107 +237,58 @@
>  #define FIND_GLOBAL_POINTER \
>    (gdbarch_tdep (current_gdbarch)->find_global_pointer)
> 
> -static const char *
> -ia64_register_name (int reg)
> -{
> -  return ia64_register_names[reg];
> -}
> -
> -int
> -ia64_register_raw_size (int reg)
> -{
> -  return (IA64_FR0_REGNUM <= reg && reg <= IA64_FR127_REGNUM) ? 16 : 8;
> -}
> +#ifdef NEED_PROLOGUE_SCANNING
> 
> -int
> -ia64_register_virtual_size (int reg)
> -{
> -  return (IA64_FR0_REGNUM <= reg && reg <= IA64_FR127_REGNUM) ? 16 : 8;
> -}
> +/* An enumeration of the different IA-64 instruction types.  */
> 
> -/* Return true iff register N's virtual format is different from
> -   its raw format. */
> -int
> -ia64_register_convertible (int nr)
> +typedef enum instruction_type
>  {
> -  return (IA64_FR0_REGNUM <= nr && nr <= IA64_FR127_REGNUM);
> -}
> +  A,                   /* Integer ALU ;    I-unit or M-unit */
> +  I,                   /* Non-ALU integer; I-unit */
> +  M,                   /* Memory ;         M-unit */
> +  F,                   /* Floating-point ; F-unit */
> +  B,                   /* Branch ;         B-unit */
> +  L,                   /* Extended (L+X) ; I-unit */
> +  X,                   /* Extended (L+X) ; I-unit */
> +  undefined            /* undefined or reserved */
> +} instruction_type;
> 
> -const struct floatformat floatformat_ia64_ext =
> +static enum instruction_type template_encoding_table[32][3] =
>  {
> -  floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
> -  floatformat_intbit_yes
> +  { M, I, I },                         /* 00 */
> +  { M, I, I },                         /* 01 */
> +  { M, I, I },                         /* 02 */
> +  { M, I, I },                         /* 03 */
> +  { M, L, X },                         /* 04 */
> +  { M, L, X },                         /* 05 */
> +  { undefined, undefined, undefined },  /* 06 */
> +  { undefined, undefined, undefined },  /* 07 */
> +  { M, M, I },                         /* 08 */
> +  { M, M, I },                         /* 09 */
> +  { M, M, I },                         /* 0A */
> +  { M, M, I },                         /* 0B */
> +  { M, F, I },                         /* 0C */
> +  { M, F, I },                         /* 0D */
> +  { M, M, F },                         /* 0E */
> +  { M, M, F },                         /* 0F */
> +  { M, I, B },                         /* 10 */
> +  { M, I, B },                         /* 11 */
> +  { M, B, B },                         /* 12 */
> +  { M, B, B },                         /* 13 */
> +  { undefined, undefined, undefined },  /* 14 */
> +  { undefined, undefined, undefined },  /* 15 */
> +  { B, B, B },                         /* 16 */
> +  { B, B, B },                         /* 17 */
> +  { M, M, B },                         /* 18 */
> +  { M, M, B },                         /* 19 */
> +  { undefined, undefined, undefined },  /* 1A */
> +  { undefined, undefined, undefined },  /* 1B */
> +  { M, F, B },                         /* 1C */
> +  { M, F, B },                         /* 1D */
> +  { undefined, undefined, undefined },  /* 1E */
> +  { undefined, undefined, undefined },  /* 1F */
>  };
> 
> -void
> -ia64_register_convert_to_virtual (int regnum, struct type *type,
> -                                  char *from, char *to)
> -{
> -  if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR127_REGNUM)
> -    {
> -      DOUBLEST val;
> -      floatformat_to_doublest (&floatformat_ia64_ext, from, &val);
> -      store_floating(to, TYPE_LENGTH(type), val);
> -    }
> -  else
> -    error("ia64_register_convert_to_virtual called with non floating point register number");
> -}
> -
> -void
> -ia64_register_convert_to_raw (struct type *type, int regnum,
> -                              char *from, char *to)
> -{
> -  if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR127_REGNUM)
> -    {
> -      DOUBLEST val = extract_floating (from, TYPE_LENGTH(type));
> -      floatformat_from_doublest (&floatformat_ia64_ext, &val, to);
> -    }
> -  else
> -    error("ia64_register_convert_to_raw called with non floating point register number");
> -}
> -
> -struct type *
> -ia64_register_virtual_type (int reg)
> -{
> -  if (reg >= IA64_FR0_REGNUM && reg <= IA64_FR127_REGNUM)
> -    return builtin_type_long_double;
> -  else
> -    return builtin_type_long;
> -}
> -
> -int
> -ia64_register_byte (int reg)
> -{
> -  return (8 * reg) +
> -   (reg <= IA64_FR0_REGNUM ? 0 : 8 * ((reg > IA64_FR127_REGNUM) ? 128 : reg - IA64_FR0_REGNUM));
> -}
> -
> -/* Read the given register from a sigcontext structure in the
> -   specified frame.  */
> -
> -static CORE_ADDR
> -read_sigcontext_register (struct frame_info *frame, int regnum)
> -{
> -  CORE_ADDR regaddr;
> -
> -  if (frame == NULL)
> -    internal_error (__FILE__, __LINE__,
> -                   "read_sigcontext_register: NULL frame");
> -  if (!frame->signal_handler_caller)
> -    internal_error (__FILE__, __LINE__,
> -                   "read_sigcontext_register: frame not a signal_handler_caller");
> -  if (SIGCONTEXT_REGISTER_ADDRESS == 0)
> -    internal_error (__FILE__, __LINE__,
> -                   "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0");
> -
> -  regaddr = SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regnum);
> -  if (regaddr)
> -    return read_memory_integer (regaddr, REGISTER_RAW_SIZE (regnum));
> -  else
> -    internal_error (__FILE__, __LINE__,
> -                   "read_sigcontext_register: Register %d not in struct sigcontext", regnum);
> -}
> -
>  /* Extract ``len'' bits from an instruction bundle starting at
>     bit ``from''.  */
> 
> @@ -381,107 +326,14 @@
>    return result;
>  }
> 
> -/* Replace the specified bits in an instruction bundle */
> +/* Return the contents of slot N (for N = 0, 1, or 2) in
> +   and instruction bundle */
> 
> -static void
> -replace_bit_field (char *bundle, long long val, int from, int len)
> +static long long
> +slotN_contents (char *bundle, int slotnum)
>  {
> -  int to = from + len;
> -  int from_byte = from / 8;
> -  int to_byte = to / 8;
> -  unsigned char *b = (unsigned char *) bundle;
> -  unsigned char c;
> -
> -  if (from_byte == to_byte)
> -    {
> -      unsigned char left, right;
> -      c = b[from_byte];
> -      left = (c >> (to % 8)) << (to % 8);
> -      right = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
> -      c = (unsigned char) (val & 0xff);
> -      c = (unsigned char) (c << (from % 8 + 8 - to % 8)) >> (8 - to % 8);
> -      c |= right | left;
> -      b[from_byte] = c;
> -    }
> -  else
> -    {
> -      int i;
> -      c = b[from_byte];
> -      c = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
> -      c = c | (val << (from % 8));
> -      b[from_byte] = c;
> -      val >>= 8 - from % 8;
> -
> -      for (i = from_byte+1; i < to_byte; i++)
> -       {
> -         c = val & 0xff;
> -         val >>= 8;
> -         b[i] = c;
> -       }
> -
> -      if (to % 8 != 0)
> -       {
> -         unsigned char cv = (unsigned char) val;
> -         c = b[to_byte];
> -         c = c >> (to % 8) << (to % 8);
> -         c |= ((unsigned char) (cv << (8 - to % 8))) >> (8 - to % 8);
> -         b[to_byte] = c;
> -       }
> -    }
> -}
> -
> -/* Return the contents of slot N (for N = 0, 1, or 2) in
> -   and instruction bundle */
> -
> -static long long
> -slotN_contents (char *bundle, int slotnum)
> -{
> -  return extract_bit_field (bundle, 5+41*slotnum, 41);
> -}
> -
> -/* Store an instruction in an instruction bundle */
> -
> -static void
> -replace_slotN_contents (char *bundle, long long instr, int slotnum)
> -{
> -  replace_bit_field (bundle, instr, 5+41*slotnum, 41);
> -}
> -
> -static enum instruction_type template_encoding_table[32][3] =
> -{
> -  { M, I, I },                         /* 00 */
> -  { M, I, I },                         /* 01 */
> -  { M, I, I },                         /* 02 */
> -  { M, I, I },                         /* 03 */
> -  { M, L, X },                         /* 04 */
> -  { M, L, X },                         /* 05 */
> -  { undefined, undefined, undefined },  /* 06 */
> -  { undefined, undefined, undefined },  /* 07 */
> -  { M, M, I },                         /* 08 */
> -  { M, M, I },                         /* 09 */
> -  { M, M, I },                         /* 0A */
> -  { M, M, I },                         /* 0B */
> -  { M, F, I },                         /* 0C */
> -  { M, F, I },                         /* 0D */
> -  { M, M, F },                         /* 0E */
> -  { M, M, F },                         /* 0F */
> -  { M, I, B },                         /* 10 */
> -  { M, I, B },                         /* 11 */
> -  { M, B, B },                         /* 12 */
> -  { M, B, B },                         /* 13 */
> -  { undefined, undefined, undefined },  /* 14 */
> -  { undefined, undefined, undefined },  /* 15 */
> -  { B, B, B },                         /* 16 */
> -  { B, B, B },                         /* 17 */
> -  { M, M, B },                         /* 18 */
> -  { M, M, B },                         /* 19 */
> -  { undefined, undefined, undefined },  /* 1A */
> -  { undefined, undefined, undefined },  /* 1B */
> -  { M, F, B },                         /* 1C */
> -  { M, F, B },                         /* 1D */
> -  { undefined, undefined, undefined },  /* 1E */
> -  { undefined, undefined, undefined },  /* 1F */
> -};
> +  return extract_bit_field (bundle, 5+41*slotnum, 41);
> +}
> 
>  /* Fetch and (partially) decode an instruction at ADDR and return the
>     address of the next instruction to fetch.  */
> @@ -533,284 +385,486 @@
>    return addr;
>  }
> 
> -/* There are 5 different break instructions (break.i, break.b,
> -   break.m, break.f, and break.x), but they all have the same
> -   encoding.  (The five bit template in the low five bits of the
> -   instruction bundle distinguishes one from another.)
> -
> -   The runtime architecture manual specifies that break instructions
> -   used for debugging purposes must have the upper two bits of the 21
> -   bit immediate set to a 0 and a 1 respectively.  A breakpoint
> -   instruction encodes the most significant bit of its 21 bit
> -   immediate at bit 36 of the 41 bit instruction.  The penultimate msb
> -   is at bit 25 which leads to the pattern below.
> -
> -   Originally, I had this set up to do, e.g, a "break.i 0x80000"  But
> -   it turns out that 0x80000 was used as the syscall break in the early
> -   simulators.  So I changed the pattern slightly to do "break.i 0x080001"
> -   instead.  But that didn't work either (I later found out that this
> -   pattern was used by the simulator that I was using.)  So I ended up
> -   using the pattern seen below. */
> +/* Limit the number of skipped non-prologue instructions since examining
> +   of the prologue is expensive.  */
> +static int max_skip_non_prologue_insns = 10;
> 
> -#if 0
> -#define BREAKPOINT 0x00002000040LL
> -#endif
> -#define BREAKPOINT 0x00003333300LL
> +/* Given PC representing the starting address of a function, and
> +   LIM_PC which is the (sloppy) limit to which to scan when looking
> +   for a prologue, attempt to further refine this limit by using
> +   the line data in the symbol table.  If successful, a better guess
> +   on where the prologue ends is returned, otherwise the previous
> +   value of lim_pc is returned.  TRUST_LIMIT is a pointer to a flag
> +   which will be set to indicate whether the returned limit may be
> +   used with no further scanning in the event that the function is
> +   frameless.  */
> 
> -static int
> -ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
> +static CORE_ADDR
> +refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
>  {
> -  char bundle[BUNDLE_LEN];
> -  int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
> -  long long instr;
> -  int val;
> -  int template;
> +  struct symtab_and_line prologue_sal;
> +  CORE_ADDR start_pc = pc;
> 
> -  if (slotnum > 2)
> -    error("Can't insert breakpoint for slot numbers greater than 2.");
> +  /* Start off not trusting the limit.  */
> +  *trust_limit = 0;
> 
> -  addr &= ~0x0f;
> +  prologue_sal = find_pc_line (pc, 0);
> +  if (prologue_sal.line != 0)
> +    {
> +      int i;
> +      CORE_ADDR addr = prologue_sal.end;
> 
> -  val = target_read_memory (addr, bundle, BUNDLE_LEN);
> +      /* Handle the case in which compiler's optimizer/scheduler
> +         has moved instructions into the prologue.  We scan ahead
> +        in the function looking for address ranges whose corresponding
> +        line number is less than or equal to the first one that we
> +        found for the function.  (It can be less than when the
> +        scheduler puts a body instruction before the first prologue
> +        instruction.)  */
> +      for (i = 2 * max_skip_non_prologue_insns;
> +           i > 0 && (lim_pc == 0 || addr < lim_pc);
> +          i--)
> +        {
> +         struct symtab_and_line sal;
> 
> -  /* Check for L type instruction in 2nd slot, if present then
> -     bump up the slot number to the 3rd slot */
> -  template = extract_bit_field (bundle, 0, 5);
> -  if (slotnum == 1 && template_encoding_table[template][1] == L)
> -    {
> -      slotnum = 2;
> +         sal = find_pc_line (addr, 0);
> +         if (sal.line == 0)
> +           break;
> +         if (sal.line <= prologue_sal.line
> +             && sal.symtab == prologue_sal.symtab)
> +           {
> +             prologue_sal = sal;
> +           }
> +         addr = sal.end;
> +       }
> +
> +      if (lim_pc == 0 || prologue_sal.end < lim_pc)
> +       {
> +         lim_pc = prologue_sal.end;
> +         if (start_pc == get_pc_function_start (lim_pc))
> +           *trust_limit = 1;
> +       }
>      }
> +  return lim_pc;
> +}
> 
> -  instr = slotN_contents (bundle, slotnum);
> -  memcpy(contents_cache, &instr, sizeof(instr));
> -  replace_slotN_contents (bundle, BREAKPOINT, slotnum);
> -  if (val == 0)
> -    target_write_memory (addr, bundle, BUNDLE_LEN);
> +#define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
> +  || (8 <= (_regnum_) && (_regnum_) <= 11) \
> +  || (14 <= (_regnum_) && (_regnum_) <= 31))
> +#define imm9(_instr_) \
> +  ( ((((_instr_) & 0x01000000000LL) ? -1 : 0) << 8) \
> +   | (((_instr_) & 0x00008000000LL) >> 20) \
> +   | (((_instr_) & 0x00000001fc0LL) >> 6))
> 
> -  return val;
> -}
> +#endif /* NEED_PROLOGUE_SCANNING */
> 
> -static int
> -ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
> -{
> -  char bundle[BUNDLE_LEN];
> -  int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
> -  long long instr;
> -  int val;
> -  int template;
> +#ifdef HAVE_LIBUNWIND_IA64_H
> 
> -  addr &= ~0x0f;
> +#include <elf.h>
> +#include <fcntl.h>
> +#include <libunwind-ia64.h>
> 
> -  val = target_read_memory (addr, bundle, BUNDLE_LEN);
> +#include <sys/mman.h>
> 
> -  /* Check for L type instruction in 2nd slot, if present then
> -     bump up the slot number to the 3rd slot */
> -  template = extract_bit_field (bundle, 0, 5);
> -  if (slotnum == 1 && template_encoding_table[template][1] == L)
> -    {
> -      slotnum = 2;
> -    }
> +#include "gdb_assert.h"
> 
> -  memcpy (&instr, contents_cache, sizeof instr);
> -  replace_slotN_contents (bundle, instr, slotnum);
> -  if (val == 0)
> -    target_write_memory (addr, bundle, BUNDLE_LEN);
> +/* XXX fix me */
> +#if 0
> +extern unsigned long getunwind (void *buf, size_t len);
> +#else
> 
> -  return val;
> -}
> +#include <unistd.h>
> +#include <sys/syscall.h>
> 
> -/* We don't really want to use this, but remote.c needs to call it in order
> -   to figure out if Z-packets are supported or not.  Oh, well. */
> -const unsigned char *
> -ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
> +# ifndef __NR_getunwind
> +#  define __NR_getunwind       1215
> +# endif
> +
> +static unsigned long
> +getunwind (void *buf, size_t len)
>  {
> -  static unsigned char breakpoint[] =
> -    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> -  *lenptr = sizeof (breakpoint);
> -#if 0
> -  *pcptr &= ~0x0f;
> -#endif
> -  return breakpoint;
> +  return syscall (SYS_getunwind, buf, len);
>  }
> +#endif
> 
> -CORE_ADDR
> -ia64_read_pc (ptid_t ptid)
> -{
> -  CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
> -  CORE_ADDR pc_value   = read_register_pid (IA64_IP_REGNUM, ptid);
> -  int slot_num = (psr_value >> 41) & 3;
> +struct ia64_unwind_table_entry
> +  {
> +    unw_word_t start_offset;
> +    unw_word_t end_offset;
> +    unw_word_t info_offset;
> +  };
> 
> -  return pc_value | (slot_num * SLOT_MULTIPLIER);
> +static __inline__ uint64_t
> +ia64_rse_slot_num (uint64_t addr)
> +{
> +  return (addr >> 3) & 0x3f;
>  }
> 
> -void
> -ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
> +static __inline__ uint64_t
> +ia64_rse_skip_regs (uint64_t addr, long num_regs)
>  {
> -  int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
> -  CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
> -  psr_value &= ~(3LL << 41);
> -  psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
> -
> -  new_pc &= ~0xfLL;
> +  long delta = ia64_rse_slot_num(addr) + num_regs;
> 
> -  write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
> -  write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
> +  if (num_regs < 0)
> +    delta -= 0x3e;
> +  return addr + ((num_regs + delta/0x3f) << 3);
>  }
> 
> -#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
> +unw_regnum_t
> +gdb2uw_regnum (int regnum)
> +{
> +  if (regnum == sp_regnum)
> +    return UNW_IA64_SP;
> +  else if (regnum == IA64_BSP_REGNUM)
> +    return UNW_IA64_BSP;
> +  else if ((unsigned) (regnum - IA64_GR0_REGNUM) < 128)
> +    return UNW_IA64_GR + (regnum - IA64_GR0_REGNUM);
> +  else if ((unsigned) (regnum - IA64_FR0_REGNUM) < 128)
> +    return UNW_IA64_FR + (regnum - IA64_FR0_REGNUM);
> +  else if ((unsigned) (regnum - IA64_PR0_REGNUM) < 64)
> +    return -1;
> +  else if ((unsigned) (regnum - IA64_BR0_REGNUM) < 8)
> +    return UNW_IA64_BR + (regnum - IA64_BR0_REGNUM);
> +  else if (regnum == IA64_PR_REGNUM)
> +    return UNW_IA64_PR;
> +  else if (regnum == IA64_IP_REGNUM)
> +    return UNW_REG_IP;
> +  else if (regnum == IA64_CFM_REGNUM)
> +    return UNW_IA64_CFM;
> +  else if ((unsigned) (regnum - IA64_AR0_REGNUM) < 128)
> +    return UNW_IA64_AR + (regnum - IA64_AR0_REGNUM);
> +  else if ((unsigned) (regnum - IA64_NAT0_REGNUM) < 128)
> +    return UNW_IA64_NAT + (regnum - IA64_NAT0_REGNUM);
> +  else
> +    return -1;
> +}
> 
> -/* Returns the address of the slot that's NSLOTS slots away from
> -   the address ADDR. NSLOTS may be positive or negative. */
> -static CORE_ADDR
> -rse_address_add(CORE_ADDR addr, int nslots)
> +int
> +uw2gdb_regnum (unw_regnum_t uw_regnum)
>  {
> -  CORE_ADDR new_addr;
> -  int mandatory_nat_slots = nslots / 63;
> -  int direction = nslots < 0 ? -1 : 1;
> +  if (uw_regnum == UNW_IA64_SP)
> +    return sp_regnum;
> +  else if (uw_regnum == UNW_IA64_BSP)
> +    return IA64_BSP_REGNUM;
> +  else if ((unsigned) (uw_regnum - UNW_IA64_GR) < 128)
> +    return IA64_GR0_REGNUM + (uw_regnum - UNW_IA64_GR);
> +  else if ((unsigned) (uw_regnum - UNW_IA64_FR) < 128)
> +    return IA64_FR0_REGNUM + (uw_regnum - UNW_IA64_FR);
> +  else if ((unsigned) (uw_regnum - UNW_IA64_BR) < 8)
> +    return IA64_BR0_REGNUM + (uw_regnum - UNW_IA64_BR);
> +  else if (uw_regnum == UNW_IA64_PR)
> +    return IA64_PR_REGNUM;
> +  else if (uw_regnum == UNW_REG_IP)
> +    return IA64_IP_REGNUM;
> +  else if (uw_regnum == UNW_IA64_CFM)
> +    return IA64_CFM_REGNUM;
> +  else if ((unsigned) (uw_regnum - UNW_IA64_AR) < 128)
> +    return IA64_AR0_REGNUM + (uw_regnum - UNW_IA64_AR);
> +  else if ((unsigned) (uw_regnum - UNW_IA64_NAT) < 128)
> +    return IA64_NAT0_REGNUM + (uw_regnum - UNW_IA64_NAT);
> +  else
> +    return -1;
> +}
> 
> -  new_addr = addr + 8 * (nslots + mandatory_nat_slots);
> +static int
> +access_reg (unw_regnum_t uw_regnum, unw_word_t *val, int write, void *arg)
> +{
> +  int regnum = uw2gdb_regnum (uw_regnum);
> +  unw_word_t bsp, sof, cfm, psr, ip;
> +  struct frame_info *fi = arg;
> +  long new_sof, old_sof;
> 
> -  if ((new_addr >> 9)  != ((addr + 8 * 64 * mandatory_nat_slots) >> 9))
> -    new_addr += 8 * direction;
> +  if (fi && PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
> +    {
> +      if (write)
> +       return -UNW_EREADONLYREG;
> +      else
> +       {
> +         *val = generic_read_register_dummy (fi->pc, fi->frame, regnum);
> +         if (gdbarch_debug >= 1)
> +           fprintf_unfiltered (gdb_stdlog, "  access_reg: from dummy: "
> +                               "%4s=%016lx (uwreg %s)\n",
> +                               (((unsigned) regnum <= IA64_NAT127_REGNUM)
> +                                ? ia64_register_names[regnum] : "r??"), *val,
> +                               unw_regname (uw_regnum));
> +         return 0;
> +       }
> +    }
> 
> -  if (IS_NaT_COLLECTION_ADDR(new_addr))
> -    new_addr += 8 * direction;
> -
> -  return new_addr;
> -}
> +  if (write)
> +    {
> +      if (regnum < 0)
> +       /* ignore writes to pseudo-registers such as UNW_IA64_PROC_START */
> +       return 0;
> 
> -/* The IA-64 frame chain is a bit odd.  We won't always have a frame
> -   pointer, so we use the SP value as the FP for the purpose of
> -   creating a frame.  There is sometimes a register (not fixed) which
> -   is used as a frame pointer.  When this register exists, it is not
> -   especially hard to determine which one is being used.  It isn't
> -   even really hard to compute the frame chain, but it can be
> -   computationally expensive.  So, instead of making life difficult
> -   (and slow), we pick a more convenient representation of the frame
> -   chain, knowing that we'll have to make some small adjustments in
> -   other places.  (E.g, note that read_fp() is actually read_sp() in
> -   ia64_gdbarch_init() below.)
> +      switch (uw_regnum)
> +       {
> +       case UNW_REG_IP:
> +         ia64_write_pc (*val, inferior_ptid);
> +         break;
> 
> -   Okay, so what is the frame chain exactly?  It'll be the SP value
> -   at the time that the function in question was entered.
> +       case UNW_IA64_AR_BSP:
> +       case UNW_IA64_BSP:
> +         /* Account for the fact that ptrace() expects bsp to point
> +            *after* the current register frame.  */
> +         cfm = read_register (IA64_CFM_REGNUM);
> +         sof = (cfm & 0x7f);
> +         bsp = ia64_rse_skip_regs (*val, sof);
> +         write_register (IA64_BSP_REGNUM, bsp);
> +         break;
> 
> -   Note that this *should* actually the frame pointer for the current
> -   function!  But as I note above, if we were to attempt to find the
> -   address of the beginning of the previous frame, we'd waste a lot
> -   of cycles for no good reason.  So instead, we simply choose to
> -   represent the frame chain as the end of the previous frame instead
> -   of the beginning.  */
> +       case UNW_IA64_CFM:
> +         /* If we change CFM, we need to adjust ptrace's notion of
> +            bsp accordingly, so that the real bsp remains
> +            unchanged.  */
> +         bsp = read_register (IA64_BSP_REGNUM);
> +         cfm = read_register (IA64_CFM_REGNUM);
> +         old_sof = (cfm & 0x7f);
> +         new_sof = (*val & 0x7f);
> +         if (old_sof != new_sof)
> +           {
> +             bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
> +             write_register (IA64_BSP_REGNUM, bsp);
> +           }
> +         write_register (IA64_CFM_REGNUM, *val);
> +         break;
> 
> -CORE_ADDR
> -ia64_frame_chain (struct frame_info *frame)
> -{
> -  if (frame->signal_handler_caller)
> -    return read_sigcontext_register (frame, sp_regnum);
> -  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
> -    return frame->frame;
> +       default:
> +         write_register (regnum, *val);
> +         break;
> +       }
> +      if (gdbarch_debug >= 1)
> +       fprintf_unfiltered (gdb_stdlog, "  access_reg: to cache: "
> +                           "%4s=%016lx (uwreg %s)\n",
> +                           (((unsigned) regnum <= IA64_NAT127_REGNUM)
> +                            ? ia64_register_names[regnum] : "r??"), *val,
> +                           unw_regname (uw_regnum));
> +    }
>    else
>      {
> -      FRAME_INIT_SAVED_REGS (frame);
> -      if (frame->saved_regs[IA64_VFP_REGNUM])
> -       return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
> -      else
> -       return frame->frame + frame->extra_info->mem_stack_frame_size;
> +      switch (uw_regnum)
> +       {
> +       case UNW_REG_IP:
> +         if (fi)
> +           *val = fi->pc;
> +         else
> +           {
> +             ip = read_register (IA64_IP_REGNUM);
> +             psr = read_register (IA64_PSR_REGNUM);
> +             *val = ip | ((psr >> 41) & 0x3);
> +           }
> +         break;
> +
> +       case UNW_IA64_AR_BSP:
> +         /* Account for the fact that ptrace() returns a value for
> +            bsp that points *after* the current register frame.  */
> +         bsp = read_register (IA64_BSP_REGNUM);
> +         cfm = read_register (IA64_CFM_REGNUM);
> +         sof = (cfm & 0x7f);
> +         *val = ia64_rse_skip_regs (bsp, -sof);
> +         break;
> +
> +       case UNW_IA64_GR + 12:
> +         if (fi)
> +           {
> +             *val = fi->frame;
> +             break;
> +           }
> +         /* fall through */
> +       default:
> +         *val = read_register (regnum);
> +         break;
> +       }
> +
> +      if (gdbarch_debug >= 1)
> +       fprintf_unfiltered (gdb_stdlog, "  access_reg: from cache: "
> +                           "%4s=%016lx (uwreg %s)\n",
> +                           (((unsigned) regnum <= IA64_NAT127_REGNUM)
> +                            ? ia64_register_names[regnum] : "r??"), *val,
> +                           unw_regname (uw_regnum));
>      }
> +  return 0;
>  }
> 
> -CORE_ADDR
> -ia64_frame_saved_pc (struct frame_info *frame)
> +static int
> +access_fpreg (unw_regnum_t uw_regnum, unw_fpreg_t *val, int write, void *arg)
>  {
> -  if (frame->signal_handler_caller)
> -    return read_sigcontext_register (frame, pc_regnum);
> -  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
> -    return generic_read_register_dummy (frame->pc, frame->frame, pc_regnum);
> +  int regnum = uw2gdb_regnum (uw_regnum);
> +
> +  if (write)
> +    write_register_gen (regnum, (char *) val);
>    else
> +    read_register_gen (regnum, (char *) val);
> +  return 0;
> +}
> +
> +static int
> +get_kernel_table (unw_word_t ip, unw_ia64_table_t *t)
> +{
> +  size_t size;
> +  static struct ia64_unwind_table_entry *ktab = NULL, *etab;
> +
> +  if (!ktab)
>      {
> -      FRAME_INIT_SAVED_REGS (frame);
> +      size = getunwind (NULL, 0);
> +      ktab = xmalloc (size);
> +      getunwind (ktab, size);
> 
> -      if (frame->saved_regs[IA64_VRAP_REGNUM])
> -       return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
> -      else if (frame->next && frame->next->signal_handler_caller)
> -       return read_sigcontext_register (frame->next, IA64_BR0_REGNUM);
> -      else     /* either frameless, or not far enough along in the prologue... */
> -       return ia64_saved_pc_after_call (frame);
> +      /* Determine length of kernel's unwind table.  */
> +      for (etab = ktab; etab->start_offset; ++etab);
>      }
> -}
> 
> -/* Limit the number of skipped non-prologue instructions since examining
> -   of the prologue is expensive.  */
> -static int max_skip_non_prologue_insns = 10;
> +  if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
> +    return -UNW_ENOINFO;
> 
> -/* Given PC representing the starting address of a function, and
> -   LIM_PC which is the (sloppy) limit to which to scan when looking
> -   for a prologue, attempt to further refine this limit by using
> -   the line data in the symbol table.  If successful, a better guess
> -   on where the prologue ends is returned, otherwise the previous
> -   value of lim_pc is returned.  TRUST_LIMIT is a pointer to a flag
> -   which will be set to indicate whether the returned limit may be
> -   used with no further scanning in the event that the function is
> -   frameless.  */
> +  t->name = "<kernel>";
> +  t->gp = 0;
> +  t->segbase = 0;
> +  t->start = ktab[0].start_offset;
> +  t->end = etab[-1].end_offset;
> +  t->length = etab - ktab;
> +  t->array = ktab;
> +  t->unwind_info_base = (const u_int8_t *) ktab;
> 
> -static CORE_ADDR
> -refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit)
> +  if (gdbarch_debug >= 1)
> +    fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': "
> +                       "segbase=%lx, length=%lu, gp=%lx\n",
> +                       t->name, t->segbase, t->length, t->gp);
> +  return 0;
> +}
> +
> +static void *
> +map_segment (bfd *bfd, Elf_Internal_Phdr *p_text)
>  {
> -  struct symtab_and_line prologue_sal;
> -  CORE_ADDR start_pc = pc;
> +  size_t page_mask = getpagesize () - 1, nbytes;
> +  char *buf, *cp;
> +  ssize_t nread;
> +  int fd;
> 
> -  /* Start off not trusting the limit.  */
> -  *trust_limit = 0;
> +  if (bfd->iostream)
> +    fd = fileno (bfd->iostream);
> +  else
> +    fd = open (bfd_get_filename (bfd), O_RDONLY);
> 
> -  prologue_sal = find_pc_line (pc, 0);
> -  if (prologue_sal.line != 0)
> +  if (fd < 0)
> +    return NULL;
> +
> +  buf = mmap (0, p_text->p_filesz, PROT_READ, MAP_PRIVATE, fd,
> +             p_text->p_offset & ~page_mask);
> +  if (buf == (char *) -1)
> +    buf += p_text->p_offset & page_mask;
> +  else
>      {
> -      int i;
> -      CORE_ADDR addr = prologue_sal.end;
> +      /* mmap () failed, try reading the file: */
> 
> -      /* Handle the case in which compiler's optimizer/scheduler
> -         has moved instructions into the prologue.  We scan ahead
> -        in the function looking for address ranges whose corresponding
> -        line number is less than or equal to the first one that we
> -        found for the function.  (It can be less than when the
> -        scheduler puts a body instruction before the first prologue
> -        instruction.)  */
> -      for (i = 2 * max_skip_non_prologue_insns;
> -           i > 0 && (lim_pc == 0 || addr < lim_pc);
> -          i--)
> -        {
> -         struct symtab_and_line sal;
> +      if (lseek (fd, p_text->p_offset, SEEK_SET) < 0)
> +       {
> +         if (!bfd->iostream)
> +           close (fd);
> +         return NULL;
> +       }
> 
> -         sal = find_pc_line (addr, 0);
> -         if (sal.line == 0)
> -           break;
> -         if (sal.line <= prologue_sal.line
> -             && sal.symtab == prologue_sal.symtab)
> -           {
> -             prologue_sal = sal;
> -           }
> -         addr = sal.end;
> +      nbytes = p_text->p_filesz;
> +      cp = buf = xmalloc (nbytes);
> +      while ((nbytes > 0) && (nread = read (fd, cp, nbytes)) > 0)
> +       {
> +         cp += nread;
> +         nbytes -= nread;
>         }
> +      if (nbytes > 0)
> +       /* premature end-of-file or some error */
> +       buf = 0;
> +    }
> +  if (!bfd->iostream)
> +    close (fd);
> 
> -      if (lim_pc == 0 || prologue_sal.end < lim_pc)
> +  return buf;
> +}
> +
> +static int
> +acquire_unwind_info (unw_word_t ip, void *unwind_info, void *arg)
> +{
> +  Elf_Internal_Phdr *phdr, *p_text = NULL, *p_unwind = NULL;
> +  struct obj_section *sec = find_pc_section (ip);
> +  unw_ia64_table_t *t = unwind_info;
> +  Elf_Internal_Ehdr *ehdr;
> +  CORE_ADDR load_base;
> +  bfd *bfd;
> +  int i;
> +
> +  if (!sec)
> +    /* XXX This only works if the host and the target architecture are
> +       both ia64 and if the have (more or less) the same kernel
> +       version.  */
> +    return get_kernel_table (ip, t);
> +
> +  bfd = sec->objfile->obfd;
> +
> +  ehdr = elf_tdata (bfd)->elf_header;
> +  phdr = elf_tdata (bfd)->phdr;
> +
> +  load_base = ANOFFSET (sec->objfile->section_offsets,
> +                       SECT_OFF_TEXT (sec->objfile));
> +
> +  for (i = 0; i < ehdr->e_phnum; ++i)
> +    {
> +      switch (phdr[i].p_type)
>         {
> -         lim_pc = prologue_sal.end;
> -         if (start_pc == get_pc_function_start (lim_pc))
> -           *trust_limit = 1;
> +       case PT_LOAD:
> +         if ((unw_word_t) (ip - load_base - phdr[i].p_vaddr)
> +             < phdr[i].p_memsz)
> +           p_text = phdr + i;
> +         break;
> +
> +       case PT_IA_64_UNWIND:
> +         p_unwind = phdr + i;
> +         break;
> +
> +       default:
> +         break;
>         }
>      }
> -  return lim_pc;
> +
> +  if (!p_text || !p_unwind)
> +    return -UNW_ENOINFO;
> +
> +  t->name = bfd_get_filename (bfd);
> +  t->segbase = p_text->p_vaddr + load_base;
> +  t->start = p_text->p_vaddr + load_base;
> +  t->end = p_text->p_vaddr + load_base + p_text->p_memsz;
> +  t->gp = FIND_GLOBAL_POINTER (ip);
> +  t->length = p_unwind->p_memsz / 24;
> +
> +  t->unwind_info_base = map_segment (bfd, p_text);
> +  if (!t->unwind_info_base)
> +    return -UNW_ENOINFO;
> +
> +  t->array = ((unsigned char *) t->unwind_info_base
> +             + (p_unwind->p_vaddr - p_text->p_vaddr));
> +
> +  if (gdbarch_debug >= 1)
> +    fprintf_unfiltered (gdb_stdlog, "ia64_acquire_unwind_info: %lx -> "
> +                       "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx,"
> +                       "length=%lu,array=%p)\n", ip, t->name, t->segbase,
> +                       t->start, t->end, t->gp, t->length, t->array);
> +  return 0;
>  }
> 
> -#define isScratch(_regnum_) ((_regnum_) == 2 || (_regnum_) == 3 \
> -  || (8 <= (_regnum_) && (_regnum_) <= 11) \
> -  || (14 <= (_regnum_) && (_regnum_) <= 31))
> -#define imm9(_instr_) \
> -  ( ((((_instr_) & 0x01000000000LL) ? -1 : 0) << 8) \
> -   | (((_instr_) & 0x00008000000LL) >> 20) \
> -   | (((_instr_) & 0x00000001fc0LL) >> 6))
> +static int
> +release_unwind_info (void *unwind_info, void *arg)
> +{
> +  /* TBD */
> +  return 0;
> +}
> +
> +#include "unwind-common.h"
> +
> +#ifdef NEED_PROLOGUE_SCANNING
> +
> +/* Simplified version of examine_prologue() below.  */
> 
>  static CORE_ADDR
> -examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
> +min_examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc)
>  {
>    CORE_ADDR next_pc;
>    CORE_ADDR last_prologue_pc = pc;
> @@ -833,23 +887,11 @@
>    memset (instores, 0, sizeof instores);
>    memset (infpstores, 0, sizeof infpstores);
> 
> -  if (frame && !frame->saved_regs)
> -    {
> -      frame_saved_regs_zalloc (frame);
> -      do_fsr_stuff = 1;
> -    }
> -
> -  if (frame
> -      && !do_fsr_stuff
> -      && frame->extra_info->after_prologue != 0
> -      && frame->extra_info->after_prologue <= lim_pc)
> -    return frame->extra_info->after_prologue;
> -
>    lim_pc = refine_prologue_limit (pc, lim_pc, &trust_limit);
> 
>    /* Must start with an alloc instruction */
>    next_pc = fetch_instruction (pc, &it, &instr);
> -  if (pc < lim_pc && next_pc
> +  if (pc < lim_pc && next_pc
>        && it == M && ((instr & 0x1ee0000003fLL) == 0x02c00000000LL))
>      {
>        /* alloc */
> @@ -883,7 +925,7 @@
>        if ((it == B && ((instr & 0x1e1f800003f) != 0x04000000000))
>            || ((instr & 0x3fLL) != 0LL))
>         {
> -         /* Exit loop upon hitting a non-nop branch instruction
> +         /* Exit loop upon hitting a non-nop branch instruction
>              or a predicated instruction. */
>           break;
>         }
> @@ -900,11 +942,11 @@
>               last_prologue_pc = next_pc;
>             }
>         }
> -      else if ((it == I || it == M)
> +      else if ((it == I || it == M)
>            && ((instr & 0x1ee00000000LL) == 0x10800000000LL))
>         {
>           /* adds rN = imm14, rM   (or mov rN, rM  when imm14 is 0) */
> -         int imm = (int) ((((instr & 0x01000000000LL) ? -1 : 0) << 13)
> +         int imm = (int) ((((instr & 0x01000000000LL) ? -1 : 0) << 13)
>                            | ((instr & 0x001f8000000LL) >> 20)
>                            | ((instr & 0x000000fe000LL) >> 13));
>           int rM = (int) ((instr & 0x00007f00000LL) >> 20);
> @@ -923,29 +965,27 @@
>               mem_stack_frame_size -= imm;
>               last_prologue_pc = next_pc;
>             }
> -         else if (qp == 0 && rN == 2
> +         else if (qp == 0 && rN == 2
>                 && ((rM == fp_reg && fp_reg != 0) || rM == 12))
>             {
> -             /* adds r2, spilloffset, rFramePointer
> +             /* adds r2, spilloffset, rFramePointer
>                    or
>                  adds r2, spilloffset, r12
> 
>                  Get ready for stf.spill or st8.spill instructions.
> -                The address to start spilling at is loaded into r2.
> +                The address to start spilling at is loaded into r2.
>                  FIXME:  Why r2?  That's what gcc currently uses; it
>                  could well be different for other compilers.  */
> 
>               /* Hmm... whether or not this will work will depend on
>                  where the pc is.  If it's still early in the prologue
>                  this'll be wrong.  FIXME */
> -             spill_addr  = (frame ? frame->frame : 0)
> -                         + (rM == 12 ? 0 : mem_stack_frame_size)
> -                         + imm;
> +             spill_addr  = (rM == 12 ? 0 : mem_stack_frame_size) + imm;
>               spill_reg   = rN;
>               last_prologue_pc = next_pc;
>             }
>         }
> -      else if (it == M
> +      else if (it == M
>              && (   ((instr & 0x1efc0000000LL) == 0x0eec0000000LL)
>                  || ((instr & 0x1ffc8000000LL) == 0x0cec0000000LL) ))
>         {
> @@ -960,9 +1000,6 @@
>           if (qp == 0 && rN == spill_reg && spill_addr != 0
>               && ((2 <= fM && fM <= 5) || (16 <= fM && fM <= 31)))
>             {
> -             if (do_fsr_stuff)
> -               frame->saved_regs[IA64_FR0_REGNUM + fM] = spill_addr;
> -
>                if ((instr & 0x1efc0000000) == 0x0eec0000000)
>                 spill_addr += imm;
>               else
> @@ -973,8 +1010,8 @@
>        else if ((it == M && ((instr & 0x1eff8000000LL) == 0x02110000000LL))
>              || (it == I && ((instr & 0x1eff8000000LL) == 0x00050000000LL)) )
>         {
> -         /* mov.m rN = arM
> -              or
> +         /* mov.m rN = arM
> +              or
>              mov.i rN = arM */
> 
>           int arM = (int) ((instr & 0x00007f00000LL) >> 20);
> @@ -999,11 +1036,11 @@
>               last_prologue_pc = next_pc;
>             }
>         }
> -      else if (it == M
> +      else if (it == M
>              && (   ((instr & 0x1ffc8000000LL) == 0x08cc0000000LL)
>                 || ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)))
>         {
> -         /* st8 [rN] = rM
> +         /* st8 [rN] = rM
>               or
>              st8 [rN] = rM, imm9 */
>           int rN = (int) ((instr & 0x00007f00000LL) >> 20);
> @@ -1019,15 +1056,11 @@
>               if (rM == unat_save_reg)
>                 {
>                   /* Track UNAT register */
> -                 if (do_fsr_stuff)
> -                   frame->saved_regs[IA64_UNAT_REGNUM] = spill_addr;
>                   unat_save_reg = 0;
>                 }
>               else
>                 {
>                   /* Track PR register */
> -                 if (do_fsr_stuff)
> -                   frame->saved_regs[IA64_PR_REGNUM] = spill_addr;
>                   pr_save_reg = 0;
>                 }
>               if ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)
> @@ -1052,7 +1085,7 @@
>                st4 [rN] = rM
>                st8 [rN] = rM
>              Note that the st8 case is handled in the clause above.
> -
> +
>              Advance over stores of input registers. One store per input
>              register is permitted. */
>           int rM = (int) ((instr & 0x000000fe000LL) >> 13);
> @@ -1095,8 +1128,6 @@
>               /* We've found a spill of one of the preserved general purpose
>                  regs.  Record the spill address and advance the spill
>                  register if appropriate. */
> -             if (do_fsr_stuff)
> -               frame->saved_regs[IA64_GR0_REGNUM + rM] = spill_addr;
>               if ((instr & 0x1efc0000000LL) == 0x0aec0000000LL)
>                 /* st8.spill [rN] = rM, imm9 */
>                 spill_addr += imm9(instr);
> @@ -1108,179 +1139,646 @@
> 
>        pc = next_pc;
>      }
> -
> -  if (do_fsr_stuff) {
> -    int i;
> -    CORE_ADDR addr;
> -    int sor, rrb_gr;
> -
> -    /* Extract the size of the rotating portion of the stack
> -       frame and the register rename base from the current
> -       frame marker. */
> -    sor = ((frame->extra_info->cfm >> 14) & 0xf) * 8;
> -    rrb_gr = (frame->extra_info->cfm >> 18) & 0x7f;
> -
> -    for (i = 0, addr = frame->extra_info->bsp;
> -        i < frame->extra_info->sof;
> -        i++, addr += 8)
> -      {
> -       if (IS_NaT_COLLECTION_ADDR (addr))
> -         {
> -           addr += 8;
> -         }
> -       if (i < sor)
> -         frame->saved_regs[IA64_GR32_REGNUM + ((i + (sor - rrb_gr)) % sor)]
> -           = addr;
> -       else
> -         frame->saved_regs[IA64_GR32_REGNUM + i] = addr;
> -
> -       if (i+32 == cfm_reg)
> -         frame->saved_regs[IA64_CFM_REGNUM] = addr;
> -       if (i+32 == ret_reg)
> -         frame->saved_regs[IA64_VRAP_REGNUM] = addr;
> -       if (i+32 == fp_reg)
> -         frame->saved_regs[IA64_VFP_REGNUM] = addr;
> -      }
> -  }
> -
> -  if (frame && frame->extra_info) {
> -    frame->extra_info->after_prologue = last_prologue_pc;
> -    frame->extra_info->mem_stack_frame_size = mem_stack_frame_size;
> -    frame->extra_info->fp_reg = fp_reg;
> -  }
> -
>    return last_prologue_pc;
>  }
> 
> +#endif /* NEED_PROLOGUE_SCANNING */
> +
>  CORE_ADDR
>  ia64_skip_prologue (CORE_ADDR pc)
>  {
> -  return examine_prologue (pc, pc+1024, 0);
> +#ifdef NEED_PROLOGUE_SCANNING
> +  return min_examine_prologue (pc, pc + 1024);
> +#else
> +  return pc;
> +#endif
>  }
> 
>  void
>  ia64_frame_init_saved_regs (struct frame_info *frame)
>  {
> -  if (frame->saved_regs)
> -    return;
> -
> -  if (frame->signal_handler_caller && SIGCONTEXT_REGISTER_ADDRESS)
> -    {
> -      int regno;
> +  /* Nothing to do here.  */
> +}
> 
> -      frame_saved_regs_zalloc (frame);
> +int
> +ia64_frameless_function_invocation (struct frame_info *frame)
> +{
> +  return 0;
> +}
> 
> -      frame->saved_regs[IA64_VRAP_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_IP_REGNUM);
> -      frame->saved_regs[IA64_CFM_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CFM_REGNUM);
> -      frame->saved_regs[IA64_PSR_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PSR_REGNUM);
> -#if 0
> -      frame->saved_regs[IA64_BSP_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_BSP_REGNUM);
> -#endif
> -      frame->saved_regs[IA64_RNAT_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_RNAT_REGNUM);
> -      frame->saved_regs[IA64_CCV_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CCV_REGNUM);
> -      frame->saved_regs[IA64_UNAT_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_UNAT_REGNUM);
> -      frame->saved_regs[IA64_FPSR_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_FPSR_REGNUM);
> -      frame->saved_regs[IA64_PFS_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PFS_REGNUM);
> -      frame->saved_regs[IA64_LC_REGNUM] =
> -       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_LC_REGNUM);
> -      for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
> -       if (regno != sp_regnum)
> -         frame->saved_regs[regno] =
> -           SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> -      for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
> -       frame->saved_regs[regno] =
> -         SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> -      for (regno = IA64_FR2_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
> -       frame->saved_regs[regno] =
> -         SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> +CORE_ADDR
> +ia64_frame_args_address (struct frame_info *frame)
> +{
> +  /* frame->frame points at the SP for this frame; But we want the start
> +     of the frame, not the end.  Calling frame chain will get his for us. */
> +  return uw_frame_chain (frame);
> +}
> +
> +CORE_ADDR
> +ia64_frame_locals_address (struct frame_info *frame)
> +{
> +  /* frame->frame points at the SP for this frame; But we want the start
> +     of the frame, not the end.  Calling frame chain will get his for us. */
> +  return uw_frame_chain (frame);
> +}
> +
> +static int
> +ia64_frame_unchanged (struct frame_info *prev, struct frame_info *next)
> +{
> +  /* libunwind already returns a NULL frame when reaching the end of
> +     the call chain (or when encountering some sort of error).  Thus,
> +     this test is never needed.  */
> +  return 0;
> +}
> +
> +#else /* !HAVE_LIBUNWIND_IA64_H */
> +
> +struct frame_extra_info
> +  {
> +    CORE_ADDR bsp;     /* points at r32 for the current frame */
> +    CORE_ADDR cfm;     /* cfm value for current frame */
> +    int sof;           /* Size of frame  (decoded from cfm value) */
> +    int        sol;            /* Size of locals (decoded from cfm value) */
> +    CORE_ADDR after_prologue;
> +                       /* Address of first instruction after the last
> +                          prologue instruction;  Note that there may
> +                          be instructions from the function's body
> +                          intermingled with the prologue. */
> +    int mem_stack_frame_size;
> +                       /* Size of the memory stack frame (may be zero),
> +                          or -1 if it has not been determined yet. */
> +    int        fp_reg;         /* Register number (if any) used a frame pointer
> +                          for this frame.  0 if no register is being used
> +                          as the frame pointer. */
> +  };
> +
> +static gdbarch_frame_chain_ftype ia64_frame_chain;
> +static gdbarch_frame_saved_pc_ftype ia64_frame_saved_pc;
> +static gdbarch_get_saved_register_ftype ia64_get_saved_register;
> +static gdbarch_init_extra_frame_info_ftype ia64_init_extra_frame_info;
> +static gdbarch_pop_frame_ftype ia64_pop_frame;
> +static void ia64_pop_frame_regular (struct frame_info *frame);
> +
> +static int lr_regnum = IA64_VRAP_REGNUM;
> +
> +/* Read the given register from a sigcontext structure in the
> +   specified frame.  */
> +
> +static CORE_ADDR
> +read_sigcontext_register (struct frame_info *frame, int regnum)
> +{
> +  CORE_ADDR regaddr;
> +
> +  if (frame == NULL)
> +    internal_error (__FILE__, __LINE__,
> +                   "read_sigcontext_register: NULL frame");
> +  if (!frame->signal_handler_caller)
> +    internal_error (__FILE__, __LINE__,
> +                   "read_sigcontext_register: frame not a signal_handler_caller");
> +  if (SIGCONTEXT_REGISTER_ADDRESS == 0)
> +    internal_error (__FILE__, __LINE__,
> +                   "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0");
> +
> +  regaddr = SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regnum);
> +  if (regaddr)
> +    return read_memory_integer (regaddr, REGISTER_RAW_SIZE (regnum));
> +  else
> +    internal_error (__FILE__, __LINE__,
> +                   "read_sigcontext_register: Register %d not in struct sigcontext", regnum);
> +}
> +
> +/* The IA-64 frame chain is a bit odd.  We won't always have a frame
> +   pointer, so we use the SP value as the FP for the purpose of
> +   creating a frame.  There is sometimes a register (not fixed) which
> +   is used as a frame pointer.  When this register exists, it is not
> +   especially hard to determine which one is being used.  It isn't
> +   even really hard to compute the frame chain, but it can be
> +   computationally expensive.  So, instead of making life difficult
> +   (and slow), we pick a more convenient representation of the frame
> +   chain, knowing that we'll have to make some small adjustments
> +   in other places.  (E.g, note that read_fp() and write_fp() are
> +   actually read_sp() and write_sp() below in ia64_gdbarch_init()
> +   below.)
> +
> +   Okay, so what is the frame chain exactly?  It'll be the SP value
> +   at the time that the function in question was entered.
> +
> +   Note that this *should* actually the frame pointer for the current
> +   function!  But as I note above, if we were to attempt to find the
> +   address of the beginning of the previous frame, we'd waste a lot
> +   of cycles for no good reason.  So instead, we simply choose to
> +   represent the frame chain as the end of the previous frame instead
> +   of the beginning.  */
> +
> +CORE_ADDR
> +ia64_frame_chain (struct frame_info *frame)
> +{
> +  if (frame->signal_handler_caller)
> +    return read_sigcontext_register (frame, sp_regnum);
> +  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
> +    return frame->frame;
> +  else
> +    {
> +      FRAME_INIT_SAVED_REGS (frame);
> +      if (frame->saved_regs[IA64_VFP_REGNUM])
> +       return read_memory_integer (frame->saved_regs[IA64_VFP_REGNUM], 8);
> +      else
> +       return frame->frame + frame->extra_info->mem_stack_frame_size;
>      }
> +}
> +
> +CORE_ADDR
> +ia64_frame_saved_pc (struct frame_info *frame)
> +{
> +  if (frame->signal_handler_caller)
> +    return read_sigcontext_register (frame, pc_regnum);
> +  else if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
> +    return generic_read_register_dummy (frame->pc, frame->frame, pc_regnum);
>    else
>      {
> -      CORE_ADDR func_start;
> +      FRAME_INIT_SAVED_REGS (frame);
> 
> -      func_start = get_pc_function_start (frame->pc);
> -      examine_prologue (func_start, frame->pc, frame);
> +      if (frame->saved_regs[IA64_VRAP_REGNUM])
> +       return read_memory_integer (frame->saved_regs[IA64_VRAP_REGNUM], 8);
> +      else if (frame->next && frame->next->signal_handler_caller)
> +       return read_sigcontext_register (frame->next, IA64_BR0_REGNUM);
> +      else     /* either frameless, or not far enough along in the prologue... */
> +       return ia64_saved_pc_after_call (frame);
>      }
>  }
> 
> -void
> -ia64_get_saved_register (char *raw_buffer,
> -                         int *optimized,
> -                        CORE_ADDR *addrp,
> -                        struct frame_info *frame,
> -                        int regnum,
> -                        enum lval_type *lval)
> +static CORE_ADDR
> +examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *frame)
>  {
> -  int is_dummy_frame;
> +  CORE_ADDR next_pc;
> +  CORE_ADDR last_prologue_pc = pc;
> +  instruction_type it;
> +  long long instr;
> +  int do_fsr_stuff = 0;
> 
> -  if (!target_has_registers)
> -    error ("No registers.");
> +  int cfm_reg  = 0;
> +  int ret_reg  = 0;
> +  int fp_reg   = 0;
> +  int unat_save_reg = 0;
> +  int pr_save_reg = 0;
> +  int mem_stack_frame_size = 0;
> +  int spill_reg   = 0;
> +  CORE_ADDR spill_addr = 0;
> +  char instores[8];
> +  char infpstores[8];
> +  int trust_limit;
> 
> -  if (optimized != NULL)
> -    *optimized = 0;
> +  memset (instores, 0, sizeof instores);
> +  memset (infpstores, 0, sizeof infpstores);
> 
> -  if (addrp != NULL)
> -    *addrp = 0;
> +  if (frame && !frame->saved_regs)
> +    {
> +      frame_saved_regs_zalloc (frame);
> +      do_fsr_stuff = 1;
> +    }
> 
> -  if (lval != NULL)
> -    *lval = not_lval;
> +  if (frame
> +      && !do_fsr_stuff
> +      && frame->extra_info->after_prologue != 0
> +      && frame->extra_info->after_prologue <= lim_pc)
> +    return frame->extra_info->after_prologue;
> 
> -  is_dummy_frame = PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame);
> +  lim_pc = refine_prologue_limit (pc, lim_pc, &trust_limit);
> 
> -  if (regnum == SP_REGNUM && frame->next)
> -    {
> -      /* Handle SP values for all frames but the topmost. */
> -      store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
> -    }
> -  else if (regnum == IA64_BSP_REGNUM)
> +  /* Must start with an alloc instruction */
> +  next_pc = fetch_instruction (pc, &it, &instr);
> +  if (pc < lim_pc && next_pc
> +      && it == M && ((instr & 0x1ee0000003fLL) == 0x02c00000000LL))
>      {
> -      store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
> -                     frame->extra_info->bsp);
> +      /* alloc */
> +      int sor = (int) ((instr & 0x00078000000LL) >> 27);
> +      int sol = (int) ((instr & 0x00007f00000LL) >> 20);
> +      int sof = (int) ((instr & 0x000000fe000LL) >> 13);
> +      /* Okay, so sor, sol, and sof aren't used right now; but perhaps
> +         we could compare against the size given to us via the cfm as
> +        either a sanity check or possibly to see if the frame has been
> +        changed by a later alloc instruction... */
> +      int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
> +      cfm_reg = rN;
> +      last_prologue_pc = next_pc;
> +      pc = next_pc;
>      }
> -  else if (regnum == IA64_VFP_REGNUM)
> +  else
>      {
> -      /* If the function in question uses an automatic register (r32-r127)
> -         for the frame pointer, it'll be found by ia64_find_saved_register()
> -        above.  If the function lacks one of these frame pointers, we can
> -        still provide a value since we know the size of the frame */
> -      CORE_ADDR vfp = frame->frame + frame->extra_info->mem_stack_frame_size;
> -      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_VFP_REGNUM), vfp);
> +      pc = lim_pc;     /* Frameless: We're done early.  */
> +      if (trust_limit)
> +       last_prologue_pc = lim_pc;
>      }
> -  else if (IA64_PR0_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
> +
> +  /* Loop, looking for prologue instructions, keeping track of
> +     where preserved registers were spilled. */
> +  while (pc < lim_pc)
>      {
> -      char *pr_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
> -      int  pr_optim;
> -      enum lval_type pr_lval;
> -      CORE_ADDR pr_addr;
> -      int prN_val;
> -      ia64_get_saved_register (pr_raw_buffer, &pr_optim, &pr_addr,
> -                               frame, IA64_PR_REGNUM, &pr_lval);
> -      if (IA64_PR16_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
> -       {
> -         /* Fetch predicate register rename base from current frame
> -            marker for this frame. */
> -         int rrb_pr = (frame->extra_info->cfm >> 32) & 0x3f;
> +      next_pc = fetch_instruction (pc, &it, &instr);
> +      if (next_pc == 0)
> +       break;
> 
> -         /* Adjust the register number to account for register rotation. */
> -         regnum = IA64_PR16_REGNUM
> -                + ((regnum - IA64_PR16_REGNUM) + rrb_pr) % 48;
> +      if ((it == B && ((instr & 0x1e1f800003f) != 0x04000000000))
> +          || ((instr & 0x3fLL) != 0LL))
> +       {
> +         /* Exit loop upon hitting a non-nop branch instruction
> +            or a predicated instruction. */
> +         break;
>         }
> -      prN_val = extract_bit_field ((unsigned char *) pr_raw_buffer,
> -                                   regnum - IA64_PR0_REGNUM, 1);
> -      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), prN_val);
> -    }
> -  else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
> -    {
> -      char *unat_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
> +      else if (it == I && ((instr & 0x1eff8000000LL) == 0x00188000000LL))
> +        {
> +         /* Move from BR */
> +         int b2 = (int) ((instr & 0x0000000e000LL) >> 13);
> +         int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
> +         int qp = (int) (instr & 0x0000000003f);
> +
> +         if (qp == 0 && b2 == 0 && rN >= 32 && ret_reg == 0)
> +           {
> +             ret_reg = rN;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if ((it == I || it == M)
> +          && ((instr & 0x1ee00000000LL) == 0x10800000000LL))
> +       {
> +         /* adds rN = imm14, rM   (or mov rN, rM  when imm14 is 0) */
> +         int imm = (int) ((((instr & 0x01000000000LL) ? -1 : 0) << 13)
> +                          | ((instr & 0x001f8000000LL) >> 20)
> +                          | ((instr & 0x000000fe000LL) >> 13));
> +         int rM = (int) ((instr & 0x00007f00000LL) >> 20);
> +         int rN = (int) ((instr & 0x00000001fc0LL) >> 6);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +
> +         if (qp == 0 && rN >= 32 && imm == 0 && rM == 12 && fp_reg == 0)
> +           {
> +             /* mov rN, r12 */
> +             fp_reg = rN;
> +             last_prologue_pc = next_pc;
> +           }
> +         else if (qp == 0 && rN == 12 && rM == 12)
> +           {
> +             /* adds r12, -mem_stack_frame_size, r12 */
> +             mem_stack_frame_size -= imm;
> +             last_prologue_pc = next_pc;
> +           }
> +         else if (qp == 0 && rN == 2
> +               && ((rM == fp_reg && fp_reg != 0) || rM == 12))
> +           {
> +             /* adds r2, spilloffset, rFramePointer
> +                  or
> +                adds r2, spilloffset, r12
> +
> +                Get ready for stf.spill or st8.spill instructions.
> +                The address to start spilling at is loaded into r2.
> +                FIXME:  Why r2?  That's what gcc currently uses; it
> +                could well be different for other compilers.  */
> +
> +             /* Hmm... whether or not this will work will depend on
> +                where the pc is.  If it's still early in the prologue
> +                this'll be wrong.  FIXME */
> +             spill_addr  = (frame ? frame->frame : 0)
> +                         + (rM == 12 ? 0 : mem_stack_frame_size)
> +                         + imm;
> +             spill_reg   = rN;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == M
> +            && (   ((instr & 0x1efc0000000LL) == 0x0eec0000000LL)
> +                || ((instr & 0x1ffc8000000LL) == 0x0cec0000000LL) ))
> +       {
> +         /* stf.spill [rN] = fM, imm9
> +            or
> +            stf.spill [rN] = fM  */
> +
> +         int imm = imm9(instr);
> +         int rN = (int) ((instr & 0x00007f00000LL) >> 20);
> +         int fM = (int) ((instr & 0x000000fe000LL) >> 13);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && rN == spill_reg && spill_addr != 0
> +             && ((2 <= fM && fM <= 5) || (16 <= fM && fM <= 31)))
> +           {
> +             if (do_fsr_stuff)
> +               frame->saved_regs[IA64_FR0_REGNUM + fM] = spill_addr;
> +
> +              if ((instr & 0x1efc0000000) == 0x0eec0000000)
> +               spill_addr += imm;
> +             else
> +               spill_addr = 0;         /* last one; must be done */
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if ((it == M && ((instr & 0x1eff8000000LL) == 0x02110000000LL))
> +            || (it == I && ((instr & 0x1eff8000000LL) == 0x00050000000LL)) )
> +       {
> +         /* mov.m rN = arM
> +              or
> +            mov.i rN = arM */
> +
> +         int arM = (int) ((instr & 0x00007f00000LL) >> 20);
> +         int rN  = (int) ((instr & 0x00000001fc0LL) >> 6);
> +         int qp  = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && isScratch (rN) && arM == 36 /* ar.unat */)
> +           {
> +             /* We have something like "mov.m r3 = ar.unat".  Remember the
> +                r3 (or whatever) and watch for a store of this register... */
> +             unat_save_reg = rN;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == I && ((instr & 0x1eff8000000LL) == 0x00198000000LL))
> +       {
> +         /* mov rN = pr */
> +         int rN  = (int) ((instr & 0x00000001fc0LL) >> 6);
> +         int qp  = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && isScratch (rN))
> +           {
> +             pr_save_reg = rN;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == M
> +            && (   ((instr & 0x1ffc8000000LL) == 0x08cc0000000LL)
> +               || ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)))
> +       {
> +         /* st8 [rN] = rM
> +             or
> +            st8 [rN] = rM, imm9 */
> +         int rN = (int) ((instr & 0x00007f00000LL) >> 20);
> +         int rM = (int) ((instr & 0x000000fe000LL) >> 13);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && rN == spill_reg && spill_addr != 0
> +             && (rM == unat_save_reg || rM == pr_save_reg))
> +           {
> +             /* We've found a spill of either the UNAT register or the PR
> +                register.  (Well, not exactly; what we've actually found is
> +                a spill of the register that UNAT or PR was moved to).
> +                Record that fact and move on... */
> +             if (rM == unat_save_reg)
> +               {
> +                 /* Track UNAT register */
> +                 if (do_fsr_stuff)
> +                   frame->saved_regs[IA64_UNAT_REGNUM] = spill_addr;
> +                 unat_save_reg = 0;
> +               }
> +             else
> +               {
> +                 /* Track PR register */
> +                 if (do_fsr_stuff)
> +                   frame->saved_regs[IA64_PR_REGNUM] = spill_addr;
> +                 pr_save_reg = 0;
> +               }
> +             if ((instr & 0x1efc0000000LL) == 0x0acc0000000LL)
> +               /* st8 [rN] = rM, imm9 */
> +               spill_addr += imm9(instr);
> +             else
> +               spill_addr = 0;         /* must be done spilling */
> +             last_prologue_pc = next_pc;
> +           }
> +         else if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
> +           {
> +             /* Allow up to one store of each input register. */
> +             instores[rM-32] = 1;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == M && ((instr & 0x1ff08000000LL) == 0x08c00000000LL))
> +       {
> +         /* One of
> +              st1 [rN] = rM
> +              st2 [rN] = rM
> +              st4 [rN] = rM
> +              st8 [rN] = rM
> +            Note that the st8 case is handled in the clause above.
> +
> +            Advance over stores of input registers. One store per input
> +            register is permitted. */
> +         int rM = (int) ((instr & 0x000000fe000LL) >> 13);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && 32 <= rM && rM < 40 && !instores[rM-32])
> +           {
> +             instores[rM-32] = 1;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == M && ((instr & 0x1ff88000000LL) == 0x0cc80000000LL))
> +        {
> +         /* Either
> +              stfs [rN] = fM
> +            or
> +              stfd [rN] = fM
> +
> +            Advance over stores of floating point input registers.  Again
> +            one store per register is permitted */
> +         int fM = (int) ((instr & 0x000000fe000LL) >> 13);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && 8 <= fM && fM < 16 && !infpstores[fM - 8])
> +           {
> +             infpstores[fM-8] = 1;
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +      else if (it == M
> +            && (   ((instr & 0x1ffc8000000LL) == 0x08ec0000000LL)
> +               || ((instr & 0x1efc0000000LL) == 0x0aec0000000LL)))
> +       {
> +         /* st8.spill [rN] = rM
> +              or
> +            st8.spill [rN] = rM, imm9 */
> +         int rN = (int) ((instr & 0x00007f00000LL) >> 20);
> +         int rM = (int) ((instr & 0x000000fe000LL) >> 13);
> +         int qp = (int) (instr & 0x0000000003fLL);
> +         if (qp == 0 && rN == spill_reg && 4 <= rM && rM <= 7)
> +           {
> +             /* We've found a spill of one of the preserved general purpose
> +                regs.  Record the spill address and advance the spill
> +                register if appropriate. */
> +             if (do_fsr_stuff)
> +               frame->saved_regs[IA64_GR0_REGNUM + rM] = spill_addr;
> +             if ((instr & 0x1efc0000000LL) == 0x0aec0000000LL)
> +               /* st8.spill [rN] = rM, imm9 */
> +               spill_addr += imm9(instr);
> +             else
> +               spill_addr = 0;         /* Done spilling */
> +             last_prologue_pc = next_pc;
> +           }
> +       }
> +
> +      pc = next_pc;
> +    }
> +
> +  if (do_fsr_stuff) {
> +    int i;
> +    CORE_ADDR addr;
> +    int sor, rrb_gr;
> +
> +    /* Extract the size of the rotating portion of the stack
> +       frame and the register rename base from the current
> +       frame marker. */
> +    sor = ((frame->extra_info->cfm >> 14) & 0xf) * 8;
> +    rrb_gr = (frame->extra_info->cfm >> 18) & 0x7f;
> +
> +    for (i = 0, addr = frame->extra_info->bsp;
> +        i < frame->extra_info->sof;
> +        i++, addr += 8)
> +      {
> +       if (IS_NaT_COLLECTION_ADDR (addr))
> +         {
> +           addr += 8;
> +         }
> +       if (i < sor)
> +         frame->saved_regs[IA64_GR32_REGNUM + ((i + (sor - rrb_gr)) % sor)]
> +           = addr;
> +       else
> +         frame->saved_regs[IA64_GR32_REGNUM + i] = addr;
> +
> +       if (i+32 == cfm_reg)
> +         frame->saved_regs[IA64_CFM_REGNUM] = addr;
> +       if (i+32 == ret_reg)
> +         frame->saved_regs[IA64_VRAP_REGNUM] = addr;
> +       if (i+32 == fp_reg)
> +         frame->saved_regs[IA64_VFP_REGNUM] = addr;
> +      }
> +  }
> +
> +  if (frame && frame->extra_info) {
> +    frame->extra_info->after_prologue = last_prologue_pc;
> +    frame->extra_info->mem_stack_frame_size = mem_stack_frame_size;
> +    frame->extra_info->fp_reg = fp_reg;
> +  }
> +
> +  return last_prologue_pc;
> +}
> +
> +CORE_ADDR
> +ia64_skip_prologue (CORE_ADDR pc)
> +{
> +  return examine_prologue (pc, pc+1024, 0);
> +}
> +
> +void
> +ia64_frame_init_saved_regs (struct frame_info *frame)
> +{
> +  if (frame->saved_regs)
> +    return;
> +
> +  if (frame->signal_handler_caller && SIGCONTEXT_REGISTER_ADDRESS)
> +    {
> +      int regno;
> +
> +      frame_saved_regs_zalloc (frame);
> +
> +      frame->saved_regs[IA64_VRAP_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_IP_REGNUM);
> +      frame->saved_regs[IA64_CFM_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CFM_REGNUM);
> +      frame->saved_regs[IA64_PSR_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PSR_REGNUM);
> +#if 0
> +      frame->saved_regs[IA64_BSP_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_BSP_REGNUM);
> +#endif
> +      frame->saved_regs[IA64_RNAT_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_RNAT_REGNUM);
> +      frame->saved_regs[IA64_CCV_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_CCV_REGNUM);
> +      frame->saved_regs[IA64_UNAT_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_UNAT_REGNUM);
> +      frame->saved_regs[IA64_FPSR_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_FPSR_REGNUM);
> +      frame->saved_regs[IA64_PFS_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_PFS_REGNUM);
> +      frame->saved_regs[IA64_LC_REGNUM] =
> +       SIGCONTEXT_REGISTER_ADDRESS (frame->frame, IA64_LC_REGNUM);
> +      for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
> +       if (regno != sp_regnum)
> +         frame->saved_regs[regno] =
> +           SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> +      for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
> +       frame->saved_regs[regno] =
> +         SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> +      for (regno = IA64_FR2_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
> +       frame->saved_regs[regno] =
> +         SIGCONTEXT_REGISTER_ADDRESS (frame->frame, regno);
> +    }
> +  else
> +    {
> +      CORE_ADDR func_start;
> +
> +      func_start = get_pc_function_start (frame->pc);
> +      examine_prologue (func_start, frame->pc, frame);
> +    }
> +}
> +
> +void
> +ia64_get_saved_register (char *raw_buffer,
> +                         int *optimized,
> +                        CORE_ADDR *addrp,
> +                        struct frame_info *frame,
> +                        int regnum,
> +                        enum lval_type *lval)
> +{
> +  int is_dummy_frame;
> +
> +  if (!target_has_registers)
> +    error ("No registers.");
> +
> +  if (optimized != NULL)
> +    *optimized = 0;
> +
> +  if (addrp != NULL)
> +    *addrp = 0;
> +
> +  if (lval != NULL)
> +    *lval = not_lval;
> +
> +  is_dummy_frame = PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame);
> +
> +  if (regnum == SP_REGNUM && frame->next)
> +    {
> +      /* Handle SP values for all frames but the topmost. */
> +      store_address (raw_buffer, REGISTER_RAW_SIZE (regnum), frame->frame);
> +    }
> +  else if (regnum == IA64_BSP_REGNUM)
> +    {
> +      store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
> +                     frame->extra_info->bsp);
> +    }
> +  else if (regnum == IA64_VFP_REGNUM)
> +    {
> +      /* If the function in question uses an automatic register (r32-r127)
> +         for the frame pointer, it'll be found by ia64_find_saved_register()
> +        above.  If the function lacks one of these frame pointers, we can
> +        still provide a value since we know the size of the frame */
> +      CORE_ADDR vfp = frame->frame + frame->extra_info->mem_stack_frame_size;
> +      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_VFP_REGNUM), vfp);
> +    }
> +  else if (IA64_PR0_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
> +    {
> +      char *pr_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
> +      int  pr_optim;
> +      enum lval_type pr_lval;
> +      CORE_ADDR pr_addr;
> +      int prN_val;
> +      ia64_get_saved_register (pr_raw_buffer, &pr_optim, &pr_addr,
> +                               frame, IA64_PR_REGNUM, &pr_lval);
> +      if (IA64_PR16_REGNUM <= regnum && regnum <= IA64_PR63_REGNUM)
> +       {
> +         /* Fetch predicate register rename base from current frame
> +            marker for this frame. */
> +         int rrb_pr = (frame->extra_info->cfm >> 32) & 0x3f;
> +
> +         /* Adjust the register number to account for register rotation. */
> +         regnum = IA64_PR16_REGNUM
> +                + ((regnum - IA64_PR16_REGNUM) + rrb_pr) % 48;
> +       }
> +      prN_val = extract_bit_field ((unsigned char *) pr_raw_buffer,
> +                                   regnum - IA64_PR0_REGNUM, 1);
> +      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), prN_val);
> +    }
> +  else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
> +    {
> +      char *unat_raw_buffer = alloca (MAX_REGISTER_RAW_SIZE);
>        int  unat_optim;
>        enum lval_type unat_lval;
>        CORE_ADDR unat_addr;
> @@ -1289,96 +1787,504 @@
>                                 frame, IA64_UNAT_REGNUM, &unat_lval);
>        unatN_val = extract_bit_field ((unsigned char *) unat_raw_buffer,
>                                     regnum - IA64_NAT0_REGNUM, 1);
> -      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum),
> +      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum),
>                                unatN_val);
>      }
> -  else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
> +  else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
> +    {
> +      int natval = 0;
> +      /* Find address of general register corresponding to nat bit we're
> +         interested in. */
> +      CORE_ADDR gr_addr = 0;
> +
> +      if (!is_dummy_frame)
> +       {
> +         FRAME_INIT_SAVED_REGS (frame);
> +         gr_addr = frame->saved_regs[ regnum - IA64_NAT0_REGNUM
> +                                             + IA64_GR0_REGNUM];
> +       }
> +      if (gr_addr)
> +       {
> +         /* Compute address of nat collection bits */
> +         CORE_ADDR nat_addr = gr_addr | 0x1f8;
> +         CORE_ADDR bsp = read_register (IA64_BSP_REGNUM);
> +         CORE_ADDR nat_collection;
> +         int nat_bit;
> +         /* If our nat collection address is bigger than bsp, we have to get
> +            the nat collection from rnat.  Otherwise, we fetch the nat
> +            collection from the computed address. */
> +         if (nat_addr >= bsp)
> +           nat_collection = read_register (IA64_RNAT_REGNUM);
> +         else
> +           nat_collection = read_memory_integer (nat_addr, 8);
> +         nat_bit = (gr_addr >> 3) & 0x3f;
> +         natval = (nat_collection >> nat_bit) & 1;
> +       }
> +      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), natval);
> +    }
> +  else if (regnum == IA64_IP_REGNUM)
> +    {
> +      CORE_ADDR pc;
> +      if (frame->next)
> +        {
> +         /* FIXME: Set *addrp, *lval when possible. */
> +         pc = ia64_frame_saved_pc (frame->next);
> +        }
> +      else
> +        {
> +         pc = read_pc ();
> +       }
> +      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
> +    }
> +  else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
> +    {
> +      CORE_ADDR addr = 0;
> +      if (!is_dummy_frame)
> +       {
> +         FRAME_INIT_SAVED_REGS (frame);
> +         addr = frame->saved_regs[regnum];
> +       }
> +
> +      if (addr != 0)
> +       {
> +         if (lval != NULL)
> +           *lval = lval_memory;
> +         if (addrp != NULL)
> +           *addrp = addr;
> +         read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
> +       }
> +      else
> +        {
> +         /* r32 - r127 must be fetchable via memory.  If they aren't,
> +            then the register is unavailable */
> +         memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
> +        }
> +    }
> +  else
> +    {
> +      if (IA64_FR32_REGNUM <= regnum && regnum <= IA64_FR127_REGNUM)
> +       {
> +         /* Fetch floating point register rename base from current
> +            frame marker for this frame. */
> +         int rrb_fr = (frame->extra_info->cfm >> 25) & 0x7f;
> +
> +         /* Adjust the floating point register number to account for
> +            register rotation. */
> +         regnum = IA64_FR32_REGNUM
> +                + ((regnum - IA64_FR32_REGNUM) + rrb_fr) % 96;
> +       }
> +
> +      generic_get_saved_register (raw_buffer, optimized, addrp, frame,
> +                                  regnum, lval);
> +    }
> +}
> +
> +int
> +ia64_frameless_function_invocation (struct frame_info *frame)
> +{
> +  FRAME_INIT_SAVED_REGS (frame);
> +  return (frame->extra_info->mem_stack_frame_size == 0);
> +}
> +
> +CORE_ADDR
> +ia64_frame_args_address (struct frame_info *frame)
> +{
> +  /* frame->frame points at the SP for this frame; But we want the start
> +     of the frame, not the end.  Calling frame chain will get his for us. */
> +  return ia64_frame_chain (frame);
> +}
> +
> +CORE_ADDR
> +ia64_frame_locals_address (struct frame_info *frame)
> +{
> +  /* frame->frame points at the SP for this frame; But we want the start
> +     of the frame, not the end.  Calling frame chain will get his for us. */
> +  return ia64_frame_chain (frame);
> +}
> +
> +void
> +ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
> +{
> +  CORE_ADDR bsp, cfm;
> +  int next_frame_is_call_dummy = ((frame->next != NULL)
> +    && PC_IN_CALL_DUMMY (frame->next->pc, frame->next->frame,
> +                                          frame->next->frame));
> +
> +  frame->extra_info = (struct frame_extra_info *)
> +    frame_obstack_alloc (sizeof (struct frame_extra_info));
> +
> +  if (frame->next == 0)
> +    {
> +      bsp = read_register (IA64_BSP_REGNUM);
> +      cfm = read_register (IA64_CFM_REGNUM);
> +
> +    }
> +  else if (frame->next->signal_handler_caller)
> +    {
> +      bsp = read_sigcontext_register (frame->next, IA64_BSP_REGNUM);
> +      cfm = read_sigcontext_register (frame->next, IA64_CFM_REGNUM);
> +    }
> +  else if (next_frame_is_call_dummy)
> +    {
> +      bsp = generic_read_register_dummy (frame->next->pc, frame->next->frame,
> +                                         IA64_BSP_REGNUM);
> +      cfm = generic_read_register_dummy (frame->next->pc, frame->next->frame,
> +                                         IA64_CFM_REGNUM);
> +    }
> +  else
> +    {
> +      struct frame_info *frn = frame->next;
> +
> +      FRAME_INIT_SAVED_REGS (frn);
> +
> +      if (frn->saved_regs[IA64_CFM_REGNUM] != 0)
> +       cfm = read_memory_integer (frn->saved_regs[IA64_CFM_REGNUM], 8);
> +      else if (frn->next && frn->next->signal_handler_caller)
> +       cfm = read_sigcontext_register (frn->next, IA64_PFS_REGNUM);
> +      else if (frn->next
> +               && PC_IN_CALL_DUMMY (frn->next->pc, frn->next->frame,
> +                                                  frn->next->frame))
> +       cfm = generic_read_register_dummy (frn->next->pc, frn->next->frame,
> +                                          IA64_PFS_REGNUM);
> +      else
> +       cfm = read_register (IA64_PFS_REGNUM);
> +
> +      bsp = frn->extra_info->bsp;
> +    }
> +  frame->extra_info->cfm = cfm;
> +  frame->extra_info->sof = cfm & 0x7f;
> +  frame->extra_info->sol = (cfm >> 7) & 0x7f;
> +  if (frame->next == 0
> +      || frame->next->signal_handler_caller
> +      || next_frame_is_call_dummy)
> +    frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sof);
> +  else
> +    frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sol);
> +
> +  frame->extra_info->after_prologue = 0;
> +  frame->extra_info->mem_stack_frame_size = -1;        /* Not yet determined */
> +  frame->extra_info->fp_reg = 0;
> +}
> +
> +void
> +ia64_pop_frame (void)
> +{
> +  generic_pop_current_frame (ia64_pop_frame_regular);
> +}
> +
> +static void
> +ia64_pop_frame_regular (struct frame_info *frame)
> +{
> +  int regno;
> +  CORE_ADDR bsp, cfm, pfs;
> +
> +  FRAME_INIT_SAVED_REGS (frame);
> +
> +  for (regno = 0; regno < ia64_num_regs; regno++)
> +    {
> +      if (frame->saved_regs[regno]
> +         && (!(IA64_GR32_REGNUM <= regno && regno <= IA64_GR127_REGNUM))
> +         && regno != pc_regnum
> +         && regno != sp_regnum
> +         && regno != IA64_PFS_REGNUM
> +         && regno != IA64_CFM_REGNUM
> +         && regno != IA64_BSP_REGNUM
> +         && regno != IA64_BSPSTORE_REGNUM)
> +       {
> +         write_register (regno,
> +                         read_memory_integer (frame->saved_regs[regno],
> +                                              REGISTER_RAW_SIZE (regno)));
> +       }
> +    }
> +
> +  write_register (sp_regnum, FRAME_CHAIN (frame));
> +  write_pc (FRAME_SAVED_PC (frame));
> +
> +  cfm = read_register (IA64_CFM_REGNUM);
> +
> +  if (frame->saved_regs[IA64_PFS_REGNUM])
>      {
> -      int natval = 0;
> -      /* Find address of general register corresponding to nat bit we're
> -         interested in. */
> -      CORE_ADDR gr_addr = 0;
> +      pfs = read_memory_integer (frame->saved_regs[IA64_PFS_REGNUM],
> +                                REGISTER_RAW_SIZE (IA64_PFS_REGNUM));
> +    }
> +  else
> +    pfs = read_register (IA64_PFS_REGNUM);
> 
> -      if (!is_dummy_frame)
> -       {
> -         FRAME_INIT_SAVED_REGS (frame);
> -         gr_addr = frame->saved_regs[ regnum - IA64_NAT0_REGNUM
> -                                             + IA64_GR0_REGNUM];
> -       }
> -      if (gr_addr)
> -       {
> -         /* Compute address of nat collection bits */
> -         CORE_ADDR nat_addr = gr_addr | 0x1f8;
> -         CORE_ADDR bsp = read_register (IA64_BSP_REGNUM);
> -         CORE_ADDR nat_collection;
> -         int nat_bit;
> -         /* If our nat collection address is bigger than bsp, we have to get
> -            the nat collection from rnat.  Otherwise, we fetch the nat
> -            collection from the computed address. */
> -         if (nat_addr >= bsp)
> -           nat_collection = read_register (IA64_RNAT_REGNUM);
> -         else
> -           nat_collection = read_memory_integer (nat_addr, 8);
> -         nat_bit = (gr_addr >> 3) & 0x3f;
> -         natval = (nat_collection >> nat_bit) & 1;
> -       }
> -      store_unsigned_integer (raw_buffer, REGISTER_RAW_SIZE (regnum), natval);
> +  /* Compute the new bsp by *adding* the difference between the
> +     size of the frame and the size of the locals (both wrt the
> +     frame that we're going back to).  This seems kind of strange,
> +     especially since it seems like we ought to be subtracting the
> +     size of the locals... and we should; but the Linux kernel
> +     wants bsp to be set at the end of all used registers.  It's
> +     likely that this code will need to be revised to accomodate
> +     other operating systems. */
> +  bsp = rse_address_add (frame->extra_info->bsp,
> +                         (pfs & 0x7f) - ((pfs >> 7) & 0x7f));
> +  write_register (IA64_BSP_REGNUM, bsp);
> +
> +  /* FIXME: What becomes of the epilog count in the PFS? */
> +  cfm = (cfm & ~0xffffffffffffLL) | (pfs & 0xffffffffffffLL);
> +  write_register (IA64_CFM_REGNUM, cfm);
> +
> +  flush_cached_frames ();
> +}
> +
> +static int
> +ia64_frame_unchanged (struct frame_info *prev, struct frame_info *next)
> +{
> +  return (prev->frame == next->frame && prev->pc == next->pc
> +         && prev->extra_info->bsp == next->extra_info->bsp);
> +}
> +
> +#endif /* !HAVE_LIBUNWIND_IA64_H */
> +
> +static const char *
> +ia64_register_name (int reg)
> +{
> +  return ia64_register_names[reg];
> +}
> +
> +int
> +ia64_register_raw_size (int reg)
> +{
> +  return (IA64_FR0_REGNUM <= reg && reg <= IA64_FR127_REGNUM) ? 16 : 8;
> +}
> +
> +int
> +ia64_register_virtual_size (int reg)
> +{
> +  return (IA64_FR0_REGNUM <= reg && reg <= IA64_FR127_REGNUM) ? 16 : 8;
> +}
> +
> +/* Return true iff register N's virtual format is different from
> +   its raw format. */
> +int
> +ia64_register_convertible (int nr)
> +{
> +  return (IA64_FR0_REGNUM <= nr && nr <= IA64_FR127_REGNUM);
> +}
> +
> +const struct floatformat floatformat_ia64_ext =
> +{
> +  floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
> +  floatformat_intbit_yes
> +};
> +
> +void
> +ia64_register_convert_to_virtual (int regnum, struct type *type,
> +                                  char *from, char *to)
> +{
> +  if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR127_REGNUM)
> +    {
> +      DOUBLEST val;
> +      floatformat_to_doublest (&floatformat_ia64_ext, from, &val);
> +      store_floating(to, TYPE_LENGTH(type), val);
>      }
> -  else if (regnum == IA64_IP_REGNUM)
> +  else
> +    error("ia64_register_convert_to_virtual called with non floating point register number");
> +}
> +
> +void
> +ia64_register_convert_to_raw (struct type *type, int regnum,
> +                              char *from, char *to)
> +{
> +  if (regnum >= IA64_FR0_REGNUM && regnum <= IA64_FR127_REGNUM)
>      {
> -      CORE_ADDR pc;
> -      if (frame->next)
> -        {
> -         /* FIXME: Set *addrp, *lval when possible. */
> -         pc = ia64_frame_saved_pc (frame->next);
> -        }
> -      else
> -        {
> -         pc = read_pc ();
> -       }
> -      store_address (raw_buffer, REGISTER_RAW_SIZE (IA64_IP_REGNUM), pc);
> +      DOUBLEST val = extract_floating (from, TYPE_LENGTH(type));
> +      floatformat_from_doublest (&floatformat_ia64_ext, &val, to);
>      }
> -  else if (IA64_GR32_REGNUM <= regnum && regnum <= IA64_GR127_REGNUM)
> +  else
> +    error("ia64_register_convert_to_raw called with non floating point register number");
> +}
> +
> +struct type *
> +ia64_register_virtual_type (int reg)
> +{
> +  if (reg >= IA64_FR0_REGNUM && reg <= IA64_FR127_REGNUM)
> +    return builtin_type_long_double;
> +  else
> +    return builtin_type_long;
> +}
> +
> +int
> +ia64_register_byte (int reg)
> +{
> +  return (8 * reg) +
> +   (reg <= IA64_FR0_REGNUM ? 0 : 8 * ((reg > IA64_FR127_REGNUM) ? 128 : reg - IA64_FR0_REGNUM));
> +}
> +
> +/* Replace the specified bits in an instruction bundle */
> +
> +static void
> +replace_bit_field (char *bundle, long long val, int from, int len)
> +{
> +  int to = from + len;
> +  int from_byte = from / 8;
> +  int to_byte = to / 8;
> +  unsigned char *b = (unsigned char *) bundle;
> +  unsigned char c;
> +
> +  if (from_byte == to_byte)
>      {
> -      CORE_ADDR addr = 0;
> -      if (!is_dummy_frame)
> +      unsigned char left, right;
> +      c = b[from_byte];
> +      left = (c >> (to % 8)) << (to % 8);
> +      right = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
> +      c = (unsigned char) (val & 0xff);
> +      c = (unsigned char) (c << (from % 8 + 8 - to % 8)) >> (8 - to % 8);
> +      c |= right | left;
> +      b[from_byte] = c;
> +    }
> +  else
> +    {
> +      int i;
> +      c = b[from_byte];
> +      c = ((unsigned char) (c << (8 - from % 8))) >> (8 - from % 8);
> +      c = c | (val << (from % 8));
> +      b[from_byte] = c;
> +      val >>= 8 - from % 8;
> +
> +      for (i = from_byte+1; i < to_byte; i++)
>         {
> -         FRAME_INIT_SAVED_REGS (frame);
> -         addr = frame->saved_regs[regnum];
> +         c = val & 0xff;
> +         val >>= 8;
> +         b[i] = c;
> +       }
> +
> +      if (to % 8 != 0)
> +       {
> +         unsigned char cv = (unsigned char) val;
> +         c = b[to_byte];
> +         c = c >> (to % 8) << (to % 8);
> +         c |= ((unsigned char) (cv << (8 - to % 8))) >> (8 - to % 8);
> +         b[to_byte] = c;
>         }
> +    }
> +}
> +
> +/* Store an instruction in an instruction bundle */
> +
> +static void
> +replace_slotN_contents (char *bundle, long long instr, int slotnum)
> +{
> +  replace_bit_field (bundle, instr, 5+41*slotnum, 41);
> +}
> +
> +/* There are 5 different break instructions (break.i, break.b,
> +   break.m, break.f, and break.x), but they all have the same
> +   encoding.  (The five bit template in the low five bits of the
> +   instruction bundle distinguishes one from another.)
> +
> +   The runtime architecture manual specifies that break instructions
> +   used for debugging purposes must have the upper two bits of the 21
> +   bit immediate set to a 0 and a 1 respectively.  A breakpoint
> +   instruction encodes the most significant bit of its 21 bit
> +   immediate at bit 36 of the 41 bit instruction.  The penultimate msb
> +   is at bit 25 which leads to the pattern below.
> +
> +   Originally, I had this set up to do, e.g, a "break.i 0x80000"  But
> +   it turns out that 0x80000 was used as the syscall break in the early
> +   simulators.  So I changed the pattern slightly to do "break.i 0x080001"
> +   instead.  But that didn't work either (I later found out that this
> +   pattern was used by the simulator that I was using.)  So I ended up
> +   using the pattern seen below. */
> +
> +#if 0
> +#define BREAKPOINT 0x00002000040LL
> +#endif
> +#define BREAKPOINT 0x00003333300LL
> +
> +static int
> +ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
> +{
> +  char bundle[BUNDLE_LEN];
> +  int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
> +  long long instr;
> +  int val;
> +
> +  if (slotnum > 2)
> +    error("Can't insert breakpoint for slot numbers greater than 2.");
> +
> +  addr &= ~0x0f;
> +
> +  val = target_read_memory (addr, bundle, BUNDLE_LEN);
> +  instr = slotN_contents (bundle, slotnum);
> +  memcpy(contents_cache, &instr, sizeof(instr));
> +  replace_slotN_contents (bundle, BREAKPOINT, slotnum);
> +  if (val == 0)
> +    target_write_memory (addr, bundle, BUNDLE_LEN);
> +
> +  return val;
> +}
> +
> +static int
> +ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
> +{
> +  char bundle[BUNDLE_LEN];
> +  int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
> +  long long instr;
> +  int val;
> +  int template;
> 
> -      if (addr != 0)
> -       {
> -         if (lval != NULL)
> -           *lval = lval_memory;
> -         if (addrp != NULL)
> -           *addrp = addr;
> -         read_memory (addr, raw_buffer, REGISTER_RAW_SIZE (regnum));
> -       }
> -      else
> -        {
> -         /* r32 - r127 must be fetchable via memory.  If they aren't,
> -            then the register is unavailable */
> -         memset (raw_buffer, 0, REGISTER_RAW_SIZE (regnum));
> -        }
> -    }
> -  else
> -    {
> -      if (IA64_FR32_REGNUM <= regnum && regnum <= IA64_FR127_REGNUM)
> -       {
> -         /* Fetch floating point register rename base from current
> -            frame marker for this frame. */
> -         int rrb_fr = (frame->extra_info->cfm >> 25) & 0x7f;
> +  addr &= ~0x0f;
> 
> -         /* Adjust the floating point register number to account for
> -            register rotation. */
> -         regnum = IA64_FR32_REGNUM
> -                + ((regnum - IA64_FR32_REGNUM) + rrb_fr) % 96;
> -       }
> +  val = target_read_memory (addr, bundle, BUNDLE_LEN);
> 
> -      generic_get_saved_register (raw_buffer, optimized, addrp, frame,
> -                                  regnum, lval);
> +  /* Check for L type instruction in 2nd slot, if present then
> +     bump up the slot number to the 3rd slot */
> +  template = extract_bit_field (bundle, 0, 5);
> +  if (slotnum == 1 && template_encoding_table[template][1] == L)
> +    {
> +      slotnum = 2;
>      }
> +
> +  memcpy (&instr, contents_cache, sizeof instr);
> +  replace_slotN_contents (bundle, instr, slotnum);
> +  if (val == 0)
> +    target_write_memory (addr, bundle, BUNDLE_LEN);
> +
> +  memcpy (&instr, contents_cache, sizeof instr);
> +  replace_slotN_contents (bundle, instr, slotnum);
> +  if (val == 0)
> +    target_write_memory (addr, bundle, BUNDLE_LEN);
> +
> +  return val;
> +}
> +
> +/* We don't really want to use this, but remote.c needs to call it in order
> +   to figure out if Z-packets are supported or not.  Oh, well. */
> +const unsigned char *
> +ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
> +{
> +  static unsigned char breakpoint[] =
> +    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
> +  *lenptr = sizeof (breakpoint);
> +#if 0
> +  *pcptr &= ~0x0f;
> +#endif
> +  return breakpoint;
> +}
> +
> +#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
> +
> +/* Returns the address of the slot that's NSLOTS slots away from
> +   the address ADDR. NSLOTS may be positive or negative. */
> +static CORE_ADDR
> +rse_address_add (CORE_ADDR addr, int nslots)
> +{
> +  CORE_ADDR new_addr;
> +  int mandatory_nat_slots = nslots / 63;
> +  int direction = nslots < 0 ? -1 : 1;
> +
> +  new_addr = addr + 8 * (nslots + mandatory_nat_slots);
> +
> +  if ((new_addr >> 9)  != ((addr + 8 * 64 * mandatory_nat_slots) >> 9))
> +    new_addr += 8 * direction;
> +
> +  if (IS_NaT_COLLECTION_ADDR(new_addr))
> +    new_addr += 8 * direction;
> +
> +  return new_addr;
>  }
> 
>  /* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
> @@ -1448,98 +2354,12 @@
>    struct_return_address = addr;
>  }
> 
> -int
> -ia64_frameless_function_invocation (struct frame_info *frame)
> -{
> -  FRAME_INIT_SAVED_REGS (frame);
> -  return (frame->extra_info->mem_stack_frame_size == 0);
> -}
> -
>  CORE_ADDR
>  ia64_saved_pc_after_call (struct frame_info *frame)
>  {
>    return read_register (IA64_BR0_REGNUM);
>  }
> 
> -CORE_ADDR
> -ia64_frame_args_address (struct frame_info *frame)
> -{
> -  /* frame->frame points at the SP for this frame; But we want the start
> -     of the frame, not the end.  Calling frame chain will get his for us. */
> -  return ia64_frame_chain (frame);
> -}
> -
> -CORE_ADDR
> -ia64_frame_locals_address (struct frame_info *frame)
> -{
> -  /* frame->frame points at the SP for this frame; But we want the start
> -     of the frame, not the end.  Calling frame chain will get his for us. */
> -  return ia64_frame_chain (frame);
> -}
> -
> -void
> -ia64_init_extra_frame_info (int fromleaf, struct frame_info *frame)
> -{
> -  CORE_ADDR bsp, cfm;
> -  int next_frame_is_call_dummy = ((frame->next != NULL)
> -    && PC_IN_CALL_DUMMY (frame->next->pc, frame->next->frame,
> -                                          frame->next->frame));
> -
> -  frame->extra_info = (struct frame_extra_info *)
> -    frame_obstack_alloc (sizeof (struct frame_extra_info));
> -
> -  if (frame->next == 0)
> -    {
> -      bsp = read_register (IA64_BSP_REGNUM);
> -      cfm = read_register (IA64_CFM_REGNUM);
> -
> -    }
> -  else if (frame->next->signal_handler_caller)
> -    {
> -      bsp = read_sigcontext_register (frame->next, IA64_BSP_REGNUM);
> -      cfm = read_sigcontext_register (frame->next, IA64_CFM_REGNUM);
> -    }
> -  else if (next_frame_is_call_dummy)
> -    {
> -      bsp = generic_read_register_dummy (frame->next->pc, frame->next->frame,
> -                                         IA64_BSP_REGNUM);
> -      cfm = generic_read_register_dummy (frame->next->pc, frame->next->frame,
> -                                         IA64_CFM_REGNUM);
> -    }
> -  else
> -    {
> -      struct frame_info *frn = frame->next;
> -
> -      FRAME_INIT_SAVED_REGS (frn);
> -
> -      if (frn->saved_regs[IA64_CFM_REGNUM] != 0)
> -       cfm = read_memory_integer (frn->saved_regs[IA64_CFM_REGNUM], 8);
> -      else if (frn->next && frn->next->signal_handler_caller)
> -       cfm = read_sigcontext_register (frn->next, IA64_PFS_REGNUM);
> -      else if (frn->next
> -               && PC_IN_CALL_DUMMY (frn->next->pc, frn->next->frame,
> -                                                  frn->next->frame))
> -       cfm = generic_read_register_dummy (frn->next->pc, frn->next->frame,
> -                                          IA64_PFS_REGNUM);
> -      else
> -       cfm = read_register (IA64_PFS_REGNUM);
> -
> -      bsp = frn->extra_info->bsp;
> -    }
> -  frame->extra_info->cfm = cfm;
> -  frame->extra_info->sof = cfm & 0x7f;
> -  frame->extra_info->sol = (cfm >> 7) & 0x7f;
> -  if (frame->next == 0
> -      || frame->next->signal_handler_caller
> -      || next_frame_is_call_dummy)
> -    frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sof);
> -  else
> -    frame->extra_info->bsp = rse_address_add (bsp, -frame->extra_info->sol);
> -
> -  frame->extra_info->after_prologue = 0;
> -  frame->extra_info->mem_stack_frame_size = -1;                /* Not yet determined */
> -  frame->extra_info->fp_reg = 0;
> -}
> 
>  static int
>  is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
> @@ -1638,7 +2458,7 @@
>  generic_elf_find_global_pointer (CORE_ADDR faddr)
>  {
>    struct obj_section *faddr_sect;
> -
> +
>    faddr_sect = find_pc_section (faddr);
>    if (faddr_sect != NULL)
>      {
> @@ -1767,7 +2587,7 @@
>        write_memory (fdesc, buf, 16);
>      }
> 
> -  return fdesc;
> +  return fdesc;
>  }
> 
>  CORE_ADDR
> @@ -1820,7 +2640,7 @@
>    cfm &= 0xc000000000000000LL;
>    cfm |= rseslots;
>    write_register (IA64_CFM_REGNUM, cfm);
> -
> +
>    /* We will attempt to find function descriptors in the .opd segment,
>       but if we can't we'll construct them ourselves.  That being the
>       case, we'll need to reserve space on the stack for them. */
> @@ -1848,8 +2668,8 @@
>        len = TYPE_LENGTH (type);
> 
>        /* Special handling for function parameters */
> -      if (len == 8
> -          && TYPE_CODE (type) == TYPE_CODE_PTR
> +      if (len == 8
> +          && TYPE_CODE (type) == TYPE_CODE_PTR
>           && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
>         {
>           char val_buf[8];
> @@ -1920,18 +2740,6 @@
>    /* Sync gdb's idea of what the registers are with the target. */
>    target_store_registers (-1);
> 
> -  /* FIXME: This doesn't belong here!  Instead, SAVE_DUMMY_FRAME_TOS needs
> -     to be defined to call generic_save_dummy_frame_tos().  But at the
> -     time of this writing, SAVE_DUMMY_FRAME_TOS wasn't gdbarch'd, so
> -     I chose to put this call here instead of using the old mechanisms.
> -     Once SAVE_DUMMY_FRAME_TOS is gdbarch'd, all we need to do is add the
> -     line
> -
> -       set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
> -
> -     to ia64_gdbarch_init() and remove the line below. */
> -  generic_save_dummy_frame_tos (sp);
> -
>    return sp;
>  }
> 
> @@ -1961,69 +2769,6 @@
>                           valbuf, TYPE_LENGTH (type));
>  }
> 
> -void
> -ia64_pop_frame (void)
> -{
> -  generic_pop_current_frame (ia64_pop_frame_regular);
> -}
> -
> -static void
> -ia64_pop_frame_regular (struct frame_info *frame)
> -{
> -  int regno;
> -  CORE_ADDR bsp, cfm, pfs;
> -
> -  FRAME_INIT_SAVED_REGS (frame);
> -
> -  for (regno = 0; regno < ia64_num_regs; regno++)
> -    {
> -      if (frame->saved_regs[regno]
> -         && (!(IA64_GR32_REGNUM <= regno && regno <= IA64_GR127_REGNUM))
> -         && regno != pc_regnum
> -         && regno != sp_regnum
> -         && regno != IA64_PFS_REGNUM
> -         && regno != IA64_CFM_REGNUM
> -         && regno != IA64_BSP_REGNUM
> -         && regno != IA64_BSPSTORE_REGNUM)
> -       {
> -         write_register (regno,
> -                         read_memory_integer (frame->saved_regs[regno],
> -                                              REGISTER_RAW_SIZE (regno)));
> -       }
> -    }
> -
> -  write_register (sp_regnum, FRAME_CHAIN (frame));
> -  write_pc (FRAME_SAVED_PC (frame));
> -
> -  cfm = read_register (IA64_CFM_REGNUM);
> -
> -  if (frame->saved_regs[IA64_PFS_REGNUM])
> -    {
> -      pfs = read_memory_integer (frame->saved_regs[IA64_PFS_REGNUM],
> -                                REGISTER_RAW_SIZE (IA64_PFS_REGNUM));
> -    }
> -  else
> -    pfs = read_register (IA64_PFS_REGNUM);
> -
> -  /* Compute the new bsp by *adding* the difference between the
> -     size of the frame and the size of the locals (both wrt the
> -     frame that we're going back to).  This seems kind of strange,
> -     especially since it seems like we ought to be subtracting the
> -     size of the locals... and we should; but the Linux kernel
> -     wants bsp to be set at the end of all used registers.  It's
> -     likely that this code will need to be revised to accomodate
> -     other operating systems. */
> -  bsp = rse_address_add (frame->extra_info->bsp,
> -                         (pfs & 0x7f) - ((pfs >> 7) & 0x7f));
> -  write_register (IA64_BSP_REGNUM, bsp);
> -
> -  /* FIXME: What becomes of the epilog count in the PFS? */
> -  cfm = (cfm & ~0xffffffffffffLL) | (pfs & 0xffffffffffffLL);
> -  write_register (IA64_CFM_REGNUM, cfm);
> -
> -  flush_cached_frames ();
> -}
> -
>  static void
>  ia64_remote_translate_xfer_address (CORE_ADDR memaddr, int nr_bytes,
>                                     CORE_ADDR *targ_addr, int *targ_len)
> @@ -2177,13 +2922,9 @@
>    set_gdbarch_frameless_function_invocation (gdbarch, ia64_frameless_function_invocation);
> 
>    set_gdbarch_saved_pc_after_call (gdbarch, ia64_saved_pc_after_call);
> -
> -  set_gdbarch_frame_chain (gdbarch, ia64_frame_chain);
>    set_gdbarch_frame_chain_valid (gdbarch, generic_func_frame_chain_valid);
> -  set_gdbarch_frame_saved_pc (gdbarch, ia64_frame_saved_pc);
> 
>    set_gdbarch_frame_init_saved_regs (gdbarch, ia64_frame_init_saved_regs);
> -  set_gdbarch_get_saved_register (gdbarch, ia64_get_saved_register);
> 
>    set_gdbarch_register_convertible (gdbarch, ia64_register_convertible);
>    set_gdbarch_register_convert_to_virtual (gdbarch, ia64_register_convert_to_virtual);
> @@ -2207,13 +2948,11 @@
>    set_gdbarch_call_dummy_length (gdbarch, 0);
>    set_gdbarch_push_arguments (gdbarch, ia64_push_arguments);
>    set_gdbarch_push_return_address (gdbarch, ia64_push_return_address);
> -  set_gdbarch_pop_frame (gdbarch, ia64_pop_frame);
> 
>    set_gdbarch_call_dummy_p (gdbarch, 1);
>    set_gdbarch_call_dummy_words (gdbarch, ia64_call_dummy_words);
>    set_gdbarch_sizeof_call_dummy_words (gdbarch, sizeof (ia64_call_dummy_words));
>    set_gdbarch_call_dummy_breakpoint_offset_p (gdbarch, 1);
> -  set_gdbarch_init_extra_frame_info (gdbarch, ia64_init_extra_frame_info);
>    set_gdbarch_frame_args_address (gdbarch, ia64_frame_args_address);
>    set_gdbarch_frame_locals_address (gdbarch, ia64_frame_locals_address);
> 
> @@ -2238,6 +2977,7 @@
>    set_gdbarch_call_dummy_stack_adjust_p (gdbarch, 0);
>    set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame);
>    set_gdbarch_fix_call_dummy (gdbarch, generic_fix_call_dummy);
> +  set_gdbarch_save_dummy_frame_tos (gdbarch, generic_save_dummy_frame_tos);
> 
>    set_gdbarch_decr_pc_after_break (gdbarch, 0);
>    set_gdbarch_function_start_offset (gdbarch, 0);
> @@ -2245,6 +2985,22 @@
> 
>    set_gdbarch_remote_translate_xfer_address (
>      gdbarch, ia64_remote_translate_xfer_address);
> +
> +  set_gdbarch_frame_unchanged (gdbarch, ia64_frame_unchanged);
> +
> +#ifdef HAVE_LIBUNWIND_IA64_H
> +  set_gdbarch_frame_chain (gdbarch, uw_frame_chain);
> +  set_gdbarch_frame_saved_pc (gdbarch, uw_get_ra);
> +  set_gdbarch_get_saved_register (gdbarch, uw_get_saved_register);
> +  set_gdbarch_pop_frame (gdbarch, uw_pop_frame);
> +  set_gdbarch_init_extra_frame_info (gdbarch, uw_init_extra_frame_info);
> +#else
> +  set_gdbarch_frame_chain (gdbarch, ia64_frame_chain);
> +  set_gdbarch_frame_saved_pc (gdbarch, ia64_frame_saved_pc);
> +  set_gdbarch_get_saved_register (gdbarch, ia64_get_saved_register);
> +  set_gdbarch_pop_frame (gdbarch, ia64_pop_frame);
> +  set_gdbarch_init_extra_frame_info (gdbarch, ia64_init_extra_frame_info);
> +#endif
> 
>    return gdbarch;
>  }
> 
> --- /dev/null   Sat Mar 24 01:35:12 2001
> +++ unwind-common.h     Wed May  8 16:29:57 2002
> @@ -0,0 +1,367 @@
> +/* Common code for libunwind-based unwinding.
> +
> +   Copyright 2002 Free Software Foundation, Inc.
> +       Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
> +
> +   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 2 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, write to the Free Software
> +   Foundation, Inc., 59 Temple Place - Suite 330,
> +   Boston, MA 02111-1307, USA.  */
> +
> +/* Before this file is included, the libunwind header file for the
> +   desired target needs to be included (e.g., <libunwind-ia64.h>) and
> +   the following routines need to be defined (see ia64-tdep.c for
> +   sample implementation):
> +
> +     static int uw2gdb_regnum(r)
> +       Convert unwind register number to corresponding GDB register number.
> +
> +     static int access_reg (r, valp, write, arg)
> +       Read or write register number R.
> +
> +     static int access_fpreg (r, valp, write, arg)
> +       Read or write floating-point register number R.
> +
> +     static int acquire_unwind_info (ip, info, arg)
> +       Acquire unwind info for module containing IP (aka "pc").
> +
> +     static int release_unwind_info (info, arg)
> +       Release unwind info.
> +
> +   This file defines the following entry-points:
> +
> +     uw_pop_frame ()
> +     uw_frame_chain ()
> +     uw_get_ra ()
> +     uw_init_extra_frame_info ()
> +     uw_get_saved_register ()
> +*/
> +
> +#define UW_CURSOR(fi)  ((unw_cursor_t *) ((fi)->context))
> +
> +static int
> +access_mem (unw_word_t addr, unw_word_t *val, int write, void *arg)
> +{
> +  /* XXX do we need to normalize byte-order here?  */
> +  if (write)
> +    return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
> +  else
> +    return target_read_memory (addr, (char *) val, sizeof (unw_word_t));
> +}
> +
> +static unw_accessors_t accessors =
> +{
> +  acquire_unwind_info,
> +  release_unwind_info,
> +  access_mem,
> +  access_reg,
> +  access_fpreg,
> +  /* resume */
> +  /* arg */
> +};
> +
> +static int
> +get_reg (unw_cursor_t *c, int regnum, char *regbuf)
> +{
> +  unw_regnum_t uw_regnum = gdb2uw_regnum (regnum);
> +  unw_word_t intval;
> +  unw_fpreg_t fpval;
> +  void *buf;
> +  int ret;
> +
> +  /* XXX check byte-order */
> +  if (unw_is_fpreg (uw_regnum))
> +    {
> +      ret = unw_get_fpreg (c, uw_regnum, &fpval);
> +      buf = &fpval;
> +    }
> +  else
> +    {
> +      ret = unw_get_reg (c, uw_regnum, &intval);
> +      buf = &intval;
> +    }
> +
> +  if (ret < 0)
> +    {
> +      memset (regbuf, 0, REGISTER_RAW_SIZE (regnum));
> +      return ret;
> +    }
> +
> +  /* regbuf may not be properly aligned: */
> +  memcpy (regbuf, buf, REGISTER_RAW_SIZE (regnum));
> +  return 0;
> +}
> +
> +static void
> +pop_frame_regular (struct frame_info *frame)
> +{
> +  unw_regnum_t uw_regnum;
> +  unw_cursor_t *c;
> +  unw_fpreg_t fpvals[UNW_REG_LAST];
> +  unw_word_t intvals[UNW_REG_LAST];
> +
> +  /* Pop the frame by restoring the state of the previous frame.  */
> +
> +  frame = get_prev_frame (frame);
> +  if (!frame)
> +    return;
> +
> +  c = UW_CURSOR (frame);
> +
> +  /* read current register values: */
> +  for (uw_regnum = 0; uw_regnum <= UNW_REG_LAST; ++uw_regnum)
> +    {
> +      if (unw_is_fpreg (uw_regnum))
> +       unw_get_fpreg (c, uw_regnum, &fpvals[uw_regnum]);
> +      else
> +       unw_get_reg (c, uw_regnum, &intvals[uw_regnum]);
> +    }
> +
> +  /* now establish the read values as the current register contents: */
> +  for (uw_regnum = 0; uw_regnum <= UNW_REG_LAST; ++uw_regnum)
> +    {
> +      if (unw_is_fpreg (uw_regnum))
> +       access_fpreg (uw_regnum, &fpvals[uw_regnum], 1, NULL);
> +      else
> +       access_reg (uw_regnum, &intvals[uw_regnum], 1, NULL);
> +    }
> +  flush_cached_frames ();
> +}
> +
> +
> +static void
> +uw_pop_frame (void)
> +{
> +  generic_pop_current_frame (pop_frame_regular);
> +}
> +
> +/* Determine the address of the calling function's frame.  */
> +static CORE_ADDR
> +uw_frame_chain (struct frame_info *fi)
> +{
> +  unw_cursor_t c = *UW_CURSOR (fi);
> +  unw_word_t sp;
> +  int ret;
> +
> +  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
> +    {
> +      sp = generic_dummy_frame_chain (fi->pc, fi->frame);
> +      if (gdbarch_debug >= 1)
> +       fprintf_unfiltered (gdb_stdlog, "uw_frame_chain: next frame at %lx "
> +                           "(from dummy call)\n", (unsigned long) sp);
> +      return sp;
> +    }
> +
> +  /* The gdb interface is rather stupid: it requires us to determine
> +     the caller's frame address without giving us a chance to stash
> +     away the caller's frame info at the same time.  This means we
> +     have to do extraneous copying and unw_step() calls to move by one
> +     step in the call chain.  Hopefully, the interface can be fixed
> +     some day.  */
> +  ret = unw_step (&c);
> +  if (ret <= 0)
> +    return 0;  /* outermost frame or some error occurred */
> +
> +  ret = unw_get_reg (&c, UNW_REG_SP, &sp);
> +  if (ret < 0)
> +    return 0;
> +
> +  if (gdbarch_debug >= 1)
> +    {
> +      unw_word_t pc;
> +      if (unw_get_reg (&c, UNW_REG_IP, &pc) < 0)
> +       pc = 0;
> +      fprintf_unfiltered (gdb_stdlog, "uw_frame_chain: next frame at %lx "
> +                         "(from regular)\n", (unsigned long) sp);
> +    }
> +  return sp;
> +}
> +
> +/* Determine the return-address of the current frame.  */
> +static CORE_ADDR
> +uw_get_ra (struct frame_info *fi)
> +{
> +  unw_word_t ip;
> +  int ret;
> +
> +  /* Normally, we get here with fi->prev already set up.  */
> +  if (fi->prev)
> +    {
> +      unw_cursor_t *c = UW_CURSOR (fi->prev);
> +
> +      ret = unw_get_reg (c, UNW_REG_IP, &ip);
> +      if (ret < 0)
> +       return 0;
> +      if (gdbarch_debug >= 1)
> +       fprintf_unfiltered (gdb_stdlog, "uw_get_ra: pc=%lx, frame=%lx -> "
> +                           "ra=%lx (from previous)\n",
> +                           (unsigned long) fi->pc, (unsigned long) fi->frame,
> +                           (unsigned long) ip);
> +    }
> +  else
> +    {
> +      /* We can get here, e.g., when the user types "info frame" while
> +        inside the frame of the main program.  gdb normally does not
> +        display the call chain beyond main() but when this command is
> +        typed, it will still ask for the return address.  */
> +      unw_cursor_t c = *UW_CURSOR (fi);
> +
> +      ret = unw_step (&c);
> +      if (ret <= 0)
> +       return 0;       /* outermost frame or some error occurred */
> +
> +      ret = unw_get_reg (&c, UNW_REG_IP, &ip);
> +      if (ret < 0)
> +       return 0;
> +      if (gdbarch_debug >= 1)
> +       fprintf_unfiltered (gdb_stdlog, "uw_get_ra: pc=%lx, frame=%lx -> "
> +                           "ra=%lx (from unwind)\n", (unsigned long) fi->pc,
> +                           (unsigned long) fi->frame, (unsigned long) ip);
> +    }
> +  return ip;
> +}
> +
> +/* Initialize unwind context informations of the frame.  */
> +static void
> +uw_init_extra_frame_info (int fromleaf, struct frame_info *fi)
> +{
> +  unw_cursor_t *c;
> +  int ret;
> +
> +  c = UW_CURSOR (fi) = frame_obstack_alloc (sizeof (unw_cursor_t));
> +
> +  if (fi->next)
> +    {
> +      if (PC_IN_CALL_DUMMY (fi->next->pc, fi->next->frame, fi->next->frame))
> +       {
> +         unw_accessors_t acc = accessors;
> +
> +         acc.arg = fi->next;
> +         ret = unw_init_remote (c, &acc);
> +       }
> +      else
> +       {
> +         /* Initialize current frame based on return address/stack
> +            pointer of next frame.  */
> +         *c = *UW_CURSOR (fi->next);
> +
> +         ret = unw_step (c);
> +       }
> +      if (ret < 0)
> +       return;
> +
> +      if (gdbarch_debug >= 1)
> +       {
> +         unw_word_t pc, sp;
> +         if (unw_get_reg (c, UNW_REG_IP, &pc) < 0)
> +           pc = 0;
> +         if (unw_get_reg (c, UNW_REG_SP, &sp) < 0)
> +           sp = 0;
> +         fprintf_unfiltered (gdb_stdlog, "uw_init_extra_frame_info: "
> +                             "pc=%lx, sp=%lx (from unwind)\n",
> +                             (unsigned long) pc, (unsigned long) sp);
> +       }
> +    }
> +  else
> +    {
> +      unw_accessors_t acc = accessors;
> +
> +      /* Initialize current frame based on the pc (IP) that has been
> +        set up by create_new_frame ().  In this case, the frame
> +        address is stored in fi->frame (normally obtained via
> +        TARGET_READ_FP()) and the IP is stored in fi->pc (normally
> +        obtained via TARGET_READ_PC()).  These values normally
> +        correspond to the current stack pointer and current IP
> +        values.  However, a gdb user can explicitly specify arbitrary
> +        other values.  User-specified frame/pc addresses may not work
> +        reliably, because restoring the frame state generally may
> +        require knowing the contents of other (saved) registers.  In
> +        other words, user-specific frame/pc addresses are probably a
> +        gdb misfeature.  */
> +      acc.arg = fi;
> +      if (unw_init_remote (c, &acc) < 0)
> +       return;
> +      if (gdbarch_debug >= 1)
> +       {
> +         unw_word_t pc, sp;
> +         if (unw_get_reg (c, UNW_REG_IP, &pc) < 0)
> +           pc = 0;
> +         if (unw_get_reg (c, UNW_REG_SP, &sp) < 0)
> +           sp = 0;
> +         fprintf_unfiltered (gdb_stdlog, "uw_init_extra_frame_info: "
> +                             "pc=%lx, sp=%lx (from init)\n",
> +                             (unsigned long) pc, (unsigned long) sp);
> +       }
> +    }
> +
> +  /* A bit rude, but IN_SIGTRAMP() doesn't get the right arguments.  */
> +  fi->signal_handler_caller = unw_is_signal_frame (c);
> +}
> +
> +
> +/* Find register number REGNUM relative to FRAME and put its
> +   (raw) contents in *RAW_BUFFER.  Set *OPTIMIZED if the variable
> +   was optimized out (and thus can't be fetched).  If the variable
> +   was fetched from memory, set *ADDRP to where it was fetched from,
> +   otherwise it was fetched from a register.
> +
> +   The argument RAW_BUFFER must point to aligned memory.  */
> +static void
> +uw_get_saved_register (char *raw_buffer, int *optimized, CORE_ADDR *addrp,
> +                      struct frame_info *fi, int regnum,
> +                      enum lval_type *lval)
> +{
> +  unw_cursor_t *c;
> +  unw_save_loc_t sl;
> +
> +  if (!target_has_registers)
> +    error ("No registers.");
> +
> +  c = UW_CURSOR (fi);
> +
> +  if (optimized != NULL)
> +    *optimized = 0;
> +
> +  if (addrp != NULL)
> +    *addrp = 0;
> +
> +  if (lval != NULL)
> +    *lval = not_lval;
> +
> +  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
> +    return;
> +
> +  if (get_reg (c, regnum, raw_buffer) < 0)
> +    return;
> +
> +  if (unw_get_save_loc (c, regnum, &sl) < 0)
> +    return;
> +
> +  switch (sl.type)
> +    {
> +    case UNW_SLT_NONE:
> +      if (optimized != NULL)
> +       *optimized = 1;
> +      break;
> +
> +    case UNW_SLT_MEMORY:
> +      if (addrp != NULL)
> +       *addrp = sl.u.addr;
> +      break;
> +
> +    case UNW_SLT_REG:
> +      break;
> +    }
> +}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]