| /* |
| * Kernel Memory Editor (KME) |
| * |
| * 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, 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. |
| */ |
| |
| char kme_c_version[] = "@(#)kme.c $Revision$ $Date$"; |
| |
| #include <sys/types.h> |
| |
| #include <setjmp.h> |
| #include <ctype.h> |
| #include <signal.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <stdio.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| #include "config.h" |
| |
| #if HAVE_SOCKET |
| # include <netinet/in.h> |
| # include <netdb.h> |
| #endif |
| |
| #if COFF && NLIST |
| #error You are hosed. Defined either COFF or NLIST - not both. |
| #endif |
| |
| /* |
| This really should be autoconfiscated, but now that every useful |
| system on the planet has a perfectly lovely nlist, I'm not convinced |
| it's useful. |
| #if COFF |
| # include <filehdr.h> |
| # include <ldfcn.h> |
| # include <syms.h> |
| #endif */ |
| |
| #if HAVE_SOCKET |
| # include <sys/socket.h> |
| #endif |
| |
| #if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| #endif |
| |
| #if HAVE_SYS_KSYM_H |
| # include <sys/ksym.h> |
| # include <sys/elf.h> |
| #endif |
| |
| #if HAVE_NLIST_H |
| # include <nlist.h> |
| #endif |
| |
| #if HAVE_LIBELF_NLIST_H |
| # include <libelf/nlist.h> |
| #endif |
| |
| #if HAVE_MMAP |
| # include <sys/mman.h> |
| #endif |
| |
| /* #if !defined(VTIME) */ |
| # include <termio.h> |
| /* #endif */ |
| |
| #if defined(KEY_HOME) |
| # define TERMINFO 1 |
| #endif |
| |
| #if HAVE_LIBNCURSES |
| # include <ncurses.h> |
| #endif |
| |
| #if HAVE_LIBCURSES |
| # include <curses.h> |
| #endif |
| |
| #if HAVE_SYS_PTRACE_H |
| # include <sys/ptrace.h> |
| #endif |
| |
| #if HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| |
| #if HAVE_STDLIB_H |
| # include <stdlib.h> |
| #endif |
| |
| #if HAVE_STRING_H |
| # include <string.h> |
| #endif |
| |
| #if HAVE_WAIT_H |
| # include <wait.h> |
| #endif |
| |
| #if HAVE_SOCKET |
| # include <netinet/in.h> |
| # include <netdb.h> |
| #endif |
| |
| #if HAVE_LIBDL |
| # include <dlfcn.h> |
| #endif |
| |
| /* |
| * Unsigned variables. This form makes them impervious |
| * to similar defs in sys/types.h. |
| */ |
| |
| #define uchar unsigned char |
| #define ushort unsigned short |
| #define ulong unsigned long |
| |
| #if HAVE_SOCKET |
| #if HAVE_STROPTS_H |
| # include <stropts.h> |
| #endif /* HAVE_STROPTS_H */ |
| #endif |
| |
| /* |
| * Compensate for lame systems that support ptrace, but |
| * have no <sys/ptrace.h> |
| */ |
| |
| #if !defined PTRACE_ATTACH |
| # define PTRACE_ATTACH 10 |
| #endif |
| #if !defined PTRACE_DETACH |
| # define PTRACE_DETACH 11 |
| #endif |
| #if !defined PTRACE_PEEKDATA |
| # define PTRACE_PEEKDATA 2 |
| #endif |
| #if !defined PTRACE_POKEDATA |
| # define PTRACE_POKEDATA 5 |
| #endif |
| |
| #if lint |
| #define malloc(x) 0 |
| #endif |
| |
| extern int optind ; |
| extern char *optarg ; |
| |
| #include "kme.h" |
| char kme_h_version[] = KME_H_VERSION; |
| |
| /* |
| * OLDCURSE indicates a curses where keypad keys (eg arrow keys) |
| * do not work when using VMIN=0. Unfortunately, keypad keys |
| * are broken almost everywhere, so OLDCURSE is now default. |
| */ |
| |
| #define OLDCURSE 1 |
| |
| #if OLDCURSE |
| #define chtype int |
| #endif |
| |
| #define ctrl(x) ((x) & 0x1f) |
| |
| /* |
| * Default file names. |
| */ |
| |
| char *corename = "/dev/kmem" ; |
| char *defsname = "kme_defs" ; |
| char *symname = 0 ; |
| char *defspath = "." ; |
| |
| /* |
| * Interface to SC vi-edit routines. |
| */ |
| |
| #define LINELEN 200 /* Max line size */ |
| |
| extern int linepos ; /* Line position */ |
| extern char line[] ; /* Line buffer */ |
| extern (*lineproc)() ; /* Line processing procedure */ |
| |
| extern int mode_ind ; /* Mode indicator */ |
| |
| /* |
| * Address field definition. |
| */ |
| |
| typedef struct |
| { |
| long a_addr ; /* Display offset */ |
| char* a_disp ; /* Display string */ |
| int a_size ; /* Number of bytes */ |
| int a_grow ; /* Automatically unobscure itself */ |
| } a_field ; |
| |
| long addr_mask = -1 ; /* All addresses read from a symbol |
| file are masked with this */ |
| |
| #define NADR 400 /* Max number of addresses */ |
| a_field afield[NADR] ; /* Address fields */ |
| a_field bfield[NADR] ; /* Address buffer */ |
| |
| /* |
| * Data field definition. |
| */ |
| |
| typedef struct |
| { |
| ulong d_addr ; /* Address */ |
| int d_type ; /* Type */ |
| } d_field ; |
| |
| #define NDATA (66 * 12) /* Max number of data columns */ |
| |
| d_field dfield[NDATA] ; /* Column fields */ |
| |
| #define DFIELD(r,c) (dfield[ncol * ((r) - frow) + (c) - 1]) |
| |
| /* |
| * Field row/column positioning. |
| */ |
| |
| #define FROW(r) ((r) - frow) |
| #define FCOL(c) ((c) ? (8 * (c) + 7) : 5) |
| |
| int initial_display_row; /* To track order of automatic |
| insertions */ |
| |
| #if OLDCURSE |
| /* |
| * Terminal structure. |
| */ |
| |
| struct termio otio ; /* Original terminal structure */ |
| struct termio tio ; /* Curses terminal structure */ |
| #endif |
| |
| /* |
| * Expression parsing variables. |
| */ |
| |
| jmp_buf efail ; /* Error recovery */ |
| char *str ; /* String position */ |
| int inparen = 0 ; /* In parenthesis */ |
| int ebase ; /* Default input base */ |
| |
| /* |
| * Symbol structure. |
| */ |
| |
| typedef struct symbol SYM ; |
| |
| struct symbol |
| { |
| SYM* s_next ; /* Next item on list */ |
| ulong s_value ; /* Symbol value */ |
| char s_name[10] ; /* Symbol name */ |
| } ; |
| |
| #define NHASH 2909 /* Hash table size (prime) */ |
| |
| SYM* symbol[NHASH] ; /* Hash table */ |
| |
| char *symparam ; /* Symbol file name parameter */ |
| |
| /* |
| * Temp variables. |
| */ |
| |
| #define TEMP_MAX 10 |
| |
| ulong temp[TEMP_MAX]; /* Temp store variables */ |
| int width = 4; |
| |
| /* |
| * Miscellaneous flags. |
| */ |
| |
| char *progname ; /* Program name */ |
| |
| int sigint ; /* Got an interrupt */ |
| |
| int idline ; /* Call idlok() */ |
| |
| int quitreq ; /* Exit quick */ |
| int debug ; /* Debug on */ |
| |
| int depth ; /* Recursion depth */ |
| |
| int scount ; /* Scroll count */ |
| |
| int uptime = 2 ; /* Screen update time */ |
| int helpflag = 0 ; /* Show help information */ |
| int addrflag = 1 ; /* Show addresses */ |
| int writeflag = 1 ; /* Open core file for write */ |
| |
| int swapflag = 0 ; /* Swap "endianness" for |
| words & longs */ |
| |
| int index_mode = 1 ; /* display array as |
| "foo+0x80" or "foo[1]" */ |
| |
| int addrscale = 1; /* Scale displayed addresses */ |
| |
| int rw_max ; /* Max readahead */ |
| |
| /* |
| * Special FEP support variables. |
| */ |
| |
| int def_board ; /* Default board number */ |
| int def_conc ; /* Default concentrator number */ |
| int ov_board ; /* Overide board number */ |
| int ov_conc ; /* Overide concentrator number */ |
| |
| #if HAVE_SOCKET |
| int nsoc ; /* Actual number of sockets */ |
| char *fepdev ; /* FEP device name */ |
| #endif |
| |
| #if HAVE_STROPTS_H |
| int strdev = 0; |
| #endif |
| |
| #if HAVE_SOCKET |
| #define RW_PAKLEN \ |
| ((unsigned)&((rw_t *)0)->rw_data[sizeof(((rw_t *)0)->rw_data)]) |
| |
| #define MAXSOC 10 /* Max number of open sockets */ |
| int socfd[MAXSOC] ; /* Socket file descriptor */ |
| char *hostname ; /* Host name list */ |
| #endif |
| |
| int fepfd ; /* FEP file descriptor */ |
| |
| /* |
| * Special Emulator support variables. |
| */ |
| |
| #if USE_HP_ANALYZER |
| #define EM_READ 64 /* Size of emulator read */ |
| |
| char *emdev ; /* tty device name */ |
| int emfd ; /* tty file descriptor */ |
| |
| FILE *emin ; /* tty file name */ |
| FILE *emout ; /* tty output file */ |
| #endif |
| |
| /* |
| * Screen variables. |
| */ |
| |
| int onscreen ; /* This row on the screen */ |
| |
| int brow ; /* Number of rows in buffer */ |
| |
| int frow ; /* First row on the screen */ |
| int lrow ; /* First row on last refresh */ |
| int trow ; /* Temporary version of frow */ |
| |
| int crow ; /* Current display row */ |
| int erow ; /* End of display area */ |
| |
| int irow ; /* Input row */ |
| int icol ; /* Input column */ |
| |
| int orow ; /* Output row */ |
| int ocol ; /* Output column */ |
| |
| int nrow ; /* Number of rows on screen */ |
| int ncol ; /* Number of columns on screen */ |
| |
| /* |
| * Formatting strings. |
| */ |
| |
| char *format[26] ; /* Display formatting strings */ |
| char keyformat[26] ; /* Format entered from |
| command/keyboard */ |
| |
| /* |
| * Symbolic formatting strings. |
| */ |
| |
| typedef struct |
| { |
| char * name ; /* Name entered from command or kbd */ |
| char * format; /* Display formatting strings */ |
| char *(*dlfunc)(ulong *addrp, int dlarg); /* Function */ |
| int dlarg; /* User defined function argument */ |
| } d_fmt ; |
| |
| int fmt_cnt; |
| int dl_fmt_cnt; |
| |
| #define NSYM_FORMATS 512 /* Max number of symbol formattings */ |
| |
| d_fmt dfmt[NSYM_FORMATS] ; |
| |
| |
| int readch(void) ; |
| |
| char hexnum[] = "0123456789abcdefghijklmnopqrstuvwxyz" ; |
| |
| /* |
| * Core memory access. |
| */ |
| |
| char *coredev ; /* Core file parameter */ |
| |
| ulong base ; /* Base address */ |
| ulong addr ; /* Memory address being displayed */ |
| ulong faddr ; /* First address this display item */ |
| |
| int lboard ; /* Last board number */ |
| int lconc ; /* Last conc number */ |
| ulong laddr ; /* Low read address */ |
| ulong haddr ; /* High read address */ |
| |
| int memfd ; /* Core file descriptor */ |
| |
| long mem[128] ; /* Memory array */ |
| |
| #if HAVE_MMAP |
| ulong mempa; /* Memory phys addr */ |
| ulong memlen; /* Memory length */ |
| uchar *memva; /* Virtual address */ |
| #endif |
| |
| #define ALIGNED(ADDR,BYTES) (! (((int) ADDR) & (BYTES-1))) |
| |
| #if HAVE_PTRACE |
| int pid ; /* Process ID of process we're |
| examining */ |
| #endif |
| |
| /* |
| * Help strings. |
| */ |
| |
| char *helptext[] = |
| { |
| "+/- (c)hange (d)elete (e)dit (i)nsert (m)acro (p)ut (y)ank (q)uit (z)ero", |
| "Enter address/format", |
| "Enter the value to store in memory", |
| } ; |
| |
| |
| /************************************************************************ |
| * catch - catch interrupts gracefully |
| ************************************************************************/ |
| |
| void |
| catch(sig) |
| { |
| signal(SIGINT, catch) ; |
| |
| sigint = 1 ; |
| |
| beep() ; |
| } |
| |
| |
| /************************************************************************ |
| * bigendian - Return true if we are on a bigendian host |
| ************************************************************************/ |
| bigendian() |
| { |
| int endian = 1; |
| |
| return ((char *) &endian)[0] != 1; |
| } |
| |
| |
| /************************************************************************ |
| * swaps - Swap short operand. |
| ************************************************************************/ |
| |
| ushort |
| always_swaps(mval) |
| register ushort mval; |
| { |
| mval = (((mval >> 8) & 0xff) | ((mval << 8) & 0xff00)) ; |
| return (mval); |
| } |
| |
| |
| ushort |
| swaps(mval) |
| register ushort mval ; |
| { |
| if (swapflag) |
| { |
| mval = always_swaps(mval); |
| } |
| |
| return (mval) ; |
| } |
| |
| |
| /************************************************************************ |
| * swapl - Swap long operand. |
| ************************************************************************/ |
| |
| ulong |
| always_swapl (mval) |
| register ulong mval ; |
| { |
| mval = (((mval >> 24) & 0x000000ff) | |
| ((mval >> 8) & 0x0000ff00) | |
| ((mval << 8) & 0x00ff0000) | |
| ((mval << 24) & 0xff000000)); |
| return(mval); |
| } |
| |
| |
| ulong |
| swapl(mval) |
| register ulong mval ; |
| { |
| if (swapflag) |
| mval = always_swapl(mval); |
| |
| return (mval) ; |
| } |
| |
| |
| /************************************************************************ |
| * stralloc - Allocate string. |
| ************************************************************************/ |
| |
| char * |
| stralloc(s) |
| char *s ; |
| { |
| char *d ; |
| |
| if (s == 0) return(0) ; |
| |
| d = (char *)malloc((unsigned)strlen(s)+1) ; |
| if (d) strcpy(d, s) ; |
| |
| return(d) ; |
| } |
| |
| |
| |
| /************************************************************************ |
| * strfree - Free string. |
| ************************************************************************/ |
| |
| void |
| strfree(s) |
| char *s ; |
| { |
| if (s) free((void *)s) ; |
| } |
| |
| |
| /************************************************************************ |
| * Find a display symbol name in the tables |
| * Returns index in array. |
| * |
| * FIXME: Optimization Opportunity. Rather |
| * than ripping through these sequentially, |
| * do a hashed lookup. This has to consume |
| * killer clock cycles, and it's run on each |
| * screen update..... |
| * |
| ************************************************************************/ |
| |
| int |
| find_format(s) |
| char *s ; |
| { |
| int x; |
| for (x=0;x<fmt_cnt;x++) |
| if (strcmp(dfmt[x].name,s) == 0) |
| return (x); |
| return(-1); |
| |
| } |
| |
| |
| /************************************************************************ |
| * Add a symbolic format to the table. |
| * FIXME: should build hash table (index?) hinted at above... |
| ************************************************************************/ |
| |
| void |
| add_format(char *name, char *format, |
| char * (*dlfunc)(ulong *addrp, int dlarg), int dlarg) |
| { |
| dfmt[fmt_cnt].name = stralloc(name); |
| dfmt[fmt_cnt].format = format ? stralloc(format) : NULL; |
| dfmt[fmt_cnt].dlfunc = dlfunc; |
| dfmt[fmt_cnt].dlarg = dlarg; |
| |
| if (debug) |
| fprintf(stderr, |
| "Defined full command: (%s)%d = %s\n", |
| dfmt[fmt_cnt].name, fmt_cnt, |
| format ? dfmt[fmt_cnt].format : "function") ; |
| |
| if (fmt_cnt++ > NSYM_FORMATS) |
| { |
| fprintf(stderr, "\nFATAL: exceeded %d symbolic formats\n", |
| NSYM_FORMATS); |
| exit(1); |
| } |
| } |
| |
| |
| /************************************************************************ |
| * getbase - Convert the next few characters of an ascii |
| * string to a number of the specified base. |
| ************************************************************************/ |
| |
| char * |
| getbase(s, value, b) |
| register char *s ; |
| ulong *value ; |
| int b ; |
| { |
| ulong v ; |
| int n ; |
| int d ; |
| |
| if (s[0] == '0') |
| { |
| if (s[1] == 't') { b = 10 ; s += 2 ; } |
| else if (s[1] == 'x') { b = 16 ; s += 2 ; } |
| else b = 16 ; |
| } |
| |
| v = 0 ; |
| for (n = 0 ;; n++) |
| { |
| if ('0' <= *s && *s <= '9') d = *s - '0' ; |
| else if ('a' <= *s && *s <= 'z') d = *s - 'a' + 10 ; |
| else if ('A' <= *s && *s <= 'z') d = *s - 'A' + 10 ; |
| else break ; |
| |
| if (d >= b) break ; |
| |
| v = b * v + d ; |
| s++ ; |
| } |
| |
| if (n == 0) return(0) ; |
| |
| *value = v ; |
| |
| return(s) ; |
| } |
| |
| |
| /************************************************************************ |
| * getdigit - Convert an alphanumeric digit to a number. |
| ************************************************************************/ |
| |
| int |
| getdigit(c) |
| int c ; |
| { |
| return(c <= '9' ? c - '0' : c < 'Z' ? c - 'A' + 10 : c - 'a' + 10) ; |
| } |
| |
| |
| /************************************************************************ |
| * readdefs - Read formatting strings from a file. |
| ************************************************************************/ |
| |
| int readdefs() |
| { |
| register char *cp ; |
| register int ch ; |
| register int i ; |
| register int nstring ; |
| register int cmd ; |
| int full_cmd ; |
| int rtn ; |
| int quote ; |
| int bang ; |
| char *s ; |
| char *f ; |
| FILE *file ; |
| char buf[200] ; |
| char string[32768] ; |
| char fmt_name[200] ; |
| char *fmt_name_index ; |
| |
| /* |
| * Discard old format strings. |
| */ |
| |
| for (i = 0 ; i < 26 ; i++) |
| { |
| if (!keyformat[i]) |
| { |
| strfree(format[i]) ; |
| format[i] = 0 ; |
| } |
| } |
| |
| fmt_cnt = dl_fmt_cnt; |
| |
| /* |
| * Loop to open several filenames separated |
| * by colons. |
| */ |
| |
| rtn = 1 ; |
| |
| for (f = defsname ; *f ;) |
| { |
| /* |
| * Open the file. |
| */ |
| |
| s = buf ; |
| while (*f && (ch = *f++) != ':') *s++ = ch ; |
| *s = 0 ; |
| |
| if (*buf == '/') |
| { |
| file = fopen(buf, "r") ; |
| if (file == 0) |
| { |
| rtn = 0 ; |
| fprintf(stderr, "Warning: could not open ") ; |
| perror(buf) ; |
| continue ; |
| } |
| } |
| else |
| { |
| char path[200]; |
| char fullpath[200]; |
| char *p, *ps; |
| |
| file = 0; |
| for (p = defspath; *p;) |
| { |
| ps = path; |
| while (*p && (ch = *p++) != ':') *ps++ = ch ; |
| *ps = 0 ; |
| if (*path == 0) strcpy(path, "."); |
| |
| sprintf(fullpath, "%s/%s", path, buf); |
| file = fopen(fullpath, "r") ; |
| if (file) |
| break; |
| } |
| if (file == 0) |
| { |
| if (strcmp(buf, "kme_defs")) |
| { |
| rtn = 0 ; |
| fprintf(stderr, "Warning: could not find ") ; |
| perror(buf) ; |
| } |
| continue ; |
| } |
| } |
| |
| /* |
| * Read lines from the file. |
| */ |
| |
| cmd = 0 ; |
| full_cmd = 0 ; |
| nstring = 0 ; |
| |
| for (;;) |
| { |
| /* |
| * Get next line from input. |
| */ |
| |
| s = fgets(buf, sizeof(buf), file) ; |
| |
| /* |
| * If EOF, or a new command, allocate space for |
| * the last command. |
| */ |
| |
| if (s == 0 || isupper(buf[0]) || (buf[0] == '!')) |
| { |
| if (cmd && !keyformat[cmd -= 'A']) |
| { |
| strfree(format[cmd]) ; |
| |
| string[nstring] = 0 ; |
| format[cmd] = stralloc(string) ; |
| |
| if (debug) |
| { |
| fprintf(stderr, "Defined command: %c = %s\n", |
| cmd + 'A', string) ; |
| } |
| } |
| else if (full_cmd) |
| { |
| string[nstring] = 0 ; |
| add_format(fmt_name, string, NULL, 0); |
| } |
| cmd = 0 ; |
| full_cmd = 0 ; |
| nstring = 0 ; |
| } |
| |
| /* |
| * Exit on EOF. |
| */ |
| |
| if (s == 0) break ; |
| |
| /* |
| * A line beginning with an upper case letter begins |
| * a definition. A line who's first non-white space |
| * is a "#" is a comment. Other lines are continuations. |
| * Single and double quoted strings are passed verbatim, |
| * otherwise white space is discarded. |
| * Behaviour Change 07/02/94 robertl@arnet.com..... |
| * If the first character is a '!', we take that as |
| * a "symbolic" format name. |
| * Symbolic format names are not recursive. |
| * Symbolic names may contain any printing character. |
| */ |
| |
| cp = &buf[0] ; |
| |
| /* |
| * Check for a new format definition name at beginning of line |
| */ |
| if (isupper(*cp)) |
| { |
| /* |
| * Its an old style definition |
| */ |
| cmd = *cp++; |
| } |
| else if (*cp == '!') |
| { |
| /* |
| * Its a new style definition |
| */ |
| ++cp; |
| |
| fmt_name_index = fmt_name ; |
| while (cp && (isalnum(*cp) || (*cp == '_'))) |
| *fmt_name_index++ = *cp++; |
| *fmt_name_index = 0; |
| |
| full_cmd = 1; |
| } |
| |
| /* |
| * Process rest of line |
| */ |
| |
| while (isspace(*cp)) cp++ ; |
| |
| if ((*cp == '#')) continue ; |
| |
| quote = 0 ; |
| bang = 0; |
| |
| while ((ch = *cp++) != 0) |
| { |
| if (quote) |
| { |
| if (ch == quote) quote = 0 ; |
| } |
| else |
| { |
| if (bang) |
| { |
| if (!isalnum(ch) && ch != '_') bang = 0; |
| if (isspace(ch)) ch = ' '; |
| } |
| else if (isspace(ch)) continue ; |
| |
| if (ch == '\'' || ch == '"') quote = ch ; |
| else if (ch == '!') bang = 1; |
| } |
| |
| if (nstring < sizeof(string)-2) string[nstring++] = ch ; |
| } |
| |
| if (quote && nstring < sizeof(string)-2) string[nstring++] = ch ; |
| } |
| |
| fclose(file) ; |
| } |
| |
| return(rtn) ; |
| } |
| |
| |
| /************************************************************************ |
| * hashname - Hash name to symbol table pointer. |
| ************************************************************************/ |
| |
| SYM** |
| hashname(name) |
| char *name ; |
| { |
| register ulong v ; |
| |
| v = 0 ; |
| |
| while (*name) |
| { |
| v += *name++ ; |
| v *= 23 ; |
| } |
| |
| return symbol + (v % NHASH) ; |
| } |
| |
| |
| /************************************************************************ |
| * readsym - Read namelist file. |
| ************************************************************************/ |
| |
| int |
| readsym() |
| { |
| register SYM **spp ; |
| register SYM *sp ; |
| register char *cp ; |
| char *f ; |
| int ch ; |
| int rtn ; |
| FILE *file ; |
| ulong value ; |
| char *name ; |
| char buf[100] ; |
| unsigned n ; |
| |
| #if COFF |
| LDFILE *ldp; |
| SYMENT sym; |
| int i; |
| unsigned short magic; |
| #endif |
| |
| /* |
| * Clear the current namelist file. |
| */ |
| |
| for (spp = symbol ; spp < symbol + NHASH ; spp++) |
| { |
| while (sp = *spp) |
| { |
| *spp = sp->s_next ; |
| free((void *)sp) ; |
| } |
| } |
| |
| /* |
| * Read in the new symbol file. |
| */ |
| |
| rtn = 1 ; |
| |
| for (f = symname ; *f ;) |
| { |
| /* |
| * Open the file. |
| */ |
| |
| cp = buf ; |
| while (*f && (ch = *f++) != ':') *cp++ = ch ; |
| *cp = 0 ; |
| |
| file = fopen(buf, "r") ; |
| if (file == 0) |
| { |
| rtn = 0 ; |
| continue ; |
| } |
| |
| #if COFF |
| /* |
| * See if file is COFF |
| */ |
| |
| n = fread(&magic, sizeof(magic), 1, file); |
| if (n == 1 && ISCOFF(magic)) |
| { |
| /* |
| * COFF namelist |
| */ |
| |
| fclose(file); |
| ldp = ldopen(buf, (LDFILE *) NULL); |
| if (ldp) |
| { |
| for (i = 0; ldtbread(ldp, i, &sym) != FAILURE; ++i) |
| { |
| i += sym.n_numaux; /* Skip AUX info */ |
| name = ldgetname(ldp, &sym); |
| if (!name) continue; |
| if (sym.n_sclass != C_EXT) continue; |
| spp = hashname(name) ; |
| n = (unsigned)&((SYM*)0)->s_name[strlen(name)+1] ; |
| sp = (SYM*)malloc(n) ; |
| if (sp == 0) |
| { |
| fprintf(stderr, "Out of memory") ; |
| exit(1) ; |
| } |
| sp->s_next = *spp ; |
| *spp = sp ; |
| sp->s_value = sym.n_value & addr_mask ; |
| strcpy(sp->s_name, name) ; |
| if (debug) |
| { |
| fprintf(stderr, "Added Symbol %s = %x\n", |
| sp->s_name, sp->s_value) ; |
| } |
| } |
| ldclose(ldp); |
| } |
| continue ; |
| } |
| |
| fseek(file, 0L, 0); |
| #endif |
| #if HAVE_NLIST |
| /* |
| If we're able to use nlist(2), we don't have to |
| read this whole thing into core. But to allow |
| the ability for a single kme binary to work with |
| both native binaries (say, /unix) and binaries |
| that we provide an ASCII symbol table for (cay, |
| csfep.sym), let's read some stuff. If any of it |
| is non-ascii, we'll let the nlister take care of |
| it. |
| */ |
| { |
| int file_is_binary = 0 ; |
| |
| n = fread(&buf, 1, sizeof(buf), file); |
| while(n--) |
| { |
| if (!isascii(buf[n])) |
| file_is_binary = 1 ; |
| } |
| if (file_is_binary) |
| { |
| if (debug) |
| fprintf(stderr, "File is binary, continuing\n"); |
| fclose(file); |
| continue; |
| } |
| } |
| #endif |
| |
| /* |
| * Read all the symbols in the (ASCII) file. |
| */ |
| |
| fseek(file, 0L, 0); |
| while (fgets(buf, sizeof(buf), file) != 0) |
| { |
| cp = buf ; |
| while (isspace(*cp)) cp++ ; |
| |
| cp = getbase(cp, &value, 16) ; |
| if (cp == 0) |
| { |
| rtn = 0 ; |
| continue ; |
| } |
| |
| while (isspace(*cp)) cp++ ; |
| |
| name = cp ; |
| while (*cp && !isspace(*cp)) |
| cp++ ; |
| *cp = 0 ; |
| |
| #if HAVE_PROC_KSYMS |
| /* |
| * Strip module Ids from /dev/ksym files. |
| */ |
| |
| if (cp - name > 10 && cp[-10] == '_' && cp[-9] == 'R') |
| { |
| char *hp = cp - 8; |
| |
| while (isxdigit(*hp)) |
| hp++; |
| |
| if (*hp == 0) |
| cp[-10] = 0; |
| } |
| #endif |
| |
| spp = hashname(name) ; |
| |
| n = (unsigned)&((SYM*)0)->s_name[strlen(name)+1] ; |
| |
| sp = (SYM*)malloc(n) ; |
| |
| if (sp == 0) |
| { |
| fprintf(stderr, "Out of memory") ; |
| exit(1) ; |
| } |
| |
| sp->s_next = *spp ; |
| *spp = sp ; |
| |
| sp->s_value = value & addr_mask ; |
| strcpy(sp->s_name, name) ; |
| |
| if (debug) |
| { |
| fprintf(stderr, "Added Symbol %s = %lx\n", |
| sp->s_name, sp->s_value) ; |
| } |
| } |
| } |
| |
| return(rtn) ; |
| } |
| |
| |
| /************************************************************************ |
| * gethex - Hexidecimal number reader for the HP logic |
| * analyzer interface. |
| ************************************************************************/ |
| |
| #if USE_HP_ANALYZER |
| char * |
| gethex(p, val, n) |
| char *p ; |
| ulong *val ; |
| int n ; |
| { |
| ulong v ; |
| int d ; |
| |
| for (v = 0 ;;) |
| { |
| if ('0' <= *p && *p <= '9') d = *p - '0' ; |
| else if ('A' <= *p && *p <= 'Z') d = *p - 'A' + 10 ; |
| else if ('a' <= *p && *p <= 'z') d = *p - 'a' + 10 ; |
| else break ; |
| |
| v = 16 * v + d ; |
| |
| p++ ; |
| n-- ; |
| } |
| |
| if (n) return(0) ; |
| |
| if (debug) fprintf(stderr, "Gethex: %x\n", v) ; |
| |
| *val = v ; |
| return(p) ; |
| } |
| #endif |
| |
| |
| /************************************************************************ |
| * getmem - Get memory bytes. |
| ************************************************************************/ |
| |
| int |
| getmem(nbyte) |
| unsigned nbyte ; |
| { |
| int rw_size = rw_max < nbyte ? rw_max : nbyte; |
| long a = (addr + base) & addr_mask; |
| |
| static rw_t rw ; |
| static rtncode ; |
| |
| /* |
| * If the data is already in the read-ahead buffer, |
| * there is no need to fetch it. |
| */ |
| |
| if (ov_board == lboard && |
| ov_conc == lconc && |
| a >= laddr && |
| a + nbyte <= haddr) |
| { |
| goto rw_return; |
| } |
| |
| #if HAVE_STROPTS_H |
| if (fepdev && strdev) |
| { |
| struct strioctl stio; |
| |
| /* |
| * Build the request and do the ioctl. |
| */ |
| |
| rw.rw_req = RW_READ ; |
| rw.rw_size = rw_size ; |
| |
| rw.rw_board = lboard = ov_board ; |
| rw.rw_conc = lconc = ov_conc ; |
| rw.rw_addr = laddr = a ; |
| |
| stio.ic_cmd = DIGI_KME; |
| stio.ic_timout = 0; |
| stio.ic_len = sizeof(rw); |
| stio.ic_dp = (char *) &rw; |
| |
| if (ioctl(fepfd, I_STR, &stio) == -1 || |
| rw.rw_size < nbyte) |
| { |
| haddr = rw.rw_addr + 1024 ; |
| rtncode = 0 ; |
| } |
| else |
| { |
| haddr = rw.rw_addr + rw.rw_size ; |
| rtncode = 1 ; |
| } |
| |
| goto rw_return; |
| } |
| #endif /* HAVE_STROPTS_H */ |
| |
| /* |
| * Read memory from the DigiBoard special device |
| * driver hooks. |
| */ |
| |
| if (fepdev) |
| { |
| /* |
| * Build the request and do the ioctl. |
| */ |
| |
| rw.rw_req = RW_READ ; |
| rw.rw_size = rw_size ; |
| |
| rw.rw_board = lboard = ov_board ; |
| rw.rw_conc = lconc = ov_conc ; |
| rw.rw_addr = laddr = a ; |
| |
| if (ioctl(fepfd, DIGI_KME, &rw) == -1 || |
| rw.rw_size < nbyte) |
| { |
| haddr = rw.rw_addr + 1024 ; |
| rtncode = 0 ; |
| } |
| else |
| { |
| haddr = rw.rw_addr + rw.rw_size ; |
| rtncode = 1 ; |
| } |
| |
| goto rw_return; |
| } |
| |
| #if HAVE_SOCKET |
| /* |
| * Read memory from TCP/IP style device. |
| */ |
| |
| if (nsoc) |
| { |
| int fd ; |
| int rtry ; |
| int wtry ; |
| rw_t w ; |
| struct timeval tv ; |
| |
| static fd_set fdn ; |
| static fd_set fdr ; |
| |
| if (ov_board >= nsoc) return(0) ; |
| |
| /* |
| * Build the request packet. |
| */ |
| |
| w.rw_req = RW_READ ; |
| w.rw_size = rw_size ; |
| |
| w.rw_board = lboard = ov_board ; |
| w.rw_conc = lconc = ov_conc ; |
| w.rw_addr = laddr = a ; |
| |
| w.rw_size = swaps(w.rw_size) ; |
| w.rw_addr = swapl(w.rw_addr) ; |
| |
| fd = socfd[w.rw_board] ; |
| |
| /* |
| * Repeatedly request the data with UDP until |
| * a response is heard from the remote. |
| */ |
| |
| rtncode = 0 ; |
| |
| for (wtry = 0 ; !rtncode ; wtry++) |
| { |
| if (wtry >= 3) |
| { |
| haddr = laddr + 1024 ; |
| break ; |
| } |
| |
| write(fd, (char *)&w, RW_PAKLEN) ; |
| |
| /* |
| * Wait for the response packet. |
| */ |
| |
| for (rtry = 0 ; !rtncode && rtry < 3 ; rtry++) |
| { |
| /* |
| * On timeout, exit with bad return status. |
| */ |
| |
| FD_ZERO(&fdr) ; |
| FD_SET(fd, &fdr) ; |
| |
| tv.tv_sec = 1 ; |
| tv.tv_usec = 0 ; |
| |
| if (select(FD_SETSIZE, &fdr, &fdn, &fdn, &tv) < 1) |
| break ; |
| |
| /* |
| * On response from the correct file descriptor, |
| * with the response we expect, accept the response. |
| * |
| * Note that it is possible to get an irrelevant |
| * response if on a previous request, the network |
| * delays exceeded our simplistic 2 second timeout. |
| */ |
| |
| if (read(fd, (char *)&rw, RW_PAKLEN) == RW_PAKLEN && |
| rw.rw_req == w.rw_req && |
| rw.rw_board == w.rw_board && |
| rw.rw_conc == w.rw_conc && |
| rw.rw_addr == w.rw_addr) |
| { |
| rw.rw_size = swaps(rw.rw_size) ; |
| rw.rw_addr = swapl(rw.rw_addr) ; |
| |
| if (rw.rw_size < nbyte) |
| { |
| haddr = rw.rw_addr + 0x100 ; |
| return(0) ; |
| } |
| |
| haddr = rw.rw_addr + rw.rw_size ; |
| rtncode = 1 ; |
| break ; |
| } |
| } |
| } |
| |
| goto rw_return; |
| } |
| #endif |
| |
| #if USE_HP_ANALYZER |
| /* |
| * Read memory from the HP emulator. |
| */ |
| |
| if (emdev) |
| { |
| ulong a ; |
| ulong v ; |
| int n ; |
| int ch ; |
| char *p ; |
| char buf[100] ; |
| static char embuf[EM_READ] ; |
| static rtncode ; |
| |
| if (a < laddr || a + nbyte > haddr) |
| { |
| laddr = a ; |
| haddr = a + EM_READ ; |
| |
| fprintf(emout, "m -db %x..%x\r", laddr, haddr-1) ; |
| fflush(emout) ; |
| |
| a = laddr ; |
| |
| for (;;) |
| { |
| clearerr(emin) ; |
| |
| for (n = 0 ; n < sizeof(buf)-2 ;) |
| { |
| |
| ch = getc(emin) ; |
| |
| if (ch == EOF) break ; |
| |
| ch &= 0x7f ; |
| |
| if (ch < 0x20) |
| { |
| if (n > 40) break ; |
| |
| n = 0 ; |
| } |
| else |
| { |
| buf[n++] = ch ; |
| } |
| } |
| |
| if (n == 0) |
| { |
| if (debug) fprintf(stderr, "EM eof\n") ; |
| rtncode = (a == haddr) ; |
| break ; |
| } |
| |
| buf[n] = 0 ; |
| |
| if (debug) |
| { |
| fprintf(stderr, "EM string: %s\n", buf) ; |
| } |
| |
| if (a >= haddr) continue ; |
| |
| p = buf ; |
| while (*p == ' ' || *p == '\r') p++ ; |
| |
| if ((p = gethex(p, &v, 6)) == 0 || |
| v != a || |
| *p++ != '.' || |
| *p++ != '.' || |
| (p = gethex(p, &v, 6)) == 0 || |
| v != a+15 || |
| *p++ != ' ') |
| continue ; |
| |
| for (n = 0 ;; n++) |
| { |
| if (n == 16) |
| { |
| a += 16 ; |
| break ; |
| } |
| |
| if (*p++ != ' ' || |
| (p = gethex(p, &v, 2)) == 0) |
| break ; |
| |
| embuf[n + a - laddr] = v ; |
| } |
| } |
| } |
| |
| if (rtncode) |
| { |
| memcpy((char *)mem, (char *)&embuf[a-laddr], nbyte) ; |
| } |
| |
| return(rtncode) ; |
| } |
| #endif |
| |
| #if HAVE_MMAP |
| /* |
| * Read data from mapped file. |
| */ |
| |
| if (memlen) |
| { |
| char *p = memva + a; |
| |
| if (a < 0 || a + nbyte > memlen) |
| return(0); |
| |
| switch (nbyte) |
| { |
| case 1: |
| *(char *) mem = *(char *) p; |
| break; |
| case 2: |
| if (ALIGNED(mem,2) && ALIGNED(p,2)) |
| *(short *) mem = *(short *) p; |
| else |
| memcpy((char *) mem, p, (unsigned) nbyte); |
| break; |
| case 4: |
| if (ALIGNED(mem,4) && ALIGNED(p,4)) |
| *(long *) mem = *(long *) p; |
| else |
| memcpy((char *) mem, p, (unsigned) nbyte); |
| break; |
| default: |
| memcpy((char *) mem, p, (unsigned) nbyte); |
| break; |
| } |
| |
| return(1); |
| } |
| #endif |
| |
| #if HAVE_PTRACE |
| /* |
| * Ptrace memory read. |
| */ |
| |
| if (pid) |
| { |
| int x ; |
| |
| /* Attach to process, and stop it */ |
| if (ptrace (PTRACE_ATTACH, pid, a, 0) == -1) |
| { |
| printw("Errno %d", errno); |
| } |
| for (x = 0 ; x < 1+(nbyte/sizeof(long)) ; x += sizeof(long)) |
| { |
| long ret; |
| ret = ptrace (PTRACE_PEEKDATA, pid, a + x , 0); |
| if (ret == -1) |
| { |
| printw("Errno %d", errno); |
| } |
| mem [ (x) / sizeof(long) ] = ret ; |
| } |
| |
| /* Restart process */ |
| if (ptrace (PTRACE_DETACH, pid, a, 0) == -1) |
| { |
| printw("Errno %d", errno); |
| } |
| |
| return (1); |
| } |
| #endif |
| |
| /* |
| * Plain old memory read. |
| */ |
| |
| if (lseek(memfd, a, SEEK_SET) != a || |
| read(memfd, (char *)mem, (unsigned) nbyte) != nbyte) |
| { |
| return 0 ; |
| } |
| |
| return 1 ; |
| |
| /* |
| * Return data in rw buffer. |
| */ |
| |
| rw_return: |
| if (rtncode) |
| { |
| memcpy((char *)mem, |
| (char *)&rw.rw_data[a-laddr], |
| nbyte) ; |
| } |
| |
| return rtncode; |
| } |
| |
| |
| /************************************************************************ |
| * showhelp - Show help if selected. |
| ************************************************************************/ |
| |
| void showhelp(index) |
| int index ; /* Help index */ |
| { |
| char *hp ; |
| |
| if (!helpflag) return ; |
| |
| hp = helptext[index] ; |
| |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| move(LINES-1, (COLS - strlen(hp)) / 2) ; |
| printw("%s", hp) ; |
| } |
| |
| |
| /************************************************************************ |
| * clearline - Clear the current line. |
| ************************************************************************/ |
| |
| void clearline() |
| { |
| register d_field *dp ; |
| register int i ; |
| |
| assert(frow <= crow && crow < frow + nrow) ; |
| |
| /* |
| * Show line number. |
| */ |
| |
| if (lrow != frow) |
| { |
| standend() ; |
| move(FROW(crow), 0) ; |
| printw("%3d| ", crow + 1) ; |
| } |
| |
| /* |
| * Clear remainder of line. |
| */ |
| |
| move(FROW(crow), FCOL(0)) ; |
| clrtoeol() ; |
| |
| /* |
| * Highlight the selected field. |
| */ |
| |
| if (irow == crow) |
| { |
| move(FROW(irow), FCOL(icol)) ; |
| standout() ; |
| printw(" ") ; |
| } |
| |
| /* |
| * Clear data fields this line. |
| */ |
| |
| dp = &DFIELD(crow, 1) ; |
| for (i = ncol ; --i >= 0 ;) |
| { |
| dp->d_type = 0 ; |
| dp->d_addr = 0 ; |
| dp++ ; |
| } |
| } |
| |
| |
| /************************************************************************ |
| * insertscreenline - shove everything down 'count' lines |
| * on the scereen |
| ************************************************************************/ |
| void |
| insertscreenline(int count) |
| { |
| int r; |
| a_field *ap ; |
| if (count == 0) count = 1 ; |
| |
| r = NADR ; |
| ap = &afield[NADR] ; |
| while (r > irow) |
| { |
| --ap ; |
| --r ; |
| |
| if (r >= NADR-count) strfree(ap[0].a_disp) ; |
| |
| if (r >= irow+count) |
| ap[0] = ap[-count] ; |
| else |
| { |
| ap[0].a_addr = 0 ; |
| ap[0].a_disp = 0 ; |
| ap[0].a_size = 0 ; |
| } |
| } |
| } |
| |
| |
| /************************************************************************ |
| * initline - Initialize a line prior to writing on it. |
| ************************************************************************/ |
| |
| void initline() |
| { |
| clearline() ; |
| |
| if (irow == crow && icol == 0) standout() ; |
| else standend() ; |
| |
| move(FROW(crow), FCOL(0)) ; |
| crow++ ; |
| |
| if (crow < NADR && afield[crow].a_disp) |
| { |
| erow = crow ; |
| |
| /* If it's an automatically growing field, and we are |
| * overlapping, shove everything down. Try to keep out |
| * cursor in the obvious place. |
| */ |
| if (afield[crow].a_grow) |
| { |
| int orig_irow = irow; |
| irow=crow; |
| insertscreenline(1); |
| irow = orig_irow; |
| } |
| } |
| } |
| |
| |
| /************************************************************************ |
| * setup - Setup next field. |
| ************************************************************************/ |
| |
| void setup() |
| { |
| /* |
| * At end-of-line, advance to the next line. |
| */ |
| |
| if (ocol == ncol) |
| { |
| orow++ ; |
| ocol = 0 ; |
| } |
| |
| /* |
| * Clear screen rows from the last position data was written |
| * to the current field position. Write the address of each |
| * line in the first field. Scale the address displayed by |
| * the scale factor (used when kme'ing things that aren't |
| * byte addressable, like DSPs). |
| */ |
| |
| while (crow <= orow && crow < erow) |
| { |
| initline() ; |
| printw("%06x", addr / addrscale) ; |
| } |
| |
| /* |
| * Position to the next field, and determine if it is |
| * on the screen. |
| */ |
| |
| ocol++ ; |
| |
| if (frow <= orow && orow < erow) |
| { |
| onscreen = 1 ; |
| |
| if (irow == orow && icol == ocol) standout() ; |
| else standend() ; |
| |
| move(FROW(orow), FCOL(ocol)) ; |
| } |
| else |
| { |
| onscreen = 0 ; |
| } |
| } |
| |
| |
| /************************************************************************ |
| * printchar - Unambiguously print character. |
| ************************************************************************/ |
| |
| void printchar(ch) |
| int ch ; |
| { |
| if (ch < 0x20) |
| printw("^%c", (ch & 0x1f) + 0x40) ; |
| else if (ch < 0x7f) |
| printw(" %c", ch) ; |
| else |
| printw("%02x", ch) ; |
| } |
| |
| |
| /************************************************************************ |
| * display - Display memory data. |
| ************************************************************************/ |
| |
| void display(fp) |
| register char *fp ; |
| { |
| register int ch ; |
| register int count ; |
| register int n ; |
| register int i ; |
| ulong a ; |
| int c ; |
| static char *endparen ; |
| int orig_swapflag = swapflag; |
| int orig_width = width; |
| int have_count; |
| |
| count = 0 ; |
| have_count = 0 ; |
| |
| while (ch = *fp++) |
| { |
| /* |
| * Get count field. |
| */ |
| |
| if ('0' <= ch && ch <= '9') |
| { |
| have_count = 1; |
| count *= 10 ; |
| count += ch - '0' ; |
| continue ; |
| } |
| |
| /* |
| * Process field type. |
| */ |
| |
| switch (ch) |
| { |
| /* |
| * Skip whitespace. |
| */ |
| |
| case ' ': |
| break ; |
| |
| /* |
| * Process parenthesized expression. |
| */ |
| |
| case '(': |
| for (;;) |
| { |
| ulong a = faddr; |
| faddr = addr; |
| display(fp); |
| faddr = a; |
| if (--count <= 0) break; |
| } |
| fp = endparen ; |
| break ; |
| |
| case ')': |
| endparen = fp ; |
| return ; |
| |
| /* |
| * Negate swapflag. This allows override on specific display |
| * elements endianness. |
| */ |
| |
| case '%': |
| swapflag ^= 1; |
| break; |
| |
| /* |
| * Process string field. |
| */ |
| |
| case '"': |
| case '\'': |
| { |
| int hilite = 0 ; |
| |
| setup() ; |
| |
| n = 0 ; |
| while (*fp) |
| { |
| /* |
| FP is in a very wierd format by this time. |
| Many things are already quoted for us. That's |
| why this is a little funny. |
| FIXME: you should be able to emit a \ in a string, |
| but you can't. You couldn't do it before I added |
| this either.... |
| */ |
| if (*fp == '\\') |
| { |
| switch (fp[1]) |
| { |
| |
| /* Implement only a simple toggle, no nesting */ |
| case 'h': |
| hilite ^= 1 ; |
| if (hilite) |
| standout(); |
| else |
| standend(); |
| fp ++ ; |
| break; |
| } |
| fp ++ ; |
| continue ; |
| } |
| |
| if (*fp == ch) |
| { |
| fp++ ; |
| break ; |
| } |
| |
| if (++n == 9) |
| { |
| setup() ; |
| /* setup may turn off our standout mode... */ |
| if (hilite) |
| standout(); |
| n = 1 ; |
| } |
| |
| if (onscreen) |
| addch((chtype) *fp) ; |
| |
| fp++ ; |
| } |
| } |
| break ; |
| |
| /* |
| * Position to memory relative address. |
| */ |
| |
| case '#': |
| addr = faddr + addrscale * count ; |
| break ; |
| |
| /* |
| * Save current address in temp variable. |
| */ |
| |
| case '$': |
| if ((unsigned)count < TEMP_MAX) temp[count] = addr; |
| break ; |
| |
| /* |
| * Set count from temp variable |
| */ |
| |
| case '*': |
| if ((unsigned)count >= TEMP_MAX) |
| break; |
| count = temp[count]; |
| have_count = 1; |
| continue; |
| |
| /* |
| * Save value at current address in a temp variables |
| */ |
| |
| case '&': |
| if ((unsigned)count >= TEMP_MAX) |
| break; |
| |
| if (!getmem(width)) |
| *(ulong *) mem = 0; |
| |
| switch (width) |
| { |
| case 1: temp[count] = *(uchar *) mem; break; |
| case 2: temp[count] = *(ushort *) mem; break; |
| case 4: temp[count] = *(ulong *) mem; break; |
| } |
| break; |
| |
| /* |
| * Set width parameter (Used by &, ^) |
| */ |
| |
| case '=': |
| width = count; |
| break; |
| |
| /* |
| * Roundup a value |
| */ |
| |
| case '^': |
| if ((unsigned)count >= TEMP_MAX) |
| break; |
| temp[count] = temp[count] + width - 1; |
| temp[count] /= width; |
| temp[count] *= width; |
| break; |
| |
| /* |
| * Set readahead max for remainder of this entry. |
| */ |
| |
| case ':': |
| rw_max = ((unsigned)(count - 1) < 128) ? count : 128 ; |
| break ; |
| |
| /* |
| * Skip memory forward. |
| */ |
| |
| case '+': |
| if (have_count == 0) count = 1 ; |
| addr += addrscale * count ; |
| break ; |
| |
| /* |
| * Skip memory reverse. |
| */ |
| |
| case '-': |
| if (have_count == 0) count = 1 ; |
| addr -= addrscale * count ; |
| break ; |
| |
| /* |
| * Blank field. |
| */ |
| |
| case '.': |
| do { |
| setup() ; |
| } while (--count > 0) ; |
| break ; |
| |
| /* |
| * Newline. |
| */ |
| |
| case 'n': |
| orow += count ? count : 1 ; |
| ocol = 0 ; |
| break ; |
| |
| /* |
| * String. |
| */ |
| |
| case 's': |
| do { |
| setup() ; |
| |
| n = count <= 8 ? count : 8 ; |
| |
| if (!getmem(n)) |
| { |
| if (onscreen) printw("????") ; |
| } |
| else if (onscreen) |
| { |
| for (i = 0 ; i < n ; i++) |
| { |
| c = ((uchar *)mem)[i] ; |
| if (c == 0) c = ' ' ; |
| else if (c < ' ' || c >= 0x7f) c = '.' ; |
| addch((chtype) c) ; |
| } |
| } |
| |
| count -= n ; |
| addr += n ; |
| } while (count > 0) ; |
| break ; |
| |
| /* |
| * Process numeric data fields. |
| */ |
| |
| case 'a': |
| case 'b': |
| case 'c': |
| case 'd': |
| case 'e': |
| case 'i': |
| case 'l': |
| case 't': |
| case 'u': |
| case 'x': |
| case 'z': |
| if (have_count && count == 0) |
| break; |
| for (;;) |
| { |
| setup() ; |
| |
| a = addr ; |
| |
| switch (ch) |
| { |
| |
| /* ASCII */ |
| |
| case 'a': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(uchar))) |
| printw("??") ; |
| else |
| { |
| printchar((int)*(uchar *)mem & 0x7f) ; |
| } |
| } |
| addr += sizeof(uchar) ; |
| break ; |
| |
| /* Hex byte */ |
| |
| case 'b': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(uchar))) |
| printw("??") ; |
| else |
| printw("%02x", *(uchar *)mem) ; |
| } |
| addr += sizeof(uchar) ; |
| break ; |
| |
| /* Character */ |
| |
| case 'c': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(uchar))) |
| printw("??") ; |
| else |
| { |
| printchar((int)*(uchar *)mem) ; |
| } |
| } |
| addr += sizeof(uchar) ; |
| break ; |
| |
| /* Signed decimal word */ |
| |
| case 'd': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(ushort))) |
| printw("????") ; |
| else |
| printw("%d", swaps(*(ushort *)mem)) ; |
| } |
| addr += sizeof(ushort) ; |
| break ; |
| |
| /* Decimal longword */ |
| |
| case 'e': |
| if (onscreen) |
| { |
| ulong mval; |
| if (!getmem(sizeof(ulong))) |
| printw("????????") ; |
| else |
| { |
| mval = swapl(*(ulong *)mem) ; |
| printw("%ld", mval % 10000000) ; |
| if (mval / 10000000) printw("+") ; |
| } |
| } |
| addr += sizeof(ulong) ; |
| break ; |
| |
| /* FEP input buffer */ |
| |
| case 'i': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(ushort))) |
| { |
| printw("?? ??") ; |
| } |
| else |
| { |
| printw("%02x ", *((uchar *)mem + 1)) ; |
| printchar((int)*(uchar *)mem & 0x7f) ; |
| } |
| } |
| addr += sizeof(ushort) ; |
| break ; |
| |
| /* HEX longword */ |
| |
| case 'l': |
| if (onscreen) |
| { |
| ulong mval; |
| if (!getmem(sizeof(ulong))) |
| printw("????????") ; |
| else |
| { |
| mval = swapl(*(ulong *)mem) ; |
| printw("%04lx", mval) ; |
| } |
| } |
| addr += sizeof(ulong) ; |
| break ; |
| |
| /* Unsigned decimal byte */ |
| |
| case 't': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(uchar))) |
| printw("????") ; |
| else |
| printw("%d", *(uchar *)mem) ; |
| } |
| addr += sizeof(uchar) ; |
| break ; |
| |
| /* Hex word */ |
| |
| case 'x': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(ushort))) |
| printw("????") ; |
| else |
| printw("%04x", swaps(*(ushort *)mem)) ; |
| } |
| addr += sizeof(ushort) ; |
| break ; |
| |
| /* Unsigned decimal word */ |
| |
| case 'u': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(short))) |
| printw("????") ; |
| else |
| { |
| printw("%d", swaps(*(ushort *)mem)) ; |
| } |
| } |
| addr += sizeof(short) ; |
| break ; |
| |
| /* Decimal longword */ |
| |
| case 'z': |
| if (onscreen) |
| { |
| if (!getmem(sizeof(ulong))) |
| printw("????????") ; |
| else |
| printw("%ld", swapl(*(ulong *)mem)) ; |
| } |
| addr += sizeof(ulong) ; |
| break ; |
| } |
| if (onscreen) |
| { |
| register d_field *dp ; |
| |
| dp = &DFIELD(orow, ocol) ; |
| dp->d_type = ch ; |
| dp->d_addr = a ; |
| } |
| |
| if (--count <= 0) break ; |
| } |
| break ; |
| |
| /* |
| * Accept '!' to mean what follows is a symbolic |
| * format name. Note: These do not recurse. |
| */ |
| case '!': |
| { |
| char fmt_label[200] ; |
| char *flp = fmt_label ; |
| int x ; |
| |
| /* Build null terminated fmt_label */ |
| for (;isalnum(*fp) || (*fp == '_'); *flp++=*fp++); |
| *flp = 0 ; |
| |
| /* |
| * If this is a legal format, display it, |
| * respect repeat counts. |
| */ |
| if ((x = find_format(fmt_label)) >= 0) |
| { |
| do { |
| if (dfmt[x].format) |
| display(dfmt[x].format); |
| else |
| { |
| char *fmt; |
| |
| fmt = (*dfmt[x].dlfunc)(&addr, dfmt[x].dlarg); |
| if (fmt) |
| display(fmt); |
| } |
| } while (--count > 0) ; |
| |
| } |
| else if (onscreen) |
| { |
| setup() ; |
| printw("??Count:%d Format Label \"%s\" unknown", count, fmt_label) ; |
| } |
| } |
| break ; |
| |
| /* |
| * Handle macro defines & undefined characters. |
| * |
| * If we hit a recursion depth of 10, assume |
| * we are in a recursive loop. Show an error |
| * backtrace and exit. |
| */ |
| |
| default: |
| if (isupper(ch) && format[ch - 'A']) |
| { |
| depth++ ; |
| |
| if (depth < 10) |
| { |
| do { |
| display(format[ch - 'A']) ; |
| } while (--count > 0) ; |
| } |
| |
| if (depth >= 10) |
| { |
| if (onscreen) |
| { |
| setup() ; |
| printw("**** %c", ch) ; |
| } |
| endparen = "" ; |
| return ; |
| } |
| |
| depth-- ; |
| } |
| else if (onscreen) |
| { |
| setup() ; |
| printw("?%d%c", count, ch) ; |
| } |
| } |
| |
| count = 0 ; |
| have_count = 0; |
| } |
| |
| swapflag = orig_swapflag; |
| width = orig_width; |
| |
| endparen = "" ; |
| } |
| |
| |
| /************************************************************************ |
| * inbase - Input base address. |
| ************************************************************************/ |
| |
| int |
| inbase(buf) |
| char *buf ; |
| { |
| return getbase(buf, &base, 16) != 0 ; |
| } |
| |
| |
| /************************************************************************ |
| * getvalue - Get numeric or symbol value when parsing expressions. |
| ************************************************************************/ |
| |
| ulong |
| getname() |
| { |
| register SYM *sp ; |
| register char *d ; |
| register char *s ; |
| char name[100] ; |
| ulong value ; |
| |
| s = str ; |
| |
| if (*s < '0' || *s > '9') |
| { |
| d = name ; |
| |
| while(d < name + sizeof(name) - 1 && |
| (isalnum(*s) || *s == '_')) |
| *d++ = *s++ ; |
| |
| *d = 0 ; |
| |
| if (d != name) |
| { |
| sp = *hashname(name) ; |
| |
| #if HAVE_GETKSYM |
| /* |
| On UnixWare, give getksym a shot at it before nlist. |
| This allows symbol detection in dynamically loaded mods. |
| FIXME: If you suspect this code could benefit from greater |
| commonality with the NLIST case (or even better, a better |
| abstraction of the symbol table groper) you would be right. |
| */ |
| |
| if (!sp) |
| { |
| /* |
| Must not be in the hash table, let's |
| look it up, then add it . |
| */ |
| |
| register SYM **spp = hashname(name) ; |
| long info; |
| long value = 0; |
| int n; |
| |
| if (debug) |
| printw("Looking up `%s' ", name); |
| if (getksym(name, &value, &info)) |
| goto try_nlist; |
| |
| /* |
| This mess is blatantly plagarized from elsewhere in |
| the code. Sure wish I understood it.... |
| */ |
| n = (unsigned)&((SYM*)0)->s_name[strlen(name)+1] ; |
| if (debug) |
| printw("n is %d\n", n); |
| sp = (SYM*)malloc(n) ; |
| if (sp == 0) |
| { |
| fprintf(stderr, "Out of memory") ; |
| exit(1) ; |
| } |
| sp->s_next = *spp ; |
| *spp = sp ; |
| sp->s_value = value & addr_mask; |
| |
| strcpy(sp->s_name, name) ; |
| if (debug) |
| { |
| fprintf(stderr, "Added Symbol %s = %lx\n", |
| sp->s_name, sp->s_value) ; |
| } |
| /* |
| Tell the parser if we found it, by advancing str |
| and returning the value. |
| */ |
| str = s ; |
| return(sp->s_value); |
| } |
| try_nlist: |
| #endif |
| |
| #if HAVE_NLIST |
| if (!sp) |
| { |
| /* |
| Must not be in the hash table, let's |
| look it up, then add it . |
| */ |
| |
| register SYM **spp = hashname(name) ; |
| int n ; |
| struct nlist nlist_tbl[2]; |
| |
| if (debug) |
| printw("Looking up %s\n", name); |
| |
| /* |
| Nlist can (efficiently) look up multiple symbols |
| in one shot. We don't take advantage of this, but |
| we do attempt to look it up only once.... |
| So, nlist_tbl[0] becomes what we're interested in, |
| next comes the null terminator.... |
| */ |
| nlist_tbl[0].n_name = name; |
| nlist_tbl[1].n_name = NULL; |
| nlist(symname, nlist_tbl); |
| if (!nlist_tbl[0].n_value) |
| { |
| /* Even though it's not a symbol, it could still |
| be a number - probably hex . */ |
| goto might_be_a_num; |
| } |
| |
| /* |
| This mess is blatantly plagarized from elsewhere in |
| the code. Sure wish I understood it.... |
| */ |
| n = (unsigned)&((SYM*)0)->s_name[strlen(name)+1] ; |
| sp = (SYM*)malloc(n) ; |
| if (sp == 0) |
| { |
| fprintf(stderr, "Out of memory") ; |
| exit(1) ; |
| } |
| sp->s_next = *spp ; |
| *spp = sp ; |
| sp->s_value = nlist_tbl[0].n_value & addr_mask ; |
| strcpy(sp->s_name, name) ; |
| if (debug) |
| { |
| fprintf(stderr, "Added Symbol %s = %lx\n", |
| sp->s_name, sp->s_value) ; |
| } |
| /* |
| Tell the parser if we found it, by advancing str |
| and returning the value. |
| */ |
| str = s ; |
| return(sp->s_value); |
| } |
| might_be_a_num: |
| #endif |
| while (sp) |
| { |
| if (strcmp(name, sp->s_name) == 0) |
| { |
| str = s ; |
| return(sp->s_value) ; |
| } |
| sp = sp->s_next ; |
| } |
| } |
| } |
| |
| s = getbase(str, &value, ebase) ; |
| |
| if (s == 0 || isalpha(*s) || *s == '_') longjmp(efail, 1) ; |
| |
| str = s ; |
| |
| return(value) ; |
| } |
| |
| |
| /************************************************************************ |
| * expr - Parse expression by recursive descent. |
| ************************************************************************/ |
| |
| long |
| expr(pri) |
| int pri ; |
| { |
| long v, v1, v2 ; |
| |
| /* |
| * Handle UNARY prefix operations. |
| */ |
| |
| while (*++str == ' ') ; |
| |
| switch (*str) |
| { |
| case '-': |
| v = -expr(10) ; |
| break ; |
| |
| case '+': |
| v = expr(10) ; |
| break ; |
| |
| case '~': |
| v = ~expr(10) ; |
| break ; |
| |
| case '*': |
| addr = expr(10) & addr_mask ; |
| if (!getmem(sizeof(ulong))) goto fail ; |
| v = swapl(*(ulong *)mem) ; |
| break ; |
| |
| case '@': |
| addr = expr(10) & addr_mask ; |
| if (!getmem(sizeof(ushort))) goto fail ; |
| v = swaps(*(ushort *)mem) ; |
| break ; |
| |
| case '#': |
| addr = expr(10) & addr_mask ; |
| if (!getmem(sizeof(uchar))) goto fail ; |
| v = *(uchar *)mem ; |
| break ; |
| |
| case '$': |
| v = expr(10); |
| if ((unsigned)v >= TEMP_MAX) goto fail ; |
| v = temp[v]; |
| break; |
| |
| case '(': |
| inparen++ ; |
| v = expr(0) ; |
| inparen-- ; |
| if (*str != ')') goto fail ; |
| str++ ; |
| break ; |
| |
| /* |
| * Unary Override endianness on long. |
| */ |
| |
| case '%': |
| v = always_swapl(expr(10)); |
| break; |
| |
| /* |
| * Unary Override endianness on short. |
| */ |
| |
| case '^': |
| v = always_swaps(expr(10)); |
| break; |
| |
| |
| /* |
| * Unary extended operators |
| */ |
| case '<': |
| if (0) |
| {} |
| else if (strncmp(str, "<be32>", 6) == 0) |
| { |
| str += 5; |
| v = bigendian() ? expr(10) : always_swapl(expr(10)); |
| } |
| else if (strncmp(str, "<le32>", 6) == 0) |
| { |
| str += 5; |
| v = !bigendian() ? expr(10) : always_swapl(expr(10)); |
| } |
| else if (strncmp(str, "<be16>", 6) == 0) |
| { |
| str += 5; |
| v = bigendian() ? expr(10) : always_swaps(expr(10)); |
| } |
| else if (strncmp(str, "<le16>", 6) == 0) |
| { |
| str += 5; |
| v = !bigendian() ? expr(10) : always_swaps(expr(10)); |
| } |
| else |
| goto fail; |
| break; |
| |
| default: |
| v = getname() ; |
| } |
| |
| /* |
| * Handle BINARY operators. |
| */ |
| |
| for (;;) |
| { |
| switch(*str) |
| { |
| case ' ': |
| str++ ; |
| break ; |
| |
| case '?': |
| if (pri > 1) goto rtn ; |
| v1 = expr(0) ; |
| if (*str != ':') goto fail ; |
| v2 = expr(1) ; |
| v = v ? v1 : v2 ; |
| break ; |
| |
| case '|': |
| if (pri >= 2) goto rtn ; |
| v |= expr(2) ; |
| break ; |
| |
| case '^': |
| if (pri >= 3) goto rtn ; |
| v ^= expr(3) ; |
| break ; |
| |
| case '&': |
| if (pri >= 4) goto rtn ; |
| v &= expr(4) ; |
| break ; |
| |
| case '!': |
| if (str[1] == '=') |
| { |
| str++ ; |
| if (pri >= 5) goto rtn ; |
| v = v != expr(5) ; |
| } |
| else |
| goto fail; |
| break ; |
| |
| case '=': |
| if (str[1] == '=') |
| { |
| str++ ; |
| if (pri >= 5) goto rtn ; |
| v = v == expr(5) ; |
| } |
| else |
| goto fail; |
| break ; |
| |
| case '>': |
| if (str[1] == '>') |
| { |
| str++ ; |
| if (pri >= 7) goto rtn ; |
| v = v >= expr(7) ; |
| } |
| else if (str[1] == '=') |
| { |
| str++ ; |
| if (pri >= 6) goto rtn ; |
| v = v >= expr(6) ; |
| } |
| else |
| { |
| if (pri >= 6) goto rtn ; |
| v = v > expr(6) ; |
| } |
| break ; |
| |
| case '<': |
| if (str[1] == '<') |
| { |
| str++ ; |
| if (pri >= 7) goto rtn ; |
| v = v << expr(7) ; |
| } |
| else if (str[1] == '=') |
| { |
| str++ ; |
| if (pri >= 6) goto rtn ; |
| v = v <= expr(6) ; |
| } |
| else |
| { |
| if (pri >= 6) goto rtn ; |
| v = v < expr(6) ; |
| } |
| break ; |
| |
| case '+': |
| if (pri >= 8) goto rtn ; |
| v += expr(8) ; |
| break ; |
| |
| case '-': |
| if (pri >= 8) goto rtn ; |
| v -= expr(8) ; |
| break ; |
| |
| case '*': |
| if (pri >= 9) goto rtn ; |
| v *= expr(9) ; |
| break ; |
| |
| case '/': |
| if (pri >= 9 || !inparen) goto rtn ; |
| v /= expr(9) ; |
| break ; |
| |
| case '%': |
| if (pri >= 9) goto rtn ; |
| v %= expr(9) ; |
| break ; |
| |
| case '.': |
| v += expr(10) ; |
| break ; |
| |
| case '[': |
| inparen++ ; |
| v += expr(0) ; |
| inparen-- ; |
| if (*str != ']') goto fail ; |
| str++ ; |
| addr = v & addr_mask ; |
| if (!getmem(sizeof(ulong))) goto fail ; |
| v = swapl(*(ulong *)mem) ; |
| break ; |
| |
| case '{': |
| inparen++ ; |
| v += expr(0) ; |
| inparen-- ; |
| if (*str != '}') goto fail ; |
| str++ ; |
| addr = v & addr_mask ; |
| if (!getmem(sizeof(ushort))) goto fail ; |
| v = swaps(*(ushort *)mem) ; |
| break ; |
| |
| case ':': |
| case ')': |
| case ']': |
| case '}': |
| goto rtn ; |
| |
| case 0: |
| goto rtn ; |
| |
| default: |
| goto fail ; |
| } |
| } |
| |
| fail: |
| longjmp(efail, 1) ; |
| |
| rtn: |
| return(v) ; |
| } |
| |
| |
| /************************************************************************ |
| * inaddr - Read address string from keyboard. |
| ************************************************************************/ |
| |
| int |
| inaddr(buf) |
| char *buf ; /* Format to crack */ |
| { |
| register a_field *ap ; |
| |
| ap = &afield[irow] ; |
| |
| ap->a_addr = 0 ; |
| |
| /* |
| * An empty field deletes the entry. |
| */ |
| |
| if (*buf == 0) |
| { |
| strfree(ap->a_disp) ; |
| ap->a_disp = 0 ; |
| return(1) ; |
| } |
| |
| strfree(ap->a_disp) ; |
| |
| ap->a_disp = stralloc(buf) ; |
| |
| if (debug) |
| fprintf(stderr, "Input %d, %s\n", |
| irow+1, ap->a_disp ? ap->a_disp : "null") ; |
| |
| return(1) ; |
| } |
| |
| |
| |
| /************************************************************************ |
| * inparam - Input command parameter. |
| ************************************************************************/ |
| |
| int |
| inparam(buf) |
| char *buf ; |
| { |
| int cmd ; |
| |
| /* |
| * Handle define parameter. |
| */ |
| |
| if (isupper(*buf)) |
| { |
| cmd = *buf++ - 'A' ; |
| if (*buf == '=') buf++ ; |
| strfree(format[cmd]) ; |
| format[cmd] = stralloc(buf) ; |
| keyformat[cmd] = 1 ; |
| |
| if (debug) fprintf(stderr, |
| "Defined %c = %s\n", cmd + 'A', buf) ; |
| return(1) ; |
| } |
| |
| /* |
| * Handle line=display parameter. |
| */ |
| |
| irow = 0 ; |
| while (isdigit(*buf)) |
| { |
| irow = 10 * irow + *buf++ - '0' ; |
| } |
| |
| if (*buf++ != '=') return(0) ; |
| |
| if (irow == 0 && irow < NADR) |
| { |
| irow = ++initial_display_row; |
| afield[irow].a_grow = 1 ; |
| } |
| |
| if (--irow < 0 || irow >= NADR) return(0) ; |
| |
| |
| return(inaddr(buf)) ; |
| } |
| |
| |
| /************************************************************************ |
| * indata - Input data. |
| ************************************************************************/ |
| |
| int |
| indata(buf) |
| char *buf ; |
| { |
| register ulong v ; |
| register int size ; |
| register d_field *dp ; |
| long a; |
| |
| /* |
| * Setup call to expression input routine. |
| */ |
| |
| if (setjmp(efail)) |
| return(0) ; |
| |
| str = buf - 1 ; |
| inparen = 1 ; |
| |
| dp = &DFIELD(irow, icol) ; |
| |
| switch (dp->d_type) |
| { |
| case 'd' : |
| case 'e' : |
| case 't' : |
| case 'u' : |
| case 'z' : |
| ebase = 10 ; |
| break ; |
| |
| default: |
| ebase = 16 ; |
| break ; |
| } |
| |
| v = expr(0) ; |
| |
| if (*str != 0) return(0) ; |
| |
| switch (dp->d_type) |
| { |
| case 'a': |
| case 'b': |
| case 'c': |
| case 't': |
| size = sizeof(uchar) ; |
| *(uchar *)mem = v ; |
| break ; |
| |
| case 'd': |
| case 'i': |
| case 'x': |
| case 's': |
| size = sizeof(ushort) ; |
| *(ushort *)mem = swaps((ushort)v) ; |
| break ; |
| |
| case 'e': |
| case 'l': |
| case 'z': |
| size = sizeof(ulong) ; |
| *(ulong *)mem = swapl(v) ; |
| break ; |
| |
| default: |
| return(0) ; |
| } |
| |
| a = dp->d_addr + base; |
| |
| #if HAVE_STROPTS_H |
| if (fepdev && strdev) |
| { |
| static rw_t rw ; |
| register a_field *ap ; |
| struct strioctl stio; |
| |
| rw.rw_req = RW_WRITE ; |
| rw.rw_size = size ; |
| |
| for (ap = &afield[irow] ; ap->a_disp == 0 ; --ap) {} |
| |
| if (isalnum(ap->a_disp[0]) && |
| isalnum(ap->a_disp[1]) && |
| ap->a_disp[2] == ':') |
| { |
| rw.rw_board = getdigit(ap->a_disp[0]) ; |
| rw.rw_conc = getdigit(ap->a_disp[1]) ; |
| rw.rw_addr = a ; |
| } |
| else if |
| (isalnum(ap->a_disp[0]) && |
| ap->a_disp[1] == ':') |
| { |
| rw.rw_board = getdigit(ap->a_disp[0]) ; |
| rw.rw_conc = 0 ; |
| rw.rw_addr = a ; |
| } |
| else |
| { |
| rw.rw_board = def_board ; |
| rw.rw_conc = def_conc ; |
| rw.rw_addr = a ; |
| } |
| |
| memcpy((char *)rw.rw_data, (char *)mem, size) ; |
| |
| stio.ic_cmd = DIGI_KME; |
| stio.ic_timout = 0; |
| stio.ic_len = sizeof(rw); |
| stio.ic_dp = (char *) &rw; |
| |
| if (ioctl(fepfd, I_STR, (char *)&stio) == -1 || |
| rw.rw_size != size) |
| return(0) ; |
| |
| return(1) ; |
| } |
| #endif /* HAVE_STROPTS_H */ |
| |
| /* |
| * Write using DigiBoard special device driver hooks. |
| */ |
| |
| if (fepdev) |
| { |
| static rw_t rw ; |
| register a_field *ap ; |
| |
| rw.rw_req = RW_WRITE ; |
| rw.rw_size = size ; |
| |
| for (ap = &afield[irow] ; ap->a_disp == 0 ; --ap) {} |
| |
| if (isalnum(ap->a_disp[0]) && |
| isalnum(ap->a_disp[1]) && |
| ap->a_disp[2] == ':') |
| { |
| rw.rw_board = getdigit(ap->a_disp[0]) ; |
| rw.rw_conc = getdigit(ap->a_disp[1]) ; |
| rw.rw_addr = a ; |
| } |
| else if |
| (isalnum(ap->a_disp[0]) && |
| ap->a_disp[1] == ':') |
| { |
| rw.rw_board = getdigit(ap->a_disp[0]) ; |
| rw.rw_conc = 0 ; |
| rw.rw_addr = a ; |
| } |
| else |
| { |
| rw.rw_board = def_board ; |
| rw.rw_conc = def_conc ; |
| rw.rw_addr = a ; |
| } |
| |
| memcpy((char *)rw.rw_data, (char *)mem, size) ; |
| |
| if (ioctl(fepfd, DIGI_KME, (char *)&rw) == -1 || |
| rw.rw_size != size) |
| return(0) ; |
| |
| return(1) ; |
| } |
| |
| #if HAVE_SOCKET |
| /* |
| * Write using DigiBoard special device driver hooks. |
| */ |
| |
| if (nsoc) |
| { |
| int fd ; |
| int rtry ; |
| int wtry ; |
| rw_t w ; |
| struct timeval tv ; |
| |
| static fd_set fdn ; |
| static fd_set fdr ; |
| static rw_t r ; |
| register a_field *ap ; |
| |
| if (ov_board >= nsoc) return(0) ; |
| |
| /* |
| * Build the request packet. |
| */ |
| |
| w.rw_req = RW_WRITE ; |
| w.rw_size = size ; |
| |
| for (ap = &afield[irow] ; ap->a_disp == 0 ; --ap) {} |
| |
| if (isalnum(ap->a_disp[0]) && |
| isalnum(ap->a_disp[1]) && |
| ap->a_disp[2] == ':') |
| { |
| w.rw_board = getdigit(ap->a_disp[0]) ; |
| w.rw_conc = getdigit(ap->a_disp[1]) ; |
| w.rw_addr = a ; |
| } |
| else if |
| (isalnum(ap->a_disp[0]) && |
| ap->a_disp[1] == ':') |
| { |
| w.rw_board = getdigit(ap->a_disp[0]) ; |
| w.rw_conc = 0 ; |
| w.rw_addr = a ; |
| } |
| else |
| { |
| w.rw_board = def_board ; |
| w.rw_conc = def_conc ; |
| w.rw_addr = a ; |
| } |
| |
| w.rw_size = swaps(w.rw_size) ; |
| w.rw_addr = swapl(w.rw_addr) ; |
| |
| memcpy((char *)w.rw_data, (char *)mem, size) ; |
| |
| /* |
| * Repeatedly request the data with UDP until |
| * a response is heard from the remote. |
| */ |
| |
| fd = socfd[w.rw_board] ; |
| |
| for (wtry = 0 ; wtry < 1 ; wtry++) |
| { |
| write(fd, (char *)&w, RW_PAKLEN) ; |
| |
| /* |
| * Wait for the response packet. |
| */ |
| |
| for (rtry = 0 ; rtry < 3 ; rtry++) |
| { |
| FD_ZERO(&fdr) ; |
| FD_SET(fd, &fdr) ; |
| |
| tv.tv_sec = 2 ; |
| tv.tv_usec = 0 ; |
| |
| if (select(FD_SETSIZE, &fdr, &fdn, &fdn, &tv) < 1) |
| break ; |
| |
| /* |
| * On response from the correct file descriptor, |
| * with the response we expect, accept the response. |
| * |
| * Note that it is possible to get an irrelevant |
| * response if on a previous request, the network |
| * delays exceeded our simplistic 2 second timeout. |
| */ |
| |
| if (FD_ISSET(fd, &fdr) && |
| read(fd, (char *)&r, RW_PAKLEN) == RW_PAKLEN && |
| r.rw_req == w.rw_req && |
| r.rw_board == w.rw_board && |
| r.rw_conc == w.rw_conc && |
| r.rw_addr == w.rw_addr && |
| r.rw_size == w.rw_size) |
| { |
| return(1) ; |
| } |
| } |
| } |
| |
| return(0) ; |
| } |
| #endif |
| |
| #if USE_HP_ANALYZER |
| /* |
| * Write to HP emulator device. |
| */ |
| |
| if (emdev) |
| { |
| int i ; |
| |
| fprintf(emout, "m -d%c %x=", "0bw3d"[size], a) ; |
| |
| for (i = 0 ; i < size ; i++) |
| { |
| fprintf(emout, "%02x", ((char *)mem)[i]) ; |
| } |
| |
| fputc('\r', emout) ; |
| fflush(emout) ; |
| |
| clearerr(emin) ; |
| |
| do clearerr(emin) ; while (fgetc(emin) != EOF) ; |
| |
| return(1) ; |
| } |
| #endif |
| |
| #if HAVE_MMAP |
| if (memlen) |
| { |
| char *addr = memva + a; |
| |
| switch (size) |
| { |
| case 1: |
| *(char *) addr = *(char *) mem; |
| break; |
| case 2: |
| if (ALIGNED(addr,2) && ALIGNED(mem,2)) |
| *(short *) addr = *(short *) mem; |
| else |
| memcpy(addr, (char *) mem, (unsigned) size); |
| break; |
| case 4: |
| if (ALIGNED(addr,4) && ALIGNED(mem,4)) |
| *(long *) addr = *(long *) mem; |
| else |
| memcpy(addr, (char *) mem, (unsigned) size); |
| break; |
| default: |
| memcpy(addr, (char *) mem, (unsigned) size); |
| break; |
| } |
| return (1); |
| } |
| #endif |
| |
| #if HAVE_PTRACE |
| if (pid) |
| { |
| /* |
| This section is really hurt by gene's affinity for making |
| buffers (like mem) out of longs when they really are char |
| buffers....Since ptrace wants to deal with *words*, we |
| have to deal with cases like when the user wants to modify |
| single byte....Read it all in, modify only the bottom |
| byte, write it all out. Fortunately, memory changes happen |
| rarely in normal KME use (since they come from the keyboard). |
| */ |
| |
| char *cm = (char *) mem ; |
| long ret; |
| |
| /* Attach to process, and stop it */ |
| ptrace (PTRACE_ATTACH, pid, a, 0) ; |
| |
| /* Read the *word*. We may need to modify one or more |
| bytes in this word. */ |
| |
| /* HAZARD: I'm not at all convinced this will do the right |
| * thing on cross-endian cases. I'm also cant think why you'd |
| * be running ptrace on a different process than KME itself. */ |
| |
| ret = ptrace (PTRACE_PEEKDATA, pid, a, 0); |
| switch (size) |
| { |
| case 1: |
| *(char *)&ret = *(char *)cm ; |
| case 2: |
| *(short *)&ret = *(short *)cm; |
| case 4: |
| ret = *(int *) cm; |
| |
| /* Why are we called to modify zero bytes? */ |
| case 0: |
| break ; |
| |
| /* Aaaagh! */ |
| default: |
| abort(); |
| } |
| |
| /* Write modified data to target address space */ |
| ret = ptrace (PTRACE_POKEDATA, pid, a, ret); |
| |
| ptrace (PTRACE_DETACH, pid, addr, 0) ; /* Restart process */ |
| return (1); |
| } |
| #endif |
| |
| /* |
| * Write to memory device. |
| */ |
| |
| if (lseek(memfd, a, SEEK_SET) != a || |
| write(memfd, (char *)mem, (unsigned) size) != size) |
| { |
| return(0) ; |
| } |
| |
| if (debug) |
| fprintf(stderr, |
| "Wrote %lx to %lx (%d bytes)\n", |
| v, a, size) ; |
| |
| return(1) ; |
| } |
| |
| |
| /************************************************************************ |
| * inshell - Input shell. |
| ************************************************************************/ |
| |
| int |
| inshell(buf) |
| char *buf ; |
| { |
| register int i ; |
| register char *sh ; |
| register int pid ; |
| int status ; |
| void (*sig[3])() ; |
| |
| if (debug) fprintf(stderr, "executing: %s\n", buf) ; |
| |
| move(LINES-1, 0) ; |
| refresh() ; |
| |
| #if OLDCURSE |
| ioctl(0, TCSETA, &otio) ; |
| #else |
| reset_shell_mode() ; |
| #endif |
| |
| putchar('\n') ; |
| fflush(stdout) ; |
| |
| /* |
| * Fork off a child process to become the shell. |
| * If we have problems getting a process, keep |
| * trying. |
| */ |
| |
| sigint = 0 ; |
| |
| while ((pid = fork()) == -1) |
| { |
| if (sigint) |
| { |
| fprintf(stderr, "Couldn't fork!") ; |
| sleep(2) ; |
| goto done ; |
| } |
| sleep(1) ; |
| } |
| |
| /* |
| * With the child process, execute a shell. |
| */ |
| |
| if (pid == 0) |
| { |
| for (i = 3 ; i < 10 ; i++) close(i) ; |
| |
| sh = getenv("SHELL") ; |
| if (sh == 0) sh = "/bin/sh" ; |
| execl(sh, "sh", "-c", buf, (char *)0) ; |
| |
| perror(sh) ; |
| exit(0xff) ; |
| } |
| |
| /* |
| * Execute the command. |
| */ |
| |
| sig[0] = signal(SIGINT, SIG_IGN) ; |
| sig[1] = signal(SIGQUIT, SIG_IGN) ; |
| sig[2] = signal(SIGTERM, SIG_IGN) ; |
| |
| while (wait(&status) != pid) ; |
| |
| signal(SIGINT, sig[0]) ; |
| signal(SIGQUIT, sig[1]) ; |
| signal(SIGTERM, sig[2]) ; |
| |
| /* |
| * Restore tty modes. |
| */ |
| |
| done: |
| fputc('\r', stdout) ; |
| fflush(stdout) ; |
| |
| #if OLDCURSE |
| tio.c_cc[VMIN] = 1 ; |
| tio.c_cc[VTIME] = 0 ; |
| ioctl(0, TCSETAW, &tio) ; |
| #else |
| reset_prog_mode() ; |
| #endif |
| |
| clrtoeol() ; |
| standout() ; |
| addstr("[Hit return to continue] ") ; |
| standend() ; |
| refresh() ; |
| |
| readch() ; |
| |
| clearok(stdscr, 1) ; |
| |
| return(1) ; |
| } |
| |
| |
| /************************************************************************ |
| * inprint - Input print file name, and save screen |
| ************************************************************************/ |
| |
| static char last_print[80] = "| lpr"; /* A good default */ |
| |
| int |
| inprint(buf) |
| char *buf ; |
| { |
| register FILE *file ; |
| int oldx, oldy; |
| int x, y, cols; |
| int pipe = 0; |
| int append = 0; |
| char *obuf = buf; |
| |
| /* |
| * Parse filename for append and pipe options |
| */ |
| if (buf[0] == '|') |
| { |
| pipe = 1; |
| ++buf; |
| } |
| else if (buf[0] == '>') |
| { |
| ++buf; |
| if (buf[0] == '>') |
| { |
| ++buf; |
| append = 1; |
| } |
| } |
| |
| while (*buf == ' ' || *buf == '\t') ++buf; |
| if (*buf == 0) return; |
| |
| /* |
| * Open output file or pipe. |
| */ |
| if (pipe) |
| file = popen(buf, "w"); |
| else |
| file = fopen(buf, append ? "a" : "w"); |
| if (!file) return (0); |
| |
| strncpy(last_print, obuf, sizeof(last_print) -1); |
| |
| getyx(stdscr, oldy, oldx); |
| |
| /* |
| * Print the screen |
| */ |
| for (y = 0; y < LINES-1; ++y) |
| { |
| for (cols = COLS-1; cols; --cols) |
| if ((mvinch(y, cols) & A_CHARTEXT) != ' ') |
| break; |
| ++cols; |
| for (x = 0; x < cols; ++x) |
| fputc(mvinch(y, x) & A_CHARTEXT, file); |
| fputc('\n', file); |
| } |
| |
| move(oldy, oldx); |
| |
| if (pipe) |
| return(pclose(file) == 0) ; |
| else |
| return(fclose(file) == 0) ; |
| } |
| |
| |
| /************************************************************************ |
| * insave - Input save file name, and save user-entered |
| * stuff into a command file. |
| ************************************************************************/ |
| |
| static last_saved[80]; /* So we can edit later */ |
| |
| int insave(buf) |
| char *buf ; |
| { |
| register FILE *file ; |
| register a_field *ap ; |
| register int ch ; |
| register int i ; |
| register char *s ; |
| |
| /* |
| * Open output file. |
| */ |
| |
| i = open(buf, O_WRONLY|O_CREAT|O_TRUNC, 0777) ; |
| |
| if (i == -1) |
| return(0) ; |
| |
| file = fdopen(i, "w") ; |
| if (file == 0) |
| return(0) ; |
| |
| strncpy((char *)last_saved, buf, sizeof(last_saved) -1); |
| |
| /* |
| * Output command name and options. |
| */ |
| |
| fprintf(file, "exec %s", progname) ; |
| |
| if (!addrflag) |
| fprintf(file, " -a") ; |
| |
| if (base) |
| fprintf(file, " -b %lx", base) ; |
| |
| #if HAVE_MMAP |
| if (memlen) |
| fprintf(file, " -M 0x%lx:0x%lx", mempa, memlen) ; |
| #endif |
| |
| if (coredev) |
| fprintf(file, " -c %s", coredev) ; |
| |
| #if USE_HP_ANALYZER |
| if (emdev) |
| fprintf(file, " -e %s", emdev) ; |
| #endif |
| |
| if (fepdev) |
| fprintf(file, " -f %s", fepdev) ; |
| |
| if (helpflag) |
| fprintf(file, " -h") ; |
| |
| if (idline) |
| fprintf(file, " -i") ; |
| |
| if (def_board || def_conc) |
| { |
| fprintf(file, " -k %c", hexnum[def_board]) ; |
| if (def_conc) fprintf(file, "%c", hexnum[def_conc]) ; |
| } |
| |
| #if HAVE_SOCKET |
| if (hostname) |
| { |
| fprintf(file, " -m %s", hostname) ; |
| } |
| #endif |
| |
| if (symparam) |
| fprintf(file, " -n %s", symparam) ; |
| |
| if (frow) |
| fprintf(file," -p %d", frow + 1) ; |
| |
| if (writeflag == 0) |
| fprintf(file, " -r") ; |
| |
| if (swapflag) |
| fprintf(file, " -s") ; |
| |
| if (addr_mask != -1) |
| fprintf(file, " -S 0x%lx", addr_mask) ; |
| |
| if (!index_mode) |
| fprintf(file, " -t") ; |
| |
| if (uptime != 2) |
| fprintf(file, " -u %d", uptime) ; |
| |
| fprintf(file, " $*") ; |
| |
| /* |
| * Output keyboard entered defines. |
| */ |
| |
| for (i = 0 ; i < 26 ; i++) |
| { |
| if (keyformat[i] && (s = format[i])) |
| { |
| fprintf(file, " %c=", i + 'A') ; |
| while ((ch = *s++)) |
| { |
| if (!isalnum(ch)) fputc('\\', file) ; |
| fputc(ch, file) ; |
| } |
| } |
| } |
| |
| /* |
| * Output field defines. |
| */ |
| |
| ap = &afield[0] ; |
| for (i = 0 ; i < NADR ; i++) |
| { |
| if (ap->a_disp) |
| { |
| fprintf(file, " %d=", i+1) ; |
| |
| for (s = ap->a_disp ; (ch = *s++) ;) |
| { |
| if (!isalnum(ch)) fputc('\\', file) ; |
| fputc(ch, file) ; |
| } |
| } |
| ap++ ; |
| } |
| |
| fputc('\n', file) ; |
| |
| return(fclose(file) == 0) ; |
| } |
| |
| |
| /************************************************************************ |
| * inuptime - Input update time. |
| ************************************************************************/ |
| |
| int |
| inuptime(buf) |
| char *buf ; |
| { |
| int u ; |
| |
| if (sscanf(buf, "%d", &u) != 1) |
| return(0) ; |
| |
| uptime = u ; |
| |
| return(1) ; |
| } |
| |
| |
| /************************************************************************ |
| * insearch - Input search string. |
| * |
| * NOTE: full semantics of / not yet implemented. This |
| * version doesn't search format text, nor does it do REs. |
| ************************************************************************/ |
| |
| static char last_search[80]; |
| int search_dir; |
| |
| insearch(buf) |
| char *buf; |
| { |
| int i, r; |
| a_field *ap; |
| char *p; |
| |
| strncpy((char *)last_search, buf, sizeof(last_search) - 1); |
| |
| r = irow + search_dir; |
| for (i = 0; i < NADR; ++i, r += search_dir) |
| { |
| if (r == NADR) |
| r = 0; |
| if (r < 0) |
| r = NADR - 1; |
| |
| ap = &afield[r]; |
| |
| if (!ap->a_disp) |
| continue; |
| |
| /* |
| * Search in address expression and top level format |
| */ |
| if (strstr(ap->a_disp, buf)) |
| break; |
| |
| /* |
| * Extremely simplistic seach thru definition of first !format |
| * |
| * This is so incomplete and badly handled I'm embarrassed. |
| * Yet, it solves the immediate problem I have. |
| */ |
| p = strchr(ap->a_disp, '!'); |
| if (p) |
| { |
| char fbuf[80]; |
| char *fp = fbuf; |
| char *sp = fbuf; |
| int x; |
| int state; |
| int offset; |
| |
| ++p; |
| while (isalnum(*p) || (*p == '_')) |
| *fp++ = *p++; |
| *fp = 0; |
| x = find_format(fbuf); |
| if (x != -1 && dfmt[x].format && (sp = strstr(dfmt[x].format, buf))) |
| { |
| state = 0; |
| offset = 1; |
| for (fp = dfmt[x].format; fp < sp; ++fp) |
| { |
| switch (state) |
| { |
| case 0: |
| if (*fp == '"') |
| state = 1; |
| else if (*fp == 'n') |
| ++offset; |
| break; |
| case 1: |
| if (*fp == '"') |
| state = 0; |
| break; |
| } |
| } |
| r += offset; |
| if (r >= NADR) |
| r = NADR - 1; |
| break; |
| } |
| } |
| } |
| |
| if (i != NADR) |
| { |
| irow = trow = r; |
| lrow = -1; |
| } |
| else |
| beep(); |
| |
| return (1); |
| } |
| |
| |
| /************************************************************************ |
| * readch - Read an input character in delay mode. |
| ************************************************************************/ |
| |
| int readch(void) |
| { |
| char ch ; |
| |
| #if OLDCURSE |
| read(0, &ch, 1) ; |
| |
| return(ch) ; |
| #else |
| for (;;) |
| { |
| ch = getch() ; |
| if (ch != ERR) return(ch) ; |
| } |
| #endif |
| } |
| |
| |
| /************************************************************************ |
| * collect - Collect characters into a field. |
| ************************************************************************/ |
| |
| void |
| collect(row, col, buf, width, proc) |
| int row ; /* Start row */ |
| int col ; /* Start col */ |
| char *buf ; /* Initial contents */ |
| int width ; /* Field width */ |
| int (*proc)() ; /* Process procedure */ |
| { |
| register int i ; |
| register int ch ; |
| register int startpos ; |
| register int len ; |
| |
| for (len = 0 ; buf && *buf && len < LINELEN ; len++) |
| line[len] = *buf++ ; |
| |
| line[len] = 0 ; |
| |
| #if 0 |
| /* |
| * If no edit string is given, go into insert mode with |
| * a blank line. If an edit string is given, position |
| * the cursor to the end of line, and go into edit mode |
| * immediately. |
| */ |
| |
| if (buf) |
| edit_mode() ; |
| else |
| insert_mode() ; |
| #else |
| /* |
| * It seems to be easier for the unwashed masses to handle |
| * if you always start in edit mode. |
| */ |
| |
| insert_mode() ; |
| #endif |
| |
| linepos = len ; |
| startpos = 0 ; |
| |
| lineproc = proc ; |
| |
| /* |
| * Loop to edit keystroke input. |
| */ |
| |
| #if OLDCURSE |
| tio.c_cc[VMIN] = 1 ; |
| tio.c_cc[VTIME] = 0 ; |
| ioctl(0, TCSETAW, &tio) ; |
| #else |
| nocbreak(); |
| cbreak(); |
| #endif |
| |
| for (;;) |
| { |
| /* |
| * Display current field, scrolling if necessary so the |
| * complete input line can be displayed. |
| */ |
| |
| move(row, col) ; |
| |
| len = strlen(line) ; |
| |
| if (startpos <= linepos - width) startpos = linepos - width + 1 ; |
| if (startpos > linepos) startpos = linepos ; |
| |
| for (i = startpos ; i < startpos + width ; i++) |
| { |
| if (i < len) addch((chtype) line[i]) ; |
| else addch((chtype) mode_ind) ; |
| } |
| |
| /* |
| * Read next input character. |
| */ |
| |
| move(row, col + linepos - startpos) ; |
| refresh() ; |
| |
| ch = readch() ; |
| |
| switch (ch) |
| { |
| /* |
| * Handle screen refresh special. |
| */ |
| |
| #if KEY_REFRESH |
| case KEY_REFRESH: |
| #endif |
| case ctrl('l'): |
| case ctrl('r'): |
| clearok(stdscr, 1) ; |
| break ; |
| |
| /* |
| * Everything else is a VI command. |
| */ |
| |
| default: |
| update_line(ch) ; |
| break ; |
| } |
| |
| if (linepos == -1) break ; |
| } |
| } |
| |
| |
| /************************************************************************ |
| * docmd - Process command keystrokes. |
| ************************************************************************/ |
| |
| void docmd() |
| { |
| register int ch ; |
| register a_field *ap ; |
| register a_field *bp ; |
| int r ; |
| int m ; |
| int n ; |
| static int count ; |
| |
| #if OLDCURSE |
| int nbuf ; |
| int i ; |
| char buf[100] ; |
| #endif |
| |
| /* |
| * Position the cursor, and flush output. |
| */ |
| |
| move(FROW(irow), FCOL(icol)) ; |
| refresh() ; |
| |
| #if OLDCURSE |
| tio.c_cc[VMIN] = 0 ; |
| tio.c_cc[VTIME] = uptime ; |
| |
| ioctl(0, TCSETAW, &tio) ; |
| |
| nbuf = read(0, buf, sizeof(buf)) ; |
| i = 0 ; |
| #else |
| cbreak(); |
| #endif |
| |
| /* |
| * Process the characters received. |
| */ |
| |
| trow = frow ; |
| |
| for (n = 0 ;; n++) |
| { |
| |
| #if OLDCURSE |
| if (i >= nbuf) goto done ; |
| ch = buf[i++] ; |
| #else |
| halfdelay(uptime) ; |
| |
| ch = getch() ; |
| if (ch == ERR) goto done ; |
| |
| nocbreak(); |
| cbreak(); |
| #endif |
| |
| if ((count ? '0' : '1') <= ch && ch <= '9') |
| { |
| if (count > 999) count = 999 ; |
| count = 10 * count + ch - '0' ; |
| continue ; |
| } |
| |
| if (isupper(ch)) |
| ch = tolower(ch) ; |
| |
| switch (ch) |
| { |
| |
| /* |
| * Redraw screen. |
| */ |
| |
| #if KEY_REFRESH |
| case KEY_REFRESH: |
| #endif |
| case ctrl('l'): |
| case ctrl('r'): |
| clearok(stdscr, 1) ; |
| lrow = -1 ; |
| break ; |
| |
| /* |
| * Toggle between index formats (byte and array index) |
| */ |
| |
| case ctrl('t'): |
| index_mode ^= 1 ; |
| break; |
| |
| /* |
| * Next page. |
| */ |
| |
| #if KEY_NPAGE |
| case KEY_NPAGE: |
| #endif |
| case ctrl('F'): |
| if (count == 0) count = 1 ; |
| r = trow + (nrow-1) * count ; |
| if (r > NADR - nrow) r = NADR - nrow ; |
| if (r == trow) beep() ; |
| irow += r - trow ; |
| trow = r ; |
| break ; |
| |
| /* |
| * Scroll down. |
| */ |
| |
| #if KEY_SF |
| case KEY_SF: |
| #endif |
| case ctrl('D'): |
| if (count) scount = count ; |
| r = trow + scount ; |
| if (r > NADR - nrow) r = NADR - nrow ; |
| if (r == trow) beep() ; |
| irow += r - trow ; |
| trow = r ; |
| break ; |
| |
| /* |
| * Previous page. |
| */ |
| |
| #if KEY_PPAGE |
| case KEY_PPAGE: |
| #endif |
| case ctrl('B'): |
| if (count == 0) count = 1 ; |
| r = trow - (nrow-1) * count ; |
| if (r < 0) r = 0 ; |
| irow += r - trow ; |
| if (r == trow) beep() ; |
| trow = r ; |
| break ; |
| |
| /* |
| * Scroll up. |
| */ |
| |
| #if KEY_SR |
| case KEY_SR: |
| #endif |
| case ctrl('U'): |
| if (count) scount = count ; |
| r = trow - scount ; |
| if (r < 0) r = 0 ; |
| irow += r - trow ; |
| if (r == trow) beep() ; |
| trow = r ; |
| break ; |
| |
| /* |
| * Next line. |
| */ |
| |
| case '\r': |
| case '\n': |
| icol = 0 ; |
| if (irow >= NADR - 1) goto error ; |
| irow += count ? count : 1 ; |
| if (irow >= NADR) irow = NADR - 1 ; |
| if (irow >= trow + nrow) trow = irow - nrow + 1 ; |
| break ; |
| |
| /* |
| * Shell escape. |
| */ |
| |
| #if KEY_COMMAND |
| case KEY_COMMAND: |
| #endif |
| case '!': |
| case ':': |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("shell:") ; |
| collect(LINES-1, 7, (char *)0, COLS-8, inshell) ; |
| lrow = -1 ; |
| goto flush ; |
| |
| /* |
| * Help on/off. |
| */ |
| |
| #if KEY_HELP |
| case KEY_HELP: |
| #endif |
| case '?': |
| if (helpflag ^= 1) |
| { |
| nrow-- ; |
| if (irow >= trow + nrow) irow-- ; |
| } |
| else |
| { |
| nrow++ ; |
| if (trow > NADR - nrow) trow-- ; |
| lrow = -1 ; |
| } |
| break ; |
| |
| /* |
| * Backward in memory. |
| */ |
| |
| #if KEY_PREVIOUS |
| case KEY_PREVIOUS: |
| #endif |
| case '-': |
| ap = &afield[irow] ; |
| while (ap->a_disp == 0) |
| { |
| if (ap == afield) goto error ; |
| ap-- ; |
| } |
| |
| if (ap->a_size == 0) goto error ; |
| |
| if (count == 0) count = 1 ; |
| ap->a_addr -= count * ap->a_size ; |
| break ; |
| |
| /* |
| * Forward in memory. |
| */ |
| |
| #if KEY_NEXT |
| case KEY_NEXT: |
| #endif |
| case '+': |
| ap = &afield[irow] ; |
| while (ap->a_disp == 0) |
| { |
| if (ap == afield) goto error ; |
| ap-- ; |
| } |
| |
| if (ap->a_size == 0) goto error ; |
| |
| if (count == 0) count = 1 ; |
| ap->a_addr += count * ap->a_size ; |
| break ; |
| |
| /* |
| * Start of line. |
| */ |
| |
| case '0': |
| case '^': |
| if (icol == 0) goto error ; |
| icol = 0 ; |
| break ; |
| |
| /* |
| * Toggle address display mode. |
| */ |
| |
| case 'a': |
| addrflag = !addrflag ; |
| break ; |
| |
| /* |
| * Enter base address. |
| */ |
| |
| case 'b': |
| { |
| char base_asc[11]; |
| sprintf(base_asc, "0x%lx", base); |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("base address:") ; |
| collect(LINES-1, 14, base_asc, 8, inbase) ; |
| lrow = -1 ; |
| goto flush ; |
| } |
| |
| /* |
| * Change field. |
| */ |
| |
| #if KEY_REPLACE |
| case KEY_REPLACE: |
| #endif |
| case 'c': |
| if (icol == 0) |
| { |
| showhelp(1) ; |
| collect(FROW(irow), FCOL(0), (char *)0, |
| COLS - FCOL(0) - 1, inaddr) ; |
| } |
| else if (DFIELD(irow, icol).d_type) |
| { |
| if (!writeflag) goto error ; |
| |
| showhelp(2) ; |
| collect(FROW(irow), FCOL(icol), (char *)0, 8, indata) ; |
| } |
| else goto error ; |
| goto flush ; |
| |
| /* |
| * Delete rows. |
| */ |
| |
| #if KEY_DL |
| case KEY_DL: |
| #endif |
| case 'd': |
| if (count == 0) count = 1 ; |
| |
| r = 0 ; |
| bp = &bfield[0] ; |
| while (r < brow) |
| { |
| strfree(bp[0].a_disp) ; |
| bp[0].a_addr = 0 ; |
| bp[0].a_disp = 0 ; |
| bp[0].a_size = 0 ; |
| r++ ; |
| bp++ ; |
| } |
| |
| r = irow ; |
| ap = &afield[irow] ; |
| bp = &bfield[0] ; |
| while (r < NADR) |
| { |
| if (r < irow+count) bp[0] = ap[0] ; |
| |
| if (r < NADR-count) |
| ap[0] = ap[count] ; |
| else |
| { |
| ap[0].a_addr = 0 ; |
| ap[0].a_disp = 0 ; |
| ap[0].a_size = 0 ; |
| } |
| |
| r++ ; |
| ap++ ; |
| bp++ ; |
| } |
| |
| brow = count ; |
| break ; |
| |
| /* |
| * Edit field. |
| */ |
| |
| case 'e': |
| ap = &afield[irow] ; |
| if (icol == 0) |
| { |
| showhelp(1) ; |
| collect(FROW(irow), FCOL(0), ap->a_disp ? ap->a_disp : "", |
| COLS - FCOL(0) - 1, inaddr) ; |
| } |
| else if (DFIELD(irow, icol).d_type) |
| { |
| if (!writeflag) goto error ; |
| |
| showhelp(2) ; |
| collect(FROW(irow), FCOL(icol), "", 8, indata) ; |
| } |
| else goto error ; |
| goto flush ; |
| |
| /* |
| * Switch emulator to port A. |
| */ |
| |
| case 'f': |
| #if USE_HP_ANALYZER |
| if (emdev) |
| { |
| fprintf(emout, "po -a a\r") ; |
| break ; |
| } |
| #endif |
| beep() ; |
| break ; |
| |
| /* |
| * Go to line number. |
| */ |
| |
| #if KEY_FIND |
| case KEY_FIND: |
| #endif |
| #if KEY_REFERENCE |
| case KEY_REFERENCE: |
| #endif |
| case 'g': |
| if (count == 0) irow = NADR - 1 ; |
| else if (count > NADR) goto error ; |
| else irow = count - 1 ; |
| if (irow < trow) trow = irow ; |
| if (irow >= trow + nrow) trow = irow - nrow + 1 ; |
| break ; |
| |
| /* |
| * Move left. |
| */ |
| |
| #if KEY_LEFT |
| case KEY_LEFT: |
| #endif |
| case 'h': |
| r = irow * (ncol + 1) + icol ; |
| if (r == 0) goto error ; |
| r -= count ? count : 1 ; |
| if (r < 0) r = 0 ; |
| irow = r / (ncol + 1) ; |
| icol = r % (ncol + 1) ; |
| if (trow > irow) trow = irow ; |
| break ; |
| |
| /* |
| * Insert rows. |
| */ |
| |
| #if KEY_OPEN |
| case KEY_OPEN: |
| #endif |
| case 'i': |
| insertscreenline(count); |
| break ; |
| |
| /* |
| * Move down. |
| */ |
| |
| #if KEY_DOWN |
| case KEY_DOWN: |
| #endif |
| case 'j': |
| if (irow >= NADR - 1) goto error ; |
| irow += count ? count : 1 ; |
| if (irow >= NADR) irow = NADR - 1 ; |
| if (irow >= trow + nrow) trow = irow - nrow + 1 ; |
| break ; |
| |
| /* |
| * Move up. |
| */ |
| |
| #if KEY_UP |
| case KEY_UP: |
| #endif |
| case 'k': |
| if (irow == 0) goto error ; |
| irow -= count ? count : 1 ; |
| if (irow < 0) irow = 0 ; |
| if (irow < trow) trow = irow ; |
| break ; |
| |
| /* |
| * Move right. |
| */ |
| |
| #if KEY_RIGHT |
| case KEY_RIGHT: |
| #endif |
| case ' ': |
| case 'l': |
| r = irow * (ncol + 1) + icol ; |
| m = NADR * (ncol + 1) - 1 ; |
| if (r == m) goto error ; |
| r += count ? count : 1 ; |
| if (r > m) r = m ; |
| irow = r / (ncol + 1) ; |
| icol = r % (ncol + 1) ; |
| if (irow >= trow + nrow) trow = irow - nrow + 1 ; |
| break ; |
| |
| /* |
| * Define format macro. |
| */ |
| |
| #if KEY_CREATE |
| case KEY_CREATE: |
| #endif |
| case 'm': |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("macro:") ; |
| r = irow ; |
| collect(LINES-1, 7, (char *)0, COLS-8, inparam) ; |
| irow = r ; |
| lrow = -1 ; |
| goto flush ; |
| |
| /* |
| * Get namelist file. |
| */ |
| |
| case 'n': |
| if (!readsym()) beep() ; |
| break ; |
| |
| /* |
| * Put deleted lines back in. |
| */ |
| |
| #if KEY_IL |
| case KEY_IL: |
| #endif |
| case 'p': |
| if (brow == 0) goto error ; |
| |
| r = NADR ; |
| ap = &afield[NADR] ; |
| bp = &bfield[NADR-irow] ; |
| while (r > irow) |
| { |
| --r ; |
| --ap ; |
| --bp ; |
| |
| if (r >= NADR-brow) strfree(ap[0].a_disp) ; |
| |
| if (r >= irow+brow) ap[0] = ap[-brow] ; |
| else |
| { |
| ap[0].a_addr = bp[0].a_addr ; |
| ap[0].a_disp = stralloc(bp[0].a_disp) ; |
| ap[0].a_size = bp[0].a_size ; |
| } |
| } |
| break ; |
| |
| /* |
| * Output screen to a file |
| */ |
| |
| case 'o': |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("print file:") ; |
| |
| collect(LINES-1, 12, last_print, COLS-13, inprint) ; |
| lrow = -1 ; |
| goto flush ; |
| |
| #if 0 /* letter already used, waaaaaa */ |
| case '?': |
| search_dir = -1; |
| goto search; |
| #endif |
| |
| case '/': |
| search_dir = 1; |
| goto search; |
| |
| search: |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("search:") ; |
| |
| collect(LINES-1, 8, last_search, COLS-8-1, insearch) ; |
| lrow = -1 ; |
| goto flush ; |
| |
| /* |
| * Quit. |
| */ |
| |
| #if KEY_EXIT |
| case KEY_EXIT: |
| #endif |
| case 'q': |
| quitreq = 1 ; |
| goto flush ; |
| |
| /* |
| * Re-read defines file. |
| */ |
| |
| #if KEY_REDO |
| case KEY_REDO: |
| #endif |
| case 'r': |
| readdefs() ; |
| break ; |
| |
| /* |
| * Save configuration. |
| */ |
| |
| #if KEY_SAVE |
| case KEY_SAVE: |
| #endif |
| case 's': |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("save file:") ; |
| |
| /* |
| If not already saved, default to "insert/append" mode, |
| otherwise, let them edit current prompt |
| */ |
| if (last_saved[0]) |
| collect(LINES-1, 11, last_saved, COLS-12, insave) ; |
| else |
| collect(LINES-1, 11, (char *)0, COLS-12, insave) ; |
| lrow = -1 ; |
| goto flush ; |
| |
| /* |
| * Set update time. |
| */ |
| |
| case 'u': |
| { |
| char update_asc[8]; |
| sprintf(update_asc, "%d", uptime); |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| printw("update interval (1/10ths of sec):") ; |
| |
| collect(LINES-1, 34, update_asc, 4, inuptime) ; |
| lrow = -1 ; |
| goto flush ; |
| } |
| |
| /* |
| * Pause update. |
| */ |
| |
| case 'w': |
| move(LINES-1, 0) ; |
| clrtoeol() ; |
| move(LINES-1, (COLS-32) / 2) ; |
| standout() ; |
| printw(" Paused - Hit Return to Continue ") ; |
| standend() ; |
| refresh() ; |
| |
| #if OLDCURSE |
| tio.c_cc[VMIN] = 1 ; |
| tio.c_cc[VTIME] = 0 ; |
| ioctl(0, TCSETAW, &tio) ; |
| #else |
| halfdelay(250) ; |
| #endif |
| readch() ; |
| |
| lrow = -1 ; |
| goto done ; |
| |
| /* |
| * Yank lines into buffer. |
| */ |
| |
| #if KEY_COPY |
| case KEY_COPY: |
| #endif |
| case 'y': |
| if (count == 0) count = 1 ; |
| |
| r = 0 ; |
| bp = &bfield[0] ; |
| while (r < brow) |
| { |
| strfree(bp[0].a_disp) ; |
| bp[0].a_addr = 0 ; |
| bp[0].a_disp = 0 ; |
| bp[0].a_size = 0 ; |
| r++ ; |
| bp++ ; |
| } |
| |
| r = 0 ; |
| ap = &afield[irow] ; |
| bp = &bfield[0] ; |
| while (r < count) |
| { |
| bp[0].a_addr = ap[0].a_addr ; |
| bp[0].a_disp = stralloc(ap[0].a_disp) ; |
| bp[0].a_size = ap[0].a_size ; |
| r++ ; |
| ap++ ; |
| bp++ ; |
| } |
| |
| brow = count ; |
| break ; |
| |
| /* |
| * Zero field. |
| */ |
| |
| case 'z': |
| if (!writeflag) goto error ; |
| |
| if (count == 0) count = 1 ; |
| if (icol == 0) icol = 1 ; |
| |
| for (;;) |
| { |
| if (DFIELD(irow, icol).d_type) |
| { |
| if (count <= 0) break ; |
| indata("0") ; |
| count-- ; |
| } |
| |
| if (++icol > ncol) |
| { |
| if (++irow >= trow + nrow) |
| { |
| irow-- ; |
| icol-- ; |
| goto error ; |
| } |
| icol = 1 ; |
| } |
| } |
| break ; |
| |
| /* |
| * Others are errors. |
| */ |
| |
| default: |
| goto error ; |
| } |
| |
| count = 0 ; |
| } |
| |
| error: |
| beep() ; |
| |
| flush: |
| count = 0 ; |
| |
| done: |
| frow = trow ; |
| |
| if (n == 0) |
| laddr = haddr = 0 ; |
| |
| return ; |
| } |
| |
| |
| /************************************************************************ |
| * check_symread - See if the symbol table file has changed. |
| * If so, we silently reread it. |
| * Optimizatino opportunities abound. |
| ************************************************************************/ |
| |
| check_symreread() |
| { |
| static struct stat symstat ; |
| static time_t last_time ; |
| |
| /* If the file is gone now, we'll let someone else complain. |
| * It may show back up on the next poll. */ |
| |
| if (stat(symname, &symstat) < 0) |
| { |
| return ; |
| } |
| |
| if (symstat.st_mtime > last_time) |
| { |
| readsym(); |
| last_time = symstat.st_mtime; |
| } |
| } |
| |
| |
| /************************************************************************ |
| * mainloop - Update the screen and read keystroke commands. |
| ************************************************************************/ |
| |
| mainloop() |
| { |
| register a_field *ap ; |
| register int arow ; |
| int err ; |
| int c ; |
| |
| if (frow > NADR - nrow) frow = NADR - nrow ; |
| if (frow < 0) frow = 0 ; |
| |
| irow = frow ; |
| lrow = -1 ; |
| |
| laddr = haddr = 0; |
| |
| while (!quitreq) |
| { |
| /* |
| * Find the last row before the start of |
| * the screen which has data to display. |
| */ |
| |
| for (orow = frow ;; orow--) |
| { |
| if (orow < 0) |
| { |
| orow = frow ; |
| break ; |
| } |
| |
| if (afield[orow].a_disp) break ; |
| } |
| |
| /* |
| * Output data over the displayable region |
| * of the screen only. |
| */ |
| |
| crow = frow ; |
| |
| while (crow < frow + nrow) |
| { |
| erow = frow + nrow ; |
| arow = crow ; |
| ocol = 0 ; |
| |
| /* |
| * If a field begins on this line, process it, possibly |
| * filling in subsequent lines until the data runs out, |
| * the screen ends, or we run into another field. |
| */ |
| |
| ap = &afield[orow] ; |
| |
| if (ap->a_disp) |
| { |
| /* |
| * Recognize board/concentrator prefix at beginning |
| * of expression. |
| */ |
| |
| str = ap->a_disp ; |
| |
| #if HAVE_SOCKET |
| if (fepdev || nsoc) |
| { |
| if (isalnum(str[0]) && |
| isalnum(str[1]) && |
| str[2] == ':') |
| { |
| ov_board = getdigit(str[0]) ; |
| ov_conc = getdigit(str[1]) ; |
| str += 3 ; |
| } |
| else if |
| (isalnum(str[0]) && |
| str[1] == ':') |
| { |
| ov_board = getdigit(str[0]) ; |
| ov_conc = 0 ; |
| str += 2 ; |
| } |
| else |
| { |
| ov_board = def_board ; |
| ov_conc = def_conc ; |
| } |
| } |
| #endif |
| /* |
| * Initialize the expression parser, to figure |
| * out the address to display. |
| */ |
| |
| --str ; |
| inparen = 0 ; |
| |
| err = 0 ; |
| |
| if (setjmp(efail)) |
| { |
| err++ ; |
| } |
| else |
| { |
| temp[0] = ap->a_size ; |
| ebase = 16 ; |
| addr = (expr(0) + ap->a_addr) & addr_mask ; |
| addr *= addrscale; |
| |
| if (*str != '/') err++ ; |
| } |
| |
| /* |
| * On an error, show the incorrect display expression |
| * in the first field of the line. |
| */ |
| |
| if (err) |
| { |
| if (orow >= frow) |
| { |
| initline() ; |
| |
| c = *str ; |
| *str = 0 ; |
| printw("%s", ap->a_disp) ; |
| *str = c ; |
| |
| printw(" <ERROR> ") ; |
| |
| printw("%s", str) ; |
| } |
| orow++ ; |
| } |
| |
| /* |
| * If the addrflag is set, show the display |
| * expression alone on the first line. |
| * |
| * In any case, display the formatted data on |
| * the next line. |
| */ |
| |
| else |
| { |
| if (addrflag) |
| { |
| if (orow >= frow) |
| { |
| initline() ; |
| |
| *str = 0 ; |
| printw("%s", ap->a_disp) ; |
| |
| if (ap->a_addr < 0) |
| { |
| if (index_mode) |
| { |
| printw("-%lx", -ap->a_addr) ; |
| } |
| else |
| { |
| printw("[-%ld]", -(ap->a_addr/ap->a_size)) ; |
| } |
| } |
| |
| if (ap->a_addr > 0) |
| if (index_mode) |
| printw("+%lx", ap->a_addr) ; |
| else |
| printw("[%ld]", ap->a_addr/ap->a_size) ; |
| |
| *str = '/' ; |
| printw("%s", str) ; |
| } |
| |
| orow++ ; |
| } |
| |
| depth = 0 ; |
| faddr = addr; |
| rw_max = 128 ; |
| |
| display(str+1) ; |
| |
| ap->a_size = (addr - faddr) / addrscale ; |
| } |
| |
| move(FROW(irow), FCOL(icol)) ; |
| refresh() ; |
| } |
| |
| if (crow == arow) |
| { |
| clearline() ; |
| crow++ ; |
| } |
| |
| orow = crow ; |
| } |
| |
| lrow = frow ; |
| |
| standend() ; |
| |
| showhelp(0) ; |
| |
| docmd() ; |
| |
| check_symreread(); |
| } |
| } |
| |
| |
| /************************************************************************ |
| * beeper - Beep at operator. |
| ************************************************************************/ |
| |
| #if OLDCURSE && 0 |
| void |
| beeper() |
| { |
| static char beepc = '\007' ; |
| |
| write(1, &beepc, 1) ; |
| } |
| #endif |
| |
| |
| /************************************************************************ |
| * opensoc - Open socket interface. |
| ************************************************************************/ |
| |
| #if HAVE_SOCKET |
| void |
| opensoc(str) |
| char *str ; |
| { |
| int fd ; |
| int i ; |
| int ch ; |
| struct servent *sp ; |
| struct hostent *hp ; |
| struct sockaddr_in sin ; |
| char host[100]; |
| |
| while (*str) { |
| |
| /* |
| * Extract the next entry in the colon separated |
| * list of host names. |
| */ |
| |
| for (i = 0 ; *str && (ch = *str++) != ':' ;) |
| { |
| if (i < sizeof(host)-1) host[i++] = ch ; |
| } |
| host[i] = 0 ; |
| |
| if (nsoc >= MAXSOC) |
| { |
| fprintf(stderr, "Too many sockets, increase MAXSOC\n") ; |
| exit(2) ; |
| } |
| |
| /* |
| * Open a socket, and bind it to a non-priveleged port. |
| */ |
| |
| fd = socket(AF_INET, SOCK_DGRAM, 0) ; |
| if (fd < 0) { |
| perror("socket") ; |
| exit(2) ; |
| } |
| |
| sin.sin_family = AF_INET ; |
| sin.sin_addr.s_addr = htonl(INADDR_ANY) ; |
| sin.sin_port = htons(0) ; |
| |
| if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) |
| { |
| perror("connect") ; |
| exit(2) ; |
| } |
| |
| /* |
| * Get "kme" service port number. |
| */ |
| |
| memset((char *)&sin, 0, sizeof(sin)) ; |
| |
| sp = getservbyname("kme", "udp") ; |
| if (sp == 0) { |
| fprintf(stderr, "kme/udp: unknown service\n"); |
| exit(2); |
| } |
| |
| sin.sin_port = sp->s_port ; |
| |
| /* |
| * Get destination address. |
| */ |
| |
| sin.sin_addr.s_addr = inet_addr(host) ; |
| |
| if (sin.sin_addr.s_addr != -1) |
| { |
| sin.sin_family = AF_INET; |
| } |
| else |
| { |
| hp = gethostbyname(host) ; |
| if (hp == 0) |
| { |
| fprintf(stderr, "unknown host: %s\n", host) ; |
| exit(2) ; |
| } |
| sin.sin_family = hp->h_addrtype ; |
| memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length) ; |
| } |
| |
| if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
| perror("connect") ; |
| exit(2) ; |
| } |
| |
| socfd[nsoc] = fd ; |
| |
| nsoc++ ; |
| } |
| } |
| #endif |
| |
| |
| /************************************************************************ |
| * version_info - display confiration information. |
| ************************************************************************/ |
| void |
| version_info(void) |
| { |
| char *vinfo[] = { |
| PACKAGE " version " VERSION, |
| |
| #if HAVE_MMAP |
| "MMAP enabled", |
| #endif |
| |
| #if USE_HP_ANALYZER |
| "HP analyzer supported", |
| #endif |
| |
| #if HAVE_NLIST |
| "nlist enabled", |
| #endif |
| |
| #if HAVE_PTRACE |
| "ptrace enabled", |
| #endif |
| |
| #if HAVE_LIBELF |
| "libelf present", |
| #endif |
| |
| #if HAVE_LIBDL |
| "libdl present", |
| #endif |
| NULL |
| }; |
| |
| char **v = vinfo; |
| while (*v) |
| { |
| printf("%s\n", *v); |
| *v++; |
| } |
| exit(0); |
| } |
| |
| |
| /************************************************************************ |
| * main - main program. |
| ************************************************************************/ |
| |
| main(argc, argv) |
| int argc ; |
| char **argv ; |
| { |
| char *cp ; |
| int c ; |
| |
| /* |
| * Unpack options. |
| */ |
| |
| progname = argv[0] ; |
| |
| if (cp = getenv("KME_DEFS")) defsname = cp ; |
| if (cp = getenv("KME_PATH")) defspath = cp ; |
| if (cp = getenv("KME_CORE")) corename = cp ; |
| if (cp = getenv("KME_SYMS")) symname = cp ; |
| |
| fmt_cnt = dl_fmt_cnt = 0; |
| |
| while ((c = getopt(argc, argv, "aA:b:c:d:D:e:f:hik:L:m:M:n:p:P:rsS:tu:Vx")) != -1) |
| { |
| switch (c) |
| { |
| case 'a': |
| addrflag = !addrflag ; |
| break ; |
| |
| case 'A': |
| addrscale = atoi(optarg); |
| break; |
| |
| case 'b': |
| if (!inbase(optarg)) goto usage ; |
| break ; |
| |
| case 'c': |
| coredev = corename = optarg ; |
| break ; |
| |
| case 'd': |
| defsname = optarg ; |
| break ; |
| |
| case 'D': |
| defspath = optarg; |
| break; |
| |
| case 'e': |
| #if USE_HP_ANALYZER |
| emdev = optarg ; |
| break ; |
| #else |
| fprintf(stderr, "EMULATOR not compiled in!\n") ; |
| return(2) ; |
| #endif |
| |
| case 'f': |
| fepdev = optarg ; |
| break ; |
| |
| case 'h': |
| helpflag = 1 ; |
| break ; |
| |
| case 'i': |
| #if TERMINFO |
| idline ^= 1 ; |
| #else |
| fprintf(stderr, |
| "Note: insert/delete option not compiled in!\n") ; |
| #endif |
| break ; |
| |
| case 'k': |
| if (isalnum(optarg[0])) |
| { |
| def_board = getdigit(optarg[0]) ; |
| def_conc = isalnum(optarg[1]) ? getdigit(optarg[1]) : 0 ; |
| } |
| else |
| { |
| def_board = 0 ; |
| def_conc = 0 ; |
| } |
| break ; |
| |
| case 'L': |
| #if HAVE_LIBDL |
| { |
| void *handle; |
| |
| handle = dlopen(optarg, RTLD_NOW); |
| if (!handle) |
| { |
| fprintf(stderr, "%s\n", dlerror()); |
| exit(1); |
| } |
| } |
| #else |
| fprintf(stderr, "LIBDL not compiled in!\n") ; |
| #endif |
| break; |
| |
| #if HAVE_SOCKET |
| case 'm': |
| hostname = optarg ; |
| break ; |
| #endif |
| |
| case 'M': /* -M physaddr:len */ |
| #if HAVE_MMAP |
| mempa = (off_t) strtoul(optarg, (char **) NULL, 0); |
| cp = strchr(optarg, ':'); |
| if (!cp) goto usage; |
| memlen = strtoul(cp+1, (char **) NULL, 0); |
| break; |
| #else |
| fprintf(stderr, "MMAP not compiled in!\n") ; |
| return(2) ; |
| #endif |
| |
| case 'n': |
| symparam = symname = optarg ; |
| break ; |
| |
| case 'p': |
| frow = atoi(optarg) - 1 ; |
| break ; |
| |
| case 'P': |
| #if HAVE_PTRACE |
| pid = atoi(optarg) ? atoi(optarg) : getpid(); ; |
| #else |
| fprintf(stderr, "PTRACE not compiled in!\n") ; |
| return(2) ; |
| #endif |
| break; |
| |
| case 'u': |
| uptime = atoi(optarg) ; |
| break ; |
| |
| case 'r': |
| writeflag = 0 ; |
| break ; |
| |
| case 's': |
| swapflag = !swapflag; |
| break; |
| |
| case 'S': |
| addr_mask = strtoul(optarg, (char **) NULL, 0); |
| if (addr_mask == 0) |
| { |
| fprintf(stderr, "An address mask (-S) of zero is almost certainly not what you want.\n"); |
| return(2); |
| } |
| break; |
| |
| case 't': |
| index_mode = 0 ; |
| break; |
| |
| case 'V': |
| version_info(); |
| break; |
| |
| case 'x': |
| debug++ ; |
| break ; |
| |
| default: |
| goto usage ; |
| } |
| } |
| |
| /* |
| * Default symbol file name if none specified. |
| */ |
| |
| /* |
| * Get define file(s). |
| */ |
| |
| dl_fmt_cnt = fmt_cnt; |
| |
| if (!readdefs()) |
| { |
| sleep(2) ; |
| } |
| |
| /* |
| * Read in symbols. |
| */ |
| |
| if (symname == 0) |
| { |
| #if HAVE_DEV_KSYMS |
| symname = (strcmp(corename, "/dev/kmem") == 0 ? |
| "/dev/ksyms" : "kme_syms"); |
| #elif HAVE_PROC_KSYMS |
| symname = (strcmp(corename, "/dev/kmem") == 0 ? |
| "/proc/ksyms" : "kme_syms"); |
| #else |
| symname = "kme_syms"; |
| #endif |
| } |
| |
| if (!readsym() && strcmp(symname, "kme_syms")) |
| { |
| fprintf(stderr, "Problem with: %s\n", symname) ; |
| perror(symname) ; |
| sleep(2) ; |
| } |
| |
| /* |
| * Now that we have symbols available, read in |
| * the screen configuration. |
| */ |
| |
| while (optind != argc) |
| { |
| if (!inparam(argv[optind++])) goto usage ; |
| } |
| |
| /* |
| * Open memory access file. |
| */ |
| |
| if (fepdev) |
| { |
| fepfd = open(fepdev, O_WRONLY|O_NDELAY) ; |
| |
| if (fepfd < 0) |
| fepfd = open(fepdev, O_RDONLY|O_NDELAY) ; |
| |
| if (fepfd < 0) |
| { |
| fprintf(stderr, "Cannot open ") ; |
| perror(fepdev) ; |
| return(2) ; |
| } |
| |
| #if HAVE_STROPTS_H |
| /* Test to see if this is a STREAM device */ |
| strdev = ! (ioctl(fepfd, I_FLUSH, FLUSHRW) == -1); |
| #endif |
| } |
| |
| #if HAVE_SOCKET |
| else if (hostname) |
| { |
| opensoc(hostname) ; |
| } |
| #endif |
| |
| #if USE_HP_ANALYZER |
| else if (emdev) |
| { |
| emfd = open(emdev, O_RDWR) ; |
| if (emfd < 0) |
| { |
| fprintf(stderr, "Cannot open ") ; |
| perror(emdev) ; |
| return(2) ; |
| } |
| |
| { |
| static struct termio emtio ; |
| emtio.c_cflag = HUPCL|CREAD|CS8|EXTB ; |
| emtio.c_iflag = ISTRIP ; |
| emtio.c_cc[VMIN] = 0 ; |
| emtio.c_cc[VTIME] = 2 ; |
| if (ioctl(emfd, TCSETAF, &emtio) != 0) |
| { |
| perror(emdev) ; |
| return (2) ; |
| } |
| |
| emin = fdopen(emfd, "r") ; |
| emout = fdopen(emfd, "w") ; |
| } |
| } |
| #endif |
| |
| #if HAVE_MMAP |
| else if (memlen) |
| { |
| memva = (uchar *) mmap((caddr_t) 0, memlen, |
| PROT_READ | (writeflag ? PROT_WRITE : 0), |
| MAP_SHARED, memfd, mempa); |
| if (memva == (void *) -1) |
| { |
| perror("can't mmap corefile"); |
| return(2); |
| } |
| } |
| #endif |
| |
| else |
| { |
| if ((memfd = open(corename, writeflag ? O_RDWR : O_RDONLY)) == -1) |
| { |
| perror(corename) ; |
| return(2) ; |
| } |
| } |
| |
| /* |
| * Initialize curses. |
| */ |
| |
| #if OLDCURSE |
| ioctl(0, TCGETA, &otio) ; |
| #endif |
| |
| initscr() ; |
| |
| #if OLDCURSE |
| ioctl(0, TCGETA, &tio) ; |
| tio.c_lflag &= ~(ECHO|ICANON) ; |
| tio.c_iflag &= ~(ICRNL|IGNCR|INLCR) ; |
| #else |
| noecho() ; |
| typeahead(-1) ; |
| keypad(stdscr, 1) ; |
| #endif |
| |
| #if TERMINFO |
| idlok(stdscr, idline) ; |
| #endif |
| |
| /* |
| * Figure number of rows/columns on screen. |
| */ |
| |
| nrow = LINES ; |
| if (nrow > NADR) nrow = NADR ; |
| nrow -= helpflag ; |
| |
| scount = nrow / 2 ; |
| |
| ncol = (COLS - FCOL(1)) / 8 ; |
| |
| if (nrow * ncol > NDATA) ncol = NDATA / nrow ; |
| |
| /* |
| * Run the main loop. |
| */ |
| |
| signal(SIGINT, catch) ; |
| |
| irow = frow ; |
| mainloop() ; |
| |
| /* |
| * Exit curses. |
| */ |
| |
| move(LINES-1, 0) ; |
| refresh() ; |
| |
| endwin() ; |
| |
| putchar('\n') ; |
| |
| return(0) ; |
| |
| usage: |
| fprintf(stderr, |
| "usage: %s %s\n\t%s\n\t%s\n\t%s\n", argv[0], |
| "[-ahirsx] [-b base] [-c core] [-d defs] [-e emulator]", |
| "[-f tty] [-k node] [-m hostname] [-n symfile] [-p row]", |
| "[-u uptime] [-Mstartaddr:size] [-S address mask] [-A addrscale]", |
| "[-P pid] [param ...]") ; |
| return(2) ; |
| } |