blob: 392c18ec50378cb01f4b9256a9712810ac0d7ef6 [file] [log] [blame] [raw]
/*
* 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 <sys/socket.h>
# include <netinet/in.h>
# include <netdb.h>
# include <arpa/inet.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_GETOPT_H
# include <getopt.h>
#endif
#if HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#if HAVE_SYS_KSYM_H
# include <sys/ksym.h>
#endif
#if HAVE_ELF_H
# include <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;
int insert_mode(void);
int update_line(int);
#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 int (*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;
ulong addr_mask = -1L; /* 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_module; /* Default concentrator number */
int ov_board; /* Overide board number */
int ov_module; /* 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 */
int udp_port; /* UDP port number */
#endif
int fepfd; /* FEP file descriptor */
/*
* 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(int sig)
{
signal(SIGINT, catch);
sigint = 1;
beep();
}
/************************************************************************
* bigendian - Return true if we are on a bigendian host
************************************************************************/
int bigendian()
{
int endian = 1;
return ((char *) &endian)[0] != 1;
}
/************************************************************************
* swaps - Swap short operand.
************************************************************************/
ushort
always_swaps(ushort mval)
{
mval = (((mval >> 8) & 0xff) | ((mval << 8) & 0xff00));
return (mval);
}
ushort
swaps(ushort mval)
{
if (swapflag)
{
mval = always_swaps(mval);
}
return (mval);
}
/************************************************************************
* swapl - Swap long operand.
************************************************************************/
ulong
always_swapl(ulong mval)
{
mval = (((mval >> 24) & 0x000000ff) |
((mval >> 8) & 0x0000ff00) |
((mval << 8) & 0x00ff0000) |
((mval << 24) & 0xff000000));
return(mval);
}
ulong
swapl(ulong mval)
{
if (swapflag)
mval = always_swapl(mval);
return (mval);
}
/************************************************************************
* stralloc - Allocate string.
************************************************************************/
char *
stralloc(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(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(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(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(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(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[512];
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) != 0)
{
*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);
}
/************************************************************************
* getmem - Get memory bytes.
************************************************************************/
int
getmem(unsigned nbyte)
{
int rw_size = rw_max < nbyte ? rw_max : nbyte;
long a = (addr + base) & addr_mask;
static rw_t rw;
static int rtncode;
/*
* If the data is already in the read-ahead buffer,
* there is no need to fetch it.
*/
if (ov_board == lboard &&
ov_module == 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_module = lconc = ov_module;
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_module = lconc = ov_module;
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_module = lconc = ov_module;
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_module == w.rw_module &&
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 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(int 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(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(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++) != 0)
{
/*
* 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(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(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(char* buf)
{
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(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(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_module = 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_module = 0;
rw.rw_addr = a;
}
else
{
rw.rw_board = def_board;
rw.rw_module = def_module;
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_module = 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_module = 0;
rw.rw_addr = a;
}
else
{
rw.rw_board = def_board;
rw.rw_module = def_module;
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
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_module = 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_module = 0;
w.rw_addr = a;
}
else
{
w.rw_board = def_board;
w.rw_module = def_module;
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_module == w.rw_module &&
r.rw_addr == w.rw_addr &&
r.rw_size == w.rw_size)
{
return(1);
}
}
}
return(0);
}
#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(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(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(0);
/*
* 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 char last_saved[80]; /* So we can edit later */
int insave(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 (coredev)
fprintf(file, " -c %s", coredev);
if (fepdev)
fprintf(file, " -f %s", fepdev);
if (helpflag)
fprintf(file, " -h");
if (idline)
fprintf(file, " -i");
if (def_board || def_module)
{
fprintf(file, " -k %c", hexnum[def_board]);
if (def_module) fprintf(file, "%c", hexnum[def_module]);
}
#if HAVE_SOCKET
if (hostname)
{
fprintf(file, " -m %s", hostname);
}
#endif
#if HAVE_MMAP
if (memlen)
fprintf(file, " -M 0x%lx:0x%lx", mempa, memlen);
#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);
#if HAVE_SOCKET
if (udp_port != 0)
fprintf(file, " -U %d", udp_port);
#endif
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(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;
int
insearch(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(int row, int col, char* buf, int width, int (*proc)())
{
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;
/*
* 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.
************************************************************************/
void
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.
************************************************************************/
void 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_module = getdigit(str[1]);
str += 3;
}
else if
(isalnum(str[0]) &&
str[1] == ':')
{
ov_board = getdigit(str[0]);
ov_module = 0;
str += 2;
}
else
{
ov_board = def_board;
ov_module = def_module;
}
}
#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(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.
*/
if (udp_port != 0)
{
sin.sin_port = htons(udp_port);
}
else
{
memset((char *)&sin, 0, sizeof(sin));
sp = getservbyname("kme", "udp");
if (sp != 0)
sin.sin_port = sp->s_port;
else
sin.sin_port = htons(UDP_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 HAVE_SOCKET
"sockets enabled",
#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.
************************************************************************/
int
main(int argc, char** argv)
{
char *cp;
char ch;
int c;
/*
* Unpack options.
*/
progname = argv[0];
if ((cp = getenv("KME_DEFS")) != 0) defsname = cp;
if ((cp = getenv("KME_PATH")) != 0) defspath = cp;
if ((cp = getenv("KME_CORE")) != 0) corename = cp;
if ((cp = getenv("KME_SYMS")) != 0) symname = cp;
fmt_cnt = dl_fmt_cnt = 0;
while ((c = getopt(argc, argv,
"aA:b:c:d:D:f:hik:L:m:M:n:p:P:rsS:tu:U: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 '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_module = isalnum(optarg[1]) ? getdigit(optarg[1]) : 0;
}
else
{
def_board = 0;
def_module = 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;
case 'm':
#if HAVE_SOCKET
hostname = optarg;
break;
#else
fprintf(stderr, "Networking support not compiled in!\n");
goto usage;
#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");
goto usage;
#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 'r':
writeflag = 0;
break;
case 's':
swapflag = !swapflag;
break;
case 'S':
if (sscanf(optarg, "%lx%c", &addr_mask, &ch) != 1 ||
addr_mask < 0x100
)
goto usage;
fprintf(stderr, "address mask = %lx\n", addr_mask);
break;
case 't':
index_mode = 0;
break;
case 'u':
uptime = atoi(optarg);
break;
case 'U':
#if HAVE_SOCKET
if (sscanf(optarg, "%d%c", &udp_port, &ch) != 1)
goto usage;
break;
#else
fprintf(stderr, "Networking not compiled in!\n");
goto usage;
#endif
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 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 [-ahirstVx] [-A addrscale] [-b base] [-c core]\n"
"\t[-d defs] [-D defspath] [-f tty] [-k node] [-L lib]\n"
"[-m hostlist] [-M addr:len] [-n symfile] [-p row]\n"
"[-u uptime] [-Mstartaddr:size] [-S address mask]\n"
"[-P pid] [-S mask] [-u uptime] [-U port] [param ...]\n",
argv[0]);
return(2);
}