diff options
author | Mark Alexander <marka@cygnus> | 1997-09-15 21:06:16 +0000 |
---|---|---|
committer | Mark Alexander <marka@cygnus> | 1997-09-15 21:06:16 +0000 |
commit | 899c402166e46e5b16b3e668d2b947b12a682136 (patch) | |
tree | 6005600a8fef2ac571d224536ecfe7640b616eb5 /gdb/mips-tdep.c | |
parent | a611b1c2fd7c9974146134a1eeaf41c04c743386 (diff) | |
download | gdb-899c402166e46e5b16b3e668d2b947b12a682136.zip gdb-899c402166e46e5b16b3e668d2b947b12a682136.tar.gz gdb-899c402166e46e5b16b3e668d2b947b12a682136.tar.bz2 |
* dbxread.c (MSYMBOL_SIZE): New macro.
(end_psymtab): Use MSYMBOL_SIZE to extract size from minimal symbol.
* elfread.c (elf_symtab_read): If ELF symbol is "special",
such as a MIPS16 function, mark minimal symbol as special too.
* mips-tdep.c (pc_is_mips16): New function to check whether
a function is MIPS16 by looking at the minimal symbol. Use
pc_is_mips16 throughout instead of IS_MIPS16_ADDR macro.
* config/mips/tm-mips.h (SYMBOL_IS_SPECIAL, MAKE_MSYMBOL_SPECIAL,
MSYMBOL_IS_SPECIAL, MSYMBOL_SIZE): New functions for setting/testing
"special" MIPS16 bit in ELF and minimal symbols.
* mdebugread.c (parse_partial_symbols): Don't construct a partial
symbol table for a file that already has one.
start-sanitize-tx19
* configure.tgt: Support TX19.
* config/mips/tm-tx19.h, config/mips/tm-tx19l.h, config/mips/tx19.mt,
config/mips/tx19l.mt: New files for TX19.
end-sanitize-tx19
Diffstat (limited to 'gdb/mips-tdep.c')
-rw-r--r-- | gdb/mips-tdep.c | 238 |
1 files changed, 186 insertions, 52 deletions
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index 54d0fc5..b624739 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -207,6 +207,28 @@ struct linked_proc_info } *linked_proc_desc_table = NULL; +/* Tell if the program counter value in MEMADDR is in a MIPS16 function. */ + +static int +pc_is_mips16 (bfd_vma memaddr) +{ + struct minimal_symbol *sym; + + /* If bit 0 of the address is set, assume this is a MIPS16 address. */ + if (IS_MIPS16_ADDR (memaddr)) + return 1; + + /* A flag indicating that this is a MIPS16 function is stored by elfread.c in + the high bit of the info field. Use this to decide if the function is + MIPS16 or normal MIPS. */ + sym = lookup_minimal_symbol_by_pc (memaddr); + if (sym) + return MSYMBOL_IS_SPECIAL (sym); + else + return 0; +} + + /* This returns the PC of the first inst after the prologue. If we can't find the prologue, then return 0. */ @@ -316,7 +338,7 @@ mips_fetch_instruction (addr) int instlen; int status; - if (IS_MIPS16_ADDR (addr)) + if (pc_is_mips16 (addr)) { instlen = MIPS16_INSTLEN; addr = UNMAKE_MIPS16_ADDR (addr); @@ -429,14 +451,14 @@ mips_find_saved_regs (fci) /* If the address is odd, assume this is MIPS16 code. */ addr = PROC_LOW_ADDR (proc_desc); - instlen = IS_MIPS16_ADDR (addr) ? MIPS16_INSTLEN : MIPS_INSTLEN; + instlen = pc_is_mips16 (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) { inst = mips_fetch_instruction (addr); - if (IS_MIPS16_ADDR (addr)) + if (pc_is_mips16 (addr)) mips16_decode_reg_save (inst, &gen_save_found); else mips32_decode_reg_save (inst, &gen_save_found, &float_save_found); @@ -460,7 +482,7 @@ mips_find_saved_regs (fci) 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))) + if (pc_is_mips16 (PROC_LOW_ADDR (proc_desc))) { inst = mips_fetch_instruction (PROC_LOW_ADDR (proc_desc)); if ((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700) /* entry */ @@ -620,7 +642,7 @@ heuristic_proc_start(pc) || fence < VM_MIN_ADDRESS) fence = VM_MIN_ADDRESS; - instlen = IS_MIPS16_ADDR (pc) ? MIPS16_INSTLEN : MIPS_INSTLEN; + instlen = pc_is_mips16 (pc) ? MIPS16_INSTLEN : MIPS_INSTLEN; /* search back for previous return */ for (start_pc -= instlen; ; start_pc -= instlen) @@ -655,7 +677,7 @@ Otherwise, you told GDB there was a function where there isn't one, or\n\ return 0; } - else if (IS_MIPS16_ADDR (start_pc)) + else if (pc_is_mips16 (start_pc)) { unsigned short inst; @@ -971,7 +993,7 @@ heuristic_proc_desc(start_pc, limit_pc, next_frame) if (start_pc + 200 < limit_pc) limit_pc = start_pc + 200; - if (IS_MIPS16_ADDR (start_pc)) + if (pc_is_mips16 (start_pc)) mips16_heuristic_proc_desc (start_pc, limit_pc, next_frame, sp); else mips32_heuristic_proc_desc (start_pc, limit_pc, next_frame, sp); @@ -1586,20 +1608,21 @@ mips_print_register (regnum, all) } /* If an even floating point register, also print as double. */ - if (regnum >= FP0_REGNUM && regnum < FP0_REGNUM+MIPS_NUMREGS + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT && !((regnum-FP0_REGNUM) & 1)) - { - char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; + if (REGISTER_RAW_SIZE(regnum) == 4) /* this would be silly on MIPS64 */ + { + char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; - read_relative_register_raw_bytes (regnum, dbuffer); - read_relative_register_raw_bytes (regnum+1, dbuffer+MIPS_REGSIZE); - REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer); + read_relative_register_raw_bytes (regnum, dbuffer); + read_relative_register_raw_bytes (regnum+1, dbuffer+MIPS_REGSIZE); + REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer); - printf_filtered ("(d%d: ", regnum-FP0_REGNUM); - val_print (builtin_type_double, dbuffer, 0, - gdb_stdout, 0, 1, 0, Val_pretty_default); - printf_filtered ("); "); - } + printf_filtered ("(d%d: ", regnum-FP0_REGNUM); + val_print (builtin_type_double, dbuffer, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + printf_filtered ("); "); + } fputs_filtered (reg_names[regnum], gdb_stdout); /* The problem with printing numeric register names (r26, etc.) is that @@ -1613,22 +1636,146 @@ mips_print_register (regnum, all) /* If virtual format is floating, print it that way. */ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) - val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, - gdb_stdout, 0, 1, 0, Val_pretty_default); + if (REGISTER_RAW_SIZE(regnum) == 8) + { /* show 8-byte floats as float AND double: */ + int offset = 4 * (TARGET_BYTE_ORDER == BIG_ENDIAN); + + printf_filtered (" (float) "); + val_print (builtin_type_float, raw_buffer + offset, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + printf_filtered (", (double) "); + val_print (builtin_type_double, raw_buffer, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + } + else + val_print (REGISTER_VIRTUAL_TYPE (regnum), raw_buffer, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); /* Else print as integer in hex. */ else print_scalar_formatted (raw_buffer, REGISTER_VIRTUAL_TYPE (regnum), 'x', 0, gdb_stdout); } -/* Replacement for generic do_registers_info. */ +/* Replacement for generic do_registers_info. + Print regs in pretty columns. */ + +static int +do_fp_register_row (regnum) + int regnum; +{ /* do values for FP (float) regs */ + char raw_buffer[2] [REGISTER_RAW_SIZE(FP0_REGNUM)]; + char dbl_buffer[2 * REGISTER_RAW_SIZE(FP0_REGNUM)]; + /* use HI and LO to control the order of combining two flt regs */ + int HI = (TARGET_BYTE_ORDER == BIG_ENDIAN); + int LO = (TARGET_BYTE_ORDER != BIG_ENDIAN); + double doub, flt1, flt2; /* doubles extracted from raw hex data */ + int inv1, inv2, inv3; + + /* Get the data in raw format. */ + if (read_relative_register_raw_bytes (regnum, raw_buffer[HI])) + error ("can't read register %d (%s)", regnum, reg_names[regnum]); + if (REGISTER_RAW_SIZE(regnum) == 4) + { + /* 4-byte registers: we can fit two registers per row. */ + /* Also print every pair of 4-byte regs as an 8-byte double. */ + if (read_relative_register_raw_bytes (regnum + 1, raw_buffer[LO])) + error ("can't read register %d (%s)", + regnum + 1, reg_names[regnum + 1]); + + /* copy the two floats into one double, and unpack both */ + memcpy (dbl_buffer, raw_buffer, sizeof(dbl_buffer)); + flt1 = unpack_double (builtin_type_float, raw_buffer[HI], &inv1); + flt2 = unpack_double (builtin_type_float, raw_buffer[LO], &inv2); + doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + + printf_filtered (inv1 ? " %-5s: <invalid float>" : + " %-5s%-17.9g", reg_names[regnum], flt1); + printf_filtered (inv2 ? " %-5s: <invalid float>" : + " %-5s%-17.9g", reg_names[regnum + 1], flt2); + printf_filtered (inv3 ? " dbl: <invalid double>\n" : + " dbl: %-24.17g\n", doub); + /* may want to do hex display here (future enhancement) */ + regnum +=2; + } + else + { /* eight byte registers: print each one as float AND as double. */ + int offset = 4 * (TARGET_BYTE_ORDER == BIG_ENDIAN); + + memcpy (dbl_buffer, raw_buffer[HI], sizeof(dbl_buffer)); + flt1 = unpack_double (builtin_type_float, + &raw_buffer[HI][offset], &inv1); + doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + + printf_filtered (inv1 ? " %-5s: <invalid float>" : + " %-5s flt: %-17.9g", reg_names[regnum], flt1); + printf_filtered (inv3 ? " dbl: <invalid double>\n" : + " dbl: %-24.17g\n", doub); + /* may want to do hex display here (future enhancement) */ + regnum++; + } + return regnum; +} + +/* Print a row's worth of GP (int) registers, with name labels above */ + +static int +do_gp_register_row (regnum) + int regnum; +{ /* do values for GP (int) regs */ + char raw_buffer[REGISTER_RAW_SIZE(0)]; + int ncols = MIPS_REGSIZE == 8 ? 4 : 8; /* display cols per row */ + int col, byte, start_regnum = regnum; + + /* For GP registers, we print a separate row of names above the vals */ + printf_filtered (" "); + for (col = 0; col < ncols && regnum < NUM_REGS; regnum++) + { + if (*reg_names[regnum] == '\0') + continue; /* unused register */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) + break; /* end the row: reached FP register */ + printf_filtered (MIPS_REGSIZE == 8 ? "%17s" : "%9s", + reg_names[regnum]); + col++; + } + printf_filtered (start_regnum < MIPS_NUMREGS ? "\n R%-4d" : "\n ", + start_regnum); /* print the R0 to R31 names */ + + regnum = start_regnum; /* go back to start of row */ + /* now print the values in hex, 4 or 8 to the row */ + for (col = 0; col < ncols && regnum < NUM_REGS; regnum++) + { + if (*reg_names[regnum] == '\0') + continue; /* unused register */ + if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) + break; /* end row: reached FP register */ + /* OK: get the data in raw format. */ + if (read_relative_register_raw_bytes (regnum, raw_buffer)) + error ("can't read register %d (%s)", regnum, reg_names[regnum]); + /* Now print the register value in hex, endian order. */ + if (TARGET_BYTE_ORDER == BIG_ENDIAN) + for (byte = 0; byte < REGISTER_RAW_SIZE (regnum); byte++) + printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); + else + for (byte = REGISTER_RAW_SIZE (regnum) - 1; byte >= 0; byte--) + printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); + printf_filtered (" "); + col++; + } + if (col > 0) /* ie. if we actually printed anything... */ + printf_filtered ("\n"); + + return regnum; +} + +/* MIPS_DO_REGISTERS_INFO(): called by "info register" command */ void mips_do_registers_info (regnum, fpregs) int regnum; int fpregs; { - if (regnum != -1) + if (regnum != -1) /* do one specified register */ { if (*(reg_names[regnum]) == '\0') error ("Not a valid register for the current processor type"); @@ -1636,30 +1783,17 @@ mips_do_registers_info (regnum, fpregs) mips_print_register (regnum, 0); printf_filtered ("\n"); } - else + else /* do all (or most) registers */ { - int did_newline = 0; - - for (regnum = 0; regnum < NUM_REGS; ) - { - if (((!fpregs) && regnum >= FP0_REGNUM && regnum <= FCRIR_REGNUM) - || *(reg_names[regnum]) == '\0') - { - regnum++; - continue; - } - mips_print_register (regnum, 1); - regnum++; - printf_filtered ("; "); - did_newline = 0; - if ((regnum & 3) == 0) - { - printf_filtered ("\n"); - did_newline = 1; - } - } - if (!did_newline) - printf_filtered ("\n"); + regnum = 0; + while (regnum < NUM_REGS) + if (TYPE_CODE(REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) + if (fpregs) /* true for "INFO ALL-REGISTERS" command */ + regnum = do_fp_register_row (regnum); /* FP regs */ + else + regnum += MIPS_NUMREGS; /* skip floating point regs */ + else + regnum = do_gp_register_row (regnum); /* GP (int) regs */ } } @@ -1706,7 +1840,7 @@ mips_step_skips_delay (pc) char buf[MIPS_INSTLEN]; /* There is no branch delay slot on MIPS16. */ - if (IS_MIPS16_ADDR (pc)) + if (pc_is_mips16 (pc)) return 0; if (target_read_memory (pc, buf, MIPS_INSTLEN) != 0) @@ -1909,7 +2043,7 @@ mips_skip_prologue (pc, lenient) /* Can't determine prologue from the symbol table, need to examine instructions. */ - if (IS_MIPS16_ADDR (pc)) + if (pc_is_mips16 (pc)) return mips16_skip_prologue (pc, lenient); else return mips32_skip_prologue (pc, lenient); @@ -2188,9 +2322,9 @@ gdb_print_insn_mips (memaddr, info) it's definitely a 16-bit function. Otherwise, we have to just guess that if the address passed in is odd, it's 16-bits. */ if (proc_desc) - info->mach = IS_MIPS16_ADDR (PROC_LOW_ADDR (proc_desc)) ? 16 : 0; + info->mach = pc_is_mips16 (PROC_LOW_ADDR (proc_desc)) ? 16 : 0; else - info->mach = IS_MIPS16_ADDR (memaddr) ? 16 : 0; + info->mach = pc_is_mips16 (memaddr) ? 16 : 0; /* Round down the instruction address to the appropriate boundary. */ memaddr &= (info->mach == 16 ? ~1 : ~3); @@ -2215,7 +2349,7 @@ unsigned char *mips_breakpoint_from_pc (pcptr, lenptr) { if (TARGET_BYTE_ORDER == BIG_ENDIAN) { - if (IS_MIPS16_ADDR (*pcptr)) + if (pc_is_mips16 (*pcptr)) { static char mips16_big_breakpoint[] = MIPS16_BIG_BREAKPOINT; *pcptr = UNMAKE_MIPS16_ADDR (*pcptr); @@ -2242,7 +2376,7 @@ unsigned char *mips_breakpoint_from_pc (pcptr, lenptr) } else { - if (IS_MIPS16_ADDR (*pcptr)) + if (pc_is_mips16 (*pcptr)) { static char mips16_little_breakpoint[] = MIPS16_LITTLE_BREAKPOINT; *pcptr = UNMAKE_MIPS16_ADDR (*pcptr); @@ -2276,7 +2410,7 @@ int mips_about_to_return (pc) CORE_ADDR pc; { - if (IS_MIPS16_ADDR (pc)) + if (pc_is_mips16 (pc)) /* This mips16 case isn't necessarily reliable. Sometimes the compiler generates a "jr $ra"; other times it generates code to load the return address from the stack to an accessible register (such |