| 1 | /* Tracing support for CGEN-based simulators. |
| 2 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. |
| 3 | Contributed by Cygnus Support. |
| 4 | |
| 5 | This file is part of GDB, the GNU debugger. |
| 6 | |
| 7 | This program is free software; you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation; either version 2, or (at your option) |
| 10 | any later version. |
| 11 | |
| 12 | This program is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | GNU General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License along |
| 18 | with this program; if not, write to the Free Software Foundation, Inc., |
| 19 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
| 20 | |
| 21 | #include "sim-main.h" |
| 22 | #include "bfd.h" |
| 23 | #include "cpu-opc.h" |
| 24 | |
| 25 | #ifndef SIZE_INSTRUCTION |
| 26 | #define SIZE_INSTRUCTION 16 |
| 27 | #endif |
| 28 | |
| 29 | #ifndef SIZE_LOCATION |
| 30 | #define SIZE_LOCATION 20 |
| 31 | #endif |
| 32 | |
| 33 | #ifndef SIZE_PC |
| 34 | #define SIZE_PC 6 |
| 35 | #endif |
| 36 | |
| 37 | #ifndef SIZE_LINE_NUMBER |
| 38 | #define SIZE_LINE_NUMBER 4 |
| 39 | #endif |
| 40 | |
| 41 | #ifndef SIZE_CYCLE_COUNT |
| 42 | #define SIZE_CYCLE_COUNT 2 |
| 43 | #endif |
| 44 | |
| 45 | #ifndef SIZE_TOTAL_CYCLE_COUNT |
| 46 | #define SIZE_TOTAL_CYCLE_COUNT 9 |
| 47 | #endif |
| 48 | |
| 49 | /* Text is queued in TRACE_BUF because we want to output the insn's cycle |
| 50 | count first but that isn't known until after the insn has executed. */ |
| 51 | static char trace_buf[1024]; |
| 52 | /* If NULL, output to stdout directly. */ |
| 53 | static char *bufptr; |
| 54 | |
| 55 | /* For computing an instruction's cycle count. |
| 56 | FIXME: Need to move into cpu struct for smp case. */ |
| 57 | static unsigned long last_cycle_count; |
| 58 | |
| 59 | void |
| 60 | trace_insn_init (SIM_CPU *cpu) |
| 61 | { |
| 62 | bufptr = trace_buf; |
| 63 | *bufptr = 0; |
| 64 | } |
| 65 | |
| 66 | void |
| 67 | trace_insn_fini (SIM_CPU *cpu) |
| 68 | { |
| 69 | if (CPU_PROFILE_FLAGS (cpu) [PROFILE_MODEL_IDX]) |
| 70 | { |
| 71 | unsigned long total = PROFILE_TOTAL_CYCLE_COUNT (CPU_PROFILE_DATA (cpu)); |
| 72 | trace_printf (CPU_STATE (cpu), cpu, "%-*ld %-*ld ", |
| 73 | SIZE_CYCLE_COUNT, total - last_cycle_count, |
| 74 | SIZE_TOTAL_CYCLE_COUNT, total); |
| 75 | last_cycle_count = total; |
| 76 | } |
| 77 | |
| 78 | trace_printf (CPU_STATE (cpu), cpu, "%s\n", trace_buf); |
| 79 | } |
| 80 | |
| 81 | /* For communication between trace_insn and trace_result. */ |
| 82 | static int printed_result_p; |
| 83 | |
| 84 | void |
| 85 | trace_insn (SIM_CPU *cpu, const struct cgen_insn *opcode, |
| 86 | const struct argbuf *abuf, PCADDR pc) |
| 87 | { |
| 88 | const char *filename; |
| 89 | const char *functionname; |
| 90 | unsigned int linenumber; |
| 91 | char *p, buf[256], disasm_buf[50]; |
| 92 | |
| 93 | if (! TRACE_P (cpu, TRACE_LINENUM_IDX)) |
| 94 | { |
| 95 | cgen_trace_printf (cpu, "0x%.*x %-*s ", |
| 96 | SIZE_PC, (unsigned) pc, |
| 97 | SIZE_INSTRUCTION, |
| 98 | CGEN_INSN_MNEMONIC (opcode)); |
| 99 | return; |
| 100 | } |
| 101 | |
| 102 | buf[0] = 0; |
| 103 | |
| 104 | if (STATE_TEXT_SECTION (CPU_STATE (cpu)) |
| 105 | && pc >= STATE_TEXT_START (CPU_STATE (cpu)) |
| 106 | && pc < STATE_TEXT_END (CPU_STATE (cpu))) |
| 107 | { |
| 108 | filename = (const char *) 0; |
| 109 | functionname = (const char *) 0; |
| 110 | linenumber = 0; |
| 111 | if (bfd_find_nearest_line (STATE_PROG_BFD (CPU_STATE (cpu)), |
| 112 | STATE_TEXT_SECTION (CPU_STATE (cpu)), |
| 113 | (struct symbol_cache_entry **) 0, |
| 114 | pc - STATE_TEXT_START (CPU_STATE (cpu)), |
| 115 | &filename, &functionname, &linenumber)) |
| 116 | { |
| 117 | p = buf; |
| 118 | if (linenumber) |
| 119 | { |
| 120 | sprintf (p, "#%-*d ", SIZE_LINE_NUMBER, linenumber); |
| 121 | p += strlen (p); |
| 122 | } |
| 123 | else |
| 124 | { |
| 125 | sprintf (p, "%-*s ", SIZE_LINE_NUMBER+1, "---"); |
| 126 | p += SIZE_LINE_NUMBER+2; |
| 127 | } |
| 128 | |
| 129 | if (functionname) |
| 130 | { |
| 131 | sprintf (p, "%s ", functionname); |
| 132 | p += strlen (p); |
| 133 | } |
| 134 | else if (filename) |
| 135 | { |
| 136 | char *q = (char *) strrchr (filename, '/'); |
| 137 | sprintf (p, "%s ", (q) ? q+1 : filename); |
| 138 | p += strlen (p); |
| 139 | } |
| 140 | |
| 141 | if (*p == ' ') |
| 142 | *p = '\0'; |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | sim_disassemble_insn (cpu, opcode, abuf, pc, disasm_buf); |
| 147 | |
| 148 | cgen_trace_printf (cpu, "0x%.*x %-*.*s %-*s ", |
| 149 | SIZE_PC, (unsigned) pc, |
| 150 | SIZE_LOCATION, SIZE_LOCATION, buf, |
| 151 | SIZE_INSTRUCTION, |
| 152 | #if 0 |
| 153 | CGEN_INSN_SYNTAX (opcode)->mnemonic |
| 154 | #else |
| 155 | disasm_buf |
| 156 | #endif |
| 157 | ); |
| 158 | |
| 159 | printed_result_p = 0; |
| 160 | } |
| 161 | |
| 162 | void |
| 163 | trace_extract (SIM_CPU *cpu, PCADDR pc, char *name, ...) |
| 164 | { |
| 165 | va_list args; |
| 166 | int printed_one_p = 0; |
| 167 | char *fmt; |
| 168 | |
| 169 | va_start (args, name); |
| 170 | |
| 171 | trace_printf (CPU_STATE (cpu), cpu, "Extract: 0x%.*x: %s ", SIZE_PC, pc, name); |
| 172 | |
| 173 | do { |
| 174 | int type,ival; |
| 175 | |
| 176 | fmt = va_arg (args, char *); |
| 177 | |
| 178 | if (fmt) |
| 179 | { |
| 180 | if (printed_one_p) |
| 181 | trace_printf (CPU_STATE (cpu), cpu, ", "); |
| 182 | printed_one_p = 1; |
| 183 | type = va_arg (args, int); |
| 184 | switch (type) |
| 185 | { |
| 186 | case 'x' : |
| 187 | ival = va_arg (args, int); |
| 188 | trace_printf (CPU_STATE (cpu), cpu, fmt, ival); |
| 189 | break; |
| 190 | default : |
| 191 | abort (); |
| 192 | } |
| 193 | } |
| 194 | } while (fmt); |
| 195 | |
| 196 | va_end (args); |
| 197 | trace_printf (CPU_STATE (cpu), cpu, "\n"); |
| 198 | } |
| 199 | |
| 200 | void |
| 201 | trace_result (SIM_CPU *cpu, char *name, int type, ...) |
| 202 | { |
| 203 | va_list args; |
| 204 | |
| 205 | va_start (args, type); |
| 206 | if (printed_result_p) |
| 207 | cgen_trace_printf (cpu, ", "); |
| 208 | switch (type) |
| 209 | { |
| 210 | case 'x' : |
| 211 | default : |
| 212 | cgen_trace_printf (cpu, "%s <- 0x%x", name, va_arg (args, int)); |
| 213 | break; |
| 214 | case 'D' : |
| 215 | { |
| 216 | DI di; |
| 217 | /* this is separated from previous line for sunos cc */ |
| 218 | di = va_arg (args, DI); |
| 219 | cgen_trace_printf (cpu, "%s <- 0x%x%08x", name, |
| 220 | GETHIDI(di), GETLODI (di)); |
| 221 | break; |
| 222 | } |
| 223 | } |
| 224 | printed_result_p = 1; |
| 225 | va_end (args); |
| 226 | } |
| 227 | |
| 228 | /* Print trace output to BUFPTR if active, otherwise print normally. |
| 229 | This is only for tracing semantic code. */ |
| 230 | |
| 231 | void |
| 232 | cgen_trace_printf (SIM_CPU *cpu, char *fmt, ...) |
| 233 | { |
| 234 | va_list args; |
| 235 | |
| 236 | va_start (args, fmt); |
| 237 | |
| 238 | if (bufptr == NULL) |
| 239 | { |
| 240 | if (TRACE_FILE (CPU_TRACE_DATA (cpu)) == NULL) |
| 241 | (* STATE_CALLBACK (CPU_STATE (cpu))->evprintf_filtered) |
| 242 | (STATE_CALLBACK (CPU_STATE (cpu)), fmt, args); |
| 243 | else |
| 244 | vfprintf (TRACE_FILE (CPU_TRACE_DATA (cpu)), fmt, args); |
| 245 | } |
| 246 | else |
| 247 | { |
| 248 | vsprintf (bufptr, fmt, args); |
| 249 | bufptr += strlen (bufptr); |
| 250 | } |
| 251 | |
| 252 | va_end (args); |
| 253 | } |