URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [gdb-5.3/] [gdb/] [or1k-tdep.c] - Rev 1765
Compare with Previous | Blame | View Log
/* Target-dependent code for the or1k architecture, for GDB, the GNU Debugger. Copyright 1988-1999, Free Software Foundation, Inc. Contributed by Alessandro Forin(af@cs.cmu.edu at CMU and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "demangle.h" #include "defs.h" #include "gdb_string.h" #include "frame.h" #include "inferior.h" #include "symtab.h" #include "value.h" #include "gdbcmd.h" #include "language.h" #include "gdbcore.h" #include "symfile.h" #include "objfiles.h" #include "gdbtypes.h" #include "target.h" #include "regcache.h" #include "opcode/or32.h" /* *INDENT-OFF* */ /* Group reg name size. See or1k_reg_names. */ int or1k_group_name_sizes[OR1K_NUM_SPR_GROUPS] = { 80, 0, 0, 6, 4, 3, 22, 16, 1, 3, 2, 8 }; /* Generated reg names (max valid alias index). See or1k_spr_reg_name. */ int or1k_spr_valid_aliases[OR1K_NUM_SPR_GROUPS] = { 2047+1, 2047+1, 2047+1, 258+1, 257+1, 257+1, 78+1, 263+1, 16+1, 18+1, 256+1, 7+1 }; /* Register names. */ char *or1k_reg_names[] = { /* group 0 - general*/ "VR", "UPR", "CPUCFGR", "DMMUCFGR", "IMMUCFGR", "DCCFGR", "ICCFGR", "DCFGR", "PCCFGR", "SPR0_9", "SPR0_10", "SPR0_11", "SPR0_12", "SPR0_13", "SPR0_14", "SPR0_15", "NPC", "SR", "PPC", "SPR0_19", "SPR0_20", "SPR0_21", "SPR0_22", "SPR0_23", "SPR0_24", "SPR0_25", "SPR0_26", "SPR0_27", "SPR0_28", "SPR0_29", "SPR0_30", "SPR0_31", "EPCR0", "EPCR1", "EPCR2", "EPCR3", "EPCR4", "EPCR5", "EPCR6", "EPCR7", "EPCR8", "EPCR9", "EPCR10", "EPCR11", "EPCR12", "EPCR13", "EPCR14", "EPCR15", "EEAR0","EEAR1", "EEAR2", "EEAR3", "EEAR4", "EEAR5", "EEAR6", "EEAR7", "EEAR8", "EEAR9", "EEAR10", "EEAR11", "EEAR12", "EEAR13", "EEAR14", "EEAR15", "ESR0", "ESR1", "ESR2", "ESR3", "ESR4", "ESR5", "ESR6", "ESR7", "ESR8", "ESR9", "ESR10", "ESR11", "ESR12", "ESR13", "ESR14", "ESR15", /* gpr+vf registers generated */ /* group 1 - Data MMU - not listed, generated */ /* group 2 - Instruction MMU - not listed, generated */ /* group 3 - Data cache */ "DCCR", "DCBPR", "DCBFR", "DCBIR", "DCBWR", "DCBLR", /* group 4 - Instruction cache */ "ICCR", "ICBPR", "ICBIR", "ICBLR", /* group 5 - MAC */ "SPR5_0", "MACLO", "MACHI", /* group 6 - debug */ "DVR0", "DVR1", "DVR2", "DVR3", "DVR4", "DVR5", "DVR6", "DVR7", "DCR0", "DCR1", "DCR2", "DCR3", "DCR4", "DCR5", "DCR6", "DCR7", "DMR1", "DMR2", "DCWR0","DCWR1","DSR", "DRR", /* group 7 - performance counters unit */ "PCCR0", "PCCR1", "PCCR2", "PCCR3", "PCCR4", "PCCR5", "PCCR6", "PCCR7", "PCCMR0", "PCMR1", "PCMR2", "PCMR3", "PCMR4", "PCMR5", "PCMR6", "PCMR7", /* group 8 - power management */ "PMR", /* group 9 - PIC */ "PICMR", /* now-defunct PICPR */ "SPR9_1", "PICSR", /* group 10 - tick timer */ "TTMR", "TTCR", /* group 11 - configuration */ "CPUCFGR", "DMMUCFGR", "IMMUCFGR", "DCCFGR", "ICCFGR", "SPR11_5", "DCFGR", "PCCFGR" }; static char *or1k_gdb_reg_names[] = { /* general purpose registers */ "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15", "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23", "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31", /* Modified by CZ 12/09/01 */ /* vector/floating point registers */ "VFA0", "VFA1", "VFA2", "VFA3", "VFA4", "VFA5", "VFRV ", "VFR7", "VFR8", "VFR9", "VFR10", "VFR11", "VFR12", "VFR13", "VFR14", "VFR15", "VFR16", "VFR17", "VFR18", "VFR19", "VFR20", "VFR21", "VFR22", "VFR23", "VFR24", "VFR25", "VFR26", "VFR27", "VFR28", "VFR29", "VFR30", "VFR31", "PC", "SR", "EPCR", "ExPC", "ExEAR", "ExSR" }; static char *or1k_group_names[] = { "SYS", "DMMU", "IMMU", "DCACHE", "ICACHE", "MAC", "DEBUG", "PERF", "POWER", "PIC", "TIMER", "CONFIG" }; /* Table of or1k signals. */ static struct { char *name; char *string; } or1k_signals [NUM_OR1K_SIGNALS + 1] = { {"RSTE", "Reset Exception"}, {"BUSE", "Bus Error" }, {"DFPE", "Data Page Fault Exception"}, {"IFPE", "Instruction Page Fault Exception"}, {"LPINTE", "Low Priority Interrupt Exception"}, {"AE", "Alignment Exception"}, {"ILINSE" "Illegal Instruction" }, {"HPINTE", "High Priority Interrupt Exception"}, {"DME", "DTLB Miss Exception"}, {"IME", "ITLB Miss Exception"}, {"RE", "Range Exception"}, {"SCE", "SCE Exception"}, {"BRKPTE", "Breakpoint Exception"}, {NULL, NULL} }; const char *compare_to_names[NUM_CT_NAMES] = { "DISABLED", "FETCH", "LEA", "SEA", "LDATA", "SDATA", "AEA", "ADATA" }; const char *or1k_record_names[MAX_RECORD_NAMES] = { "PC", "LSEA", "LDATA", "SDATA", "READSPR", "WRITESPR", "INSTR" }; const char *or1k_is_names[MAX_IS_NAMES] = { "IF_NONE", "IF_NORMAL", "IF_BRANCH", "IF_DELAY" }; const char *or1k_ls_names[MAX_LS_NAMES] = { "LS_NONE", " ", "LBZ", "LBS", "LHZ", "LHS", "LWZ", "LWS", " ", " ", "SB", " ", "SH", " ", "SW", " " }; /* *INDENT-ON* */ /* The list of available "set or1k " and "show or1k " commands */ static struct cmd_list_element *htrace_cmdlist = NULL; static struct cmd_list_element *htrace_mode_cmdlist = NULL; struct htrace_struct or1k_htrace; struct hwatch_struct or1k_hwatch[MAX_HW_WATCHES]; int num_hw_watches = 0; /* Trace data. */ char trace_filename[TRACE_FILENAME_SIZE] = "trace.dat"; /* Size of trace file in records. */ int trace_size = 0; /* Previous values for buffer display. */ static int prev_length = 10; static int prev_from = 0; /* Converts regno to sprno. or1k debug unit has GPRs mapped to SPRs, which are not compact, so we are mapping them for GDB. */ /* Rewritten by CZ 12/09/01 */ int or1k_regnum_to_sprnum (int regno) { if(regno < MAX_GPR_REGS) return SPR_REG(SPR_SYSTEM_GROUP, regno + CURRENT_CID * MAX_GPR_REGS + SPR_GPR_START); if (regno < MAX_GPR_REGS + MAX_VF_REGS) return SPR_REG(SPR_SYSTEM_GROUP, regno - MAX_GPR_REGS + CURRENT_CID * MAX_GPR_REGS + SPR_VFPR_START); switch(regno) { case PS_REGNUM: return SR_SPRNUM; case PC_REGNUM: return PC_SPRNUM; /*case CCR_REGNUM: return CCR_SPRNUM(CURRENT_CID);*/ case EPCR_REGNUM: return EPCR_SPRNUM(CURRENT_CID); /*case EAR_REGNUM: return EAR_SPRNUM(CURRENT_CID); case ESR_REGNUM: return ESR_SPRNUM(CURRENT_CID);*/ default: error("Invalid register number!"); break; } return 0; } /* Builds and returns register name. */ static char tmp_name[16]; static char * or1k_spr_register_name (i) int i; { int group = i >> SPR_GROUP_SIZE_BITS; int index = i & (SPR_GROUP_SIZE - 1); switch (group) { /* Names covered in or1k_reg_names. */ case 0: /* Generate upper names. */ if (index >= SPR_GPR_START) { if (index < SPR_VFPR_START) sprintf (tmp_name, "GPR%i", index - SPR_GPR_START); else sprintf (tmp_name, "VFR%i", index - SPR_VFPR_START); return (char *)&tmp_name; } case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: { int group_start = 0; for (i = 0; i < group; i++) group_start += or1k_group_name_sizes[i]; if (index >= or1k_group_name_sizes[group]) { sprintf (tmp_name, "SPR%i_%i", group, index); return (char *)&tmp_name; } else return or1k_reg_names[group_start + index]; } /* Build names for DMMU group. */ case 1: case 2: strcpy (tmp_name, (group == 1)?"D":"I"); switch (index) { case 16: return strcat (tmp_name, "MMUCR"); case 17: return strcat (tmp_name, "MMUPR"); case 18: return strcat (tmp_name, "TLBEIR"); case 24: return strcat (tmp_name, "ATBMR0"); case 25: return strcat (tmp_name, "ATBMR1"); case 26: return strcat (tmp_name, "ATBMR2"); case 27: return strcat (tmp_name, "ATBMR3"); case 28: return strcat (tmp_name, "ATBTR0"); case 29: return strcat (tmp_name, "ATBTR0"); case 30: return strcat (tmp_name, "ATBTR0"); case 31: return strcat (tmp_name, "ATBTR0"); default: if (index >= 1024) { index -= 1024; sprintf (tmp_name, "%sTLBW%iMR%i", (group == 1)?"D":"I", index / 128, index % 128); return (char *)&tmp_name; } sprintf (tmp_name, "SPR%i_%i", group, index); return (char *)&tmp_name; } default: sprintf (tmp_name, "SPR%i_%i", group, index); return (char *)&tmp_name; } } /* Get register index in group from name. Negative if no match. */ static int or1k_regno_from_name (group, name) int group; char *name; { int i; if (toupper(name[0]) == 'S' && toupper(name[1]) == 'P' && toupper(name[2]) == 'R') { char *ptr_c; name += 3; i = (int) strtoul (name, &ptr_c, 10); if (*ptr_c != '_' || i != group) return -1; ptr_c++; i = (int) strtoul (name, &ptr_c, 10); if (*ptr_c) return -1; else return i; } for (i = 0; i < or1k_spr_valid_aliases[group]; i++) { char *s; s = or1k_spr_register_name (SPR_REG(group, i)); if (strcasecmp (name, s) == 0) return i; } return -1; } /* Returns gdb register name. */ char * or1k_register_name (regno) int regno; { return or1k_gdb_reg_names[regno]; } /* Utility function to display vf regs. */ static int do_vf_register (regnum) int regnum; { /* do values for FP (float) regs */ char *raw_buffer; /* doubles extracted from raw hex data */ double doub, flt; int inv1, inv3, byte; raw_buffer = (char *) alloca (OR1K_VF_REGSIZE); /* Get the data in raw format. */ read_register_gen (regnum, raw_buffer); flt = unpack_double (builtin_type_float, raw_buffer, &inv1); doub = unpack_double (builtin_type_double, raw_buffer, &inv3); if (inv1) printf_filtered (" %-5s flt: <invalid float>", REGISTER_NAME (regnum)); else printf_filtered (" %-5s flt:%-17.9g", REGISTER_NAME (regnum), flt); printf_filtered (inv3 ? " dbl: <invalid double> " : " dbl: %-24.17g ", doub); /* pad small registers */ for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++) printf_filtered (" "); /* Now print the register value in hex, endian order. */ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum); byte < REGISTER_RAW_SIZE (regnum); byte++) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); else for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1; byte >= 0; byte--) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); printf_filtered ("\n"); 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[MAX_REGISTER_RAW_SIZE]; /* display cols per row */ int ncols = (OR1K_64BIT_IMPLEMENTATION ? 4 : 8); int col, byte; int start_regnum = regnum; int numregs = NUM_REGS; /* For GP registers, we print a separate row of names above the vals */ printf_filtered (" "); for (col = 0; col < ncols && regnum < numregs; regnum++) { if (*REGISTER_NAME (regnum) == '\0') continue; /* unused register */ if (OR1K_IS_VF(regnum)) break; /* end the row: reached VF register */ printf_filtered (OR1K_64BIT_IMPLEMENTATION ? "%17s" : "%9s", REGISTER_NAME (regnum)); col++; } printf_filtered ("\n "); 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 < numregs; regnum++) { /* unused register? */ if (*REGISTER_NAME (regnum) == '\0') continue; /* end row: reached VF register? */ if (OR1K_IS_VF(regnum)) break; /* OK: get the data in raw format. */ read_register_gen (regnum, raw_buffer); /* pad small registers */ for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++) printf_filtered (" "); /* Now print the register value in hex, endian order. */ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum); byte < REGISTER_RAW_SIZE (regnum); byte++) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); else for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1; byte >= 0; byte--) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); printf_filtered (" "); col++; } /* ie. if we actually printed anything... */ if (col > 0) printf_filtered ("\n"); return regnum; } /* Replacement for generic do_registers_info. Print regs in pretty columns. */ static void print_register (regnum, all) int regnum, all; { int offset; char raw_buffer[MAX_REGISTER_RAW_SIZE]; /* Get the data in raw format. */ read_register_gen (regnum, raw_buffer); /* If virtual format is floating, print it that way. */ if (OR1K_IS_VF (regnum)) do_vf_register (regnum); else { int byte; printf_filtered ("%-16s\t", REGISTER_NAME (regnum)); /* pad small registers */ for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++) printf_filtered (" "); /* Now print the register value in hex, endian order. */ if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum); byte < REGISTER_RAW_SIZE (regnum); byte++) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); else for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1; byte >= 0; byte--) printf_filtered ("%02x", (unsigned char) raw_buffer[byte]); printf_filtered (" "); } } /* DO_REGISTERS_INFO: called by "info register" command */ void or1k_do_registers_info (regnum, fpregs) int regnum; int fpregs; { if (fpregs && !or1k_implementation.vf_present) { warning ("VF register set not present in this implementation."); fpregs = 0; } if (regnum != -1) { /* do one specified register */ if (*(REGISTER_NAME (regnum)) == '\0') error ("Not a valid register for the current processor type"); print_register (regnum, 0); printf_filtered ("\n"); } else /* do all (or most) registers */ { regnum = 0; while (regnum < NUM_REGS) { if (OR1K_IS_VF (regnum)) /* true for "INFO ALL-REGISTERS" command */ if (fpregs) /* FP regs */ regnum = do_vf_register (regnum); else /* skip floating point regs */ regnum++; else /* GP (int) regs */ regnum = do_gp_register_row (regnum); } } } /* Given the address at which to insert a breakpoint (BP_ADDR), what will that breakpoint be? For or1k, we have a breakpoint instruction. Since all or1k instructions are 32 bits, this is all we need, regardless of address. K is not used. */ unsigned char * or1k_breakpoint_from_pc (bp_addr, bp_size) CORE_ADDR * bp_addr; int *bp_size; { static char breakpoint[] = BRK_INSTR_STRUCT; *bp_size = OR1K_INSTLEN; return breakpoint; } /* Return the string for a signal. Replacement for target_signal_to_string (sig). NOT USED. */ char *or1k_signal_to_string (sig) enum target_signal sig; { if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST)) return or1k_signals[sig].string; else if (sig <= TARGET_SIGNAL_LAST + NUM_OR1K_SIGNALS) return or1k_signals[sig - TARGET_SIGNAL_LAST].string; else return 0; } /* Return the name for a signal. */ char * or1k_signal_to_name (sig) enum target_signal sig; { if (sig >= TARGET_SIGNAL_LAST) if (sig <= TARGET_SIGNAL_LAST + NUM_OR1K_SIGNALS) return or1k_signals[sig - TARGET_SIGNAL_LAST].name; else /* I think the code which prints this will always print it along with the string, so no need to be verbose. */ return "?"; if (sig == TARGET_SIGNAL_UNKNOWN) return "?"; return 0; } /* Given a name, return its signal. NOT USED. */ enum target_signal or1k_signal_from_name (name) char *name; { enum target_signal sig; /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD" for TARGET_SIGNAL_SIGCHLD. SIGIOT, on the other hand, is more questionable; seems like by now people should call it SIGABRT instead. */ /* This ugly cast brought to you by the native VAX compiler. */ for (sig = TARGET_SIGNAL_FIRST; or1k_signal_to_name (sig) != NULL; sig = (enum target_signal) ((int) sig + 1)) if (STREQ (name, or1k_signal_to_name (sig))) return sig; return TARGET_SIGNAL_UNKNOWN; } /* Given a return value in `regbuf' with a type `valtype', extract and copy its value into `valbuf'. */ void or1k_extract_return_value (valtype, regbuf, valbuf) struct type *valtype; char regbuf[REGISTER_BYTES]; char *valbuf; { if (TYPE_CODE_FLT == TYPE_CODE (valtype)) memcpy (valbuf, ®buf[REGISTER_BYTE (VFRV_REGNUM)], TYPE_LENGTH (valtype)); else memcpy (valbuf, ®buf[REGISTER_BYTE (RV_REGNUM)], TYPE_LENGTH (valtype)); } /* Given a register index, return the first byte of the register within a remote protocol packet. This applies only to serial targets, not jtag or sim. */ int or1k_register_byte(regnum) int regnum; { int byte_offset; byte_offset = 0; if (regnum < MAX_GPR_REGS) { if (regnum < NUM_GPR_REGS) return byte_offset + regnum * OR1K_GPR_REGSIZE; else return -1; } byte_offset += NUM_GPR_REGS * OR1K_GPR_REGSIZE; regnum -= MAX_GPR_REGS; if (regnum < MAX_VF_REGS) { if (regnum < NUM_VF_REGS) return byte_offset + regnum * OR1K_VF_REGSIZE; else return -1; } /* Must be PC, SR, or EPC */ byte_offset += NUM_VF_REGS * OR1K_VF_REGSIZE; regnum -= MAX_VF_REGS; if (regnum < 3) return byte_offset + regnum * OR1K_SPR_REGSIZE; /* Illegal register */ return -1; } /* Number of bytes of storage in the actual machine representation for register N. NOTE: This indirectly defines the register size transfered by the GDB protocol. If we have 64bit processor implementation, GPR register raw size is 8B, otherwise 4B. */ int or1k_register_raw_size(int regnum) { int byte_offset; if (regnum < MAX_GPR_REGS) { if (regnum < NUM_GPR_REGS) return OR1K_GPR_REGSIZE; else return 0; } regnum -= MAX_GPR_REGS; if (regnum < MAX_VF_REGS) { if (regnum < NUM_VF_REGS) return OR1K_VF_REGSIZE; else return 0; } /* Must be PC, SR, or EPC */ regnum -= MAX_VF_REGS; if (regnum < 3) return OR1K_SPR_REGSIZE; /* Illegal register */ return 0; } /* Extra arch-specific data tied to frame */ struct frame_extra_info { /* Size of stack frame, in bytes. Produced by skip_prologue() */ int frame_size; /* List of frame offsets of all registers saved in a function's prologue. This is deduced by skip_prologue(). Offset is in bytes, relative to sp. If value is -1, corresponding reg is not saved by the prologue code. */ int saved_reg_frame_offset[NUM_REGS]; /* Address of first instruction after the last prologue instruction; Note that there may be instructions from the function's body intermingled with the prologue. If value is -1, not initialized. */ CORE_ADDR after_prologue; }; /* Initialize arch-specific frame data */ void or1k_init_extra_frame_info (int fromleaf, struct frame_info *frame) { int i; frame->extra_info = (struct frame_extra_info *) frame_obstack_alloc (sizeof (struct frame_extra_info)); frame->extra_info->after_prologue = -1; frame->extra_info->frame_size = -1; for (i = 0; i < NUM_REGS; i++) frame->extra_info->saved_reg_frame_offset[i] = -1; } /* For stack frame sizes less than 0x8000, the or1k version of gcc emits the following prologue: l.addi r1, r1, -<STACK_FRAME_SIZE> l.sw <FP_OFFSET>(r1),r2 l.addi r2, r1, <STACK_FRAME_SIZE> ; Save regs that will be clobbered l.sw <OFFSET_Rx>(r1),rx l.sw <OFFSET_Ry>(r1),ry ; ... */ /* FIXME: Does not work with frames greater than 0x7fff in size */ /* If pframeless is non-NULL, only parse enough of the prologue to determine if a function has a frame or not and return the result in *pframeless. This may save some remote transactions with the target. */ CORE_ADDR or1k_skip_prologue (CORE_ADDR pc, struct frame_info *fi) { unsigned long insn; CORE_ADDR skip_pc; CORE_ADDR func_addr, func_end; struct symtab_and_line sal; int i, frameless; int offset = 0; int rB, immediate, immediate_hi; int* saved_reg_frame_offset; /* Check to see if prologue analysis is cached from prior call */ if (fi && fi->extra_info->after_prologue != -1) return fi->extra_info->after_prologue; if (fi) saved_reg_frame_offset = &fi->extra_info->saved_reg_frame_offset[0]; /* Is there a prologue? */ insn = or1k_fetch_instruction (pc); if ((insn & 0xFFFF0000) != 0x9c210000) /* l.addi r1,r1,I */ goto done; pc += OR1K_INSTLEN; /* Get the link register */ insn = or1k_fetch_instruction (pc); if ((insn & 0xfc1ff800) != 0xd4014800) /* l.sw I(r1),r9 */ goto fp_save; immediate_hi = (insn & 0x03E00000) >> 10; immediate = (insn & 0x000007FF) | immediate_hi; pc += OR1K_INSTLEN; if (fi) saved_reg_frame_offset[9] = saved_reg_frame_offset[PC_REGNUM] = immediate; fp_save: insn = or1k_fetch_instruction (pc); if ((insn & 0xfc1ff800) != 0xd4011000) /* l.sw I(r1),r2 */ goto fp_adjust; immediate_hi = (insn & 0x03E00000) >> 10; immediate = (insn & 0x000007FF) | immediate_hi; pc += OR1K_INSTLEN; if (fi) saved_reg_frame_offset[2] = immediate; fp_adjust: insn = or1k_fetch_instruction (pc); if ((insn & 0xFFFF0000) != 0x9c410000) /* l.addi r2,r1,I */ goto done; if (fi) fi->extra_info->frame_size = insn & 0xFFFF; pc += OR1K_INSTLEN; /* Skip stored registers. */ insn = or1k_fetch_instruction (pc); while ((insn & 0xfc1f0000) == 0xd4010000) /* l.sw I(r1),rx */ { rB = (insn & 0x0000F800) >> 11; immediate_hi = (insn & 0x03E00000) >> 10; immediate = (insn & 0x000007FF) | immediate_hi; /* get saved reg. */ if (fi) saved_reg_frame_offset[rB] = immediate; pc += OR1K_INSTLEN; insn = or1k_fetch_instruction (pc); } done: if (fi) fi->extra_info->after_prologue = pc; return pc; } /* Determines whether this function has frame. */ int or1k_frameless_function_invocation (struct frame_info *fi) { int frameless; CORE_ADDR func_start, after_prologue; func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET); /* If we don't skip pc, we don't have even shortest possible prologue. */ after_prologue = or1k_skip_prologue (func_start, fi); frameless = (after_prologue <= func_start); return frameless; } /* Given a GDB frame, determine the address of the calling function's frame. This will be used to create a new GDB frame struct, and then INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */ CORE_ADDR or1k_frame_chain (frame) struct frame_info *frame; { CORE_ADDR fp = 0; if (USE_GENERIC_DUMMY_FRAMES) { if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)) /* dummy frame same as caller's frame */ return frame->frame; } if (inside_entry_file (frame->pc) || frame->pc == entry_point_address ()) return 0; if (frame->signal_handler_caller) fp = read_memory_integer (frame->frame, 4); else if (frame->next != NULL && frame->next->signal_handler_caller && FRAMELESS_FUNCTION_INVOCATION (frame)) /* A frameless function interrupted by a signal did not change the frame pointer. */ fp = FRAME_FP (frame); else { unsigned long func_pc = get_pc_function_start(frame->pc); unsigned long insn = read_memory_integer(func_pc,4); int i; int offset = 0; /* The first instruction should tell us the number of bytes in our frame. If it isn't we're in trouble because the function is without a prologue... */ if ((insn & 0xFFFF0000) == 0x9c210000) /* l.addi r1,r1,I */ { /* Sign extend immediate */ int immediate = (long)(insn << 16) >> 16; int frame_size = -immediate; /* Look for the storage of the frame pointer in the function prologue.. */ unsigned long insn = read_memory_integer(func_pc+4,4); /* If this is not the l.sw I(r1),r2 we're looking for, give it a second try. */ if( (insn&0xFC1FF800) != 0xd4011000 ) insn = read_memory_integer(func_pc+8,4); /* If bits are 31 - 26 are %110101, and bits 20 - 16 are %00001, and bits 15 - 11 are %00010, then our frame pointer lies at the offset specified by bits [25-21][10-0]. */ int code = insn >> 26; int r1 = (insn & 0x001F0000) >> 16; int r2 = (insn & 0x0000F800) >> 11; int idx_h = (insn & 0x03E00000) >> 10; int idx = (insn & 0x000007FF) | idx_h; if(code == 0x35 && r1 == 1 && r2 == 2) { offset = idx - frame_size; fp = read_memory_integer (frame->frame + offset, 4); } } } if (USE_GENERIC_DUMMY_FRAMES) { CORE_ADDR fpp, lr; lr = (CORE_ADDR)read_register (LR_REGNUM); if (lr == entry_point_address ()) if (fp != 0 && (fpp = read_memory_integer (fp, 4)) != 0) if (PC_IN_CALL_DUMMY (lr, fpp, fpp)) return fpp; } return fp; } /* The code to store, into a struct frame_saved_regs, the addresses of the saved registers of frame described by FRAME_INFO. This includes special registers such as pc and fp saved in special ways in the stack frame. sp is even more special: the address we return for it IS the sp for the next frame. */ void or1k_init_saved_regs (struct frame_info *fi) { int i; CORE_ADDR frame_addr; CORE_ADDR func_pc = get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET; int pc_found = 0; frame_saved_regs_zalloc (fi); /* Skip prologue sets frame_size and register frame save offsets which will both be used shortly. */ or1k_skip_prologue (func_pc, fi); /* If the frame_size is less than 0, we have hit an assembly routine which we can't traverse beyond. Let's give up here, because attempting to continue will only lead to trouble. */ if(fi->extra_info->frame_size < 0) { printf("Found a function without a prologue at 0x%08x\n",func_pc); printf("Frame pc was at 0x%08x\n",fi->pc); return; } for (i = 0; i < NUM_GPR_REGS + NUM_VF_REGS; i++) if (fi->extra_info->saved_reg_frame_offset[i] >= 0) fi->saved_regs[i] = fi->frame + (fi->extra_info->saved_reg_frame_offset[i] - fi->extra_info->frame_size); /* We want to make sure we fill in the PC with the value of the r9 register from the NEXT frame, and that the value of r1 is the correct value of r1 for the next frame, which can be calculated by adding the frame_size to the frame pointer. */ fi->saved_regs[1] = fi->frame - fi->extra_info->frame_size; if(fi->saved_regs[LR_REGNUM]) fi->saved_regs[PC_REGNUM] = read_memory_integer(fi->saved_regs[LR_REGNUM],4); else fi->saved_regs[PC_REGNUM] = (CORE_ADDR)read_register(LR_REGNUM); } static CORE_ADDR read_next_frame_reg (fi, regno) struct frame_info *fi; int regno; { for (; fi; fi = fi->next) { /* We have to get the saved sp from the sigcontext if it is a signal handler frame. */ if (regno == SP_REGNUM && !fi->signal_handler_caller) return fi->frame; else { if (fi->saved_regs == NULL) or1k_init_saved_regs (fi); if (fi->saved_regs[regno]) { if(regno == SP_REGNUM || regno == PC_REGNUM) return fi->saved_regs[regno]; else return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE); } } } return (CORE_ADDR)read_register (regno); } /* Find the caller of this frame. We do this by seeing if LR_REGNUM is saved in the stack anywhere, otherwise we get it from the registers. */ CORE_ADDR or1k_frame_saved_pc (fi) struct frame_info *fi; { CORE_ADDR saved_pc; /* We have to get the saved pc from the sigcontext if it is a signal handler frame. */ if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame)) saved_pc = read_memory_integer (fi->frame, OR1K_GPR_REGSIZE); else saved_pc = read_next_frame_reg (fi, PC_REGNUM); return ADDR_BITS_REMOVE (saved_pc); } /* Discard from the stack the innermost frame, restoring all registers. */ void or1k_pop_frame () { register int regnum; struct frame_info *frame = get_current_frame (); CORE_ADDR new_sp = FRAME_FP (frame); write_register (PC_REGNUM, FRAME_SAVED_PC (frame)); if (frame->saved_regs == NULL) or1k_init_saved_regs (frame); for (regnum = 0; regnum < NUM_REGS; regnum++) { if (regnum != SP_REGNUM && regnum != PC_REGNUM && frame->saved_regs[regnum] >= 0) write_register (regnum, read_memory_integer (frame->saved_regs[regnum], OR1K_GPR_REGSIZE)); } write_register (SP_REGNUM, new_sp); flush_cached_frames (); } CORE_ADDR or1k_push_arguments (nargs, args, sp, struct_return, struct_addr) int nargs; struct value* *args; CORE_ADDR sp; int struct_return; CORE_ADDR struct_addr; { int argreg; int float_argreg; int argnum; int len = 0; int stack_offset = 0; /* Initialize the integer and float register pointers. */ argreg = A0_REGNUM; float_argreg = VFA0_REGNUM; /* The struct_return pointer occupies the RV value register. */ if (struct_return) write_register (RV_REGNUM, struct_addr); /* Now load as many as possible of the first arguments into registers, and push the rest onto the stack. Loop thru args from first to last. */ for (argnum = 0; argnum < nargs; argnum++) { char *val; char valbuf[MAX_REGISTER_RAW_SIZE]; struct value * arg = args[argnum]; struct type *arg_type = check_typedef (VALUE_TYPE (arg)); int len = TYPE_LENGTH (arg_type); enum type_code typecode = TYPE_CODE (arg_type); /* The EABI passes structures that do not fit in a register by reference. In all other cases, pass the structure by value. */ if (len > OR1K_GPR_REGSIZE && (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION)) { store_address (valbuf, OR1K_GPR_REGSIZE, VALUE_ADDRESS (arg)); typecode = TYPE_CODE_PTR; len = OR1K_GPR_REGSIZE; val = valbuf; } else { val = (char *) VALUE_CONTENTS (arg); if (typecode == TYPE_CODE_FLT /* Doubles are not stored in regs on 32b target. */ && len <= OR1K_VF_REGSIZE && OR1K_VF_PRESENT) { if (float_argreg <= OR1K_LAST_FP_ARG_REGNUM) { CORE_ADDR regval = extract_address (val, len); write_register (float_argreg++, regval); } else { write_memory ((CORE_ADDR) sp, val, OR1K_VF_REGSIZE); sp -= OR1K_STACK_ALIGN; } } else { if (argreg <= OR1K_LAST_ARG_REGNUM) { CORE_ADDR regval = extract_address (val, len); write_register (argreg++, regval); } else { write_memory ((CORE_ADDR) sp, val, OR1K_GPR_REGSIZE); sp -= OR1K_STACK_ALIGN; } } } } /* Return adjusted stack pointer. */ return sp; } /* Return nonzero when instruction has delay slot. */ int is_delayed (insn) unsigned long insn; { int index; index = insn_decode (insn); return or32_opcodes[index].flags & OR32_IF_DELAY; } int or1k_step_skips_delay (pc) CORE_ADDR pc; { char buf[OR1K_INSTLEN]; if (target_read_memory (pc, buf, OR1K_INSTLEN) != 0) /* If error reading memory, guess that it is not a delayed branch. */ return 0; return is_delayed ((unsigned long) extract_unsigned_integer (buf, OR1K_INSTLEN)); } CORE_ADDR or1k_push_return_address (pc, sp) CORE_ADDR pc; CORE_ADDR sp; { /* Set the return address register to point to the entry point of the program, where a breakpoint lies in wait. */ write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ()); return sp; } /* Parses args for spr name and puts result into group and index. */ static char * parse_spr_params (args, group, index) char *args; int *group, *index; { *index = -1; if (args) { int i; char *ptr_c; /* Check if group number was supplied. */ ptr_c = args; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; *group = (int) strtoul (args, &ptr_c, 0); if (*ptr_c != 0) { *group = OR1K_NUM_SPR_GROUPS; /* check for group name */ for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) if (strcasecmp (or1k_group_names[i], args) == 0) { *group = i; break; } /* Invalid group => check all register names in all groups. */ if (*group >= OR1K_NUM_SPR_GROUPS) { for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) { int regno; regno = or1k_regno_from_name (i, args); if (regno >= 0) { *group = i; *index = regno; break; } } } } if (*group < 0 || *group >= OR1K_NUM_SPR_GROUPS) error ("Invalid group or register.\n"); if (*index < 0) { printf ("a'%s'\n", args); args += strlen(args) + 1; printf ("b'%s'\n", args); if (*args != 0) { ptr_c = args; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; *index = (int) strtoul (args, &ptr_c, 0); if (*ptr_c != 0) *index = or1k_regno_from_name (*group, args); } if (*index < 0) { printf_filtered ("No register supplied. Valid registers are:\n"); for (i = 0; i < or1k_spr_valid_aliases[*group]; i++) { char reg_name[16]; char *gen_name = or1k_spr_register_name (SPR_REG(*group, i)); sprintf (reg_name, "SPR%i_%i", *group, i); if (strcmp (reg_name, gen_name) != 0) printf_filtered ("%s\t", gen_name); } printf_filtered ("\n"); return args + strlen(args) + 1; } } } else { /* No parameters - print groups */ int i; printf_filtered ("No parameter supplied. Valid groups are:\n"); for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++) printf_filtered ("%s\t", or1k_group_names[i]); printf_filtered ("\nSingle register name or register name or number after the group can be also supplied.\n"); return args; } return args + strlen(args) + 1; } /* SPR register info. */ void info_spr_command (args, from_tty) char *args; int from_tty; { int group, index; parse_spr_params (args, &group, &index); if (index >= 0) { unsigned long value = or1k_read_spr_reg (SPR_REG(group, index)); printf_unfiltered ("%s.%s = SPR%i_%i = %i(%x)\n", or1k_group_names[group], or1k_spr_register_name (SPR_REG(group, index)), group, index, value, value); } } void info_trace_command (args, from_tty) char *args; int from_tty; { unsigned char i; int j; printf_filtered (" add insn res time\n"); i = or1k_read_spr_reg (SPR_REG(6, 255)); for (j = 0; j < 256; j++, i++) printf_filtered ("%03d %03u %08x %08x %08x %08x\n", 255 - j, i, or1k_read_spr_reg (SPR_REG(6, 0x100 + i)), or1k_read_spr_reg (SPR_REG(6, 0x200 + i)), or1k_read_spr_reg (SPR_REG(6, 0x300 + i)), or1k_read_spr_reg (SPR_REG(6, 0x400 + i))); } /* Set SPR register. */ void spr_command (args, from_tty) char *args; int from_tty; { int group, index; char *nargs = parse_spr_params (args, &group, &index); if (index >= 0) { unsigned long prev; unsigned long value; char *ptr_c; /* Any arguments left? */ if (args + strlen(args) >= nargs) error ("Invalid register value."); prev = or1k_read_spr_reg (SPR_REG(group, index)); ptr_c = nargs; while (*ptr_c != ' ' && *ptr_c != 0) ptr_c++; *ptr_c = 0; value = strtoul (nargs, &ptr_c, 0); if (*ptr_c != 0) error ("Invalid register value."); or1k_write_spr_reg (SPR_REG(group, index), value); printf_unfiltered ("%s.%s (SPR%i_%i) set to %i(%x), was:%i(%x)\n", or1k_group_names[group], or1k_spr_register_name (SPR_REG(group, index)), group, index, value, value, prev, prev); } } /* Calls extended command on target. */ void sim_command (args, from_tty) char *args; int from_tty; { or1k_sim_cmd (args, from_tty); } static union exp_element exp_error; /* Parses compare variable and returns it into ct. */ union exp_element * or1k_parse_ct (exp, ct) union exp_element *exp; int *ct; { int i; if (exp->opcode != OP_INTERNALVAR) error ("Valid lvalue expected."); exp++; for (i = 1; i < NUM_CT_NAMES; i++) if (strcasecmp (compare_to_names[i], exp->internalvar->name) == 0) break; if (i >= NUM_CT_NAMES) error ("Invalid compare to operand."); *ct = i; exp++; if (exp->opcode != OP_INTERNALVAR) return &exp_error; exp++; return exp; } /* Parses compare value and returns it into cv. */ union exp_element * or1k_parse_cv (exp, cv) union exp_element *exp; unsigned int *cv; { switch (exp->opcode) { case UNOP_IND: exp++; exp = or1k_parse_cv (exp, cv); *cv = or1k_fetch_word (*cv); break; case OP_LONG: exp += 2; *cv = exp->longconst; exp += 2; break; case OP_REGISTER: exp++; *cv = (unsigned int)read_register (exp->longconst); exp += 2; break; default: error ("Value expected."); } return exp; } /* Parse conditional. Puts freshly allocated array of matchpoints into match. */ union exp_element * or1k_parse_cond (exp, match, nmatch) union exp_element *exp; struct matchpoint **match; int *nmatch; { unsigned int ct; *match = (struct matchpoint *) malloc (sizeof (struct matchpoint)); *nmatch = 1; switch (exp->opcode) { case BINOP_EQUAL: (*match)->dcr.cc = CC_EQUAL; break; case BINOP_NOTEQUAL: (*match)->dcr.cc = CC_NEQUAL; break; case BINOP_LESS: (*match)->dcr.cc = CC_LESS; break; case BINOP_GTR: (*match)->dcr.cc = CC_GREAT; break; case BINOP_LEQ: (*match)->dcr.cc = CC_LESSE; break; case BINOP_GEQ: (*match)->dcr.cc = CC_GREATE; break; case BINOP_BITWISE_AND: (*match)->dcr.cc = CC_MASKED; break; default: return &exp_error; } exp++; (*match)->dcr.dp = 1; (*match)->dcr.sc = 0; if (exp->opcode == OP_INTERNALVAR) { exp = or1k_parse_ct (exp, &ct); exp = or1k_parse_cv (exp, &(*match)->dvr); } else { exp = or1k_parse_cv (exp, &(*match)->dvr); exp = or1k_parse_ct (exp, &ct); } (*match)->dcr.ct = ct; (*match)->chain_type = CHAINING_NONE; (*match)->cause_breakpoint = 0; return exp; } /* Parses expression with && or || operators. Puts freshly allocated array of matchpoints into match. valid & 1: && is allowed, valid & 2: || is allowed. */ union exp_element * or1k_parse_any (exp, match, nmatch, valid) union exp_element *exp; struct matchpoint **match; int *nmatch; int valid; { union exp_element *tmp; int first_and_only = 0, first_or_only = 0; struct matchpoint *tmp_match1, *tmp_match2, *tmpm; int tmp_nmatch1, tmp_nmatch2, tmpn; switch (exp->opcode) { case BINOP_LOGICAL_AND: if (!(valid & 1)) return &exp_error; exp++; /* Parse first argument. */ tmp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, 1); if (tmp == &exp_error) exp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, valid); else { /* and_only successful */ exp = tmp; first_and_only = 1; } if (exp == &exp_error) return &exp_error; /* Parse second argument. */ if (first_and_only) exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, valid); else exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 1); if (exp == &exp_error) return &exp_error; if (first_and_only) { /* Exchange structures, so that and_only is listed last. */ struct matchpoint *tmpm = tmp_match1; int tmpn = tmp_nmatch1; tmp_match1 = tmp_match2; tmp_nmatch1 = tmp_nmatch2; tmp_match2 = tmpm; tmp_nmatch2 = tmpn; } *nmatch = tmp_nmatch1 + tmp_nmatch2; *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint)); memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint)); free (tmp_match1); tmp_match2[0].chain_type = CHAINING_AND; memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint)); free (tmp_match2); return exp; case BINOP_LOGICAL_OR: if (!(valid & 2)) return &exp_error; exp++; /* Parse first argument. */ tmp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, 2); if (tmp == &exp_error) exp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, valid); else { /* and_only successful */ exp = tmp; first_or_only = 1; } if (exp == &exp_error) return &exp_error; /* Parse second argument. */ if (first_or_only) exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, valid); else exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 2); if (exp == &exp_error) return &exp_error; if (first_or_only) { /* Exchange structures, so that and_only is listed first. */ struct matchpoint *tmpm = tmp_match1; int tmpn = tmp_nmatch1; tmp_match1 = tmp_match2; tmp_nmatch1 = tmp_nmatch2; tmp_match2 = tmpm; tmp_nmatch2 = tmpn; } *nmatch = tmp_nmatch1 + tmp_nmatch2; *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint)); memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint)); free (tmp_match1); tmp_match2[0].chain_type = CHAINING_OR; memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint)); free (tmp_match2); return exp; default: return or1k_parse_cond (exp, match, nmatch); } } /* Parses sequence of ||s. Puts freshly allocated array of matchpoints into match. */ union exp_element * or1k_parse_or (exp, match, nmatch, set_break) union exp_element *exp; struct matchpoint **match; int *nmatch; int set_break; { struct matchpoint *tmp_match1, *tmp_match2; int tmp_nmatch1, tmp_nmatch2; switch (exp->opcode) { case BINOP_LOGICAL_OR: exp++; exp = or1k_parse_or (exp, &tmp_match1, &tmp_nmatch1); if (exp == &exp_error) return &exp_error; exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 3); if (set_break) { tmp_match1[tmp_nmatch1 - 1].cause_breakpoint = 1; tmp_match2[tmp_nmatch2 - 1].cause_breakpoint = 1; } *nmatch = tmp_nmatch1 + tmp_nmatch2; *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint)); memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint)); free (tmp_match1); memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint)); free (tmp_match2); return exp; default: return or1k_parse_any (exp, match, nmatch, 3); if (set_break) (*match)[*nmatch - 1].cause_breakpoint = 1; } } /* Prints single matchpoint from specified struct. */ static void print_matchpoint_struct (mp) struct matchpoint *mp; { printf_filtered ("%-6s (%i) %u, ON=%i, chain_type=%i, cause break=%i\n", compare_to_names[mp->dcr.ct], mp->dcr.cc, mp->dvr, mp->dcr.dp, mp->chain_type, mp->cause_breakpoint); } /* Build watchpoint(s) based on given structure. */ static void set_matchpoints (match, nmatch) struct matchpoint *match; int nmatch; { int i; debug_regs_changed = 1; sift_matchpoints (); for (i = 0; i < nmatch; i++) { int num = or1k_implementation.num_used_matchpoints; dcr[num] = match[i].dcr; dvr[num] = match[i].dvr; /* Set chaining bits. */ dmr1 &= ~(3 << (2 * num)); dmr1 |= match[i].chain_type << (2 * num); /* Set watchpoint bits */ dmr2 &= 1 << num; dmr2 |= match[i].cause_breakpoint << num; matchpoint_user_count[i]++; or1k_implementation.num_used_matchpoints++; } } /* Returns nonzero, if matchpoints [start .. start+nmatch-1] are equal to match record. */ static int matchpoint_matches (start, match, nmatch) int start; struct matchpoint *match; int nmatch; { int i; if (nmatch + start >= or1k_implementation.num_matchpoints) return 0; for (i = 0; i < nmatch; i++) { int j = i + start; /* Everything exept cause breakpoint must match. */ if (dcr[j].dp != match[i].dcr.dp || dcr[j].ct != match[i].dcr.ct || dcr[j].cc != match[i].dcr.cc || dcr[j].sc != match[i].dcr.sc || dvr[j] != match[i].dvr || match[i].chain_type != (dmr1 >> (2 * j)) & 3) return 0; } return 1; } static void hwatch_command (arg, from_tty) char *arg; int from_tty; { struct expression *exp; int i, nfree, nmatch, remove = 0; struct matchpoint *match; if (arg == NULL) arg = ""; if (strncasecmp ("remove ", arg, 7) == 0) { arg += 7; remove = 1; } /* Parse arguments. */ exp = parse_exp_1 (&arg, 0, 0); #ifdef DEBUG dump_prefix_expression (exp, gdb_stdout, "expr1"); #endif if (or1k_parse_or (&exp->elts[0], &match, &nmatch, 1) == &exp_error) error ("Watchpoint too complex."); for (i = 0; i < nmatch; i++) print_matchpoint_struct (&match[i]); if (remove) { int start = -1; int cleared = 0; if (num_hw_watches <= 0) error ("No extended hardware supported watchpoints present."); for (i = 0; i < num_hw_watches; i++) if (matchpoint_matches (or1k_hwatch[i].matchpoint_start, match, nmatch)) { start = or1k_hwatch[i].matchpoint_start; break; } if (start < 0) error ("Watchpoint not found."); for (i = 0; i < nmatch; i++) { int j = start + i; if (--matchpoint_user_count[j] <= 0) { debug_regs_changed = 1; memset (&dcr[j], 0, sizeof (dcr[j])); or1k_implementation.num_used_matchpoints--; cleared = 1; } } if (!cleared) warning ("No matchpoint(s) freed. Resources are busy."); } else { if (num_hw_watches >= MAX_HW_WATCHES) error ("Number of watchpoints too large."); /* Now we have to find out if given prefix expression matches our HW based support. It may take up to or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints. */ nfree = or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints; if (nmatch > nfree) error ("Not enough free matchpoint resources."); /* Build watchpoint(s) based on just built structure. */ or1k_hwatch[num_hw_watches].matchpoint_start = or1k_implementation.num_used_matchpoints; set_matchpoints (match, nmatch); num_hw_watches++; printf_unfiltered ("Watchpoint successfully allocated.\n"); } free (match); free (exp); } static void htrace_command (args, from_tty) char *args; int from_tty; { help_list (htrace_cmdlist, "htrace ", all_commands, gdb_stdout); } static void htrace_mode_command (args, from_tty) char *args; int from_tty; { help_list (htrace_mode_cmdlist, "htrace mode ", all_commands, gdb_stdout); } static void htrace_mode_contin_command (args, from_tty) char *args; int from_tty; { or1k_htrace.moder.contin = 1; printf_unfiltered ("Continuous trace mode set.\n"); } static void htrace_mode_suspend_command (args, from_tty) char *args; int from_tty; { or1k_htrace.moder.contin = 0; printf_unfiltered ("Suspend trace mode set.\n"); } static void print_event_struct (event, stop) struct htrace_event_struct *event; int stop; { int i; if (event->operation == TRIGOP_ANY) if (stop) printf_filtered ("not active"); else printf_filtered ("always active"); else { char *comma; if (event->operation == TRIGOP_AND) comma = "&("; else comma = "|("; if (event->is_valid) { printf_filtered ("%s%s", comma, or1k_is_names[event->is_trig]); comma = ", "; } if (event->ls_valid) { printf_filtered ("%s%s", comma, or1k_ls_names[event->ls_trig]); comma = ", "; } if (event->bp_valid) { printf_filtered ("%sbreak", comma); comma = ", "; } if (event->wp_valid) for (i = 0; i < 11; i++) if ((event->wp_trig >> i) & 1) { printf_filtered ("%sWP%i", comma, i); comma = ", "; } if (comma[0] == ',') printf_filtered (")"); else printf_filtered ("not active"); } } static void print_record_struct (record) struct htrace_record_struct *record; { int i; char *comma = ""; for (i = 0; i < MAX_RECORD_NAMES; i++) { if ((record->rec >> i)&1) { printf_filtered ("%s%s", comma, or1k_record_names[i]); comma = ", "; } } if (!*comma) printf_unfiltered ("none"); } static void htrace_info_command (args, from_tty) char *args; int from_tty; { int i; printf_filtered ("Trace trigger: "); print_event_struct (&or1k_htrace.trig, 0); printf_filtered ("\nTrace qualifier: "); print_event_struct (&or1k_htrace.qual, 0); for (i = 0; i < MAX_MATCHPOINTS; i++) { printf_filtered ("\n WP%i records: ", i); print_record_struct (&or1k_htrace.recwp[i]); } printf_filtered ("\n BP records: "); print_record_struct (&or1k_htrace.recbp); printf_filtered ("\nTrace stop: "); print_event_struct (&or1k_htrace.stop, 1); printf_filtered ("\n"); } /* Parses event from given string. Result is placed into event structure, and previously allocated resources are freed. Parameter stop is nonzero, when we are parsing for stop criteria. */ static void parse_event (args, event, stop) char *args; struct htrace_event_struct *event; int stop; { int i, op_type = 0, was_last_op = 1, any = 0; /* Release previous resources. */ for (i = 0; i < MAX_MATCHPOINTS; i++) { if ((event->wp_trig << i) & 1) if (--matchpoint_user_count[i] <= 0) { memset (&dcr[i], 0, sizeof (dcr[i])); debug_regs_changed = 1; or1k_implementation.num_used_matchpoints--; } } event->is_valid = event->is_trig = 0; event->ls_valid = event->ls_trig = 0; event->bp_valid = event->bp_trig = 0; event->wp_valid = event->wp_trig = 0; if (args == NULL) args = ""; while (*args == ' ') args++; while (*args != '\0') { if (strncasecmp ("breakpoint", args, 10) == 0) { if (!was_last_op) error ("Syntax error."); was_last_op = 0; event->bp_valid = event->bp_trig = 1; } else if (!stop && strncasecmp ("any", args, 3) == 0 || stop && strncasecmp ("none", args, 4) == 0) { if (!was_last_op) error ("Syntax error."); was_last_op = 0; any = 1; } else if (strncasecmp ("||", args, 2) == 0) { if (op_type == TRIGOP_AND) error ("Only one type of logical operator allowed at a time."); op_type = TRIGOP_OR; if (was_last_op) error ("Syntax error."); was_last_op = 1; args += 2; } else if (strncasecmp ("&&", args, 2) == 0) { if (op_type == TRIGOP_OR) error ("Only one type of logical operator allowed at a time."); op_type = TRIGOP_AND; if (was_last_op) error ("Syntax error."); was_last_op = 1; args += 2; } else { int found = 0; if (!was_last_op) error ("Syntax error."); was_last_op = 0; /* Search through is and ls tables for a match. */ for (i = 0; i < MAX_IS_NAMES; i++) if (strncasecmp (args, or1k_is_names[i], strlen (or1k_is_names[i])) == 0) { event->is_valid = 1; event->is_trig = i; args += strlen (or1k_is_names[i]); found = 1; break; } if (!found) { for (i = 0; i < MAX_LS_NAMES; i++) if (strncasecmp (args, or1k_ls_names[i], strlen (or1k_ls_names[i])) == 0) { event->ls_valid = 1; event->ls_trig = i; args += strlen (or1k_ls_names[i]); found = 1; break; } } if (!found) { /* No special name was found => parse expression. */ struct expression *exp; struct matchpoint *match; int nmatch, nfree; exp = parse_exp_1 (&args, 0, 0); if (or1k_parse_any (&exp->elts[0], &match, &nmatch, 3) == &exp_error) error ("Expression too complex."); for (i = 0; i < nmatch; i++) print_matchpoint_struct (&match[i]); /* Now we have to find out if given prefix expression matches our HW based support. It may take up to or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints. */ nfree = or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints; if (nmatch > nfree) error ("Not enough free matchpoint resources."); /* Build matchpoint(s) based on just built structure. */ set_matchpoints (match, nmatch); event->wp_valid = 1; event->wp_trig |= 1 << (or1k_implementation.num_used_matchpoints - 1); printf_unfiltered ("Watchpoint successfully allocated.\n"); free (match); free (exp); found = 1; } if (!found) warning ("Invalid event at '%s'", args); } while (*args == ' ') args++; } if (any) event->operation = TRIGOP_ANY; else { if (op_type == 0) op_type = TRIGOP_AND; event->operation = op_type; } } static void htrace_trigger_command (args, from_tty) char *args; int from_tty; { parse_event (args, &or1k_htrace.trig, 0); printf_filtered ("Trace starts, when:\n"); print_event_struct (&or1k_htrace.trig, 0); printf_filtered ("\n"); } static void htrace_qualifier_command (args, from_tty) char *args; int from_tty; { parse_event (args, &or1k_htrace.qual, 0); printf_filtered ("Trace records, when:\n"); print_event_struct (&or1k_htrace.qual, 0); printf_filtered ("\n"); } static void htrace_stop_command (args, from_tty) char *args; int from_tty; { parse_event (args, &or1k_htrace.stop, 1); printf_filtered ("Trace stops, when:\n"); print_event_struct (&or1k_htrace.stop, 1); printf_filtered ("\n"); } static void htrace_clear_records_command (args, from_tty) char *args; int from_tty; { int i, j, cleared = 0; /* Clear all. */ for (i = 0; i < MAX_MATCHPOINTS; i++) { for (j = 0; j < MAX_MATCHPOINTS; j++) { if ((or1k_htrace.wp_record_uses[i] << j) & 1) if (--matchpoint_user_count[j] <= 0) { memset (&dcr[j], 0, sizeof (dcr[j])); debug_regs_changed = 1; cleared = 1; or1k_implementation.num_used_matchpoints--; } } or1k_htrace.wp_record_uses[i] = 0; } if (!cleared) warning ("No matchpoints freed. Resources are busy."); } /* Syntax: htrace record {data}* when {expr} */ static void htrace_record_command (args, from_tty) char *args; int from_tty; { struct expression *exp; int i, nfree, nmatch, wp; struct matchpoint *match; unsigned int recdata = 0; char *c; if (args == '\0') error ( "Please specify data to record, e.g.:\n" "htrace record PC SDATA when $SEA == 100\n" "htrace record when $SEA == 100 to remove record"); for (i = 0; *args != '\0' && strncasecmp ("when ", args, 5); i++) { int j, found = 0; for (j = 0; j < MAX_RECORD_NAMES; j++) if (strncasecmp (args, or1k_record_names[j], strlen (or1k_record_names[j])) == 0) { recdata |= 1 << j; found = 1; break; } if (!found) warning ("Invalid record data name at '%s'.", args); while (*args != ' ' && *args != '\0') args++; while (*args == ' ') args++; } if (strncasecmp ("when ", args, 5) != 0) if (*args == '\0') { warning ("Condition not set. Assuming breakpoint."); wp = -1; } else error ("Syntax error."); else { args += 5; if (strcasecmp ("breakpoint", args) == 0) wp = -1; else { /* Parse arguments. */ exp = parse_exp_1 (&args, 0, 0); #ifdef DEBUG dump_prefix_expression (exp, gdb_stdout, "expr1"); #endif if (or1k_parse_any (&exp->elts[0], &match, &nmatch, 3) == &exp_error) error ("Expression too complex."); for (i = 0; i < nmatch; i++) print_matchpoint_struct (&match[i]); if (recdata) { /* Now we have to find out if given prefix expression matches our HW based support. It may take up to or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints. */ nfree = or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints; if (nmatch > nfree) error ("Not enough free matchpoint resources."); wp = or1k_implementation.num_used_matchpoints - 1; or1k_htrace.wp_record_uses[wp] = 0; for (i = or1k_implementation.num_used_matchpoints; i <= wp; i++) or1k_htrace.wp_record_uses[wp] |= 1 << i; set_matchpoints (match, nmatch); } else { /* Remove record. */ int start = -1, cleared = 0; for (i = 0; i < MAX_MATCHPOINTS; i++) { int mp_start = 0, j; j = or1k_htrace.wp_record_uses[i]; while (j > 0 && j & 1 == 0) mp_start++; if (matchpoint_matches (mp_start, match, nmatch)) { start = mp_start; or1k_htrace.wp_record_uses[i] = 0; break; } } if (start < 0) error ("Record with such expression not found."); for (i = 0; i < nmatch; i++) { int j = i + start; if (--matchpoint_user_count[j] <= 0) { memset (&dcr[j], 0, sizeof (dcr[j])); debug_regs_changed = 1; cleared = 1; } } if (!cleared) warning ("No matchpoint(s) freed."); } } } /* If we reached this point we have matchpoints set, and wp holds the value of that watchpoint. wp == -1, if breakpoint was specified. */ if (wp < 0) or1k_htrace.recbp.rec = recdata; else or1k_htrace.recwp[wp].rec = recdata; if (recdata) { printf_unfiltered ("Data"); for (i = 0; i < MAX_RECORD_NAMES; i++) if ((recdata >> i) & 1) printf_unfiltered (" %s,", or1k_record_names[i]); } else printf_unfiltered ("No data"); if (wp < 0) printf_unfiltered (" will be recorded when breakpoint occurs\n"); else printf_unfiltered (" will be recorded when watchpoint #%i occurs\n", wp); } static void htrace_enable_command (args, from_tty) char *args; int from_tty; { or1k_htrace.moder.trace_enable = 1; printf_unfiltered ("HW Trace enabled.\n"); } static void htrace_disable_command (args, from_tty) char *args; int from_tty; { or1k_htrace.moder.trace_enable = 0; printf_unfiltered ("HW Trace disabled.\n"); } static void htrace_rewind_command (args, from_tty) char *args; int from_tty; { FILE *f; if (args != NULL && *args != '\0') strncpy (TRACE_FILENAME, args, TRACE_FILENAME_SIZE); /* Just empty it. */ if ((f = fopen (TRACE_FILENAME, "wb+")) == NULL) error ("Cannot open trace file."); fclose (f); printf_unfiltered ("Trace data cleared.\n"); } static void print_data_struct (pos, data) unsigned int pos; struct htrace_data_struct *data; { struct symbol *func; char *funname = NULL; if (data->type < 4) { /* Determine function name - copied from stack.c */ func = find_pc_function (data->data); if (func) { struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (data->data); if (msymbol != NULL && (SYMBOL_VALUE_ADDRESS (msymbol) > BLOCK_START (SYMBOL_BLOCK_VALUE (func)))) funname = SYMBOL_NAME (msymbol); else { char *demangled; funname = SYMBOL_NAME (func); if (SYMBOL_LANGUAGE (func) == language_cplus) { demangled = cplus_demangle (funname, DMGL_ANSI); if (demangled == NULL) funname = SYMBOL_SOURCE_NAME (func); } } } else { struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (data->data); if (msymbol != NULL) funname = SYMBOL_NAME (msymbol); } } printf_filtered ("%06X%c %-8s %08X", pos, data->valid ? '>' : ':', or1k_record_names[data->type], data->data); if (funname) printf_filtered (" (%s)\n", funname); else printf_filtered ("\n"); } /* Prints out trace buffer. */ static void htrace_print_command (args, from_tty) char *args; int from_tty; { int i, from = 0, length = prev_length; FILE *f; struct htrace_data_struct *td; if (args == NULL) args = ""; while (*args == ' ') args++; if (*args == '\0') { /* We will display buffer further. */ from = prev_from + prev_length; } else { /* Display buffer range. */ int numbers = 0; char *cnum = args; while (*args != ' ' && *args != '\0') args++; /* Any arguments? */ if (*args == '\0') numbers = 1; else { *args = 0; args++; numbers = 2; } from = strtoul (cnum, &cnum, 0); if (*cnum != 0) error ("Invalid from value."); if (from < 0) from += trace_size; if (numbers == 2) { while (*args == ' ') args++; length = strtoul (cnum, &cnum, 0); if (*args != 0) error ("Invalid length value."); if (length < 0) { from += length; length = -length; } } } if (from >= trace_size) from = trace_size - 1; if (from < 0) from = 0; if (from + length >= trace_size) length = trace_size - from; prev_length = length; prev_from = from; if (length == 0) error ("Nothing to print."); printf_filtered ("Trace buffer %06x:%06x (size = %i)\n", from, from + length - 1, length); if ((f = fopen (TRACE_FILENAME, "rb")) == NULL) error ("Cannot open trace file."); if (fseek (f, TRACE_DATA_SIZE * from, SEEK_SET)) error ("Error reading trace file."); td = (struct htrace_data_struct *) malloc (TRACE_DATA_SIZE * length); length = fread (td, TRACE_DATA_SIZE, length, f); for (i = 0; i < length; i++) print_data_struct (from + i, td[i]); fclose (f); } int print_insn_big_or32 (bfd_vma,struct disassemble_info*); int print_insn_little_or32 (bfd_vma,struct disassemble_info*); void _initialize_or1k_tdep () { build_automata (); /* Added by CZ 26/06/01 */ if(TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) tm_print_insn = print_insn_big_or32; else tm_print_insn = print_insn_little_or32; /* Commands to show and set sprs. */ add_info ("spr", info_spr_command, "Show information about the spr registers."); add_info ("trace", info_trace_command, "Display trace buffer contents."); add_com ("spr", class_support, spr_command, "Set specified SPR register."); /* hwatch command. */ add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watch" "point.\nExample: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_" "var)&&($SDATA >= 50).\nSee OR1k Architecture document for more" " info."); /* htrace commands. */ add_prefix_cmd ("htrace", class_breakpoint, htrace_command, "Group of commands for handling hardware assisted trace\n\n" "See OR1k Architecture and gdb for or1k documents for more info.", &htrace_cmdlist, "htrace ", 0, &cmdlist); add_cmd ("info", class_breakpoint, htrace_info_command, "Display information about HW trace.", &htrace_cmdlist); add_alias_cmd ("i", "info", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("trigger", class_breakpoint, htrace_trigger_command, "Set starting criteria for trace.", &htrace_cmdlist); add_alias_cmd ("t", "trigger", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("qualifier", class_breakpoint, htrace_qualifier_command, "Set acquisition qualifier for HW trace.", &htrace_cmdlist); add_alias_cmd ("q", "qualifier", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("stop", class_breakpoint, htrace_stop_command, "Set HW trace stopping criteria.", &htrace_cmdlist); add_alias_cmd ("s", "stop", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("record", class_breakpoint, htrace_record_command, "Sets data to be recorded when expression occurs.", &htrace_cmdlist); add_alias_cmd ("r", "record", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("clear records", class_breakpoint, htrace_clear_records_command, "Disposes all matchpoints used by records.", &htrace_cmdlist); add_cmd ("enable", class_breakpoint, htrace_enable_command, "Enables the HW trace.", &htrace_cmdlist); add_alias_cmd ("e", "enable", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("disable", class_breakpoint, htrace_disable_command, "Disables the HW trace.", &htrace_cmdlist); add_alias_cmd ("d", "disable", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("rewind", class_breakpoint, htrace_rewind_command, "Clears currently recorded trace data.\n" "If filename is specified, new trace file is made and any newly collected data\n" "will be written there.", &htrace_cmdlist); add_cmd ("print", class_breakpoint, htrace_print_command, "Prints trace buffer, using current record configuration.\n" "htrace print [<start> [<len>]]\n" "htrace print" , &htrace_cmdlist); add_alias_cmd ("p", "print", class_breakpoint, 1, &htrace_cmdlist); add_prefix_cmd ("mode", class_breakpoint, htrace_mode_command, "Configures the HW trace.\n" "htrace mode [continuous|suspend]" , &htrace_mode_cmdlist, "htrace mode ", 0, &htrace_cmdlist); add_alias_cmd ("m", "mode", class_breakpoint, 1, &htrace_cmdlist); add_cmd ("continuous", class_breakpoint, htrace_mode_contin_command, "Set continuous trace mode.\n", &htrace_mode_cmdlist); add_cmd ("suspend", class_breakpoint, htrace_mode_suspend_command, "Set suspend trace mode.\n", &htrace_mode_cmdlist); /* Extra functions supported by simulator. */ add_com ("sim", class_obscure, sim_command, "Send a extended command to the simulator."); }