This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [patch] unwind support for gdb/ia64
- From: Michael Snyder <msnyder at redhat dot com>
- To: davidm at hpl dot hp dot com
- Cc: gdb-patches at sources dot redhat dot com, ac131313 at ges dot redhat dot com, kevinb at redhat dot com
- Date: Mon, 26 Aug 2002 19:24:45 -0700
- Subject: Re: [patch] unwind support for gdb/ia64
- Organization: Red Hat, Inc.
- References: <200207102315.g6ANFMHh022230@napali.hpl.hp.com>
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;
> + }
> +}