From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1509 invoked by alias); 27 Aug 2002 02:24:49 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 1502 invoked from network); 27 Aug 2002 02:24:48 -0000 Received: from unknown (HELO cygnus.com) (205.180.83.203) by sources.redhat.com with SMTP; 27 Aug 2002 02:24:48 -0000 Received: from redhat.com (reddwarf.sfbay.redhat.com [172.16.24.50]) by runyon.cygnus.com (8.8.7-cygnus/8.8.7) with ESMTP id TAA10742; Mon, 26 Aug 2002 19:17:51 -0700 (PDT) Message-ID: <3D6AE2ED.53D9E877@redhat.com> Date: Mon, 26 Aug 2002 20:12:00 -0000 From: Michael Snyder Organization: Red Hat, Inc. X-Accept-Language: en MIME-Version: 1.0 To: davidm@hpl.hp.com CC: gdb-patches@sources.redhat.com, ac131313@ges.redhat.com, kevinb@redhat.com Subject: Re: [patch] unwind support for gdb/ia64 References: <200207102315.g6ANFMHh022230@napali.hpl.hp.com> Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-SW-Source: 2002-08/txt/msg00889.txt.bz2 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 > > * 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 > > * 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 has pr_siginfo64_t. */ > #undef HAVE_PR_SIGINFO64_T > > +/* Define if 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 > +#include > +#include > > - val = target_read_memory (addr, bundle, BUNDLE_LEN); > +#include > > - /* 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 > +#include > > -/* 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 = ""; > + 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 > + > + 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., ) 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; > + } > +}