diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /gdb/convex-tdep.c | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'gdb/convex-tdep.c')
-rw-r--r-- | gdb/convex-tdep.c | 1217 |
1 files changed, 1217 insertions, 0 deletions
diff --git a/gdb/convex-tdep.c b/gdb/convex-tdep.c new file mode 100644 index 0000000..8eeb2b3 --- /dev/null +++ b/gdb/convex-tdep.c @@ -0,0 +1,1217 @@ +/* Convex stuff for GDB. + Copyright (C) 1990, 1991, 1996 Free Software Foundation, Inc. + +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 "defs.h" +#include "command.h" +#include "symtab.h" +#include "value.h" +#include "frame.h" +#include "inferior.h" +#include "wait.h" + +#include <signal.h> +#include <fcntl.h> + +#include "gdbcore.h" +#include <sys/param.h> +#include <sys/dir.h> +#include <sys/user.h> +#include <sys/ioctl.h> +#include <sys/pcntl.h> +#include <sys/thread.h> +#include <sys/proc.h> +#include <sys/file.h> +#include "gdb_stat.h" +#include <sys/mman.h> + +#include "gdbcmd.h" + +exec_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + int n; + struct stat st_exec; + + /* Eliminate all traces of old exec file. + Mark text segment as empty. */ + + if (execfile) + free (execfile); + execfile = 0; + data_start = 0; + data_end = 0; + text_start = 0; + text_end = 0; + exec_data_start = 0; + exec_data_end = 0; + if (execchan >= 0) + close (execchan); + execchan = -1; + + n_exec = 0; + + /* Now open and digest the file the user requested, if any. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + execchan = openp (getenv ("PATH"), 1, filename, O_RDONLY, 0, + &execfile); + if (execchan < 0) + perror_with_name (filename); + + if (myread (execchan, &filehdr, sizeof filehdr) < 0) + perror_with_name (filename); + + if (! IS_SOFF_MAGIC (filehdr.h_magic)) + error ("%s: not an executable file.", filename); + + if (myread (execchan, &opthdr, filehdr.h_opthdr) <= 0) + perror_with_name (filename); + + /* Read through the section headers. + For text, data, etc, record an entry in the exec file map. + Record text_start and text_end. */ + + lseek (execchan, (long) filehdr.h_scnptr, 0); + + for (n = 0; n < filehdr.h_nscns; n++) + { + if (myread (execchan, &scnhdr, sizeof scnhdr) < 0) + perror_with_name (filename); + + if ((scnhdr.s_flags & S_TYPMASK) >= S_TEXT + && (scnhdr.s_flags & S_TYPMASK) <= S_COMON) + { + exec_map[n_exec].mem_addr = scnhdr.s_vaddr; + exec_map[n_exec].mem_end = scnhdr.s_vaddr + scnhdr.s_size; + exec_map[n_exec].file_addr = scnhdr.s_scnptr; + exec_map[n_exec].type = scnhdr.s_flags & S_TYPMASK; + n_exec++; + + if ((scnhdr.s_flags & S_TYPMASK) == S_TEXT) + { + text_start = scnhdr.s_vaddr; + text_end = scnhdr.s_vaddr + scnhdr.s_size; + } + } + } + + fstat (execchan, &st_exec); + exec_mtime = st_exec.st_mtime; + + validate_files (); + } + else if (from_tty) + printf_filtered ("No executable file now.\n"); + + /* Tell display code (if any) about the changed file name. */ + if (exec_file_display_hook) + (*exec_file_display_hook) (filename); +} + +#if 0 +/* Read data from SOFF exec or core file. + Return 0 on success, EIO if address out of bounds. */ + +int +xfer_core_file (memaddr, myaddr, len) + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register int i; + register int n; + register int val; + int xferchan; + char **xferfile; + int fileptr; + int returnval = 0; + + while (len > 0) + { + xferfile = 0; + xferchan = 0; + + /* Determine which file the next bunch of addresses reside in, + and where in the file. Set the file's read/write pointer + to point at the proper place for the desired address + and set xferfile and xferchan for the correct file. + If desired address is nonexistent, leave them zero. + i is set to the number of bytes that can be handled + along with the next address. */ + + i = len; + + for (n = 0; n < n_core; n++) + { + if (memaddr >= core_map[n].mem_addr && memaddr < core_map[n].mem_end + && (core_map[n].thread == -1 + || core_map[n].thread == inferior_thread)) + { + i = min (len, core_map[n].mem_end - memaddr); + fileptr = core_map[n].file_addr + memaddr - core_map[n].mem_addr; + if (core_map[n].file_addr) + { + xferfile = &corefile; + xferchan = corechan; + } + break; + } + else if (core_map[n].mem_addr >= memaddr + && core_map[n].mem_addr < memaddr + i) + i = core_map[n].mem_addr - memaddr; + } + + if (!xferfile) + for (n = 0; n < n_exec; n++) + { + if (memaddr >= exec_map[n].mem_addr + && memaddr < exec_map[n].mem_end) + { + i = min (len, exec_map[n].mem_end - memaddr); + fileptr = exec_map[n].file_addr + memaddr + - exec_map[n].mem_addr; + if (exec_map[n].file_addr) + { + xferfile = &execfile; + xferchan = execchan; + } + break; + } + else if (exec_map[n].mem_addr >= memaddr + && exec_map[n].mem_addr < memaddr + i) + i = exec_map[n].mem_addr - memaddr; + } + + /* Now we know which file to use. + Set up its pointer and transfer the data. */ + if (xferfile) + { + if (*xferfile == 0) + if (xferfile == &execfile) + error ("No program file to examine."); + else + error ("No core dump file or running program to examine."); + val = lseek (xferchan, fileptr, 0); + if (val < 0) + perror_with_name (*xferfile); + val = myread (xferchan, myaddr, i); + if (val < 0) + perror_with_name (*xferfile); + } + /* If this address is for nonexistent memory, + read zeros if reading, or do nothing if writing. */ + else + { + memset (myaddr, '\0', i); + returnval = EIO; + } + + memaddr += i; + myaddr += i; + len -= i; + } + return returnval; +} +#endif + +/* Here from info files command to print an address map. */ + +print_maps () +{ + struct pmap ptrs[200]; + int n; + + /* ID strings for core and executable file sections */ + + static char *idstr[] = + { + "0", "text", "data", "tdata", "bss", "tbss", + "common", "ttext", "ctx", "tctx", "10", "11", "12", + }; + + for (n = 0; n < n_core; n++) + { + core_map[n].which = 0; + ptrs[n] = core_map[n]; + } + for (n = 0; n < n_exec; n++) + { + exec_map[n].which = 1; + ptrs[n_core+n] = exec_map[n]; + } + + qsort (ptrs, n_core + n_exec, sizeof *ptrs, ptr_cmp); + + for (n = 0; n < n_core + n_exec; n++) + { + struct pmap *p = &ptrs[n]; + if (n > 0) + { + if (p->mem_addr < ptrs[n-1].mem_end) + p->mem_addr = ptrs[n-1].mem_end; + if (p->mem_addr >= p->mem_end) + continue; + } + printf_filtered ("%08x .. %08x %-6s %s\n", + p->mem_addr, p->mem_end, idstr[p->type], + p->which ? execfile : corefile); + } +} + +/* Compare routine to put file sections in order. + Sort into increasing order on address, and put core file sections + before exec file sections if both files contain the same addresses. */ + +static ptr_cmp (a, b) + struct pmap *a, *b; +{ + if (a->mem_addr != b->mem_addr) return a->mem_addr - b->mem_addr; + return a->which - b->which; +} + +/* Trapped internal variables are used to handle special registers. + A trapped i.v. calls a hook here every time it is dereferenced, + to provide a new value for the variable, and it calls a hook here + when a new value is assigned, to do something with the value. + + The vector registers are $vl, $vs, $vm, $vN, $VN (N in 0..7). + The communication registers are $cN, $CN (N in 0..63). + They not handled as regular registers because it's expensive to + read them, and their size varies, and they have too many names. */ + + +/* Return 1 if NAME is a trapped internal variable, else 0. */ + +int +is_trapped_internalvar (name) + char *name; +{ + if ((name[0] == 'c' || name[0] == 'C') + && name[1] >= '0' && name[1] <= '9' + && (name[2] == '\0' + || (name[2] >= '0' && name[2] <= '9' + && name[3] == '\0' && name[1] != '0')) + && atoi (&name[1]) < 64) return 1; + + if ((name[0] == 'v' || name[0] == 'V') + && (((name[1] & -8) == '0' && name[2] == '\0') + || STREQ (name, "vl") + || STREQ (name, "vs") + || STREQ (name, "vm"))) + return 1; + else return 0; +} + +/* Return the value of trapped internal variable VAR */ + +value +value_of_trapped_internalvar (var) + struct internalvar *var; +{ + char *name = var->name; + value val; + struct type *type; + struct type *range_type; + long len = *read_vector_register (VL_REGNUM); + if (len <= 0 || len > 128) len = 128; + + if (STREQ (name, "vl")) + { + val = value_from_longest (builtin_type_int, + (LONGEST) *read_vector_register_1 (VL_REGNUM)); + } + else if (STREQ (name, "vs")) + { + val = value_from_longest (builtin_type_int, + (LONGEST) *read_vector_register_1 (VS_REGNUM)); + } + else if (STREQ (name, "vm")) + { + long vm[4]; + long i, *p; + memcpy (vm, read_vector_register_1 (VM_REGNUM), sizeof vm); + range_type = + create_range_type ((struct type *) NULL, builtin_type_int, 0, len - 1); + type = + create_array_type ((struct type *) NULL, builtin_type_int, range_type); + val = allocate_value (type); + p = (long *) VALUE_CONTENTS (val); + for (i = 0; i < len; i++) + *p++ = !! (vm[3 - (i >> 5)] & (1 << (i & 037))); + } + else if (name[0] == 'V') + { + range_type = + create_range_type ((struct type *) NULL, builtin_type_int 0, len - 1); + type = + create_array_type ((struct type *) NULL, builtin_type_long_long, + range_type); + val = allocate_value (type); + memcpy (VALUE_CONTENTS (val), + read_vector_register_1 (name[1] - '0'), + TYPE_LENGTH (type)); + } + else if (name[0] == 'v') + { + long *p1, *p2; + range_type = + create_range_type ((struct type *) NULL, builtin_type_int 0, len - 1); + type = + create_array_type ((struct type *) NULL, builtin_type_long, + range_type); + val = allocate_value (type); + p1 = read_vector_register_1 (name[1] - '0'); + p2 = (long *) VALUE_CONTENTS (val); + while (--len >= 0) {p1++; *p2++ = *p1++;} + } + + else if (name[0] == 'c') + val = value_from_longest (builtin_type_int, + read_comm_register (atoi (&name[1]))); + else if (name[0] == 'C') + val = value_from_longest (builtin_type_long_long, + read_comm_register (atoi (&name[1]))); + + VALUE_LVAL (val) = lval_internalvar; + VALUE_INTERNALVAR (val) = var; + return val; +} + +/* Handle a new value assigned to a trapped internal variable */ + +void +set_trapped_internalvar (var, val, bitpos, bitsize, offset) + struct internalvar *var; + value val; + int bitpos, bitsize, offset; +{ + char *name = var->name; + long long newval = value_as_long (val); + + if (STREQ (name, "vl")) + write_vector_register (VL_REGNUM, 0, newval); + else if (STREQ (name, "vs")) + write_vector_register (VS_REGNUM, 0, newval); + else if (name[0] == 'c' || name[0] == 'C') + write_comm_register (atoi (&name[1]), newval); + else if (STREQ (name, "vm")) + error ("can't assign to $vm"); + else + { + offset /= bitsize / 8; + write_vector_register (name[1] - '0', offset, newval); + } +} + +/* Print an integer value when no format was specified. gdb normally + prints these values in decimal, but the the leading 0x80000000 of + pointers produces intolerable 10-digit negative numbers. + If it looks like an address, print it in hex instead. */ + +decout (stream, type, val) + GDB_FILE *stream; + struct type *type; + LONGEST val; +{ + long lv = val; + + switch (output_radix) + { + case 0: + if ((lv == val || (unsigned) lv == val) + && ((lv & 0xf0000000) == 0x80000000 + || ((lv & 0xf0000000) == 0xf0000000 && lv < STACK_END_ADDR))) + { + print_longest (stream, "x", 0, val); + return; + } + + case 10: + print_longest (stream, TYPE_UNSIGNED (type) ? "u" : "d", 0, val); + return; + + case 8: + print_longest (stream, "o", 0, val); + return; + + case 16: + print_longest (stream, "x", 0, val); + return; + } +} + +/* Change the default output radix to 10 or 16, or set it to 0 (heuristic). + This command is mostly obsolete now that the print command allows + formats to apply to aggregates, but is still handy occasionally. */ + +static void +set_base_command (arg) + char *arg; +{ + int new_radix; + + if (!arg) + output_radix = 0; + else + { + new_radix = atoi (arg); + if (new_radix != 10 && new_radix != 16 && new_radix != 8) + error ("base must be 8, 10 or 16, or null"); + else output_radix = new_radix; + } +} + +/* Turn pipelining on or off in the inferior. */ + +static void +set_pipelining_command (arg) + char *arg; +{ + if (!arg) + { + sequential = !sequential; + printf_filtered ("%s\n", sequential ? "off" : "on"); + } + else if (STREQ (arg, "on")) + sequential = 0; + else if (STREQ (arg, "off")) + sequential = 1; + else error ("valid args are `on', to allow instructions to overlap, or\n\ +`off', to prevent it and thereby pinpoint exceptions."); +} + +/* Enable, disable, or force parallel execution in the inferior. */ + +static void +set_parallel_command (arg) + char *arg; +{ + struct rlimit rl; + int prevparallel = parallel; + + if (!strncmp (arg, "fixed", strlen (arg))) + parallel = 2; + else if (STREQ (arg, "on")) + parallel = 1; + else if (STREQ (arg, "off")) + parallel = 0; + else error ("valid args are `on', to allow multiple threads, or\n\ +`fixed', to force multiple threads, or\n\ +`off', to run with one thread only."); + + if ((prevparallel == 0) != (parallel == 0) && inferior_pid) + printf_filtered ("will take effect at next run.\n"); + + getrlimit (RLIMIT_CONCUR, &rl); + rl.rlim_cur = parallel ? rl.rlim_max : 1; + setrlimit (RLIMIT_CONCUR, &rl); + + if (inferior_pid) + set_fixed_scheduling (inferior_pid, parallel == 2); +} + +/* Add a new name for an existing command. */ + +static void +alias_command (arg) + char *arg; +{ + static char *aliaserr = "usage is `alias NEW OLD', no args allowed"; + char *newname = arg; + struct cmd_list_element *new, *old; + + if (!arg) + error_no_arg ("newname oldname"); + + new = lookup_cmd (&arg, cmdlist, "", -1); + if (new && !strncmp (newname, new->name, strlen (new->name))) + { + newname = new->name; + if (!(*arg == '-' + || (*arg >= 'a' && *arg <= 'z') + || (*arg >= 'A' && *arg <= 'Z') + || (*arg >= '0' && *arg <= '9'))) + error (aliaserr); + } + else + { + arg = newname; + while (*arg == '-' + || (*arg >= 'a' && *arg <= 'z') + || (*arg >= 'A' && *arg <= 'Z') + || (*arg >= '0' && *arg <= '9')) + arg++; + if (*arg != ' ' && *arg != '\t') + error (aliaserr); + *arg = '\0'; + arg++; + } + + old = lookup_cmd (&arg, cmdlist, "", 0); + + if (*arg != '\0') + error (aliaserr); + + if (new && !strncmp (newname, new->name, strlen (new->name))) + { + char *tem; + if (new->class == (int) class_user || new->class == (int) class_alias) + tem = "Redefine command \"%s\"? "; + else + tem = "Really redefine built-in command \"%s\"? "; + if (!query (tem, new->name)) + error ("Command \"%s\" not redefined.", new->name); + } + + add_com (newname, class_alias, old->function, old->doc); +} + + + +/* Print the current thread number, and any threads with signals in the + queue. */ + +thread_info () +{ + struct threadpid *p; + + if (have_inferior_p ()) + { + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + } + + /* FIXME: stop_signal is from target.h but stop_sigcode is a + convex-specific thing. */ + printf_filtered ("Current thread %d stopped with signal %d.%d (%s).\n", + inferior_thread, stop_signal, stop_sigcode, + subsig_name (stop_signal, stop_sigcode)); + + for (p = signal_stack; p->pid; p--) + printf_filtered ("Thread %d stopped with signal %d.%d (%s).\n", + p->thread, p->signo, p->subsig, + subsig_name (p->signo, p->subsig)); + + if (iscrlbit (comm_registers.crctl.lbits.cc, 64+13)) + printf_filtered ("New thread start pc %#x\n", + (long) (comm_registers.crreg.pcpsw >> 32)); +} + +/* Return string describing a signal.subcode number */ + +static char * +subsig_name (signo, subcode) + int signo, subcode; +{ + static char *subsig4[] = { + "error exit", "privileged instruction", "unknown", + "unknown", "undefined opcode", + 0}; + static char *subsig5[] = {0, + "breakpoint", "single step", "fork trap", "exec trap", "pfork trap", + "join trap", "idle trap", "last thread", "wfork trap", + "process breakpoint", "trap instruction", + 0}; + static char *subsig8[] = {0, + "int overflow", "int divide check", "float overflow", + "float divide check", "float underflow", "reserved operand", + "sqrt error", "exp error", "ln error", "sin error", "cos error", + 0}; + static char *subsig10[] = {0, + "invalid inward ring address", "invalid outward ring call", + "invalid inward ring return", "invalid syscall gate", + "invalid rtn frame length", "invalid comm reg address", + "invalid trap gate", + 0}; + static char *subsig11[] = {0, + "read access denied", "write access denied", "execute access denied", + "segment descriptor fault", "page table fault", "data reference fault", + "i/o access denied", "levt pte invalid", + 0}; + + static char **subsig_list[] = + {0, 0, 0, 0, subsig4, subsig5, 0, 0, subsig8, 0, subsig10, subsig11, 0}; + + int i; + char *p; + + if ((p = strsignal (signo)) == NULL) + p = "unknown"; + if (signo >= (sizeof subsig_list / sizeof *subsig_list) + || !subsig_list[signo]) + return p; + for (i = 1; subsig_list[signo][i]; i++) + if (i == subcode) + return subsig_list[signo][subcode]; + return p; +} + + +/* Print a compact display of thread status, essentially x/i $pc + for all active threads. */ + +static void +threadstat () +{ + int t; + + for (t = 0; t < n_threads; t++) + if (thread_state[t] == PI_TALIVE) + { + printf_filtered ("%d%c %08x%c %d.%d ", t, + (t == inferior_thread ? '*' : ' '), thread_pc[t], + (thread_is_in_kernel[t] ? '#' : ' '), + thread_signal[t], thread_sigcode[t]); + print_insn (thread_pc[t], stdout); + printf_filtered ("\n"); + } +} + +/* Change the current thread to ARG. */ + +set_thread_command (arg) + char *arg; +{ + int thread; + + if (!arg) + { + threadstat (); + return; + } + + thread = parse_and_eval_address (arg); + + if (thread < 0 || thread > n_threads || thread_state[thread] != PI_TALIVE) + error ("no such thread."); + + select_thread (thread); + + stop_pc = read_pc (); + flush_cached_frames (); + select_frame (get_current_frame (), 0); + print_stack_frame (selected_frame, selected_frame_level, -1); +} + +/* Here on CONT command; gdb's dispatch address is changed to come here. + Set global variable ALL_CONTINUE to tell resume() that it should + start up all threads, and that a thread switch will not blow gdb's + mind. */ + +static void +convex_cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + all_continue = 1; + cont_command (proc_count_exp, from_tty); +} + +/* Here on 1CONT command. Resume only the current thread. */ + +one_cont_command (proc_count_exp, from_tty) + char *proc_count_exp; + int from_tty; +{ + cont_command (proc_count_exp, from_tty); +} + +/* Print the contents and lock bits of all communication registers, + or just register ARG if ARG is a communication register, + or the 3-word resource structure in memory at address ARG. */ + +comm_registers_info (arg) + char *arg; +{ + int i, regnum; + + if (arg) + { + if (sscanf (arg, "$c%d", ®num) == 1) { + ; + } else if (sscanf (arg, "$C%d", ®num) == 1) { + ; + } else { + regnum = parse_and_eval_address (arg); + if (regnum > 0) + regnum &= ~0x8000; + } + + if (regnum >= 64) + error ("%s: invalid register name.", arg); + + /* if we got a (user) address, examine the resource struct there */ + + if (regnum < 0) + { + static int buf[3]; + read_memory (regnum, buf, sizeof buf); + printf_filtered ("%08x %08x%08x%s\n", regnum, buf[1], buf[2], + buf[0] & 0xff ? " locked" : ""); + return; + } + } + + ps.pi_buffer = (char *) &comm_registers; + ps.pi_nbytes = sizeof comm_registers; + ps.pi_offset = 0; + ps.pi_thread = inferior_thread; + ioctl (inferior_fd, PIXRDCREGS, &ps); + + for (i = 0; i < 64; i++) + if (!arg || i == regnum) + printf_filtered ("%2d 0x8%03x %016llx%s\n", i, i, + comm_registers.crreg.r4[i], + (iscrlbit (comm_registers.crctl.lbits.cc, i) + ? " locked" : "")); +} + +/* Print the psw */ + +static void +psw_info (arg) + char *arg; +{ + struct pswbit + { + int bit; + int pos; + char *text; + }; + + static struct pswbit pswbit[] = + { + { 0x80000000, -1, "A carry" }, + { 0x40000000, -1, "A integer overflow" }, + { 0x20000000, -1, "A zero divide" }, + { 0x10000000, -1, "Integer overflow enable" }, + { 0x08000000, -1, "Trace" }, + { 0x06000000, 25, "Frame length" }, + { 0x01000000, -1, "Sequential" }, + { 0x00800000, -1, "S carry" }, + { 0x00400000, -1, "S integer overflow" }, + { 0x00200000, -1, "S zero divide" }, + { 0x00100000, -1, "Zero divide enable" }, + { 0x00080000, -1, "Floating underflow" }, + { 0x00040000, -1, "Floating overflow" }, + { 0x00020000, -1, "Floating reserved operand" }, + { 0x00010000, -1, "Floating zero divide" }, + { 0x00008000, -1, "Floating error enable" }, + { 0x00004000, -1, "Floating underflow enable" }, + { 0x00002000, -1, "IEEE" }, + { 0x00001000, -1, "Sequential stores" }, + { 0x00000800, -1, "Intrinsic error" }, + { 0x00000400, -1, "Intrinsic error enable" }, + { 0x00000200, -1, "Trace thread creates" }, + { 0x00000100, -1, "Thread init trap" }, + { 0x000000e0, 5, "Reserved" }, + { 0x0000001f, 0, "Intrinsic error code" }, + {0, 0, 0}, + }; + + long psw; + struct pswbit *p; + + if (arg) + psw = parse_and_eval_address (arg); + else + psw = read_register (PS_REGNUM); + + for (p = pswbit; p->bit; p++) + { + if (p->pos < 0) + printf_filtered ("%08x %s %s\n", p->bit, + (psw & p->bit) ? "yes" : "no ", p->text); + else + printf_filtered ("%08x %3d %s\n", p->bit, + (psw & p->bit) >> p->pos, p->text); + } +} + +#include "symtab.h" + +/* reg (fmt_field, inst_field) -- + the {first,second,third} operand of instruction as fmt_field = [ijk] + gets the value of the field from the [ijk] position of the instruction */ + +#define reg(a,b) ((char (*)[3])(op[fmt->a]))[inst.f0.b] + +/* lit (fmt_field) -- field [ijk] is a literal (PSW, VL, eg) */ + +#define lit(i) op[fmt->i] + +/* aj[j] -- name for A register j */ + +#define aj ((char (*)[3])(op[A])) + +union inst { + struct { + unsigned : 7; + unsigned i : 3; + unsigned j : 3; + unsigned k : 3; + unsigned : 16; + unsigned : 32; + } f0; + struct { + unsigned : 8; + unsigned indir : 1; + unsigned len : 1; + unsigned j : 3; + unsigned k : 3; + unsigned : 16; + unsigned : 32; + } f1; + unsigned char byte[8]; + unsigned short half[4]; + char signed_byte[8]; + short signed_half[4]; +}; + +struct opform { + int mask; /* opcode mask */ + int shift; /* opcode align */ + struct formstr *formstr[3]; /* ST, E0, E1 */ +}; + +struct formstr { + unsigned lop:8, rop:5; /* opcode */ + unsigned fmt:5; /* inst format */ + unsigned i:5, j:5, k:2; /* operand formats */ +}; + +#include "opcode/convex.h" + +CONST unsigned char formdecode [] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +CONST struct opform opdecode[] = { + 0x7e00, 9, format0, e0_format0, e1_format0, + 0x3f00, 8, format1, e0_format1, e1_format1, + 0x1fc0, 6, format2, e0_format2, e1_format2, + 0x0fc0, 6, format3, e0_format3, e1_format3, + 0x0700, 8, format4, e0_format4, e1_format4, + 0x03c0, 6, format5, e0_format5, e1_format5, + 0x01f8, 3, format6, e0_format6, e1_format6, + 0x00f8, 3, format7, e0_format7, e1_format7, + 0x0000, 0, formatx, formatx, formatx, + 0x0f80, 7, formatx, formatx, formatx, + 0x0f80, 7, formatx, formatx, formatx, +}; + +/* Print the instruction at address MEMADDR in debugged memory, + on STREAM. Returns length of the instruction, in bytes. */ + +int +convex_print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + union inst inst; + struct formstr *fmt; + register int format, op1, pfx; + int l; + + read_memory (memaddr, &inst, sizeof inst); + + /* Remove and note prefix, if present */ + + pfx = inst.half[0]; + if ((pfx & 0xfff0) == 0x7ef0) + { + pfx = ((pfx >> 3) & 1) + 1; + *(long long *) &inst = *(long long *) &inst.half[1]; + } + else pfx = 0; + + /* Split opcode into format.op1 and look up in appropriate table */ + + format = formdecode[inst.byte[0]]; + op1 = (inst.half[0] & opdecode[format].mask) >> opdecode[format].shift; + if (format == 9) + { + if (pfx) + fmt = formatx; + else if (inst.f1.j == 0) + fmt = &format1a[op1]; + else if (inst.f1.j == 1) + fmt = &format1b[op1]; + else + fmt = formatx; + } + else + fmt = &opdecode[format].formstr[pfx][op1]; + + /* Print it */ + + if (fmt->fmt == xxx) + { + /* noninstruction */ + fprintf (stream, "0x%04x", pfx ? pfx : inst.half[0]); + return 2; + } + + if (pfx) + pfx = 2; + + fprintf (stream, "%s%s%s", lop[fmt->lop], rop[fmt->rop], + &" "[strlen(lop[fmt->lop]) + strlen(rop[fmt->rop])]); + + switch (fmt->fmt) + { + case rrr: /* three register */ + fprintf (stream, "%s,%s,%s", reg(i,i), reg(j,j), reg(k,k)); + return pfx + 2; + + case rr: /* two register */ + fprintf (stream, "%s,%s", reg(i,j), reg(j,k)); + return pfx + 2; + + case rxr: /* two register, reversed i and j fields */ + fprintf (stream, "%s,%s", reg(i,k), reg(j,j)); + return pfx + 2; + + case r: /* one register */ + fprintf (stream, "%s", reg(i,k)); + return pfx + 2; + + case nops: /* no operands */ + return pfx + 2; + + case nr: /* short immediate, one register */ + fprintf (stream, "#%d,%s", inst.f0.j, reg(i,k)); + return pfx + 2; + + case pcrel: /* pc relative */ + print_address (memaddr + 2 * inst.signed_byte[1], stream); + return pfx + 2; + + case lr: /* literal, one register */ + fprintf (stream, "%s,%s", lit(i), reg(j,k)); + return pfx + 2; + + case rxl: /* one register, literal */ + fprintf (stream, "%s,%s", reg(i,k), lit(j)); + return pfx + 2; + + case rlr: /* register, literal, register */ + fprintf (stream, "%s,%s,%s", reg(i,j), lit(j), reg(k,k)); + return pfx + 2; + + case rrl: /* register, register, literal */ + fprintf (stream, "%s,%s,%s", reg(i,j), reg(j,k), lit(k)); + return pfx + 2; + + case iml: /* immediate, literal */ + if (inst.f1.len) + { + fprintf (stream, "#%#x,%s", + (inst.signed_half[1] << 16) + inst.half[2], lit(i)); + return pfx + 6; + } + else + { + fprintf (stream, "#%d,%s", inst.signed_half[1], lit(i)); + return pfx + 4; + } + + case imr: /* immediate, register */ + if (inst.f1.len) + { + fprintf (stream, "#%#x,%s", + (inst.signed_half[1] << 16) + inst.half[2], reg(i,k)); + return pfx + 6; + } + else + { + fprintf (stream, "#%d,%s", inst.signed_half[1], reg(i,k)); + return pfx + 4; + } + + case a1r: /* memory, register */ + l = print_effa (inst, stream); + fprintf (stream, ",%s", reg(i,k)); + return pfx + l; + + case a1l: /* memory, literal */ + l = print_effa (inst, stream); + fprintf (stream, ",%s", lit(i)); + return pfx + l; + + case a2r: /* register, memory */ + fprintf (stream, "%s,", reg(i,k)); + return pfx + print_effa (inst, stream); + + case a2l: /* literal, memory */ + fprintf (stream, "%s,", lit(i)); + return pfx + print_effa (inst, stream); + + case a3: /* memory */ + return pfx + print_effa (inst, stream); + + case a4: /* system call */ + l = 29; goto a4a5; + case a5: /* trap */ + l = 27; + a4a5: + if (inst.f1.len) + { + unsigned int m = (inst.signed_half[1] << 16) + inst.half[2]; + fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); + return pfx + 6; + } + else + { + unsigned int m = inst.signed_half[1]; + fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); + return pfx + 4; + } + } +} + + +/* print effective address @nnn(aj), return instruction length */ + +int print_effa (inst, stream) + union inst inst; + FILE *stream; +{ + int n, l; + + if (inst.f1.len) + { + n = (inst.signed_half[1] << 16) + inst.half[2]; + l = 6; + } + else + { + n = inst.signed_half[1]; + l = 4; + } + + if (inst.f1.indir) + printf ("@"); + + if (!inst.f1.j) + { + print_address (n, stream); + return l; + } + + fprintf (stream, (n & 0xf0000000) == 0x80000000 ? "%#x(%s)" : "%d(%s)", + n, aj[inst.f1.j]); + + return l; +} + + +void +_initialize_convex_dep () +{ + add_com ("alias", class_support, alias_command, + "Add a new name for an existing command."); + + add_cmd ("base", class_vars, set_base_command, + "Change the integer output radix to 8, 10 or 16\n\ +or use just `set base' with no args to return to the ad-hoc default,\n\ +which is 16 for integers that look like addresses, 10 otherwise.", + &setlist); + + add_cmd ("pipeline", class_run, set_pipelining_command, + "Enable or disable overlapped execution of instructions.\n\ +With `set pipe off', exceptions are reported with\n\ +$pc pointing at the instruction after the faulting one.\n\ +The default is `set pipe on', which runs faster.", + &setlist); + + add_cmd ("parallel", class_run, set_parallel_command, + "Enable or disable multi-threaded execution of parallel code.\n\ +`set parallel off' means run the program on a single CPU.\n\ +`set parallel fixed' means run the program with all CPUs assigned to it.\n\ +`set parallel on' means run the program on any CPUs that are available.", + &setlist); + + add_com ("1cont", class_run, one_cont_command, + "Continue the program, activating only the current thread.\n\ +Args are the same as the `cont' command."); + + add_com ("thread", class_run, set_thread_command, + "Change the current thread, the one under scrutiny and control.\n\ +With no arg, show the active threads, the current one marked with *."); + + add_info ("threads", thread_info, + "List status of active threads."); + + add_info ("comm-registers", comm_registers_info, + "List communication registers and their contents.\n\ +A communication register name as argument means describe only that register.\n\ +An address as argument means describe the resource structure at that address.\n\ +`Locked' means that the register has been sent to but not yet received from."); + + add_info ("psw", psw_info, + "Display $ps, the processor status word, bit by bit.\n\ +An argument means display that value's interpretation as a psw."); + + add_cmd ("convex", no_class, 0, "Convex-specific commands.\n\ +32-bit registers $pc $ps $sp $ap $fp $a1-5 $s0-7 $v0-7 $vl $vs $vm $c0-63\n\ +64-bit registers $S0-7 $V0-7 $C0-63\n\ +\n\ +info threads display info on stopped threads waiting to signal\n\ +thread display list of active threads\n\ +thread N select thread N (its registers, stack, memory, etc.)\n\ +step, next, etc step selected thread only\n\ +1cont continue selected thread only\n\ +cont continue all threads\n\ +info comm-registers display contents of comm register(s) or a resource struct\n\ +info psw display processor status word $ps\n\ +set base N change integer radix used by `print' without a format\n\ +set pipeline off exceptions are precise, $pc points after the faulting insn\n\ +set pipeline on normal mode, $pc is somewhere ahead of faulting insn\n\ +set parallel off program runs on a single CPU\n\ +set parallel fixed all CPUs are assigned to the program\n\ +set parallel on normal mode, parallel execution on random available CPUs\n\ +", + &cmdlist); + +} |