diff options
author | Mark Alexander <marka@cygnus> | 1997-03-22 04:40:03 +0000 |
---|---|---|
committer | Mark Alexander <marka@cygnus> | 1997-03-22 04:40:03 +0000 |
commit | c81a76b311a313707e80af5de287a11008fc72bc (patch) | |
tree | c652b707ee4b7218a2c6e756f55375fdb3dda613 | |
parent | 7cad1a894be0fce0f179275d89d575cc1e49a249 (diff) | |
download | gdb-c81a76b311a313707e80af5de287a11008fc72bc.zip gdb-c81a76b311a313707e80af5de287a11008fc72bc.tar.gz gdb-c81a76b311a313707e80af5de287a11008fc72bc.tar.bz2 |
* mips-tdep.c (mips_push_arguments): On non-EABI architectures,
copy first two floating point arguments to general registers, so that
MIPS16 functions will receive the arguments correctly.
(mips_print_register): Print double registers correctly on
little-endian hosts.
(mips_extract_return_value): Return double values correctly
on little-endian hosts.
* mdebugread.c (parse_procedure): Adjust address of procedure relative
to address in file descriptor record; this accounts for constant
strings that may precede functions in the text section. Remove
now-useless lowest_pdr_addr from argument list and all calls.
-rw-r--r-- | gdb/ChangeLog | 15 | ||||
-rw-r--r-- | gdb/mdebugread.c | 11 | ||||
-rw-r--r-- | gdb/mips-tdep.c | 207 |
3 files changed, 147 insertions, 86 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 9ec35d5..bc85bfa 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,18 @@ +Fri Mar 21 19:10:05 1997 Mark Alexander <marka@cygnus.com> + + * mips-tdep.c (mips_push_arguments): On non-EABI architectures, + copy first two floating point arguments to general registers, so that + MIPS16 functions will receive the arguments correctly. + (mips_print_register): Print double registers correctly on + little-endian hosts. + (mips_extract_return_value): Return double values correctly + on little-endian hosts. + + * mdebugread.c (parse_procedure): Adjust address of procedure relative + to address in file descriptor record; this accounts for constant + strings that may precede functions in the text section. Remove + now-useless lowest_pdr_addr from argument list and all calls. + Fri Mar 21 15:36:25 1997 Michael Meissner <meissner@cygnus.com> * configure.tgt (powerpc*-{eabi,linux,sysv,elf}*): Determine diff --git a/gdb/mdebugread.c b/gdb/mdebugread.c index 8047798..1e9fe6d 100644 --- a/gdb/mdebugread.c +++ b/gdb/mdebugread.c @@ -1893,14 +1893,13 @@ upgrade_type (fd, tpp, tq, ax, bigend, sym_name) to look for the function which contains the MIPS_EFI_SYMBOL_NAME symbol in question, or NULL to use top_stack->cur_block. */ -static void parse_procedure PARAMS ((PDR *, struct symtab *, CORE_ADDR, +static void parse_procedure PARAMS ((PDR *, struct symtab *, struct partial_symtab *)); static void -parse_procedure (pr, search_symtab, lowest_pdr_addr, pst) +parse_procedure (pr, search_symtab, pst) PDR *pr; struct symtab *search_symtab; - CORE_ADDR lowest_pdr_addr; struct partial_symtab *pst; { struct symbol *s, *i; @@ -2006,7 +2005,7 @@ parse_procedure (pr, search_symtab, lowest_pdr_addr, pst) e = (struct mips_extra_func_info *) SYMBOL_VALUE (i); e->pdr = *pr; e->pdr.isym = (long) s; - e->pdr.adr += pst->textlow - lowest_pdr_addr; + e->pdr.adr += cur_fdr->adr; /* PDR address is relative to FDR address */ /* Correct incorrect setjmp procedure descriptor from the library to make backtrace through setjmp work. */ @@ -3372,7 +3371,7 @@ psymtab_to_symtab_1 (pst, filename) pdr_in = pr_block; pdr_in_end = pdr_in + fh->cpd; for (; pdr_in < pdr_in_end; pdr_in++) - parse_procedure (pdr_in, st, lowest_pdr_addr, pst); + parse_procedure (pdr_in, st, pst); do_cleanups (old_chain); } @@ -3486,7 +3485,7 @@ psymtab_to_symtab_1 (pst, filename) pdr_in = pr_block; pdr_in_end = pdr_in + fh->cpd; for (; pdr_in < pdr_in_end; pdr_in++) - parse_procedure (pdr_in, 0, lowest_pdr_addr, pst); + parse_procedure (pdr_in, 0, pst); do_cleanups (old_chain); } diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 1c02ded..14f5d01 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -316,6 +316,32 @@ mips16_decode_reg_save (inst, gen_mask) *gen_mask |= (1 << 31); } + +/* Fetch and return instruction from the specified location. If the PC + is odd, assume it's a MIPS16 instruction; otherwise MIPS32. */ + +static t_inst +mips_fetch_instruction (addr) + CORE_ADDR addr; +{ + char buf[MIPS_INSTLEN]; + int instlen; + int status; + + if (IS_MIPS16_ADDR (addr)) + { + instlen = MIPS16_INSTLEN; + addr = UNMAKE_MIPS16_ADDR (addr); + } + else + instlen = MIPS_INSTLEN; + status = read_memory_nobpt (addr, buf, instlen); + if (status) + memory_error (status, addr); + return extract_unsigned_integer (buf, instlen); +} + + /* Guaranteed to set fci->saved_regs to some values (it never leaves it NULL). */ @@ -330,6 +356,7 @@ mips_find_saved_regs (fci) /* What registers have been saved? Bitmasks. */ unsigned long gen_mask, float_mask; mips_extra_func_info_t proc_desc; + t_inst inst; fci->saved_regs = (struct frame_saved_regs *) obstack_alloc (&frame_cache_obstack, sizeof(struct frame_saved_regs)); @@ -406,34 +433,22 @@ mips_find_saved_regs (fci) claims are saved have been saved yet. */ CORE_ADDR addr; - int status; - char buf[MIPS_INSTLEN]; - t_inst inst; - int instlen; /* Bitmasks; set if we have found a save for the register. */ unsigned long gen_save_found = 0; unsigned long float_save_found = 0; + int instlen; /* If the address is odd, assume this is MIPS16 code. */ addr = PROC_LOW_ADDR (proc_desc); - if (IS_MIPS16_ADDR (addr)) - { - instlen = MIPS16_INSTLEN; - addr = UNMAKE_MIPS16_ADDR (addr); - } - else - instlen = MIPS_INSTLEN; + instlen = IS_MIPS16_ADDR (addr) ? MIPS16_INSTLEN : MIPS_INSTLEN; /* Scan through this function's instructions preceding the current PC, and look for those that save registers. */ while (addr < fci->pc) { - status = read_memory_nobpt (addr, buf, instlen); - if (status) - memory_error (status, addr); - inst = extract_unsigned_integer (buf, instlen); - if (instlen == MIPS16_INSTLEN) + inst = mips_fetch_instruction (addr); + if (IS_MIPS16_ADDR (addr)) mips16_decode_reg_save (inst, &gen_save_found); else mips32_decode_reg_save (inst, &gen_save_found, &float_save_found); @@ -452,6 +467,33 @@ mips_find_saved_regs (fci) fci->saved_regs->regs[ireg] = reg_position; reg_position -= MIPS_REGSIZE; } + + /* The MIPS16 entry instruction saves $s0 and $s1 in the reverse order + of that normally used by gcc. Therefore, we have to fetch the first + instruction of the function, and if it's an entry instruction that + saves $s0 or $s1, correct their saved addresses. */ + if (IS_MIPS16_ADDR (PROC_LOW_ADDR (proc_desc))) + { + inst = mips_fetch_instruction (PROC_LOW_ADDR (proc_desc)); + if ((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */ + { + int reg; + int sreg_count = (inst >> 6) & 3; + + /* Check if the ra register was pushed on the stack. */ + reg_position = fci->frame + PROC_REG_OFFSET (proc_desc); + if (inst & 0x20) + reg_position -= MIPS_REGSIZE; + + /* Check if the s0 and s1 registers were pushed on the stack. */ + for (reg = 16; reg < sreg_count+16; reg++) + { + fci->saved_regs->regs[reg] = reg_position; + reg_position -= MIPS_REGSIZE; + } + } + } + /* Fill in the offsets for the registers which float_mask says were saved. */ reg_position = fci->frame + PROC_FREG_OFFSET (proc_desc); @@ -459,7 +501,7 @@ mips_find_saved_regs (fci) /* The freg_offset points to where the first *double* register is saved. So skip to the high-order word. */ if (! GDB_TARGET_IS_MIPS64) - reg_position += 4; + reg_position += MIPS_REGSIZE; /* Fill in the offsets for the float registers which float_mask says were saved. */ @@ -621,7 +663,7 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\ addiu sp,-n daddiu sp,-n extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n' */ - inst = read_memory_integer (UNMAKE_MIPS16_ADDR (start_pc), 2); + inst = mips_fetch_instruction (start_pc); if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */ || (inst & 0xff80) == 0x6380 /* addiu sp,-n */ || (inst & 0xff80) == 0xfb80 /* daddiu sp,-n */ @@ -647,7 +689,7 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\ return start_pc; } -/* Fetch the immediate value from the current instruction. +/* Fetch the immediate value from a MIPS16 instruction. If the previous instruction was an EXTEND, use it to extend the upper bits of the immediate value. This is a helper function for mips16_heuristic_proc_desc. */ @@ -701,19 +743,14 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS16_INSTLEN) { - char buf[MIPS16_INSTLEN]; - int status, reg, offset; + int reg, offset; /* Save the previous instruction. If it's an EXTEND, we'll extract the immediate offset extension from it in mips16_get_imm. */ prev_inst = inst; - /* Fetch the instruction. */ - status = read_memory_nobpt (UNMAKE_MIPS16_ADDR (cur_pc), buf, - MIPS16_INSTLEN); - if (status) memory_error (status, cur_pc); - inst = (unsigned short) extract_unsigned_integer (buf, MIPS16_INSTLEN); - + /* Fetch and decode the instruction. */ + inst = (unsigned short) mips_fetch_instruction (cur_pc); if ((inst & 0xff00) == 0x6300 /* addiu sp */ || (inst & 0xff00) == 0xfb00) /* daddiu sp */ { @@ -786,10 +823,11 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) PROC_FRAME_OFFSET(&temp_proc_desc) += 32; /* Check if a0-a3 were saved in the caller's argument save area. */ - for (reg = 4, offset = 32; reg < areg_count+4; reg++, offset += 4) + for (reg = 4, offset = 32; reg < areg_count+4; reg++) { PROC_REG_MASK(&temp_proc_desc) |= 1 << reg; temp_saved_regs.regs[reg] = sp + offset; + offset -= MIPS_REGSIZE; } /* Check if the ra register was pushed on the stack. */ @@ -798,14 +836,15 @@ mips16_heuristic_proc_desc(start_pc, limit_pc, next_frame, sp) { PROC_REG_MASK(&temp_proc_desc) |= 1 << 31; temp_saved_regs.regs[31] = sp + offset; - offset -= 4; + offset -= MIPS_REGSIZE; } /* Check if the s0 and s1 registers were pushed on the stack. */ - for (reg = 16; reg < sreg_count+16; reg++, offset -= 4) + for (reg = 16; reg < sreg_count+16; reg++) { PROC_REG_MASK(&temp_proc_desc) |= 1 << reg; temp_saved_regs.regs[reg] = sp + offset; + offset -= MIPS_REGSIZE; } } else if ((inst & 0xf800) == 0x1800) /* jal(x) */ @@ -825,14 +864,11 @@ restart: PROC_FRAME_OFFSET(&temp_proc_desc) = 0; for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSTLEN) { - char buf[MIPS_INSTLEN]; unsigned long inst, high_word, low_word; - int status, reg; + int reg; /* Fetch the instruction. */ - status = (unsigned long) read_memory_nobpt (cur_pc, buf, MIPS_INSTLEN); - if (status) memory_error (status, cur_pc); - inst = (unsigned long) extract_unsigned_integer (buf, MIPS_INSTLEN); + inst = (unsigned long) mips_fetch_instruction (cur_pc); /* Save some code by pre-extracting some useful fields. */ high_word = (inst >> 16) & 0xffff; @@ -1246,7 +1282,12 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) /* 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 - the low word, and the odd register gets the high word. */ + the low word, and the odd register gets the high word. + On non-EABI processors, the first two floating point arguments are + also copied to general registers, because MIPS16 functions + don't use float registers for arguments. This duplication of + arguments in general registers can't hurt non-MIPS16 functions + because those registers are normally skipped. */ if (typecode == TYPE_CODE_FLT && float_argreg <= MIPS_LAST_FP_ARG_REGNUM && mips_fpu != MIPS_FPU_NONE) @@ -1256,21 +1297,34 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) int low_offset = TARGET_BYTE_ORDER == BIG_ENDIAN ? 4 : 0; unsigned long regval; + /* Write the low word of the double to the even register(s). */ regval = extract_unsigned_integer (val+low_offset, 4); - write_register (float_argreg++, regval); /* low word */ + write_register (float_argreg++, regval); + if (!MIPS_EABI) + write_register (argreg+1, regval); + + /* Write the high word of the double to the odd register(s). */ regval = extract_unsigned_integer (val+4-low_offset, 4); - write_register (float_argreg++, regval); /* high word */ + write_register (float_argreg++, regval); + if (!MIPS_EABI) + { + write_register (argreg, regval); + argreg += 2; + } } else { + /* This is a floating point value that fits entirely + in a single register. */ CORE_ADDR regval = extract_address (val, len); write_register (float_argreg++, regval); + if (!MIPS_EABI) + { + write_register (argreg, regval); + argreg += GDB_TARGET_IS_MIPS64 ? 1 : 2; + } } - - /* If this is the old ABI, skip one or two general registers. */ - if (!MIPS_EABI) - argreg += GDB_TARGET_IS_MIPS64 ? 1 : 2; } else { @@ -1325,7 +1379,7 @@ mips_push_arguments(nargs, args, sp, struct_return, struct_addr) return sp; } -void +static void mips_push_register(CORE_ADDR *sp, int regno) { char buffer[MAX_REGISTER_RAW_SIZE]; @@ -1488,11 +1542,11 @@ mips_print_register (regnum, all) { char dbuffer[MAX_REGISTER_RAW_SIZE]; - read_relative_register_raw_bytes (regnum, dbuffer); - read_relative_register_raw_bytes (regnum+1, dbuffer+4); /* FIXME!! */ -#ifdef REGISTER_CONVERT_TO_TYPE - REGISTER_CONVERT_TO_TYPE(regnum, builtin_type_double, dbuffer); -#endif + /* MIPS doubles are stored in a register pair with the least + signficant register in the lower-numbered register. */ + read_relative_register_raw_bytes (regnum+1, dbuffer); + read_relative_register_raw_bytes (regnum, dbuffer+MIPS_REGSIZE); + printf_filtered ("(d%d: ", regnum-FP0_REGNUM); val_print (builtin_type_double, dbuffer, 0, gdb_stdout, 0, 1, 0, Val_pretty_default); @@ -1632,14 +1686,9 @@ mips32_skip_prologue (pc, lenient) or in the gcc frame. */ for (end_pc = pc + 100; pc < end_pc; pc += MIPS_INSTLEN) { - char buf[MIPS_INSTLEN]; - int status; unsigned long high_word; - status = read_memory_nobpt (pc, buf, MIPS_INSTLEN); - if (status) - memory_error (status, pc); - inst = (unsigned long)extract_unsigned_integer (buf, MIPS_INSTLEN); + inst = mips_fetch_instruction (pc); high_word = (inst >> 16) & 0xffff; #if 0 @@ -1724,6 +1773,8 @@ mips16_skip_prologue (pc, lenient) int lenient; { CORE_ADDR end_pc; + int extend_bytes = 0; + int prev_extend_bytes; /* Table of instructions likely to be found in a function prologue. */ static struct @@ -1751,23 +1802,10 @@ mips16_skip_prologue (pc, lenient) or in the gcc frame. */ for (end_pc = pc + 100; pc < end_pc; pc += MIPS16_INSTLEN) { - char buf[MIPS16_INSTLEN]; - int status; unsigned short inst; - int extend_bytes = 0; - int prev_extend_bytes; int i; - status = read_memory_nobpt (UNMAKE_MIPS16_ADDR (pc), buf, - MIPS16_INSTLEN); - if (status) - memory_error (status, pc); - inst = (unsigned long)extract_unsigned_integer (buf, MIPS16_INSTLEN); - -#if 0 - if (lenient && is_delayed (inst)) - continue; -#endif + inst = mips_fetch_instruction (pc); /* Normally we ignore an extend instruction. However, if it is not followed by a valid prologue instruction, we must adjust @@ -1857,23 +1895,32 @@ mips_extract_return_value (valtype, regbuf, valbuf) { int regnum; int offset = 0; + int len = TYPE_LENGTH (valtype); regnum = 2; if (TYPE_CODE (valtype) == TYPE_CODE_FLT && (mips_fpu == MIPS_FPU_DOUBLE - || (mips_fpu == MIPS_FPU_SINGLE && TYPE_LENGTH (valtype) <= 4))) /* FIXME!! */ - regnum = FP0_REGNUM; + || (mips_fpu == MIPS_FPU_SINGLE && len <= MIPS_REGSIZE))) + { + regnum = FP0_REGNUM; + + /* If this is a double, the odd-numbered register (FP1) contains the + high word of the result. Copy that to the buffer before + copying the low word in FP0. */ + if (len > MIPS_REGSIZE) + { + memcpy (valbuf, regbuf + REGISTER_BYTE (regnum+1), MIPS_REGSIZE); + len -= MIPS_REGSIZE; + valbuf += MIPS_REGSIZE; + } + } if (TARGET_BYTE_ORDER == BIG_ENDIAN && TYPE_CODE (valtype) != TYPE_CODE_FLT - && TYPE_LENGTH (valtype) < REGISTER_RAW_SIZE (regnum)) - offset = REGISTER_RAW_SIZE (regnum) - TYPE_LENGTH (valtype); - - memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, - TYPE_LENGTH (valtype)); -#ifdef REGISTER_CONVERT_TO_TYPE - REGISTER_CONVERT_TO_TYPE(regnum, valtype, valbuf); -#endif + && len < REGISTER_RAW_SIZE (regnum)) + offset = REGISTER_RAW_SIZE (regnum) - len; + + memcpy (valbuf, regbuf + REGISTER_BYTE (regnum) + offset, len); } /* Given a return value in `regbuf' with a type `valtype', @@ -2162,9 +2209,9 @@ mips_about_to_return (pc) as $a3), then a "jr" using that register. This second case is almost impossible to distinguish from an indirect jump used for switch statements, so we don't even try. */ - return read_memory_integer (UNMAKE_MIPS16_ADDR (pc), 2) == 0xe820; /* jr $ra */ + return mips_fetch_instruction (pc) == 0xe820; /* jr $ra */ else - return read_memory_integer (pc, 4) == 0x3e00008; /* jr $ra */ + return mips_fetch_instruction (pc) == 0x3e00008; /* jr $ra */ } |