X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fia64-tdep.c;h=1d1fd2e5f0ee479edfccd2da05442e06d43a03a5;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=d31b05bf06d82e6edb0ca65bbfaef825f0411bef;hpb=6503b91ee3225a4b976d419bf27fe56fb5668d22;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c index d31b05bf06..1d1fd2e5f0 100644 --- a/gdb/ia64-tdep.c +++ b/gdb/ia64-tdep.c @@ -1,12 +1,12 @@ /* Target-dependent code for the IA-64 for GDB, the GNU debugger. - Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1999-2020 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,45 +15,63 @@ 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. */ + along with this program. If not, see . */ #include "defs.h" #include "inferior.h" -#include "symfile.h" /* for entry_point_address */ #include "gdbcore.h" #include "arch-utils.h" #include "floatformat.h" +#include "gdbtypes.h" #include "regcache.h" #include "reggroups.h" #include "frame.h" #include "frame-base.h" #include "frame-unwind.h" -#include "doublest.h" +#include "target-float.h" #include "value.h" -#include "gdb_assert.h" #include "objfiles.h" #include "elf/common.h" /* for DT_PLTGOT value */ #include "elf-bfd.h" -#include "elf.h" /* for PT_IA64_UNWIND value */ #include "dis-asm.h" +#include "infcall.h" +#include "osabi.h" +#include "ia64-tdep.h" +#include "cp-abi.h" #ifdef HAVE_LIBUNWIND_IA64_H -#include "libunwind-frame.h" -#include "libunwind-ia64.h" -#endif +#include "elf/ia64.h" /* for PT_IA_64_UNWIND value */ +#include "ia64-libunwind-tdep.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. */ +/* Note: KERNEL_START is supposed to be an address which is not going + to ever contain any valid unwind info. For ia64 linux, the choice + of 0xc000000000000000 is fairly safe since that's uncached space. + + We use KERNEL_START as follows: after obtaining the kernel's + unwind table via getunwind(), we project its unwind data into + address-range KERNEL_START-(KERNEL_START+ktab_size) and then + when ia64_access_mem() sees a memory access to this + address-range, we redirect it to ktab instead. + + None of this hackery is needed with a modern kernel/libcs + which uses the kernel virtual DSO to provide access to the + kernel's unwind info. In that case, ktab_size remains 0 and + hence the value of KERNEL_START doesn't matter. */ + +#define KERNEL_START 0xc000000000000000ULL + +static size_t ktab_size = 0; +struct ia64_table_entry + { + uint64_t start_offset; + uint64_t end_offset; + uint64_t info_offset; + }; + +static struct ia64_table_entry *ktab = NULL; +static gdb::optional ktab_buf; -CORE_ADDR (*native_find_global_pointer) (CORE_ADDR) = 0; +#endif /* An enumeration of the different IA-64 instruction types. */ @@ -82,18 +100,19 @@ typedef enum instruction_type is set to six (which is how it was set up initially). -- objdump displays pretty disassembly dumps with this value. For our purposes, we'll set bytes_per_line to SLOT_MULTIPLIER. This is okay since we - never want to also display the raw bytes the way objdump does. */ + never want to also display the raw bytes the way objdump does. */ #define SLOT_MULTIPLIER 1 -/* Length in bytes of an instruction bundle */ +/* Length in bytes of an instruction bundle. */ #define BUNDLE_LEN 16 -/* FIXME: These extern declarations should go in ia64-tdep.h. */ -extern CORE_ADDR ia64_linux_sigcontext_register_address (CORE_ADDR, int); -extern CORE_ADDR ia64_aix_sigcontext_register_address (CORE_ADDR, int); -extern unsigned long ia64_linux_getunwind_table (void *, size_t); +/* See the saved memory layout comment for ia64_memory_insert_breakpoint. */ + +#if BREAKPOINT_MAX < BUNDLE_LEN - 2 +# error "BREAKPOINT_MAX < BUNDLE_LEN - 2" +#endif static gdbarch_init_ftype ia64_gdbarch_init; @@ -101,29 +120,31 @@ static gdbarch_register_name_ftype ia64_register_name; static gdbarch_register_type_ftype ia64_register_type; static gdbarch_breakpoint_from_pc_ftype ia64_breakpoint_from_pc; static gdbarch_skip_prologue_ftype ia64_skip_prologue; -static gdbarch_extract_return_value_ftype ia64_extract_return_value; -static gdbarch_extract_struct_value_address_ftype ia64_extract_struct_value_address; -static gdbarch_use_struct_convention_ftype ia64_use_struct_convention; static struct type *is_float_or_hfa_type (struct type *t); - -static struct type *builtin_type_ia64_ext; +static CORE_ADDR ia64_find_global_pointer (struct gdbarch *gdbarch, + CORE_ADDR faddr); #define NUM_IA64_RAW_REGS 462 +/* Big enough to hold a FP register in bytes. */ +#define IA64_FP_REGISTER_SIZE 16 + static int sp_regnum = IA64_GR12_REGNUM; -static int fp_regnum = IA64_VFP_REGNUM; -static int lr_regnum = IA64_VRAP_REGNUM; -/* NOTE: we treat the register stack registers r32-r127 as pseudo-registers because - they may not be accessible via the ptrace register get/set interfaces. */ -enum pseudo_regs { FIRST_PSEUDO_REGNUM = NUM_IA64_RAW_REGS, VBOF_REGNUM = IA64_NAT127_REGNUM + 1, V32_REGNUM, +/* NOTE: we treat the register stack registers r32-r127 as + pseudo-registers because they may not be accessible via the ptrace + register get/set interfaces. */ + +enum pseudo_regs { FIRST_PSEUDO_REGNUM = NUM_IA64_RAW_REGS, + VBOF_REGNUM = IA64_NAT127_REGNUM + 1, V32_REGNUM, V127_REGNUM = V32_REGNUM + 95, - VP0_REGNUM, VP16_REGNUM = VP0_REGNUM + 16, VP63_REGNUM = VP0_REGNUM + 63, LAST_PSEUDO_REGNUM }; + VP0_REGNUM, VP16_REGNUM = VP0_REGNUM + 16, + VP63_REGNUM = VP0_REGNUM + 63, LAST_PSEUDO_REGNUM }; /* Array of register names; There should be ia64_num_regs strings in the initializer. */ -static char *ia64_register_names[] = +static const 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", @@ -241,41 +262,65 @@ struct ia64_frame_cache CORE_ADDR cfm; /* cfm value for current frame */ CORE_ADDR prev_cfm; /* cfm value for previous frame */ int frameless; - int sof; /* Size of frame (decoded from cfm value) */ - int sol; /* Size of locals (decoded from cfm value) */ - int sor; /* Number of rotating registers. (decoded from cfm value) */ + int sof; /* Size of frame (decoded from cfm value). */ + int sol; /* Size of locals (decoded from cfm value). */ + int sor; /* Number of rotating registers (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. */ + 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. */ + 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. */ + as the frame pointer. */ /* Saved registers. */ CORE_ADDR saved_regs[NUM_IA64_RAW_REGS]; }; -struct gdbarch_tdep - { - CORE_ADDR (*sigcontext_register_address) (CORE_ADDR, int); - /* OS specific function which, given a frame address - and register number, returns the offset to the - given register from the start of the frame. */ - CORE_ADDR (*find_global_pointer) (CORE_ADDR); - }; +static int +floatformat_valid (const struct floatformat *fmt, const void *from) +{ + return 1; +} + +static const struct floatformat floatformat_ia64_ext_little = +{ + floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64, + floatformat_intbit_yes, "floatformat_ia64_ext_little", floatformat_valid, NULL +}; + +static const struct floatformat floatformat_ia64_ext_big = +{ + floatformat_big, 82, 46, 47, 17, 65535, 0x1ffff, 64, 64, + floatformat_intbit_yes, "floatformat_ia64_ext_big", floatformat_valid +}; + +static const struct floatformat *floatformats_ia64_ext[2] = +{ + &floatformat_ia64_ext_big, + &floatformat_ia64_ext_little +}; + +static struct type * +ia64_ext_type (struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (!tdep->ia64_ext_type) + tdep->ia64_ext_type + = arch_float_type (gdbarch, 128, "builtin_type_ia64_ext", + floatformats_ia64_ext); -#define SIGCONTEXT_REGISTER_ADDRESS \ - (gdbarch_tdep (current_gdbarch)->sigcontext_register_address) -#define FIND_GLOBAL_POINTER \ - (gdbarch_tdep (current_gdbarch)->find_global_pointer) + return tdep->ia64_ext_type; +} -int +static int ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *group) { @@ -285,7 +330,7 @@ ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum, if (group == all_reggroup) return 1; vector_p = TYPE_VECTOR (register_type (gdbarch, regnum)); - float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT; + float_p = register_type (gdbarch, regnum)->code () == TYPE_CODE_FLT; raw_p = regnum < NUM_IA64_RAW_REGS; if (group == float_reggroup) return float_p; @@ -299,7 +344,7 @@ ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum, } static const char * -ia64_register_name (int reg) +ia64_register_name (struct gdbarch *gdbarch, int reg) { return ia64_register_names[reg]; } @@ -308,63 +353,25 @@ struct type * ia64_register_type (struct gdbarch *arch, int reg) { if (reg >= IA64_FR0_REGNUM && reg <= IA64_FR127_REGNUM) - return builtin_type_ia64_ext; + return ia64_ext_type (arch); else - return builtin_type_long; + return builtin_type (arch)->builtin_long; } static int -ia64_dwarf_reg_to_regnum (int reg) +ia64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) { if (reg >= IA64_GR32_REGNUM && reg <= IA64_GR127_REGNUM) return V32_REGNUM + (reg - IA64_GR32_REGNUM); return reg; } -static int -floatformat_valid (const struct floatformat *fmt, const char *from) -{ - return 1; -} - -const struct floatformat floatformat_ia64_ext = -{ - floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64, - floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid -}; - - -/* 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 (!(get_frame_type (frame) == SIGTRAMP_FRAME)) - internal_error (__FILE__, __LINE__, - "read_sigcontext_register: frame not a signal trampoline"); - if (SIGCONTEXT_REGISTER_ADDRESS == 0) - internal_error (__FILE__, __LINE__, - "read_sigcontext_register: SIGCONTEXT_REGISTER_ADDRESS is 0"); - - regaddr = SIGCONTEXT_REGISTER_ADDRESS (get_frame_base (frame), regnum); - if (regaddr) - return read_memory_integer (regaddr, register_size (current_gdbarch, 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''. */ static long long -extract_bit_field (char *bundle, int from, int len) +extract_bit_field (const gdb_byte *bundle, int from, int len) { long long result = 0LL; int to = from + len; @@ -397,10 +404,10 @@ extract_bit_field (char *bundle, int from, int len) return result; } -/* Replace the specified bits in an instruction bundle */ +/* Replace the specified bits in an instruction bundle. */ static void -replace_bit_field (char *bundle, long long val, int from, int len) +replace_bit_field (gdb_byte *bundle, long long val, int from, int len) { int to = from + len; int from_byte = from / 8; @@ -447,23 +454,23 @@ replace_bit_field (char *bundle, long long val, int from, int len) } /* Return the contents of slot N (for N = 0, 1, or 2) in - and instruction bundle */ + and instruction bundle. */ static long long -slotN_contents (char *bundle, int slotnum) +slotN_contents (gdb_byte *bundle, int slotnum) { return extract_bit_field (bundle, 5+41*slotnum, 41); } -/* Store an instruction in an instruction bundle */ +/* Store an instruction in an instruction bundle. */ static void -replace_slotN_contents (char *bundle, long long instr, int slotnum) +replace_slotN_contents (gdb_byte *bundle, long long instr, int slotnum) { replace_bit_field (bundle, instr, 5+41*slotnum, 41); } -static enum instruction_type template_encoding_table[32][3] = +static const enum instruction_type template_encoding_table[32][3] = { { M, I, I }, /* 00 */ { M, I, I }, /* 01 */ @@ -505,9 +512,9 @@ static enum instruction_type template_encoding_table[32][3] = static CORE_ADDR fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr) { - char bundle[BUNDLE_LEN]; + gdb_byte bundle[BUNDLE_LEN]; int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long template; + long long templ; int val; /* Warn about slot numbers greater than 2. We used to generate @@ -525,8 +532,8 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr) at the assembly language level. */ if (slotnum > 2) { - warning ("Can't fetch instructions for slot numbers greater than 2.\n" - "Using slot 0 instead"); + warning (_("Can't fetch instructions for slot numbers greater than 2.\n" + "Using slot 0 instead")); slotnum = 0; } @@ -538,8 +545,8 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr) return 0; *instr = slotN_contents (bundle, slotnum); - template = extract_bit_field (bundle, 0, 5); - *it = template_encoding_table[(int)template][slotnum]; + templ = extract_bit_field (bundle, 0, 5); + *it = template_encoding_table[(int)templ][slotnum]; if (slotnum == 2 || (slotnum == 1 && *it == L)) addr += 16; @@ -566,129 +573,342 @@ fetch_instruction (CORE_ADDR addr, instruction_type *it, long long *instr) 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. */ + using the pattern seen below. + + SHADOW_CONTENTS has byte-based addressing (PLACED_ADDRESS and SHADOW_LEN) + while we need bit-based addressing as the instructions length is 41 bits and + we must not modify/corrupt the adjacent slots in the same bundle. + Fortunately we may store larger memory incl. the adjacent bits with the + original memory content (not the possibly already stored breakpoints there). + We need to be careful in ia64_memory_remove_breakpoint to always restore + only the specific bits of this instruction ignoring any adjacent stored + bits. + + We use the original addressing with the low nibble in the range <0..2> which + gets incorrectly interpreted by generic non-ia64 breakpoint_restore_shadows + as the direct byte offset of SHADOW_CONTENTS. We store whole BUNDLE_LEN + bytes just without these two possibly skipped bytes to not to exceed to the + next bundle. + + If we would like to store the whole bundle to SHADOW_CONTENTS we would have + to store already the base address (`address & ~0x0f') into PLACED_ADDRESS. + In such case there is no other place where to store + SLOTNUM (`adress & 0x0f', value in the range <0..2>). We need to know + SLOTNUM in ia64_memory_remove_breakpoint. + + There is one special case where we need to be extra careful: + L-X instructions, which are instructions that occupy 2 slots + (The L part is always in slot 1, and the X part is always in + slot 2). We must refuse to insert breakpoints for an address + that points at slot 2 of a bundle where an L-X instruction is + present, since there is logically no instruction at that address. + However, to make things more interesting, the opcode of L-X + instructions is located in slot 2. This means that, to insert + a breakpoint at an address that points to slot 1, we actually + need to write the breakpoint in slot 2! Slot 1 is actually + the extended operand, so writing the breakpoint there would not + have the desired effect. Another side-effect of this issue + is that we need to make sure that the shadow contents buffer + does save byte 15 of our instruction bundle (this is the tail + end of slot 2, which wouldn't be saved if we were to insert + the breakpoint in slot 1). + + ia64 16-byte bundle layout: + | 5 bits | slot 0 with 41 bits | slot 1 with 41 bits | slot 2 with 41 bits | + + The current addressing used by the code below: + original PC placed_address placed_size required covered + == bp_tgt->shadow_len reqd \subset covered + 0xABCDE0 0xABCDE0 0x10 <0x0...0x5> <0x0..0xF> + 0xABCDE1 0xABCDE1 0xF <0x5...0xA> <0x1..0xF> + 0xABCDE2 0xABCDE2 0xE <0xA...0xF> <0x2..0xF> + + L-X instructions are treated a little specially, as explained above: + 0xABCDE1 0xABCDE1 0xF <0xA...0xF> <0x1..0xF> + + `objdump -d' and some other tools show a bit unjustified offsets: + original PC byte where starts the instruction objdump offset + 0xABCDE0 0xABCDE0 0xABCDE0 + 0xABCDE1 0xABCDE5 0xABCDE6 + 0xABCDE2 0xABCDEA 0xABCDEC + */ -#if 0 -#define IA64_BREAKPOINT 0x00002000040LL -#endif #define IA64_BREAKPOINT 0x00003333300LL static int -ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache) +ia64_memory_insert_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { - char bundle[BUNDLE_LEN]; - int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address; + gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER, shadow_slotnum; + long long instr_breakpoint; int val; - int template; + int templ; if (slotnum > 2) - error("Can't insert breakpoint for slot numbers greater than 2."); + error (_("Can't insert breakpoint for slot numbers greater than 2.")); addr &= ~0x0f; + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle for the purpose of SHADOW_CONTENTS. + Otherwise, we could possibly store into the shadow parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ + scoped_restore restore_memory_0 + = make_scoped_restore_show_memory_breakpoints (0); val = target_read_memory (addr, bundle, BUNDLE_LEN); + if (val != 0) + return val; + + /* SHADOW_SLOTNUM saves the original slot number as expected by the caller + for addressing the SHADOW_CONTENTS placement. */ + shadow_slotnum = slotnum; - /* 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) + /* Always cover the last byte of the bundle in case we are inserting + a breakpoint on an L-X instruction. */ + bp_tgt->shadow_len = BUNDLE_LEN - shadow_slotnum; + + templ = extract_bit_field (bundle, 0, 5); + if (template_encoding_table[templ][slotnum] == X) + { + /* X unit types can only be used in slot 2, and are actually + part of a 2-slot L-X instruction. We cannot break at this + address, as this is the second half of an instruction that + lives in slot 1 of that bundle. */ + gdb_assert (slotnum == 2); + error (_("Can't insert breakpoint for non-existing slot X")); + } + if (template_encoding_table[templ][slotnum] == L) { + /* L unit types can only be used in slot 1. But the associated + opcode for that instruction is in slot 2, so bump the slot number + accordingly. */ + gdb_assert (slotnum == 1); slotnum = 2; } - instr = slotN_contents (bundle, slotnum); - memcpy(contents_cache, &instr, sizeof(instr)); + /* Store the whole bundle, except for the initial skipped bytes by the slot + number interpreted as bytes offset in PLACED_ADDRESS. */ + memcpy (bp_tgt->shadow_contents, bundle + shadow_slotnum, + bp_tgt->shadow_len); + + /* Re-read the same bundle as above except that, this time, read it in order + to compute the new bundle inside which we will be inserting the + breakpoint. Therefore, disable the automatic memory restoration from + breakpoints while we read our instruction bundle. Otherwise, the general + restoration mechanism kicks in and we would possibly remove parts of the + adjacent placed breakpoints. It is due to our SHADOW_CONTENTS overlapping + the real breakpoint instruction bits region. */ + scoped_restore restore_memory_1 + = make_scoped_restore_show_memory_breakpoints (1); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + if (val != 0) + return val; + + /* Breakpoints already present in the code will get detected and not get + reinserted by bp_loc_is_permanent. Multiple breakpoints at the same + location cannot induce the internal error as they are optimized into + a single instance by update_global_location_list. */ + instr_breakpoint = slotN_contents (bundle, slotnum); + if (instr_breakpoint == IA64_BREAKPOINT) + internal_error (__FILE__, __LINE__, + _("Address %s already contains a breakpoint."), + paddress (gdbarch, bp_tgt->placed_address)); replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum); - if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + + val = target_write_memory (addr + shadow_slotnum, bundle + shadow_slotnum, + bp_tgt->shadow_len); return val; } static int -ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache) +ia64_memory_remove_breakpoint (struct gdbarch *gdbarch, + struct bp_target_info *bp_tgt) { - char bundle[BUNDLE_LEN]; - int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER; - long long instr; + CORE_ADDR addr = bp_tgt->placed_address; + gdb_byte bundle_mem[BUNDLE_LEN], bundle_saved[BUNDLE_LEN]; + int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER, shadow_slotnum; + long long instr_breakpoint, instr_saved; int val; - int template; + int templ; addr &= ~0x0f; - val = target_read_memory (addr, bundle, BUNDLE_LEN); + /* Disable the automatic memory restoration from breakpoints while + we read our instruction bundle. Otherwise, the general restoration + mechanism kicks in and we would possibly remove parts of the adjacent + placed breakpoints. It is due to our SHADOW_CONTENTS overlapping the real + breakpoint instruction bits region. */ + scoped_restore restore_memory_1 + = make_scoped_restore_show_memory_breakpoints (1); + val = target_read_memory (addr, bundle_mem, BUNDLE_LEN); + if (val != 0) + return val; - /* 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) + /* SHADOW_SLOTNUM saves the original slot number as expected by the caller + for addressing the SHADOW_CONTENTS placement. */ + shadow_slotnum = slotnum; + + templ = extract_bit_field (bundle_mem, 0, 5); + if (template_encoding_table[templ][slotnum] == X) + { + /* X unit types can only be used in slot 2, and are actually + part of a 2-slot L-X instruction. We refuse to insert + breakpoints at this address, so there should be no reason + for us attempting to remove one there, except if the program's + code somehow got modified in memory. */ + gdb_assert (slotnum == 2); + warning (_("Cannot remove breakpoint at address %s from non-existing " + "X-type slot, memory has changed underneath"), + paddress (gdbarch, bp_tgt->placed_address)); + return -1; + } + if (template_encoding_table[templ][slotnum] == L) { + /* L unit types can only be used in slot 1. But the breakpoint + was actually saved using slot 2, so update the slot number + accordingly. */ + gdb_assert (slotnum == 1); slotnum = 2; } - memcpy (&instr, contents_cache, sizeof instr); - replace_slotN_contents (bundle, instr, slotnum); - if (val == 0) - target_write_memory (addr, bundle, BUNDLE_LEN); + gdb_assert (bp_tgt->shadow_len == BUNDLE_LEN - shadow_slotnum); + + instr_breakpoint = slotN_contents (bundle_mem, slotnum); + if (instr_breakpoint != IA64_BREAKPOINT) + { + warning (_("Cannot remove breakpoint at address %s, " + "no break instruction at such address."), + paddress (gdbarch, bp_tgt->placed_address)); + return -1; + } + + /* Extract the original saved instruction from SLOTNUM normalizing its + bit-shift for INSTR_SAVED. */ + memcpy (bundle_saved, bundle_mem, BUNDLE_LEN); + memcpy (bundle_saved + shadow_slotnum, bp_tgt->shadow_contents, + bp_tgt->shadow_len); + instr_saved = slotN_contents (bundle_saved, slotnum); + + /* In BUNDLE_MEM, be careful to modify only the bits belonging to SLOTNUM + and not any of the other ones that are stored in SHADOW_CONTENTS. */ + replace_slotN_contents (bundle_mem, instr_saved, slotnum); + val = target_write_raw_memory (addr, bundle_mem, 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) +/* Implement the breakpoint_kind_from_pc gdbarch method. */ + +static int +ia64_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) { - static unsigned char breakpoint[] = - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - *lenptr = sizeof (breakpoint); -#if 0 - *pcptr &= ~0x0f; -#endif - return breakpoint; + /* A place holder of gdbarch method breakpoint_kind_from_pc. */ + return 0; } -static CORE_ADDR -ia64_read_fp (void) +/* As gdbarch_breakpoint_from_pc ranges have byte granularity and ia64 + instruction slots ranges are bit-granular (41 bits) we have to provide an + extended range as described for ia64_memory_insert_breakpoint. We also take + care of preserving the `break' instruction 21-bit (or 62-bit) parameter to + make a match for permanent breakpoints. */ + +static const gdb_byte * +ia64_breakpoint_from_pc (struct gdbarch *gdbarch, + CORE_ADDR *pcptr, int *lenptr) { - /* We won't necessarily have a frame pointer and even if we do, it - winds up being extraordinarly messy when attempting to find the - frame chain. So for the purposes of creating frames (which is - all deprecated_read_fp() is used for), simply use the stack - pointer value instead. */ - gdb_assert (SP_REGNUM >= 0); - return read_register (SP_REGNUM); + CORE_ADDR addr = *pcptr; + static gdb_byte bundle[BUNDLE_LEN]; + int slotnum = (int) (*pcptr & 0x0f) / SLOT_MULTIPLIER, shadow_slotnum; + long long instr_fetched; + int val; + int templ; + + if (slotnum > 2) + error (_("Can't insert breakpoint for slot numbers greater than 2.")); + + addr &= ~0x0f; + + /* Enable the automatic memory restoration from breakpoints while + we read our instruction bundle to match bp_loc_is_permanent. */ + { + scoped_restore restore_memory_0 + = make_scoped_restore_show_memory_breakpoints (0); + val = target_read_memory (addr, bundle, BUNDLE_LEN); + } + + /* The memory might be unreachable. This can happen, for instance, + when the user inserts a breakpoint at an invalid address. */ + if (val != 0) + return NULL; + + /* SHADOW_SLOTNUM saves the original slot number as expected by the caller + for addressing the SHADOW_CONTENTS placement. */ + shadow_slotnum = slotnum; + + /* Cover always the last byte of the bundle for the L-X slot case. */ + *lenptr = BUNDLE_LEN - shadow_slotnum; + + /* Check for L type instruction in slot 1, if present then bump up the slot + number to the slot 2. */ + templ = extract_bit_field (bundle, 0, 5); + if (template_encoding_table[templ][slotnum] == X) + { + gdb_assert (slotnum == 2); + error (_("Can't insert breakpoint for non-existing slot X")); + } + if (template_encoding_table[templ][slotnum] == L) + { + gdb_assert (slotnum == 1); + slotnum = 2; + } + + /* A break instruction has its all its opcode bits cleared except for + the parameter value. For L+X slot pair we are at the X slot (slot 2) so + we should not touch the L slot - the upper 41 bits of the parameter. */ + instr_fetched = slotN_contents (bundle, slotnum); + instr_fetched &= 0x1003ffffc0LL; + replace_slotN_contents (bundle, instr_fetched, slotnum); + + return bundle + shadow_slotnum; } static CORE_ADDR -ia64_read_pc (ptid_t ptid) +ia64_read_pc (readable_regcache *regcache) { - 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; + ULONGEST psr_value, pc_value; + int slot_num; + + regcache->cooked_read (IA64_PSR_REGNUM, &psr_value); + regcache->cooked_read (IA64_IP_REGNUM, &pc_value); + slot_num = (psr_value >> 41) & 3; return pc_value | (slot_num * SLOT_MULTIPLIER); } -static void -ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid) +void +ia64_write_pc (struct regcache *regcache, CORE_ADDR new_pc) { int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER; - CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid); + ULONGEST psr_value; + + regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr_value); psr_value &= ~(3LL << 41); - psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41; + psr_value |= (ULONGEST)(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); + regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr_value); + regcache_cooked_write_unsigned (regcache, IA64_IP_REGNUM, new_pc); } #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. */ + the address ADDR. NSLOTS may be positive or negative. */ static CORE_ADDR rse_address_add(CORE_ADDR addr, int nslots) { @@ -707,38 +927,66 @@ rse_address_add(CORE_ADDR addr, int nslots) return new_addr; } -static void -ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, - int regnum, void *buf) +static enum register_status +ia64_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, + int regnum, gdb_byte *buf) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + enum register_status status; + if (regnum >= V32_REGNUM && regnum <= V127_REGNUM) { - ULONGEST bsp; - ULONGEST cfm; - CORE_ADDR reg; - regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); - regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); - - /* The bsp points at the end of the register frame so we - subtract the size of frame from it to get start of register frame. */ - bsp = rse_address_add (bsp, -(cfm & 0x7f)); - - if ((cfm & 0x7f) > regnum - V32_REGNUM) +#ifdef HAVE_LIBUNWIND_IA64_H + /* First try and use the libunwind special reg accessor, + otherwise fallback to standard logic. */ + if (!libunwind_is_initialized () + || libunwind_get_reg_special (gdbarch, regcache, regnum, buf) != 0) +#endif { - ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM)); - reg = read_memory_integer ((CORE_ADDR)reg_addr, 8); - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg); + /* The fallback position is to assume that r32-r127 are + found sequentially in memory starting at $bof. This + isn't always true, but without libunwind, this is the + best we can do. */ + ULONGEST cfm; + ULONGEST bsp; + CORE_ADDR reg; + + status = regcache->cooked_read (IA64_BSP_REGNUM, &bsp); + if (status != REG_VALID) + return status; + + status = regcache->cooked_read (IA64_CFM_REGNUM, &cfm); + if (status != REG_VALID) + return status; + + /* The bsp points at the end of the register frame so we + subtract the size of frame from it to get start of + register frame. */ + bsp = rse_address_add (bsp, -(cfm & 0x7f)); + + if ((cfm & 0x7f) > regnum - V32_REGNUM) + { + ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM)); + reg = read_memory_integer ((CORE_ADDR)reg_addr, 8, byte_order); + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, reg); + } + else + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, 0); } - else - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0); } else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM) { ULONGEST unatN_val; ULONGEST unat; - regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat); + + status = regcache->cooked_read (IA64_UNAT_REGNUM, &unat); + if (status != REG_VALID) + return status; unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0; - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), unatN_val); + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, unatN_val); } else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM) { @@ -746,8 +994,14 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, ULONGEST bsp; ULONGEST cfm; CORE_ADDR gr_addr = 0; - regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); - regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); + + status = regcache->cooked_read (IA64_BSP_REGNUM, &bsp); + if (status != REG_VALID) + return status; + + status = regcache->cooked_read (IA64_CFM_REGNUM, &cfm); + if (status != REG_VALID) + return status; /* The bsp points at the end of the register frame so we subtract the size of frame from it to get start of register frame. */ @@ -760,71 +1014,85 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, { /* Compute address of nat collection bits. */ CORE_ADDR nat_addr = gr_addr | 0x1f8; - CORE_ADDR nat_collection; + ULONGEST 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) - regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM, &nat_collection); + regcache->cooked_read (IA64_RNAT_REGNUM, &nat_collection); else - nat_collection = read_memory_integer (nat_addr, 8); + nat_collection = read_memory_integer (nat_addr, 8, byte_order); nat_bit = (gr_addr >> 3) & 0x3f; natN_val = (nat_collection >> nat_bit) & 1; } - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), natN_val); + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, natN_val); } else if (regnum == VBOF_REGNUM) { /* A virtual register frame start is provided for user convenience. - It can be calculated as the bsp - sof (sizeof frame). */ + It can be calculated as the bsp - sof (sizeof frame). */ ULONGEST bsp, vbsp; ULONGEST cfm; - CORE_ADDR reg; - regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); - regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); + + status = regcache->cooked_read (IA64_BSP_REGNUM, &bsp); + if (status != REG_VALID) + return status; + status = regcache->cooked_read (IA64_CFM_REGNUM, &cfm); + if (status != REG_VALID) + return status; /* The bsp points at the end of the register frame so we subtract the size of frame from it to get beginning of frame. */ vbsp = rse_address_add (bsp, -(cfm & 0x7f)); - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), vbsp); + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, vbsp); } else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM) { ULONGEST pr; ULONGEST cfm; ULONGEST prN_val; - CORE_ADDR reg; - regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr); - regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); + + status = regcache->cooked_read (IA64_PR_REGNUM, &pr); + if (status != REG_VALID) + return status; + status = regcache->cooked_read (IA64_CFM_REGNUM, &cfm); + if (status != REG_VALID) + return status; if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM) { /* Fetch predicate register rename base from current frame - marker for this frame. */ + marker for this frame. */ int rrb_pr = (cfm >> 32) & 0x3f; - /* Adjust the register number to account for register rotation. */ + /* Adjust the register number to account for register rotation. */ regnum = VP16_REGNUM + ((regnum - VP16_REGNUM) + rrb_pr) % 48; } prN_val = (pr & (1LL << (regnum - VP0_REGNUM))) != 0; - store_unsigned_integer (buf, register_size (current_gdbarch, regnum), prN_val); + store_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order, prN_val); } else - memset (buf, 0, register_size (current_gdbarch, regnum)); + memset (buf, 0, register_size (gdbarch, regnum)); + + return REG_VALID; } static void ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, - int regnum, const void *buf) + int regnum, const gdb_byte *buf) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + if (regnum >= V32_REGNUM && regnum <= V127_REGNUM) { ULONGEST bsp; ULONGEST cfm; - CORE_ADDR reg; regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); @@ -833,14 +1101,16 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, if ((cfm & 0x7f) > regnum - V32_REGNUM) { ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM)); - write_memory (reg_addr, (void *)buf, 8); + write_memory (reg_addr, buf, 8); } } else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM) { ULONGEST unatN_val, unat, unatN_mask; regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat); - unatN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); + unatN_val = extract_unsigned_integer (buf, register_size (gdbarch, + regnum), + byte_order); unatN_mask = (1LL << (regnum - IA64_NAT0_REGNUM)); if (unatN_val == 0) unat &= ~unatN_mask; @@ -864,7 +1134,9 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, if ((cfm & 0x7f) > regnum - V32_REGNUM) gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM)); - natN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); + natN_val = extract_unsigned_integer (buf, register_size (gdbarch, + regnum), + byte_order); if (gr_addr != 0 && (natN_val == 0 || natN_val == 1)) { @@ -878,22 +1150,26 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, collection from the computed address. */ if (nat_addr >= bsp) { - regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM, &nat_collection); + regcache_cooked_read_unsigned (regcache, + IA64_RNAT_REGNUM, + &nat_collection); if (natN_val) nat_collection |= natN_mask; else nat_collection &= ~natN_mask; - regcache_cooked_write_unsigned (regcache, IA64_RNAT_REGNUM, nat_collection); + regcache_cooked_write_unsigned (regcache, IA64_RNAT_REGNUM, + nat_collection); } else { - char nat_buf[8]; - nat_collection = read_memory_integer (nat_addr, 8); + gdb_byte nat_buf[8]; + nat_collection = read_memory_integer (nat_addr, 8, byte_order); if (natN_val) nat_collection |= natN_mask; else nat_collection &= ~natN_mask; - store_unsigned_integer (nat_buf, register_size (current_gdbarch, regnum), nat_collection); + store_unsigned_integer (nat_buf, register_size (gdbarch, regnum), + byte_order, nat_collection); write_memory (nat_addr, nat_buf, 8); } } @@ -911,14 +1187,15 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM) { /* Fetch predicate register rename base from current frame - marker for this frame. */ + marker for this frame. */ int rrb_pr = (cfm >> 32) & 0x3f; - /* Adjust the register number to account for register rotation. */ + /* Adjust the register number to account for register rotation. */ regnum = VP16_REGNUM + ((regnum - VP16_REGNUM) + rrb_pr) % 48; } - prN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum)); + prN_val = extract_unsigned_integer (buf, register_size (gdbarch, regnum), + byte_order); prN_mask = (1LL << (regnum - VP0_REGNUM)); if (prN_val == 0) pr &= ~prN_mask; @@ -932,26 +1209,39 @@ ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, and the special ia64 floating point register format. */ static int -ia64_convert_register_p (int regno, struct type *type) +ia64_convert_register_p (struct gdbarch *gdbarch, int regno, struct type *type) { - return (regno >= IA64_FR0_REGNUM && regno <= IA64_FR127_REGNUM); + return (regno >= IA64_FR0_REGNUM && regno <= IA64_FR127_REGNUM + && type->code () == TYPE_CODE_FLT + && type != ia64_ext_type (gdbarch)); } -static void +static int ia64_register_to_value (struct frame_info *frame, int regnum, - struct type *valtype, void *out) + struct type *valtype, gdb_byte *out, + int *optimizedp, int *unavailablep) { - char in[MAX_REGISTER_SIZE]; - frame_register_read (frame, regnum, in); - convert_typed_floating (in, builtin_type_ia64_ext, out, valtype); + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte in[IA64_FP_REGISTER_SIZE]; + + /* Convert to TYPE. */ + if (!get_frame_register_bytes (frame, regnum, 0, + register_size (gdbarch, regnum), + in, optimizedp, unavailablep)) + return 0; + + target_float_convert (in, ia64_ext_type (gdbarch), out, valtype); + *optimizedp = *unavailablep = 0; + return 1; } static void ia64_value_to_register (struct frame_info *frame, int regnum, - struct type *valtype, const void *in) + struct type *valtype, const gdb_byte *in) { - char out[MAX_REGISTER_SIZE]; - convert_typed_floating (in, valtype, out, builtin_type_ia64_ext); + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte out[IA64_FP_REGISTER_SIZE]; + target_float_convert (in, valtype, out, ia64_ext_type (gdbarch)); put_frame_register (frame, regnum, out); } @@ -970,11 +1260,20 @@ static int max_skip_non_prologue_insns = 40; used with no further scanning in the event that the function is frameless. */ +/* FIXME: cagney/2004-02-14: This function and logic have largely been + superseded by skip_prologue_using_sal. */ + static CORE_ADDR refine_prologue_limit (CORE_ADDR pc, CORE_ADDR lim_pc, int *trust_limit) { struct symtab_and_line prologue_sal; CORE_ADDR start_pc = pc; + CORE_ADDR end_pc; + + /* The prologue can not possibly go past the function end itself, + so we can already adjust LIM_PC accordingly. */ + if (find_pc_partial_function (pc, NULL, NULL, &end_pc) && end_pc < lim_pc) + lim_pc = end_pc; /* Start off not trusting the limit. */ *trust_limit = 0; @@ -1056,7 +1355,9 @@ ia64_alloc_frame_cache (void) } static CORE_ADDR -examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, struct ia64_frame_cache *cache) +examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, + struct frame_info *this_frame, + struct ia64_frame_cache *cache) { CORE_ADDR next_pc; CORE_ADDR last_prologue_pc = pc; @@ -1077,7 +1378,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, int frameless = 1; int i; CORE_ADDR addr; - char buf[8]; + gdb_byte buf[8]; CORE_ADDR bof, sor, sol, sof, cfm, rrb_gr; memset (instores, 0, sizeof instores); @@ -1097,19 +1398,18 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, && it == M && ((instr & 0x1ee0000003fLL) == 0x02c00000000LL)) { /* alloc - start of a regular function. */ - int sor = (int) ((instr & 0x00078000000LL) >> 27); - int sol = (int) ((instr & 0x00007f00000LL) >> 20); - int sof = (int) ((instr & 0x000000fe000LL) >> 13); + int sol_bits = (int) ((instr & 0x00007f00000LL) >> 20); + int sof_bits = (int) ((instr & 0x000000fe000LL) >> 13); int rN = (int) ((instr & 0x00000001fc0LL) >> 6); /* Verify that the current cfm matches what we think is the function start. If we have somehow jumped within a function, we do not want to interpret the prologue and calculate the - addresses of various registers such as the return address. - We will instead treat the frame as frameless. */ - if (!next_frame || - (sof == (cache->cfm & 0x7f) && - sol == ((cache->cfm >> 7) & 0x7f))) + addresses of various registers such as the return address. + We will instead treat the frame as frameless. */ + if (!this_frame || + (sof_bits == (cache->cfm & 0x7f) && + sol_bits == ((cache->cfm >> 7) & 0x7f))) frameless = 0; cfm_reg = rN; @@ -1132,7 +1432,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, int qp = (int) (instr & 0x0000000003fLL); if (qp == 0 && rN == 2 && imm == 0 && rM == 12 && fp_reg == 0) { - /* mov r2, r12 - beginning of leaf routine */ + /* mov r2, r12 - beginning of leaf routine. */ fp_reg = rN; last_prologue_pc = next_pc; } @@ -1149,16 +1449,16 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, } /* Loop, looking for prologue instructions, keeping track of - where preserved registers were spilled. */ + where preserved registers were spilled. */ while (pc < lim_pc) { next_pc = fetch_instruction (pc, &it, &instr); if (next_pc == 0) break; - if (it == B && ((instr & 0x1e1f800003f) != 0x04000000000)) + if (it == B && ((instr & 0x1e1f800003fLL) != 0x04000000000LL)) { - /* Exit loop upon hitting a non-nop branch instruction. */ + /* Exit loop upon hitting a non-nop branch instruction. */ if (trust_limit) lim_pc = pc; break; @@ -1211,35 +1511,32 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, else if (qp == 0 && rN == 2 && ((rM == fp_reg && fp_reg != 0) || rM == 12)) { - char buf[MAX_REGISTER_SIZE]; CORE_ADDR saved_sp = 0; /* 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 + /* 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 */ - if (next_frame) - { - frame_unwind_register (next_frame, sp_regnum, buf); - saved_sp = extract_unsigned_integer (buf, 8); - } + if (this_frame) + saved_sp = get_frame_register_unsigned (this_frame, + sp_regnum); spill_addr = saved_sp + (rM == 12 ? 0 : mem_stack_frame_size) + imm; spill_reg = rN; last_prologue_pc = next_pc; } - else if (qp == 0 && rM >= 32 && rM < 40 && !instores[rM] && + else if (qp == 0 && rM >= 32 && rM < 40 && !instores[rM-32] && rN < 256 && imm == 0) { - /* mov rN, rM where rM is an input register */ + /* mov rN, rM where rM is an input register. */ reg_contents[rN] = rM; last_prologue_pc = next_pc; } @@ -1268,10 +1565,10 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, { cache->saved_regs[IA64_FR0_REGNUM + fM] = spill_addr; - if ((instr & 0x1efc0000000) == 0x0eec0000000) + if ((instr & 0x1efc0000000LL) == 0x0eec0000000LL) spill_addr += imm; else - spill_addr = 0; /* last one; must be done */ + spill_addr = 0; /* last one; must be done. */ last_prologue_pc = next_pc; } } @@ -1288,7 +1585,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, 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... */ + r3 (or whatever) and watch for a store of this register... */ unat_save_reg = rN; last_prologue_pc = next_pc; } @@ -1321,16 +1618,16 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, /* 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... */ + Record that fact and move on... */ if (rM == unat_save_reg) { - /* Track UNAT register */ + /* Track UNAT register. */ cache->saved_regs[IA64_UNAT_REGNUM] = spill_addr; unat_save_reg = 0; } else { - /* Track PR register */ + /* Track PR register. */ cache->saved_regs[IA64_PR_REGNUM] = spill_addr; pr_save_reg = 0; } @@ -1338,12 +1635,12 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, /* st8 [rN] = rM, imm9 */ spill_addr += imm9(instr); else - spill_addr = 0; /* must be done spilling */ + 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. */ + /* Allow up to one store of each input register. */ instores[rM-32] = 1; last_prologue_pc = next_pc; } @@ -1364,8 +1661,8 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, 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. */ + Advance over stores of input registers. One store per input + register is permitted. */ int rM = (int) ((instr & 0x000000fe000LL) >> 13); int qp = (int) (instr & 0x0000000003fLL); int indirect = rM < 256 ? reg_contents[rM] : 0; @@ -1390,7 +1687,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, stfd [rN] = fM Advance over stores of floating point input registers. Again - one store per register is permitted */ + 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]) @@ -1413,13 +1710,13 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, { /* We've found a spill of one of the preserved general purpose regs. Record the spill address and advance the spill - register if appropriate. */ + register if appropriate. */ cache->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 */ + spill_addr = 0; /* Done spilling. */ last_prologue_pc = next_pc; } } @@ -1427,14 +1724,18 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, pc = next_pc; } - /* If not frameless and we aren't called by skip_prologue, then we need to calculate - registers for the previous frame which will be needed later. */ + /* If not frameless and we aren't called by skip_prologue, then we need + to calculate registers for the previous frame which will be needed + later. */ - if (!frameless && next_frame) + if (!frameless && this_frame) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + /* Extract the size of the rotating portion of the stack frame and the register rename base from the current - frame marker. */ + frame marker. */ cfm = cache->cfm; sor = cache->sor; sof = cache->sof; @@ -1460,17 +1761,18 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, cache->saved_regs[IA64_VFP_REGNUM] = addr; } - /* For the previous argument registers we require the previous bof. + /* For the previous argument registers we require the previous bof. If we can't find the previous cfm, then we can do nothing. */ cfm = 0; if (cache->saved_regs[IA64_CFM_REGNUM] != 0) { - cfm = read_memory_integer (cache->saved_regs[IA64_CFM_REGNUM], 8); + cfm = read_memory_integer (cache->saved_regs[IA64_CFM_REGNUM], + 8, byte_order); } else if (cfm_reg != 0) { - frame_unwind_register (next_frame, cfm_reg, buf); - cfm = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, cfm_reg, buf); + cfm = extract_unsigned_integer (buf, 8, byte_order); } cache->prev_cfm = cfm; @@ -1481,8 +1783,9 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, sol = (cfm >> 7) & 0x7f; rrb_gr = (cfm >> 18) & 0x7f; - /* The previous bof only requires subtraction of the sol (size of locals) - due to the overlap between output and input of subsequent frames. */ + /* The previous bof only requires subtraction of the sol (size of + locals) due to the overlap between output and input of + subsequent frames. */ bof = rse_address_add (bof, -sol); for (i = 0, addr = bof; @@ -1494,7 +1797,8 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, addr += 8; } if (i < sor) - cache->saved_regs[IA64_GR32_REGNUM + ((i + (sor - rrb_gr)) % sor)] + cache->saved_regs[IA64_GR32_REGNUM + + ((i + (sor - rrb_gr)) % sor)] = addr; else cache->saved_regs[IA64_GR32_REGNUM + i] = addr; @@ -1516,7 +1820,7 @@ examine_prologue (CORE_ADDR pc, CORE_ADDR lim_pc, struct frame_info *next_frame, } CORE_ADDR -ia64_skip_prologue (CORE_ADDR pc) +ia64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) { struct ia64_frame_cache cache; cache.base = 0; @@ -1524,7 +1828,8 @@ ia64_skip_prologue (CORE_ADDR pc) cache.cfm = 0; cache.bsp = 0; - /* Call examine_prologue with - as third argument since we don't have a next frame pointer to send. */ + /* Call examine_prologue with - as third argument since we don't + have a next frame pointer to send. */ return examine_prologue (pc, pc+1024, 0, &cache); } @@ -1532,33 +1837,33 @@ ia64_skip_prologue (CORE_ADDR pc) /* Normal frames. */ static struct ia64_frame_cache * -ia64_frame_cache (struct frame_info *next_frame, void **this_cache) +ia64_frame_cache (struct frame_info *this_frame, void **this_cache) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct ia64_frame_cache *cache; - char buf[8]; - CORE_ADDR cfm, sof, sol, bsp, psr; - int i; + gdb_byte buf[8]; + CORE_ADDR cfm; if (*this_cache) - return *this_cache; + return (struct ia64_frame_cache *) *this_cache; cache = ia64_alloc_frame_cache (); *this_cache = cache; - frame_unwind_register (next_frame, sp_regnum, buf); - cache->saved_sp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, sp_regnum, buf); + cache->saved_sp = extract_unsigned_integer (buf, 8, byte_order); /* We always want the bsp to point to the end of frame. This way, we can always get the beginning of frame (bof) by subtracting frame size. */ - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - cache->bsp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + cache->bsp = extract_unsigned_integer (buf, 8, byte_order); - frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf); - psr = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_PSR_REGNUM, buf); - frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf); - cfm = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_CFM_REGNUM, buf); + cfm = extract_unsigned_integer (buf, 8, byte_order); cache->sof = (cfm & 0x7f); cache->sol = (cfm >> 7) & 0x7f; @@ -1566,10 +1871,10 @@ ia64_frame_cache (struct frame_info *next_frame, void **this_cache) cache->cfm = cfm; - cache->pc = frame_func_unwind (next_frame); + cache->pc = get_frame_func (this_frame); if (cache->pc != 0) - examine_prologue (cache->pc, frame_pc_unwind (next_frame), next_frame, cache); + examine_prologue (cache->pc, get_frame_pc (this_frame), this_frame, cache); cache->base = cache->saved_sp + cache->mem_stack_frame_size; @@ -1577,119 +1882,98 @@ ia64_frame_cache (struct frame_info *next_frame, void **this_cache) } static void -ia64_frame_this_id (struct frame_info *next_frame, void **this_cache, +ia64_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct ia64_frame_cache *cache = - ia64_frame_cache (next_frame, this_cache); - - /* This marks the outermost frame. */ - if (cache->base == 0) - return; + ia64_frame_cache (this_frame, this_cache); - (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp); + /* If outermost frame, mark with null frame id. */ + if (cache->base != 0) + (*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp); if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, - "regular frame id: code %lx, stack %lx, special %lx, next_frame %p\n", - this_id->code_addr, this_id->stack_addr, cache->bsp, next_frame); + "regular frame id: code %s, stack %s, " + "special %s, this_frame %s\n", + paddress (gdbarch, this_id->code_addr), + paddress (gdbarch, this_id->stack_addr), + paddress (gdbarch, cache->bsp), + host_address_to_string (this_frame)); } -static void -ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *valuep) +static struct value * +ia64_frame_prev_register (struct frame_info *this_frame, void **this_cache, + int regnum) { - struct ia64_frame_cache *cache = - ia64_frame_cache (next_frame, this_cache); - char dummy_valp[MAX_REGISTER_SIZE]; - char buf[8]; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct ia64_frame_cache *cache = ia64_frame_cache (this_frame, this_cache); + gdb_byte buf[8]; gdb_assert (regnum >= 0); if (!target_has_registers) - error ("No registers."); + error (_("No registers.")); - *optimizedp = 0; - *addrp = 0; - *lvalp = not_lval; - *realnump = -1; + if (regnum == gdbarch_sp_regnum (gdbarch)) + return frame_unwind_got_constant (this_frame, regnum, cache->base); - /* Rather than check each time if valuep is non-null, supply a dummy buffer - when valuep is not supplied. */ - if (!valuep) - valuep = dummy_valp; - - memset (valuep, 0, register_size (current_gdbarch, regnum)); - - if (regnum == SP_REGNUM) - { - /* Handle SP values for all frames but the topmost. */ - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), - cache->base); - } else if (regnum == IA64_BSP_REGNUM) { - char cfm_valuep[MAX_REGISTER_SIZE]; - int cfm_optim; - int cfm_realnum; - enum lval_type cfm_lval; - CORE_ADDR cfm_addr; - CORE_ADDR bsp, prev_cfm, prev_bsp; - - /* We want to calculate the previous bsp as the end of the previous register stack frame. - This corresponds to what the hardware bsp register will be if we pop the frame - back which is why we might have been called. We know the beginning of the current - frame is cache->bsp - cache->sof. This value in the previous frame points to - the start of the output registers. We can calculate the end of that frame by adding - the size of output (sof (size of frame) - sol (size of locals)). */ - ia64_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM, - &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep); - prev_cfm = extract_unsigned_integer (cfm_valuep, 8); - + struct value *val; + CORE_ADDR prev_cfm, bsp, prev_bsp; + + /* We want to calculate the previous bsp as the end of the previous + register stack frame. This corresponds to what the hardware bsp + register will be if we pop the frame back which is why we might + have been called. We know the beginning of the current frame is + cache->bsp - cache->sof. This value in the previous frame points + to the start of the output registers. We can calculate the end of + that frame by adding the size of output: + (sof (size of frame) - sol (size of locals)). */ + val = ia64_frame_prev_register (this_frame, this_cache, IA64_CFM_REGNUM); + prev_cfm = extract_unsigned_integer (value_contents_all (val), + 8, byte_order); bsp = rse_address_add (cache->bsp, -(cache->sof)); - prev_bsp = rse_address_add (bsp, (prev_cfm & 0x7f) - ((prev_cfm >> 7) & 0x7f)); + prev_bsp = + rse_address_add (bsp, (prev_cfm & 0x7f) - ((prev_cfm >> 7) & 0x7f)); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), - prev_bsp); + return frame_unwind_got_constant (this_frame, regnum, prev_bsp); } + else if (regnum == IA64_CFM_REGNUM) { CORE_ADDR addr = cache->saved_regs[IA64_CFM_REGNUM]; if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); - } - else if (cache->prev_cfm) - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), cache->prev_cfm); - else if (cache->frameless) - { - CORE_ADDR cfm = 0; - frame_unwind_register (next_frame, IA64_PFS_REGNUM, valuep); - } + return frame_unwind_got_memory (this_frame, regnum, addr); + + if (cache->prev_cfm) + return frame_unwind_got_constant (this_frame, regnum, cache->prev_cfm); + + if (cache->frameless) + return frame_unwind_got_register (this_frame, IA64_PFS_REGNUM, + IA64_PFS_REGNUM); + return frame_unwind_got_register (this_frame, regnum, 0); } + 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 = cache->base; - store_unsigned_integer (valuep, register_size (current_gdbarch, IA64_VFP_REGNUM), vfp); + return frame_unwind_got_constant (this_frame, regnum, cache->base); } + else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM) { - char pr_valuep[MAX_REGISTER_SIZE]; - int pr_optim; - int pr_realnum; - enum lval_type pr_lval; - CORE_ADDR pr_addr; - ULONGEST prN_val; - ia64_frame_prev_register (next_frame, this_cache, IA64_PR_REGNUM, - &pr_optim, &pr_lval, &pr_addr, &pr_realnum, pr_valuep); + struct value *pr_val; + ULONGEST prN; + + pr_val = ia64_frame_prev_register (this_frame, this_cache, + IA64_PR_REGNUM); if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM) { /* Fetch predicate register rename base from current frame @@ -1697,28 +1981,24 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache, int rrb_pr = (cache->cfm >> 32) & 0x3f; /* Adjust the register number to account for register rotation. */ - regnum = VP16_REGNUM - + ((regnum - VP16_REGNUM) + rrb_pr) % 48; + regnum = VP16_REGNUM + ((regnum - VP16_REGNUM) + rrb_pr) % 48; } - prN_val = extract_bit_field ((unsigned char *) pr_valuep, - regnum - VP0_REGNUM, 1); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val); + prN = extract_bit_field (value_contents_all (pr_val), + regnum - VP0_REGNUM, 1); + return frame_unwind_got_constant (this_frame, regnum, prN); } + else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM) { - char unat_valuep[MAX_REGISTER_SIZE]; - int unat_optim; - int unat_realnum; - enum lval_type unat_lval; - CORE_ADDR unat_addr; - ULONGEST unatN_val; - ia64_frame_prev_register (next_frame, this_cache, IA64_UNAT_REGNUM, - &unat_optim, &unat_lval, &unat_addr, &unat_realnum, unat_valuep); - unatN_val = extract_bit_field ((unsigned char *) unat_valuep, - regnum - IA64_NAT0_REGNUM, 1); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), - unatN_val); + struct value *unat_val; + ULONGEST unatN; + unat_val = ia64_frame_prev_register (this_frame, this_cache, + IA64_UNAT_REGNUM); + unatN = extract_bit_field (value_contents_all (unat_val), + regnum - IA64_NAT0_REGNUM, 1); + return frame_unwind_got_constant (this_frame, regnum, unatN); } + else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM) { int natval = 0; @@ -1726,8 +2006,8 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache, interested in. */ CORE_ADDR gr_addr; - gr_addr = cache->saved_regs[regnum - IA64_NAT0_REGNUM - + IA64_GR0_REGNUM]; + gr_addr = cache->saved_regs[regnum - IA64_NAT0_REGNUM + IA64_GR0_REGNUM]; + if (gr_addr != 0) { /* Compute address of nat collection bits. */ @@ -1735,130 +2015,126 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache, CORE_ADDR bsp; 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. */ - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - bsp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + bsp = extract_unsigned_integer (buf, 8, byte_order); if (nat_addr >= bsp) { - frame_unwind_register (next_frame, IA64_RNAT_REGNUM, buf); - nat_collection = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_RNAT_REGNUM, buf); + nat_collection = extract_unsigned_integer (buf, 8, byte_order); } else - nat_collection = read_memory_integer (nat_addr, 8); + nat_collection = read_memory_integer (nat_addr, 8, byte_order); nat_bit = (gr_addr >> 3) & 0x3f; natval = (nat_collection >> nat_bit) & 1; } - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), natval); + return frame_unwind_got_constant (this_frame, regnum, natval); } + else if (regnum == IA64_IP_REGNUM) { CORE_ADDR pc = 0; CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM]; if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM)); - pc = extract_unsigned_integer (buf, 8); - } + { + read_memory (addr, buf, register_size (gdbarch, IA64_IP_REGNUM)); + pc = extract_unsigned_integer (buf, 8, byte_order); + } else if (cache->frameless) { - frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf); - pc = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BR0_REGNUM, buf); + pc = extract_unsigned_integer (buf, 8, byte_order); } pc &= ~0xf; - store_unsigned_integer (valuep, 8, pc); + return frame_unwind_got_constant (this_frame, regnum, pc); } + else if (regnum == IA64_PSR_REGNUM) { - /* We don't know how to get the complete previous PSR, but we need it for - the slot information when we unwind the pc (pc is formed of IP register - plus slot information from PSR). To get the previous slot information, - we mask it off the return address. */ + /* We don't know how to get the complete previous PSR, but we need it + for the slot information when we unwind the pc (pc is formed of IP + register plus slot information from PSR). To get the previous + slot information, we mask it off the return address. */ ULONGEST slot_num = 0; - CORE_ADDR pc= 0; + CORE_ADDR pc = 0; CORE_ADDR psr = 0; CORE_ADDR addr = cache->saved_regs[IA64_VRAP_REGNUM]; - frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf); - psr = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_PSR_REGNUM, buf); + psr = extract_unsigned_integer (buf, 8, byte_order); if (addr != 0) { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM)); - pc = extract_unsigned_integer (buf, 8); + read_memory (addr, buf, register_size (gdbarch, IA64_IP_REGNUM)); + pc = extract_unsigned_integer (buf, 8, byte_order); } else if (cache->frameless) { - CORE_ADDR pc; - frame_unwind_register (next_frame, IA64_BR0_REGNUM, buf); - pc = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BR0_REGNUM, buf); + pc = extract_unsigned_integer (buf, 8, byte_order); } psr &= ~(3LL << 41); slot_num = pc & 0x3LL; psr |= (CORE_ADDR)slot_num << 41; - store_unsigned_integer (valuep, 8, psr); + return frame_unwind_got_constant (this_frame, regnum, psr); } + else if (regnum == IA64_BR0_REGNUM) { - CORE_ADDR br0 = 0; CORE_ADDR addr = cache->saved_regs[IA64_BR0_REGNUM]; + if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, buf, register_size (current_gdbarch, IA64_BR0_REGNUM)); - br0 = extract_unsigned_integer (buf, 8); - } - store_unsigned_integer (valuep, 8, br0); + return frame_unwind_got_memory (this_frame, regnum, addr); + + return frame_unwind_got_constant (this_frame, regnum, 0); } - else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) || - (regnum >= V32_REGNUM && regnum <= V127_REGNUM)) + + else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) + || (regnum >= V32_REGNUM && regnum <= V127_REGNUM)) { CORE_ADDR addr = 0; + if (regnum >= V32_REGNUM) regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM); addr = cache->saved_regs[regnum]; if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); - } - else if (cache->frameless) + return frame_unwind_got_memory (this_frame, regnum, addr); + + if (cache->frameless) { - char r_valuep[MAX_REGISTER_SIZE]; - int r_optim; - int r_realnum; - enum lval_type r_lval; - CORE_ADDR r_addr; - CORE_ADDR prev_cfm, prev_bsp, prev_bof; - CORE_ADDR addr = 0; + struct value *reg_val; + CORE_ADDR prev_cfm, prev_bsp, prev_bof; + + /* FIXME: brobecker/2008-05-01: Doesn't this seem redundant + with the same code above? */ if (regnum >= V32_REGNUM) regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM); - ia64_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM, - &r_optim, &r_lval, &r_addr, &r_realnum, r_valuep); - prev_cfm = extract_unsigned_integer (r_valuep, 8); - ia64_frame_prev_register (next_frame, this_cache, IA64_BSP_REGNUM, - &r_optim, &r_lval, &r_addr, &r_realnum, r_valuep); - prev_bsp = extract_unsigned_integer (r_valuep, 8); + reg_val = ia64_frame_prev_register (this_frame, this_cache, + IA64_CFM_REGNUM); + prev_cfm = extract_unsigned_integer (value_contents_all (reg_val), + 8, byte_order); + reg_val = ia64_frame_prev_register (this_frame, this_cache, + IA64_BSP_REGNUM); + prev_bsp = extract_unsigned_integer (value_contents_all (reg_val), + 8, byte_order); prev_bof = rse_address_add (prev_bsp, -(prev_cfm & 0x7f)); addr = rse_address_add (prev_bof, (regnum - IA64_GR32_REGNUM)); - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); + return frame_unwind_got_memory (this_frame, regnum, addr); } + + return frame_unwind_got_constant (this_frame, regnum, 0); } - else + + else /* All other registers. */ { CORE_ADDR addr = 0; + if (IA64_FR32_REGNUM <= regnum && regnum <= IA64_FR127_REGNUM) { /* Fetch floating point register rename base from current @@ -1874,152 +2150,143 @@ ia64_frame_prev_register (struct frame_info *next_frame, void **this_cache, /* If we have stored a memory address, access the register. */ addr = cache->saved_regs[regnum]; if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); - } + return frame_unwind_got_memory (this_frame, regnum, addr); /* Otherwise, punt and get the current value of the register. */ else - frame_unwind_register (next_frame, regnum, valuep); + return frame_unwind_got_register (this_frame, regnum, regnum); } - - if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, - "regular prev register <%d> <%s> is %lx\n", regnum, - (((unsigned) regnum <= IA64_NAT127_REGNUM) - ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8)); } static const struct frame_unwind ia64_frame_unwind = { NORMAL_FRAME, + default_frame_unwind_stop_reason, &ia64_frame_this_id, - &ia64_frame_prev_register + &ia64_frame_prev_register, + NULL, + default_frame_sniffer }; -static const struct frame_unwind * -ia64_frame_sniffer (struct frame_info *next_frame) -{ - return &ia64_frame_unwind; -} - /* Signal trampolines. */ static void -ia64_sigtramp_frame_init_saved_regs (struct ia64_frame_cache *cache) +ia64_sigtramp_frame_init_saved_regs (struct frame_info *this_frame, + struct ia64_frame_cache *cache) { - if (SIGCONTEXT_REGISTER_ADDRESS) + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (tdep->sigcontext_register_address) { int regno; - cache->saved_regs[IA64_VRAP_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_IP_REGNUM); - cache->saved_regs[IA64_CFM_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CFM_REGNUM); - cache->saved_regs[IA64_PSR_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PSR_REGNUM); - cache->saved_regs[IA64_BSP_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_BSP_REGNUM); - cache->saved_regs[IA64_RNAT_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_RNAT_REGNUM); - cache->saved_regs[IA64_CCV_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CCV_REGNUM); - cache->saved_regs[IA64_UNAT_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_UNAT_REGNUM); - cache->saved_regs[IA64_FPSR_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_FPSR_REGNUM); - cache->saved_regs[IA64_PFS_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PFS_REGNUM); - cache->saved_regs[IA64_LC_REGNUM] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_LC_REGNUM); + cache->saved_regs[IA64_VRAP_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_IP_REGNUM); + cache->saved_regs[IA64_CFM_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_CFM_REGNUM); + cache->saved_regs[IA64_PSR_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_PSR_REGNUM); + cache->saved_regs[IA64_BSP_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_BSP_REGNUM); + cache->saved_regs[IA64_RNAT_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_RNAT_REGNUM); + cache->saved_regs[IA64_CCV_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_CCV_REGNUM); + cache->saved_regs[IA64_UNAT_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_UNAT_REGNUM); + cache->saved_regs[IA64_FPSR_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_FPSR_REGNUM); + cache->saved_regs[IA64_PFS_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_PFS_REGNUM); + cache->saved_regs[IA64_LC_REGNUM] + = tdep->sigcontext_register_address (gdbarch, cache->base, + IA64_LC_REGNUM); + for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++) cache->saved_regs[regno] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno); + tdep->sigcontext_register_address (gdbarch, cache->base, regno); for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++) cache->saved_regs[regno] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno); + tdep->sigcontext_register_address (gdbarch, cache->base, regno); for (regno = IA64_FR2_REGNUM; regno <= IA64_FR31_REGNUM; regno++) cache->saved_regs[regno] = - SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno); + tdep->sigcontext_register_address (gdbarch, cache->base, regno); } } static struct ia64_frame_cache * -ia64_sigtramp_frame_cache (struct frame_info *next_frame, void **this_cache) +ia64_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct ia64_frame_cache *cache; - CORE_ADDR addr; - char buf[8]; - int i; + gdb_byte buf[8]; if (*this_cache) - return *this_cache; + return (struct ia64_frame_cache *) *this_cache; cache = ia64_alloc_frame_cache (); - frame_unwind_register (next_frame, sp_regnum, buf); + get_frame_register (this_frame, sp_regnum, buf); /* Note that frame size is hard-coded below. We cannot calculate it via prologue examination. */ - cache->base = extract_unsigned_integer (buf, 8) + 16; + cache->base = extract_unsigned_integer (buf, 8, byte_order) + 16; - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - cache->bsp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + cache->bsp = extract_unsigned_integer (buf, 8, byte_order); - frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf); - cache->cfm = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_CFM_REGNUM, buf); + cache->cfm = extract_unsigned_integer (buf, 8, byte_order); cache->sof = cache->cfm & 0x7f; - ia64_sigtramp_frame_init_saved_regs (cache); + ia64_sigtramp_frame_init_saved_regs (this_frame, cache); *this_cache = cache; return cache; } static void -ia64_sigtramp_frame_this_id (struct frame_info *next_frame, - void **this_cache, struct frame_id *this_id) +ia64_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) { + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct ia64_frame_cache *cache = - ia64_sigtramp_frame_cache (next_frame, this_cache); + ia64_sigtramp_frame_cache (this_frame, this_cache); - (*this_id) = frame_id_build_special (cache->base, frame_pc_unwind (next_frame), cache->bsp); + (*this_id) = frame_id_build_special (cache->base, + get_frame_pc (this_frame), + cache->bsp); if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, - "sigtramp frame id: code %lx, stack %lx, special %lx, next_frame %p\n", - this_id->code_addr, this_id->stack_addr, cache->bsp, next_frame); + "sigtramp frame id: code %s, stack %s, " + "special %s, this_frame %s\n", + paddress (gdbarch, this_id->code_addr), + paddress (gdbarch, this_id->stack_addr), + paddress (gdbarch, cache->bsp), + host_address_to_string (this_frame)); } -static void -ia64_sigtramp_frame_prev_register (struct frame_info *next_frame, - void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *valuep) +static struct value * +ia64_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) { - char dummy_valp[MAX_REGISTER_SIZE]; - char buf[MAX_REGISTER_SIZE]; - struct ia64_frame_cache *cache = - ia64_sigtramp_frame_cache (next_frame, this_cache); + ia64_sigtramp_frame_cache (this_frame, this_cache); gdb_assert (regnum >= 0); if (!target_has_registers) - error ("No registers."); + error (_("No registers.")); - *optimizedp = 0; - *addrp = 0; - *lvalp = not_lval; - *realnump = -1; - - /* Rather than check each time if valuep is non-null, supply a dummy buffer - when valuep is not supplied. */ - if (!valuep) - valuep = dummy_valp; - - memset (valuep, 0, register_size (current_gdbarch, regnum)); - if (regnum == IA64_IP_REGNUM) { CORE_ADDR pc = 0; @@ -2027,73 +2294,72 @@ ia64_sigtramp_frame_prev_register (struct frame_info *next_frame, if (addr != 0) { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM)); - pc = extract_unsigned_integer (buf, 8); + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + pc = read_memory_unsigned_integer (addr, 8, byte_order); } pc &= ~0xf; - store_unsigned_integer (valuep, 8, pc); + return frame_unwind_got_constant (this_frame, regnum, pc); } - else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) || - (regnum >= V32_REGNUM && regnum <= V127_REGNUM)) + + else if ((regnum >= IA64_GR32_REGNUM && regnum <= IA64_GR127_REGNUM) + || (regnum >= V32_REGNUM && regnum <= V127_REGNUM)) { CORE_ADDR addr = 0; + if (regnum >= V32_REGNUM) regnum = IA64_GR32_REGNUM + (regnum - V32_REGNUM); addr = cache->saved_regs[regnum]; if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); - } + return frame_unwind_got_memory (this_frame, regnum, addr); + + return frame_unwind_got_constant (this_frame, regnum, 0); } - else + + else /* All other registers not listed above. */ { - /* All other registers not listed above. */ CORE_ADDR addr = cache->saved_regs[regnum]; + if (addr != 0) - { - *lvalp = lval_memory; - *addrp = addr; - read_memory (addr, valuep, register_size (current_gdbarch, regnum)); - } - } + return frame_unwind_got_memory (this_frame, regnum, addr); - if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, - "sigtramp prev register <%s> is %lx\n", - (((unsigned) regnum <= IA64_NAT127_REGNUM) - ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8)); + return frame_unwind_got_constant (this_frame, regnum, 0); + } } -static const struct frame_unwind ia64_sigtramp_frame_unwind = +static int +ia64_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); + if (tdep->pc_in_sigtramp) + { + CORE_ADDR pc = get_frame_pc (this_frame); + + if (tdep->pc_in_sigtramp (pc)) + return 1; + } + + return 0; +} + +static const struct frame_unwind ia64_sigtramp_frame_unwind = { SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, ia64_sigtramp_frame_this_id, - ia64_sigtramp_frame_prev_register + ia64_sigtramp_frame_prev_register, + NULL, + ia64_sigtramp_frame_sniffer }; -static const struct frame_unwind * -ia64_sigtramp_frame_sniffer (struct frame_info *next_frame) -{ - char *name; - CORE_ADDR pc = frame_pc_unwind (next_frame); - - find_pc_partial_function (pc, &name, NULL, NULL); - if (PC_IN_SIGTRAMP (pc, name)) - return &ia64_sigtramp_frame_unwind; - - return NULL; -} static CORE_ADDR -ia64_frame_base_address (struct frame_info *next_frame, void **this_cache) +ia64_frame_base_address (struct frame_info *this_frame, void **this_cache) { - struct ia64_frame_cache *cache = - ia64_frame_cache (next_frame, this_cache); + struct ia64_frame_cache *cache = ia64_frame_cache (this_frame, this_cache); return cache->base; } @@ -2133,8 +2399,8 @@ ia64_rse_skip_regs (uint64_t addr, long num_regs) return addr + ((num_regs + delta/0x3f) << 3); } -/* Gdb libunwind-frame callback function to convert from an ia64 gdb register - number to a libunwind register number. */ +/* Gdb ia64-libunwind-tdep callback function to convert from an ia64 gdb + register number to a libunwind register number. */ static int ia64_gdb2uw_regnum (int regnum) { @@ -2166,8 +2432,8 @@ ia64_gdb2uw_regnum (int regnum) return -1; } -/* Gdb libunwind-frame callback function to convert from a libunwind register - number to a ia64 gdb register number. */ +/* Gdb ia64-libunwind-tdep callback function to convert from a libunwind + register number to a ia64 gdb register number. */ static int ia64_uw2gdb_regnum (int uw_regnum) { @@ -2197,137 +2463,154 @@ ia64_uw2gdb_regnum (int uw_regnum) return -1; } -/* Gdb libunwind-frame callback function to reveal if register is a float - register or not. */ +/* Gdb ia64-libunwind-tdep callback function to reveal if register is + a float register or not. */ static int ia64_is_fpreg (int uw_regnum) { return unw_is_fpreg (uw_regnum); } - + /* Libunwind callback accessor function for general registers. */ static int ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val, int write, void *arg) { int regnum = ia64_uw2gdb_regnum (uw_regnum); - unw_word_t bsp, sof, sol, cfm, psr, ip; - struct frame_info *next_frame = arg; - long new_sof, old_sof; - char buf[MAX_REGISTER_SIZE]; + unw_word_t bsp, sof, cfm, psr, ip; + struct frame_info *this_frame = (struct frame_info *) arg; + struct gdbarch *gdbarch = get_frame_arch (this_frame); - if (write) + /* We never call any libunwind routines that need to write registers. */ + gdb_assert (!write); + + switch (uw_regnum) { - if (regnum < 0) - /* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */ - return 0; - - switch (uw_regnum) - { - case UNW_REG_IP: - ia64_write_pc (*val, inferior_ptid); - break; + case UNW_REG_IP: + /* Libunwind expects to see the pc value which means the slot number + from the psr must be merged with the ip word address. */ + ip = get_frame_register_unsigned (this_frame, IA64_IP_REGNUM); + psr = get_frame_register_unsigned (this_frame, IA64_PSR_REGNUM); + *val = ip | ((psr >> 41) & 0x3); + break; + + case UNW_IA64_AR_BSP: + /* Libunwind expects to see the beginning of the current + register frame so we must account for the fact that + ptrace() will return a value for bsp that points *after* + the current register frame. */ + bsp = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM); + cfm = get_frame_register_unsigned (this_frame, IA64_CFM_REGNUM); + sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm); + *val = ia64_rse_skip_regs (bsp, -sof); + break; - case UNW_IA64_AR_BSPSTORE: - write_register (IA64_BSP_REGNUM, *val); - break; - - 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; - - 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; - - default: - write_register (regnum, *val); - break; - } - if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, - " access_reg: to cache: %4s=%016lx\n", - (((unsigned) regnum <= IA64_NAT127_REGNUM) - ? ia64_register_names[regnum] : "r??"), *val); + case UNW_IA64_AR_BSPSTORE: + /* Libunwind wants bspstore to be after the current register frame. + This is what ptrace() and gdb treats as the regular bsp value. */ + *val = get_frame_register_unsigned (this_frame, IA64_BSP_REGNUM); + break; + + default: + /* For all other registers, just unwind the value directly. */ + *val = get_frame_register_unsigned (this_frame, regnum); + break; } - else + + if (gdbarch_debug >= 1) + fprintf_unfiltered (gdb_stdlog, + " access_reg: from cache: %4s=%s\n", + (((unsigned) regnum <= IA64_NAT127_REGNUM) + ? ia64_register_names[regnum] : "r??"), + paddress (gdbarch, *val)); + return 0; +} + +/* Libunwind callback accessor function for floating-point registers. */ +static int +ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, + unw_fpreg_t *val, int write, void *arg) +{ + int regnum = ia64_uw2gdb_regnum (uw_regnum); + struct frame_info *this_frame = (struct frame_info *) arg; + + /* We never call any libunwind routines that need to write registers. */ + gdb_assert (!write); + + get_frame_register (this_frame, regnum, (gdb_byte *) val); + + return 0; +} + +/* Libunwind callback accessor function for top-level rse registers. */ +static int +ia64_access_rse_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, + unw_word_t *val, int write, void *arg) +{ + int regnum = ia64_uw2gdb_regnum (uw_regnum); + unw_word_t bsp, sof, cfm, psr, ip; + struct regcache *regcache = (struct regcache *) arg; + struct gdbarch *gdbarch = regcache->arch (); + + /* We never call any libunwind routines that need to write registers. */ + gdb_assert (!write); + + switch (uw_regnum) { - switch (uw_regnum) - { - case UNW_REG_IP: - /* Libunwind expects to see the pc value which means the slot number - from the psr must be merged with the ip word address. */ - frame_unwind_register (next_frame, IA64_IP_REGNUM, buf); - ip = extract_unsigned_integer (buf, 8); - frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf); - psr = extract_unsigned_integer (buf, 8); - *val = ip | ((psr >> 41) & 0x3); - break; + case UNW_REG_IP: + /* Libunwind expects to see the pc value which means the slot number + from the psr must be merged with the ip word address. */ + regcache_cooked_read_unsigned (regcache, IA64_IP_REGNUM, &ip); + regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr); + *val = ip | ((psr >> 41) & 0x3); + break; - case UNW_IA64_AR_BSP: - /* Libunwind expects to see the beginning of the current register - frame so we must account for the fact that ptrace() will return a value - for bsp that points *after* the current register frame. */ - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - bsp = extract_unsigned_integer (buf, 8); - frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf); - cfm = extract_unsigned_integer (buf, 8); - sof = (cfm & 0x7f); - *val = ia64_rse_skip_regs (bsp, -sof); - break; + case UNW_IA64_AR_BSP: + /* Libunwind expects to see the beginning of the current + register frame so we must account for the fact that + ptrace() will return a value for bsp that points *after* + the current register frame. */ + regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); + regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); + sof = (cfm & 0x7f); + *val = ia64_rse_skip_regs (bsp, -sof); + break; - case UNW_IA64_AR_BSPSTORE: - /* Libunwind wants bspstore to be after the current register frame. - This is what ptrace() and gdb treats as the regular bsp value. */ - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - *val = extract_unsigned_integer (buf, 8); - break; + case UNW_IA64_AR_BSPSTORE: + /* Libunwind wants bspstore to be after the current register frame. + This is what ptrace() and gdb treats as the regular bsp value. */ + regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, val); + break; - default: - /* For all other registers, just unwind the value directly. */ - frame_unwind_register (next_frame, regnum, buf); - *val = extract_unsigned_integer (buf, 8); - break; - } - - if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, - " access_reg: from cache: %4s=%016lx\n", - (((unsigned) regnum <= IA64_NAT127_REGNUM) - ? ia64_register_names[regnum] : "r??"), *val); + default: + /* For all other registers, just unwind the value directly. */ + regcache_cooked_read_unsigned (regcache, regnum, val); + break; } + + if (gdbarch_debug >= 1) + fprintf_unfiltered (gdb_stdlog, + " access_rse_reg: from cache: %4s=%s\n", + (((unsigned) regnum <= IA64_NAT127_REGNUM) + ? ia64_register_names[regnum] : "r??"), + paddress (gdbarch, *val)); + return 0; } -/* Libunwind callback accessor function for floating-point registers. */ +/* Libunwind callback accessor function for top-level fp registers. */ static int -ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val, - int write, void *arg) +ia64_access_rse_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, + unw_fpreg_t *val, int write, void *arg) { int regnum = ia64_uw2gdb_regnum (uw_regnum); + struct regcache *regcache = (struct regcache *) arg; - if (write) - regcache_cooked_write (current_regcache, regnum, (char *) val); - else - regcache_cooked_read (current_regcache, regnum, (char *) val); + /* We never call any libunwind routines that need to write registers. */ + gdb_assert (!write); + + regcache->cooked_read (regnum, (gdb_byte *) val); + return 0; } @@ -2337,49 +2620,58 @@ ia64_access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write, void *arg) { + if (addr - KERNEL_START < ktab_size) + { + unw_word_t *laddr = (unw_word_t*) ((char *) ktab + + (addr - KERNEL_START)); + + if (write) + *laddr = *val; + else + *val = *laddr; + return 0; + } + /* XXX do we need to normalize byte-order here? */ if (write) - return target_write_memory (addr, (char *) val, sizeof (unw_word_t)); + return target_write_memory (addr, (gdb_byte *) val, sizeof (unw_word_t)); else - return target_read_memory (addr, (char *) val, sizeof (unw_word_t)); + return target_read_memory (addr, (gdb_byte *) val, sizeof (unw_word_t)); } /* Call low-level function to access the kernel unwind table. */ -static int -getunwind_table (void *buf, size_t len) +static gdb::optional +getunwind_table () { - LONGEST x; - x = target_read_partial (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL, - buf, 0, len); + /* FIXME drow/2005-09-10: This code used to call + ia64_linux_xfer_unwind_table directly to fetch the unwind table + for the currently running ia64-linux kernel. That data should + come from the core file and be accessed via the auxv vector; if + we want to preserve fall back to the running kernel's table, then + we should find a way to override the corefile layer's + xfer_partial method. */ - return (int)x; + return target_read_alloc (current_top_target (), TARGET_OBJECT_UNWIND_TABLE, + NULL); } - + /* Get the kernel unwind table. */ static int get_kernel_table (unw_word_t ip, unw_dyn_info_t *di) { - size_t size; - struct ia64_table_entry - { - uint64_t start_offset; - uint64_t end_offset; - uint64_t info_offset; - }; - static struct ia64_table_entry *ktab = NULL, *etab; + static struct ia64_table_entry *etab; - if (!ktab) + if (!ktab) { - size = getunwind_table (NULL, 0); - if ((int)size < 0) + ktab_buf = getunwind_table (); + if (!ktab_buf) return -UNW_ENOINFO; - ktab = xmalloc (size); - getunwind_table (ktab, size); - - /* Determine length of kernel's unwind table and relocate - it's entries. */ + + ktab = (struct ia64_table_entry *) ktab_buf->data (); + ktab_size = ktab_buf->size (); + for (etab = ktab; etab->start_offset; ++etab) - etab->info_offset += (uint64_t) ktab; + etab->info_offset += KERNEL_START; } if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset) @@ -2396,9 +2688,11 @@ get_kernel_table (unw_word_t ip, unw_dyn_info_t *di) if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, "get_kernel_table: found table `%s': " - "segbase=%lx, length=%lu, gp=%lx\n", - (char *) di->u.ti.name_ptr, di->u.ti.segbase, - di->u.ti.table_len, di->gp); + "segbase=%s, length=%s, gp=%s\n", + (char *) di->u.ti.name_ptr, + hex_string (di->u.ti.segbase), + pulongest (di->u.ti.table_len), + hex_string (di->gp)); return 0; } @@ -2419,7 +2713,7 @@ ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip, ehdr = elf_tdata (bfd)->elf_header; phdr = elf_tdata (bfd)->phdr; - load_base = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); + load_base = objfile->text_section_offset (); for (i = 0; i < ehdr->e_phnum; ++i) { @@ -2440,18 +2734,37 @@ ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip, } } - if (!p_text || !p_unwind - /* Verify that the segment that contains the IP also contains - the static unwind table. If not, we are dealing with - runtime-generated code, for which we have no info here. */ - || (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz) + if (!p_text || !p_unwind) return -UNW_ENOINFO; + /* Verify that the segment that contains the IP also contains + the static unwind table. If not, we may be in the Linux kernel's + DSO gate page in which case the unwind table is another segment. + Otherwise, we are dealing with runtime-generated code, for which we + have no info here. */ segbase = p_text->p_vaddr + load_base; - dip->start_ip = segbase; + if ((p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz) + { + int ok = 0; + for (i = 0; i < ehdr->e_phnum; ++i) + { + if (phdr[i].p_type == PT_LOAD + && (p_unwind->p_vaddr - phdr[i].p_vaddr) < phdr[i].p_memsz) + { + ok = 1; + /* Get the segbase from the section containing the + libunwind table. */ + segbase = phdr[i].p_vaddr + load_base; + } + } + if (!ok) + return -UNW_ENOINFO; + } + + dip->start_ip = p_text->p_vaddr + load_base; dip->end_ip = dip->start_ip + p_text->p_memsz; - dip->gp = FIND_GLOBAL_POINTER (ip); + dip->gp = ia64_find_global_pointer (objfile->arch (), ip); dip->format = UNW_INFO_FORMAT_REMOTE_TABLE; dip->u.rti.name_ptr = (unw_word_t) bfd_get_filename (bfd); dip->u.rti.segbase = segbase; @@ -2480,12 +2793,15 @@ ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, return -UNW_ENOINFO; if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: %lx -> " - "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx," - "length=%lu,data=%p)\n", - ip, (char *)di.u.ti.name_ptr, - di.u.ti.segbase, di.start_ip, di.end_ip, - di.gp, di.u.ti.table_len, di.u.ti.table_data); + fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: %s -> " + "(name=`%s',segbase=%s,start=%s,end=%s,gp=%s," + "length=%s,data=%s)\n", + hex_string (ip), (char *)di.u.ti.name_ptr, + hex_string (di.u.ti.segbase), + hex_string (di.start_ip), hex_string (di.end_ip), + hex_string (di.gp), + pulongest (di.u.ti.table_len), + hex_string ((CORE_ADDR)di.u.ti.table_data)); } else { @@ -2494,12 +2810,15 @@ ia64_find_proc_info_x (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, return ret; if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: %lx -> " - "(name=`%s',segbase=%lx,start=%lx,end=%lx,gp=%lx," - "length=%lu,data=%lx)\n", - ip, (char *)di.u.rti.name_ptr, - di.u.rti.segbase, di.start_ip, di.end_ip, - di.gp, di.u.rti.table_len, di.u.rti.table_data); + fprintf_unfiltered (gdb_stdlog, "ia64_find_proc_info_x: %s -> " + "(name=`%s',segbase=%s,start=%s,end=%s,gp=%s," + "length=%s,data=%s)\n", + hex_string (ip), (char *)di.u.rti.name_ptr, + hex_string (di.u.rti.segbase), + hex_string (di.start_ip), hex_string (di.end_ip), + hex_string (di.gp), + pulongest (di.u.rti.table_len), + hex_string (di.u.rti.table_data)); } ret = libunwind_search_unwind_table (&as, ip, &di, pi, need_unwind_info, @@ -2526,7 +2845,6 @@ ia64_get_dyn_info_list (unw_addr_space_t as, unw_word_t *dilap, void *arg) { struct obj_section *text_sec; - struct objfile *objfile; unw_word_t ip, addr; unw_dyn_info_t di; int ret; @@ -2534,12 +2852,12 @@ ia64_get_dyn_info_list (unw_addr_space_t as, if (!libunwind_is_initialized ()) return -UNW_ENOINFO; - for (objfile = object_files; objfile; objfile = objfile->next) + for (objfile *objfile : current_program_space->objfiles ()) { void *buf = NULL; text_sec = objfile->sections + SECT_OFF_TEXT (objfile); - ip = text_sec->addr; + ip = obj_section_addr (text_sec); ret = ia64_find_unwind_table (objfile, ip, &di, &buf); if (ret >= 0) { @@ -2552,9 +2870,9 @@ ia64_get_dyn_info_list (unw_addr_space_t as, if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, "dynamic unwind table in objfile %s " - "at %lx (gp=%lx)\n", + "at %s (gp=%s)\n", bfd_get_filename (objfile->obfd), - addr, di.gp); + hex_string (addr), hex_string (di.gp)); *dilap = addr; return 0; } @@ -2567,35 +2885,47 @@ ia64_get_dyn_info_list (unw_addr_space_t as, /* Frame interface functions for libunwind. */ static void -ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache, - struct frame_id *this_id) +ia64_libunwind_frame_this_id (struct frame_info *this_frame, void **this_cache, + struct frame_id *this_id) { - char buf[8]; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct frame_id id = outer_frame_id; + gdb_byte buf[8]; CORE_ADDR bsp; - struct frame_id id; - libunwind_frame_this_id (next_frame, this_cache, &id); + libunwind_frame_this_id (this_frame, this_cache, &id); + if (frame_id_eq (id, outer_frame_id)) + { + (*this_id) = outer_frame_id; + return; + } - /* We must add the bsp as the special address for frame comparison purposes. */ - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - bsp = extract_unsigned_integer (buf, 8); + /* We must add the bsp as the special address for frame comparison + purposes. */ + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + bsp = extract_unsigned_integer (buf, 8, byte_order); (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp); if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, - "libunwind frame id: code %lx, stack %lx, special %lx, next_frame %p\n", - id.code_addr, id.stack_addr, bsp, next_frame); + "libunwind frame id: code %s, stack %s, " + "special %s, this_frame %s\n", + paddress (gdbarch, id.code_addr), + paddress (gdbarch, id.stack_addr), + paddress (gdbarch, bsp), + host_address_to_string (this_frame)); } -static void -ia64_libunwind_frame_prev_register (struct frame_info *next_frame, - void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, void *valuep) +static struct value * +ia64_libunwind_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) { int reg = regnum; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct value *val; if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM) reg = IA64_PR_REGNUM; @@ -2603,8 +2933,7 @@ ia64_libunwind_frame_prev_register (struct frame_info *next_frame, reg = IA64_UNAT_REGNUM; /* Let libunwind do most of the work. */ - libunwind_frame_prev_register (next_frame, this_cache, reg, - optimizedp, lvalp, addrp, realnump, valuep); + val = libunwind_frame_prev_register (this_frame, this_cache, reg); if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM) { @@ -2614,79 +2943,165 @@ ia64_libunwind_frame_prev_register (struct frame_info *next_frame, { int rrb_pr = 0; ULONGEST cfm; - unsigned char buf[MAX_REGISTER_SIZE]; /* Fetch predicate register rename base from current frame marker for this frame. */ - frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf); - cfm = extract_unsigned_integer (buf, 8); + cfm = get_frame_register_unsigned (this_frame, IA64_CFM_REGNUM); rrb_pr = (cfm >> 32) & 0x3f; /* Adjust the register number to account for register rotation. */ - regnum = VP16_REGNUM - + ((regnum - VP16_REGNUM) + rrb_pr) % 48; + regnum = VP16_REGNUM + ((regnum - VP16_REGNUM) + rrb_pr) % 48; } - prN_val = extract_bit_field ((unsigned char *) valuep, + prN_val = extract_bit_field (value_contents_all (val), regnum - VP0_REGNUM, 1); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val); + return frame_unwind_got_constant (this_frame, regnum, prN_val); } + else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM) { ULONGEST unatN_val; - unatN_val = extract_bit_field ((unsigned char *) valuep, - regnum - IA64_NAT0_REGNUM, 1); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), - unatN_val); + unatN_val = extract_bit_field (value_contents_all (val), + regnum - IA64_NAT0_REGNUM, 1); + return frame_unwind_got_constant (this_frame, regnum, unatN_val); } + else if (regnum == IA64_BSP_REGNUM) { - char cfm_valuep[MAX_REGISTER_SIZE]; - int cfm_optim; - int cfm_realnum; - enum lval_type cfm_lval; - CORE_ADDR cfm_addr; - CORE_ADDR bsp, prev_cfm, prev_bsp; - - /* We want to calculate the previous bsp as the end of the previous register stack frame. - This corresponds to what the hardware bsp register will be if we pop the frame - back which is why we might have been called. We know that libunwind will pass us back - the beginning of the current frame so we should just add sof to it. */ - prev_bsp = extract_unsigned_integer (valuep, 8); - libunwind_frame_prev_register (next_frame, this_cache, IA64_CFM_REGNUM, - &cfm_optim, &cfm_lval, &cfm_addr, &cfm_realnum, cfm_valuep); - prev_cfm = extract_unsigned_integer (cfm_valuep, 8); + struct value *cfm_val; + CORE_ADDR prev_bsp, prev_cfm; + + /* We want to calculate the previous bsp as the end of the previous + register stack frame. This corresponds to what the hardware bsp + register will be if we pop the frame back which is why we might + have been called. We know that libunwind will pass us back the + beginning of the current frame so we should just add sof to it. */ + prev_bsp = extract_unsigned_integer (value_contents_all (val), + 8, byte_order); + cfm_val = libunwind_frame_prev_register (this_frame, this_cache, + IA64_CFM_REGNUM); + prev_cfm = extract_unsigned_integer (value_contents_all (cfm_val), + 8, byte_order); prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f)); - store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), - prev_bsp); + return frame_unwind_got_constant (this_frame, regnum, prev_bsp); } + else + return val; +} - if (gdbarch_debug >= 1) - fprintf_unfiltered (gdb_stdlog, - "libunwind prev register <%s> is %lx\n", - (((unsigned) regnum <= IA64_NAT127_REGNUM) - ? ia64_register_names[regnum] : "r??"), extract_unsigned_integer (valuep, 8)); +static int +ia64_libunwind_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + if (libunwind_is_initialized () + && libunwind_frame_sniffer (self, this_frame, this_cache)) + return 1; + + return 0; } static const struct frame_unwind ia64_libunwind_frame_unwind = { NORMAL_FRAME, + default_frame_unwind_stop_reason, ia64_libunwind_frame_this_id, - ia64_libunwind_frame_prev_register + ia64_libunwind_frame_prev_register, + NULL, + ia64_libunwind_frame_sniffer, + libunwind_frame_dealloc_cache }; -static const struct frame_unwind * -ia64_libunwind_frame_sniffer (struct frame_info *next_frame) +static void +ia64_libunwind_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, + struct frame_id *this_id) { - if (libunwind_is_initialized () && libunwind_frame_sniffer (next_frame)) - return &ia64_libunwind_frame_unwind; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[8]; + CORE_ADDR bsp; + struct frame_id id = outer_frame_id; + + libunwind_frame_this_id (this_frame, this_cache, &id); + if (frame_id_eq (id, outer_frame_id)) + { + (*this_id) = outer_frame_id; + return; + } + + /* We must add the bsp as the special address for frame comparison + purposes. */ + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + bsp = extract_unsigned_integer (buf, 8, byte_order); + + /* For a sigtramp frame, we don't make the check for previous ip being 0. */ + (*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp); - return NULL; + if (gdbarch_debug >= 1) + fprintf_unfiltered (gdb_stdlog, + "libunwind sigtramp frame id: code %s, " + "stack %s, special %s, this_frame %s\n", + paddress (gdbarch, id.code_addr), + paddress (gdbarch, id.stack_addr), + paddress (gdbarch, bsp), + host_address_to_string (this_frame)); +} + +static struct value * +ia64_libunwind_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + struct value *prev_ip_val; + CORE_ADDR prev_ip; + + /* If the previous frame pc value is 0, then we want to use the SIGCONTEXT + method of getting previous registers. */ + prev_ip_val = libunwind_frame_prev_register (this_frame, this_cache, + IA64_IP_REGNUM); + prev_ip = extract_unsigned_integer (value_contents_all (prev_ip_val), + 8, byte_order); + + if (prev_ip == 0) + { + void *tmp_cache = NULL; + return ia64_sigtramp_frame_prev_register (this_frame, &tmp_cache, + regnum); + } + else + return ia64_libunwind_frame_prev_register (this_frame, this_cache, regnum); } +static int +ia64_libunwind_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_cache) +{ + if (libunwind_is_initialized ()) + { + if (libunwind_sigtramp_frame_sniffer (self, this_frame, this_cache)) + return 1; + return 0; + } + else + return ia64_sigtramp_frame_sniffer (self, this_frame, this_cache); +} + +static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind = +{ + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + ia64_libunwind_sigtramp_frame_this_id, + ia64_libunwind_sigtramp_frame_prev_register, + NULL, + ia64_libunwind_sigtramp_frame_sniffer +}; + /* Set of libunwind callback acccessor functions. */ -static unw_accessors_t ia64_unw_accessors = +unw_accessors_t ia64_unw_accessors = { ia64_find_proc_info_x, ia64_put_unwind_info, @@ -2698,25 +3113,47 @@ static unw_accessors_t ia64_unw_accessors = /* get_proc_name */ }; -/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use. */ -static struct libunwind_descr ia64_libunwind_descr = +/* Set of special libunwind callback acccessor functions specific for accessing + the rse registers. At the top of the stack, we want libunwind to figure out + how to read r32 - r127. Though usually they are found sequentially in + memory starting from $bof, this is not always true. */ +unw_accessors_t ia64_unw_rse_accessors = +{ + ia64_find_proc_info_x, + ia64_put_unwind_info, + ia64_get_dyn_info_list, + ia64_access_mem, + ia64_access_rse_reg, + ia64_access_rse_fpreg, + /* resume */ + /* get_proc_name */ +}; + +/* Set of ia64-libunwind-tdep gdb callbacks and data for generic + ia64-libunwind-tdep code to use. */ +struct libunwind_descr ia64_libunwind_descr = { ia64_gdb2uw_regnum, ia64_uw2gdb_regnum, ia64_is_fpreg, &ia64_unw_accessors, + &ia64_unw_rse_accessors, }; #endif /* HAVE_LIBUNWIND_IA64_H */ -/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of - EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc - and TYPE is the type (which is known to be struct, union or array). */ -int -ia64_use_struct_convention (int gcc_p, struct type *type) +static int +ia64_use_struct_convention (struct type *type) { struct type *float_elt_type; + /* Don't use the struct convention for anything but structure, + union, or array types. */ + if (!(type->code () == TYPE_CODE_STRUCT + || type->code () == TYPE_CODE_UNION + || type->code () == TYPE_CODE_ARRAY)) + return 0; + /* HFAs are structures (or arrays) consisting entirely of floating point values of the same length. Up to 8 of these are returned in registers. Don't use the struct convention when this is the @@ -2731,42 +3168,68 @@ ia64_use_struct_convention (int gcc_p, struct type *type) return TYPE_LENGTH (type) > 32; } -void -ia64_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf) +/* Return non-zero if TYPE is a structure or union type. */ + +static int +ia64_struct_type_p (const struct type *type) +{ + return (type->code () == TYPE_CODE_STRUCT + || type->code () == TYPE_CODE_UNION); +} + +static void +ia64_extract_return_value (struct type *type, struct regcache *regcache, + gdb_byte *valbuf) { + struct gdbarch *gdbarch = regcache->arch (); struct type *float_elt_type; float_elt_type = is_float_or_hfa_type (type); if (float_elt_type != NULL) { - char from[MAX_REGISTER_SIZE]; + gdb_byte from[IA64_FP_REGISTER_SIZE]; int offset = 0; int regnum = IA64_FR8_REGNUM; int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type); while (n-- > 0) { - regcache_cooked_read (regcache, regnum, from); - convert_typed_floating (from, builtin_type_ia64_ext, - (char *)valbuf + offset, float_elt_type); + regcache->cooked_read (regnum, from); + target_float_convert (from, ia64_ext_type (gdbarch), + valbuf + offset, float_elt_type); offset += TYPE_LENGTH (float_elt_type); regnum++; } } + else if (!ia64_struct_type_p (type) && TYPE_LENGTH (type) < 8) + { + /* This is an integral value, and its size is less than 8 bytes. + These values are LSB-aligned, so extract the relevant bytes, + and copy them into VALBUF. */ + /* brobecker/2005-12-30: Actually, all integral values are LSB aligned, + so I suppose we should also add handling here for integral values + whose size is greater than 8. But I wasn't able to create such + a type, neither in C nor in Ada, so not worrying about these yet. */ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + ULONGEST val; + + regcache_cooked_read_unsigned (regcache, IA64_GR8_REGNUM, &val); + store_unsigned_integer (valbuf, TYPE_LENGTH (type), byte_order, val); + } else { ULONGEST val; int offset = 0; int regnum = IA64_GR8_REGNUM; - int reglen = TYPE_LENGTH (ia64_register_type (NULL, IA64_GR8_REGNUM)); + int reglen = TYPE_LENGTH (register_type (gdbarch, IA64_GR8_REGNUM)); int n = TYPE_LENGTH (type) / reglen; int m = TYPE_LENGTH (type) % reglen; while (n-- > 0) { - ULONGEST val; - regcache_cooked_read_unsigned (regcache, regnum, &val); - memcpy ((char *)valbuf + offset, &val, reglen); + ULONGEST regval; + regcache_cooked_read_unsigned (regcache, regnum, ®val); + memcpy ((char *)valbuf + offset, ®val, reglen); offset += reglen; regnum++; } @@ -2779,18 +3242,85 @@ ia64_extract_return_value (struct type *type, struct regcache *regcache, void *v } } -CORE_ADDR -ia64_extract_struct_value_address (struct regcache *regcache) +static void +ia64_store_return_value (struct type *type, struct regcache *regcache, + const gdb_byte *valbuf) { - error ("ia64_extract_struct_value_address called and cannot get struct value address"); - return 0; + struct gdbarch *gdbarch = regcache->arch (); + struct type *float_elt_type; + + float_elt_type = is_float_or_hfa_type (type); + if (float_elt_type != NULL) + { + gdb_byte to[IA64_FP_REGISTER_SIZE]; + int offset = 0; + int regnum = IA64_FR8_REGNUM; + int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type); + + while (n-- > 0) + { + target_float_convert (valbuf + offset, float_elt_type, + to, ia64_ext_type (gdbarch)); + regcache->cooked_write (regnum, to); + offset += TYPE_LENGTH (float_elt_type); + regnum++; + } + } + else + { + int offset = 0; + int regnum = IA64_GR8_REGNUM; + int reglen = TYPE_LENGTH (register_type (gdbarch, IA64_GR8_REGNUM)); + int n = TYPE_LENGTH (type) / reglen; + int m = TYPE_LENGTH (type) % reglen; + + while (n-- > 0) + { + ULONGEST val; + memcpy (&val, (char *)valbuf + offset, reglen); + regcache_cooked_write_unsigned (regcache, regnum, val); + offset += reglen; + regnum++; + } + + if (m) + { + ULONGEST val; + memcpy (&val, (char *)valbuf + offset, m); + regcache_cooked_write_unsigned (regcache, regnum, val); + } + } } + +static enum return_value_convention +ia64_return_value (struct gdbarch *gdbarch, struct value *function, + struct type *valtype, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + int struct_return = ia64_use_struct_convention (valtype); + if (writebuf != NULL) + { + gdb_assert (!struct_return); + ia64_store_return_value (valtype, regcache, writebuf); + } + + if (readbuf != NULL) + { + gdb_assert (!struct_return); + ia64_extract_return_value (valtype, regcache, readbuf); + } + + if (struct_return) + return RETURN_VALUE_STRUCT_CONVENTION; + else + return RETURN_VALUE_REGISTER_CONVENTION; +} static int is_float_or_hfa_type_recurse (struct type *t, struct type **etp) { - switch (TYPE_CODE (t)) + switch (t->code ()) { case TYPE_CODE_FLT: if (*etp) @@ -2810,7 +3340,7 @@ is_float_or_hfa_type_recurse (struct type *t, struct type **etp) { int i; - for (i = 0; i < TYPE_NFIELDS (t); i++) + for (i = 0; i < t->num_fields (); i++) if (!is_float_or_hfa_type_recurse (check_typedef (TYPE_FIELD_TYPE (t, i)), etp)) return 0; @@ -2844,7 +3374,7 @@ is_float_or_hfa_type (struct type *t) static int slot_alignment_is_next_even (struct type *t) { - switch (TYPE_CODE (t)) + switch (t->code ()) { case TYPE_CODE_INT: case TYPE_CODE_FLT: @@ -2859,7 +3389,7 @@ slot_alignment_is_next_even (struct type *t) { int i; - for (i = 0; i < TYPE_NFIELDS (t); i++) + for (i = 0; i < t->num_fields (); i++) if (slot_alignment_is_next_even (check_typedef (TYPE_FIELD_TYPE (t, i)))) return 1; @@ -2881,8 +3411,10 @@ slot_alignment_is_next_even (struct type *t) d_un.d_ptr value is the global pointer. */ static CORE_ADDR -generic_elf_find_global_pointer (CORE_ADDR faddr) +ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch, + CORE_ADDR faddr) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct obj_section *faddr_sect; faddr_sect = find_pc_section (faddr); @@ -2898,19 +3430,21 @@ generic_elf_find_global_pointer (CORE_ADDR faddr) if (osect < faddr_sect->objfile->sections_end) { - CORE_ADDR addr; + CORE_ADDR addr, endaddr; - addr = osect->addr; - while (addr < osect->endaddr) + addr = obj_section_addr (osect); + endaddr = obj_section_endaddr (osect); + + while (addr < endaddr) { int status; LONGEST tag; - char buf[8]; + gdb_byte buf[8]; status = target_read_memory (addr, buf, sizeof (buf)); if (status != 0) break; - tag = extract_signed_integer (buf, sizeof (buf)); + tag = extract_signed_integer (buf, sizeof (buf), byte_order); if (tag == DT_PLTGOT) { @@ -2919,9 +3453,10 @@ generic_elf_find_global_pointer (CORE_ADDR faddr) status = target_read_memory (addr + 8, buf, sizeof (buf)); if (status != 0) break; - global_pointer = extract_unsigned_integer (buf, sizeof (buf)); + global_pointer = extract_unsigned_integer (buf, sizeof (buf), + byte_order); - /* The payoff... */ + /* The payoff... */ return global_pointer; } @@ -2935,12 +3470,31 @@ generic_elf_find_global_pointer (CORE_ADDR faddr) return 0; } +/* Attempt to find (and return) the global pointer for the given + function. We first try the find_global_pointer_from_solib routine + from the gdbarch tdep vector, if provided. And if that does not + work, then we try ia64_find_global_pointer_from_dynamic_section. */ + +static CORE_ADDR +ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + CORE_ADDR addr = 0; + + if (tdep->find_global_pointer_from_solib) + addr = tdep->find_global_pointer_from_solib (gdbarch, faddr); + if (addr == 0) + addr = ia64_find_global_pointer_from_dynamic_section (gdbarch, faddr); + return addr; +} + /* Given a function's address, attempt to find (and return) the corresponding (canonical) function descriptor. Return 0 if not found. */ static CORE_ADDR -find_extant_func_descr (CORE_ADDR faddr) +find_extant_func_descr (struct gdbarch *gdbarch, CORE_ADDR faddr) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct obj_section *faddr_sect; /* Return early if faddr is already a function descriptor. */ @@ -2959,19 +3513,21 @@ find_extant_func_descr (CORE_ADDR faddr) if (osect < faddr_sect->objfile->sections_end) { - CORE_ADDR addr; + CORE_ADDR addr, endaddr; + + addr = obj_section_addr (osect); + endaddr = obj_section_endaddr (osect); - addr = osect->addr; - while (addr < osect->endaddr) + while (addr < endaddr) { int status; LONGEST faddr2; - char buf[8]; + gdb_byte buf[8]; status = target_read_memory (addr, buf, sizeof (buf)); if (status != 0) break; - faddr2 = extract_signed_integer (buf, sizeof (buf)); + faddr2 = extract_signed_integer (buf, sizeof (buf), byte_order); if (faddr == faddr2) return addr; @@ -2988,27 +3544,30 @@ find_extant_func_descr (CORE_ADDR faddr) stack using the address at fdaptr. */ static CORE_ADDR -find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr) +find_func_descr (struct regcache *regcache, CORE_ADDR faddr, CORE_ADDR *fdaptr) { + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); CORE_ADDR fdesc; - fdesc = find_extant_func_descr (faddr); + fdesc = find_extant_func_descr (gdbarch, faddr); if (fdesc == 0) { - CORE_ADDR global_pointer; - char buf[16]; + ULONGEST global_pointer; + gdb_byte buf[16]; fdesc = *fdaptr; *fdaptr += 16; - global_pointer = FIND_GLOBAL_POINTER (faddr); + global_pointer = ia64_find_global_pointer (gdbarch, faddr); if (global_pointer == 0) - global_pointer = read_register (IA64_GR1_REGNUM); + regcache_cooked_read_unsigned (regcache, + IA64_GR1_REGNUM, &global_pointer); - store_unsigned_integer (buf, 8, faddr); - store_unsigned_integer (buf + 8, 8, global_pointer); + store_unsigned_integer (buf, 8, byte_order, faddr); + store_unsigned_integer (buf + 8, 8, byte_order, global_pointer); write_memory (fdesc, buf, 16); } @@ -3023,13 +3582,42 @@ static CORE_ADDR ia64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, CORE_ADDR addr, struct target_ops *targ) { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct obj_section *s; + gdb_byte buf[8]; s = find_pc_section (addr); /* check if ADDR points to a function descriptor. */ if (s && strcmp (s->the_bfd_section->name, ".opd") == 0) - return read_memory_unsigned_integer (addr, 8); + return read_memory_unsigned_integer (addr, 8, byte_order); + + /* Normally, functions live inside a section that is executable. + So, if ADDR points to a non-executable section, then treat it + as a function descriptor and return the target address iff + the target address itself points to a section that is executable. + Check first the memory of the whole length of 8 bytes is readable. */ + if (s && (s->the_bfd_section->flags & SEC_CODE) == 0 + && target_read_memory (addr, buf, 8) == 0) + { + CORE_ADDR pc = extract_unsigned_integer (buf, 8, byte_order); + struct obj_section *pc_section = find_pc_section (pc); + + if (pc_section && (pc_section->the_bfd_section->flags & SEC_CODE)) + return pc; + } + + /* There are also descriptors embedded in vtables. */ + if (s) + { + struct bound_minimal_symbol minsym; + + minsym = lookup_minimal_symbol_by_pc (addr); + + if (minsym.minsym + && is_vtable_name (minsym.minsym->linkage_name ())) + return read_memory_unsigned_integer (addr, 8, byte_order); + } return addr; } @@ -3040,19 +3628,64 @@ ia64_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) return sp & ~0xfLL; } +/* The default "allocate_new_rse_frame" ia64_infcall_ops routine for ia64. */ + +static void +ia64_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, int sof) +{ + ULONGEST cfm, pfs, new_bsp; + + regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm); + + new_bsp = rse_address_add (bsp, sof); + regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp); + + regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs); + pfs &= 0xc000000000000000LL; + pfs |= (cfm & 0xffffffffffffLL); + regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs); + + cfm &= 0xc000000000000000LL; + cfm |= sof; + regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm); +} + +/* The default "store_argument_in_slot" ia64_infcall_ops routine for + ia64. */ + +static void +ia64_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp, + int slotnum, gdb_byte *buf) +{ + write_memory (rse_address_add (bsp, slotnum), buf, 8); +} + +/* The default "set_function_addr" ia64_infcall_ops routine for ia64. */ + +static void +ia64_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr) +{ + /* Nothing needed. */ +} + static CORE_ADDR -ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, +ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) + function_call_return_method return_method, + CORE_ADDR struct_addr) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); int argno; struct value *arg; struct type *type; int len, argoffset; int nslots, rseslots, memslots, slotnum, nfuncargs; int floatreg; - CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr, pc, global_pointer; + ULONGEST bsp; + CORE_ADDR funcdescaddr, global_pointer; + CORE_ADDR func_addr = find_function_addr (function, NULL); nslots = 0; nfuncargs = 0; @@ -3060,13 +3693,13 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, for (argno = 0; argno < nargs; argno++) { arg = args[argno]; - type = check_typedef (VALUE_TYPE (arg)); + type = check_typedef (value_type (arg)); len = TYPE_LENGTH (type); if ((nslots & 1) && slot_alignment_is_next_even (type)) nslots++; - if (TYPE_CODE (type) == TYPE_CODE_FUNC) + if (type->code () == TYPE_CODE_FUNC) nfuncargs++; nslots += (len + 7) / 8; @@ -3077,20 +3710,8 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, memslots = nslots - rseslots; /* Allocate a new RSE frame. */ - cfm = read_register (IA64_CFM_REGNUM); - - bsp = read_register (IA64_BSP_REGNUM); - new_bsp = rse_address_add (bsp, rseslots); - write_register (IA64_BSP_REGNUM, new_bsp); - - pfs = read_register (IA64_PFS_REGNUM); - pfs &= 0xc000000000000000LL; - pfs |= (cfm & 0xffffffffffffLL); - write_register (IA64_PFS_REGNUM, pfs); - - cfm &= 0xc000000000000000LL; - cfm |= rseslots; - write_register (IA64_CFM_REGNUM, cfm); + regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp); + tdep->infcall_ops.allocate_new_rse_frame (regcache, bsp, rseslots); /* We will attempt to find function descriptors in the .opd segment, but if we can't we'll construct them ourselves. That being the @@ -3115,21 +3736,23 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, struct type *float_elt_type; arg = args[argno]; - type = check_typedef (VALUE_TYPE (arg)); + type = check_typedef (value_type (arg)); len = TYPE_LENGTH (type); /* Special handling for function parameters. */ - if (len == 8 - && TYPE_CODE (type) == TYPE_CODE_PTR - && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC) + if (len == 8 + && type->code () == TYPE_CODE_PTR + && TYPE_TARGET_TYPE (type)->code () == TYPE_CODE_FUNC) { - char val_buf[8]; - - store_unsigned_integer (val_buf, 8, - find_func_descr (extract_unsigned_integer (VALUE_CONTENTS (arg), 8), + gdb_byte val_buf[8]; + ULONGEST faddr = extract_unsigned_integer (value_contents (arg), + 8, byte_order); + store_unsigned_integer (val_buf, 8, byte_order, + find_func_descr (regcache, faddr, &funcdescaddr)); if (slotnum < rseslots) - write_memory (rse_address_add (bsp, slotnum), val_buf, 8); + tdep->infcall_ops.store_argument_in_slot (regcache, bsp, + slotnum, val_buf); else write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8); slotnum++; @@ -3145,13 +3768,37 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, argoffset = 0; while (len > 0) { - char val_buf[8]; + gdb_byte val_buf[8]; memset (val_buf, 0, 8); - memcpy (val_buf, VALUE_CONTENTS (arg) + argoffset, (len > 8) ? 8 : len); + if (!ia64_struct_type_p (type) && len < 8) + { + /* Integral types are LSB-aligned, so we have to be careful + to insert the argument on the correct side of the buffer. + This is why we use store_unsigned_integer. */ + store_unsigned_integer + (val_buf, 8, byte_order, + extract_unsigned_integer (value_contents (arg), len, + byte_order)); + } + else + { + /* This is either an 8bit integral type, or an aggregate. + For 8bit integral type, there is no problem, we just + copy the value over. + + For aggregates, the only potentially tricky portion + is to write the last one if it is less than 8 bytes. + In this case, the data is Byte0-aligned. Happy news, + this means that we don't need to differentiate the + handling of 8byte blocks and less-than-8bytes blocks. */ + memcpy (val_buf, value_contents (arg) + argoffset, + (len > 8) ? 8 : len); + } if (slotnum < rseslots) - write_memory (rse_address_add (bsp, slotnum), val_buf, 8); + tdep->infcall_ops.store_argument_in_slot (regcache, bsp, + slotnum, val_buf); else write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8); @@ -3168,10 +3815,11 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, len = TYPE_LENGTH (type); while (len > 0 && floatreg < IA64_FR16_REGNUM) { - char to[MAX_REGISTER_SIZE]; - convert_typed_floating (VALUE_CONTENTS (arg) + argoffset, float_elt_type, - to, builtin_type_ia64_ext); - regcache_cooked_write (regcache, floatreg, (void *)to); + gdb_byte to[IA64_FP_REGISTER_SIZE]; + target_float_convert (value_contents (arg) + argoffset, + float_elt_type, to, + ia64_ext_type (gdbarch)); + regcache->cooked_write (floatreg, to); floatreg++; argoffset += TYPE_LENGTH (float_elt_type); len -= TYPE_LENGTH (float_elt_type); @@ -3180,134 +3828,87 @@ ia64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr, } /* Store the struct return value in r8 if necessary. */ - if (struct_return) - { - regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM, (ULONGEST)struct_addr); - } + if (return_method == return_method_struct) + regcache_cooked_write_unsigned (regcache, IA64_GR8_REGNUM, + (ULONGEST) struct_addr); - global_pointer = FIND_GLOBAL_POINTER (func_addr); + global_pointer = ia64_find_global_pointer (gdbarch, func_addr); if (global_pointer != 0) - write_register (IA64_GR1_REGNUM, global_pointer); + regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer); + + /* The following is not necessary on HP-UX, because we're using + a dummy code sequence pushed on the stack to make the call, and + this sequence doesn't need b0 to be set in order for our dummy + breakpoint to be hit. Nonetheless, this doesn't interfere, and + it's needed for other OSes, so we do this unconditionaly. */ + regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr); - write_register (IA64_BR0_REGNUM, bp_addr); + regcache_cooked_write_unsigned (regcache, sp_regnum, sp); - write_register (sp_regnum, sp); + tdep->infcall_ops.set_function_addr (regcache, func_addr); return sp; } +static const struct ia64_infcall_ops ia64_infcall_ops = +{ + ia64_allocate_new_rse_frame, + ia64_store_argument_in_slot, + ia64_set_function_addr +}; + static struct frame_id -ia64_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) +ia64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) { - char buf[8]; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[8]; CORE_ADDR sp, bsp; - frame_unwind_register (next_frame, sp_regnum, buf); - sp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, sp_regnum, buf); + sp = extract_unsigned_integer (buf, 8, byte_order); - frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf); - bsp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, IA64_BSP_REGNUM, buf); + bsp = extract_unsigned_integer (buf, 8, byte_order); if (gdbarch_debug >= 1) fprintf_unfiltered (gdb_stdlog, - "dummy frame id: code %lx, stack %lx, special %lx\n", - frame_pc_unwind (next_frame), sp, bsp); + "dummy frame id: code %s, stack %s, special %s\n", + paddress (gdbarch, get_frame_pc (this_frame)), + paddress (gdbarch, sp), paddress (gdbarch, bsp)); - return frame_id_build_special (sp, frame_pc_unwind (next_frame), bsp); + return frame_id_build_special (sp, get_frame_pc (this_frame), bsp); } static CORE_ADDR ia64_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - char buf[8]; + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[8]; CORE_ADDR ip, psr, pc; frame_unwind_register (next_frame, IA64_IP_REGNUM, buf); - ip = extract_unsigned_integer (buf, 8); + ip = extract_unsigned_integer (buf, 8, byte_order); frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf); - psr = extract_unsigned_integer (buf, 8); + psr = extract_unsigned_integer (buf, 8, byte_order); pc = (ip & ~0xf) | ((psr >> 41) & 3); return pc; } -static void -ia64_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf) -{ - if (TYPE_CODE (type) == TYPE_CODE_FLT) - { - char to[MAX_REGISTER_SIZE]; - convert_typed_floating (valbuf, type, to, builtin_type_ia64_ext); - regcache_cooked_write (regcache, IA64_FR8_REGNUM, (void *)to); - target_store_registers (IA64_FR8_REGNUM); - } - else - regcache_cooked_write (regcache, IA64_GR8_REGNUM, valbuf); -} - -static void -ia64_remote_translate_xfer_address (struct gdbarch *gdbarch, - struct regcache *regcache, - CORE_ADDR memaddr, int nr_bytes, - CORE_ADDR *targ_addr, int *targ_len) +static int +ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info) { - *targ_addr = memaddr; - *targ_len = nr_bytes; + info->bytes_per_line = SLOT_MULTIPLIER; + return default_print_insn (memaddr, info); } -static void -process_note_abi_tag_sections (bfd *abfd, asection *sect, void *obj) -{ - int *os_ident_ptr = obj; - const char *name; - unsigned int sectsize; - - name = bfd_get_section_name (abfd, sect); - sectsize = bfd_section_size (abfd, sect); - if (strcmp (name, ".note.ABI-tag") == 0 && sectsize > 0) - { - unsigned int name_length, data_length, note_type; - char *note = alloca (sectsize); - - bfd_get_section_contents (abfd, sect, note, - (file_ptr) 0, (bfd_size_type) sectsize); - - name_length = bfd_h_get_32 (abfd, note); - data_length = bfd_h_get_32 (abfd, note + 4); - note_type = bfd_h_get_32 (abfd, note + 8); - - if (name_length == 4 && data_length == 16 && note_type == 1 - && strcmp (note + 12, "GNU") == 0) - { - int os_number = bfd_h_get_32 (abfd, note + 16); - - /* The case numbers are from abi-tags in glibc. */ - switch (os_number) - { - case 0 : - *os_ident_ptr = ELFOSABI_LINUX; - break; - case 1 : - *os_ident_ptr = ELFOSABI_HURD; - break; - case 2 : - *os_ident_ptr = ELFOSABI_SOLARIS; - break; - default : - internal_error (__FILE__, __LINE__, - "process_note_abi_sections: unknown OS number %d", os_number); - break; - } - } - } -} +/* The default "size_of_register_frame" gdbarch_tdep routine for ia64. */ static int -ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info) +ia64_size_of_register_frame (struct frame_info *this_frame, ULONGEST cfm) { - info->bytes_per_line = SLOT_MULTIPLIER; - return print_insn_ia64 (memaddr, info); + return (cfm & 0x7f); } static struct gdbarch * @@ -3321,40 +3922,10 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (arches != NULL) return arches->gdbarch; - tdep = xmalloc (sizeof (struct gdbarch_tdep)); + tdep = XCNEW (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); - /* Set the method of obtaining the sigcontext addresses at which - registers are saved. The method of checking to see if - native_find_global_pointer is nonzero to indicate that we're - on AIX is kind of hokey, but I can't think of a better way - to do it. */ - if (info.osabi == GDB_OSABI_LINUX) - tdep->sigcontext_register_address = ia64_linux_sigcontext_register_address; - else if (native_find_global_pointer != 0) - tdep->sigcontext_register_address = ia64_aix_sigcontext_register_address; - else - tdep->sigcontext_register_address = 0; - - /* We know that GNU/Linux won't have to resort to the - native_find_global_pointer hackery. But that's the only one we - know about so far, so if native_find_global_pointer is set to - something non-zero, then use it. Otherwise fall back to using - generic_elf_find_global_pointer. This arrangement should (in - theory) allow us to cross debug GNU/Linux binaries from an AIX - machine. */ - if (info.osabi == GDB_OSABI_LINUX) - tdep->find_global_pointer = generic_elf_find_global_pointer; - else if (native_find_global_pointer != 0) - tdep->find_global_pointer = native_find_global_pointer; - else - tdep->find_global_pointer = generic_elf_find_global_pointer; - - /* Define the ia64 floating-point format to gdb. */ - builtin_type_ia64_ext = - init_type (TYPE_CODE_FLT, 128 / 8, - 0, "builtin_type_ia64_ext", NULL); - TYPE_FLOATFORMAT (builtin_type_ia64_ext) = &floatformat_ia64_ext; + tdep->size_of_register_frame = ia64_size_of_register_frame; /* According to the ia64 specs, instructions that store long double floats in memory use a long-double format different than that @@ -3364,7 +3935,7 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) format for storing long doubles (e.g. HPUX). In the latter case, the setting of the format may be moved/overridden in an OS-specific tdep file. */ - set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext); + set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext); set_gdbarch_short_bit (gdbarch, 16); set_gdbarch_int_bit (gdbarch, 32); @@ -3376,14 +3947,12 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_ptr_bit (gdbarch, 64); set_gdbarch_num_regs (gdbarch, NUM_IA64_RAW_REGS); - set_gdbarch_num_pseudo_regs (gdbarch, LAST_PSEUDO_REGNUM - FIRST_PSEUDO_REGNUM); + set_gdbarch_num_pseudo_regs (gdbarch, + LAST_PSEUDO_REGNUM - FIRST_PSEUDO_REGNUM); set_gdbarch_sp_regnum (gdbarch, sp_regnum); set_gdbarch_fp0_regnum (gdbarch, IA64_FR0_REGNUM); set_gdbarch_register_name (gdbarch, ia64_register_name); - /* FIXME: Following interface should not be needed, however, without it recurse.exp - gets a number of extra failures. */ - set_gdbarch_deprecated_register_size (gdbarch, 8); set_gdbarch_register_type (gdbarch, ia64_register_type); set_gdbarch_pseudo_register_read (gdbarch, ia64_pseudo_register_read); @@ -3396,51 +3965,56 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_skip_prologue (gdbarch, ia64_skip_prologue); - set_gdbarch_use_struct_convention (gdbarch, ia64_use_struct_convention); - set_gdbarch_extract_return_value (gdbarch, ia64_extract_return_value); + set_gdbarch_return_value (gdbarch, ia64_return_value); - set_gdbarch_store_return_value (gdbarch, ia64_store_return_value); - set_gdbarch_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address); - - set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint); - set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint); + set_gdbarch_memory_insert_breakpoint (gdbarch, + ia64_memory_insert_breakpoint); + set_gdbarch_memory_remove_breakpoint (gdbarch, + ia64_memory_remove_breakpoint); set_gdbarch_breakpoint_from_pc (gdbarch, ia64_breakpoint_from_pc); + set_gdbarch_breakpoint_kind_from_pc (gdbarch, ia64_breakpoint_kind_from_pc); set_gdbarch_read_pc (gdbarch, ia64_read_pc); set_gdbarch_write_pc (gdbarch, ia64_write_pc); /* Settings for calling functions in the inferior. */ set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call); + tdep->infcall_ops = ia64_infcall_ops; set_gdbarch_frame_align (gdbarch, ia64_frame_align); - set_gdbarch_unwind_dummy_id (gdbarch, ia64_unwind_dummy_id); + set_gdbarch_dummy_id (gdbarch, ia64_dummy_id); set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc); - frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer); #ifdef HAVE_LIBUNWIND_IA64_H - frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer); + frame_unwind_append_unwinder (gdbarch, + &ia64_libunwind_sigtramp_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &ia64_libunwind_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &ia64_sigtramp_frame_unwind); libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr); +#else + frame_unwind_append_unwinder (gdbarch, &ia64_sigtramp_frame_unwind); #endif - frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer); + frame_unwind_append_unwinder (gdbarch, &ia64_frame_unwind); frame_base_set_default (gdbarch, &ia64_frame_base); /* Settings that should be unnecessary. */ set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - set_gdbarch_decr_pc_after_break (gdbarch, 0); - set_gdbarch_frame_args_skip (gdbarch, 0); + set_gdbarch_print_insn (gdbarch, ia64_print_insn); + set_gdbarch_convert_from_func_ptr_addr (gdbarch, + ia64_convert_from_func_ptr_addr); - set_gdbarch_remote_translate_xfer_address ( - gdbarch, ia64_remote_translate_xfer_address); + /* The virtual table contains 16-byte descriptors, not pointers to + descriptors. */ + set_gdbarch_vtable_function_descriptors (gdbarch, 1); - set_gdbarch_print_insn (gdbarch, ia64_print_insn); - set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr); + /* Hook in ABI-specific overrides, if they have been registered. */ + gdbarch_init_osabi (info, gdbarch); return gdbarch; } -extern initialize_file_ftype _initialize_ia64_tdep; /* -Wmissing-prototypes */ - +void _initialize_ia64_tdep (); void -_initialize_ia64_tdep (void) +_initialize_ia64_tdep () { - register_gdbarch_init (bfd_arch_ia64, ia64_gdbarch_init); + gdbarch_register (bfd_arch_ia64, ia64_gdbarch_init, NULL); }