From 930bd0e01a2f0c2e59578b6e94aa6925d52d6bed Mon Sep 17 00:00:00 2001 From: Kevin Buettner Date: Fri, 17 Dec 2010 21:39:27 +0000 Subject: [PATCH] * mips-tdep.c (make_mips16_addr): New function. (mips_elf_make_msymbol_special): Don't set the low bit in the symbol's address. (mips_read_pc, mips_unwind_pc, mips_addr_bits_remove): Strip bit indicating mips16 address, if present. (mips_write_pc): Set bit indicating mips16 address when in a mips16 function. (mips_eabi_push_dummy_call, mips_o64_push_dummy_call): Likewise, but for each function pointer argument to inferior function call. --- gdb/ChangeLog | 12 ++++++++++ gdb/mips-tdep.c | 61 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0efe32700a..46f4fe4790 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,15 @@ +2010-12-17 Kevin Buettner + + * mips-tdep.c (make_mips16_addr): New function. + (mips_elf_make_msymbol_special): Don't set the low bit in the + symbol's address. + (mips_read_pc, mips_unwind_pc, mips_addr_bits_remove): Strip bit + indicating mips16 address, if present. + (mips_write_pc): Set bit indicating mips16 address when in a mips16 + function. + (mips_eabi_push_dummy_call, mips_o64_push_dummy_call): Likewise, + but for each function pointer argument to inferior function call. + 2010-12-17 Tom Tromey * psympriv.h (struct partial_symtab) : Move field diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 6b9c5f6c83..81f2d7de63 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -205,6 +205,12 @@ unmake_mips16_addr (CORE_ADDR addr) return ((addr) & ~(CORE_ADDR) 1); } +static CORE_ADDR +make_mips16_addr (CORE_ADDR addr) +{ + return ((addr) | (CORE_ADDR) 1); +} + /* Return the MIPS ABI associated with GDBARCH. */ enum mips_abi mips_abi (struct gdbarch *gdbarch) @@ -264,7 +270,6 @@ mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym) if (((elf_symbol_type *) (sym))->internal_elf_sym.st_other == STO_MIPS16) { MSYMBOL_TARGET_FLAG_1 (msym) = 1; - SYMBOL_VALUE_ADDRESS (msym) |= 1; } } @@ -931,14 +936,21 @@ mips_read_pc (struct regcache *regcache) ULONGEST pc; int regnum = mips_regnum (get_regcache_arch (regcache))->pc; regcache_cooked_read_signed (regcache, regnum, &pc); + if (is_mips16_addr (pc)) + pc = unmake_mips16_addr (pc); return pc; } static CORE_ADDR mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) { - return frame_unwind_register_signed - (next_frame, gdbarch_num_regs (gdbarch) + mips_regnum (gdbarch)->pc); + ULONGEST pc; + + pc = frame_unwind_register_signed + (next_frame, gdbarch_num_regs (gdbarch) + mips_regnum (gdbarch)->pc); + if (is_mips16_addr (pc)) + pc = unmake_mips16_addr (pc); + return pc; } static CORE_ADDR @@ -967,7 +979,10 @@ static void mips_write_pc (struct regcache *regcache, CORE_ADDR pc) { int regnum = mips_regnum (get_regcache_arch (regcache))->pc; - regcache_cooked_write_unsigned (regcache, regnum, pc); + if (mips_pc_is_mips16 (pc)) + regcache_cooked_write_unsigned (regcache, regnum, make_mips16_addr (pc)); + else + regcache_cooked_write_unsigned (regcache, regnum, pc); } /* Fetch and return instruction from the specified location. If the PC @@ -2450,6 +2465,10 @@ static CORE_ADDR mips_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (is_mips16_addr (addr)) + addr = unmake_mips16_addr (addr); + if (mips_mask_address_p (tdep) && (((ULONGEST) addr) >> 32 == 0xffffffffUL)) /* This hack is a work-around for existing boards using PMON, the simulator, and any other 64-bit targets that doesn't have true @@ -2869,9 +2888,25 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function, "mips_eabi_push_dummy_call: %d len=%d type=%d", argnum + 1, len, (int) typecode); + /* Function pointer arguments to mips16 code need to be made into + mips16 pointers. */ + if (typecode == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC) + { + CORE_ADDR addr = extract_signed_integer (value_contents (arg), + len, byte_order); + if (mips_pc_is_mips16 (addr)) + { + store_signed_integer (valbuf, len, byte_order, + make_mips16_addr (addr)); + val = valbuf; + } + else + val = value_contents (arg); + } /* The EABI passes structures that do not fit in a register by reference. */ - if (len > regsize + else if (len > regsize && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { store_unsigned_integer (valbuf, regsize, byte_order, @@ -4159,6 +4194,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, for (argnum = 0; argnum < nargs; argnum++) { const gdb_byte *val; + gdb_byte valbuf[MAX_REGISTER_SIZE]; struct value *arg = args[argnum]; struct type *arg_type = check_typedef (value_type (arg)); int len = TYPE_LENGTH (arg_type); @@ -4171,6 +4207,21 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function, val = value_contents (arg); + /* Function pointer arguments to mips16 code need to be made into + mips16 pointers. */ + if (typecode == TYPE_CODE_PTR + && TYPE_CODE (TYPE_TARGET_TYPE (arg_type)) == TYPE_CODE_FUNC) + { + CORE_ADDR addr = extract_signed_integer (value_contents (arg), + len, byte_order); + if (mips_pc_is_mips16 (addr)) + { + store_signed_integer (valbuf, len, byte_order, + make_mips16_addr (addr)); + val = valbuf; + } + } + /* Floating point arguments passed in registers have to be treated specially. On 32-bit architectures, doubles are passed in register pairs; the even register gets -- 2.34.1